diff --git a/package.json b/package.json index 051249d43..1f38d03f2 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "clean": "tsc -b --clean packages", "format": "prettier **/**/*.ts --ignore-path ./.prettierignore --write", "lint": "eslint 'lib/**/*.ts' --fix", - "prepublish": "npm run build && npm run changelog | pbcopy", - "publish": "lerna publish --conventional-commits", + "prepublish:npm": "npm run build && npm run changelog | pbcopy", + "publish:npm": "lerna publish --conventional-commits", "prepublish:next": "npm run build", "publish:next": "lerna publish --dist-tag next", "test:e2e": "lerna run --parallel test:e2e", @@ -55,6 +55,7 @@ "husky": "7.0.4", "jest": "27.3.1", "lerna": "^4.0.0", + "lerna-changelog": "^2.2.0", "lint-staged": "11.2.3", "prettier": "2.4.1", "reflect-metadata": "0.1.13", @@ -67,55 +68,6 @@ "ts-node": "10.3.0", "typescript": "4.4.4" }, - "dependencies": { - "@graphql-tools/merge": "6.2.5", - "@graphql-tools/schema": "7.1.5", - "@graphql-tools/utils": "7.10.0", - "@nestjs/mapped-types": "1.0.0", - "chokidar": "3.5.2", - "fast-glob": "3.2.7", - "graphql-tag": "^2.12.5", - "graphql-ws": "5.5.1", - "iterall": "1.3.0", - "lodash": "4.17.21", - "normalize-path": "3.0.0", - "subscriptions-transport-ws": "0.9.19", - "tslib": "2.3.1", - "uuid": "8.3.2", - "ws": "8.2.3" - }, - "peerDependencies": { - "@apollo/gateway": "^0.29.0 || ^0.32.0 || ^0.33.0 || ^0.35.0 || ^0.38.0 || ^0.42.0", - "@apollo/subgraph": "^0.1.2", - "@nestjs/common": "^8.0.0", - "@nestjs/core": "^8.0.0", - "apollo-server-core": "^3.0.0", - "apollo-server-express": "^3.1.2", - "apollo-server-fastify": "^3.1.2", - "graphql": "^15.5.1", - "reflect-metadata": "^0.1.13", - "ts-morph": "^11.0.3 || ^12.0.0" - }, - "peerDependenciesMeta": { - "@apollo/gateway": { - "optional": true - }, - "@apollo/subgraph": { - "optional": true - }, - "apollo-server-core": { - "optional": true - }, - "apollo-server-express": { - "optional": true - }, - "apollo-server-fastify": { - "optional": true - }, - "ts-morph": { - "optional": true - } - }, "changelog": { "labels": { "type: feature :tada:": "Features", diff --git a/packages/graphql/lib/adapters/abstract-graphql.adapter.ts b/packages/graphql/lib/adapters/abstract-graphql.adapter.ts index fc332bc90..1460a7d2e 100644 --- a/packages/graphql/lib/adapters/abstract-graphql.adapter.ts +++ b/packages/graphql/lib/adapters/abstract-graphql.adapter.ts @@ -1,11 +1,13 @@ import { Inject } from '@nestjs/common'; import { ApplicationConfig, HttpAdapterHost } from '@nestjs/core'; +import { GraphQLTypesLoader } from '../graphql-types.loader'; +import { GraphQLFactory } from '../graphql.factory'; import { GqlModuleOptions } from '../interfaces'; import { wrapContextResolver } from '../utils'; export abstract class AbstractGraphQLAdapter< TDriver = unknown, - TOptions extends GqlModuleOptions = GqlModuleOptions, + TOptions extends Record = GqlModuleOptions, > { @Inject() protected readonly httpAdapterHost: HttpAdapterHost; @@ -13,6 +15,12 @@ export abstract class AbstractGraphQLAdapter< @Inject() protected readonly applicationConfig: ApplicationConfig; + @Inject() + protected readonly graphQlFactory: GraphQLFactory; + + @Inject() + protected readonly graphQlTypesLoader: GraphQLTypesLoader; + abstract get instance(): TDriver; public abstract start(options: TOptions): Promise; diff --git a/packages/graphql/lib/decorators/index.ts b/packages/graphql/lib/decorators/index.ts index 3509c05ef..8b9b85819 100644 --- a/packages/graphql/lib/decorators/index.ts +++ b/packages/graphql/lib/decorators/index.ts @@ -11,7 +11,6 @@ export * from './interface-type.decorator'; export * from './mutation.decorator'; export * from './object-type.decorator'; export * from './parent.decorator'; -export * from './plugin.decorator'; export * from './query.decorator'; export * from './resolve-field.decorator'; export * from './resolve-property.decorator'; diff --git a/packages/graphql/lib/decorators/plugin.decorator.ts b/packages/graphql/lib/decorators/plugin.decorator.ts deleted file mode 100644 index 9d55e1068..000000000 --- a/packages/graphql/lib/decorators/plugin.decorator.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { SetMetadata } from '@nestjs/common'; -import { PLUGIN_METADATA } from '../graphql.constants'; - -/** - * Decorator that marks a class as a Apollo plugin. - */ -export function Plugin(): ClassDecorator { - return (target: Function) => { - SetMetadata(PLUGIN_METADATA, true)(target); - }; -} diff --git a/packages/graphql/lib/decorators/resolve-reference.decorator.ts b/packages/graphql/lib/decorators/resolve-reference.decorator.ts index 8ea258656..73446fd8d 100644 --- a/packages/graphql/lib/decorators/resolve-reference.decorator.ts +++ b/packages/graphql/lib/decorators/resolve-reference.decorator.ts @@ -1,5 +1,5 @@ import { SetMetadata } from '@nestjs/common'; -import { RESOLVER_REFERENCE_METADATA } from '../federation/federation.constants'; +import { RESOLVER_REFERENCE_METADATA } from '../graphql.constants'; /** * Property reference resolver (method) Decorator. diff --git a/packages/graphql/lib/federation/federation.constants.ts b/packages/graphql/lib/federation/federation.constants.ts deleted file mode 100644 index a97959456..000000000 --- a/packages/graphql/lib/federation/federation.constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const GATEWAY_BUILD_SERVICE = 'graphql:gateway_build_service'; -export const RESOLVER_REFERENCE_KEY = '__resolveReference'; -export const RESOLVER_REFERENCE_METADATA = 'graphql:resolve_reference'; diff --git a/packages/graphql/lib/federation/graphql-federation.factory.ts b/packages/graphql/lib/federation/graphql-federation.factory.ts deleted file mode 100644 index baacadd6e..000000000 --- a/packages/graphql/lib/federation/graphql-federation.factory.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { mergeSchemas } from '@graphql-tools/merge'; -import { Injectable } from '@nestjs/common'; -import { loadPackage } from '@nestjs/common/utils/load-package.util'; -import { isString } from '@nestjs/common/utils/shared.utils'; -import { - GraphQLAbstractType, - GraphQLField, - GraphQLInputField, - GraphQLInputObjectType, - GraphQLInterfaceType, - GraphQLObjectType, - GraphQLResolveInfo, - GraphQLScalarType, - GraphQLSchema, - GraphQLUnionType, - isEnumType, - isInputObjectType, - isInterfaceType, - isObjectType, - isScalarType, - isUnionType, -} from 'graphql'; -import { gql } from 'graphql-tag'; -import { forEach, isEmpty } from 'lodash'; -import { GraphQLSchemaBuilder } from '../graphql-schema.builder'; -import { GraphQLSchemaHost } from '../graphql-schema.host'; -import { GqlModuleOptions } from '../interfaces'; -import { - PluginsExplorerService, - ResolversExplorerService, - ScalarsExplorerService, -} from '../services'; -import { extend } from '../utils'; -import { transformSchema } from '../utils/transform-schema.util'; - -@Injectable() -export class GraphQLFederationFactory { - constructor( - private readonly resolversExplorerService: ResolversExplorerService, - private readonly scalarsExplorerService: ScalarsExplorerService, - private readonly pluginsExplorerService: PluginsExplorerService, - private readonly gqlSchemaBuilder: GraphQLSchemaBuilder, - private readonly gqlSchemaHost: GraphQLSchemaHost, - ) {} - - async mergeOptions( - options: GqlModuleOptions = {}, - ): Promise { - const transformSchema = async (schema) => - options.transformSchema ? options.transformSchema(schema) : schema; - - options.plugins = extend( - options.plugins || [], - this.pluginsExplorerService.explore(), - ); - - let schema: GraphQLSchema; - if (options.autoSchemaFile) { - schema = await this.generateSchema(options); - } else if (isEmpty(options.typeDefs)) { - schema = options.schema; - } else { - schema = this.buildSchemaFromTypeDefs(options); - } - - this.gqlSchemaHost.schema = schema; - - return { - ...options, - schema: await transformSchema(schema), - typeDefs: undefined, - }; - } - - private buildSchemaFromTypeDefs(options: GqlModuleOptions) { - const { buildSubgraphSchema }: typeof import('@apollo/subgraph') = - loadPackage('@apollo/subgraph', 'ApolloFederation', () => - require('@apollo/subgraph'), - ); - - return buildSubgraphSchema([ - { - typeDefs: gql` - ${options.typeDefs} - `, - resolvers: this.getResolvers(options.resolvers), - }, - ]); - } - - private async generateSchema( - options: GqlModuleOptions, - ): Promise { - const { buildSubgraphSchema, printSubgraphSchema } = loadPackage( - '@apollo/subgraph', - 'ApolloFederation', - () => require('@apollo/subgraph'), - ); - - const autoGeneratedSchema: GraphQLSchema = - await this.gqlSchemaBuilder.buildFederatedSchema( - options.autoSchemaFile, - options, - this.resolversExplorerService.getAllCtors(), - ); - let executableSchema: GraphQLSchema = buildSubgraphSchema({ - typeDefs: gql(printSubgraphSchema(autoGeneratedSchema)), - resolvers: this.getResolvers(options.resolvers), - }); - - executableSchema = this.overrideOrExtendResolvers( - executableSchema, - autoGeneratedSchema, - ); - - const schema = options.schema - ? mergeSchemas({ - schemas: [options.schema, executableSchema], - }) - : executableSchema; - return schema; - } - - private getResolvers(optionResolvers: any) { - optionResolvers = Array.isArray(optionResolvers) - ? optionResolvers - : [optionResolvers]; - return this.extendResolvers([ - this.resolversExplorerService.explore(), - ...this.scalarsExplorerService.explore(), - ...optionResolvers, - ]); - } - - private extendResolvers(resolvers: any[]) { - return resolvers.reduce((prev, curr) => extend(prev, curr), {}); - } - - private overrideOrExtendResolvers( - executableSchema: GraphQLSchema, - autoGeneratedSchema: GraphQLSchema, - ): GraphQLSchema { - // Note: "transformSchema" from "apollo-graphql" cannot be used since it removes directives added by the "buildSubgraphSchema" function - // Ref issue: https://github.com/apollographql/apollo-server/issues/4106 - return transformSchema(executableSchema, (type) => { - if (isUnionType(type) && type.name !== '_Entity') { - return this.overrideFederatedResolveType(type, autoGeneratedSchema); - } else if (isInterfaceType(type)) { - return this.overrideFederatedResolveType(type, autoGeneratedSchema); - } else if (isEnumType(type)) { - return autoGeneratedSchema.getType(type.name); - } else if (isInputObjectType(type)) { - const autoGeneratedInputType = autoGeneratedSchema.getType( - type.name, - ) as GraphQLInputObjectType; - - if (!autoGeneratedInputType) { - return type; - } - const fields = type.getFields(); - forEach(fields, (value: GraphQLInputField, key: string) => { - const field = autoGeneratedInputType.getFields()[key]; - if (!field) { - return; - } - value.extensions = field.extensions; - value.astNode = field.astNode; - }); - type.extensions = autoGeneratedInputType.extensions; - return type; - } else if (isObjectType(type)) { - const autoGeneratedObjectType = autoGeneratedSchema.getType( - type.name, - ) as GraphQLObjectType; - - if (!autoGeneratedObjectType) { - return type; - } - const fields = type.getFields(); - forEach( - fields, - (value: GraphQLField, key: string) => { - const field = autoGeneratedObjectType.getFields()[key]; - if (!field) { - return; - } - value.extensions = field.extensions; - value.astNode = field.astNode; - - if (!value.resolve) { - value.resolve = field.resolve; - } - }, - ); - type.extensions = autoGeneratedObjectType.extensions; - return type; - } else if (isScalarType(type) && type.name === 'DateTime') { - const autoGeneratedScalar = autoGeneratedSchema.getType( - type.name, - ) as GraphQLScalarType; - - if (!autoGeneratedScalar) { - return type; - } - type.parseLiteral = autoGeneratedScalar.parseLiteral; - type.parseValue = autoGeneratedScalar.parseValue; - return type; - } - return type; - }); - } - - /** - * Ensures that the resolveType method for unions and interfaces in the federated schema - * is properly set from the one in the autoGeneratedSchema. - */ - private overrideFederatedResolveType( - typeInFederatedSchema: GraphQLUnionType | GraphQLInterfaceType, - autoGeneratedSchema: GraphQLSchema, - ): GraphQLUnionType | GraphQLInterfaceType { - // Get the matching type from the auto generated schema - const autoGeneratedType = autoGeneratedSchema.getType( - typeInFederatedSchema.name, - ); - // Bail if inconsistent with original schema - if ( - !autoGeneratedType || - !( - autoGeneratedType instanceof GraphQLUnionType || - autoGeneratedType instanceof GraphQLInterfaceType - ) || - !autoGeneratedType.resolveType - ) { - return typeInFederatedSchema; - } - - typeInFederatedSchema.resolveType = async ( - value: unknown, - context: unknown, - info: GraphQLResolveInfo, - abstractType: GraphQLAbstractType, - ) => { - const resultFromAutogenSchema = await autoGeneratedType.resolveType( - value, - context, - info, - abstractType, - ); - // If the result is not a GraphQLObjectType we're fine - if (!resultFromAutogenSchema || isString(resultFromAutogenSchema)) { - return resultFromAutogenSchema; - } - // We now have a GraphQLObjectType from the original union in the autogenerated schema. - // But we can't return that without the additional federation property apollo adds to object - // types (see node_modules/@apollo/federation/src/composition/types.ts:47). - // Without that property, Apollo will ignore the returned type and the - // union value will resolve to null. So we need to return the type with - // the same name from the federated schema - const resultFromFederatedSchema = info.schema.getType( - resultFromAutogenSchema.name, - ); - if ( - resultFromFederatedSchema && - resultFromFederatedSchema instanceof GraphQLObjectType - ) { - return resultFromFederatedSchema; - } - // If we couldn't find a match in the federated schema, return just the - // name of the type and hope apollo works it out - return resultFromAutogenSchema.name; - }; - return typeInFederatedSchema; - } -} diff --git a/packages/graphql/lib/federation/graphql-federation.module.ts b/packages/graphql/lib/federation/graphql-federation.module.ts deleted file mode 100644 index d063a004e..000000000 --- a/packages/graphql/lib/federation/graphql-federation.module.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { - DynamicModule, - Inject, - Module, - OnModuleDestroy, - OnModuleInit, - Optional, - Provider, -} from '@nestjs/common'; -import { loadPackage } from '@nestjs/common/utils/load-package.util'; -import { HttpAdapterHost } from '@nestjs/core'; -import { MetadataScanner } from '@nestjs/core/metadata-scanner'; -import { AbstractGraphQLAdapter } from '../adapters'; -import { GraphQLAstExplorer } from '../graphql-ast.explorer'; -import { GraphQLSchemaBuilder } from '../graphql-schema.builder'; -import { GraphQLSchemaHost } from '../graphql-schema.host'; -import { GraphQLTypesLoader } from '../graphql-types.loader'; -import { - GRAPHQL_MODULE_ID, - GRAPHQL_MODULE_OPTIONS, -} from '../graphql.constants'; -import { GraphQLFactory } from '../graphql.factory'; -import { - GqlModuleAsyncOptions, - GqlModuleOptions, - GqlOptionsFactory, -} from '../interfaces'; -import { GraphQLSchemaBuilderModule } from '../schema-builder/schema-builder.module'; -import { - PluginsExplorerService, - ResolversExplorerService, - ScalarsExplorerService, -} from '../services'; -import { extend, generateString } from '../utils'; -import { GraphQLFederationFactory } from './graphql-federation.factory'; - -@Module({ - imports: [GraphQLSchemaBuilderModule], - providers: [ - GraphQLFederationFactory, - GraphQLFactory, - MetadataScanner, - ResolversExplorerService, - PluginsExplorerService, - ScalarsExplorerService, - GraphQLAstExplorer, - GraphQLTypesLoader, - GraphQLSchemaBuilder, - GraphQLSchemaHost, - ], - exports: [GraphQLSchemaHost, GraphQLTypesLoader, GraphQLAstExplorer], -}) -export class GraphQLFederationModule - implements OnModuleInit, OnModuleDestroy -{ - get graphQlAdapter(): AbstractGraphQLAdapter { - return this._graphQlAdapter; - } - - constructor( - @Optional() - private readonly httpAdapterHost: HttpAdapterHost, - @Inject(GRAPHQL_MODULE_OPTIONS) - private readonly options: GqlModuleOptions, - private readonly graphqlFederationFactory: GraphQLFederationFactory, - private readonly graphqlTypesLoader: GraphQLTypesLoader, - private readonly graphqlFactory: GraphQLFactory, - private readonly _graphQlAdapter: AbstractGraphQLAdapter, - ) {} - - static forRoot(options: GqlModuleOptions = {}): DynamicModule { - return { - module: GraphQLFederationModule, - providers: [ - { - provide: GRAPHQL_MODULE_OPTIONS, - useValue: options, - }, - { - provide: AbstractGraphQLAdapter, - // @todo - useClass: options.adapter || (AbstractGraphQLAdapter as any), - }, - ], - }; - } - - static forRootAsync(options: GqlModuleAsyncOptions): DynamicModule { - return { - module: GraphQLFederationModule, - imports: options.imports, - providers: [ - ...this.createAsyncProviders(options), - { - provide: GRAPHQL_MODULE_ID, - useValue: generateString(), - }, - { - provide: AbstractGraphQLAdapter, - // @todo - useClass: options.adapter || (AbstractGraphQLAdapter as any), - }, - ], - }; - } - - private static createAsyncProviders( - options: GqlModuleAsyncOptions, - ): Provider[] { - if (options.useExisting || options.useFactory) { - return [this.createAsyncOptionsProvider(options)]; - } - - return [ - this.createAsyncOptionsProvider(options), - { - provide: options.useClass, - useClass: options.useClass, - }, - ]; - } - - private static createAsyncOptionsProvider( - options: GqlModuleAsyncOptions, - ): Provider { - if (options.useFactory) { - return { - provide: GRAPHQL_MODULE_OPTIONS, - useFactory: async (...args: any[]) => await options.useFactory(...args), - inject: options.inject || [], - }; - } - - return { - provide: GRAPHQL_MODULE_OPTIONS, - useFactory: async (optionsFactory: GqlOptionsFactory) => - await optionsFactory.createGqlOptions(), - inject: [options.useExisting || options.useClass], - }; - } - - async onModuleInit() { - if (!this.httpAdapterHost || !this.httpAdapterHost.httpAdapter) { - return; - } - const { printSubgraphSchema } = loadPackage( - '@apollo/subgraph', - 'ApolloFederation', - () => require('@apollo/subgraph'), - ); - const options = await this._graphQlAdapter.mergeDefaultOptions( - this.options, - ); - - const { typePaths } = options; - const typeDefs = - (await this.graphqlTypesLoader.mergeTypesByPaths(typePaths)) || []; - - const mergedTypeDefs = extend(typeDefs, options.typeDefs); - const adapterOptions = await this.graphqlFederationFactory.mergeOptions({ - ...options, - typeDefs: mergedTypeDefs, - }); - await this._graphQlAdapter.runPreOptionsHooks(adapterOptions); - - if (options.definitions && options.definitions.path) { - await this.graphqlFactory.generateDefinitions( - printSubgraphSchema(adapterOptions.schema), - options, - ); - } - - await this._graphQlAdapter.start(adapterOptions); - - if (options.installSubscriptionHandlers || options.subscriptions) { - // TL;DR - throw new Error( - 'No support for subscriptions yet when using Apollo Federation', - ); - } - } - - async onModuleDestroy() { - await this._graphQlAdapter?.stop(); - } -} diff --git a/packages/graphql/lib/federation/graphql-gateway.module.ts b/packages/graphql/lib/federation/graphql-gateway.module.ts deleted file mode 100644 index 9b66af5a4..000000000 --- a/packages/graphql/lib/federation/graphql-gateway.module.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { - DynamicModule, - Inject, - Module, - OnModuleDestroy, - OnModuleInit, - Optional, - Provider, -} from '@nestjs/common'; -import { loadPackage } from '@nestjs/common/utils/load-package.util'; -import { HttpAdapterHost } from '@nestjs/core'; -import { GATEWAY_BUILD_SERVICE } from '.'; -import { AbstractGraphQLAdapter } from '../adapters'; -import { - GRAPHQL_MODULE_ID, - GRAPHQL_MODULE_OPTIONS, -} from '../graphql.constants'; -import { - GatewayBuildService, - GatewayModuleAsyncOptions, - GatewayModuleOptions, - GatewayOptionsFactory, -} from '../interfaces'; -import { generateString } from '../utils'; - -@Module({}) -export class GraphQLGatewayModule implements OnModuleInit, OnModuleDestroy { - get graphQlAdapter(): AbstractGraphQLAdapter { - return this._graphQlAdapter; - } - - constructor( - @Optional() - private readonly httpAdapterHost: HttpAdapterHost, - @Optional() - @Inject(GATEWAY_BUILD_SERVICE) - private readonly buildService: GatewayBuildService, - @Inject(GRAPHQL_MODULE_OPTIONS) - private readonly options: GatewayModuleOptions, - private readonly _graphQlAdapter: AbstractGraphQLAdapter, - ) {} - - static forRoot(options: GatewayModuleOptions): DynamicModule { - return { - module: GraphQLGatewayModule, - providers: [ - { - provide: GRAPHQL_MODULE_OPTIONS, - useValue: options, - }, - { - provide: AbstractGraphQLAdapter, - // @todo - useClass: options.adapter || (AbstractGraphQLAdapter as any), - }, - ], - }; - } - - static forRootAsync(options: GatewayModuleAsyncOptions): DynamicModule { - return { - module: GraphQLGatewayModule, - imports: options.imports, - providers: [ - ...this.createAsyncProviders(options), - { - provide: GRAPHQL_MODULE_ID, - useValue: generateString(), - }, - { - provide: AbstractGraphQLAdapter, - // @todo - useClass: options.adapter || (AbstractGraphQLAdapter as any), - }, - ], - }; - } - - private static createAsyncProviders( - options: GatewayModuleAsyncOptions, - ): Provider[] { - if (options.useExisting || options.useFactory) { - return [this.createAsyncOptionsProvider(options)]; - } - - return [ - this.createAsyncOptionsProvider(options), - { - provide: options.useClass, - useClass: options.useClass, - }, - ]; - } - - private static createAsyncOptionsProvider( - options: GatewayModuleAsyncOptions, - ): Provider { - if (options.useFactory) { - return { - provide: GRAPHQL_MODULE_OPTIONS, - useFactory: options.useFactory, - inject: options.inject || [], - }; - } - - return { - provide: GRAPHQL_MODULE_OPTIONS, - useFactory: (optionsFactory: GatewayOptionsFactory) => - optionsFactory.createGatewayOptions(), - inject: [options.useExisting || options.useClass], - }; - } - - async onModuleInit() { - const { httpAdapter } = this.httpAdapterHost || {}; - if (!httpAdapter) { - return; - } - - const { ApolloGateway } = loadPackage( - '@apollo/gateway', - 'ApolloGateway', - () => require('@apollo/gateway'), - ); - const { - options: { server: serverOpts = {}, gateway: gatewayOpts = {} }, - buildService, - } = this; - - const gateway = new ApolloGateway({ - ...gatewayOpts, - buildService, - }); - - await this._graphQlAdapter.start({ - ...serverOpts, - gateway, - subscriptions: undefined, - }); - - if (serverOpts.installSubscriptionHandlers) { - // TL;DR - throw new Error( - 'No support for subscriptions yet when using Apollo Federation', - ); - } - } - - async onModuleDestroy() { - await this._graphQlAdapter?.stop(); - } -} diff --git a/packages/graphql/lib/federation/index.ts b/packages/graphql/lib/federation/index.ts deleted file mode 100644 index a13eb40f0..000000000 --- a/packages/graphql/lib/federation/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { GATEWAY_BUILD_SERVICE } from './federation.constants'; -export * from './graphql-federation.factory'; -export * from './graphql-federation.module'; -export * from './graphql-gateway.module'; diff --git a/packages/graphql/lib/graphql.constants.ts b/packages/graphql/lib/graphql.constants.ts index 7b6d180ea..450a8f245 100644 --- a/packages/graphql/lib/graphql.constants.ts +++ b/packages/graphql/lib/graphql.constants.ts @@ -6,11 +6,13 @@ export const FIELD_RESOLVER_MIDDLEWARE_METADATA = export const RESOLVER_DELEGATE_METADATA = 'graphql:delegate_property'; export const SCALAR_NAME_METADATA = 'graphql:scalar_name'; export const SCALAR_TYPE_METADATA = 'graphql:scalar_type'; -export const PLUGIN_METADATA = 'graphql:plugin'; export const PARAM_ARGS_METADATA = '__routeArguments__'; export const SUBSCRIPTION_OPTIONS_METADATA = 'graphql:subscription_options;'; export const CLASS_TYPE_METADATA = 'graphql:class_type'; +export const RESOLVER_REFERENCE_KEY = '__resolveReference'; +export const RESOLVER_REFERENCE_METADATA = 'graphql:resolve_reference'; + export const FIELD_TYPENAME = '__resolveType'; export const GRAPHQL_MODULE_OPTIONS = 'GqlModuleOptions'; export const GRAPHQL_MODULE_ID = 'GqlModuleId'; diff --git a/packages/graphql/lib/graphql.factory.ts b/packages/graphql/lib/graphql.factory.ts index 15491de0b..71c0fccb8 100644 --- a/packages/graphql/lib/graphql.factory.ts +++ b/packages/graphql/lib/graphql.factory.ts @@ -20,11 +20,7 @@ import { import { GraphQLSchemaBuilder } from './graphql-schema.builder'; import { GraphQLSchemaHost } from './graphql-schema.host'; import { GqlModuleOptions } from './interfaces'; -import { - PluginsExplorerService, - ResolversExplorerService, - ScalarsExplorerService, -} from './services'; +import { ResolversExplorerService, ScalarsExplorerService } from './services'; import { extend, removeTempField } from './utils'; @Injectable() @@ -32,24 +28,19 @@ export class GraphQLFactory { constructor( private readonly resolversExplorerService: ResolversExplorerService, private readonly scalarsExplorerService: ScalarsExplorerService, - private readonly pluginsExplorerService: PluginsExplorerService, private readonly graphqlAstExplorer: GraphQLAstExplorer, private readonly gqlSchemaBuilder: GraphQLSchemaBuilder, private readonly gqlSchemaHost: GraphQLSchemaHost, ) {} - async mergeOptions( - options: GqlModuleOptions = { typeDefs: [] }, - ): Promise { + async mergeOptions( + options: T = { typeDefs: [] } as T, + ): Promise { const resolvers = this.resolversExplorerService.explore(); const typesResolvers = extend( this.scalarsExplorerService.explore(), resolvers, ); - options.plugins = extend( - options.plugins || [], - this.pluginsExplorerService.explore(), - ); const transformSchema = async (schema: GraphQLSchema) => options.transformSchema ? await options.transformSchema(schema) : schema; diff --git a/packages/graphql/lib/graphql.module.ts b/packages/graphql/lib/graphql.module.ts index 5f7fee602..c46f938be 100644 --- a/packages/graphql/lib/graphql.module.ts +++ b/packages/graphql/lib/graphql.module.ts @@ -7,28 +7,21 @@ import { } from '@nestjs/common/interfaces'; import { HttpAdapterHost } from '@nestjs/core'; import { MetadataScanner } from '@nestjs/core/metadata-scanner'; -import { printSchema } from 'graphql'; import { AbstractGraphQLAdapter } from '.'; import { GraphQLAstExplorer } from './graphql-ast.explorer'; import { GraphQLSchemaBuilder } from './graphql-schema.builder'; import { GraphQLSchemaHost } from './graphql-schema.host'; import { GraphQLTypesLoader } from './graphql-types.loader'; -import { GraphQLSubscriptionService } from './graphql-ws/graphql-subscription.service'; import { GRAPHQL_MODULE_ID, GRAPHQL_MODULE_OPTIONS } from './graphql.constants'; import { GraphQLFactory } from './graphql.factory'; import { GqlModuleAsyncOptions, GqlModuleOptions, GqlOptionsFactory, - SubscriptionConfig, } from './interfaces/gql-module-options.interface'; import { GraphQLSchemaBuilderModule } from './schema-builder/schema-builder.module'; -import { - PluginsExplorerService, - ResolversExplorerService, - ScalarsExplorerService, -} from './services'; -import { extend, generateString } from './utils'; +import { ResolversExplorerService, ScalarsExplorerService } from './services'; +import { generateString } from './utils'; @Module({ imports: [GraphQLSchemaBuilderModule], @@ -37,7 +30,6 @@ import { extend, generateString } from './utils'; MetadataScanner, ResolversExplorerService, ScalarsExplorerService, - PluginsExplorerService, GraphQLAstExplorer, GraphQLTypesLoader, GraphQLSchemaBuilder, @@ -45,22 +37,20 @@ import { extend, generateString } from './utils'; ], exports: [GraphQLTypesLoader, GraphQLAstExplorer, GraphQLSchemaHost], }) -export class GraphQLModule implements OnModuleInit, OnModuleDestroy { - private _subscriptionService?: GraphQLSubscriptionService; - - get graphQlAdapter(): AbstractGraphQLAdapter { +export class GraphQLModule implements OnModuleInit, OnModuleDestroy { + get graphQlAdapter(): AbstractGraphQLAdapter { return this._graphQlAdapter; } constructor( private readonly httpAdapterHost: HttpAdapterHost, @Inject(GRAPHQL_MODULE_OPTIONS) private readonly options: GqlModuleOptions, - private readonly graphQlFactory: GraphQLFactory, - private readonly graphQlTypesLoader: GraphQLTypesLoader, - private readonly _graphQlAdapter: AbstractGraphQLAdapter, + private readonly _graphQlAdapter: AbstractGraphQLAdapter, ) {} - static forRoot(options: GqlModuleOptions = {}): DynamicModule { + static forRoot = GqlModuleOptions>( + options: TOptions = {} as TOptions, + ): DynamicModule { return { module: GraphQLModule, providers: [ @@ -70,14 +60,15 @@ export class GraphQLModule implements OnModuleInit, OnModuleDestroy { }, { provide: AbstractGraphQLAdapter, - // @todo - useClass: options.adapter || (AbstractGraphQLAdapter as any), + useClass: options.adapter, }, ], }; } - static forRootAsync(options: GqlModuleAsyncOptions): DynamicModule { + static forRootAsync = GqlModuleOptions>( + options: GqlModuleAsyncOptions>, + ): DynamicModule { return { module: GraphQLModule, imports: options.imports, @@ -89,16 +80,15 @@ export class GraphQLModule implements OnModuleInit, OnModuleDestroy { }, { provide: AbstractGraphQLAdapter, - // @todo - useClass: options?.adapter || (AbstractGraphQLAdapter as any), + useClass: options.adapter, }, ], }; } - private static createAsyncProviders( - options: GqlModuleAsyncOptions, - ): Provider[] { + private static createAsyncProviders< + TOptions extends Record = GqlModuleOptions, + >(options: GqlModuleAsyncOptions): Provider[] { if (options.useExisting || options.useFactory) { return [this.createAsyncOptionsProvider(options)]; } @@ -111,9 +101,9 @@ export class GraphQLModule implements OnModuleInit, OnModuleDestroy { ]; } - private static createAsyncOptionsProvider( - options: GqlModuleAsyncOptions, - ): Provider { + private static createAsyncOptionsProvider< + TOptions extends Record = GqlModuleOptions, + >(options: GqlModuleAsyncOptions): Provider { if (options.useFactory) { return { provide: GRAPHQL_MODULE_OPTIONS, @@ -134,45 +124,10 @@ export class GraphQLModule implements OnModuleInit, OnModuleDestroy { if (!httpAdapter) { return; } - const options = await this._graphQlAdapter.mergeDefaultOptions( - this.options, - ); - const typeDefs = - (await this.graphQlTypesLoader.mergeTypesByPaths(options.typePaths)) || - []; - - const mergedTypeDefs = extend(typeDefs, options.typeDefs); - const adapterOptions = await this.graphQlFactory.mergeOptions({ - ...options, - typeDefs: mergedTypeDefs, - }); - await this._graphQlAdapter.runPreOptionsHooks(adapterOptions); - - if (options.definitions && options.definitions.path) { - await this.graphQlFactory.generateDefinitions( - printSchema(adapterOptions.schema), - options, - ); - } - - await this._graphQlAdapter.start(adapterOptions); - if (options.installSubscriptionHandlers || options.subscriptions) { - const subscriptionsOptions: SubscriptionConfig = - options.subscriptions || { 'subscriptions-transport-ws': {} }; - this._subscriptionService = new GraphQLSubscriptionService( - { - schema: adapterOptions.schema, - path: options.path, - context: options.context, - ...subscriptionsOptions, - }, - httpAdapter.getHttpServer(), - ); - } + await this._graphQlAdapter.start(this.options); } async onModuleDestroy() { - await this._subscriptionService?.stop(); await this._graphQlAdapter.stop(); } } diff --git a/packages/graphql/lib/index.ts b/packages/graphql/lib/index.ts index 5c3b82d62..3fb5da39d 100644 --- a/packages/graphql/lib/index.ts +++ b/packages/graphql/lib/index.ts @@ -1,6 +1,5 @@ export * from './adapters'; export * from './decorators'; -export * from './federation'; export * from './graphql-ast.explorer'; export * from './graphql-definitions.factory'; export * from './graphql-schema.host'; @@ -12,6 +11,7 @@ export * from './scalars'; export * from './schema-builder'; export * from './services/gql-arguments-host'; export * from './services/gql-execution-context'; +export * from './services/gql-subscription.service'; export * from './tokens'; export * from './type-factories'; export * from './type-helpers'; diff --git a/packages/graphql/lib/interfaces/gql-gateway-module-options.interface.ts b/packages/graphql/lib/interfaces/gql-gateway-module-options.interface.ts deleted file mode 100644 index fba8f1736..000000000 --- a/packages/graphql/lib/interfaces/gql-gateway-module-options.interface.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { GatewayConfig, ServiceEndpointDefinition } from '@apollo/gateway'; -import { GraphQLDataSource } from '@apollo/gateway/dist/datasources/types'; -import { Type } from '@nestjs/common'; -import { ModuleMetadata } from '@nestjs/common/interfaces'; -import { GqlModuleOptions } from './gql-module-options.interface'; - -export interface GatewayModuleOptions { - gateway?: GatewayConfig; - server?: Omit< - GqlModuleOptions, - | 'typeDefs' - | 'typePaths' - | 'include' - | 'resolvers' - | 'resolverValidationOptions' - | 'directiveResolvers' - | 'autoSchemaFile' - | 'transformSchema' - | 'definitions' - | 'schema' - | 'subscriptions' - | 'schemaDirectives' - | 'buildSchemaOptions' - | 'fieldResolverEnhancers' - | 'adapter' - >; - adapter?: GqlModuleOptions['adapter']; -} - -export interface GatewayOptionsFactory { - createGatewayOptions(): - | Promise> - | Omit; -} - -export interface GatewayModuleAsyncOptions - extends Pick { - adapter?: GqlModuleOptions['adapter']; - useExisting?: Type; - useClass?: Type; - useFactory?: ( - ...args: any[] - ) => - | Promise> - | Omit; - inject?: any[]; -} - -export type GatewayBuildService = ( - definition: ServiceEndpointDefinition, -) => GraphQLDataSource; diff --git a/packages/graphql/lib/interfaces/gql-module-options.interface.ts b/packages/graphql/lib/interfaces/gql-module-options.interface.ts index c370cbd1c..29fa99a82 100644 --- a/packages/graphql/lib/interfaces/gql-module-options.interface.ts +++ b/packages/graphql/lib/interfaces/gql-module-options.interface.ts @@ -1,131 +1,135 @@ import { ExecutableSchemaTransformation } from '@graphql-tools/schema'; -import { IResolverValidationOptions } from '@graphql-tools/utils'; +import { IResolvers, IResolverValidationOptions } from '@graphql-tools/utils'; import { Type } from '@nestjs/common'; import { ModuleMetadata } from '@nestjs/common/interfaces'; -import { - ApolloServerPluginLandingPageGraphQLPlaygroundOptions, - Config, - GraphQLExecutor, -} from 'apollo-server-core'; import { GraphQLSchema } from 'graphql'; -import { ServerOptions } from 'graphql-ws'; -import { ServerOptions as SubscriptionTransportWsServerOptions } from 'subscriptions-transport-ws'; -import { AbstractGraphQLAdapter } from '..'; +import { AbstractGraphQLAdapter } from '../adapters/abstract-graphql.adapter'; import { DefinitionsGeneratorOptions } from '../graphql-ast.explorer'; import { BuildSchemaOptions } from './build-schema-options.interface'; -export interface ServerRegistration { - path?: string; - cors?: any | boolean; - bodyParserConfig?: any | boolean; - onHealthCheck?: (req: any) => Promise; - disableHealthCheck?: boolean; -} - -export type Omit = Pick>; - -export type GraphQLWsSubscriptionsConfig = Partial< - Pick< - ServerOptions, - | 'connectionInitWaitTimeout' - | 'onConnect' - | 'onDisconnect' - | 'onClose' - | 'onSubscribe' - | 'onNext' - > -> & { - path?: string; -}; - -export type GraphQLSubscriptionTransportWsConfig = Partial< - Pick< - SubscriptionTransportWsServerOptions, - 'onConnect' | 'onDisconnect' | 'keepAlive' - > -> & { - path?: string; -}; - -export type SubscriptionConfig = { - 'graphql-ws'?: GraphQLWsSubscriptionsConfig | boolean; - 'subscriptions-transport-ws'?: GraphQLSubscriptionTransportWsConfig | boolean; -}; - export type Enhancer = 'guards' | 'interceptors' | 'filters'; -export interface GqlModuleOptions - extends Omit, - Partial { + +/** + * "GraphQLModule" options object. + */ +export interface GqlModuleOptions { + /** + * Type definitions + */ typeDefs?: string | string[]; - typePaths?: string[]; + + /** + * GraphQL server adapter + */ + adapter?: Type; + + /** + * An array of modules to scan when searching for resolvers + */ include?: Function[]; - executorFactory?: ( - schema: GraphQLSchema, - ) => GraphQLExecutor | Promise; - installSubscriptionHandlers?: boolean; - subscriptions?: SubscriptionConfig; - resolverValidationOptions?: IResolverValidationOptions; - directiveResolvers?: any; + + /** + * Schema directives mapping + */ schemaDirectives?: Record; + + /** + * Directive resolvers + */ + directiveResolvers?: any; + + /** + * Optional GraphQL schema (to be used or to be merged) + */ + schema?: GraphQLSchema; + + /** + * Extra resolvers to be registered. + */ + resolvers?: IResolvers | Array; + + /** + * An array of executable schema transformations + */ schemaTransforms?: ExecutableSchemaTransformation[]; - transformSchema?: ( - schema: GraphQLSchema, - ) => GraphQLSchema | Promise; - playground?: boolean | ApolloServerPluginLandingPageGraphQLPlaygroundOptions; + + /** + * TypeScript definitions generator options + */ definitions?: { path?: string; outputAs?: 'class' | 'interface'; } & DefinitionsGeneratorOptions; + + /** + * If enabled, GraphQL schema will be generated automatically + */ autoSchemaFile?: string | boolean; + + /** + * Sort the schema lexicographically + */ + sortSchema?: boolean; + + /** + * Options to be passed to the schema generator + * Only applicable if "autoSchemaFile" = true + */ buildSchemaOptions?: BuildSchemaOptions; + /** * Prepends the global prefix to the url * * @see [faq/global-prefix](Global Prefix) */ useGlobalPrefix?: boolean; + /** * Enable/disable enhancers for @ResolveField() */ fieldResolverEnhancers?: Enhancer[]; + /** - * Sort the schema lexicographically + * Resolver validation options. */ - sortSchema?: boolean; + resolverValidationOptions?: IResolverValidationOptions; + /** - * Apply `transformSchema` to the `autoSchemaFile` + * Function to be applied to the schema letting you register custom transformations. */ - transformAutoSchemaFile?: boolean; + transformSchema?: ( + schema: GraphQLSchema, + ) => GraphQLSchema | Promise; + /** - * If enabled, will register a global interceptor that automatically maps - * "HttpException" class instances to corresponding Apollo errors. - * @default true + * Apply `transformSchema` to the `autoSchemaFile` */ - autoTransformHttpErrors?: boolean; + transformAutoSchemaFile?: boolean; + /** - * GraphQL server adapter + * Context function */ - adapter?: Type; + context?: any; } -export interface GqlOptionsFactory { - createGqlOptions(): - | Promise> - | Omit; +export interface GqlOptionsFactory< + T extends Record = GqlModuleOptions, +> { + createGqlOptions(): Promise> | Omit; } -export interface GqlModuleAsyncOptions extends Pick { +export interface GqlModuleAsyncOptions< + TOptions extends Record = GqlModuleOptions, + TFactory = GqlOptionsFactory, +> extends Pick { /** * GraphQL server adapter */ - adapter?: Type; - - useExisting?: Type; - useClass?: Type; + adapter?: TOptions['adapter']; + useExisting?: Type; + useClass?: Type; useFactory?: ( ...args: any[] - ) => - | Promise> - | Omit; + ) => Promise> | Omit; inject?: any[]; } diff --git a/packages/graphql/lib/interfaces/index.ts b/packages/graphql/lib/interfaces/index.ts index 5a55b4771..c25e6e5c8 100644 --- a/packages/graphql/lib/interfaces/index.ts +++ b/packages/graphql/lib/interfaces/index.ts @@ -4,7 +4,6 @@ export * from './complexity.interface'; export * from './custom-scalar.interface'; export * from './field-middleware.interface'; export * from './gql-exception-filter.interface'; -export * from './gql-gateway-module-options.interface'; export { Enhancer, GqlModuleAsyncOptions, diff --git a/packages/graphql/lib/graphql-ws/graphql-subscription.service.ts b/packages/graphql/lib/services/gql-subscription.service.ts similarity index 75% rename from packages/graphql/lib/graphql-ws/graphql-subscription.service.ts rename to packages/graphql/lib/services/gql-subscription.service.ts index db31c2993..705254d45 100644 --- a/packages/graphql/lib/graphql-ws/graphql-subscription.service.ts +++ b/packages/graphql/lib/services/gql-subscription.service.ts @@ -1,26 +1,53 @@ import { execute, GraphQLSchema, subscribe } from 'graphql'; import { GRAPHQL_TRANSPORT_WS_PROTOCOL, ServerOptions } from 'graphql-ws'; import { useServer } from 'graphql-ws/lib/use/ws'; -import { GRAPHQL_WS, SubscriptionServer } from 'subscriptions-transport-ws'; -import * as ws from 'ws'; import { - GraphQLSubscriptionTransportWsConfig, - GraphQLWsSubscriptionsConfig, - SubscriptionConfig, -} from '../interfaces/gql-module-options.interface'; + GRAPHQL_WS, + ServerOptions as SubscriptionTransportWsServerOptions, + SubscriptionServer, +} from 'subscriptions-transport-ws'; +import * as ws from 'ws'; + +export type GraphQLWsSubscriptionsConfig = Partial< + Pick< + ServerOptions, + | 'connectionInitWaitTimeout' + | 'onConnect' + | 'onDisconnect' + | 'onClose' + | 'onSubscribe' + | 'onNext' + > +> & { + path?: string; +}; + +export type GraphQLSubscriptionTransportWsConfig = Partial< + Pick< + SubscriptionTransportWsServerOptions, + 'onConnect' | 'onDisconnect' | 'keepAlive' + > +> & { + path?: string; +}; + +export type SubscriptionConfig = { + 'graphql-ws'?: GraphQLWsSubscriptionsConfig | boolean; + 'subscriptions-transport-ws'?: GraphQLSubscriptionTransportWsConfig | boolean; +}; -export interface GraphQLSubscriptionServiceOptions extends SubscriptionConfig { +export interface GqlSubscriptionServiceOptions extends SubscriptionConfig { schema: GraphQLSchema; path?: string; context?: ServerOptions['context']; } -export class GraphQLSubscriptionService { +export class GqlSubscriptionService { private readonly wss: ws.Server; private readonly subTransWs: ws.Server; constructor( - private readonly options: GraphQLSubscriptionServiceOptions, + private readonly options: GqlSubscriptionServiceOptions, private readonly httpServer: any, ) { this.wss = new ws.Server({ diff --git a/packages/graphql/lib/services/index.ts b/packages/graphql/lib/services/index.ts index 721ea1128..4657ba4c9 100644 --- a/packages/graphql/lib/services/index.ts +++ b/packages/graphql/lib/services/index.ts @@ -1,6 +1,6 @@ export * from './base-explorer.service'; export * from './gql-arguments-host'; export * from './gql-execution-context'; -export * from './plugins-explorer.service'; +export * from './gql-subscription.service'; export * from './resolvers-explorer.service'; export * from './scalars-explorer.service'; diff --git a/packages/graphql/lib/services/plugins-explorer.service.ts b/packages/graphql/lib/services/plugins-explorer.service.ts deleted file mode 100644 index efd37ab4d..000000000 --- a/packages/graphql/lib/services/plugins-explorer.service.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper'; -import { ModulesContainer } from '@nestjs/core/injector/modules-container'; -import { GRAPHQL_MODULE_OPTIONS, PLUGIN_METADATA } from '../graphql.constants'; -import { GqlModuleOptions } from '../interfaces/gql-module-options.interface'; -import { BaseExplorerService } from './base-explorer.service'; - -@Injectable() -export class PluginsExplorerService extends BaseExplorerService { - constructor( - private readonly modulesContainer: ModulesContainer, - @Inject(GRAPHQL_MODULE_OPTIONS) - private readonly gqlOptions: GqlModuleOptions, - ) { - super(); - } - - explore() { - const modules = this.getModules( - this.modulesContainer, - this.gqlOptions.include || [], - ); - return this.flatMap(modules, (instance) => - this.filterPlugins(instance), - ); - } - - filterPlugins(wrapper: InstanceWrapper) { - const { instance } = wrapper; - if (!instance) { - return undefined; - } - const metadata = Reflect.getMetadata(PLUGIN_METADATA, instance.constructor); - return metadata ? instance : undefined; - } -} diff --git a/packages/graphql/lib/utils/extract-metadata.util.ts b/packages/graphql/lib/utils/extract-metadata.util.ts index 14480d13e..4f821aaeb 100644 --- a/packages/graphql/lib/utils/extract-metadata.util.ts +++ b/packages/graphql/lib/utils/extract-metadata.util.ts @@ -1,11 +1,9 @@ import 'reflect-metadata'; -import { - RESOLVER_REFERENCE_KEY, - RESOLVER_REFERENCE_METADATA, -} from '../federation/federation.constants'; import { RESOLVER_NAME_METADATA, RESOLVER_PROPERTY_METADATA, + RESOLVER_REFERENCE_KEY, + RESOLVER_REFERENCE_METADATA, RESOLVER_TYPE_METADATA, } from '../graphql.constants'; import { ResolverMetadata } from '../interfaces/resolver-metadata.interface'; diff --git a/yarn.lock b/yarn.lock index 67a2438eb..20666dd3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,16 +7,6 @@ resolved "https://registry.yarnpkg.com/@apollo/core-schema/-/core-schema-0.1.1.tgz#5b7ecb69719a0f68e2005830cfaa8ecdbb75add7" integrity sha512-6VImC4vO3GjIapSKP84EQTo0KmRP21SKrNatpexKmuGltKe5b62M3wBA6uJgrUfWnGWXsH4SAAgCxsn37k26eg== -"@apollo/federation@0.33.3": - version "0.33.3" - resolved "https://registry.yarnpkg.com/@apollo/federation/-/federation-0.33.3.tgz#07710308c1a097c3aaee53759860751f6fff82e3" - integrity sha512-+BRJW1Kf7im86CWPQEdocXQTyPUH132MMoMCXuRvM4F1idb5EldqRkFNM8y9IAYNnbHsthmIWlrqmkuYg+irGQ== - dependencies: - "@apollo/subgraph" "^0.1.2" - apollo-graphql "^0.9.3" - apollo-server-types "^3.0.2" - lodash.xorby "^4.7.0" - "@apollo/federation@^0.33.3": version "0.33.6" resolved "https://registry.yarnpkg.com/@apollo/federation/-/federation-0.33.6.tgz#cd9fd983fdc6d007f4a09b085126845368feb525" @@ -84,7 +74,7 @@ dependencies: apollo-graphql "^0.9.3" -"@apollo/subgraph@^0.1.2", "@apollo/subgraph@^0.1.4": +"@apollo/subgraph@^0.1.4": version "0.1.4" resolved "https://registry.yarnpkg.com/@apollo/subgraph/-/subgraph-0.1.4.tgz#21ca21ea74f54f39533b5e08e92069704c6b529b" integrity sha512-G1N/sXZIHeX27tf+7lefEwVZFNYzdARe+pD597U5opfM1Gs1mYwRySfOdm1QkcItYG+EmTcSOuUJ5bNbvW0IUg== @@ -650,7 +640,7 @@ tslib "~2.3.0" value-or-promise "1.0.11" -"@graphql-tools/utils@7.10.0", "@graphql-tools/utils@^7.0.0", "@graphql-tools/utils@^7.1.2": +"@graphql-tools/utils@7", "@graphql-tools/utils@7.10.0", "@graphql-tools/utils@^7.0.0", "@graphql-tools/utils@^7.1.2": version "7.10.0" resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.10.0.tgz#07a4cb5d1bec1ff1dc1d47a935919ee6abd38699" integrity sha512-d334r6bo9mxdSqZW6zWboEnnOOFRrAPVQJ7LkU8/6grglrbcu6WhwCLzHb90E94JI3TD3ricC3YGbUqIi9Xg0w==