@depup/apollo__server 5.5.0-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/changes.json +46 -0
- package/dist/cjs/ApolloServer.d.ts +126 -0
- package/dist/cjs/ApolloServer.d.ts.map +1 -0
- package/dist/cjs/ApolloServer.js +726 -0
- package/dist/cjs/ApolloServer.js.map +1 -0
- package/dist/cjs/cachePolicy.d.ts +3 -0
- package/dist/cjs/cachePolicy.d.ts.map +1 -0
- package/dist/cjs/cachePolicy.js +33 -0
- package/dist/cjs/cachePolicy.js.map +1 -0
- package/dist/cjs/determineApolloConfig.d.ts +4 -0
- package/dist/cjs/determineApolloConfig.d.ts.map +1 -0
- package/dist/cjs/determineApolloConfig.js +58 -0
- package/dist/cjs/determineApolloConfig.js.map +1 -0
- package/dist/cjs/errorNormalize.d.ts +12 -0
- package/dist/cjs/errorNormalize.d.ts.map +1 -0
- package/dist/cjs/errorNormalize.js +71 -0
- package/dist/cjs/errorNormalize.js.map +1 -0
- package/dist/cjs/errors/index.d.ts +16 -0
- package/dist/cjs/errors/index.d.ts.map +1 -0
- package/dist/cjs/errors/index.js +28 -0
- package/dist/cjs/errors/index.js.map +1 -0
- package/dist/cjs/externalTypes/constructor.d.ts +78 -0
- package/dist/cjs/externalTypes/constructor.d.ts.map +1 -0
- package/dist/cjs/externalTypes/constructor.js +3 -0
- package/dist/cjs/externalTypes/constructor.js.map +1 -0
- package/dist/cjs/externalTypes/context.d.ts +4 -0
- package/dist/cjs/externalTypes/context.d.ts.map +1 -0
- package/dist/cjs/externalTypes/context.js +3 -0
- package/dist/cjs/externalTypes/context.js.map +1 -0
- package/dist/cjs/externalTypes/graphql.d.ts +41 -0
- package/dist/cjs/externalTypes/graphql.d.ts.map +1 -0
- package/dist/cjs/externalTypes/graphql.js +3 -0
- package/dist/cjs/externalTypes/graphql.js.map +1 -0
- package/dist/cjs/externalTypes/http.d.ts +22 -0
- package/dist/cjs/externalTypes/http.d.ts.map +1 -0
- package/dist/cjs/externalTypes/http.js +3 -0
- package/dist/cjs/externalTypes/http.js.map +1 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha2.d.ts +28 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha2.d.ts.map +1 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha2.js +3 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha2.js.map +1 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha9.d.ts +43 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha9.d.ts.map +1 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha9.js +3 -0
- package/dist/cjs/externalTypes/incrementalDeliveryPolyfillAlpha9.js.map +1 -0
- package/dist/cjs/externalTypes/index.d.ts +9 -0
- package/dist/cjs/externalTypes/index.d.ts.map +1 -0
- package/dist/cjs/externalTypes/index.js +3 -0
- package/dist/cjs/externalTypes/index.js.map +1 -0
- package/dist/cjs/externalTypes/plugins.d.ts +75 -0
- package/dist/cjs/externalTypes/plugins.d.ts.map +1 -0
- package/dist/cjs/externalTypes/plugins.js +3 -0
- package/dist/cjs/externalTypes/plugins.js.map +1 -0
- package/dist/cjs/externalTypes/requestPipeline.d.ts +50 -0
- package/dist/cjs/externalTypes/requestPipeline.d.ts.map +1 -0
- package/dist/cjs/externalTypes/requestPipeline.js +3 -0
- package/dist/cjs/externalTypes/requestPipeline.js.map +1 -0
- package/dist/cjs/generated/packageVersion.d.ts +2 -0
- package/dist/cjs/generated/packageVersion.d.ts.map +1 -0
- package/dist/cjs/generated/packageVersion.js +5 -0
- package/dist/cjs/generated/packageVersion.js.map +1 -0
- package/dist/cjs/httpBatching.d.ts +4 -0
- package/dist/cjs/httpBatching.d.ts.map +1 -0
- package/dist/cjs/httpBatching.js +58 -0
- package/dist/cjs/httpBatching.js.map +1 -0
- package/dist/cjs/incrementalDeliveryPolyfill.d.ts +82 -0
- package/dist/cjs/incrementalDeliveryPolyfill.d.ts.map +1 -0
- package/dist/cjs/incrementalDeliveryPolyfill.js +74 -0
- package/dist/cjs/incrementalDeliveryPolyfill.js.map +1 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/internalErrorClasses.d.ts +28 -0
- package/dist/cjs/internalErrorClasses.d.ts.map +1 -0
- package/dist/cjs/internalErrorClasses.js +91 -0
- package/dist/cjs/internalErrorClasses.js.map +1 -0
- package/dist/cjs/internalPlugin.d.ts +9 -0
- package/dist/cjs/internalPlugin.d.ts.map +1 -0
- package/dist/cjs/internalPlugin.js +11 -0
- package/dist/cjs/internalPlugin.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/plugin/cacheControl/index.d.ts +9 -0
- package/dist/cjs/plugin/cacheControl/index.d.ts.map +1 -0
- package/dist/cjs/plugin/cacheControl/index.js +223 -0
- package/dist/cjs/plugin/cacheControl/index.js.map +1 -0
- package/dist/cjs/plugin/disableSuggestions/index.d.ts +3 -0
- package/dist/cjs/plugin/disableSuggestions/index.d.ts.map +1 -0
- package/dist/cjs/plugin/disableSuggestions/index.js +22 -0
- package/dist/cjs/plugin/disableSuggestions/index.js.map +1 -0
- package/dist/cjs/plugin/disabled/index.d.ts +7 -0
- package/dist/cjs/plugin/disabled/index.d.ts.map +1 -0
- package/dist/cjs/plugin/disabled/index.js +30 -0
- package/dist/cjs/plugin/disabled/index.js.map +1 -0
- package/dist/cjs/plugin/drainHttpServer/index.d.ts +8 -0
- package/dist/cjs/plugin/drainHttpServer/index.d.ts.map +1 -0
- package/dist/cjs/plugin/drainHttpServer/index.js +19 -0
- package/dist/cjs/plugin/drainHttpServer/index.js.map +1 -0
- package/dist/cjs/plugin/drainHttpServer/stoppable.d.ts +10 -0
- package/dist/cjs/plugin/drainHttpServer/stoppable.d.ts.map +1 -0
- package/dist/cjs/plugin/drainHttpServer/stoppable.js +54 -0
- package/dist/cjs/plugin/drainHttpServer/stoppable.js.map +1 -0
- package/dist/cjs/plugin/inlineTrace/index.d.ts +8 -0
- package/dist/cjs/plugin/inlineTrace/index.d.ts.map +1 -0
- package/dist/cjs/plugin/inlineTrace/index.js +70 -0
- package/dist/cjs/plugin/inlineTrace/index.js.map +1 -0
- package/dist/cjs/plugin/landingPage/default/getEmbeddedHTML.d.ts +4 -0
- package/dist/cjs/plugin/landingPage/default/getEmbeddedHTML.d.ts.map +1 -0
- package/dist/cjs/plugin/landingPage/default/getEmbeddedHTML.js +143 -0
- package/dist/cjs/plugin/landingPage/default/getEmbeddedHTML.js.map +1 -0
- package/dist/cjs/plugin/landingPage/default/index.d.ts +9 -0
- package/dist/cjs/plugin/landingPage/default/index.d.ts.map +1 -0
- package/dist/cjs/plugin/landingPage/default/index.js +146 -0
- package/dist/cjs/plugin/landingPage/default/index.js.map +1 -0
- package/dist/cjs/plugin/landingPage/default/types.d.ts +56 -0
- package/dist/cjs/plugin/landingPage/default/types.d.ts.map +1 -0
- package/dist/cjs/plugin/landingPage/default/types.js +3 -0
- package/dist/cjs/plugin/landingPage/default/types.js.map +1 -0
- package/dist/cjs/plugin/schemaIsSubgraph.d.ts +3 -0
- package/dist/cjs/plugin/schemaIsSubgraph.d.ts.map +1 -0
- package/dist/cjs/plugin/schemaIsSubgraph.js +23 -0
- package/dist/cjs/plugin/schemaIsSubgraph.js.map +1 -0
- package/dist/cjs/plugin/schemaReporting/index.d.ts +10 -0
- package/dist/cjs/plugin/schemaReporting/index.d.ts.map +1 -0
- package/dist/cjs/plugin/schemaReporting/index.js +104 -0
- package/dist/cjs/plugin/schemaReporting/index.js.map +1 -0
- package/dist/cjs/plugin/schemaReporting/schemaReporter.d.ts +33 -0
- package/dist/cjs/plugin/schemaReporting/schemaReporter.d.ts.map +1 -0
- package/dist/cjs/plugin/schemaReporting/schemaReporter.js +147 -0
- package/dist/cjs/plugin/schemaReporting/schemaReporter.js.map +1 -0
- package/dist/cjs/plugin/subscriptionCallback/index.d.ts +12 -0
- package/dist/cjs/plugin/subscriptionCallback/index.d.ts.map +1 -0
- package/dist/cjs/plugin/subscriptionCallback/index.js +434 -0
- package/dist/cjs/plugin/subscriptionCallback/index.js.map +1 -0
- package/dist/cjs/plugin/traceTreeBuilder.d.ts +25 -0
- package/dist/cjs/plugin/traceTreeBuilder.d.ts.map +1 -0
- package/dist/cjs/plugin/traceTreeBuilder.js +201 -0
- package/dist/cjs/plugin/traceTreeBuilder.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/defaultSendOperationsAsTrace.d.ts +3 -0
- package/dist/cjs/plugin/usageReporting/defaultSendOperationsAsTrace.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/defaultSendOperationsAsTrace.js +44 -0
- package/dist/cjs/plugin/usageReporting/defaultSendOperationsAsTrace.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/durationHistogram.d.ts +16 -0
- package/dist/cjs/plugin/usageReporting/durationHistogram.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/durationHistogram.js +68 -0
- package/dist/cjs/plugin/usageReporting/durationHistogram.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/index.d.ts +3 -0
- package/dist/cjs/plugin/usageReporting/index.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/index.js +6 -0
- package/dist/cjs/plugin/usageReporting/index.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/iterateOverTrace.d.ts +7 -0
- package/dist/cjs/plugin/usageReporting/iterateOverTrace.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/iterateOverTrace.js +81 -0
- package/dist/cjs/plugin/usageReporting/iterateOverTrace.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/operationDerivedDataCache.d.ts +12 -0
- package/dist/cjs/plugin/usageReporting/operationDerivedDataCache.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/operationDerivedDataCache.js +33 -0
- package/dist/cjs/plugin/usageReporting/operationDerivedDataCache.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/options.d.ts +60 -0
- package/dist/cjs/plugin/usageReporting/options.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/options.js +3 -0
- package/dist/cjs/plugin/usageReporting/options.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/plugin.d.ts +7 -0
- package/dist/cjs/plugin/usageReporting/plugin.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/plugin.js +494 -0
- package/dist/cjs/plugin/usageReporting/plugin.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/stats.d.ts +96 -0
- package/dist/cjs/plugin/usageReporting/stats.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/stats.js +289 -0
- package/dist/cjs/plugin/usageReporting/stats.js.map +1 -0
- package/dist/cjs/plugin/usageReporting/traceDetails.d.ts +4 -0
- package/dist/cjs/plugin/usageReporting/traceDetails.d.ts.map +1 -0
- package/dist/cjs/plugin/usageReporting/traceDetails.js +63 -0
- package/dist/cjs/plugin/usageReporting/traceDetails.js.map +1 -0
- package/dist/cjs/preventCsrf.d.ts +4 -0
- package/dist/cjs/preventCsrf.d.ts.map +1 -0
- package/dist/cjs/preventCsrf.js +41 -0
- package/dist/cjs/preventCsrf.js.map +1 -0
- package/dist/cjs/requestPipeline.d.ts +9 -0
- package/dist/cjs/requestPipeline.d.ts.map +1 -0
- package/dist/cjs/requestPipeline.js +371 -0
- package/dist/cjs/requestPipeline.js.map +1 -0
- package/dist/cjs/runHttpQuery.d.ts +15 -0
- package/dist/cjs/runHttpQuery.d.ts.map +1 -0
- package/dist/cjs/runHttpQuery.js +230 -0
- package/dist/cjs/runHttpQuery.js.map +1 -0
- package/dist/cjs/standalone/index.d.ts +25 -0
- package/dist/cjs/standalone/index.d.ts.map +1 -0
- package/dist/cjs/standalone/index.js +97 -0
- package/dist/cjs/standalone/index.js.map +1 -0
- package/dist/cjs/utils/HeaderMap.d.ts +8 -0
- package/dist/cjs/utils/HeaderMap.d.ts.map +1 -0
- package/dist/cjs/utils/HeaderMap.js +20 -0
- package/dist/cjs/utils/HeaderMap.js.map +1 -0
- package/dist/cjs/utils/UnreachableCaseError.d.ts +4 -0
- package/dist/cjs/utils/UnreachableCaseError.d.ts.map +1 -0
- package/dist/cjs/utils/UnreachableCaseError.js +10 -0
- package/dist/cjs/utils/UnreachableCaseError.js.map +1 -0
- package/dist/cjs/utils/computeCoreSchemaHash.d.ts +2 -0
- package/dist/cjs/utils/computeCoreSchemaHash.d.ts.map +1 -0
- package/dist/cjs/utils/computeCoreSchemaHash.js +8 -0
- package/dist/cjs/utils/computeCoreSchemaHash.js.map +1 -0
- package/dist/cjs/utils/invokeHooks.d.ts +7 -0
- package/dist/cjs/utils/invokeHooks.d.ts.map +1 -0
- package/dist/cjs/utils/invokeHooks.js +36 -0
- package/dist/cjs/utils/invokeHooks.js.map +1 -0
- package/dist/cjs/utils/isDefined.d.ts +2 -0
- package/dist/cjs/utils/isDefined.d.ts.map +1 -0
- package/dist/cjs/utils/isDefined.js +7 -0
- package/dist/cjs/utils/isDefined.js.map +1 -0
- package/dist/cjs/utils/makeGatewayGraphQLRequestContext.d.ts +5 -0
- package/dist/cjs/utils/makeGatewayGraphQLRequestContext.d.ts.map +1 -0
- package/dist/cjs/utils/makeGatewayGraphQLRequestContext.js +96 -0
- package/dist/cjs/utils/makeGatewayGraphQLRequestContext.js.map +1 -0
- package/dist/cjs/utils/resolvable.d.ts +7 -0
- package/dist/cjs/utils/resolvable.d.ts.map +1 -0
- package/dist/cjs/utils/resolvable.js +14 -0
- package/dist/cjs/utils/resolvable.js.map +1 -0
- package/dist/cjs/utils/schemaInstrumentation.d.ts +16 -0
- package/dist/cjs/utils/schemaInstrumentation.d.ts.map +1 -0
- package/dist/cjs/utils/schemaInstrumentation.js +75 -0
- package/dist/cjs/utils/schemaInstrumentation.js.map +1 -0
- package/dist/cjs/utils/schemaManager.d.ts +31 -0
- package/dist/cjs/utils/schemaManager.d.ts.map +1 -0
- package/dist/cjs/utils/schemaManager.js +103 -0
- package/dist/cjs/utils/schemaManager.js.map +1 -0
- package/dist/cjs/utils/urlForHttpServer.d.ts +3 -0
- package/dist/cjs/utils/urlForHttpServer.d.ts.map +1 -0
- package/dist/cjs/utils/urlForHttpServer.js +15 -0
- package/dist/cjs/utils/urlForHttpServer.js.map +1 -0
- package/dist/cjs/validationRules/NoIntrospection.d.ts +3 -0
- package/dist/cjs/validationRules/NoIntrospection.d.ts.map +1 -0
- package/dist/cjs/validationRules/NoIntrospection.js +19 -0
- package/dist/cjs/validationRules/NoIntrospection.js.map +1 -0
- package/dist/cjs/validationRules/RecursiveSelectionsLimit.d.ts +4 -0
- package/dist/cjs/validationRules/RecursiveSelectionsLimit.d.ts.map +1 -0
- package/dist/cjs/validationRules/RecursiveSelectionsLimit.js +150 -0
- package/dist/cjs/validationRules/RecursiveSelectionsLimit.js.map +1 -0
- package/dist/cjs/validationRules/index.d.ts +3 -0
- package/dist/cjs/validationRules/index.d.ts.map +1 -0
- package/dist/cjs/validationRules/index.js +9 -0
- package/dist/cjs/validationRules/index.js.map +1 -0
- package/dist/esm/ApolloServer.d.ts +126 -0
- package/dist/esm/ApolloServer.d.ts.map +1 -0
- package/dist/esm/ApolloServer.js +683 -0
- package/dist/esm/ApolloServer.js.map +1 -0
- package/dist/esm/cachePolicy.d.ts +3 -0
- package/dist/esm/cachePolicy.d.ts.map +1 -0
- package/dist/esm/cachePolicy.js +30 -0
- package/dist/esm/cachePolicy.js.map +1 -0
- package/dist/esm/determineApolloConfig.d.ts +4 -0
- package/dist/esm/determineApolloConfig.d.ts.map +1 -0
- package/dist/esm/determineApolloConfig.js +55 -0
- package/dist/esm/determineApolloConfig.js.map +1 -0
- package/dist/esm/errorNormalize.d.ts +12 -0
- package/dist/esm/errorNormalize.d.ts.map +1 -0
- package/dist/esm/errorNormalize.js +66 -0
- package/dist/esm/errorNormalize.js.map +1 -0
- package/dist/esm/errors/index.d.ts +16 -0
- package/dist/esm/errors/index.d.ts.map +1 -0
- package/dist/esm/errors/index.js +24 -0
- package/dist/esm/errors/index.js.map +1 -0
- package/dist/esm/externalTypes/constructor.d.ts +78 -0
- package/dist/esm/externalTypes/constructor.d.ts.map +1 -0
- package/dist/esm/externalTypes/constructor.js +2 -0
- package/dist/esm/externalTypes/constructor.js.map +1 -0
- package/dist/esm/externalTypes/context.d.ts +4 -0
- package/dist/esm/externalTypes/context.d.ts.map +1 -0
- package/dist/esm/externalTypes/context.js +2 -0
- package/dist/esm/externalTypes/context.js.map +1 -0
- package/dist/esm/externalTypes/graphql.d.ts +41 -0
- package/dist/esm/externalTypes/graphql.d.ts.map +1 -0
- package/dist/esm/externalTypes/graphql.js +2 -0
- package/dist/esm/externalTypes/graphql.js.map +1 -0
- package/dist/esm/externalTypes/http.d.ts +22 -0
- package/dist/esm/externalTypes/http.d.ts.map +1 -0
- package/dist/esm/externalTypes/http.js +2 -0
- package/dist/esm/externalTypes/http.js.map +1 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha2.d.ts +28 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha2.d.ts.map +1 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha2.js +2 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha2.js.map +1 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha9.d.ts +43 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha9.d.ts.map +1 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha9.js +2 -0
- package/dist/esm/externalTypes/incrementalDeliveryPolyfillAlpha9.js.map +1 -0
- package/dist/esm/externalTypes/index.d.ts +9 -0
- package/dist/esm/externalTypes/index.d.ts.map +1 -0
- package/dist/esm/externalTypes/index.js +2 -0
- package/dist/esm/externalTypes/index.js.map +1 -0
- package/dist/esm/externalTypes/plugins.d.ts +75 -0
- package/dist/esm/externalTypes/plugins.d.ts.map +1 -0
- package/dist/esm/externalTypes/plugins.js +2 -0
- package/dist/esm/externalTypes/plugins.js.map +1 -0
- package/dist/esm/externalTypes/requestPipeline.d.ts +50 -0
- package/dist/esm/externalTypes/requestPipeline.d.ts.map +1 -0
- package/dist/esm/externalTypes/requestPipeline.js +2 -0
- package/dist/esm/externalTypes/requestPipeline.js.map +1 -0
- package/dist/esm/generated/packageVersion.d.ts +2 -0
- package/dist/esm/generated/packageVersion.d.ts.map +1 -0
- package/dist/esm/generated/packageVersion.js +2 -0
- package/dist/esm/generated/packageVersion.js.map +1 -0
- package/dist/esm/httpBatching.d.ts +4 -0
- package/dist/esm/httpBatching.d.ts.map +1 -0
- package/dist/esm/httpBatching.js +55 -0
- package/dist/esm/httpBatching.js.map +1 -0
- package/dist/esm/incrementalDeliveryPolyfill.d.ts +82 -0
- package/dist/esm/incrementalDeliveryPolyfill.d.ts.map +1 -0
- package/dist/esm/incrementalDeliveryPolyfill.js +38 -0
- package/dist/esm/incrementalDeliveryPolyfill.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internalErrorClasses.d.ts +28 -0
- package/dist/esm/internalErrorClasses.d.ts.map +1 -0
- package/dist/esm/internalErrorClasses.js +81 -0
- package/dist/esm/internalErrorClasses.js.map +1 -0
- package/dist/esm/internalPlugin.d.ts +9 -0
- package/dist/esm/internalPlugin.d.ts.map +1 -0
- package/dist/esm/internalPlugin.js +7 -0
- package/dist/esm/internalPlugin.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/plugin/cacheControl/index.d.ts +9 -0
- package/dist/esm/plugin/cacheControl/index.d.ts.map +1 -0
- package/dist/esm/plugin/cacheControl/index.js +220 -0
- package/dist/esm/plugin/cacheControl/index.js.map +1 -0
- package/dist/esm/plugin/disableSuggestions/index.d.ts +3 -0
- package/dist/esm/plugin/disableSuggestions/index.d.ts.map +1 -0
- package/dist/esm/plugin/disableSuggestions/index.js +19 -0
- package/dist/esm/plugin/disableSuggestions/index.js.map +1 -0
- package/dist/esm/plugin/disabled/index.d.ts +7 -0
- package/dist/esm/plugin/disabled/index.d.ts.map +1 -0
- package/dist/esm/plugin/disabled/index.js +23 -0
- package/dist/esm/plugin/disabled/index.js.map +1 -0
- package/dist/esm/plugin/drainHttpServer/index.d.ts +8 -0
- package/dist/esm/plugin/drainHttpServer/index.d.ts.map +1 -0
- package/dist/esm/plugin/drainHttpServer/index.js +16 -0
- package/dist/esm/plugin/drainHttpServer/index.js.map +1 -0
- package/dist/esm/plugin/drainHttpServer/stoppable.d.ts +10 -0
- package/dist/esm/plugin/drainHttpServer/stoppable.d.ts.map +1 -0
- package/dist/esm/plugin/drainHttpServer/stoppable.js +47 -0
- package/dist/esm/plugin/drainHttpServer/stoppable.js.map +1 -0
- package/dist/esm/plugin/inlineTrace/index.d.ts +8 -0
- package/dist/esm/plugin/inlineTrace/index.d.ts.map +1 -0
- package/dist/esm/plugin/inlineTrace/index.js +67 -0
- package/dist/esm/plugin/inlineTrace/index.js.map +1 -0
- package/dist/esm/plugin/landingPage/default/getEmbeddedHTML.d.ts +4 -0
- package/dist/esm/plugin/landingPage/default/getEmbeddedHTML.d.ts.map +1 -0
- package/dist/esm/plugin/landingPage/default/getEmbeddedHTML.js +138 -0
- package/dist/esm/plugin/landingPage/default/getEmbeddedHTML.js.map +1 -0
- package/dist/esm/plugin/landingPage/default/index.d.ts +9 -0
- package/dist/esm/plugin/landingPage/default/index.d.ts.map +1 -0
- package/dist/esm/plugin/landingPage/default/index.js +141 -0
- package/dist/esm/plugin/landingPage/default/index.js.map +1 -0
- package/dist/esm/plugin/landingPage/default/types.d.ts +56 -0
- package/dist/esm/plugin/landingPage/default/types.d.ts.map +1 -0
- package/dist/esm/plugin/landingPage/default/types.js +2 -0
- package/dist/esm/plugin/landingPage/default/types.js.map +1 -0
- package/dist/esm/plugin/schemaIsSubgraph.d.ts +3 -0
- package/dist/esm/plugin/schemaIsSubgraph.d.ts.map +1 -0
- package/dist/esm/plugin/schemaIsSubgraph.js +20 -0
- package/dist/esm/plugin/schemaIsSubgraph.js.map +1 -0
- package/dist/esm/plugin/schemaReporting/index.d.ts +10 -0
- package/dist/esm/plugin/schemaReporting/index.d.ts.map +1 -0
- package/dist/esm/plugin/schemaReporting/index.js +98 -0
- package/dist/esm/plugin/schemaReporting/index.js.map +1 -0
- package/dist/esm/plugin/schemaReporting/schemaReporter.d.ts +33 -0
- package/dist/esm/plugin/schemaReporting/schemaReporter.d.ts.map +1 -0
- package/dist/esm/plugin/schemaReporting/schemaReporter.js +143 -0
- package/dist/esm/plugin/schemaReporting/schemaReporter.js.map +1 -0
- package/dist/esm/plugin/subscriptionCallback/index.d.ts +12 -0
- package/dist/esm/plugin/subscriptionCallback/index.d.ts.map +1 -0
- package/dist/esm/plugin/subscriptionCallback/index.js +428 -0
- package/dist/esm/plugin/subscriptionCallback/index.js.map +1 -0
- package/dist/esm/plugin/traceTreeBuilder.d.ts +25 -0
- package/dist/esm/plugin/traceTreeBuilder.d.ts.map +1 -0
- package/dist/esm/plugin/traceTreeBuilder.js +196 -0
- package/dist/esm/plugin/traceTreeBuilder.js.map +1 -0
- package/dist/esm/plugin/usageReporting/defaultSendOperationsAsTrace.d.ts +3 -0
- package/dist/esm/plugin/usageReporting/defaultSendOperationsAsTrace.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/defaultSendOperationsAsTrace.js +41 -0
- package/dist/esm/plugin/usageReporting/defaultSendOperationsAsTrace.js.map +1 -0
- package/dist/esm/plugin/usageReporting/durationHistogram.d.ts +16 -0
- package/dist/esm/plugin/usageReporting/durationHistogram.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/durationHistogram.js +64 -0
- package/dist/esm/plugin/usageReporting/durationHistogram.js.map +1 -0
- package/dist/esm/plugin/usageReporting/index.d.ts +3 -0
- package/dist/esm/plugin/usageReporting/index.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/index.js +2 -0
- package/dist/esm/plugin/usageReporting/index.js.map +1 -0
- package/dist/esm/plugin/usageReporting/iterateOverTrace.d.ts +7 -0
- package/dist/esm/plugin/usageReporting/iterateOverTrace.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/iterateOverTrace.js +78 -0
- package/dist/esm/plugin/usageReporting/iterateOverTrace.js.map +1 -0
- package/dist/esm/plugin/usageReporting/operationDerivedDataCache.d.ts +12 -0
- package/dist/esm/plugin/usageReporting/operationDerivedDataCache.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/operationDerivedDataCache.js +29 -0
- package/dist/esm/plugin/usageReporting/operationDerivedDataCache.js.map +1 -0
- package/dist/esm/plugin/usageReporting/options.d.ts +60 -0
- package/dist/esm/plugin/usageReporting/options.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/options.js +2 -0
- package/dist/esm/plugin/usageReporting/options.js.map +1 -0
- package/dist/esm/plugin/usageReporting/plugin.d.ts +7 -0
- package/dist/esm/plugin/usageReporting/plugin.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/plugin.js +487 -0
- package/dist/esm/plugin/usageReporting/plugin.js.map +1 -0
- package/dist/esm/plugin/usageReporting/stats.d.ts +96 -0
- package/dist/esm/plugin/usageReporting/stats.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/stats.js +283 -0
- package/dist/esm/plugin/usageReporting/stats.js.map +1 -0
- package/dist/esm/plugin/usageReporting/traceDetails.d.ts +4 -0
- package/dist/esm/plugin/usageReporting/traceDetails.d.ts.map +1 -0
- package/dist/esm/plugin/usageReporting/traceDetails.js +60 -0
- package/dist/esm/plugin/usageReporting/traceDetails.js.map +1 -0
- package/dist/esm/preventCsrf.d.ts +4 -0
- package/dist/esm/preventCsrf.d.ts.map +1 -0
- package/dist/esm/preventCsrf.js +34 -0
- package/dist/esm/preventCsrf.js.map +1 -0
- package/dist/esm/requestPipeline.d.ts +9 -0
- package/dist/esm/requestPipeline.d.ts.map +1 -0
- package/dist/esm/requestPipeline.js +364 -0
- package/dist/esm/requestPipeline.js.map +1 -0
- package/dist/esm/runHttpQuery.d.ts +15 -0
- package/dist/esm/runHttpQuery.d.ts.map +1 -0
- package/dist/esm/runHttpQuery.js +221 -0
- package/dist/esm/runHttpQuery.js.map +1 -0
- package/dist/esm/standalone/index.d.ts +25 -0
- package/dist/esm/standalone/index.d.ts.map +1 -0
- package/dist/esm/standalone/index.js +91 -0
- package/dist/esm/standalone/index.js.map +1 -0
- package/dist/esm/utils/HeaderMap.d.ts +8 -0
- package/dist/esm/utils/HeaderMap.d.ts.map +1 -0
- package/dist/esm/utils/HeaderMap.js +16 -0
- package/dist/esm/utils/HeaderMap.js.map +1 -0
- package/dist/esm/utils/UnreachableCaseError.d.ts +4 -0
- package/dist/esm/utils/UnreachableCaseError.d.ts.map +1 -0
- package/dist/esm/utils/UnreachableCaseError.js +6 -0
- package/dist/esm/utils/UnreachableCaseError.js.map +1 -0
- package/dist/esm/utils/computeCoreSchemaHash.d.ts +2 -0
- package/dist/esm/utils/computeCoreSchemaHash.d.ts.map +1 -0
- package/dist/esm/utils/computeCoreSchemaHash.js +5 -0
- package/dist/esm/utils/computeCoreSchemaHash.js.map +1 -0
- package/dist/esm/utils/invokeHooks.d.ts +7 -0
- package/dist/esm/utils/invokeHooks.d.ts.map +1 -0
- package/dist/esm/utils/invokeHooks.js +31 -0
- package/dist/esm/utils/invokeHooks.js.map +1 -0
- package/dist/esm/utils/isDefined.d.ts +2 -0
- package/dist/esm/utils/isDefined.d.ts.map +1 -0
- package/dist/esm/utils/isDefined.js +4 -0
- package/dist/esm/utils/isDefined.js.map +1 -0
- package/dist/esm/utils/makeGatewayGraphQLRequestContext.d.ts +5 -0
- package/dist/esm/utils/makeGatewayGraphQLRequestContext.d.ts.map +1 -0
- package/dist/esm/utils/makeGatewayGraphQLRequestContext.js +93 -0
- package/dist/esm/utils/makeGatewayGraphQLRequestContext.js.map +1 -0
- package/dist/esm/utils/resolvable.d.ts +7 -0
- package/dist/esm/utils/resolvable.d.ts.map +1 -0
- package/dist/esm/utils/resolvable.js +12 -0
- package/dist/esm/utils/resolvable.js.map +1 -0
- package/dist/esm/utils/schemaInstrumentation.d.ts +16 -0
- package/dist/esm/utils/schemaInstrumentation.d.ts.map +1 -0
- package/dist/esm/utils/schemaInstrumentation.js +69 -0
- package/dist/esm/utils/schemaInstrumentation.js.map +1 -0
- package/dist/esm/utils/schemaManager.d.ts +31 -0
- package/dist/esm/utils/schemaManager.d.ts.map +1 -0
- package/dist/esm/utils/schemaManager.js +99 -0
- package/dist/esm/utils/schemaManager.js.map +1 -0
- package/dist/esm/utils/urlForHttpServer.d.ts +3 -0
- package/dist/esm/utils/urlForHttpServer.d.ts.map +1 -0
- package/dist/esm/utils/urlForHttpServer.js +12 -0
- package/dist/esm/utils/urlForHttpServer.js.map +1 -0
- package/dist/esm/validationRules/NoIntrospection.d.ts +3 -0
- package/dist/esm/validationRules/NoIntrospection.d.ts.map +1 -0
- package/dist/esm/validationRules/NoIntrospection.js +15 -0
- package/dist/esm/validationRules/NoIntrospection.js.map +1 -0
- package/dist/esm/validationRules/RecursiveSelectionsLimit.d.ts +4 -0
- package/dist/esm/validationRules/RecursiveSelectionsLimit.d.ts.map +1 -0
- package/dist/esm/validationRules/RecursiveSelectionsLimit.js +146 -0
- package/dist/esm/validationRules/RecursiveSelectionsLimit.js.map +1 -0
- package/dist/esm/validationRules/index.d.ts +3 -0
- package/dist/esm/validationRules/index.d.ts.map +1 -0
- package/dist/esm/validationRules/index.js +3 -0
- package/dist/esm/validationRules/index.js.map +1 -0
- package/errors/package.json +8 -0
- package/package.json +208 -0
- package/plugin/cacheControl/package.json +8 -0
- package/plugin/disableSuggestions/package.json +8 -0
- package/plugin/disabled/package.json +8 -0
- package/plugin/drainHttpServer/package.json +8 -0
- package/plugin/inlineTrace/package.json +8 -0
- package/plugin/landingPage/default/package.json +8 -0
- package/plugin/schemaReporting/package.json +8 -0
- package/plugin/subscriptionCallback/package.json +8 -0
- package/plugin/usageReporting/package.json +8 -0
- package/src/ApolloServer.ts +1456 -0
- package/src/cachePolicy.ts +33 -0
- package/src/determineApolloConfig.ts +95 -0
- package/src/errorNormalize.ts +114 -0
- package/src/errors/index.ts +33 -0
- package/src/externalTypes/constructor.ts +174 -0
- package/src/externalTypes/context.ts +18 -0
- package/src/externalTypes/graphql.ts +81 -0
- package/src/externalTypes/http.ts +44 -0
- package/src/externalTypes/incrementalDeliveryPolyfillAlpha2.ts +63 -0
- package/src/externalTypes/incrementalDeliveryPolyfillAlpha9.ts +82 -0
- package/src/externalTypes/index.ts +73 -0
- package/src/externalTypes/plugins.ts +222 -0
- package/src/externalTypes/requestPipeline.ts +123 -0
- package/src/generated/packageVersion.ts +1 -0
- package/src/httpBatching.ts +105 -0
- package/src/incrementalDeliveryPolyfill.ts +253 -0
- package/src/index.ts +4 -0
- package/src/internalErrorClasses.ts +123 -0
- package/src/internalPlugin.ts +42 -0
- package/src/plugin/cacheControl/index.ts +453 -0
- package/src/plugin/disableSuggestions/index.ts +23 -0
- package/src/plugin/disabled/index.ts +41 -0
- package/src/plugin/drainHttpServer/index.ts +42 -0
- package/src/plugin/drainHttpServer/stoppable.ts +109 -0
- package/src/plugin/inlineTrace/index.ts +156 -0
- package/src/plugin/landingPage/default/getEmbeddedHTML.ts +204 -0
- package/src/plugin/landingPage/default/index.ts +219 -0
- package/src/plugin/landingPage/default/types.ts +198 -0
- package/src/plugin/schemaIsSubgraph.ts +41 -0
- package/src/plugin/schemaReporting/generated/operations.d.ts +18359 -0
- package/src/plugin/schemaReporting/index.ts +198 -0
- package/src/plugin/schemaReporting/schemaReporter.ts +207 -0
- package/src/plugin/subscriptionCallback/index.ts +724 -0
- package/src/plugin/traceTreeBuilder.ts +356 -0
- package/src/plugin/usageReporting/defaultSendOperationsAsTrace.ts +74 -0
- package/src/plugin/usageReporting/durationHistogram.ts +87 -0
- package/src/plugin/usageReporting/index.ts +9 -0
- package/src/plugin/usageReporting/iterateOverTrace.ts +140 -0
- package/src/plugin/usageReporting/operationDerivedDataCache.ts +61 -0
- package/src/plugin/usageReporting/options.ts +414 -0
- package/src/plugin/usageReporting/plugin.ts +871 -0
- package/src/plugin/usageReporting/stats.ts +492 -0
- package/src/plugin/usageReporting/traceDetails.ts +96 -0
- package/src/preventCsrf.ts +99 -0
- package/src/requestPipeline.ts +821 -0
- package/src/runHttpQuery.ts +408 -0
- package/src/standalone/index.ts +155 -0
- package/src/utils/HeaderMap.ts +22 -0
- package/src/utils/UnreachableCaseError.ts +10 -0
- package/src/utils/computeCoreSchemaHash.ts +9 -0
- package/src/utils/invokeHooks.ts +53 -0
- package/src/utils/isDefined.ts +3 -0
- package/src/utils/makeGatewayGraphQLRequestContext.ts +197 -0
- package/src/utils/resolvable.ts +30 -0
- package/src/utils/schemaInstrumentation.ts +132 -0
- package/src/utils/schemaManager.ts +212 -0
- package/src/utils/urlForHttpServer.ts +21 -0
- package/src/validationRules/NoIntrospection.ts +27 -0
- package/src/validationRules/RecursiveSelectionsLimit.ts +198 -0
- package/src/validationRules/index.ts +5 -0
- package/standalone/package.json +8 -0
|
@@ -0,0 +1,1456 @@
|
|
|
1
|
+
import type { GatewayExecutor } from '@apollo/server-gateway-interface';
|
|
2
|
+
import { isNodeLike } from '@apollo/utils.isnodelike';
|
|
3
|
+
import {
|
|
4
|
+
InMemoryLRUCache,
|
|
5
|
+
PrefixingKeyValueCache,
|
|
6
|
+
type KeyValueCache,
|
|
7
|
+
} from '@apollo/utils.keyvaluecache';
|
|
8
|
+
import type { Logger } from '@apollo/utils.logger';
|
|
9
|
+
import type { WithRequired } from '@apollo/utils.withrequired';
|
|
10
|
+
import { makeExecutableSchema } from '@graphql-tools/schema';
|
|
11
|
+
import resolvable, { type Resolvable } from './utils/resolvable.js';
|
|
12
|
+
import {
|
|
13
|
+
GraphQLError,
|
|
14
|
+
assertValidSchema,
|
|
15
|
+
print,
|
|
16
|
+
printSchema,
|
|
17
|
+
type validate,
|
|
18
|
+
type DocumentNode,
|
|
19
|
+
type ExecutionArgs,
|
|
20
|
+
type FormattedExecutionResult,
|
|
21
|
+
type GraphQLFieldResolver,
|
|
22
|
+
type GraphQLFormattedError,
|
|
23
|
+
type GraphQLSchema,
|
|
24
|
+
type ParseOptions,
|
|
25
|
+
type TypedQueryDocumentNode,
|
|
26
|
+
type ValidationRule,
|
|
27
|
+
} from 'graphql';
|
|
28
|
+
import loglevel from 'loglevel';
|
|
29
|
+
import Negotiator from 'negotiator';
|
|
30
|
+
import { newCachePolicy } from './cachePolicy.js';
|
|
31
|
+
import { determineApolloConfig } from './determineApolloConfig.js';
|
|
32
|
+
import {
|
|
33
|
+
ensureError,
|
|
34
|
+
ensureGraphQLError,
|
|
35
|
+
normalizeAndFormatErrors,
|
|
36
|
+
} from './errorNormalize.js';
|
|
37
|
+
import { ApolloServerErrorCode } from './errors/index.js';
|
|
38
|
+
import type { ApolloServerOptionsWithStaticSchema } from './externalTypes/constructor.js';
|
|
39
|
+
import type {
|
|
40
|
+
ExecuteOperationOptions,
|
|
41
|
+
LegacyExperimentalExecuteIncrementally,
|
|
42
|
+
VariableValues,
|
|
43
|
+
} from './externalTypes/graphql.js';
|
|
44
|
+
import type {
|
|
45
|
+
ApolloConfig,
|
|
46
|
+
ApolloServerOptions,
|
|
47
|
+
ApolloServerPlugin,
|
|
48
|
+
BaseContext,
|
|
49
|
+
ContextThunk,
|
|
50
|
+
DocumentStore,
|
|
51
|
+
GraphQLRequest,
|
|
52
|
+
GraphQLRequestContext,
|
|
53
|
+
GraphQLResponse,
|
|
54
|
+
GraphQLServerContext,
|
|
55
|
+
GraphQLServerListener,
|
|
56
|
+
HTTPGraphQLHead,
|
|
57
|
+
HTTPGraphQLRequest,
|
|
58
|
+
HTTPGraphQLResponse,
|
|
59
|
+
LandingPage,
|
|
60
|
+
PersistedQueryOptions,
|
|
61
|
+
} from './externalTypes/index.js';
|
|
62
|
+
import { runPotentiallyBatchedHttpQuery } from './httpBatching.js';
|
|
63
|
+
import type {
|
|
64
|
+
GraphQLExperimentalIncrementalExecutionResultsAlpha2,
|
|
65
|
+
GraphQLExperimentalIncrementalExecutionResultsAlpha9,
|
|
66
|
+
} from './incrementalDeliveryPolyfill.js';
|
|
67
|
+
import { pluginIsInternal, type InternalPluginId } from './internalPlugin.js';
|
|
68
|
+
import {
|
|
69
|
+
preventCsrf,
|
|
70
|
+
recommendedCsrfPreventionRequestHeaders,
|
|
71
|
+
} from './preventCsrf.js';
|
|
72
|
+
import { APQ_CACHE_PREFIX, processGraphQLRequest } from './requestPipeline.js';
|
|
73
|
+
import { newHTTPGraphQLHead, prettyJSONStringify } from './runHttpQuery.js';
|
|
74
|
+
import { HeaderMap } from './utils/HeaderMap.js';
|
|
75
|
+
import { UnreachableCaseError } from './utils/UnreachableCaseError.js';
|
|
76
|
+
import { computeCoreSchemaHash } from './utils/computeCoreSchemaHash.js';
|
|
77
|
+
import { isDefined } from './utils/isDefined.js';
|
|
78
|
+
import { SchemaManager } from './utils/schemaManager.js';
|
|
79
|
+
import {
|
|
80
|
+
NoIntrospection,
|
|
81
|
+
createMaxRecursiveSelectionsRule,
|
|
82
|
+
DEFAULT_MAX_RECURSIVE_SELECTIONS,
|
|
83
|
+
} from './validationRules/index.js';
|
|
84
|
+
|
|
85
|
+
export type SchemaDerivedData = {
|
|
86
|
+
schema: GraphQLSchema;
|
|
87
|
+
// A store that, when enabled (default), will store the parsed and validated
|
|
88
|
+
// versions of operations in-memory, allowing subsequent parses/validates
|
|
89
|
+
// on the same operation to be executed immediately.
|
|
90
|
+
documentStore: DocumentStore | null;
|
|
91
|
+
// Prefix for keys in the DocumentStore if a custom one is provided (to
|
|
92
|
+
// separate the cache for different schema versions). This is vital to
|
|
93
|
+
// security so we do it explicitly so that
|
|
94
|
+
// PrefixingKeyValueCache.cacheDangerouslyDoesNotNeedPrefixesForIsolation
|
|
95
|
+
// doesn't affect it.
|
|
96
|
+
documentStoreKeyPrefix: string;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
type RunningServerState = {
|
|
100
|
+
schemaManager: SchemaManager;
|
|
101
|
+
landingPage: LandingPage | null;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
type ServerState =
|
|
105
|
+
| {
|
|
106
|
+
phase: 'initialized';
|
|
107
|
+
schemaManager: SchemaManager;
|
|
108
|
+
}
|
|
109
|
+
| {
|
|
110
|
+
phase: 'starting';
|
|
111
|
+
barrier: Resolvable<void>;
|
|
112
|
+
schemaManager: SchemaManager;
|
|
113
|
+
// This is set to true if you called
|
|
114
|
+
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests
|
|
115
|
+
// instead of start. The main purpose is that assertStarted allows you to
|
|
116
|
+
// still be in the starting phase if this is set. (This is the serverless
|
|
117
|
+
// use case.)
|
|
118
|
+
startedInBackground: boolean;
|
|
119
|
+
}
|
|
120
|
+
| {
|
|
121
|
+
phase: 'failed to start';
|
|
122
|
+
error: Error;
|
|
123
|
+
}
|
|
124
|
+
| ({
|
|
125
|
+
phase: 'started';
|
|
126
|
+
drainServers: (() => Promise<void>) | null;
|
|
127
|
+
toDispose: (() => Promise<void>)[];
|
|
128
|
+
toDisposeLast: (() => Promise<void>)[];
|
|
129
|
+
} & RunningServerState)
|
|
130
|
+
| ({
|
|
131
|
+
phase: 'draining';
|
|
132
|
+
barrier: Resolvable<void>;
|
|
133
|
+
} & RunningServerState)
|
|
134
|
+
| {
|
|
135
|
+
phase: 'stopping';
|
|
136
|
+
barrier: Resolvable<void>;
|
|
137
|
+
}
|
|
138
|
+
| {
|
|
139
|
+
phase: 'stopped';
|
|
140
|
+
stopError: Error | null;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export type ValidationOptions = NonNullable<Parameters<typeof validate>[3]>;
|
|
144
|
+
|
|
145
|
+
export interface ApolloServerInternals<TContext extends BaseContext> {
|
|
146
|
+
state: ServerState;
|
|
147
|
+
gatewayExecutor: GatewayExecutor | null;
|
|
148
|
+
dangerouslyDisableValidation?: boolean;
|
|
149
|
+
formatError?: (
|
|
150
|
+
formattedError: GraphQLFormattedError,
|
|
151
|
+
error: unknown,
|
|
152
|
+
) => GraphQLFormattedError;
|
|
153
|
+
includeStacktraceInErrorResponses: boolean;
|
|
154
|
+
persistedQueries?: WithRequired<PersistedQueryOptions, 'cache'>;
|
|
155
|
+
nodeEnv: string;
|
|
156
|
+
allowBatchedHttpRequests: boolean;
|
|
157
|
+
apolloConfig: ApolloConfig;
|
|
158
|
+
plugins: ApolloServerPlugin<TContext>[];
|
|
159
|
+
parseOptions: ParseOptions;
|
|
160
|
+
validationOptions: ValidationOptions;
|
|
161
|
+
executionOptions?: ExecutionArgs['options'];
|
|
162
|
+
// `undefined` means we figure out what to do during _start (because
|
|
163
|
+
// the default depends on whether or not we used the background version
|
|
164
|
+
// of start).
|
|
165
|
+
stopOnTerminationSignals: boolean | undefined;
|
|
166
|
+
csrfPreventionRequestHeaders: string[] | null;
|
|
167
|
+
|
|
168
|
+
rootValue?: ((parsedQuery: DocumentNode) => unknown) | unknown;
|
|
169
|
+
validationRules: Array<ValidationRule>;
|
|
170
|
+
laterValidationRules?: Array<ValidationRule>;
|
|
171
|
+
hideSchemaDetailsFromClientErrors: boolean;
|
|
172
|
+
fieldResolver?: GraphQLFieldResolver<any, TContext>;
|
|
173
|
+
// TODO(AS6): remove this option.
|
|
174
|
+
status400ForVariableCoercionErrors?: boolean;
|
|
175
|
+
__testing_incrementalExecutionResults?:
|
|
176
|
+
| GraphQLExperimentalIncrementalExecutionResultsAlpha2
|
|
177
|
+
| GraphQLExperimentalIncrementalExecutionResultsAlpha9;
|
|
178
|
+
stringifyResult: (
|
|
179
|
+
value: FormattedExecutionResult,
|
|
180
|
+
) => string | Promise<string>;
|
|
181
|
+
legacyExperimentalExecuteIncrementally?: LegacyExperimentalExecuteIncrementally;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function defaultLogger(): Logger {
|
|
185
|
+
const loglevelLogger = loglevel.getLogger('apollo-server');
|
|
186
|
+
loglevelLogger.setLevel(loglevel.levels.INFO);
|
|
187
|
+
return loglevelLogger;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// We really want to prevent this from being legal:
|
|
191
|
+
//
|
|
192
|
+
// const s: ApolloServer<{}> =
|
|
193
|
+
// new ApolloServer<{importantContextField: boolean}>({ ... });
|
|
194
|
+
// s.executeOperation({query}, {contextValue: {}});
|
|
195
|
+
//
|
|
196
|
+
// ie, if you declare an ApolloServer whose context values must be of a certain
|
|
197
|
+
// type, you can't assign it to a variable whose context values are less
|
|
198
|
+
// constrained and then pass in a context value missing important fields.
|
|
199
|
+
//
|
|
200
|
+
// We also want this to be illegal:
|
|
201
|
+
//
|
|
202
|
+
// const sBase = new ApolloServer<{}>({ ... });
|
|
203
|
+
// const s: ApolloServer<{importantContextField: boolean}> = sBase;
|
|
204
|
+
// s.addPlugin({async requestDidStart({contextValue: {importantContextField}}) { ... }})
|
|
205
|
+
// sBase.executeOperation({query}, {contextValue: {}});
|
|
206
|
+
//
|
|
207
|
+
// so you shouldn't be able to assign an ApolloServer to a variable whose
|
|
208
|
+
// context values are more constrained, either. So we want to declare that
|
|
209
|
+
// ApolloServer is *invariant* in TContext, which we do with `in out` (a
|
|
210
|
+
// TypeScript 4.7 feature).
|
|
211
|
+
export class ApolloServer<in out TContext extends BaseContext = BaseContext> {
|
|
212
|
+
private internals: ApolloServerInternals<TContext>;
|
|
213
|
+
|
|
214
|
+
public readonly cache: KeyValueCache<string>;
|
|
215
|
+
public readonly logger: Logger;
|
|
216
|
+
|
|
217
|
+
constructor(config: ApolloServerOptions<TContext>) {
|
|
218
|
+
const nodeEnv = config.nodeEnv ?? process.env.NODE_ENV ?? '';
|
|
219
|
+
|
|
220
|
+
this.logger = config.logger ?? defaultLogger();
|
|
221
|
+
|
|
222
|
+
const apolloConfig = determineApolloConfig(config.apollo, this.logger);
|
|
223
|
+
|
|
224
|
+
const isDev = nodeEnv !== 'production';
|
|
225
|
+
|
|
226
|
+
if (
|
|
227
|
+
config.cache &&
|
|
228
|
+
config.cache !== 'bounded' &&
|
|
229
|
+
PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(config.cache)
|
|
230
|
+
) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
'You cannot pass a cache returned from ' +
|
|
233
|
+
'`PrefixingKeyValueCache.cacheDangerouslyDoesNotNeedPrefixesForIsolation`' +
|
|
234
|
+
'to `new ApolloServer({ cache })`, because Apollo Server may use it for ' +
|
|
235
|
+
'multiple features whose cache keys must be distinct from each other.',
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const state: ServerState = config.gateway
|
|
240
|
+
? // ApolloServer has been initialized but we have not yet tried to load the
|
|
241
|
+
// schema from the gateway. That will wait until `start()` or
|
|
242
|
+
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()`
|
|
243
|
+
// is called. (These may be called by other helpers; for example,
|
|
244
|
+
// `standaloneServer` calls `start` for you inside its `listen` method,
|
|
245
|
+
// and a serverless framework integration would call
|
|
246
|
+
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests
|
|
247
|
+
// for you.)
|
|
248
|
+
{
|
|
249
|
+
phase: 'initialized',
|
|
250
|
+
schemaManager: new SchemaManager({
|
|
251
|
+
gateway: config.gateway,
|
|
252
|
+
apolloConfig,
|
|
253
|
+
schemaDerivedDataProvider: (schema) =>
|
|
254
|
+
ApolloServer.generateSchemaDerivedData(
|
|
255
|
+
schema,
|
|
256
|
+
config.documentStore,
|
|
257
|
+
),
|
|
258
|
+
logger: this.logger,
|
|
259
|
+
}),
|
|
260
|
+
}
|
|
261
|
+
: // We construct the schema synchronously so that we can fail fast if the
|
|
262
|
+
// schema can't be constructed. (This used to be more important because we
|
|
263
|
+
// used to have a 'schema' field that was publicly accessible immediately
|
|
264
|
+
// after construction, though that field never actually worked with
|
|
265
|
+
// gateways.)
|
|
266
|
+
{
|
|
267
|
+
phase: 'initialized',
|
|
268
|
+
schemaManager: new SchemaManager({
|
|
269
|
+
apiSchema: ApolloServer.constructSchema(config),
|
|
270
|
+
schemaDerivedDataProvider: (schema) =>
|
|
271
|
+
ApolloServer.generateSchemaDerivedData(
|
|
272
|
+
schema,
|
|
273
|
+
config.documentStore,
|
|
274
|
+
),
|
|
275
|
+
logger: this.logger,
|
|
276
|
+
}),
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const introspectionEnabled = config.introspection ?? isDev;
|
|
280
|
+
const hideSchemaDetailsFromClientErrors =
|
|
281
|
+
config.hideSchemaDetailsFromClientErrors ?? false;
|
|
282
|
+
|
|
283
|
+
// We continue to allow 'bounded' for backwards-compatibility with the AS3.9
|
|
284
|
+
// API.
|
|
285
|
+
this.cache =
|
|
286
|
+
config.cache === undefined || config.cache === 'bounded'
|
|
287
|
+
? new InMemoryLRUCache()
|
|
288
|
+
: config.cache;
|
|
289
|
+
|
|
290
|
+
// Check whether the recursive selections limit has been enabled (off by
|
|
291
|
+
// default), or whether a custom limit has been specified.
|
|
292
|
+
const maxRecursiveSelectionsRule =
|
|
293
|
+
config.maxRecursiveSelections === true
|
|
294
|
+
? [createMaxRecursiveSelectionsRule(DEFAULT_MAX_RECURSIVE_SELECTIONS)]
|
|
295
|
+
: typeof config.maxRecursiveSelections === 'number'
|
|
296
|
+
? [createMaxRecursiveSelectionsRule(config.maxRecursiveSelections)]
|
|
297
|
+
: [];
|
|
298
|
+
|
|
299
|
+
// If the recursive selections rule has been enabled, then run configured
|
|
300
|
+
// validations in a later validate() pass.
|
|
301
|
+
const validationRules = [
|
|
302
|
+
...(introspectionEnabled ? [] : [NoIntrospection]),
|
|
303
|
+
...maxRecursiveSelectionsRule,
|
|
304
|
+
];
|
|
305
|
+
let laterValidationRules;
|
|
306
|
+
if (maxRecursiveSelectionsRule.length > 0) {
|
|
307
|
+
laterValidationRules = config.validationRules;
|
|
308
|
+
} else {
|
|
309
|
+
validationRules.push(...(config.validationRules ?? []));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Note that we avoid calling methods on `this` before `this.internals` is assigned
|
|
313
|
+
// (thus a bunch of things being static methods above).
|
|
314
|
+
this.internals = {
|
|
315
|
+
formatError: config.formatError,
|
|
316
|
+
rootValue: config.rootValue,
|
|
317
|
+
validationRules,
|
|
318
|
+
laterValidationRules,
|
|
319
|
+
hideSchemaDetailsFromClientErrors,
|
|
320
|
+
dangerouslyDisableValidation:
|
|
321
|
+
config.dangerouslyDisableValidation ?? false,
|
|
322
|
+
validationOptions: config.validationOptions ?? {},
|
|
323
|
+
fieldResolver: config.fieldResolver,
|
|
324
|
+
includeStacktraceInErrorResponses:
|
|
325
|
+
config.includeStacktraceInErrorResponses ??
|
|
326
|
+
(nodeEnv !== 'production' && nodeEnv !== 'test'),
|
|
327
|
+
persistedQueries:
|
|
328
|
+
config.persistedQueries === false
|
|
329
|
+
? undefined
|
|
330
|
+
: {
|
|
331
|
+
...config.persistedQueries,
|
|
332
|
+
cache: new PrefixingKeyValueCache(
|
|
333
|
+
config.persistedQueries?.cache ?? this.cache,
|
|
334
|
+
APQ_CACHE_PREFIX,
|
|
335
|
+
),
|
|
336
|
+
},
|
|
337
|
+
nodeEnv,
|
|
338
|
+
allowBatchedHttpRequests: config.allowBatchedHttpRequests ?? false,
|
|
339
|
+
apolloConfig,
|
|
340
|
+
// Note that more plugins can be added before `start()` with `addPlugin()`
|
|
341
|
+
// (eg, plugins that want to take this ApolloServer as an argument), and
|
|
342
|
+
// `start()` will call `addDefaultPlugins` to add default plugins.
|
|
343
|
+
plugins: config.plugins ?? [],
|
|
344
|
+
parseOptions: config.parseOptions ?? {},
|
|
345
|
+
executionOptions: config.executionOptions ?? {},
|
|
346
|
+
state,
|
|
347
|
+
stopOnTerminationSignals: config.stopOnTerminationSignals,
|
|
348
|
+
|
|
349
|
+
gatewayExecutor: null, // set by _start
|
|
350
|
+
|
|
351
|
+
csrfPreventionRequestHeaders:
|
|
352
|
+
config.csrfPrevention === true || config.csrfPrevention === undefined
|
|
353
|
+
? recommendedCsrfPreventionRequestHeaders
|
|
354
|
+
: config.csrfPrevention === false
|
|
355
|
+
? null
|
|
356
|
+
: (config.csrfPrevention.requestHeaders ??
|
|
357
|
+
recommendedCsrfPreventionRequestHeaders),
|
|
358
|
+
status400ForVariableCoercionErrors:
|
|
359
|
+
config.status400ForVariableCoercionErrors ?? true,
|
|
360
|
+
__testing_incrementalExecutionResults:
|
|
361
|
+
config.__testing_incrementalExecutionResults,
|
|
362
|
+
stringifyResult: config.stringifyResult ?? prettyJSONStringify,
|
|
363
|
+
legacyExperimentalExecuteIncrementally:
|
|
364
|
+
config.legacyExperimentalExecuteIncrementally,
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
this.warnAgainstDeprecatedConfigOptions(config);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
private warnAgainstDeprecatedConfigOptions(
|
|
371
|
+
config: ApolloServerOptions<TContext>,
|
|
372
|
+
) {
|
|
373
|
+
// TODO(AS6): this option goes away altogether. We should either update or remove this warning.
|
|
374
|
+
if ('status400ForVariableCoercionErrors' in config) {
|
|
375
|
+
if (config.status400ForVariableCoercionErrors === true) {
|
|
376
|
+
this.logger.warn(
|
|
377
|
+
'The `status400ForVariableCoercionErrors: true` configuration option is now the default behavior and has no effect in Apollo Server v5. You can safely remove this option from your configuration.',
|
|
378
|
+
);
|
|
379
|
+
} else {
|
|
380
|
+
this.logger.warn(
|
|
381
|
+
'The `status400ForVariableCoercionErrors: false` configuration option is deprecated and will be removed in Apollo Server v6. Apollo recommends removing any dependency on this behavior.',
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Awaiting a call to `start` ensures that a schema has been loaded and that
|
|
388
|
+
// all plugin `serverWillStart` hooks have been called. If either of these
|
|
389
|
+
// processes throw, `start` will (async) throw as well.
|
|
390
|
+
//
|
|
391
|
+
// If you're using `standaloneServer`, you don't need to call `start` yourself
|
|
392
|
+
// (in fact, it will throw if you do so); its `listen` method takes care of
|
|
393
|
+
// that for you.
|
|
394
|
+
//
|
|
395
|
+
// If instead you're using an integration package for a non-serverless
|
|
396
|
+
// framework (like Express), you must await a call to `start` immediately
|
|
397
|
+
// after creating your `ApolloServer`, before attaching it to your web
|
|
398
|
+
// framework and starting to accept requests. `start` should only be called
|
|
399
|
+
// once; if it throws and you'd like to retry, just create another
|
|
400
|
+
// `ApolloServer`. (Calling `start` was optional in Apollo Server 2, but in
|
|
401
|
+
// Apollo Server 3+ the functions like `expressMiddleware` use `assertStarted`
|
|
402
|
+
// to throw if `start` hasn't successfully completed.)
|
|
403
|
+
//
|
|
404
|
+
// Serverless integrations like Lambda do not support calling `start()`,
|
|
405
|
+
// because their lifecycle doesn't allow you to wait before assigning a
|
|
406
|
+
// handler or allowing the handler to be called. So they call
|
|
407
|
+
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()`
|
|
408
|
+
// instead, and don't really differentiate between startup failures and
|
|
409
|
+
// request failures. This is hopefully appropriate for a "serverless"
|
|
410
|
+
// framework. Serverless startup failures result in returning a redacted error
|
|
411
|
+
// to the end user and logging the more detailed error.
|
|
412
|
+
public async start(): Promise<void> {
|
|
413
|
+
return await this._start(false);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
public startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests(): void {
|
|
417
|
+
this._start(true).catch((e) => this.logStartupError(e));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private async _start(startedInBackground: boolean): Promise<void> {
|
|
421
|
+
if (this.internals.state.phase !== 'initialized') {
|
|
422
|
+
// If we wanted we could make this error detectable and change
|
|
423
|
+
// `standaloneServer` to change the message to say not to call start() at
|
|
424
|
+
// all.
|
|
425
|
+
throw new Error(
|
|
426
|
+
`You should only call 'start()' or ` +
|
|
427
|
+
`'startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()' ` +
|
|
428
|
+
`once on your ApolloServer.`,
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
const schemaManager = this.internals.state.schemaManager;
|
|
432
|
+
const barrier = resolvable();
|
|
433
|
+
this.internals.state = {
|
|
434
|
+
phase: 'starting',
|
|
435
|
+
barrier,
|
|
436
|
+
schemaManager,
|
|
437
|
+
startedInBackground,
|
|
438
|
+
};
|
|
439
|
+
try {
|
|
440
|
+
// Now that you can't call addPlugin any more, add default plugins like
|
|
441
|
+
// usage reporting if they're not already added.
|
|
442
|
+
await this.addDefaultPlugins();
|
|
443
|
+
|
|
444
|
+
const toDispose: (() => Promise<void>)[] = [];
|
|
445
|
+
const executor = await schemaManager.start();
|
|
446
|
+
if (executor) {
|
|
447
|
+
this.internals.gatewayExecutor = executor;
|
|
448
|
+
}
|
|
449
|
+
toDispose.push(async () => {
|
|
450
|
+
await schemaManager.stop();
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
const schemaDerivedData = schemaManager.getSchemaDerivedData();
|
|
454
|
+
const service: GraphQLServerContext = {
|
|
455
|
+
logger: this.logger,
|
|
456
|
+
cache: this.cache,
|
|
457
|
+
schema: schemaDerivedData.schema,
|
|
458
|
+
apollo: this.internals.apolloConfig,
|
|
459
|
+
startedInBackground,
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
const taggedServerListeners = (
|
|
463
|
+
await Promise.all(
|
|
464
|
+
this.internals.plugins.map(async (plugin) => ({
|
|
465
|
+
serverListener:
|
|
466
|
+
plugin.serverWillStart && (await plugin.serverWillStart(service)),
|
|
467
|
+
installedImplicitly:
|
|
468
|
+
isImplicitlyInstallablePlugin(plugin) &&
|
|
469
|
+
plugin.__internal_installed_implicitly__,
|
|
470
|
+
})),
|
|
471
|
+
)
|
|
472
|
+
).filter(
|
|
473
|
+
(
|
|
474
|
+
maybeTaggedServerListener,
|
|
475
|
+
): maybeTaggedServerListener is {
|
|
476
|
+
serverListener: GraphQLServerListener;
|
|
477
|
+
installedImplicitly: boolean;
|
|
478
|
+
} => typeof maybeTaggedServerListener.serverListener === 'object',
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
taggedServerListeners.forEach(
|
|
482
|
+
({ serverListener: { schemaDidLoadOrUpdate } }) => {
|
|
483
|
+
if (schemaDidLoadOrUpdate) {
|
|
484
|
+
schemaManager.onSchemaLoadOrUpdate(schemaDidLoadOrUpdate);
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
const serverWillStops = taggedServerListeners
|
|
490
|
+
.map((l) => l.serverListener.serverWillStop)
|
|
491
|
+
.filter(isDefined);
|
|
492
|
+
if (serverWillStops.length) {
|
|
493
|
+
toDispose.push(async () => {
|
|
494
|
+
await Promise.all(
|
|
495
|
+
serverWillStops.map((serverWillStop) => serverWillStop()),
|
|
496
|
+
);
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const drainServerCallbacks = taggedServerListeners
|
|
501
|
+
.map((l) => l.serverListener.drainServer)
|
|
502
|
+
.filter(isDefined);
|
|
503
|
+
const drainServers = drainServerCallbacks.length
|
|
504
|
+
? async () => {
|
|
505
|
+
await Promise.all(
|
|
506
|
+
drainServerCallbacks.map((drainServer) => drainServer()),
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
: null;
|
|
510
|
+
|
|
511
|
+
// Find the renderLandingPage callback, if one is provided. If the user
|
|
512
|
+
// installed ApolloServerPluginLandingPageDisabled then there may be none
|
|
513
|
+
// found. On the other hand, if the user installed a landingPage plugin,
|
|
514
|
+
// then both the implicit installation of
|
|
515
|
+
// ApolloServerPluginLandingPage*Default and the other plugin will be
|
|
516
|
+
// found; we skip the implicit plugin.
|
|
517
|
+
let taggedServerListenersWithRenderLandingPage =
|
|
518
|
+
taggedServerListeners.filter((l) => l.serverListener.renderLandingPage);
|
|
519
|
+
if (taggedServerListenersWithRenderLandingPage.length > 1) {
|
|
520
|
+
taggedServerListenersWithRenderLandingPage =
|
|
521
|
+
taggedServerListenersWithRenderLandingPage.filter(
|
|
522
|
+
(l) => !l.installedImplicitly,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
let landingPage: LandingPage | null = null;
|
|
526
|
+
if (taggedServerListenersWithRenderLandingPage.length > 1) {
|
|
527
|
+
throw Error('Only one plugin can implement renderLandingPage.');
|
|
528
|
+
} else if (taggedServerListenersWithRenderLandingPage.length) {
|
|
529
|
+
landingPage =
|
|
530
|
+
await taggedServerListenersWithRenderLandingPage[0].serverListener
|
|
531
|
+
.renderLandingPage!();
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const toDisposeLast = this.maybeRegisterTerminationSignalHandlers(
|
|
535
|
+
['SIGINT', 'SIGTERM'],
|
|
536
|
+
startedInBackground,
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
this.internals.state = {
|
|
540
|
+
phase: 'started',
|
|
541
|
+
schemaManager,
|
|
542
|
+
drainServers,
|
|
543
|
+
landingPage,
|
|
544
|
+
toDispose,
|
|
545
|
+
toDisposeLast,
|
|
546
|
+
};
|
|
547
|
+
} catch (maybeError: unknown) {
|
|
548
|
+
const error = ensureError(maybeError);
|
|
549
|
+
|
|
550
|
+
try {
|
|
551
|
+
await Promise.all(
|
|
552
|
+
this.internals.plugins.map(async (plugin) =>
|
|
553
|
+
plugin.startupDidFail?.({ error }),
|
|
554
|
+
),
|
|
555
|
+
);
|
|
556
|
+
} catch (pluginError) {
|
|
557
|
+
this.logger.error(`startupDidFail hook threw: ${pluginError}`);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
this.internals.state = {
|
|
561
|
+
phase: 'failed to start',
|
|
562
|
+
error,
|
|
563
|
+
};
|
|
564
|
+
throw error;
|
|
565
|
+
} finally {
|
|
566
|
+
barrier.resolve();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
private maybeRegisterTerminationSignalHandlers(
|
|
571
|
+
signals: NodeJS.Signals[],
|
|
572
|
+
startedInBackground: boolean,
|
|
573
|
+
): (() => Promise<void>)[] {
|
|
574
|
+
const toDisposeLast: (() => Promise<void>)[] = [];
|
|
575
|
+
|
|
576
|
+
// We handle signals if it was explicitly requested
|
|
577
|
+
// (stopOnTerminationSignals === true), or if we're in Node, not in a test,
|
|
578
|
+
// not in a serverless framework (which we guess based on whether they
|
|
579
|
+
// called
|
|
580
|
+
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests),
|
|
581
|
+
// and it wasn't explicitly turned off. (We only actually register the
|
|
582
|
+
// signal handlers once we've successfully started up, because there's
|
|
583
|
+
// nothing to stop otherwise.)
|
|
584
|
+
if (
|
|
585
|
+
this.internals.stopOnTerminationSignals === false ||
|
|
586
|
+
(this.internals.stopOnTerminationSignals === undefined &&
|
|
587
|
+
!(
|
|
588
|
+
isNodeLike &&
|
|
589
|
+
this.internals.nodeEnv !== 'test' &&
|
|
590
|
+
!startedInBackground
|
|
591
|
+
))
|
|
592
|
+
) {
|
|
593
|
+
return toDisposeLast;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
let receivedSignal = false;
|
|
597
|
+
const signalHandler: NodeJS.SignalsListener = async (signal) => {
|
|
598
|
+
if (receivedSignal) {
|
|
599
|
+
// If we receive another SIGINT or SIGTERM while we're waiting
|
|
600
|
+
// for the server to stop, just ignore it.
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
receivedSignal = true;
|
|
604
|
+
try {
|
|
605
|
+
await this.stop();
|
|
606
|
+
} catch (e) {
|
|
607
|
+
this.logger.error(`stop() threw during ${signal} shutdown`);
|
|
608
|
+
this.logger.error(e);
|
|
609
|
+
// Can't rely on the signal handlers being removed.
|
|
610
|
+
process.exit(1);
|
|
611
|
+
}
|
|
612
|
+
// Note: this.stop will call the toDisposeLast handlers below, so at
|
|
613
|
+
// this point this handler will have been removed and we can re-kill
|
|
614
|
+
// ourself to die with the appropriate signal exit status. this.stop
|
|
615
|
+
// takes care to call toDisposeLast last, so the signal handler isn't
|
|
616
|
+
// removed until after the rest of shutdown happens.
|
|
617
|
+
process.kill(process.pid, signal);
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
signals.forEach((signal) => {
|
|
621
|
+
process.on(signal, signalHandler);
|
|
622
|
+
toDisposeLast.push(async () => {
|
|
623
|
+
process.removeListener(signal, signalHandler);
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
return toDisposeLast;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// This method is called at the beginning of each GraphQL request by
|
|
630
|
+
// `executeHTTPGraphQLRequest` and `executeOperation`. Most of its logic is
|
|
631
|
+
// only helpful if you started the server in the background (ie, for
|
|
632
|
+
// serverless frameworks): unless you're in a serverless framework, you should
|
|
633
|
+
// have called `await server.start()` before the server got to the point of
|
|
634
|
+
// running GraphQL requests (`assertStarted` calls in the framework
|
|
635
|
+
// integrations verify that) and so the only cases for non-serverless
|
|
636
|
+
// frameworks that this should hit are 'started', 'stopping', and 'stopped'.
|
|
637
|
+
// But if you started the server in the background (with
|
|
638
|
+
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests), this
|
|
639
|
+
// lets the server wait until fully started before serving operations.
|
|
640
|
+
private async _ensureStarted(): Promise<RunningServerState> {
|
|
641
|
+
while (true) {
|
|
642
|
+
switch (this.internals.state.phase) {
|
|
643
|
+
case 'initialized':
|
|
644
|
+
// This error probably won't happen: serverless framework integrations
|
|
645
|
+
// should call
|
|
646
|
+
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests`
|
|
647
|
+
// for you, and other frameworks call `assertStarted` before setting
|
|
648
|
+
// things up enough to make calling this function possible.
|
|
649
|
+
throw new Error(
|
|
650
|
+
'You need to call `server.start()` before using your Apollo Server.',
|
|
651
|
+
);
|
|
652
|
+
case 'starting':
|
|
653
|
+
await this.internals.state.barrier;
|
|
654
|
+
// continue the while loop
|
|
655
|
+
break;
|
|
656
|
+
case 'failed to start':
|
|
657
|
+
// First we log the error that prevented startup (which means it will
|
|
658
|
+
// get logged once for every GraphQL operation).
|
|
659
|
+
this.logStartupError(this.internals.state.error);
|
|
660
|
+
// Now make the operation itself fail.
|
|
661
|
+
// We intentionally do not re-throw actual startup error as it may contain
|
|
662
|
+
// implementation details and this error will propagate to the client.
|
|
663
|
+
throw new Error(
|
|
664
|
+
'This data graph is missing a valid configuration. More details may be available in the server logs.',
|
|
665
|
+
);
|
|
666
|
+
case 'started':
|
|
667
|
+
case 'draining': // We continue to run operations while draining.
|
|
668
|
+
return this.internals.state;
|
|
669
|
+
case 'stopping':
|
|
670
|
+
case 'stopped':
|
|
671
|
+
this.logger.warn(
|
|
672
|
+
'A GraphQL operation was received during server shutdown. The ' +
|
|
673
|
+
'operation will fail. Consider draining the HTTP server on shutdown; ' +
|
|
674
|
+
'see https://go.apollo.dev/s/drain for details.',
|
|
675
|
+
);
|
|
676
|
+
throw new Error(
|
|
677
|
+
`Cannot execute GraphQL operations ${
|
|
678
|
+
this.internals.state.phase === 'stopping'
|
|
679
|
+
? 'while the server is stopping'
|
|
680
|
+
: 'after the server has stopped'
|
|
681
|
+
}.'`,
|
|
682
|
+
);
|
|
683
|
+
default:
|
|
684
|
+
throw new UnreachableCaseError(this.internals.state);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Framework integrations should call this to ensure that you've properly
|
|
690
|
+
// started your server before you get anywhere close to actually listening for
|
|
691
|
+
// incoming requests.
|
|
692
|
+
//
|
|
693
|
+
// There's a special case that if you called
|
|
694
|
+
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests` and
|
|
695
|
+
// it hasn't finished starting up yet, this works too. This is intended for
|
|
696
|
+
// cases like a serverless integration (say, Google Cloud Functions) that
|
|
697
|
+
// calls
|
|
698
|
+
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests` for
|
|
699
|
+
// you and then immediately sets up an integration based on another middleware
|
|
700
|
+
// like `expressMiddleware` which calls this function. We'd like this to be
|
|
701
|
+
// OK, but we still want normal Express users to start their ApolloServer
|
|
702
|
+
// before setting up their HTTP server unless they know what they are doing
|
|
703
|
+
// well enough to call the function with the long name themselves.
|
|
704
|
+
public assertStarted(expressionForError: string) {
|
|
705
|
+
if (
|
|
706
|
+
this.internals.state.phase !== 'started' &&
|
|
707
|
+
this.internals.state.phase !== 'draining' &&
|
|
708
|
+
!(
|
|
709
|
+
this.internals.state.phase === 'starting' &&
|
|
710
|
+
this.internals.state.startedInBackground
|
|
711
|
+
)
|
|
712
|
+
) {
|
|
713
|
+
throw new Error(
|
|
714
|
+
'You must `await server.start()` before calling `' +
|
|
715
|
+
expressionForError +
|
|
716
|
+
'`',
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Given an error that occurred during Apollo Server startup, log it with a
|
|
722
|
+
// helpful message. This should happen when you call
|
|
723
|
+
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests` (ie,
|
|
724
|
+
// in serverless frameworks); with other frameworks, you must `await
|
|
725
|
+
// server.start()` which will throw the startup error directly instead of
|
|
726
|
+
// logging. This gets called both immediately when the startup error happens,
|
|
727
|
+
// and on all subsequent requests.
|
|
728
|
+
private logStartupError(err: Error) {
|
|
729
|
+
this.logger.error(
|
|
730
|
+
'An error occurred during Apollo Server startup. All GraphQL requests ' +
|
|
731
|
+
'will now fail. The startup error was: ' +
|
|
732
|
+
(err?.message || err),
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
private static constructSchema<TContext extends BaseContext>(
|
|
737
|
+
config: ApolloServerOptionsWithStaticSchema<TContext>,
|
|
738
|
+
): GraphQLSchema {
|
|
739
|
+
if (config.schema) {
|
|
740
|
+
return config.schema;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const { typeDefs, resolvers } = config;
|
|
744
|
+
const augmentedTypeDefs = Array.isArray(typeDefs) ? typeDefs : [typeDefs];
|
|
745
|
+
|
|
746
|
+
// For convenience, we allow you to pass a few options that we pass through
|
|
747
|
+
// to a particular version of `@graphql-tools/schema`'s
|
|
748
|
+
// `makeExecutableSchema`. If you want to use more of this function's
|
|
749
|
+
// features or have more control over the version of the packages used, just
|
|
750
|
+
// call it yourself like `new ApolloServer({schema:
|
|
751
|
+
// makeExecutableSchema(...)})`.
|
|
752
|
+
return makeExecutableSchema({
|
|
753
|
+
typeDefs: augmentedTypeDefs,
|
|
754
|
+
resolvers,
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
private static generateSchemaDerivedData(
|
|
759
|
+
schema: GraphQLSchema,
|
|
760
|
+
// null means don't use a documentStore at all.
|
|
761
|
+
// missing/undefined means use the default (creating a new one each
|
|
762
|
+
// time).
|
|
763
|
+
// defined means wrap this one in a random prefix for each new schema.
|
|
764
|
+
providedDocumentStore: DocumentStore | null | undefined,
|
|
765
|
+
): SchemaDerivedData {
|
|
766
|
+
// Instead of waiting for the first operation execution against the schema
|
|
767
|
+
// to find out if it's a valid schema or not, check right now. In the
|
|
768
|
+
// non-gateway case, if this throws then the `new ApolloServer` call will
|
|
769
|
+
// throw. In the gateway case if this throws then it will log a message and
|
|
770
|
+
// just not update the schema (although oddly the message will claim that
|
|
771
|
+
// the schema is updating).
|
|
772
|
+
assertValidSchema(schema);
|
|
773
|
+
|
|
774
|
+
return {
|
|
775
|
+
schema,
|
|
776
|
+
// The DocumentStore is schema-derived because we put documents in it
|
|
777
|
+
// after checking that they pass GraphQL validation against the schema and
|
|
778
|
+
// use this to skip validation as well as parsing. So we can't reuse the
|
|
779
|
+
// same DocumentStore for different schemas because that might make us
|
|
780
|
+
// treat invalid operations as valid. If we're using the default
|
|
781
|
+
// DocumentStore, then we just create it from scratch each time we get a
|
|
782
|
+
// new schema. If we're using a user-provided DocumentStore, then we use
|
|
783
|
+
// the schema hash as a prefix.
|
|
784
|
+
documentStore:
|
|
785
|
+
providedDocumentStore === undefined
|
|
786
|
+
? new InMemoryLRUCache<DocumentNode>()
|
|
787
|
+
: providedDocumentStore,
|
|
788
|
+
documentStoreKeyPrefix: providedDocumentStore
|
|
789
|
+
? `${computeCoreSchemaHash(printSchema(schema))}:`
|
|
790
|
+
: '',
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
public async stop() {
|
|
795
|
+
switch (this.internals.state.phase) {
|
|
796
|
+
case 'initialized':
|
|
797
|
+
case 'starting':
|
|
798
|
+
case 'failed to start':
|
|
799
|
+
throw Error(
|
|
800
|
+
'apolloServer.stop() should only be called after `await apolloServer.start()` has succeeded',
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
// Calling stop more than once should have the same result as the first time.
|
|
804
|
+
case 'stopped':
|
|
805
|
+
if (this.internals.state.stopError) {
|
|
806
|
+
throw this.internals.state.stopError;
|
|
807
|
+
}
|
|
808
|
+
return;
|
|
809
|
+
|
|
810
|
+
// Two parallel calls to stop; just wait for the other one to finish and
|
|
811
|
+
// do whatever it did.
|
|
812
|
+
case 'stopping':
|
|
813
|
+
case 'draining': {
|
|
814
|
+
await this.internals.state.barrier;
|
|
815
|
+
// The cast here is because TS doesn't understand that this.state can
|
|
816
|
+
// change during the await
|
|
817
|
+
// (https://github.com/microsoft/TypeScript/issues/9998).
|
|
818
|
+
const state = this.internals.state as ServerState;
|
|
819
|
+
if (state.phase !== 'stopped') {
|
|
820
|
+
throw Error(`Surprising post-stopping state ${state.phase}`);
|
|
821
|
+
}
|
|
822
|
+
if (state.stopError) {
|
|
823
|
+
throw state.stopError;
|
|
824
|
+
}
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
case 'started':
|
|
829
|
+
// This is handled by the rest of the function.
|
|
830
|
+
break;
|
|
831
|
+
|
|
832
|
+
default:
|
|
833
|
+
throw new UnreachableCaseError(this.internals.state);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
const barrier = resolvable();
|
|
837
|
+
|
|
838
|
+
const {
|
|
839
|
+
schemaManager,
|
|
840
|
+
drainServers,
|
|
841
|
+
landingPage,
|
|
842
|
+
toDispose,
|
|
843
|
+
toDisposeLast,
|
|
844
|
+
} = this.internals.state;
|
|
845
|
+
|
|
846
|
+
// Commit to stopping and start draining servers.
|
|
847
|
+
this.internals.state = {
|
|
848
|
+
phase: 'draining',
|
|
849
|
+
barrier,
|
|
850
|
+
schemaManager,
|
|
851
|
+
landingPage,
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
try {
|
|
855
|
+
await drainServers?.();
|
|
856
|
+
|
|
857
|
+
// Servers are drained. Prevent further operations from starting and call
|
|
858
|
+
// stop handlers.
|
|
859
|
+
this.internals.state = { phase: 'stopping', barrier };
|
|
860
|
+
|
|
861
|
+
// We run shutdown handlers in two phases because we don't want to turn
|
|
862
|
+
// off our signal listeners (ie, allow signals to kill the process) until
|
|
863
|
+
// we've done the important parts of shutdown like running serverWillStop
|
|
864
|
+
// handlers. (We can make this more generic later if it's helpful.)
|
|
865
|
+
await Promise.all([...toDispose].map((dispose) => dispose()));
|
|
866
|
+
await Promise.all([...toDisposeLast].map((dispose) => dispose()));
|
|
867
|
+
} catch (stopError) {
|
|
868
|
+
this.internals.state = {
|
|
869
|
+
phase: 'stopped',
|
|
870
|
+
stopError: stopError as Error,
|
|
871
|
+
};
|
|
872
|
+
barrier.resolve();
|
|
873
|
+
throw stopError;
|
|
874
|
+
}
|
|
875
|
+
this.internals.state = { phase: 'stopped', stopError: null };
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
private async addDefaultPlugins() {
|
|
879
|
+
const {
|
|
880
|
+
plugins,
|
|
881
|
+
apolloConfig,
|
|
882
|
+
nodeEnv,
|
|
883
|
+
hideSchemaDetailsFromClientErrors,
|
|
884
|
+
} = this.internals;
|
|
885
|
+
const isDev = nodeEnv !== 'production';
|
|
886
|
+
|
|
887
|
+
const alreadyHavePluginWithInternalId = (id: InternalPluginId) =>
|
|
888
|
+
plugins.some(
|
|
889
|
+
(p) => pluginIsInternal(p) && p.__internal_plugin_id__ === id,
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
// Make sure we're not trying to explicitly enable and disable the same
|
|
893
|
+
// feature. (Be careful: we are not trying to stop people from installing
|
|
894
|
+
// the same plugin twice if they have a use case for it, like two usage
|
|
895
|
+
// reporting plugins for different variants.)
|
|
896
|
+
//
|
|
897
|
+
// Note that this check doesn't work for the landing page plugin, because
|
|
898
|
+
// users can write their own landing page plugins and we don't know if a
|
|
899
|
+
// given plugin is a landing page plugin until the server has started.
|
|
900
|
+
const pluginsByInternalID = new Map<
|
|
901
|
+
InternalPluginId,
|
|
902
|
+
{ sawDisabled: boolean; sawNonDisabled: boolean }
|
|
903
|
+
>();
|
|
904
|
+
for (const p of plugins) {
|
|
905
|
+
if (pluginIsInternal(p)) {
|
|
906
|
+
const id = p.__internal_plugin_id__;
|
|
907
|
+
if (!pluginsByInternalID.has(id)) {
|
|
908
|
+
pluginsByInternalID.set(id, {
|
|
909
|
+
sawDisabled: false,
|
|
910
|
+
sawNonDisabled: false,
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
const seen = pluginsByInternalID.get(id)!;
|
|
914
|
+
if (p.__is_disabled_plugin__) {
|
|
915
|
+
seen.sawDisabled = true;
|
|
916
|
+
} else {
|
|
917
|
+
seen.sawNonDisabled = true;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (seen.sawDisabled && seen.sawNonDisabled) {
|
|
921
|
+
throw new Error(
|
|
922
|
+
`You have tried to install both ApolloServerPlugin${id} and ` +
|
|
923
|
+
`ApolloServerPlugin${id}Disabled in your server. Please choose ` +
|
|
924
|
+
`whether or not you want to disable the feature and install the ` +
|
|
925
|
+
`appropriate plugin for your use case.`,
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Special case: cache control is on unless you explicitly disable it.
|
|
932
|
+
{
|
|
933
|
+
if (!alreadyHavePluginWithInternalId('CacheControl')) {
|
|
934
|
+
const { ApolloServerPluginCacheControl } = await import(
|
|
935
|
+
'./plugin/cacheControl/index.js'
|
|
936
|
+
);
|
|
937
|
+
plugins.push(ApolloServerPluginCacheControl());
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// Special case: usage reporting is on by default (and first!) if you
|
|
942
|
+
// configure an API key.
|
|
943
|
+
{
|
|
944
|
+
const alreadyHavePlugin =
|
|
945
|
+
alreadyHavePluginWithInternalId('UsageReporting');
|
|
946
|
+
if (!alreadyHavePlugin && apolloConfig.key) {
|
|
947
|
+
if (apolloConfig.graphRef) {
|
|
948
|
+
// Keep this plugin first so it wraps everything. (Unfortunately despite
|
|
949
|
+
// the fact that the person who wrote this line also was the original
|
|
950
|
+
// author of the comment above in #1105, they don't quite understand why this was important.)
|
|
951
|
+
const { ApolloServerPluginUsageReporting } = await import(
|
|
952
|
+
'./plugin/usageReporting/index.js'
|
|
953
|
+
);
|
|
954
|
+
plugins.unshift(
|
|
955
|
+
ApolloServerPluginUsageReporting({
|
|
956
|
+
__onlyIfSchemaIsNotSubgraph: true,
|
|
957
|
+
}),
|
|
958
|
+
);
|
|
959
|
+
} else {
|
|
960
|
+
this.logger.warn(
|
|
961
|
+
'You have specified an Apollo key but have not specified a graph ref; usage ' +
|
|
962
|
+
'reporting is disabled. To enable usage reporting, set the `APOLLO_GRAPH_REF` ' +
|
|
963
|
+
'environment variable to `your-graph-id@your-graph-variant`. To disable this ' +
|
|
964
|
+
'warning, install `ApolloServerPluginUsageReportingDisabled`.',
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Special case: schema reporting can be turned on via environment variable.
|
|
971
|
+
{
|
|
972
|
+
const alreadyHavePlugin =
|
|
973
|
+
alreadyHavePluginWithInternalId('SchemaReporting');
|
|
974
|
+
const enabledViaEnvVar = process.env.APOLLO_SCHEMA_REPORTING === 'true';
|
|
975
|
+
if (!alreadyHavePlugin && enabledViaEnvVar) {
|
|
976
|
+
if (apolloConfig.key) {
|
|
977
|
+
const { ApolloServerPluginSchemaReporting } = await import(
|
|
978
|
+
'./plugin/schemaReporting/index.js'
|
|
979
|
+
);
|
|
980
|
+
plugins.push(ApolloServerPluginSchemaReporting());
|
|
981
|
+
} else {
|
|
982
|
+
throw new Error(
|
|
983
|
+
"You've enabled schema reporting by setting the APOLLO_SCHEMA_REPORTING " +
|
|
984
|
+
'environment variable to true, but you also need to provide your ' +
|
|
985
|
+
'Apollo API key, via the APOLLO_KEY environment ' +
|
|
986
|
+
'variable or via `new ApolloServer({apollo: {key})',
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// Special case: inline tracing is on by default for federated schemas.
|
|
993
|
+
{
|
|
994
|
+
const alreadyHavePlugin = alreadyHavePluginWithInternalId('InlineTrace');
|
|
995
|
+
if (!alreadyHavePlugin) {
|
|
996
|
+
// If we haven't explicitly disabled inline tracing via
|
|
997
|
+
// ApolloServerPluginInlineTraceDisabled or explicitly installed our own
|
|
998
|
+
// ApolloServerPluginInlineTrace, we set up inline tracing in "only if
|
|
999
|
+
// federated" mode. (This is slightly different than the
|
|
1000
|
+
// pre-ApolloServerPluginInlineTrace where we would also avoid doing
|
|
1001
|
+
// this if an API key was configured and log a warning.)
|
|
1002
|
+
const { ApolloServerPluginInlineTrace } = await import(
|
|
1003
|
+
'./plugin/inlineTrace/index.js'
|
|
1004
|
+
);
|
|
1005
|
+
plugins.push(
|
|
1006
|
+
ApolloServerPluginInlineTrace({ __onlyIfSchemaIsSubgraph: true }),
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Special case: If we're not in production, show our default landing page.
|
|
1012
|
+
//
|
|
1013
|
+
// This works a bit differently from the other implicitly installed plugins,
|
|
1014
|
+
// which rely entirely on the __internal_plugin_id__ to decide whether the
|
|
1015
|
+
// plugin takes effect. That's because we want third-party plugins to be
|
|
1016
|
+
// able to provide a landing page that overrides the default landing page,
|
|
1017
|
+
// without them having to know about __internal_plugin_id__. So unless we
|
|
1018
|
+
// actively disable the default landing page with
|
|
1019
|
+
// ApolloServerPluginLandingPageDisabled, we install the default landing
|
|
1020
|
+
// page, but with a special flag that _start() uses to ignore it if some
|
|
1021
|
+
// other plugin defines a renderLandingPage callback. (We can't just look
|
|
1022
|
+
// now to see if the plugin defines renderLandingPage because we haven't run
|
|
1023
|
+
// serverWillStart yet.)
|
|
1024
|
+
const alreadyHavePlugin = alreadyHavePluginWithInternalId(
|
|
1025
|
+
'LandingPageDisabled',
|
|
1026
|
+
);
|
|
1027
|
+
if (!alreadyHavePlugin) {
|
|
1028
|
+
const {
|
|
1029
|
+
ApolloServerPluginLandingPageLocalDefault,
|
|
1030
|
+
ApolloServerPluginLandingPageProductionDefault,
|
|
1031
|
+
} = await import('./plugin/landingPage/default/index.js');
|
|
1032
|
+
const plugin: ApolloServerPlugin<TContext> = isDev
|
|
1033
|
+
? ApolloServerPluginLandingPageLocalDefault()
|
|
1034
|
+
: ApolloServerPluginLandingPageProductionDefault();
|
|
1035
|
+
if (!isImplicitlyInstallablePlugin(plugin)) {
|
|
1036
|
+
throw Error(
|
|
1037
|
+
'default landing page plugin should be implicitly installable?',
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
plugin.__internal_installed_implicitly__ = true;
|
|
1041
|
+
plugins.push(plugin);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
{
|
|
1045
|
+
const alreadyHavePlugin =
|
|
1046
|
+
alreadyHavePluginWithInternalId('DisableSuggestions');
|
|
1047
|
+
if (hideSchemaDetailsFromClientErrors && !alreadyHavePlugin) {
|
|
1048
|
+
const { ApolloServerPluginDisableSuggestions } = await import(
|
|
1049
|
+
'./plugin/disableSuggestions/index.js'
|
|
1050
|
+
);
|
|
1051
|
+
plugins.push(ApolloServerPluginDisableSuggestions());
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
public addPlugin(plugin: ApolloServerPlugin<TContext>) {
|
|
1057
|
+
if (this.internals.state.phase !== 'initialized') {
|
|
1058
|
+
throw new Error("Can't add plugins after the server has started");
|
|
1059
|
+
}
|
|
1060
|
+
this.internals.plugins.push(plugin);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
public async executeHTTPGraphQLRequest({
|
|
1064
|
+
httpGraphQLRequest,
|
|
1065
|
+
context,
|
|
1066
|
+
}: {
|
|
1067
|
+
httpGraphQLRequest: HTTPGraphQLRequest;
|
|
1068
|
+
context: ContextThunk<TContext>;
|
|
1069
|
+
}): Promise<HTTPGraphQLResponse> {
|
|
1070
|
+
try {
|
|
1071
|
+
let runningServerState;
|
|
1072
|
+
try {
|
|
1073
|
+
runningServerState = await this._ensureStarted();
|
|
1074
|
+
} catch (error: unknown) {
|
|
1075
|
+
// This is typically either the masked error from when background startup
|
|
1076
|
+
// failed, or related to invoking this function before startup or
|
|
1077
|
+
// during/after shutdown (due to lack of draining).
|
|
1078
|
+
return await this.errorResponse(error, httpGraphQLRequest);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
if (
|
|
1082
|
+
runningServerState.landingPage &&
|
|
1083
|
+
this.prefersHTML(httpGraphQLRequest)
|
|
1084
|
+
) {
|
|
1085
|
+
let renderedHtml;
|
|
1086
|
+
if (typeof runningServerState.landingPage.html === 'string') {
|
|
1087
|
+
renderedHtml = runningServerState.landingPage.html;
|
|
1088
|
+
} else {
|
|
1089
|
+
try {
|
|
1090
|
+
renderedHtml = await runningServerState.landingPage.html();
|
|
1091
|
+
} catch (maybeError: unknown) {
|
|
1092
|
+
const error = ensureError(maybeError);
|
|
1093
|
+
this.logger.error(`Landing page \`html\` function threw: ${error}`);
|
|
1094
|
+
return await this.errorResponse(error, httpGraphQLRequest);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
return {
|
|
1099
|
+
headers: new HeaderMap([['content-type', 'text/html']]),
|
|
1100
|
+
body: {
|
|
1101
|
+
kind: 'complete',
|
|
1102
|
+
string: renderedHtml,
|
|
1103
|
+
},
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// If enabled, check to ensure that this request was preflighted before doing
|
|
1108
|
+
// anything real (such as running the context function).
|
|
1109
|
+
if (this.internals.csrfPreventionRequestHeaders) {
|
|
1110
|
+
preventCsrf(
|
|
1111
|
+
httpGraphQLRequest.headers,
|
|
1112
|
+
this.internals.csrfPreventionRequestHeaders,
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
let contextValue: TContext;
|
|
1117
|
+
try {
|
|
1118
|
+
contextValue = await context();
|
|
1119
|
+
} catch (maybeError: unknown) {
|
|
1120
|
+
const error = ensureError(maybeError);
|
|
1121
|
+
try {
|
|
1122
|
+
await Promise.all(
|
|
1123
|
+
this.internals.plugins.map(async (plugin) =>
|
|
1124
|
+
plugin.contextCreationDidFail?.({
|
|
1125
|
+
error,
|
|
1126
|
+
}),
|
|
1127
|
+
),
|
|
1128
|
+
);
|
|
1129
|
+
} catch (pluginError) {
|
|
1130
|
+
this.logger.error(
|
|
1131
|
+
`contextCreationDidFail hook threw: ${pluginError}`,
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// If some random function threw, add a helpful prefix when converting
|
|
1136
|
+
// to GraphQLError. If it was already a GraphQLError, trust that the
|
|
1137
|
+
// message was chosen thoughtfully and leave off the prefix.
|
|
1138
|
+
return await this.errorResponse(
|
|
1139
|
+
ensureGraphQLError(error, 'Context creation failed: '),
|
|
1140
|
+
httpGraphQLRequest,
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
return await runPotentiallyBatchedHttpQuery(
|
|
1145
|
+
this,
|
|
1146
|
+
httpGraphQLRequest,
|
|
1147
|
+
contextValue,
|
|
1148
|
+
runningServerState.schemaManager.getSchemaDerivedData(),
|
|
1149
|
+
this.internals,
|
|
1150
|
+
);
|
|
1151
|
+
} catch (maybeError_: unknown) {
|
|
1152
|
+
const maybeError = maybeError_; // fixes inference because catch vars are not const
|
|
1153
|
+
if (
|
|
1154
|
+
maybeError instanceof GraphQLError &&
|
|
1155
|
+
maybeError.extensions.code === ApolloServerErrorCode.BAD_REQUEST
|
|
1156
|
+
) {
|
|
1157
|
+
try {
|
|
1158
|
+
await Promise.all(
|
|
1159
|
+
this.internals.plugins.map(async (plugin) =>
|
|
1160
|
+
plugin.invalidRequestWasReceived?.({ error: maybeError }),
|
|
1161
|
+
),
|
|
1162
|
+
);
|
|
1163
|
+
} catch (pluginError) {
|
|
1164
|
+
this.logger.error(
|
|
1165
|
+
`invalidRequestWasReceived hook threw: ${pluginError}`,
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return await this.errorResponse(maybeError, httpGraphQLRequest);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
private async errorResponse(
|
|
1174
|
+
error: unknown,
|
|
1175
|
+
requestHead: HTTPGraphQLHead,
|
|
1176
|
+
): Promise<HTTPGraphQLResponse> {
|
|
1177
|
+
const { formattedErrors, httpFromErrors } = normalizeAndFormatErrors(
|
|
1178
|
+
[error],
|
|
1179
|
+
{
|
|
1180
|
+
includeStacktraceInErrorResponses:
|
|
1181
|
+
this.internals.includeStacktraceInErrorResponses,
|
|
1182
|
+
formatError: this.internals.formatError,
|
|
1183
|
+
},
|
|
1184
|
+
);
|
|
1185
|
+
|
|
1186
|
+
return {
|
|
1187
|
+
status: httpFromErrors.status ?? 500,
|
|
1188
|
+
headers: new HeaderMap([
|
|
1189
|
+
...httpFromErrors.headers,
|
|
1190
|
+
[
|
|
1191
|
+
'content-type',
|
|
1192
|
+
// Note that we may change the default to
|
|
1193
|
+
// 'application/graphql-response+json' by 2025 as encouraged by the
|
|
1194
|
+
// graphql-over-http spec. It's maybe a bit bad for us to provide
|
|
1195
|
+
// an application/json response if they send `accept: foo/bar`,
|
|
1196
|
+
// but we're already providing some sort of bad request error, and
|
|
1197
|
+
// it's probably more useful for them to fix the other error before
|
|
1198
|
+
// they deal with the `accept` header.
|
|
1199
|
+
chooseContentTypeForSingleResultResponse(requestHead) ??
|
|
1200
|
+
MEDIA_TYPES.APPLICATION_JSON,
|
|
1201
|
+
],
|
|
1202
|
+
]),
|
|
1203
|
+
body: {
|
|
1204
|
+
kind: 'complete',
|
|
1205
|
+
string: await this.internals.stringifyResult({
|
|
1206
|
+
errors: formattedErrors,
|
|
1207
|
+
}),
|
|
1208
|
+
},
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
private prefersHTML(request: HTTPGraphQLRequest): boolean {
|
|
1213
|
+
const acceptHeader = request.headers.get('accept');
|
|
1214
|
+
return (
|
|
1215
|
+
request.method === 'GET' &&
|
|
1216
|
+
!!acceptHeader &&
|
|
1217
|
+
new Negotiator({
|
|
1218
|
+
headers: { accept: acceptHeader },
|
|
1219
|
+
}).mediaType([
|
|
1220
|
+
// We need it to actively prefer text/html over less browser-y types;
|
|
1221
|
+
// eg, `accept: */*' should still go for JSON. Negotiator does tiebreak
|
|
1222
|
+
// by the order in the list we provide, so we put text/html last.
|
|
1223
|
+
MEDIA_TYPES.APPLICATION_JSON,
|
|
1224
|
+
MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON,
|
|
1225
|
+
MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL_ALPHA_2,
|
|
1226
|
+
MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL_ALPHA_9,
|
|
1227
|
+
MEDIA_TYPES.MULTIPART_MIXED_NO_DEFER_SPEC,
|
|
1228
|
+
MEDIA_TYPES.TEXT_HTML,
|
|
1229
|
+
]) === MEDIA_TYPES.TEXT_HTML
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* This method is primarily meant for testing: it allows you to execute a
|
|
1235
|
+
* GraphQL operation via the request pipeline without going through the HTTP
|
|
1236
|
+
* layer. Note that this means that any handling you do in your server at the
|
|
1237
|
+
* HTTP level will not affect this call!
|
|
1238
|
+
*
|
|
1239
|
+
* For convenience, you can provide `request.query` either as a string or a
|
|
1240
|
+
* DocumentNode, in case you choose to use the gql tag in your tests. This is
|
|
1241
|
+
* just a convenience, not an optimization (we convert provided ASTs back into
|
|
1242
|
+
* string).
|
|
1243
|
+
*
|
|
1244
|
+
* The second object is an optional options object which includes the optional
|
|
1245
|
+
* `contextValue` object available in resolvers.
|
|
1246
|
+
*
|
|
1247
|
+
* You may specify the TData and TVariables generic types when calling this
|
|
1248
|
+
* method; Apollo Server does not validate that the returned data actually
|
|
1249
|
+
* matches the structure of TData. (Typically these types are created by a
|
|
1250
|
+
* code generation tool.) Note that this does not enforce that `variables` is
|
|
1251
|
+
* provided at all, just that it has the right type if provided.
|
|
1252
|
+
*/
|
|
1253
|
+
public async executeOperation<
|
|
1254
|
+
TData = Record<string, unknown>,
|
|
1255
|
+
TVariables extends VariableValues = VariableValues,
|
|
1256
|
+
>(
|
|
1257
|
+
this: ApolloServer<BaseContext>,
|
|
1258
|
+
request: Omit<GraphQLRequest<TVariables>, 'query'> & {
|
|
1259
|
+
query?: string | DocumentNode | TypedQueryDocumentNode<TData, TVariables>;
|
|
1260
|
+
},
|
|
1261
|
+
): Promise<GraphQLResponse<TData>>;
|
|
1262
|
+
public async executeOperation<
|
|
1263
|
+
TData = Record<string, unknown>,
|
|
1264
|
+
TVariables extends VariableValues = VariableValues,
|
|
1265
|
+
>(
|
|
1266
|
+
request: Omit<GraphQLRequest<TVariables>, 'query'> & {
|
|
1267
|
+
query?: string | DocumentNode | TypedQueryDocumentNode<TData, TVariables>;
|
|
1268
|
+
},
|
|
1269
|
+
options?: ExecuteOperationOptions<TContext>,
|
|
1270
|
+
): Promise<GraphQLResponse<TData>>;
|
|
1271
|
+
|
|
1272
|
+
async executeOperation<
|
|
1273
|
+
TData = Record<string, unknown>,
|
|
1274
|
+
TVariables extends VariableValues = VariableValues,
|
|
1275
|
+
>(
|
|
1276
|
+
request: Omit<GraphQLRequest<TVariables>, 'query'> & {
|
|
1277
|
+
// We should consider supporting TypedDocumentNode from
|
|
1278
|
+
// `@graphql-typed-document-node/core` as well, as it is more popular than
|
|
1279
|
+
// the newer built-in type.
|
|
1280
|
+
query?: string | DocumentNode | TypedQueryDocumentNode<TData, TVariables>;
|
|
1281
|
+
},
|
|
1282
|
+
options: ExecuteOperationOptions<TContext> = {},
|
|
1283
|
+
): Promise<GraphQLResponse<TData>> {
|
|
1284
|
+
// Since this function is mostly for testing, you don't need to explicitly
|
|
1285
|
+
// start your server before calling it. (That also means you can use it with
|
|
1286
|
+
// `apollo-server` which doesn't support `start()`.)
|
|
1287
|
+
if (this.internals.state.phase === 'initialized') {
|
|
1288
|
+
await this.start();
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
const schemaDerivedData = (
|
|
1292
|
+
await this._ensureStarted()
|
|
1293
|
+
).schemaManager.getSchemaDerivedData();
|
|
1294
|
+
|
|
1295
|
+
// For convenience, this function lets you pass either a string or an AST,
|
|
1296
|
+
// but we normalize to string.
|
|
1297
|
+
const graphQLRequest: GraphQLRequest = {
|
|
1298
|
+
...request,
|
|
1299
|
+
query:
|
|
1300
|
+
request.query && typeof request.query !== 'string'
|
|
1301
|
+
? print(request.query)
|
|
1302
|
+
: request.query,
|
|
1303
|
+
};
|
|
1304
|
+
|
|
1305
|
+
const response: GraphQLResponse = await internalExecuteOperation(
|
|
1306
|
+
{
|
|
1307
|
+
server: this,
|
|
1308
|
+
graphQLRequest,
|
|
1309
|
+
internals: this.internals,
|
|
1310
|
+
schemaDerivedData,
|
|
1311
|
+
sharedResponseHTTPGraphQLHead: null,
|
|
1312
|
+
},
|
|
1313
|
+
options,
|
|
1314
|
+
);
|
|
1315
|
+
|
|
1316
|
+
// It's your job to set an appropriate TData (perhaps using codegen); we
|
|
1317
|
+
// don't validate it.
|
|
1318
|
+
return response as GraphQLResponse<TData>;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// Shared code between runHttpQuery (ie executeHTTPGraphQLRequest) and
|
|
1323
|
+
// executeOperation to set up a request context and invoke the request pipeline.
|
|
1324
|
+
export async function internalExecuteOperation<TContext extends BaseContext>(
|
|
1325
|
+
{
|
|
1326
|
+
server,
|
|
1327
|
+
graphQLRequest,
|
|
1328
|
+
internals,
|
|
1329
|
+
schemaDerivedData,
|
|
1330
|
+
sharedResponseHTTPGraphQLHead,
|
|
1331
|
+
}: {
|
|
1332
|
+
server: ApolloServer<TContext>;
|
|
1333
|
+
graphQLRequest: GraphQLRequest;
|
|
1334
|
+
internals: ApolloServerInternals<TContext>;
|
|
1335
|
+
schemaDerivedData: SchemaDerivedData;
|
|
1336
|
+
sharedResponseHTTPGraphQLHead: HTTPGraphQLHead | null;
|
|
1337
|
+
},
|
|
1338
|
+
options: ExecuteOperationOptions<TContext>,
|
|
1339
|
+
): Promise<GraphQLResponse> {
|
|
1340
|
+
const requestContext: GraphQLRequestContext<TContext> = {
|
|
1341
|
+
logger: server.logger,
|
|
1342
|
+
cache: server.cache,
|
|
1343
|
+
schema: schemaDerivedData.schema,
|
|
1344
|
+
request: graphQLRequest,
|
|
1345
|
+
response: {
|
|
1346
|
+
http: sharedResponseHTTPGraphQLHead ?? newHTTPGraphQLHead(),
|
|
1347
|
+
},
|
|
1348
|
+
// We clone the context because there are some assumptions that every operation
|
|
1349
|
+
// execution has a brand new context object; specifically, in order to implement
|
|
1350
|
+
// willResolveField we put a Symbol on the context that is specific to a particular
|
|
1351
|
+
// request pipeline execution. We could avoid this if we had a better way of
|
|
1352
|
+
// instrumenting execution.
|
|
1353
|
+
//
|
|
1354
|
+
// We don't want to do a deep clone here, because one of the main advantages of
|
|
1355
|
+
// using batched HTTP requests is to share context across operations for a
|
|
1356
|
+
// single request.
|
|
1357
|
+
//
|
|
1358
|
+
// The typecast here is safe, because the only way `contextValue` can be
|
|
1359
|
+
// null-ish is if we used the `contextValue?: BaseContext` override, in
|
|
1360
|
+
// which case TContext is BaseContext and {} is ok. (This does depend on
|
|
1361
|
+
// the fact we've hackily forced the class to be contravariant in
|
|
1362
|
+
// TContext.)
|
|
1363
|
+
contextValue: cloneObject(options?.contextValue ?? ({} as TContext)),
|
|
1364
|
+
metrics: {},
|
|
1365
|
+
overallCachePolicy: newCachePolicy(),
|
|
1366
|
+
requestIsBatched: sharedResponseHTTPGraphQLHead !== null,
|
|
1367
|
+
};
|
|
1368
|
+
|
|
1369
|
+
try {
|
|
1370
|
+
return await processGraphQLRequest(
|
|
1371
|
+
schemaDerivedData,
|
|
1372
|
+
server,
|
|
1373
|
+
internals,
|
|
1374
|
+
requestContext,
|
|
1375
|
+
);
|
|
1376
|
+
} catch (maybeError: unknown) {
|
|
1377
|
+
// processGraphQLRequest throwing usually means that either there's a bug in
|
|
1378
|
+
// Apollo Server or some plugin hook threw unexpectedly.
|
|
1379
|
+
const error = ensureError(maybeError);
|
|
1380
|
+
// If *these* hooks throw then we'll still get a 500 but won't mask its
|
|
1381
|
+
// error.
|
|
1382
|
+
await Promise.all(
|
|
1383
|
+
internals.plugins.map(async (plugin) =>
|
|
1384
|
+
plugin.unexpectedErrorProcessingRequest?.({
|
|
1385
|
+
requestContext,
|
|
1386
|
+
error,
|
|
1387
|
+
}),
|
|
1388
|
+
),
|
|
1389
|
+
);
|
|
1390
|
+
// Mask unexpected error externally.
|
|
1391
|
+
server.logger.error(`Unexpected error processing request: ${error}`);
|
|
1392
|
+
throw new Error('Internal server error');
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
// Unlike InternalPlugins (where we can decide whether to install the default
|
|
1397
|
+
// plugin based on looking at which plugins are installed),
|
|
1398
|
+
// ImplicitlyInstallablePlugins (ie the default landing page plugin) can't
|
|
1399
|
+
// determine if they're needed until later in startup. Specifically, we can't
|
|
1400
|
+
// know if we've defined our own landing page until after serverWillStart
|
|
1401
|
+
// plugins have run.
|
|
1402
|
+
export type ImplicitlyInstallablePlugin<TContext extends BaseContext> =
|
|
1403
|
+
ApolloServerPlugin<TContext> & {
|
|
1404
|
+
__internal_installed_implicitly__: boolean;
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
export function isImplicitlyInstallablePlugin<TContext extends BaseContext>(
|
|
1408
|
+
p: ApolloServerPlugin<TContext>,
|
|
1409
|
+
): p is ImplicitlyInstallablePlugin<TContext> {
|
|
1410
|
+
return '__internal_installed_implicitly__' in p;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
export const MEDIA_TYPES = {
|
|
1414
|
+
APPLICATION_JSON: 'application/json; charset=utf-8',
|
|
1415
|
+
APPLICATION_JSON_GRAPHQL_CALLBACK:
|
|
1416
|
+
'application/json; callbackSpec=1.0; charset=utf-8',
|
|
1417
|
+
APPLICATION_GRAPHQL_RESPONSE_JSON:
|
|
1418
|
+
'application/graphql-response+json; charset=utf-8',
|
|
1419
|
+
// We do *not* currently support this content-type; we will once incremental
|
|
1420
|
+
// delivery is part of the official GraphQL spec.
|
|
1421
|
+
MULTIPART_MIXED_NO_DEFER_SPEC: 'multipart/mixed',
|
|
1422
|
+
MULTIPART_MIXED_EXPERIMENTAL_ALPHA_2: 'multipart/mixed; deferSpec=20220824',
|
|
1423
|
+
// This references the spec stored at
|
|
1424
|
+
// https://specs.apollo.dev/incremental/v0.2/
|
|
1425
|
+
MULTIPART_MIXED_EXPERIMENTAL_ALPHA_9: 'multipart/mixed; incrementalSpec=v0.2',
|
|
1426
|
+
TEXT_HTML: 'text/html',
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
export function chooseContentTypeForSingleResultResponse(
|
|
1430
|
+
head: HTTPGraphQLHead,
|
|
1431
|
+
): string | null {
|
|
1432
|
+
const acceptHeader = head.headers.get('accept');
|
|
1433
|
+
if (!acceptHeader) {
|
|
1434
|
+
// Note that we may change the default to
|
|
1435
|
+
// 'application/graphql-response+json' by 2025 as encouraged by the
|
|
1436
|
+
// graphql-over-http spec.
|
|
1437
|
+
return MEDIA_TYPES.APPLICATION_JSON;
|
|
1438
|
+
} else {
|
|
1439
|
+
const preferred = new Negotiator({
|
|
1440
|
+
headers: { accept: head.headers.get('accept') },
|
|
1441
|
+
}).mediaType([
|
|
1442
|
+
MEDIA_TYPES.APPLICATION_JSON,
|
|
1443
|
+
MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON,
|
|
1444
|
+
MEDIA_TYPES.APPLICATION_JSON_GRAPHQL_CALLBACK,
|
|
1445
|
+
]);
|
|
1446
|
+
if (preferred) {
|
|
1447
|
+
return preferred;
|
|
1448
|
+
} else {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
function cloneObject<T extends Object>(object: T): T {
|
|
1455
|
+
return Object.assign(Object.create(Object.getPrototypeOf(object)), object);
|
|
1456
|
+
}
|