From 9a68b90e59ab98246b79718578ee6276a51fa78b Mon Sep 17 00:00:00 2001 From: Christopher Pappas Date: Mon, 30 Aug 2021 15:45:29 -0700 Subject: [PATCH] wip - schema returned, delegateToSchema undefined --- package.json | 5 + src/config.ts | 3 + src/index.ts | 15 +- src/lib/stitching2/kaws/link.ts | 12 + src/lib/stitching2/kaws/schema.ts | 28 +++ src/lib/stitching2/kaws/v2/stitching.ts | 215 ++++++++++++++++++ .../stitching2/lib/createRemoteExecutor.ts | 66 ++++++ src/lib/stitching2/mergeSchemas.ts | 41 ++++ .../middleware/responseLoggerMiddleware.ts | 29 +++ src/schema/v2/index.ts | 51 +++-- yarn.lock | 166 ++++++++++++++ 11 files changed, 613 insertions(+), 18 deletions(-) create mode 100644 src/lib/stitching2/kaws/link.ts create mode 100644 src/lib/stitching2/kaws/schema.ts create mode 100644 src/lib/stitching2/kaws/v2/stitching.ts create mode 100644 src/lib/stitching2/lib/createRemoteExecutor.ts create mode 100644 src/lib/stitching2/mergeSchemas.ts create mode 100644 src/lib/stitching2/middleware/responseLoggerMiddleware.ts diff --git a/package.json b/package.json index df243f0bbf..c4015106b5 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,11 @@ "@babel/preset-typescript": "7.3.3", "@babel/register": "7.4.4", "@graphql-tools/delegate": "6.0.10", + "@graphql-tools/graphql-file-loader": "^7.0.6", + "@graphql-tools/load": "^7.1.9", + "@graphql-tools/schema": "^8.1.2", + "@graphql-tools/stitch": "^8.2.1", + "@graphql-tools/wrap": "^8.0.13", "@heroku/foreman": "2.0.2", "@sentry/node": "5.18.1", "accounting": "0.4.1", diff --git a/src/config.ts b/src/config.ts index 430e74dcf6..9fb08f18f4 100644 --- a/src/config.ts +++ b/src/config.ts @@ -37,6 +37,7 @@ const { ENABLE_QUERY_TRACING, ENABLE_REQUEST_LOGGING, DISABLE_SCHEMA_STITCHING, + ENABLE_EXPERIMENTAL_STITCHING_MIGRATION, ENABLE_RESOLVER_BATCHING, EXCHANGE_API_BASE, EXCHANGE_APP_ID, @@ -162,6 +163,8 @@ export default { EMBEDLY_KEY, ENABLE_APOLLO: ENABLE_APOLLO === "true", ENABLE_ASYNC_STACK_TRACES, + ENABLE_EXPERIMENTAL_STITCHING_MIGRATION: + ENABLE_EXPERIMENTAL_STITCHING_MIGRATION === "true", ENABLE_METRICS, ENABLE_QUERY_TRACING, ENABLE_REQUEST_LOGGING, diff --git a/src/index.ts b/src/index.ts index c06a2c038d..05e2ec11cf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,7 @@ import { createLoaders } from "./lib/loaders" import depthLimit from "graphql-depth-limit" import express from "express" import { schema as schemaV1 } from "./schema/v1" -import { schema as schemaV2 } from "./schema/v2" +import { getSchema as getSchemaV2 } from "./schema/v2" import moment from "moment-timezone" import morgan from "artsy-morgan" import { fetchPersistedQuery } from "./lib/fetchPersistedQuery" @@ -267,8 +267,15 @@ function startApp(appSchema, path: string) { const app = express() -// This order is important for dd-trace to be able to find the nested routes. -app.use("/v2", startApp(schemaV2, "/")) -app.use("/", startApp(schemaV1, "/")) +;(async () => { + try { + const schemaV2 = await getSchemaV2() + // This order is important for dd-trace to be able to find the nested routes. + app.use("/v2", (req, res, next) => startApp(schemaV2, "/")(req, res, next)) + app.use("/", (req, res, next) => startApp(schemaV1, "/")(req, res, next)) + } catch (error) { + console.log(error) + } +})() export default app diff --git a/src/lib/stitching2/kaws/link.ts b/src/lib/stitching2/kaws/link.ts new file mode 100644 index 0000000000..857217578f --- /dev/null +++ b/src/lib/stitching2/kaws/link.ts @@ -0,0 +1,12 @@ +import urljoin from "url-join" +import config from "config" +import { createRemoteExecutor } from "../lib/createRemoteExecutor" +import { responseLoggerMiddleware } from "../middleware/responseLoggerMiddleware" + +const { KAWS_API_BASE } = config + +export const createKawsExecutor = () => { + return createRemoteExecutor(urljoin(KAWS_API_BASE, "graphql"), { + middleware: [responseLoggerMiddleware("Kaws")], + }) +} diff --git a/src/lib/stitching2/kaws/schema.ts b/src/lib/stitching2/kaws/schema.ts new file mode 100644 index 0000000000..71549c716f --- /dev/null +++ b/src/lib/stitching2/kaws/schema.ts @@ -0,0 +1,28 @@ +import { createKawsExecutor } from "./link" +import { GraphQLFileLoader } from "@graphql-tools/graphql-file-loader" +import { RenameTypes, RenameRootFields } from "@graphql-tools/wrap" +import { loadSchema } from "@graphql-tools/load" +import { GraphQLSchema } from "graphql" + +export const executableKawsSchema = async () => { + const kawsExecutor = createKawsExecutor() + const kawsSchema: GraphQLSchema = await loadSchema("src/data/kaws.graphql", { + loaders: [new GraphQLFileLoader()], + }) + + const schema = { + schema: kawsSchema, + executor: kawsExecutor, + transforms: [ + new RenameTypes((name) => { + return `Marketing${name}` + }), + new RenameRootFields( + (_operation, name) => + `marketing${name.charAt(0).toUpperCase() + name.slice(1)}` + ), + ], + } + + return schema +} diff --git a/src/lib/stitching2/kaws/v2/stitching.ts b/src/lib/stitching2/kaws/v2/stitching.ts new file mode 100644 index 0000000000..c0d2f39e7c --- /dev/null +++ b/src/lib/stitching2/kaws/v2/stitching.ts @@ -0,0 +1,215 @@ +import { GraphQLSchema, GraphQLFieldConfigArgumentMap } from "graphql" +import { + pageableFilterArtworksArgsWithInput, + filterArtworksArgs, +} from "schema/v2/filterArtworksConnection" +import gql from "lib/gql" +import { printType } from "lib/stitching/lib/printType" + +export const kawsStitchingEnvironmentV2 = ( + localSchema: GraphQLSchema, + kawsSchema: GraphQLSchema & { transforms?: any } +) => { + return { + // The SDL used to declare how to stitch an object + extensionSchema: gql` + extend type Artist { + marketingCollections(slugs: [String!], category: String, randomizationSeed: String, size: Int, isFeaturedArtistContent: Boolean, showOnEditorial: Boolean): [MarketingCollection] + } + extend type Fair { + marketingCollections(size: Int): [MarketingCollection]! + } + extend type Viewer { + marketingCollections(slugs: [String!], category: String, randomizationSeed: String, size: Int, isFeaturedArtistContent: Boolean, showOnEditorial: Boolean, artistID: String): [MarketingCollection] + } + extend type MarketingCollection { + internalID: ID! + artworksConnection(${argsToSDL( + pageableFilterArtworksArgsWithInput + ).join("\n")}): FilterArtworksConnection + } + type HomePageMarketingCollectionsModule { + results: [MarketingCollection]! + } + extend type HomePage { + marketingCollectionsModule: HomePageMarketingCollectionsModule + } + `, + // Resolvers for the above, this passes in ALL potential parameters + // from KAWS into filter_artworks to allow end users to dynamically + // modify query filters using an admin tool + resolvers: { + Artist: { + marketingCollections: { + fragment: ` + ... on Artist { + internalID + } + `, + resolve: ({ internalID: artistID }, args, context, info) => { + return info.mergeInfo.delegateToSchema({ + schema: kawsSchema, + operation: "query", + fieldName: "marketingCollections", + + args: { + artistID, + ...args, + }, + context, + info, + }) + }, + }, + }, + Fair: { + marketingCollections: { + fragment: ` + ... on Fair { + kawsCollectionSlugs + } + `, + resolve: ({ kawsCollectionSlugs: slugs }, args, context, info) => { + if (slugs.length === 0) return [] + return info.mergeInfo.delegateToSchema({ + schema: kawsSchema, + operation: "query", + fieldName: "marketingCollections", + + args: { + slugs, + ...args, + }, + context, + info, + }) + }, + }, + }, + HomePage: { + marketingCollectionsModule: { + fragment: gql` + ... on HomePage { + __typename + } + `, + resolve: () => { + return {} + }, + }, + }, + HomePageMarketingCollectionsModule: { + results: { + fragment: gql` + ... on HomePageMarketingCollectionsModule { + __typename + } + `, + resolve: async (_source, _args, context, info) => { + try { + // We hard-code the collections slugs here in MP so that the app + // can display different collections based only on an MP change + // (and not an app deploy). + return await info.mergeInfo.delegateToSchema({ + schema: kawsSchema, + operation: "query", + fieldName: "marketingCollections", + args: { + slugs: [ + "new-this-week", + "auction-highlights", + "trending-emerging-artists", + ], + }, + context, + info, + }) + } catch (error) { + // The schema guarantees a present array for results, so fall back + // to an empty one if the request to kaws fails. Note that we + // still bubble-up any errors in the GraphQL response. + return [] + } + }, + }, + }, + Viewer: { + marketingCollections: { + fragment: gql` + ...on Viewer { + __typename + } + `, + resolve: async (_source, args, context, info) => { + return await info.mergeInfo.delegateToSchema({ + schema: kawsSchema, + operation: "query", + fieldName: "marketingCollections", + + args, + context, + info, + }) + }, + }, + }, + MarketingCollection: { + artworksConnection: { + fragment: ` + fragment MarketingCollectionQuery on MarketingCollection { + query { + ${Object.keys(filterArtworksArgs).join("\n")} + } + } + `, + resolve: (parent, _args, context, info) => { + const query = parent.query + const hasKeyword = Boolean(parent.query.keyword) + + const existingLoader = + context.unauthenticatedLoaders.filterArtworksLoader + const newLoader = (loaderParams) => { + return existingLoader.call(null, loaderParams, { + requestThrottleMs: 1000 * 60 * 60, + }) + } + + // TODO: Should this really modify the context in place? + context.unauthenticatedLoaders.filterArtworksLoader = newLoader + + return info.mergeInfo.delegateToSchema({ + schema: localSchema, + operation: "query", + fieldName: "artworksConnection", + args: { + ...query, + keywordMatchExact: hasKeyword, + ..._args, + }, + context, + info, + }) + }, + }, + internalID: { + fragment: ` + fragment MarketingCollectionIDQuery on MarketingCollection { + id + } + `, + resolve: ({ id }, _args, _context, _info) => id, + }, + }, + }, + } +} + +// Very contrived version of what exists in graphql-js but isn’t exported. +// https://github.com/graphql/graphql-js/blob/master/src/utilities/schemaPrinter.js +function argsToSDL(args: GraphQLFieldConfigArgumentMap) { + const result: string[] = [] + Object.keys(args).forEach((argName) => { + result.push(`${argName}: ${printType(args[argName].type)}`) + }) + return result +} diff --git a/src/lib/stitching2/lib/createRemoteExecutor.ts b/src/lib/stitching2/lib/createRemoteExecutor.ts new file mode 100644 index 0000000000..9f3617188e --- /dev/null +++ b/src/lib/stitching2/lib/createRemoteExecutor.ts @@ -0,0 +1,66 @@ +import fetch from "node-fetch" +import { print } from "graphql" +import { ExecutionParams, Executor } from "@graphql-tools/delegate" +import { ResolverContext } from "types/graphql" + +/** + * The parameter that's passed down to an executor's middleware + */ +interface ExecutorMiddlewareOperationParameter + extends ExecutionParams { + /** The operation's parsed result payload */ + result: unknown + /** A stringified representation of the operation */ + text: string +} + +export type ExecutorMiddleware = ( + operation: ExecutorMiddlewareOperationParameter +) => ExecutorMiddlewareOperationParameter + +interface ExecutorOptions { + /** Middleware runs at the end of the operation execution */ + middleware?: ExecutorMiddleware[] +} + +/** + * + * @param graphqlURI URI to the remote graphql service + * @param options Object used to specify middleware or other configuration for the executor + */ +export const createRemoteExecutor = ( + graphqlURI: string, + options: ExecutorOptions = {} +) => { + const { middleware = [] } = options + + return async ({ + document, + variables, + ...otherOptions + }): Promise => { + const query = print(document) + const fetchResult = await fetch(graphqlURI, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ query, variables }), + }) + const result = await fetchResult.json() + if (middleware.length) { + return middleware.reduce( + (acc, middleware) => + middleware({ + document, + variables, + text: query, + result: acc, + ...otherOptions, + }), + result + ).result + } + return result + } +} diff --git a/src/lib/stitching2/mergeSchemas.ts b/src/lib/stitching2/mergeSchemas.ts new file mode 100644 index 0000000000..398d8d3c27 --- /dev/null +++ b/src/lib/stitching2/mergeSchemas.ts @@ -0,0 +1,41 @@ +import { GraphQLSchema } from "graphql" +import { executableKawsSchema } from "./kaws/schema" +import { kawsStitchingEnvironmentV2 } from "./kaws/v2/stitching" + +const { stitchSchemas } = require("@graphql-tools/stitch") + +export const incrementalMergeSchemas2 = async (localSchema) => { + const subschemas = [localSchema] as GraphQLSchema[] + const extensionResolvers = {} as any + const extensionSchemas = [] as string[] + + const useStitchingEnvironment = ({ extensionSchema, resolvers }) => { + extensionSchemas.push(extensionSchema) + for (const [type, fieldResolvers] of Object.entries( + resolvers as Record> + )) { + extensionResolvers[type] = { + ...extensionResolvers[type], + ...fieldResolvers, + } + } + + // debugger + } + + const kawsSchema = await executableKawsSchema() + subschemas.push(kawsSchema.schema) + useStitchingEnvironment( + kawsStitchingEnvironmentV2(localSchema, kawsSchema.schema) + ) + + const stitchedSchemas = stitchSchemas({ + subschemas, + resolvers: extensionResolvers, + typeDefs: extensionSchemas, + }) + + // debugger + + return stitchedSchemas +} diff --git a/src/lib/stitching2/middleware/responseLoggerMiddleware.ts b/src/lib/stitching2/middleware/responseLoggerMiddleware.ts new file mode 100644 index 0000000000..acb36a1ee8 --- /dev/null +++ b/src/lib/stitching2/middleware/responseLoggerMiddleware.ts @@ -0,0 +1,29 @@ +import { ExecutorMiddleware } from "lib/stitching2/lib/createRemoteExecutor" +import extensionsLogger from "lib/loaders/api/extensionsLogger" +import config from "config" + +const shouldLogLinkTraffic = + !!process.env.LOG_HTTP_LINKS && typeof jest === "undefined" +const { ENABLE_REQUEST_LOGGING } = config +const enableRequestLogging = ENABLE_REQUEST_LOGGING === "true" + +export const responseLoggerMiddleware = (name: string): ExecutorMiddleware => { + return (operation) => { + if (shouldLogLinkTraffic) { + console.log(`>\n> Made query to ${name}:`) + console.log(">\n" + operation.text) + console.log(`> Got Response:`) + console.log("> " + JSON.stringify(operation.result)) + } + if (enableRequestLogging) { + const requestID = operation.context?.requestIDs.requestID + if (requestID) { + extensionsLogger(requestID, "stitching", name.toLowerCase(), { + query: operation.text, + vars: operation.variables, + }) + } + } + return operation + } +} diff --git a/src/schema/v2/index.ts b/src/schema/v2/index.ts index 11e61baa04..1de3f534b5 100644 --- a/src/schema/v2/index.ts +++ b/src/schema/v2/index.ts @@ -1,24 +1,47 @@ import localSchema from "./schema" import { incrementalMergeSchemas } from "lib/stitching/mergeSchemas" +import { incrementalMergeSchemas2 } from "lib/stitching2/mergeSchemas" import { lexicographicSortSchema } from "graphql" - import config from "config" -const { DISABLE_SCHEMA_STITCHING } = config + +const { + DISABLE_SCHEMA_STITCHING, + ENABLE_EXPERIMENTAL_STITCHING_MIGRATION, +} = config // Default to the existing metaphysics schema let exportedSchema = localSchema -// If DISABLE_SCHEMA_STITCHING is set in the env -// then don't stitch -const enableSchemaStitching = !DISABLE_SCHEMA_STITCHING -if (enableSchemaStitching) { - try { - if (typeof jest == "undefined") { - console.warn("[V2] [FEATURE] Enabling Schema Stitching") + +export async function getSchema() { + const enableSchemaStitching = !DISABLE_SCHEMA_STITCHING + if (enableSchemaStitching) { + try { + if (typeof jest == "undefined") { + console.warn("[V2] [FEATURE] Enabling Schema Stitching") + } + exportedSchema = incrementalMergeSchemas(exportedSchema, 2) + } catch (err) { + console.log("[V2] Error merging schemas:", err) } - exportedSchema = incrementalMergeSchemas(exportedSchema, 2) - } catch (err) { - console.log("[V2] Error merging schemas:", err) } -} -export const schema = lexicographicSortSchema(exportedSchema) + // TODO: Remove this flag once stitching lib is upgraded + if (ENABLE_EXPERIMENTAL_STITCHING_MIGRATION) { + try { + if (typeof jest == "undefined") { + console.warn( + "[V2] [ENABLE_EXPERIMENTAL_STITCHING_MIGRATION] Enabling experimental Schema Stitching migration" + ) + } + exportedSchema = await incrementalMergeSchemas2(exportedSchema, 2) + } catch (err) { + console.log( + "[V2] [ENABLE_EXPERIMENTAL_STITCHING_MIGRATION] Error merging schemas:", + err + ) + } + } + + const schema = lexicographicSortSchema(exportedSchema) + return schema +} diff --git a/yarn.lock b/yarn.lock index be40ed1fbf..509a424e78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -971,6 +971,26 @@ dependencies: dependency-graph "0.8.1" +"@graphql-tools/batch-delegate@8.0.12": + version "8.0.12" + resolved "https://registry.yarnpkg.com/@graphql-tools/batch-delegate/-/batch-delegate-8.0.12.tgz#77089a6ff5ea4c31c7612e5555418fa3cf2e9146" + integrity sha512-ThqBdrL4dMSTKPLK7XHBg0Uv1JmqiL/oWEQ6/PLiTz6llwNzcK5s1CTTRgerwvRjCLyXiQnidMpdVQADp0jCQg== + dependencies: + "@graphql-tools/delegate" "^8.1.1" + "@graphql-tools/utils" "^8.1.2" + dataloader "2.0.0" + tslib "~2.3.0" + +"@graphql-tools/batch-execute@^8.0.5": + version "8.0.5" + resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-8.0.5.tgz#a0f8a9ff2c61209974c626faf3dd922a5c68d2b0" + integrity sha512-Zx+zs12BLGNvrQtfESIhitzwIkrWnKyKOkAfcaMNuOLGOO2pDmhwIRzbHj+6Jtq9V1/JTaVkSnm/4ozaCRck5A== + dependencies: + "@graphql-tools/utils" "^8.1.1" + dataloader "2.0.0" + tslib "~2.3.0" + value-or-promise "1.0.10" + "@graphql-tools/delegate@6.0.10": version "6.0.10" resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-6.0.10.tgz#f2fe8eea6cd5ce23f1e8f3dacfa6e136cad157da" @@ -981,6 +1001,55 @@ aggregate-error "3.0.1" tslib "~2.0.0" +"@graphql-tools/delegate@^8.1.0", "@graphql-tools/delegate@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-8.1.1.tgz#d20e6d81a2900b1c8a69c2c0a3a8a0df2f9030c2" + integrity sha512-Vttd0nfYTqRnRMKLvk8s4cIi9U+OMXGc9CMZAlKkHrBJ6dGXjdSM+4n3p9rfWZc/FtbVk1FnNS4IFyMeKwFuxA== + dependencies: + "@graphql-tools/batch-execute" "^8.0.5" + "@graphql-tools/schema" "^8.1.2" + "@graphql-tools/utils" "^8.1.2" + dataloader "2.0.0" + tslib "~2.3.0" + value-or-promise "1.0.10" + +"@graphql-tools/graphql-file-loader@^7.0.6": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.0.6.tgz#602a2013dc926e17542c979b8f9af45187329bcb" + integrity sha512-jndtcNwPUQxEiY/3FKNbAb4dpNXO8tXoDZzrnvv+z/tf27ViiZW0KUBkO4Mw4b0sqaDq+fS4d6BXzVFQQUPolA== + dependencies: + "@graphql-tools/import" "^6.2.6" + "@graphql-tools/utils" "^8.1.2" + globby "^11.0.3" + tslib "~2.3.0" + unixify "^1.0.0" + +"@graphql-tools/import@^6.2.6": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-6.3.1.tgz#731c47ab6c6ac9f7994d75c76b6c2fa127d2d483" + integrity sha512-1szR19JI6WPibjYurMLdadHKZoG9C//8I/FZ0Dt4vJSbrMdVNp8WFxg4QnZrDeMG4MzZc90etsyF5ofKjcC+jw== + dependencies: + resolve-from "5.0.0" + tslib "~2.2.0" + +"@graphql-tools/load@^7.1.9": + version "7.1.9" + resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-7.1.9.tgz#6bcff0a2866051ecdf514e6a8f82c2b4c0f5401d" + integrity sha512-4R0JLXRynPgHRWkGvL778XNH3IYX1sXjmEqGy3LPpJ4KR6woCO0us8oXNMAJMjjU4ZcOX6I8Jdj16G7qcHYTLA== + dependencies: + "@graphql-tools/schema" "8.1.2" + "@graphql-tools/utils" "^8.1.2" + p-limit "3.1.0" + tslib "~2.3.0" + +"@graphql-tools/merge@^8.0.2", "@graphql-tools/merge@^8.0.3": + version "8.0.3" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.0.3.tgz#56c844bc5d7d833456695c8e5eda4f1a0d5be873" + integrity sha512-lVMyW9cREs+nQYbUvMaaqSl+pRCezl2RafNMFi/04akjvOtjVefdi7n3pArpSqPhLHPJDyQRlI8CK8cmOZ9jTA== + dependencies: + "@graphql-tools/utils" "^8.1.2" + tslib "~2.3.0" + "@graphql-tools/schema@6.0.10": version "6.0.10" resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-6.0.10.tgz#69b36fad35ea5780f8539c92e776f9e83d929575" @@ -989,6 +1058,29 @@ "@graphql-tools/utils" "6.0.10" tslib "~2.0.0" +"@graphql-tools/schema@8.1.2", "@graphql-tools/schema@^8.1.2": + version "8.1.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.1.2.tgz#913879da1a7889a9488e9b7dc189e7c83eff74be" + integrity sha512-rX2pg42a0w7JLVYT+f/yeEKpnoZL5PpLq68TxC3iZ8slnNBNjfVfvzzOn8Q8Q6Xw3t17KP9QespmJEDfuQe4Rg== + dependencies: + "@graphql-tools/merge" "^8.0.2" + "@graphql-tools/utils" "^8.1.1" + tslib "~2.3.0" + value-or-promise "1.0.10" + +"@graphql-tools/stitch@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/stitch/-/stitch-8.2.1.tgz#19f174e642b6e4ae16064215706acd59d71f6520" + integrity sha512-QZ4qu++9XwrSVL51DpmwRSpPkdS7ScbyTkHOtudAwQv/rti6RP+qlAaRwMLao1WZfjZDnNJj/JeXqnPHjHTj8w== + dependencies: + "@graphql-tools/batch-delegate" "8.0.12" + "@graphql-tools/delegate" "^8.1.1" + "@graphql-tools/merge" "^8.0.3" + "@graphql-tools/schema" "^8.1.2" + "@graphql-tools/utils" "^8.1.2" + "@graphql-tools/wrap" "^8.0.13" + tslib "~2.3.0" + "@graphql-tools/utils@6.0.10": version "6.0.10" resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-6.0.10.tgz#ed15110a20acc5474a8dda5c0b99f970ba696c75" @@ -997,6 +1089,24 @@ aggregate-error "3.0.1" camel-case "4.1.1" +"@graphql-tools/utils@^8.1.1", "@graphql-tools/utils@^8.1.2": + version "8.1.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.1.2.tgz#a376259fafbca7532fda657e3abeec23b545e5d3" + integrity sha512-3G+NIBR5mHjPm78jAD0l07JRE0XH+lr9m7yL/wl69jAzK0Jr/H+/Ok4ljEolI70iglz+ZhIShVPAwyesF6rnFg== + dependencies: + tslib "~2.3.0" + +"@graphql-tools/wrap@^8.0.13": + version "8.0.13" + resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-8.0.13.tgz#17a4096efbc64e15b27a74135d920c8bd3e5385a" + integrity sha512-GTkHbN+Zgs+D7bFniFx3/YqNIDv8ET17prM7FewmU8LNRc2P48y6d4/dkQLcwQmryy1TZF87es6yA9FMNfQtWg== + dependencies: + "@graphql-tools/delegate" "^8.1.0" + "@graphql-tools/schema" "^8.1.2" + "@graphql-tools/utils" "^8.1.1" + tslib "~2.3.0" + value-or-promise "1.0.10" + "@heroku/foreman@2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@heroku/foreman/-/foreman-2.0.2.tgz#e24f8611bb0633ca89095648243d3a90564749fc" @@ -3428,6 +3538,11 @@ dataloader@1.3.0: resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.3.0.tgz#6fec5be4b30a712e4afd30b86b4334566b97673b" integrity sha1-b+xb5LMKcS5K/TC4a0M0VmuXZzs= +dataloader@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.0.0.tgz#41eaf123db115987e21ca93c005cd7753c55fe6f" + integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ== + date-fns@^1.27.2: version "1.29.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" @@ -4837,6 +4952,18 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globrex@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" @@ -7841,6 +7968,13 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-limit@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -8859,6 +8993,11 @@ resolve-cwd@^2.0.0: dependencies: resolve-from "^3.0.0" +resolve-from@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -9926,6 +10065,16 @@ tslib@~2.0.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3" integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g== +tslib@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + +tslib@~2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -10057,6 +10206,13 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +unixify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" + integrity sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA= + dependencies: + normalize-path "^2.1.1" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -10172,6 +10328,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +value-or-promise@1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.10.tgz#5bf041f1e9a8e7043911875547636768a836e446" + integrity sha512-1OwTzvcfXkAfabk60UVr5NdjtjJ0Fg0T5+B1bhxtrOEwSH2fe8y4DnLgoksfCyd8yZCOQQHB0qLMQnwgCjbXLQ== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -10413,6 +10574,11 @@ yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.1" +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zen-observable-ts@^0.8.19: version "0.8.19" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.19.tgz#c094cd20e83ddb02a11144a6e2a89706946b5694"