diff --git a/.prettierrc b/.prettierrc index ffa374c07..6e778b4fb 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,4 @@ { "trailingComma": "all", "singleQuote": true -} \ No newline at end of file +} diff --git a/lib/decorators/index.ts b/lib/decorators/index.ts index 794d08e8d..71d011f95 100644 --- a/lib/decorators/index.ts +++ b/lib/decorators/index.ts @@ -6,6 +6,7 @@ export * from './mutation.decorator'; export * from './parent.decorator'; export * from './query.decorator'; export * from './resolve-property.decorator'; +export * from './resolve-reference.decorator'; export * from './resolver.decorator'; export * from './root.decorator'; export * from './scalar.decorator'; diff --git a/lib/decorators/resolve-reference.decorator.ts b/lib/decorators/resolve-reference.decorator.ts new file mode 100644 index 000000000..d6d6e3bc2 --- /dev/null +++ b/lib/decorators/resolve-reference.decorator.ts @@ -0,0 +1,12 @@ +import { RESOLVER_REFERENCE_METADATA } from '../graphql.constants'; +import { SetMetadata } from '@nestjs/common'; + +export function ResolveReference(): MethodDecorator { + return ( + target: Function | Object, + key?: string | symbol, + descriptor?: any, + ) => { + SetMetadata(RESOLVER_REFERENCE_METADATA, true)(target, key, descriptor); + }; +} diff --git a/lib/external/type-graphql.types.ts b/lib/external/type-graphql.types.ts index 0ff1978e9..1702924dc 100644 --- a/lib/external/type-graphql.types.ts +++ b/lib/external/type-graphql.types.ts @@ -1,5 +1,5 @@ import { Type } from '@nestjs/common'; -import { GraphQLScalarType } from 'graphql'; +import { GraphQLDirective, GraphQLScalarType } from 'graphql'; /** * Some external types have to be included in order to provide types safety @@ -41,9 +41,13 @@ export type BasicOptions = DecoratorTypeOptions & DescriptionOptions; export type AdvancedOptions = BasicOptions & DepreciationOptions & SchemaNameOptions; + export interface BuildSchemaOptions { dateScalarMode?: DateScalarMode; scalarsMap?: ScalarsTypeMap[]; + /** Any types that are not directly referenced or returned by resolvers */ + orphanedTypes?: Function[]; + directives?: GraphQLDirective[]; } export type DateScalarMode = 'isoDate' | 'timestamp'; export interface ScalarsTypeMap { diff --git a/lib/graphql-definitions.factory.ts b/lib/graphql-definitions.factory.ts index a5a96c823..0e40af4f3 100644 --- a/lib/graphql-definitions.factory.ts +++ b/lib/graphql-definitions.factory.ts @@ -1,11 +1,12 @@ import { isEmpty } from '@nestjs/common/utils/shared.utils'; +import { loadPackage } from '@nestjs/common/utils/load-package.util'; import { gql } from 'apollo-server-core'; import { makeExecutableSchema } from 'graphql-tools'; import * as chokidar from 'chokidar'; import { printSchema } from 'graphql'; import { GraphQLAstExplorer } from './graphql-ast.explorer'; import { GraphQLTypesLoader } from './graphql-types.loader'; -import { removeTempField } from './utils/remove-temp.util'; +import { removeTempField, extend } from './utils'; export class GraphQLDefinitionsFactory { private readonly gqlAstExplorer = new GraphQLAstExplorer(); @@ -17,9 +18,11 @@ export class GraphQLDefinitionsFactory { outputAs?: 'class' | 'interface'; watch?: boolean; debug?: boolean; + federation?: boolean; }) { const isDebugEnabled = !(options && options.debug === false); const typePathsExists = options.typePaths && !isEmpty(options.typePaths); + const isFederation = options && options.federation; if (!typePathsExists) { throw new Error(`"typePaths" property cannot be empty.`); } @@ -38,6 +41,7 @@ export class GraphQLDefinitionsFactory { options.typePaths, options.path, options.outputAs, + isFederation, isDebugEnabled, ); }); @@ -46,11 +50,74 @@ export class GraphQLDefinitionsFactory { options.typePaths, options.path, options.outputAs, + isFederation, isDebugEnabled, ); } private async exploreAndEmit( + typePaths: string[], + path: string, + outputAs: 'class' | 'interface', + isFederation: boolean, + isDebugEnabled: boolean, + ) { + if (isFederation) { + return this.exploreAndEmitFederation( + typePaths, + path, + outputAs, + isDebugEnabled, + ); + } + return this.exploreAndEmitRegular( + typePaths, + path, + outputAs, + isDebugEnabled, + ); + } + + private async exploreAndEmitFederation( + typePaths: string[], + path: string, + outputAs: 'class' | 'interface', + isDebugEnabled: boolean, + ) { + const typeDefs = await this.gqlTypesLoader.mergeTypesByPaths(typePaths); + + const { buildFederatedSchema } = loadPackage( + '@apollo/federation', + 'ApolloFederation', + ); + const { printSchema } = loadPackage( + '@apollo/federation', + 'ApolloFederation', + ); + + const schema = buildFederatedSchema([ + { + typeDefs: gql` + ${typeDefs} + `, + resolvers: {}, + }, + ]); + const tsFile = await this.gqlAstExplorer.explore( + gql` + ${printSchema(schema)} + `, + path, + outputAs, + ); + await tsFile.save(); + this.printMessage( + `[${new Date().toLocaleTimeString()}] The definitions have been updated.`, + isDebugEnabled, + ); + } + + private async exploreAndEmitRegular( typePaths: string[], path: string, outputAs: 'class' | 'interface', diff --git a/lib/graphql-federation.factory.ts b/lib/graphql-federation.factory.ts new file mode 100644 index 000000000..d6ac478d1 --- /dev/null +++ b/lib/graphql-federation.factory.ts @@ -0,0 +1,110 @@ +import { Injectable } from '@nestjs/common'; +import { gql } from 'apollo-server-core'; +import { loadPackage } from '@nestjs/common/utils/load-package.util'; +import { extend } from './utils'; +import { isEmpty, forEach } from 'lodash'; +import { + ScalarsExplorerService, + DelegatesExplorerService, + ResolversExplorerService, +} from './services'; +import { mergeSchemas } from 'graphql-tools'; +import { GqlModuleOptions } from './interfaces'; +import { GraphQLSchemaBuilder } from './graphql-schema-builder'; +import { GraphQLFactory } from './graphql.factory'; +import { GraphQLSchema, GraphQLSchemaConfig } from 'graphql'; +import { GraphQLObjectType } from 'graphql'; + +@Injectable() +export class GraphQLFederationFactory { + constructor( + private readonly resolversExplorerService: ResolversExplorerService, + private readonly delegatesExplorerService: DelegatesExplorerService, + private readonly scalarsExplorerService: ScalarsExplorerService, + private readonly gqlSchemaBuilder: GraphQLSchemaBuilder, + private readonly graphqlFactory: GraphQLFactory, + ) {} + + async mergeOptions( + options: GqlModuleOptions = {}, + ): Promise { + const transformSchema = async s => + options.transformSchema ? options.transformSchema(s) : s; + + let schema: GraphQLSchema; + if (options.autoSchemaFile) { + // Enable support when Directive support in type-graphql goes stable + throw new Error('Code-first not supported yet'); + schema = await this.generateSchema(options); + } else if (isEmpty(options.typeDefs)) { + schema = options.schema; + } else { + schema = this.buildSchemaFromTypeDefs(options); + } + + return { + ...options, + schema: await transformSchema(schema), + typeDefs: undefined, + }; + } + + private buildSchemaFromTypeDefs(options: GqlModuleOptions) { + const { buildFederatedSchema } = loadPackage( + '@apollo/federation', + 'ApolloFederation', + ); + + return buildFederatedSchema([ + { + typeDefs: gql` + ${options.typeDefs} + `, + resolvers: this.getResolvers(options.resolvers), + }, + ]); + } + + private async generateSchema( + options: GqlModuleOptions, + ): Promise { + const { buildFederatedSchema, printSchema } = loadPackage( + '@apollo/federation', + 'ApolloFederation', + ); + + const autoGeneratedSchema: GraphQLSchema = await this.gqlSchemaBuilder.buildFederatedSchema( + options.autoSchemaFile, + options.buildSchemaOptions, + this.resolversExplorerService.getAllCtors(), + ); + const executableSchema = buildFederatedSchema({ + typeDefs: gql(printSchema(autoGeneratedSchema)), + resolvers: this.getResolvers(options.resolvers), + }); + + const schema = options.schema + ? mergeSchemas({ + schemas: [options.schema, executableSchema], + }) + : executableSchema; + + return schema; + } + + private getResolvers(optionResolvers) { + optionResolvers = Array.isArray(optionResolvers) + ? optionResolvers + : [optionResolvers]; + return this.extendResolvers([ + this.resolversExplorerService.explore(), + this.delegatesExplorerService.explore(), + ...this.scalarsExplorerService.explore(), + ...optionResolvers, + ]); + } + + private extendResolvers(resolvers: any[]) { + return resolvers.reduce((prev, curr) => extend(prev, curr), {}); + } +} diff --git a/lib/graphql-federation.module.ts b/lib/graphql-federation.module.ts new file mode 100644 index 000000000..d75b21d89 --- /dev/null +++ b/lib/graphql-federation.module.ts @@ -0,0 +1,240 @@ +import { + DynamicModule, + Inject, + Module, + OnModuleInit, + Optional, + Provider, +} from '@nestjs/common'; +import { ApolloServerBase } from 'apollo-server-core'; +import { MetadataScanner } from '@nestjs/core/metadata-scanner'; +import { loadPackage } from '@nestjs/common/utils/load-package.util'; +import { HttpAdapterHost, ApplicationConfig } from '@nestjs/core'; + +import { GraphQLFederationFactory } from './graphql-federation.factory'; +import { + ScalarsExplorerService, + DelegatesExplorerService, + ResolversExplorerService, +} from './services'; +import { GraphQLAstExplorer } from './graphql-ast.explorer'; +import { GraphQLTypesLoader } from './graphql-types.loader'; +import { GraphQLSchemaBuilder } from './graphql-schema-builder'; +import { GRAPHQL_MODULE_ID, GRAPHQL_MODULE_OPTIONS } from './graphql.constants'; +import { + GqlModuleAsyncOptions, + GqlModuleOptions, + GqlOptionsFactory, +} from './interfaces'; +import { generateString, mergeDefaults, normalizeRoutePath } from './utils'; +import { GraphQLFactory } from './graphql.factory'; + +@Module({ + providers: [ + GraphQLFederationFactory, + GraphQLFactory, + MetadataScanner, + ResolversExplorerService, + DelegatesExplorerService, + ScalarsExplorerService, + GraphQLAstExplorer, + GraphQLTypesLoader, + GraphQLSchemaBuilder, + ], + exports: [], +}) +export class GraphQLFederationModule implements OnModuleInit { + private apolloServer: ApolloServerBase; + + 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 applicationConfig: ApplicationConfig, + ) {} + + static forRoot(options: GqlModuleOptions = {}): DynamicModule { + options = mergeDefaults(options); + + return { + module: GraphQLFederationModule, + providers: [ + { + provide: GRAPHQL_MODULE_OPTIONS, + useValue: options, + }, + ], + }; + } + + static forRootAsync(options: GqlModuleAsyncOptions): DynamicModule { + return { + module: GraphQLFederationModule, + imports: options.imports, + providers: [ + ...this.createAsyncProviders(options), + { + provide: GRAPHQL_MODULE_ID, + useValue: generateString(), + }, + ], + }; + } + + 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: options.useFactory, + inject: options.inject || [], + }; + } + + return { + provide: GRAPHQL_MODULE_OPTIONS, + useFactory: (optionsFactory: GqlOptionsFactory) => + optionsFactory.createGqlOptions(), + inject: [options.useExisting || options.useClass], + }; + } + + async onModuleInit() { + if (!this.httpAdapterHost || !this.httpAdapterHost.httpAdapter) { + return; + } + + const { printSchema } = loadPackage( + '@apollo/federation', + 'ApolloFederation', + ); + + const { typePaths } = this.options; + const typeDefs = await this.graphqlTypesLoader.mergeTypesByPaths(typePaths); + + const apolloOptions = await this.graphqlFederationFactory.mergeOptions({ + ...this.options, + typeDefs, + }); + + if (this.options.definitions && this.options.definitions.path) { + await this.graphqlFactory.generateDefinitions( + printSchema(apolloOptions.schema), + this.options, + ); + } + + this.registerGqlServer(apolloOptions); + + if (this.options.installSubscriptionHandlers) { + // TL;DR + throw new Error( + 'No support for subscriptions yet when using Apollo Federation', + ); + /*this.apolloServer.installSubscriptionHandlers( + httpAdapter.getHttpServer(), + );*/ + } + } + + private registerGqlServer(apolloOptions: GqlModuleOptions) { + const httpAdapter = this.httpAdapterHost.httpAdapter; + const adapterName = httpAdapter.constructor && httpAdapter.constructor.name; + + if (adapterName === 'ExpressAdapter') { + this.registerExpress(apolloOptions); + } else if (adapterName === 'FastifyAdapter') { + this.registerFastify(apolloOptions); + } else { + throw new Error(`No support for current HttpAdapter: ${adapterName}`); + } + } + + private registerExpress(apolloOptions: GqlModuleOptions) { + const { ApolloServer } = loadPackage( + 'apollo-server-express', + 'GraphQLModule', + () => require('apollo-server-express'), + ); + const { + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + } = this.options; + const app = this.httpAdapterHost.httpAdapter.getInstance(); + const path = this.getNormalizedPath(apolloOptions); + + const apolloServer = new ApolloServer(apolloOptions as any); + apolloServer.applyMiddleware({ + app, + path, + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + }); + this.apolloServer = apolloServer; + } + + private registerFastify(apolloOptions: GqlModuleOptions) { + const { ApolloServer } = loadPackage( + 'apollo-server-fastify', + 'GraphQLModule', + () => require('apollo-server-fastify'), + ); + + const httpAdapter = this.httpAdapterHost.httpAdapter; + const app = httpAdapter.getInstance(); + const path = this.getNormalizedPath(apolloOptions); + + const apolloServer = new ApolloServer(apolloOptions as any); + const { + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + } = this.options; + app.register( + apolloServer.createHandler({ + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + path, + }), + ); + + this.apolloServer = apolloServer; + } + + private getNormalizedPath(apolloOptions: GqlModuleOptions): string { + const prefix = this.applicationConfig.getGlobalPrefix(); + const useGlobalPrefix = prefix && this.options.useGlobalPrefix; + const gqlOptionsPath = normalizeRoutePath(apolloOptions.path); + return useGlobalPrefix + ? normalizeRoutePath(prefix) + gqlOptionsPath + : gqlOptionsPath; + } +} diff --git a/lib/graphql-gateway.module.ts b/lib/graphql-gateway.module.ts new file mode 100644 index 000000000..8e24370e0 --- /dev/null +++ b/lib/graphql-gateway.module.ts @@ -0,0 +1,202 @@ +import { + DynamicModule, + Inject, + Module, + OnModuleInit, + Optional, + Provider, +} from '@nestjs/common'; +import { ApolloServerBase } from 'apollo-server-core'; +import { HttpAdapterHost } from '@nestjs/core'; +import { + GRAPHQL_GATEWAY_BUILD_SERVICE, + GRAPHQL_GATEWAY_MODULE_OPTIONS, + GRAPHQL_MODULE_ID, +} from './graphql.constants'; +import { + GatewayBuildService, + GatewayModuleOptions, + GatewayOptionsFactory, + GatewayModuleAsyncOptions, + GqlModuleOptions, +} from './interfaces'; +import { loadPackage } from '@nestjs/common/utils/load-package.util'; +import { generateString } from './utils'; + +@Module({}) +export class GraphQLGatewayModule implements OnModuleInit { + private apolloServer: ApolloServerBase; + + constructor( + @Optional() + private readonly httpAdapterHost: HttpAdapterHost, + @Optional() + @Inject(GRAPHQL_GATEWAY_BUILD_SERVICE) + private readonly buildService: GatewayBuildService, + @Inject(GRAPHQL_GATEWAY_MODULE_OPTIONS) + private readonly options: GatewayModuleOptions, + ) {} + + static forRoot(options: GatewayModuleOptions): DynamicModule { + return { + module: GraphQLGatewayModule, + providers: [ + { + provide: GRAPHQL_GATEWAY_MODULE_OPTIONS, + useValue: options, + }, + ], + }; + } + + static forRootAsync(options: GatewayModuleAsyncOptions): DynamicModule { + return { + module: GraphQLGatewayModule, + imports: options.imports, + providers: [ + ...this.createAsyncProviders(options), + { + provide: GRAPHQL_MODULE_ID, + useValue: generateString(), + }, + ], + }; + } + + 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_GATEWAY_MODULE_OPTIONS, + useFactory: options.useFactory, + inject: options.inject || [], + }; + } + + return { + provide: GRAPHQL_GATEWAY_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'); + const { + options: { server: serverOpts = {}, gateway: gatewayOpts = {} }, + buildService, + } = this; + + const gateway = new ApolloGateway({ + ...gatewayOpts, + buildService, + }); + + this.registerGqlServer({ ...serverOpts, gateway, subscriptions: false }); + + if (serverOpts.installSubscriptionHandlers) { + // TL;DR + throw new Error( + 'No support for subscriptions yet when using Apollo Federation', + ); + /*this.apolloServer.installSubscriptionHandlers( + httpAdapter.getHttpServer(), + );*/ + } + } + + private registerGqlServer(apolloOptions: GqlModuleOptions) { + const httpAdapter = this.httpAdapterHost.httpAdapter; + const adapterName = httpAdapter.constructor && httpAdapter.constructor.name; + + if (adapterName === 'ExpressAdapter') { + this.registerExpress(apolloOptions); + } else if (adapterName === 'FastifyAdapter') { + this.registerFastify(apolloOptions); + } else { + throw new Error(`No support for current HttpAdapter: ${adapterName}`); + } + } + + private registerExpress(apolloOptions: GqlModuleOptions) { + const { ApolloServer } = loadPackage( + 'apollo-server-express', + 'GraphQLModule', + () => require('apollo-server-express'), + ); + const { + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + path, + } = apolloOptions; + const app = this.httpAdapterHost.httpAdapter.getInstance(); + + const apolloServer = new ApolloServer(apolloOptions); + apolloServer.applyMiddleware({ + app, + path, + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + }); + this.apolloServer = apolloServer; + } + + private registerFastify(apolloOptions: GqlModuleOptions) { + const { ApolloServer } = loadPackage( + 'apollo-server-fastify', + 'GraphQLModule', + () => require('apollo-server-fastify'), + ); + + const httpAdapter = this.httpAdapterHost.httpAdapter; + const app = httpAdapter.getInstance(); + + const apolloServer = new ApolloServer(apolloOptions); + const { + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + path, + } = apolloOptions; + app.register( + apolloServer.createHandler({ + disableHealthCheck, + onHealthCheck, + cors, + bodyParserConfig, + path, + }), + ); + + this.apolloServer = apolloServer; + } +} diff --git a/lib/graphql-schema-builder.ts b/lib/graphql-schema-builder.ts index 77e6e64f0..f80daa3bd 100644 --- a/lib/graphql-schema-builder.ts +++ b/lib/graphql-schema-builder.ts @@ -1,8 +1,8 @@ import { Injectable } from '@nestjs/common'; import { loadPackage } from '@nestjs/common/utils/load-package.util'; -import { GraphQLSchema } from 'graphql'; +import { GraphQLSchema, specifiedDirectives } from 'graphql'; import { BuildSchemaOptions } from './external/type-graphql.types'; -import { ScalarsExplorerService } from './services/scalars-explorer.service'; +import { ScalarsExplorerService } from './services'; import { lazyMetadataStorage } from './storages/lazy-metadata.storage'; @Injectable() @@ -36,10 +36,48 @@ export class GraphQLSchemaBuilder { } } + async buildFederatedSchema( + autoSchemaFile: string | boolean, + options: BuildSchemaOptions = {}, + resolvers: Function[], + ) { + lazyMetadataStorage.load(); + + const buildSchema = this.loadBuildSchemaFactory(); + const scalarsMap = this.scalarsExplorerService.getScalarsMap(); + + try { + return await buildSchema({ + ...options, + directives: [ + ...specifiedDirectives, + ...this.loadFederationDirectives(), + ...((options && options.directives) || []), + ], + emitSchemaFile: autoSchemaFile !== true ? autoSchemaFile : false, + validate: false, + scalarsMap, + resolvers, + skipCheck: true, + }); + } catch (err) { + if (err && err.details) { + console.error(err.details); + } + throw err; + } + } + private loadBuildSchemaFactory(): (...args: any[]) => GraphQLSchema { - const { buildSchema } = loadPackage('type-graphql', 'SchemaBuilder', () => - require('type-graphql'), - ); + const { buildSchema } = loadPackage('type-graphql', 'SchemaBuilder'); return buildSchema; } + + private loadFederationDirectives() { + const { federationDirectives } = loadPackage( + '@apollo/federation/dist/directives', + 'SchemaBuilder', + ); + return federationDirectives; + } } diff --git a/lib/graphql.constants.ts b/lib/graphql.constants.ts index 5d2d22ff8..f8dd6b939 100644 --- a/lib/graphql.constants.ts +++ b/lib/graphql.constants.ts @@ -1,17 +1,23 @@ export const RESOLVER_TYPE_METADATA = 'graphql:resolver_type'; export const RESOLVER_NAME_METADATA = 'graphql:resolver_name'; export const RESOLVER_PROPERTY_METADATA = 'graphql:resolve_property'; +export const RESOLVER_REFERENCE_METADATA = 'graphql:resolve_reference'; 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 PARAM_ARGS_METADATA = '__routeArguments__'; export const SUBSCRIPTION_OPTIONS_METADATA = 'graphql:subscription_options;'; +export const GRAPHQL_GATEWAY_MODULE_OPTIONS = 'graphql:gateway_module_options'; +export const GRAPHQL_GATEWAY_BUILD_SERVICE = 'graphql:gateway_build_service'; + export const FIELD_TYPENAME = '__resolveType'; export const GRAPHQL_MODULE_OPTIONS = 'GqlModuleOptions'; export const GRAPHQL_MODULE_ID = 'GqlModuleId'; export const SUBSCRIPTION_TYPE = 'Subscription'; +export const RESOLVER_REFERENCE_KEY = '__resolveReference'; + export const DEFINITIONS_FILE_HEADER = ` /** ------------------------------------------------------ * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) diff --git a/lib/graphql.factory.ts b/lib/graphql.factory.ts index c963ddeb0..fd79b8322 100644 --- a/lib/graphql.factory.ts +++ b/lib/graphql.factory.ts @@ -11,12 +11,13 @@ import { import { forEach, isEmpty } from 'lodash'; import { GraphQLAstExplorer } from './graphql-ast.explorer'; import { GraphQLSchemaBuilder } from './graphql-schema-builder'; -import { GqlModuleOptions } from './interfaces/gql-module-options.interface'; -import { DelegatesExplorerService } from './services/delegates-explorer.service'; -import { ResolversExplorerService } from './services/resolvers-explorer.service'; -import { ScalarsExplorerService } from './services/scalars-explorer.service'; -import { extend } from './utils/extend.util'; -import { removeTempField } from './utils/remove-temp.util'; +import { GqlModuleOptions } from './interfaces'; +import { + ScalarsExplorerService, + DelegatesExplorerService, + ResolversExplorerService, +} from './services'; +import { extend, removeTempField } from './utils'; @Injectable() export class GraphQLFactory { diff --git a/lib/graphql.module.ts b/lib/graphql.module.ts index 16924f0e0..1c660a371 100644 --- a/lib/graphql.module.ts +++ b/lib/graphql.module.ts @@ -19,13 +19,17 @@ import { GqlModuleOptions, GqlOptionsFactory, } from './interfaces/gql-module-options.interface'; -import { DelegatesExplorerService } from './services/delegates-explorer.service'; -import { ResolversExplorerService } from './services/resolvers-explorer.service'; -import { ScalarsExplorerService } from './services/scalars-explorer.service'; -import { extend } from './utils/extend.util'; -import { generateString } from './utils/generate-token.util'; -import { mergeDefaults } from './utils/merge-defaults.util'; -import { normalizeRoutePath } from './utils/normalize-route-path.util'; +import { + DelegatesExplorerService, + ResolversExplorerService, + ScalarsExplorerService, +} from './services'; +import { + extend, + generateString, + mergeDefaults, + normalizeRoutePath, +} from './utils'; @Module({ providers: [ diff --git a/lib/index.ts b/lib/index.ts index 1e7af3922..913fcb633 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,8 +1,11 @@ export * from './decorators'; export * from './graphql-ast.explorer'; +export { GRAPHQL_GATEWAY_BUILD_SERVICE } from './graphql.constants'; export * from './graphql-definitions.factory'; export * from './graphql-types.loader'; export * from './graphql.factory'; +export * from './graphql-federation.module'; +export * from './graphql-gateway.module'; export * from './graphql.module'; export * from './interfaces'; export * from './services/gql-arguments-host'; diff --git a/lib/interfaces/gql-gateway-module-options.interface.ts b/lib/interfaces/gql-gateway-module-options.interface.ts new file mode 100644 index 000000000..06f61c704 --- /dev/null +++ b/lib/interfaces/gql-gateway-module-options.interface.ts @@ -0,0 +1,43 @@ +import { Type } from '@nestjs/common'; +import { GqlModuleOptions } from './gql-module-options.interface'; +import { GatewayConfig, ServiceEndpointDefinition } from '@apollo/gateway'; +import { GraphQLDataSource } from '@apollo/gateway/src/datasources/types'; +import { ModuleMetadata } from '@nestjs/common/interfaces'; + +export interface GatewayModuleOptions { + gateway?: GatewayConfig; + server?: Omit< + GqlModuleOptions, + | 'typeDefs' + | 'typePaths' + | 'include' + | 'resolvers' + | 'resolverValidationOptions' + | 'directiveResolvers' + | 'autoSchemaFile' + | 'transformSchema' + | 'definitions' + | 'schema' + | 'subscriptions' + | 'schemaDirectives' + | 'buildSchemaOptions' + | 'fieldResolverEnhancers' + >; +} + +export interface GatewayOptionsFactory { + createGatewayOptions(): Promise | GatewayModuleOptions; +} +export interface GatewayModuleAsyncOptions + extends Pick { + useExisting?: Type; + useClass?: Type; + useFactory?: ( + ...args: any[] + ) => Promise | GatewayModuleOptions; + inject?: any[]; +} + +export type GatewayBuildService = ( + definition: ServiceEndpointDefinition, +) => GraphQLDataSource; diff --git a/lib/interfaces/index.ts b/lib/interfaces/index.ts index 69ec58599..b32259b47 100644 --- a/lib/interfaces/index.ts +++ b/lib/interfaces/index.ts @@ -1,5 +1,6 @@ export * from './custom-scalar.interface'; export * from './gql-exception-filter.interface'; +export * from './gql-gateway-module-options.interface'; export { GqlModuleAsyncOptions, GqlModuleOptions, diff --git a/lib/services/index.ts b/lib/services/index.ts new file mode 100644 index 000000000..d65cd6c2d --- /dev/null +++ b/lib/services/index.ts @@ -0,0 +1,6 @@ +export * from './base-explorer.service'; +export * from './delegates-explorer.service'; +export * from './gql-arguments-host'; +export * from './gql-execution-context'; +export * from './resolvers-explorer.service'; +export * from './scalars-explorer.service'; diff --git a/lib/services/resolvers-explorer.service.ts b/lib/services/resolvers-explorer.service.ts index 892ccdc57..648d0e82f 100644 --- a/lib/services/resolvers-explorer.service.ts +++ b/lib/services/resolvers-explorer.service.ts @@ -70,11 +70,13 @@ export class ResolversExplorerService extends BaseExplorerService { const predicate = ( resolverType: string, isDelegated: boolean, + isReferenceResolver: boolean, isPropertyResolver: boolean, ) => isUndefined(resolverType) || isDelegated || - (!isPropertyResolver && + (!isReferenceResolver && + !isPropertyResolver && ![Resolvers.MUTATION, Resolvers.QUERY, Resolvers.SUBSCRIPTION].some( type => type === resolverType, )); diff --git a/lib/utils/extract-metadata.util.ts b/lib/utils/extract-metadata.util.ts index 1293bf3a2..85f3dcb0c 100644 --- a/lib/utils/extract-metadata.util.ts +++ b/lib/utils/extract-metadata.util.ts @@ -1,11 +1,13 @@ import 'reflect-metadata'; +import { ResolverMetadata } from '../interfaces/resolver-metadata.interface'; import { RESOLVER_DELEGATE_METADATA, 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'; export function extractMetadata( instance: Record, @@ -14,6 +16,7 @@ export function extractMetadata( filterPredicate: ( resolverType: string, isDelegated: boolean, + isReferenceResolver?: boolean, isPropertyResolver?: boolean, ) => boolean, ): ResolverMetadata { @@ -22,21 +25,40 @@ export function extractMetadata( Reflect.getMetadata(RESOLVER_TYPE_METADATA, callback) || Reflect.getMetadata(RESOLVER_TYPE_METADATA, instance.constructor); - const isPropertyResolver = Reflect.getMetadata( + const isPropertyResolver = !!Reflect.getMetadata( RESOLVER_PROPERTY_METADATA, callback, ); + const resolverName = Reflect.getMetadata(RESOLVER_NAME_METADATA, callback); const isDelegated = !!Reflect.getMetadata( RESOLVER_DELEGATE_METADATA, callback, ); - if (filterPredicate(resolverType, isDelegated, isPropertyResolver)) { + + const isReferenceResolver = !!Reflect.getMetadata( + RESOLVER_REFERENCE_METADATA, + callback, + ); + + if ( + filterPredicate( + resolverType, + isDelegated, + isReferenceResolver, + isPropertyResolver, + ) + ) { return null; } + + const name = isReferenceResolver + ? RESOLVER_REFERENCE_KEY + : resolverName || methodName; + return { - name: resolverName || methodName, type: resolverType, methodName, + name, }; } diff --git a/lib/utils/index.ts b/lib/utils/index.ts new file mode 100644 index 000000000..fb46ad94f --- /dev/null +++ b/lib/utils/index.ts @@ -0,0 +1,7 @@ +export * from './async-iterator.util'; +export * from './extend.util'; +export * from './extract-metadata.util'; +export * from './generate-token.util'; +export * from './merge-defaults.util'; +export * from './normalize-route-path.util'; +export * from './remove-temp.util'; diff --git a/package-lock.json b/package-lock.json index d15135a2a..d5683e293 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,193 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@apollo/federation": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@apollo/federation/-/federation-0.10.2.tgz", + "integrity": "sha512-N+JoD7YraGAgDJq1GTkAzRRPUA+FgclFgAUcUDng9ICA4N147nuGUrbrpQdgLnE59nCLJAhcFvOgQRs177XMWw==", + "optional": true, + "requires": { + "apollo-env": "^0.5.1", + "apollo-graphql": "^0.3.4", + "apollo-server-env": "^2.4.3", + "lodash.xorby": "^4.7.0" + }, + "dependencies": { + "apollo-env": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.5.1.tgz", + "integrity": "sha512-fndST2xojgSdH02k5hxk1cbqA9Ti8RX4YzzBoAB4oIe1Puhq7+YlhXGXfXB5Y4XN0al8dLg+5nAkyjNAR2qZTw==", + "optional": true, + "requires": { + "core-js": "^3.0.1", + "node-fetch": "^2.2.0", + "sha.js": "^2.4.11" + } + }, + "apollo-graphql": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.3.4.tgz", + "integrity": "sha512-w+Az1qxePH4oQ8jvbhQBl5iEVvqcqynmU++x/M7MM5xqN1C7m1kyIzpN17gybXlTJXY4Oxej2WNURC2/hwpfYw==", + "optional": true, + "requires": { + "apollo-env": "^0.5.1", + "lodash.sortby": "^4.7.0" + } + } + } + }, + "@apollo/gateway": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/@apollo/gateway/-/gateway-0.10.8.tgz", + "integrity": "sha512-j+FR/ui9G+A2h6bqlhmf1AzJLft3DH96uj4CV3K/CvAXbhlQLXAK+snNhxwrS/YD7nBjOsMTzzzSa1bJOpayYg==", + "optional": true, + "requires": { + "@apollo/federation": "^0.10.2", + "apollo-engine-reporting-protobuf": "^0.4.1", + "apollo-env": "^0.5.1", + "apollo-graphql": "^0.3.4", + "apollo-server-caching": "^0.5.0", + "apollo-server-core": "^2.9.7", + "apollo-server-env": "^2.4.3", + "apollo-server-types": "^0.2.5", + "graphql-extensions": "^0.10.4", + "loglevel": "^1.6.1", + "loglevel-debug": "^0.0.1", + "pretty-format": "^24.7.0" + }, + "dependencies": { + "apollo-cache-control": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.8.5.tgz", + "integrity": "sha512-2yQ1vKgJQ54SGkoQS/ZLZrDX3La6cluAYYdruFYJMJtL4zQrSdeOCy11CQliCMYEd6eKNyE70Rpln51QswW2Og==", + "optional": true, + "requires": { + "apollo-server-env": "^2.4.3", + "graphql-extensions": "^0.10.4" + } + }, + "apollo-engine-reporting": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-1.4.7.tgz", + "integrity": "sha512-qsKDz9VkoctFhojM3Nj3nvRBO98t8TS2uTgtiIjUGs3Hln2poKMP6fIQ37Nm2Q2B3JJst76HQtpPwXmRJd1ZUg==", + "optional": true, + "requires": { + "apollo-engine-reporting-protobuf": "^0.4.1", + "apollo-graphql": "^0.3.4", + "apollo-server-caching": "^0.5.0", + "apollo-server-env": "^2.4.3", + "apollo-server-types": "^0.2.5", + "async-retry": "^1.2.1", + "graphql-extensions": "^0.10.4" + } + }, + "apollo-engine-reporting-protobuf": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/apollo-engine-reporting-protobuf/-/apollo-engine-reporting-protobuf-0.4.1.tgz", + "integrity": "sha512-d7vFFZ2oUrvGaN0Hpet8joe2ZG0X0lIGilN+SwgVP38dJnOuadjsaYMyrD9JudGQJg0bJA5wVQfYzcCVy0slrw==", + "optional": true, + "requires": { + "protobufjs": "^6.8.6" + } + }, + "apollo-env": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.5.1.tgz", + "integrity": "sha512-fndST2xojgSdH02k5hxk1cbqA9Ti8RX4YzzBoAB4oIe1Puhq7+YlhXGXfXB5Y4XN0al8dLg+5nAkyjNAR2qZTw==", + "optional": true, + "requires": { + "core-js": "^3.0.1", + "node-fetch": "^2.2.0", + "sha.js": "^2.4.11" + } + }, + "apollo-graphql": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.3.4.tgz", + "integrity": "sha512-w+Az1qxePH4oQ8jvbhQBl5iEVvqcqynmU++x/M7MM5xqN1C7m1kyIzpN17gybXlTJXY4Oxej2WNURC2/hwpfYw==", + "optional": true, + "requires": { + "apollo-env": "^0.5.1", + "lodash.sortby": "^4.7.0" + } + }, + "apollo-server-core": { + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.9.7.tgz", + "integrity": "sha512-EqKyROy+21sM93YHjGpy6wlnzK/vH0fnZh7RCf3uB69aQ3OjgdP4AQ5oWRQ62NDN+aoic7OLhChSDJeDonq/NQ==", + "optional": true, + "requires": { + "@apollographql/apollo-tools": "^0.4.0", + "@apollographql/graphql-playground-html": "1.6.24", + "@types/graphql-upload": "^8.0.0", + "@types/ws": "^6.0.0", + "apollo-cache-control": "^0.8.5", + "apollo-engine-reporting": "^1.4.7", + "apollo-server-caching": "^0.5.0", + "apollo-server-env": "^2.4.3", + "apollo-server-errors": "^2.3.4", + "apollo-server-plugin-base": "^0.6.5", + "apollo-server-types": "^0.2.5", + "apollo-tracing": "^0.8.5", + "fast-json-stable-stringify": "^2.0.0", + "graphql-extensions": "^0.10.4", + "graphql-tag": "^2.9.2", + "graphql-tools": "^4.0.0", + "graphql-upload": "^8.0.2", + "sha.js": "^2.4.11", + "subscriptions-transport-ws": "^0.9.11", + "ws": "^6.0.0" + } + }, + "apollo-server-errors": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.3.4.tgz", + "integrity": "sha512-Y0PKQvkrb2Kd18d1NPlHdSqmlr8TgqJ7JQcNIfhNDgdb45CnqZlxL1abuIRhr8tiw8OhVOcFxz2KyglBi8TKdA==", + "optional": true + }, + "apollo-server-plugin-base": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.6.5.tgz", + "integrity": "sha512-z2ve7HEPWmZI3EzL0iiY9qyt1i0hitT+afN5PzssCw594LB6DfUQWsI14UW+W+gcw8hvl8VQUpXByfUntAx5vw==", + "optional": true, + "requires": { + "apollo-server-types": "^0.2.5" + } + }, + "apollo-server-types": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.2.5.tgz", + "integrity": "sha512-6iJQsPh59FWu4K7ABrVmpnQVgeK8Ockx8BcawBh+saFYWTlVczwcLyGSZPeV1tPSKwFwKZutyEslrYSafcarXQ==", + "optional": true, + "requires": { + "apollo-engine-reporting-protobuf": "^0.4.1", + "apollo-server-caching": "^0.5.0", + "apollo-server-env": "^2.4.3" + } + }, + "apollo-tracing": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.8.5.tgz", + "integrity": "sha512-lZn10/GRBZUlMxVYLghLMFsGcLN0jTYDd98qZfBtxw+wEWUx+PKkZdljDT+XNoOm/kDvEutFGmi5tSLhArIzWQ==", + "optional": true, + "requires": { + "apollo-server-env": "^2.4.3", + "graphql-extensions": "^0.10.4" + } + }, + "graphql-extensions": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.10.4.tgz", + "integrity": "sha512-lE6MroluEYocbR/ICwccv39w+Pz4cBPadJ11z1rJkbZv5wstISEganbDOwl9qN21rcZGiWzh7QUNxUiFUXXEDw==", + "optional": true, + "requires": { + "@apollographql/apollo-tools": "^0.4.0", + "apollo-server-env": "^2.4.3", + "apollo-server-types": "^0.2.5" + } + } + } + }, "@apollo/protobufjs": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.0.3.tgz", @@ -37,7 +224,6 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.4.3.tgz", "integrity": "sha512-CtC1bmohB1owdGMT2ZZKacI94LcPAZDN2WvCe+4ZXT5d7xO5PHOAb70EP/LcFbvnS8QI+pkYRSCGFQnUcv9efg==", - "dev": true, "requires": { "apollo-env": "^0.6.1" } @@ -45,8 +231,7 @@ "@apollographql/graphql-playground-html": { "version": "1.6.24", "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.24.tgz", - "integrity": "sha512-8GqG48m1XqyXh4mIZrtB5xOhUwSsh1WsrrsaZQOEYYql3YN9DEu9OOSg0ILzXHZo/h2Q74777YE4YzlArQzQEQ==", - "dev": true + "integrity": "sha512-8GqG48m1XqyXh4mIZrtB5xOhUwSsh1WsrrsaZQOEYYql3YN9DEu9OOSg0ILzXHZo/h2Q74777YE4YzlArQzQEQ==" }, "@babel/code-frame": { "version": "7.0.0", @@ -578,6 +763,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", "integrity": "sha1-H2R13IvZdM6gei2vOGSzF7HdMyw=", + "optional": true, "requires": { "is-absolute": "^1.0.0", "is-negated-glob": "^1.0.0" @@ -971,15 +1157,6 @@ "chalk": "^3.0.0" } }, - "@types/yargs": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.1.tgz", - "integrity": "sha512-sYlwNU7zYi6eZbMzFvG6eHD7VsEvFdoDtlD7eI1JTg7YNnuguzmiGsc6MPSq5l8n+h21AsNof0je+9sgOe4+dg==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1078,15 +1255,6 @@ "chalk": "^3.0.0" } }, - "@types/yargs": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.1.tgz", - "integrity": "sha512-sYlwNU7zYi6eZbMzFvG6eHD7VsEvFdoDtlD7eI1JTg7YNnuguzmiGsc6MPSq5l8n+h21AsNof0je+9sgOe4+dg==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1292,15 +1460,6 @@ "chalk": "^3.0.0" } }, - "@types/yargs": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.1.tgz", - "integrity": "sha512-sYlwNU7zYi6eZbMzFvG6eHD7VsEvFdoDtlD7eI1JTg7YNnuguzmiGsc6MPSq5l8n+h21AsNof0je+9sgOe4+dg==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1359,70 +1518,6 @@ } } }, - "@jest/types": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz", - "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "@kamilkisiela/graphql-tools": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@kamilkisiela/graphql-tools/-/graphql-tools-4.0.6.tgz", @@ -1467,14 +1562,6 @@ "cli-color": "2.0.0", "tslib": "1.10.0", "uuid": "3.4.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - } } }, "@nestjs/core": { @@ -1497,12 +1584,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==", "dev": true - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true } } }, @@ -1545,12 +1626,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==", "dev": true - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true } } }, @@ -1562,37 +1637,6 @@ "requires": { "optional": "0.1.4", "tslib": "1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" - }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" } }, "@nuxtjs/opencollective": { @@ -1606,174 +1650,30 @@ "node-fetch": "^2.3.0" } }, - "@octokit/auth-token": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.0.tgz", - "integrity": "sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.0" - } - }, - "@octokit/endpoint": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.2.tgz", - "integrity": "sha512-ICDcRA0C2vtTZZGud1nXRrBLXZqFayodXAKZfo3dkdcLNqcHsgaz3YSTupbURusYeucSVRjjG+RTcQhx6HPPcg==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.0", - "is-plain-object": "^3.0.0", - "universal-user-agent": "^4.0.0" - }, - "dependencies": { - "is-plain-object": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", - "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", - "dev": true, - "requires": { - "isobject": "^4.0.0" - } - }, - "isobject": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", - "dev": true - } - } - }, - "@octokit/plugin-paginate-rest": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", - "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.1" - } - }, - "@octokit/plugin-request-log": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz", - "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==", - "dev": true - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", - "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.1", - "deprecation": "^2.3.1" - } - }, - "@octokit/request": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz", - "integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==", - "dev": true, - "requires": { - "@octokit/endpoint": "^5.5.0", - "@octokit/request-error": "^1.0.1", - "@octokit/types": "^2.0.0", - "deprecation": "^2.0.0", - "is-plain-object": "^3.0.0", - "node-fetch": "^2.3.0", - "once": "^1.4.0", - "universal-user-agent": "^4.0.0" - }, - "dependencies": { - "is-plain-object": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", - "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", - "dev": true, - "requires": { - "isobject": "^4.0.0" - } - }, - "isobject": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", - "dev": true - } - } - }, - "@octokit/request-error": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz", - "integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "@octokit/rest": { - "version": "16.43.1", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz", - "integrity": "sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==", - "dev": true, - "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/plugin-paginate-rest": "^1.1.1", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "2.4.0", - "@octokit/request": "^5.2.0", - "@octokit/request-error": "^1.0.2", - "atob-lite": "^2.0.0", - "before-after-hook": "^2.0.0", - "btoa-lite": "^1.0.0", - "deprecation": "^2.0.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "lodash.uniq": "^4.5.0", - "octokit-pagination-methods": "^1.1.0", - "once": "^1.4.0", - "universal-user-agent": "^4.0.0" - } - }, - "@octokit/types": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.1.1.tgz", - "integrity": "sha512-89LOYH+d/vsbDX785NOfLxTW88GjNd0lWRz1DVPVsZgg9Yett5O+3MOvwo7iHgvUwbFz0mf/yPIjBkUbs4kxoQ==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", - "dev": true + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, "@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "dev": true + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", - "dev": true + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, "@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "dev": true, "requires": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -1782,32 +1682,27 @@ "@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", - "dev": true + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" }, "@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", - "dev": true + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" }, "@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", - "dev": true + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" }, "@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", - "dev": true + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" }, "@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", - "dev": true + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, "@samverschueren/stream-to-observable": { "version": "0.3.0", @@ -1825,9 +1720,9 @@ "dev": true }, "@sinonjs/commons": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.0.tgz", - "integrity": "sha512-qbk9AP+cZUsKdW1GJsBpxPKFmCJ0T8swwzVje3qFd+AkQb74Q/tiuzrdfFg8AD2g5HH/XbE/I8Uc1KYHVYWfhg==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", + "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -1846,6 +1741,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.1.1.tgz", "integrity": "sha512-8TLlC85CXgKNoTeqoXtrscPmKDbQCBfwZJ4hqli/QI4STa7sD2H6UqI9LSg8uBV5FYaD0QSdj/mtrCDrELvF+Q==", + "optional": true, "requires": { "@dsherret/to-absolute-glob": "^2.0.2", "fs-extra": "^8.1.0", @@ -1860,6 +1756,7 @@ "version": "10.0.2", "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "optional": true, "requires": { "@types/glob": "^7.1.1", "array-union": "^2.1.0", @@ -1874,7 +1771,8 @@ "typescript": { "version": "3.7.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", - "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==" + "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==", + "optional": true } } }, @@ -1882,15 +1780,14 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", - "dev": true, "requires": { "@types/node": "*" } }, "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.2.tgz", + "integrity": "sha512-cfCCrFmiGY/yq0NuKNxIQvZFy9kY/1immpSpTngOnyIbD4+eJOG5mxphhHDv3CHL9GltO4GcKr54kGBg3RNdbg==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -1920,9 +1817,9 @@ } }, "@types/babel__traverse": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.8.tgz", - "integrity": "sha512-yGeB2dHEdvxjP0y4UbRtQaSkXJ9649fYCmIdRoul5kfAoGCwxuCbMhag0k3RPfnuh9kPGm8x89btcfDEXdVWGw==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.9.tgz", + "integrity": "sha512-jEFQ8L1tuvPjOI8lnpaf73oCJe+aoxL6ygqSy6c8LcW98zaC+4mzWuQIRCEvKeCOu+lbqdXcg4Uqmm1S8AP1tw==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -1932,7 +1829,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz", "integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==", - "dev": true, "requires": { "@types/connect": "*", "@types/node": "*" @@ -1941,23 +1837,90 @@ "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, "@types/connect": { "version": "3.4.33", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", - "dev": true, "requires": { "@types/node": "*" + }, + "dependencies": { + "@jest/types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz", + "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "@types/yargs": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.1.tgz", + "integrity": "sha512-sYlwNU7zYi6eZbMzFvG6eHD7VsEvFdoDtlD7eI1JTg7YNnuguzmiGsc6MPSq5l8n+h21AsNof0je+9sgOe4+dg==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@types/cookies": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.4.tgz", "integrity": "sha512-oTGtMzZZAVuEjTwCjIh8T8FrC8n/uwy+PG0yTvQcdZ7etoel7C7/3MSd7qrukENTgQtotG7gvBlBojuVs7X5rw==", - "dev": true, "requires": { "@types/connect": "*", "@types/express": "*", @@ -1989,7 +1952,6 @@ "version": "4.17.2", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz", "integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==", - "dev": true, "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "*", @@ -2000,7 +1962,6 @@ "version": "4.17.2", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz", "integrity": "sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==", - "dev": true, "requires": { "@types/node": "*", "@types/range-parser": "*" @@ -2010,7 +1971,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz", "integrity": "sha512-FKVPOCFbhCvZxpVAMhdBdTfVfXUpsh15wFHgqOKxh9N9vzWZVuWCSijZ5T4U34XYNnuj2oduh6xcs1i+LPI+BQ==", - "dev": true, "requires": { "@types/node": "*" } @@ -2028,13 +1988,13 @@ "@types/graphql": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.2.3.tgz", - "integrity": "sha512-UoCovaxbJIxagCvVfalfK7YaNhmxj3BQFRQ2RHQKLiu+9wNXhJnlbspsLHt/YQM99IaLUUFJNzCwzc6W0ypMeQ==" + "integrity": "sha512-UoCovaxbJIxagCvVfalfK7YaNhmxj3BQFRQ2RHQKLiu+9wNXhJnlbspsLHt/YQM99IaLUUFJNzCwzc6W0ypMeQ==", + "dev": true }, "@types/graphql-upload": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/@types/graphql-upload/-/graphql-upload-8.0.3.tgz", "integrity": "sha512-hmLg9pCU/GmxBscg8GCr1vmSoEmbItNNxdD5YH2TJkXm//8atjwuprB+xJBK714JG1dkxbbhp5RHX+Pz1KsCMA==", - "dev": true, "requires": { "@types/express": "*", "@types/fs-capacitor": "*", @@ -2045,20 +2005,17 @@ "@types/http-assert": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.1.tgz", - "integrity": "sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==", - "dev": true + "integrity": "sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==" }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==" }, "@types/istanbul-lib-report": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "dev": true, "requires": { "@types/istanbul-lib-coverage": "*" } @@ -2067,7 +2024,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, "requires": { "@types/istanbul-lib-coverage": "*", "@types/istanbul-lib-report": "*" @@ -2081,6 +2037,94 @@ "requires": { "jest-diff": "^25.1.0", "pretty-format": "^25.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz", + "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz", + "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==", + "dev": true, + "requires": { + "@jest/types": "^25.1.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@types/json-schema": { @@ -2092,14 +2136,12 @@ "@types/keygrip": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", - "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==", - "dev": true + "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==" }, "@types/koa": { "version": "2.11.1", "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.11.1.tgz", "integrity": "sha512-/kqQs+8Qd9GL0cdl39HEhK91k7xq6+Zci76RUdqtTLj1Mg1aVG7zwJm3snkeyFUeAvY8noY27eMXgqg1wHZgwA==", - "dev": true, "requires": { "@types/accepts": "*", "@types/cookies": "*", @@ -2113,7 +2155,6 @@ "version": "3.2.5", "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.5.tgz", "integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==", - "dev": true, "requires": { "@types/koa": "*" } @@ -2121,14 +2162,12 @@ "@types/long": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", - "dev": true + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/mime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", - "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", - "dev": true + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" }, "@types/minimatch": { "version": "3.0.3", @@ -2144,7 +2183,6 @@ "version": "2.5.4", "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.4.tgz", "integrity": "sha512-Oz6id++2qAOFuOlE1j0ouk1dzl3mmI1+qINPNBhi9nt/gVOz0G+13Ao6qjhdF0Ys+eOkhu6JnFmt38bR3H0POQ==", - "dev": true, "requires": { "@types/node": "*" } @@ -2164,8 +2202,7 @@ "@types/range-parser": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", - "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", - "dev": true + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, "@types/semver": { "version": "6.0.0", @@ -2177,7 +2214,6 @@ "version": "1.13.3", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", - "dev": true, "requires": { "@types/express-serve-static-core": "*", "@types/mime": "*" @@ -2189,11 +2225,16 @@ "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", "dev": true }, + "@types/validator": { + "version": "10.11.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-10.11.3.tgz", + "integrity": "sha512-GKF2VnEkMmEeEGvoo03ocrP9ySMuX1ypKazIYMlsjfslfBMhOAtC5dmEWKdJioW4lJN7MZRS88kalTsVClyQ9w==", + "optional": true + }, "@types/ws": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.4.tgz", "integrity": "sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg==", - "dev": true, "requires": { "@types/node": "*" } @@ -2210,8 +2251,7 @@ "@types/yargs-parser": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw==", - "dev": true + "integrity": "sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw==" }, "@typescript-eslint/eslint-plugin": { "version": "2.20.0", @@ -2488,7 +2528,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -2558,7 +2597,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.6.1.tgz", "integrity": "sha512-B9BgpQGR1ndeDtb4Gtor0J4CITQ+OPACZrVW6lgStnljKEe9ZB76DZ1dAd3OCeizAswW6Lo9uvfK8jhVS5nBhQ==", - "dev": true, "requires": { "@types/node-fetch": "2.5.4", "core-js": "^3.0.1", @@ -2591,7 +2629,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.5.1.tgz", "integrity": "sha512-L7LHZ3k9Ao5OSf2WStvQhxdsNVplRQi7kCAPfqf9Z3GBEnQ2uaL0EgO0hSmtVHfXTbk5CTRziMT1Pe87bXrFIw==", - "dev": true, "requires": { "lru-cache": "^5.0.0" } @@ -2629,7 +2666,6 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-2.4.3.tgz", "integrity": "sha512-23R5Xo9OMYX0iyTu2/qT0EUb+AULCBriA9w8HDfMoChB8M+lFClqUkYtaTTHDfp6eoARLW8kDBhPOBavsvKAjA==", - "dev": true, "requires": { "node-fetch": "^2.1.2", "util.promisify": "^1.0.0" @@ -2788,7 +2824,8 @@ "array-differ": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==" + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "optional": true }, "array-equal": { "version": "1.0.0", @@ -2967,7 +3004,8 @@ "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "optional": true }, "asn1": { "version": "0.2.4", @@ -2999,14 +3037,12 @@ "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "async-retry": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", - "dev": true, "requires": { "retry": "0.12.0" } @@ -3023,12 +3059,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "atob-lite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", - "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", - "dev": true - }, "avvio": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/avvio/-/avvio-6.3.0.tgz", @@ -3251,8 +3281,7 @@ "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "dev": true + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, "balanced-match": { "version": "1.0.0", @@ -3323,12 +3352,6 @@ "tweetnacl": "^0.14.3" } }, - "before-after-hook": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", - "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", - "dev": true - }, "binary-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", @@ -3527,12 +3550,6 @@ "node-int64": "^0.4.0" } }, - "btoa-lite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", - "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", - "dev": true - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -3793,13 +3810,22 @@ } }, "class-validator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.9.1.tgz", - "integrity": "sha512-3wApflrd3ywVZyx4jaasGoFt8pmo4aGLPPAEKCKCsTRWVGPilahD88q3jQjRQwja50rl9a7rsP5LAxJYwGK8/Q==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.11.0.tgz", + "integrity": "sha512-niAmmSPFku9xsnpYYrddy8NZRrCX3yyoZ/rgPKOilE5BG0Ma1eVCIxpR4X0LasL/6BzbYzsutG+mSbAXlh4zNw==", "optional": true, "requires": { + "@types/validator": "10.11.3", "google-libphonenumber": "^3.1.6", - "validator": "10.4.0" + "validator": "12.0.0" + }, + "dependencies": { + "validator": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-12.0.0.tgz", + "integrity": "sha512-r5zA1cQBEOgYlesRmSEwc9LkbfNLTtji+vWyaHzRZUxCTHdsX3bd+sdHfs5tGZ2W6ILGGsxWxCNwT/h3IY/3ng==", + "optional": true + } } }, "clean-stack": { @@ -3963,7 +3989,8 @@ "code-block-writer": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.0.tgz", - "integrity": "sha512-RG9hpXtWFeUWhuUav1YuP/vGcyncW+t90yJLk9fNZs1De2OuHTHKAKThVCokt29PYq5RoJ0QSZaIZ+rvPO23hA==" + "integrity": "sha512-RG9hpXtWFeUWhuUav1YuP/vGcyncW+t90yJLk9fNZs1De2OuHTHKAKThVCokt29PYq5RoJ0QSZaIZ+rvPO23hA==", + "optional": true }, "code-point-at": { "version": "1.1.0", @@ -3991,7 +4018,6 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, "requires": { "color-name": "^1.1.1" } @@ -3999,8 +4025,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "combined-stream": { "version": "1.0.7", @@ -4183,8 +4208,7 @@ "core-js": { "version": "3.6.4", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", - "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==", - "dev": true + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==" }, "core-util-is": { "version": "1.0.2", @@ -4429,7 +4453,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -4484,8 +4507,7 @@ "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, "deprecated-decorator": { "version": "0.1.6", @@ -4502,12 +4524,6 @@ "lodash": "^4.17.11" } }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -4692,7 +4708,6 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", - "dev": true, "requires": { "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", @@ -4706,7 +4721,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -5271,8 +5285,7 @@ "eventemitter3": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", - "dev": true + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" }, "exec-sh": { "version": "0.3.4", @@ -5636,8 +5649,6 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==", "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.0", "merge2": "^1.3.0", "micromatch": "^4.0.2", @@ -5775,6 +5786,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", + "dev": true, "requires": { "reusify": "^1.0.0" } @@ -6005,13 +6017,13 @@ "fs-capacitor": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz", - "integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==", - "dev": true + "integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==" }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "optional": true, "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -6021,7 +6033,8 @@ "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "optional": true } } }, @@ -6039,8 +6052,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -6211,7 +6223,6 @@ "version": "14.6.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.6.0.tgz", "integrity": "sha512-VKzfvHEKybTKjQVpTFrA5yUq2S9ihcZvfJAtsDBBCuV6wauPu1xl/f9ehgVf0FcEJJs4vz6ysb/ZMkGigQZseg==", - "dev": true, "requires": { "iterall": "^1.2.2" } @@ -6248,8 +6259,7 @@ "graphql-tag": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.3.tgz", - "integrity": "sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA==", - "dev": true + "integrity": "sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA==" }, "graphql-tools": { "version": "4.0.7", @@ -6267,7 +6277,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-8.1.0.tgz", "integrity": "sha512-U2OiDI5VxYmzRKw0Z2dmfk0zkqMRaecH9Smh1U277gVgVe9Qn+18xqf4skwr4YJszGIh7iQDZ57+5ygOK9sM/Q==", - "dev": true, "requires": { "busboy": "^0.3.1", "fs-capacitor": "^2.0.4", @@ -6279,7 +6288,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==", - "dev": true, "requires": { "dicer": "0.3.0" } @@ -6288,7 +6296,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", - "dev": true, "requires": { "streamsearch": "0.1.2" } @@ -6297,7 +6304,6 @@ "version": "1.7.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.4", @@ -6309,8 +6315,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" } } }, @@ -6341,7 +6346,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -6364,8 +6368,7 @@ "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, "has-value": { "version": "1.0.0", @@ -6793,6 +6796,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "optional": true, "requires": { "is-relative": "^1.0.0", "is-windows": "^1.0.1" @@ -6841,8 +6845,7 @@ "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, "is-ci": { "version": "2.0.0", @@ -6876,8 +6879,7 @@ "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-descriptor": { "version": "0.1.6", @@ -6968,7 +6970,8 @@ "is-negated-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "optional": true }, "is-npm": { "version": "4.0.0", @@ -7027,7 +7030,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, "requires": { "has": "^1.0.1" } @@ -7048,6 +7050,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "optional": true, "requires": { "is-unc-path": "^1.0.0" } @@ -7077,7 +7080,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, "requires": { "has-symbols": "^1.0.0" } @@ -7101,6 +7103,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "optional": true, "requires": { "unc-path-regex": "^0.1.2" } @@ -7679,6 +7682,24 @@ "pretty-format": "^25.1.0" }, "dependencies": { + "@jest/types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz", + "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -7720,6 +7741,24 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "pretty-format": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz", + "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==", + "dev": true, + "requires": { + "@jest/types": "^25.1.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "dev": true + }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -9670,6 +9709,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optional": true, "requires": { "graceful-fs": "^4.1.6" } @@ -10099,7 +10139,8 @@ "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "optional": true }, "lodash.memoize": { "version": "4.1.2", @@ -10107,17 +10148,10 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", - "dev": true - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, "lodash.template": { "version": "4.5.0", @@ -10138,11 +10172,11 @@ "lodash._reinterpolate": "^3.0.0" } }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true + "lodash.xorby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.xorby/-/lodash.xorby-4.7.0.tgz", + "integrity": "sha1-nBmm+fBjputT3QPBtocXmYAUY9c=", + "optional": true }, "log-symbols": { "version": "3.0.0", @@ -10177,6 +10211,21 @@ "wrap-ansi": "^3.0.1" } }, + "loglevel": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz", + "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==", + "optional": true + }, + "loglevel-debug": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/loglevel-debug/-/loglevel-debug-0.0.1.tgz", + "integrity": "sha1-ifidPboTy6iiy0YV1dOtcYn0iik=", + "optional": true, + "requires": { + "loglevel": "^1.4.0" + } + }, "lolex": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", @@ -10189,8 +10238,7 @@ "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "dev": true + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "loud-rejection": { "version": "1.6.0", @@ -10212,7 +10260,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "requires": { "yallist": "^3.0.2" } @@ -10537,6 +10584,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", + "optional": true, "requires": { "@types/minimatch": "^3.0.3", "array-differ": "^3.0.0", @@ -10597,8 +10645,7 @@ "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", - "dev": true + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, "node-int64": { "version": "0.4.0", @@ -10737,14 +10784,12 @@ "object-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", - "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", - "dev": true + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==" }, "object-path": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", - "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=", - "dev": true + "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=" }, "object-visit": { "version": "1.0.1", @@ -10771,7 +10816,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" @@ -10857,12 +10901,6 @@ } } }, - "octokit-pagination-methods": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", - "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==", - "dev": true - }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -11293,47 +11331,20 @@ "dev": true }, "pretty-format": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz", - "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==", - "dev": true, + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "optional": true, "requires": { - "@jest/types": "^25.1.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0" }, "dependencies": { "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "optional": true } } }, @@ -11359,6 +11370,35 @@ "sisteransi": "^1.0.3" } }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "optional": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.5.tgz", + "integrity": "sha512-RElZIr/7JreF1eY6oD5RF3kpmdcreuQPjg5ri4oQ5g9sq7YWU8HkfB3eH8GwAwxf5OaCh0VPi7r4N/yoTGelrA==", + "optional": true + } + } + }, "protocols": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz", @@ -11468,12 +11508,6 @@ } } }, - "react-is": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", - "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", - "dev": true - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -11658,7 +11692,6 @@ "dev": true, "requires": { "@iarna/toml": "2.2.3", - "@octokit/rest": "16.43.1", "async-retry": "1.3.1", "chalk": "3.0.0", "cosmiconfig": "5.2.1", @@ -12047,13 +12080,13 @@ "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true }, "rfdc": { "version": "1.1.4", @@ -12065,6 +12098,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "requires": { "glob": "^7.1.3" } @@ -12084,11 +12118,6 @@ "is-promise": "^2.1.0" } }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" - }, "rxjs": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", @@ -12101,8 +12130,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "safe-regex": { "version": "1.1.0", @@ -12419,14 +12447,12 @@ "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -12783,8 +12809,7 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, "stealthy-require": { "version": "1.1.1", @@ -12795,8 +12820,7 @@ "streamsearch": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", - "dev": true + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, "string-argv": { "version": "0.3.1", @@ -12931,7 +12955,6 @@ "version": "0.9.16", "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.16.tgz", "integrity": "sha512-pQdoU7nC+EpStXnCfh/+ho0zE0Z+ma+i7xvj7bkXKb1dvYHSZxgRPaU6spRP+Bjzow67c/rRDoix5RT0uU9omw==", - "dev": true, "requires": { "backo2": "^1.0.2", "eventemitter3": "^3.1.0", @@ -12944,7 +12967,6 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, "requires": { "async-limiter": "~1.0.0" } @@ -13018,8 +13040,7 @@ "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, "symbol-tree": { "version": "3.2.4", @@ -13285,8 +13306,7 @@ "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tough-cookie": { "version": "3.0.1", @@ -13350,6 +13370,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-5.0.0.tgz", "integrity": "sha512-VP5dFnOzmlsDkSyuGczgVNtyJdYXMxFqMO2Rb0pIeni0o0Cy/nDljETBWhJs4FI4DIWv7Ftq69kgZO8p8w6LCw==", + "optional": true, "requires": { "@dsherret/to-absolute-glob": "^2.0.2", "@ts-morph/common": "~0.1.0", @@ -13370,9 +13391,9 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tsutils": { "version": "3.17.1", @@ -13510,7 +13531,8 @@ "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "optional": true }, "union-value": { "version": "1.0.1", @@ -13533,19 +13555,11 @@ "crypto-random-string": "^2.0.0" } }, - "universal-user-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", - "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", - "dev": true, - "requires": { - "os-name": "^3.1.0" - } - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "optional": true }, "unixify": { "version": "1.0.0", @@ -13730,7 +13744,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, "requires": { "define-properties": "^1.1.2", "object.getownpropertydescriptors": "^2.0.3" @@ -13782,12 +13795,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "validator": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.4.0.tgz", - "integrity": "sha512-Q/wBy3LB1uOyssgNlXSRmaf22NxjvDNZM2MtIQ4jaEOAB61xsh1TQxsq1CgzUMBV1lDrVMogIh8GjG1DYW0zLg==", - "optional": true - }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -14097,7 +14104,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "dev": true, "requires": { "async-limiter": "~1.0.0" } @@ -14135,8 +14141,7 @@ "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yaml": { "version": "1.7.2", diff --git a/package.json b/package.json index f1d3876e9..3350c054f 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "publish:npm": "npm publish --access public", "prepublish:next": "npm run build", "publish:next": "npm publish --access public --tag next", - "test:integration": "jest --config ./tests/jest-e2e.json", + "test:integration": "jest --config ./tests/jest-e2e.json --runInBand", "prerelease": "npm run build", "release": "release-it" }, @@ -28,6 +28,7 @@ "@types/graphql": "14.2.3", "@types/jest": "25.1.3", "@types/node": "12.12.21", + "@types/node-fetch": "^2.5.2", "@types/normalize-path": "3.0.0", "@typescript-eslint/eslint-plugin": "2.20.0", "@typescript-eslint/parser": "2.20.0", @@ -42,6 +43,7 @@ "jest": "25.1.0", "lint-staged": "10.0.7", "prettier": "1.19.1", + "rimraf": "3.0.2", "release-it": "12.6.1", "reflect-metadata": "0.1.13", "supertest": "4.0.2", @@ -50,7 +52,6 @@ "typescript": "3.8.2" }, "dependencies": { - "@types/graphql": "14.2.3", "chokidar": "3.3.1", "fast-glob": "3.2.2", "graphql-tools": "4.0.7", @@ -58,8 +59,7 @@ "lodash": "4.17.15", "merge-graphql-schemas": "1.7.6", "normalize-path": "3.0.0", - "rimraf": "3.0.2", - "ts-morph": "5.0.0", + "tslib": "^1.10.0", "uuid": "3.4.0" }, "peerDependencies": { @@ -68,6 +68,9 @@ "reflect-metadata": "^0.1.12" }, "optionalDependencies": { + "@apollo/federation": "^0.10.1", + "@apollo/gateway": "^0.10.8", + "ts-morph": "^5.0.0", "type-graphql": "^0.17.3" }, "lint-staged": { diff --git a/tests/e2e/generated-definitions.spec.ts b/tests/e2e/generated-definitions.spec.ts index d8fe41408..08654d0b1 100644 --- a/tests/e2e/generated-definitions.spec.ts +++ b/tests/e2e/generated-definitions.spec.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import * as util from 'util'; import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; -import { GraphQLFactory } from '../../lib'; +import { GraphQLFactory, GraphQLDefinitionsFactory } from '../../lib'; import { ApplicationModule } from '../type-graphql/app.module'; const readFile = util.promisify(fs.readFile); @@ -161,6 +161,21 @@ describe('Generated Definitions', () => { ).toBe(await readFile(outputFile, 'utf8')); }); + it('should generate for a federated graph', async () => { + const outputFile = generatedDefinitions('federation.test-definitions.ts'); + const factory = new GraphQLDefinitionsFactory(); + await factory.generate({ + typePaths: [generatedDefinitions('federation.graphql')], + path: outputFile, + outputAs: 'class', + federation: true, + }); + + expect( + await readFile(generatedDefinitions('federation.fixture.ts'), 'utf8'), + ).toBe(await readFile(outputFile, 'utf8')); + }); + afterEach(async () => { await app.close(); }); diff --git a/tests/e2e/graphql-fastify.spec.ts b/tests/e2e/graphql-fastify.spec.ts index be7f1b1c4..68a43e2f5 100644 --- a/tests/e2e/graphql-fastify.spec.ts +++ b/tests/e2e/graphql-fastify.spec.ts @@ -4,7 +4,7 @@ import * as request from 'supertest'; import { ApplicationModule } from '../graphql/app.module'; import { FastifyAdapter } from '@nestjs/platform-fastify'; -describe('GraphQL', () => { +describe('GraphQL with fastify', () => { let app: INestApplication; beforeEach(async () => { diff --git a/tests/e2e/graphql-federation-async-class.spec.ts b/tests/e2e/graphql-federation-async-class.spec.ts new file mode 100644 index 000000000..826184203 --- /dev/null +++ b/tests/e2e/graphql-federation-async-class.spec.ts @@ -0,0 +1,45 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule } from '../graphql-federation/users-service/federation-users.async-class.module'; + +describe('GraphQL Federation async-class', () => { + let app: INestApplication; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + }); + + it(`should return query result`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getUser(id: "5") { + id, + name, + } + }`, + }) + .expect(200, { + data: { + getUser: { + id: '5', + name: 'GraphQL', + }, + }, + }); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/tests/e2e/graphql-federation-async-existing.spec.ts b/tests/e2e/graphql-federation-async-existing.spec.ts new file mode 100644 index 000000000..8a3a5c6e5 --- /dev/null +++ b/tests/e2e/graphql-federation-async-existing.spec.ts @@ -0,0 +1,45 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule } from '../graphql-federation/users-service/federation-users.async-existing.module'; + +describe('GraphQL Federation Async', () => { + let app: INestApplication; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + }); + + it(`should return query result`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getUser(id: "5") { + id, + name, + } + }`, + }) + .expect(200, { + data: { + getUser: { + id: '5', + name: 'GraphQL', + }, + }, + }); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/tests/e2e/graphql-federation-async.spec.ts b/tests/e2e/graphql-federation-async.spec.ts new file mode 100644 index 000000000..69182b033 --- /dev/null +++ b/tests/e2e/graphql-federation-async.spec.ts @@ -0,0 +1,45 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule } from '../graphql-federation/users-service/federation-users.async.module'; + +describe('GraphQL Federation Async', () => { + let app: INestApplication; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + }); + + it(`should return query result`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getUser(id: "5") { + id, + name, + } + }`, + }) + .expect(200, { + data: { + getUser: { + id: '5', + name: 'GraphQL', + }, + }, + }); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/tests/e2e/graphql-federation-fastify.spec.ts b/tests/e2e/graphql-federation-fastify.spec.ts new file mode 100644 index 000000000..c6b1803a6 --- /dev/null +++ b/tests/e2e/graphql-federation-fastify.spec.ts @@ -0,0 +1,54 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { FastifyAdapter } from '@nestjs/platform-fastify'; + +describe('GraphQL federation with fastify', () => { + let app: INestApplication; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = module.createNestApplication(new FastifyAdapter()); + await app.init(); + await app + .getHttpAdapter() + .getInstance() + .ready(); + }); + + it(`should return query result`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + }, + ], + }, + }); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/tests/e2e/graphql-federation.spec.ts b/tests/e2e/graphql-federation.spec.ts new file mode 100644 index 000000000..49ffec84c --- /dev/null +++ b/tests/e2e/graphql-federation.spec.ts @@ -0,0 +1,151 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule as PostsModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { AppModule as UsersModule } from '../graphql-federation/users-service/federation-users.module'; + +describe('GraphQL Federation', () => { + let app: INestApplication; + + describe('UsersService', () => { + beforeEach(async () => { + const module = await Test.createTestingModule({ + imports: [UsersModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + }); + + it(`should return query result`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getUser(id: "5") { + id, + name, + } + }`, + }) + .expect(200, { + data: { + getUser: { + id: '5', + name: 'GraphQL', + }, + }, + }); + }); + }); + + describe('PostsService', () => { + beforeEach(async () => { + const module = await Test.createTestingModule({ + imports: [PostsModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + }); + + it(`should return query result`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + }, + ], + }, + }); + }); + + it('should return a stripped reference', () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + user { + id + } + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + user: { + id: '5', + }, + }, + ], + }, + }); + }); + + it(`should handle scalars`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + mutation { + publishPost(id: "1", publishDate: 500) { + id, + title, + body, + publishDate + } + }`, + }) + .expect(200, { + data: { + publishPost: { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + publishDate: 500, + }, + }, + }); + }); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/tests/e2e/graphql-gateway-async-class.spec.ts b/tests/e2e/graphql-gateway-async-class.spec.ts new file mode 100644 index 000000000..95f272637 --- /dev/null +++ b/tests/e2e/graphql-gateway-async-class.spec.ts @@ -0,0 +1,77 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule as PostsModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { AppModule as UsersModule } from '../graphql-federation/users-service/federation-users.module'; +import { AppModule as GatewayModule } from '../graphql-federation/gateway/gateway-async-class.module'; + +describe('GraphQL Gateway async-class', () => { + let postsApp: INestApplication; + let usersApp: INestApplication; + let gatewayApp: INestApplication; + + beforeEach(async () => { + const usersModule = await Test.createTestingModule({ + imports: [UsersModule], + }).compile(); + + usersApp = usersModule.createNestApplication(); + await usersApp.listenAsync(3001); + + const postsModule = await Test.createTestingModule({ + imports: [PostsModule], + }).compile(); + + postsApp = postsModule.createNestApplication(); + await postsApp.listenAsync(3002); + + const gatewayModule = await Test.createTestingModule({ + imports: [GatewayModule], + }).compile(); + + gatewayApp = gatewayModule.createNestApplication(); + await gatewayApp.init(); + }); + + it(`should run lookup across boundaries`, () => { + return request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + user { + id, + name, + } + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + user: { + id: '5', + name: 'GraphQL', + }, + }, + ], + }, + }); + }); + + afterEach(async () => { + await postsApp.close(); + await usersApp.close(); + await gatewayApp.close(); + }); +}); diff --git a/tests/e2e/graphql-gateway-async-existing.spec.ts b/tests/e2e/graphql-gateway-async-existing.spec.ts new file mode 100644 index 000000000..67ff35aea --- /dev/null +++ b/tests/e2e/graphql-gateway-async-existing.spec.ts @@ -0,0 +1,77 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule as PostsModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { AppModule as UsersModule } from '../graphql-federation/users-service/federation-users.module'; +import { AppModule as GatewayModule } from '../graphql-federation/gateway/gateway-async-existing.module'; + +describe('GraphQL gateway async-existing', () => { + let postsApp: INestApplication; + let usersApp: INestApplication; + let gatewayApp: INestApplication; + + beforeEach(async () => { + const usersModule = await Test.createTestingModule({ + imports: [UsersModule], + }).compile(); + + usersApp = usersModule.createNestApplication(); + await usersApp.listenAsync(3001); + + const postsModule = await Test.createTestingModule({ + imports: [PostsModule], + }).compile(); + + postsApp = postsModule.createNestApplication(); + await postsApp.listenAsync(3002); + + const gatewayModule = await Test.createTestingModule({ + imports: [GatewayModule], + }).compile(); + + gatewayApp = gatewayModule.createNestApplication(); + await gatewayApp.init(); + }); + + it(`should run lookup across boundaries`, () => { + return request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + user { + id, + name, + } + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + user: { + id: '5', + name: 'GraphQL', + }, + }, + ], + }, + }); + }); + + afterEach(async () => { + await postsApp.close(); + await usersApp.close(); + await gatewayApp.close(); + }); +}); diff --git a/tests/e2e/graphql-gateway-async.spec.ts b/tests/e2e/graphql-gateway-async.spec.ts new file mode 100644 index 000000000..4d0513f44 --- /dev/null +++ b/tests/e2e/graphql-gateway-async.spec.ts @@ -0,0 +1,77 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule as PostsModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { AppModule as UsersModule } from '../graphql-federation/users-service/federation-users.module'; +import { AppModule as GatewayModule } from '../graphql-federation/gateway/gateway-async.module'; + +describe('GraphQL Gateway async', () => { + let postsApp: INestApplication; + let usersApp: INestApplication; + let gatewayApp: INestApplication; + + beforeEach(async () => { + const usersModule = await Test.createTestingModule({ + imports: [UsersModule], + }).compile(); + + usersApp = usersModule.createNestApplication(); + await usersApp.listenAsync(3001); + + const postsModule = await Test.createTestingModule({ + imports: [PostsModule], + }).compile(); + + postsApp = postsModule.createNestApplication(); + await postsApp.listenAsync(3002); + + const gatewayModule = await Test.createTestingModule({ + imports: [GatewayModule], + }).compile(); + + gatewayApp = gatewayModule.createNestApplication(); + await gatewayApp.init(); + }); + + it(`should run lookup across boundaries`, () => { + return request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + user { + id, + name, + } + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + user: { + id: '5', + name: 'GraphQL', + }, + }, + ], + }, + }); + }); + + afterEach(async () => { + await postsApp.close(); + await usersApp.close(); + await gatewayApp.close(); + }); +}); diff --git a/tests/e2e/graphql-gateway-buildservice.spec.ts b/tests/e2e/graphql-gateway-buildservice.spec.ts new file mode 100644 index 000000000..03cef4cc7 --- /dev/null +++ b/tests/e2e/graphql-gateway-buildservice.spec.ts @@ -0,0 +1,90 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule as PostsModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { AppModule as UsersModule } from '../graphql-federation/users-service/federation-users.module'; +import { AppModule as GatewayModule } from '../graphql-federation/gateway/gateway-buildservice.module'; +import { RemoteGraphQLDataSource } from '@apollo/gateway'; +import { GRAPHQL_GATEWAY_BUILD_SERVICE } from '../../lib/graphql.constants'; + +describe('GraphQL Gateway buildservice', () => { + let postsApp: INestApplication; + let usersApp: INestApplication; + let gatewayApp: INestApplication; + let buildServiceHook: Function; + + beforeEach(async () => { + buildServiceHook = jest.fn(); + const usersModule = await Test.createTestingModule({ + imports: [UsersModule], + }).compile(); + + usersApp = usersModule.createNestApplication(); + await usersApp.listenAsync(3001); + + const postsModule = await Test.createTestingModule({ + imports: [PostsModule], + }).compile(); + + postsApp = postsModule.createNestApplication(); + await postsApp.listenAsync(3002); + + const gatewayModule = await Test.createTestingModule({ + imports: [GatewayModule], + }) + .overrideProvider(GRAPHQL_GATEWAY_BUILD_SERVICE) + .useValue(({ url }) => { + return new RemoteGraphQLDataSource({ + url, + willSendRequest: buildServiceHook as any, + }); + }) + .compile(); + + gatewayApp = gatewayModule.createNestApplication(); + await gatewayApp.init(); + }); + + it(`should run query through build service`, async () => { + await request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + user { + id, + name, + } + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + user: { + id: '5', + name: 'GraphQL', + }, + }, + ], + }, + }); + expect(buildServiceHook).toHaveBeenCalled(); + }); + + afterEach(async () => { + await postsApp.close(); + await usersApp.close(); + await gatewayApp.close(); + }); +}); diff --git a/tests/e2e/graphql-gateway-fastify.spec.ts b/tests/e2e/graphql-gateway-fastify.spec.ts new file mode 100644 index 000000000..fcea537a8 --- /dev/null +++ b/tests/e2e/graphql-gateway-fastify.spec.ts @@ -0,0 +1,119 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule as PostsModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { AppModule as UsersModule } from '../graphql-federation/users-service/federation-users.module'; +import { AppModule as GatewayModule } from '../graphql-federation/gateway/gateway.module'; +import { FastifyAdapter } from '@nestjs/platform-fastify'; + +describe('GraphQL Gateway with fastify', () => { + let postsApp: INestApplication; + let usersApp: INestApplication; + let gatewayApp: INestApplication; + + beforeEach(async () => { + const usersModule = await Test.createTestingModule({ + imports: [UsersModule], + }).compile(); + + usersApp = usersModule.createNestApplication(); + await usersApp.listenAsync(3001); + + const postsModule = await Test.createTestingModule({ + imports: [PostsModule], + }).compile(); + + postsApp = postsModule.createNestApplication(); + await postsApp.listenAsync(3002); + + const gatewayModule = await Test.createTestingModule({ + imports: [GatewayModule], + }).compile(); + + gatewayApp = gatewayModule.createNestApplication(new FastifyAdapter()); + await gatewayApp.init(); + await gatewayApp + .getHttpAdapter() + .getInstance() + .ready(); + }); + + it(`should run lookup across boundaries`, () => { + return request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + user { + id, + name, + } + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + user: { + id: '5', + name: 'GraphQL', + }, + }, + ], + }, + }); + }); + + it(`should run reverse lookup across boundaries`, () => { + return request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getUser(id: "5") { + id, + name, + posts { + id, + title, + body, + } + } + }`, + }) + .expect(200, { + data: { + getUser: { + id: '5', + name: 'GraphQL', + posts: [ + { + id: '1', + title: 'Hello world', + body: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + }, + ], + }, + }, + }); + }); + + afterEach(async () => { + await postsApp.close(); + await usersApp.close(); + await gatewayApp.close(); + }); +}); diff --git a/tests/e2e/graphql-gateway.spec.ts b/tests/e2e/graphql-gateway.spec.ts new file mode 100644 index 000000000..e906f6d24 --- /dev/null +++ b/tests/e2e/graphql-gateway.spec.ts @@ -0,0 +1,114 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule as PostsModule } from '../graphql-federation/posts-service/federation-posts.module'; +import { AppModule as UsersModule } from '../graphql-federation/users-service/federation-users.module'; +import { AppModule as GatewayModule } from '../graphql-federation/gateway/gateway.module'; + +describe('GraphQL Gateway', () => { + let postsApp: INestApplication; + let usersApp: INestApplication; + let gatewayApp: INestApplication; + + beforeEach(async () => { + const usersModule = await Test.createTestingModule({ + imports: [UsersModule], + }).compile(); + + usersApp = usersModule.createNestApplication(); + await usersApp.listenAsync(3001); + + const postsModule = await Test.createTestingModule({ + imports: [PostsModule], + }).compile(); + + postsApp = postsModule.createNestApplication(); + await postsApp.listenAsync(3002); + + const gatewayModule = await Test.createTestingModule({ + imports: [GatewayModule], + }).compile(); + + gatewayApp = gatewayModule.createNestApplication(); + await gatewayApp.init(); + }); + + it(`should run lookup across boundaries`, () => { + return request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getPosts { + id, + title, + body, + user { + id, + name, + } + } + }`, + }) + .expect(200, { + data: { + getPosts: [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + user: { + id: '5', + name: 'GraphQL', + }, + }, + ], + }, + }); + }); + + it(`should run reverse lookup across boundaries`, () => { + return request(gatewayApp.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + getUser(id: "5") { + id, + name, + posts { + id, + title, + body, + } + } + }`, + }) + .expect(200, { + data: { + getUser: { + id: '5', + name: 'GraphQL', + posts: [ + { + id: '1', + title: 'Hello world', + body: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + }, + ], + }, + }, + }); + }); + + afterEach(async () => { + await postsApp.close(); + await usersApp.close(); + await gatewayApp.close(); + }); +}); diff --git a/tests/e2e/typegraphql-federation.spec.ts b/tests/e2e/typegraphql-federation.spec.ts new file mode 100644 index 000000000..6e7e33fe2 --- /dev/null +++ b/tests/e2e/typegraphql-federation.spec.ts @@ -0,0 +1,42 @@ +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import * as request from 'supertest'; +// import { ApplicationModule } from '../type-graphql-federation/app.module'; + +describe.skip('TypeGraphQL - Federation', () => { + let app: INestApplication; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + imports: [], // ApplicationModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + }); + + it(`should return query result`, () => { + return request(app.getHttpServer()) + .post('/graphql') + .send({ + operationName: null, + variables: {}, + query: ` + { + _service { sdl } + }`, + }) + .expect(200, { + data: { + _service: { + sdl: + 'type Post @key(fields: "id") {\n id: ID!\n title: String!\n authorId: Int!\n}\n\ntype Query {\n findPost(id: Float!): Post!\n getPosts: [Post!]!\n}\n\ntype User @extends @key(fields: "id") {\n id: ID! @external\n posts: [Post!]!\n}\n', + }, + }, + }); + }); + + afterEach(async () => { + await app.close(); + }); +}); diff --git a/tests/generated-definitions/federation.fixture.ts b/tests/generated-definitions/federation.fixture.ts new file mode 100644 index 000000000..1f91b9687 --- /dev/null +++ b/tests/generated-definitions/federation.fixture.ts @@ -0,0 +1,11 @@ + +/** ------------------------------------------------------ + * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) + * ------------------------------------------------------- + */ + +/* tslint:disable */ +export class Post { + id: string; + title: string; +} diff --git a/tests/generated-definitions/federation.graphql b/tests/generated-definitions/federation.graphql new file mode 100644 index 000000000..7d030b6a4 --- /dev/null +++ b/tests/generated-definitions/federation.graphql @@ -0,0 +1,13 @@ +type Post { + id: ID! + title: String! +} + +extend type User @key(fields: "id") { + id: ID! @external + posts: [Post] +} + +extend type Query { + getPosts: [Post] +} \ No newline at end of file diff --git a/tests/graphql-federation/gateway/config/config.module.ts b/tests/graphql-federation/gateway/config/config.module.ts new file mode 100644 index 000000000..eaa505c84 --- /dev/null +++ b/tests/graphql-federation/gateway/config/config.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { ConfigService } from './config.service'; + +@Module({ + providers: [ConfigService], + exports: [ConfigService], +}) +export class ConfigModule {} diff --git a/tests/graphql-federation/gateway/config/config.service.ts b/tests/graphql-federation/gateway/config/config.service.ts new file mode 100644 index 000000000..55b3a7b70 --- /dev/null +++ b/tests/graphql-federation/gateway/config/config.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@nestjs/common'; +import { GatewayModuleOptions, GatewayOptionsFactory } from '../../../../lib'; + +@Injectable() +export class ConfigService implements GatewayOptionsFactory { + public createGatewayOptions(): Partial { + return { + gateway: { + serviceList: [ + { name: 'users', url: 'http://localhost:3001/graphql' }, + { name: 'posts', url: 'http://localhost:3002/graphql' }, + ], + }, + }; + } +} diff --git a/tests/graphql-federation/gateway/gateway-async-class.module.ts b/tests/graphql-federation/gateway/gateway-async-class.module.ts new file mode 100644 index 000000000..1a62f29f2 --- /dev/null +++ b/tests/graphql-federation/gateway/gateway-async-class.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { GraphQLGatewayModule } from '../../../lib/graphql-gateway.module'; +import { ConfigModule } from './config/config.module'; +import { ConfigService } from './config/config.service'; + +@Module({ + imports: [ + GraphQLGatewayModule.forRootAsync({ + useClass: ConfigService, + imports: [ConfigModule], + inject: [ConfigService], + }), + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/gateway/gateway-async-existing.module.ts b/tests/graphql-federation/gateway/gateway-async-existing.module.ts new file mode 100644 index 000000000..3f801a2d0 --- /dev/null +++ b/tests/graphql-federation/gateway/gateway-async-existing.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common'; +import { GraphQLGatewayModule } from '../../../lib/graphql-gateway.module'; +import { ConfigModule } from './config/config.module'; +import { ConfigService } from './config/config.service'; + +@Module({ + imports: [ + GraphQLGatewayModule.forRootAsync({ + useExisting: ConfigService, + imports: [ConfigModule], + inject: [ConfigService], + }), + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/gateway/gateway-async.module.ts b/tests/graphql-federation/gateway/gateway-async.module.ts new file mode 100644 index 000000000..a270c7296 --- /dev/null +++ b/tests/graphql-federation/gateway/gateway-async.module.ts @@ -0,0 +1,17 @@ +import { Module } from '@nestjs/common'; +import { GraphQLGatewayModule } from '../../../lib/graphql-gateway.module'; +import { ConfigModule } from './config/config.module'; +import { ConfigService } from './config/config.service'; + +@Module({ + imports: [ + GraphQLGatewayModule.forRootAsync({ + useFactory: async (configService: ConfigService) => ({ + ...configService.createGatewayOptions(), + }), + imports: [ConfigModule], + inject: [ConfigService], + }), + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/gateway/gateway-buildservice.module.ts b/tests/graphql-federation/gateway/gateway-buildservice.module.ts new file mode 100644 index 000000000..228b4a356 --- /dev/null +++ b/tests/graphql-federation/gateway/gateway-buildservice.module.ts @@ -0,0 +1,37 @@ +import { Module } from '@nestjs/common'; +import { + GRAPHQL_GATEWAY_BUILD_SERVICE, + GraphQLGatewayModule, +} from '../../../lib'; +import { RemoteGraphQLDataSource } from '@apollo/gateway'; + +@Module({ + providers: [ + { + provide: GRAPHQL_GATEWAY_BUILD_SERVICE, + useValue: ({ name, url }) => { + return new RemoteGraphQLDataSource({ url }); + }, + }, + ], + exports: [GRAPHQL_GATEWAY_BUILD_SERVICE], +}) +class BuildServiceModule {} + +@Module({ + imports: [ + GraphQLGatewayModule.forRootAsync({ + useFactory: async () => ({ + gateway: { + serviceList: [ + { name: 'users', url: 'http://localhost:3001/graphql' }, + { name: 'posts', url: 'http://localhost:3002/graphql' }, + ], + }, + }), + imports: [BuildServiceModule], + inject: [GRAPHQL_GATEWAY_BUILD_SERVICE], + }), + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/gateway/gateway.module.ts b/tests/graphql-federation/gateway/gateway.module.ts new file mode 100644 index 000000000..4a0e9f8d8 --- /dev/null +++ b/tests/graphql-federation/gateway/gateway.module.ts @@ -0,0 +1,16 @@ +import { Module } from '@nestjs/common'; +import { GraphQLGatewayModule } from '../../../lib/graphql-gateway.module'; + +@Module({ + imports: [ + GraphQLGatewayModule.forRoot({ + gateway: { + serviceList: [ + { name: 'users', url: 'http://localhost:3001/graphql' }, + { name: 'posts', url: 'http://localhost:3002/graphql' }, + ], + }, + }), + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/posts-service/federation-posts.module.ts b/tests/graphql-federation/posts-service/federation-posts.module.ts new file mode 100644 index 000000000..8ecd698e1 --- /dev/null +++ b/tests/graphql-federation/posts-service/federation-posts.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { GraphQLFederationModule } from '../../../lib/graphql-federation.module'; +import { PostsModule } from './posts/posts.module'; +import { join } from 'path'; + +@Module({ + imports: [ + GraphQLFederationModule.forRoot({ + typePaths: [join(__dirname, '**/*.graphql')], + }), + PostsModule, + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/posts-service/posts/date.scalar.ts b/tests/graphql-federation/posts-service/posts/date.scalar.ts new file mode 100644 index 000000000..fb49f412f --- /dev/null +++ b/tests/graphql-federation/posts-service/posts/date.scalar.ts @@ -0,0 +1,26 @@ +import { Scalar, CustomScalar } from '../../../../lib'; +import { Kind, ValueNode } from 'graphql'; + +@Scalar('Date') +export class DateScalar implements CustomScalar { + description = 'Date custom scalar type'; + + parseValue(value: any): Date { + const date = new Date(parseInt(value, 10)); // value from the client + if (isNaN(date.getTime())) { + throw new TypeError('Invalid date given'); + } + return date; + } + + serialize(value: Date): number { + return value.getTime(); // value sent to the client + } + + parseLiteral(ast: ValueNode): Date { + if (ast.kind === Kind.INT) { + return new Date(parseInt(ast.value, 10)); // value from the client + } + return null; + } +} diff --git a/tests/graphql-federation/posts-service/posts/posts.interfaces.ts b/tests/graphql-federation/posts-service/posts/posts.interfaces.ts new file mode 100644 index 000000000..1ff6a20f9 --- /dev/null +++ b/tests/graphql-federation/posts-service/posts/posts.interfaces.ts @@ -0,0 +1,7 @@ +export interface Post { + id: string; + title: string; + body: string; + userId: string; + publishDate: Date; +} diff --git a/tests/graphql-federation/posts-service/posts/posts.module.ts b/tests/graphql-federation/posts-service/posts/posts.module.ts new file mode 100644 index 000000000..3747ab33a --- /dev/null +++ b/tests/graphql-federation/posts-service/posts/posts.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { PostsResolvers } from './posts.resolvers'; +import { UsersResolvers } from './users.resolvers'; +import { PostsService } from './posts.service'; +import { DateScalar } from './date.scalar'; + +@Module({ + providers: [PostsResolvers, PostsService, UsersResolvers, DateScalar], +}) +export class PostsModule {} diff --git a/tests/graphql-federation/posts-service/posts/posts.resolvers.ts b/tests/graphql-federation/posts-service/posts/posts.resolvers.ts new file mode 100644 index 000000000..4f0e131eb --- /dev/null +++ b/tests/graphql-federation/posts-service/posts/posts.resolvers.ts @@ -0,0 +1,30 @@ +import { + Query, + Resolver, + Parent, + ResolveProperty, + Mutation, + Args, +} from '../../../../lib'; +import { PostsService } from './posts.service'; +import { Post } from './posts.interfaces'; + +@Resolver('Post') +export class PostsResolvers { + constructor(private readonly postsService: PostsService) {} + + @Query('getPosts') + getPosts() { + return this.postsService.findAll(); + } + + @Mutation() + publishPost(@Args('id') id, @Args('publishDate') publishDate: Date) { + return this.postsService.publish(id, publishDate); + } + + @ResolveProperty('user') + getUser(@Parent() post: Post) { + return { __typename: 'User', id: post.userId }; + } +} diff --git a/tests/graphql-federation/posts-service/posts/posts.service.ts b/tests/graphql-federation/posts-service/posts/posts.service.ts new file mode 100644 index 000000000..ed28475b9 --- /dev/null +++ b/tests/graphql-federation/posts-service/posts/posts.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { Post } from './posts.interfaces'; + +@Injectable() +export class PostsService { + private readonly posts: Post[] = [ + { + id: '1', + title: 'Hello world', + body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + userId: '5', + publishDate: new Date(0), + }, + ]; + + findAll() { + return Promise.resolve(this.posts); + } + + findById(id: string) { + return Promise.resolve(this.posts.find(p => p.id === id)); + } + + findByUserId(id: string) { + return Promise.resolve(this.posts.filter(p => p.userId === id)); + } + + async publish(id: string, publishDate: Date) { + const post = await this.findById(id); + post.publishDate = publishDate; + return post; + } +} diff --git a/tests/graphql-federation/posts-service/posts/posts.types.graphql b/tests/graphql-federation/posts-service/posts/posts.types.graphql new file mode 100644 index 000000000..2a508fbd2 --- /dev/null +++ b/tests/graphql-federation/posts-service/posts/posts.types.graphql @@ -0,0 +1,22 @@ +scalar Date + +type Post @key(fields: "id") { + id: ID! + title: String! + body: String! + user: User + publishDate: Date +} + +extend type User @key(fields: "id") { + id: ID! @external + posts: [Post] +} + +extend type Query { + getPosts: [Post] +} + +extend type Mutation { + publishPost(id: ID!, publishDate: Date!): Post +} \ No newline at end of file diff --git a/tests/graphql-federation/posts-service/posts/users.resolvers.ts b/tests/graphql-federation/posts-service/posts/users.resolvers.ts new file mode 100644 index 000000000..eede198b1 --- /dev/null +++ b/tests/graphql-federation/posts-service/posts/users.resolvers.ts @@ -0,0 +1,12 @@ +import { Resolver, ResolveProperty } from '../../../../lib'; +import { PostsService } from './posts.service'; + +@Resolver('User') +export class UsersResolvers { + constructor(private readonly postsService: PostsService) {} + + @ResolveProperty('posts') + getPosts(reference: any) { + return this.postsService.findByUserId(reference.id); + } +} diff --git a/tests/graphql-federation/users-service/config/config.module.ts b/tests/graphql-federation/users-service/config/config.module.ts new file mode 100644 index 000000000..eaa505c84 --- /dev/null +++ b/tests/graphql-federation/users-service/config/config.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { ConfigService } from './config.service'; + +@Module({ + providers: [ConfigService], + exports: [ConfigService], +}) +export class ConfigModule {} diff --git a/tests/graphql-federation/users-service/config/config.service.ts b/tests/graphql-federation/users-service/config/config.service.ts new file mode 100644 index 000000000..6bfb60172 --- /dev/null +++ b/tests/graphql-federation/users-service/config/config.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@nestjs/common'; +import { GqlModuleOptions, GqlOptionsFactory } from '../../../../lib'; +import { join } from 'path'; + +@Injectable() +export class ConfigService implements GqlOptionsFactory { + public createGqlOptions(): Partial { + return { + typePaths: [join(__dirname, '../**/*.graphql')], + }; + } +} diff --git a/tests/graphql-federation/users-service/federation-users.async-class.module.ts b/tests/graphql-federation/users-service/federation-users.async-class.module.ts new file mode 100644 index 000000000..267a6500f --- /dev/null +++ b/tests/graphql-federation/users-service/federation-users.async-class.module.ts @@ -0,0 +1,17 @@ +import { Module } from '@nestjs/common'; +import { GraphQLFederationModule } from '../../../lib/graphql-federation.module'; +import { UsersModule } from './users/users.module'; +import { ConfigService } from './config/config.service'; +import { ConfigModule } from './config/config.module'; + +@Module({ + imports: [ + GraphQLFederationModule.forRootAsync({ + useClass: ConfigService, + imports: [ConfigModule], + inject: [ConfigService], + }), + UsersModule, + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/users-service/federation-users.async-existing.module.ts b/tests/graphql-federation/users-service/federation-users.async-existing.module.ts new file mode 100644 index 000000000..1c662c2f1 --- /dev/null +++ b/tests/graphql-federation/users-service/federation-users.async-existing.module.ts @@ -0,0 +1,17 @@ +import { Module } from '@nestjs/common'; +import { GraphQLFederationModule } from '../../../lib/graphql-federation.module'; +import { UsersModule } from './users/users.module'; +import { ConfigService } from './config/config.service'; +import { ConfigModule } from './config/config.module'; + +@Module({ + imports: [ + GraphQLFederationModule.forRootAsync({ + useExisting: ConfigService, + imports: [ConfigModule], + inject: [ConfigService], + }), + UsersModule, + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/users-service/federation-users.async.module.ts b/tests/graphql-federation/users-service/federation-users.async.module.ts new file mode 100644 index 000000000..5dc859563 --- /dev/null +++ b/tests/graphql-federation/users-service/federation-users.async.module.ts @@ -0,0 +1,19 @@ +import { Module } from '@nestjs/common'; +import { GraphQLFederationModule } from '../../../lib/graphql-federation.module'; +import { UsersModule } from './users/users.module'; +import { ConfigService } from './config/config.service'; +import { ConfigModule } from './config/config.module'; + +@Module({ + imports: [ + GraphQLFederationModule.forRootAsync({ + useFactory: async (configService: ConfigService) => ({ + ...configService.createGqlOptions(), + }), + imports: [ConfigModule], + inject: [ConfigService], + }), + UsersModule, + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/users-service/federation-users.module.ts b/tests/graphql-federation/users-service/federation-users.module.ts new file mode 100644 index 000000000..d706e28d7 --- /dev/null +++ b/tests/graphql-federation/users-service/federation-users.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { GraphQLFederationModule } from '../../../lib/graphql-federation.module'; +import { UsersModule } from './users/users.module'; +import { join } from 'path'; + +@Module({ + imports: [ + GraphQLFederationModule.forRoot({ + typePaths: [join(__dirname, '**/*.graphql')], + }), + UsersModule, + ], +}) +export class AppModule {} diff --git a/tests/graphql-federation/users-service/users/users.interfaces.ts b/tests/graphql-federation/users-service/users/users.interfaces.ts new file mode 100644 index 000000000..c58931c6c --- /dev/null +++ b/tests/graphql-federation/users-service/users/users.interfaces.ts @@ -0,0 +1,4 @@ +export interface User { + id: string; + name: string; +} diff --git a/tests/graphql-federation/users-service/users/users.module.ts b/tests/graphql-federation/users-service/users/users.module.ts new file mode 100644 index 000000000..d71042e83 --- /dev/null +++ b/tests/graphql-federation/users-service/users/users.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { UsersResolvers } from './users.resolvers'; +import { UsersService } from './users.service'; + +@Module({ + providers: [UsersResolvers, UsersService], +}) +export class UsersModule {} diff --git a/tests/graphql-federation/users-service/users/users.resolvers.ts b/tests/graphql-federation/users-service/users/users.resolvers.ts new file mode 100644 index 000000000..76b21101b --- /dev/null +++ b/tests/graphql-federation/users-service/users/users.resolvers.ts @@ -0,0 +1,17 @@ +import { Args, Query, Resolver, ResolveReference } from '../../../../lib'; +import { UsersService } from './users.service'; + +@Resolver('User') +export class UsersResolvers { + constructor(private readonly usersService: UsersService) {} + + @Query() + getUser(@Args('id') id: string) { + return this.usersService.findById(id); + } + + @ResolveReference() + resolveReference(reference: { __typename: string; id: string }) { + return this.usersService.findById(reference.id); + } +} diff --git a/tests/graphql-federation/users-service/users/users.service.ts b/tests/graphql-federation/users-service/users/users.service.ts new file mode 100644 index 000000000..c4dffb1db --- /dev/null +++ b/tests/graphql-federation/users-service/users/users.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@nestjs/common'; +import { User } from './users.interfaces'; + +@Injectable() +export class UsersService { + private readonly users: User[] = [ + { + id: '5', + name: 'GraphQL', + }, + ]; + + findById(id: string) { + return Promise.resolve(this.users.find(p => p.id === id)); + } +} diff --git a/tests/graphql-federation/users-service/users/users.types.graphql b/tests/graphql-federation/users-service/users/users.types.graphql new file mode 100644 index 000000000..d1ebd5b21 --- /dev/null +++ b/tests/graphql-federation/users-service/users/users.types.graphql @@ -0,0 +1,8 @@ +type User @key(fields: "id") { + id: ID! + name: String! +} + +extend type Query { + getUser(id: ID!): User +} \ No newline at end of file diff --git a/tests/type-graphql-federation/app.module.ts b/tests/type-graphql-federation/app.module.ts new file mode 100644 index 000000000..5542db0c4 --- /dev/null +++ b/tests/type-graphql-federation/app.module.ts @@ -0,0 +1,20 @@ +import { Module } from '@nestjs/common'; +import { GraphQLFederationModule } from '../../lib'; +import { UserModule } from './user/user.module'; +import { PostModule } from './post/post.module'; +import { User } from './user/user.entity'; + +@Module({ + imports: [ + UserModule, + PostModule, + GraphQLFederationModule.forRoot({ + debug: false, + autoSchemaFile: true, + buildSchemaOptions: { + orphanedTypes: [User], + }, + }), + ], +}) +export class ApplicationModule {} diff --git a/tests/type-graphql-federation/main.ts b/tests/type-graphql-federation/main.ts new file mode 100644 index 000000000..c04a543a1 --- /dev/null +++ b/tests/type-graphql-federation/main.ts @@ -0,0 +1,10 @@ +import { ValidationPipe } from '@nestjs/common'; +import { NestFactory } from '@nestjs/core'; +import { ApplicationModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(ApplicationModule); + app.useGlobalPipes(new ValidationPipe()); + await app.listen(3000); +} +bootstrap(); diff --git a/tests/type-graphql-federation/post/post.entity.ts b/tests/type-graphql-federation/post/post.entity.ts new file mode 100644 index 000000000..5cd68f897 --- /dev/null +++ b/tests/type-graphql-federation/post/post.entity.ts @@ -0,0 +1,18 @@ +import { Field, ID, ObjectType, Directive, Int } from 'type-graphql'; + +@ObjectType() +@Directive('@key(fields: "id")') +export class Post { + @Field(type => ID) + public id: number; + + @Field() + public title: string; + + @Field(type => Int) + public authorId: number; + + constructor(post: Partial) { + Object.assign(this, post); + } +} diff --git a/tests/type-graphql-federation/post/post.module.ts b/tests/type-graphql-federation/post/post.module.ts new file mode 100644 index 000000000..1cba92ef0 --- /dev/null +++ b/tests/type-graphql-federation/post/post.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { PostService } from './post.service'; +import { PostResolver } from './post.resolver'; + +@Module({ + providers: [PostService, PostResolver], + exports: [PostService], +}) +export class PostModule {} diff --git a/tests/type-graphql-federation/post/post.resolver.ts b/tests/type-graphql-federation/post/post.resolver.ts new file mode 100644 index 000000000..c6a42e587 --- /dev/null +++ b/tests/type-graphql-federation/post/post.resolver.ts @@ -0,0 +1,23 @@ +import { Query, Args, ResolveReference, Resolver } from '../../../lib'; +import { PostService } from './post.service'; +import { Post } from './post.entity'; + +@Resolver(of => Post) +export class PostResolver { + constructor(private readonly postService: PostService) {} + + @Query(returns => Post) + public findPost(@Args('id') id: number) { + return this.postService.findOne(id); + } + + @Query(returns => [Post]) + public getPosts() { + return this.postService.all(); + } + + @ResolveReference() + public resolveRef(reference: any) { + return this.postService.findOne(reference.id); + } +} diff --git a/tests/type-graphql-federation/post/post.service.ts b/tests/type-graphql-federation/post/post.service.ts new file mode 100644 index 000000000..09f9a6a31 --- /dev/null +++ b/tests/type-graphql-federation/post/post.service.ts @@ -0,0 +1,34 @@ +import { Post } from './post.entity'; +import { Injectable } from '@nestjs/common'; + +const data = [ + { + id: 1, + title: 'hello world', + authorId: 2, + }, + { + id: 2, + title: 'lorem ipsum', + authorId: 1, + }, +]; + +@Injectable() +export class PostService { + public findOne(id: number) { + const post = data.find(p => p.id === id); + if (post) { + return new Post(post); + } + return null; + } + + public all() { + return data.map(p => new Post(p)); + } + + public forAuthor(authorId: number) { + return data.filter(p => p.authorId === authorId).map(p => new Post(p)); + } +} diff --git a/tests/type-graphql-federation/user/user.entity.ts b/tests/type-graphql-federation/user/user.entity.ts new file mode 100644 index 000000000..6b718d353 --- /dev/null +++ b/tests/type-graphql-federation/user/user.entity.ts @@ -0,0 +1,18 @@ +import { Field, ID, ObjectType, Directive } from 'type-graphql'; +import { Post } from '../post/post.entity'; + +@ObjectType() +@Directive('@extends') +@Directive('@key(fields: "id")') +export class User { + @Field(type => ID) + @Directive('@external') + public id: number; + + @Field(type => [Post]) + public posts: Post[]; + + constructor(post: Partial) { + Object.assign(this, post); + } +} diff --git a/tests/type-graphql-federation/user/user.module.ts b/tests/type-graphql-federation/user/user.module.ts new file mode 100644 index 000000000..502eb79af --- /dev/null +++ b/tests/type-graphql-federation/user/user.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { UserResolver } from './user.resolver'; +import { PostModule } from '../post/post.module'; + +@Module({ + providers: [UserResolver], + imports: [PostModule], +}) +export class UserModule {} diff --git a/tests/type-graphql-federation/user/user.resolver.ts b/tests/type-graphql-federation/user/user.resolver.ts new file mode 100644 index 000000000..5ced2e1db --- /dev/null +++ b/tests/type-graphql-federation/user/user.resolver.ts @@ -0,0 +1,13 @@ +import { ResolveProperty, Parent, Resolver } from '../../../lib'; +import { PostService } from '../post/post.service'; +import { User } from './user.entity'; + +@Resolver(of => User) +export class UserResolver { + constructor(private readonly postService: PostService) {} + + @ResolveProperty() + public posts(@Parent() user: User) { + return this.postService.forAuthor(user.id); + } +} diff --git a/tsconfig.json b/tsconfig.json index a0e4c5dc3..fa0991cd9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "module": "commonjs", "declaration": true, "noImplicitAny": false, + "importHelpers": true, "removeComments": true, "noLib": false, "emitDecoratorMetadata": true,