@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,492 @@
|
|
|
1
|
+
import type { NonFtv1ErrorPath } from '@apollo/server-gateway-interface';
|
|
2
|
+
import {
|
|
3
|
+
type google,
|
|
4
|
+
type IContextualizedStats,
|
|
5
|
+
type IFieldStat,
|
|
6
|
+
type IPathErrorStats,
|
|
7
|
+
type IQueryLatencyStats,
|
|
8
|
+
type IReport,
|
|
9
|
+
type IStatsContext,
|
|
10
|
+
type ITracesAndStats,
|
|
11
|
+
type ITypeStat,
|
|
12
|
+
type ReportHeader,
|
|
13
|
+
Trace,
|
|
14
|
+
} from '@apollo/usage-reporting-protobuf';
|
|
15
|
+
import type { ReferencedFieldsByType } from '@apollo/utils.usagereporting';
|
|
16
|
+
import { DurationHistogram } from './durationHistogram.js';
|
|
17
|
+
import { iterateOverTrace, type ResponseNamePath } from './iterateOverTrace.js';
|
|
18
|
+
|
|
19
|
+
// protobuf.js exports both a class and an interface (starting with I) for each
|
|
20
|
+
// message type. The class is what it produces when it decodes the message; the
|
|
21
|
+
// interface is what is accepted as input. We build up our messages using custom
|
|
22
|
+
// types implementing the interfaces, so that we can take advantage of the
|
|
23
|
+
// js_use_toArray option we added to our protobuf.js fork which allows us to use
|
|
24
|
+
// classes like DurationHistogram to generate repeated fields. We end up
|
|
25
|
+
// re-creating most of the report structure as custom classes (starting with
|
|
26
|
+
// "Our"). TypeScript validates that we've properly listed all of the message
|
|
27
|
+
// fields with the appropriate types (we use `Required` to ensure we implement
|
|
28
|
+
// all message fields). Using our own classes has other advantages, like being
|
|
29
|
+
// able to specify that nested messages are instances of the same class rather
|
|
30
|
+
// than the interface type and thus that they have non-null fields (because the
|
|
31
|
+
// interface type allows all fields to be optional, even though the protobuf
|
|
32
|
+
// format doesn't differentiate between missing and falsey).
|
|
33
|
+
|
|
34
|
+
export class SizeEstimator {
|
|
35
|
+
bytes = 0;
|
|
36
|
+
}
|
|
37
|
+
export class OurReport implements Required<IReport> {
|
|
38
|
+
// Apollo Server includes each operation either as aggregated stats or as a
|
|
39
|
+
// trace, but not both. Other reporting agents such as Apollo Router include
|
|
40
|
+
// all operations in stats (even those that are sent as traces), and they set
|
|
41
|
+
// this flag to true.
|
|
42
|
+
tracesPreAggregated = false;
|
|
43
|
+
|
|
44
|
+
constructor(readonly header: ReportHeader) {}
|
|
45
|
+
readonly tracesPerQuery: Record<string, OurTracesAndStats> =
|
|
46
|
+
Object.create(null);
|
|
47
|
+
endTime: google.protobuf.ITimestamp | null = null;
|
|
48
|
+
operationCount = 0;
|
|
49
|
+
// A rough estimate of the number of bytes currently in the report. We start
|
|
50
|
+
// at zero and don't count `header` and `endTime`, which have the same size
|
|
51
|
+
// for every report. This really is a rough estimate, so we don't stress too
|
|
52
|
+
// much about counting bytes for the tags and string/message lengths, etc:
|
|
53
|
+
// we mostly just count the lengths of strings plus some estimates for the
|
|
54
|
+
// messages with a bunch of numbers in them.
|
|
55
|
+
//
|
|
56
|
+
// We store this in a class so we can pass it down as a reference to other
|
|
57
|
+
// methods which increment it.
|
|
58
|
+
readonly sizeEstimator = new SizeEstimator();
|
|
59
|
+
|
|
60
|
+
ensureCountsAreIntegers() {
|
|
61
|
+
for (const tracesAndStats of Object.values(this.tracesPerQuery)) {
|
|
62
|
+
tracesAndStats.ensureCountsAreIntegers();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
addTrace({
|
|
67
|
+
statsReportKey,
|
|
68
|
+
trace,
|
|
69
|
+
asTrace,
|
|
70
|
+
referencedFieldsByType,
|
|
71
|
+
// The max size a trace can be before it is sent as stats. Note that the
|
|
72
|
+
// Apollo reporting ingress server will never store any traces over 10mb
|
|
73
|
+
// anyway. They will still be converted to stats as we would do here.
|
|
74
|
+
maxTraceBytes = 10 * 1024 * 1024,
|
|
75
|
+
nonFtv1ErrorPaths,
|
|
76
|
+
}: {
|
|
77
|
+
statsReportKey: string;
|
|
78
|
+
trace: Trace;
|
|
79
|
+
asTrace: boolean;
|
|
80
|
+
referencedFieldsByType: ReferencedFieldsByType;
|
|
81
|
+
maxTraceBytes?: number;
|
|
82
|
+
nonFtv1ErrorPaths: NonFtv1ErrorPath[];
|
|
83
|
+
}) {
|
|
84
|
+
const tracesAndStats = this.getTracesAndStats({
|
|
85
|
+
statsReportKey,
|
|
86
|
+
referencedFieldsByType,
|
|
87
|
+
});
|
|
88
|
+
if (asTrace) {
|
|
89
|
+
const encodedTrace = Trace.encode(trace).finish();
|
|
90
|
+
|
|
91
|
+
if (!isNaN(maxTraceBytes) && encodedTrace.length > maxTraceBytes) {
|
|
92
|
+
tracesAndStats.statsWithContext.addTrace(
|
|
93
|
+
trace,
|
|
94
|
+
this.sizeEstimator,
|
|
95
|
+
nonFtv1ErrorPaths,
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
tracesAndStats.trace.push(encodedTrace);
|
|
99
|
+
this.sizeEstimator.bytes += 2 + encodedTrace.length;
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
tracesAndStats.statsWithContext.addTrace(
|
|
103
|
+
trace,
|
|
104
|
+
this.sizeEstimator,
|
|
105
|
+
nonFtv1ErrorPaths,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private getTracesAndStats({
|
|
111
|
+
statsReportKey,
|
|
112
|
+
referencedFieldsByType,
|
|
113
|
+
}: {
|
|
114
|
+
statsReportKey: string;
|
|
115
|
+
referencedFieldsByType: ReferencedFieldsByType;
|
|
116
|
+
}) {
|
|
117
|
+
const existing = this.tracesPerQuery[statsReportKey];
|
|
118
|
+
if (existing) {
|
|
119
|
+
return existing;
|
|
120
|
+
}
|
|
121
|
+
this.sizeEstimator.bytes += estimatedBytesForString(statsReportKey);
|
|
122
|
+
|
|
123
|
+
// Update the size estimator for the referenced field structure.
|
|
124
|
+
for (const [typeName, referencedFieldsForType] of Object.entries(
|
|
125
|
+
referencedFieldsByType,
|
|
126
|
+
)) {
|
|
127
|
+
// Two bytes each for the map entry and for the ReferencedFieldsForType,
|
|
128
|
+
// and for the isInterface bool if it's set.
|
|
129
|
+
this.sizeEstimator.bytes += 2 + 2;
|
|
130
|
+
if (referencedFieldsForType.isInterface) {
|
|
131
|
+
this.sizeEstimator.bytes += 2;
|
|
132
|
+
}
|
|
133
|
+
this.sizeEstimator.bytes += estimatedBytesForString(typeName);
|
|
134
|
+
for (const fieldName of referencedFieldsForType.fieldNames) {
|
|
135
|
+
this.sizeEstimator.bytes += estimatedBytesForString(fieldName);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Include the referenced fields map in the report. (In an ideal world we
|
|
140
|
+
// could have a slightly more sophisticated protocol and ingestion pipeline
|
|
141
|
+
// that allowed us to only have to send this data once for each
|
|
142
|
+
// schema/operation pair.)
|
|
143
|
+
return (this.tracesPerQuery[statsReportKey] = new OurTracesAndStats(
|
|
144
|
+
referencedFieldsByType,
|
|
145
|
+
));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class OurTracesAndStats implements Required<ITracesAndStats> {
|
|
150
|
+
constructor(readonly referencedFieldsByType: ReferencedFieldsByType) {}
|
|
151
|
+
readonly trace: Uint8Array[] = [];
|
|
152
|
+
readonly statsWithContext = new StatsByContext();
|
|
153
|
+
readonly internalTracesContributingToStats: Uint8Array[] = [];
|
|
154
|
+
|
|
155
|
+
ensureCountsAreIntegers() {
|
|
156
|
+
this.statsWithContext.ensureCountsAreIntegers();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
class StatsByContext {
|
|
161
|
+
readonly map: { [k: string]: OurContextualizedStats } = Object.create(null);
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* This function is used by the protobuf generator to convert this map into
|
|
165
|
+
* an array of contextualized stats to serialize
|
|
166
|
+
*/
|
|
167
|
+
toArray(): IContextualizedStats[] {
|
|
168
|
+
return Object.values(this.map);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
ensureCountsAreIntegers() {
|
|
172
|
+
for (const contextualizedStats of Object.values(this.map)) {
|
|
173
|
+
contextualizedStats.ensureCountsAreIntegers();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
addTrace(
|
|
178
|
+
trace: Trace,
|
|
179
|
+
sizeEstimator: SizeEstimator,
|
|
180
|
+
nonFtv1ErrorPaths: NonFtv1ErrorPath[],
|
|
181
|
+
) {
|
|
182
|
+
this.getContextualizedStats(trace, sizeEstimator).addTrace(
|
|
183
|
+
trace,
|
|
184
|
+
sizeEstimator,
|
|
185
|
+
nonFtv1ErrorPaths,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private getContextualizedStats(
|
|
190
|
+
trace: Trace,
|
|
191
|
+
sizeEstimator: SizeEstimator,
|
|
192
|
+
): OurContextualizedStats {
|
|
193
|
+
const statsContext: IStatsContext = {
|
|
194
|
+
clientName: trace.clientName,
|
|
195
|
+
clientVersion: trace.clientVersion,
|
|
196
|
+
};
|
|
197
|
+
const statsContextKey = JSON.stringify(statsContext);
|
|
198
|
+
|
|
199
|
+
const existing = this.map[statsContextKey];
|
|
200
|
+
if (existing) {
|
|
201
|
+
return existing;
|
|
202
|
+
}
|
|
203
|
+
// Adding a ContextualizedStats means adding a StatsContext plus a
|
|
204
|
+
// QueryLatencyStats. Let's guess about 20 bytes for a QueryLatencyStats;
|
|
205
|
+
// it'll be more if more features are used (like cache, APQ, etc).
|
|
206
|
+
sizeEstimator.bytes +=
|
|
207
|
+
20 +
|
|
208
|
+
estimatedBytesForString(trace.clientName) +
|
|
209
|
+
estimatedBytesForString(trace.clientVersion);
|
|
210
|
+
const contextualizedStats = new OurContextualizedStats(statsContext);
|
|
211
|
+
this.map[statsContextKey] = contextualizedStats;
|
|
212
|
+
return contextualizedStats;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export class OurContextualizedStats implements Required<IContextualizedStats> {
|
|
217
|
+
queryLatencyStats = new OurQueryLatencyStats();
|
|
218
|
+
perTypeStat: { [k: string]: OurTypeStat } = Object.create(null);
|
|
219
|
+
|
|
220
|
+
constructor(readonly context: IStatsContext) {}
|
|
221
|
+
|
|
222
|
+
ensureCountsAreIntegers() {
|
|
223
|
+
for (const typeStat of Object.values(this.perTypeStat)) {
|
|
224
|
+
typeStat.ensureCountsAreIntegers();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Extract statistics from the trace, and increment the estimated report size.
|
|
229
|
+
// We only add to the estimate when adding whole sub-messages. If it really
|
|
230
|
+
// mattered, we could do a lot more careful things like incrementing it
|
|
231
|
+
// whenever a numeric field on queryLatencyStats gets incremented over 0.
|
|
232
|
+
addTrace(
|
|
233
|
+
trace: Trace,
|
|
234
|
+
sizeEstimator: SizeEstimator,
|
|
235
|
+
nonFtv1ErrorPaths: NonFtv1ErrorPath[] = [],
|
|
236
|
+
) {
|
|
237
|
+
const { fieldExecutionWeight } = trace;
|
|
238
|
+
if (!fieldExecutionWeight) {
|
|
239
|
+
this.queryLatencyStats.requestsWithoutFieldInstrumentation++;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
this.queryLatencyStats.requestCount++;
|
|
243
|
+
if (trace.fullQueryCacheHit) {
|
|
244
|
+
this.queryLatencyStats.cacheLatencyCount.incrementDuration(
|
|
245
|
+
trace.durationNs,
|
|
246
|
+
);
|
|
247
|
+
this.queryLatencyStats.cacheHits++;
|
|
248
|
+
} else {
|
|
249
|
+
this.queryLatencyStats.latencyCount.incrementDuration(trace.durationNs);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// We only provide stats about cache TTLs on cache misses (ie, TTLs directly
|
|
253
|
+
// calculated by the backend), not for cache hits. This matches the
|
|
254
|
+
// behavior we've had for a while when converting traces into statistics
|
|
255
|
+
// in Studio's servers.
|
|
256
|
+
if (!trace.fullQueryCacheHit && trace.cachePolicy?.maxAgeNs != null) {
|
|
257
|
+
switch (trace.cachePolicy.scope) {
|
|
258
|
+
case Trace.CachePolicy.Scope.PRIVATE:
|
|
259
|
+
this.queryLatencyStats.privateCacheTtlCount.incrementDuration(
|
|
260
|
+
trace.cachePolicy.maxAgeNs,
|
|
261
|
+
);
|
|
262
|
+
break;
|
|
263
|
+
case Trace.CachePolicy.Scope.PUBLIC:
|
|
264
|
+
this.queryLatencyStats.publicCacheTtlCount.incrementDuration(
|
|
265
|
+
trace.cachePolicy.maxAgeNs,
|
|
266
|
+
);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (trace.persistedQueryHit) {
|
|
272
|
+
this.queryLatencyStats.persistedQueryHits++;
|
|
273
|
+
}
|
|
274
|
+
if (trace.persistedQueryRegister) {
|
|
275
|
+
this.queryLatencyStats.persistedQueryMisses++;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (trace.forbiddenOperation) {
|
|
279
|
+
this.queryLatencyStats.forbiddenOperationCount++;
|
|
280
|
+
}
|
|
281
|
+
if (trace.registeredOperation) {
|
|
282
|
+
this.queryLatencyStats.registeredOperationCount++;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let hasError = false;
|
|
286
|
+
|
|
287
|
+
const errorPathStats = new Set<OurPathErrorStats>();
|
|
288
|
+
|
|
289
|
+
const traceNodeStats = (node: Trace.INode, path: ResponseNamePath) => {
|
|
290
|
+
// Generate error stats and error path information
|
|
291
|
+
if (node.error?.length) {
|
|
292
|
+
hasError = true;
|
|
293
|
+
|
|
294
|
+
let currPathErrorStats = this.queryLatencyStats.rootErrorStats;
|
|
295
|
+
path.toArray().forEach((subPath) => {
|
|
296
|
+
currPathErrorStats = currPathErrorStats.getChild(
|
|
297
|
+
subPath,
|
|
298
|
+
sizeEstimator,
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
errorPathStats.add(currPathErrorStats);
|
|
303
|
+
currPathErrorStats.errorsCount += node.error.length;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (fieldExecutionWeight) {
|
|
307
|
+
// The actual field name behind the node; originalFieldName is set
|
|
308
|
+
// if an alias was used, otherwise responseName. (This is falsey for
|
|
309
|
+
// nodes that are not fields (root, array index, etc).)
|
|
310
|
+
const fieldName = node.originalFieldName || node.responseName;
|
|
311
|
+
|
|
312
|
+
// Protobuf doesn't really differentiate between "unset" and "falsey" so
|
|
313
|
+
// we're mostly actually checking that these things are non-empty string /
|
|
314
|
+
// non-zero numbers. The time fields represent the number of nanoseconds
|
|
315
|
+
// since the beginning of the entire trace, so let's pretend for the
|
|
316
|
+
// moment that it's plausible for a node to start or even end exactly when
|
|
317
|
+
// the trace started (ie, for the time values to be 0). This is unlikely
|
|
318
|
+
// in practice (everything should take at least 1ns). In practice we only
|
|
319
|
+
// write `type` and `parentType` on a Node when we write `startTime`, so
|
|
320
|
+
// the main thing we're looking out for by checking the time values is
|
|
321
|
+
// whether we somehow failed to write `endTime` at the end of the field;
|
|
322
|
+
// in this case, the `endTime >= startTime` check won't match.
|
|
323
|
+
if (
|
|
324
|
+
node.parentType &&
|
|
325
|
+
fieldName &&
|
|
326
|
+
node.type &&
|
|
327
|
+
node.endTime != null &&
|
|
328
|
+
node.startTime != null &&
|
|
329
|
+
node.endTime >= node.startTime
|
|
330
|
+
) {
|
|
331
|
+
const typeStat = this.getTypeStat(node.parentType, sizeEstimator);
|
|
332
|
+
|
|
333
|
+
const fieldStat = typeStat.getFieldStat(
|
|
334
|
+
fieldName,
|
|
335
|
+
node.type,
|
|
336
|
+
sizeEstimator,
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
fieldStat.errorsCount += node.error?.length ?? 0;
|
|
340
|
+
fieldStat.observedExecutionCount++;
|
|
341
|
+
fieldStat.estimatedExecutionCount += fieldExecutionWeight;
|
|
342
|
+
// Note: this is actually counting the number of resolver calls for this
|
|
343
|
+
// field that had at least one error, not the number of overall GraphQL
|
|
344
|
+
// queries that had at least one error for this field. That doesn't seem
|
|
345
|
+
// to match the name, but it does match the other implementations of this
|
|
346
|
+
// logic.
|
|
347
|
+
fieldStat.requestsWithErrorsCount +=
|
|
348
|
+
(node.error?.length ?? 0) > 0 ? 1 : 0;
|
|
349
|
+
fieldStat.latencyCount.incrementDuration(
|
|
350
|
+
node.endTime - node.startTime,
|
|
351
|
+
// The latency histogram is always "estimated"; we don't track
|
|
352
|
+
// "observed" and "estimated" separately.
|
|
353
|
+
fieldExecutionWeight,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return false;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
iterateOverTrace(trace, traceNodeStats, true);
|
|
362
|
+
|
|
363
|
+
// iterate over nonFtv1ErrorPaths, using some bits from traceNodeStats function
|
|
364
|
+
for (const { subgraph, path } of nonFtv1ErrorPaths) {
|
|
365
|
+
hasError = true;
|
|
366
|
+
if (path) {
|
|
367
|
+
let currPathErrorStats = this.queryLatencyStats.rootErrorStats.getChild(
|
|
368
|
+
`service:${subgraph}`,
|
|
369
|
+
sizeEstimator,
|
|
370
|
+
);
|
|
371
|
+
path.forEach((subPath) => {
|
|
372
|
+
if (typeof subPath === 'string') {
|
|
373
|
+
currPathErrorStats = currPathErrorStats.getChild(
|
|
374
|
+
subPath,
|
|
375
|
+
sizeEstimator,
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
errorPathStats.add(currPathErrorStats);
|
|
381
|
+
currPathErrorStats.errorsCount += 1;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for (const errorPath of errorPathStats) {
|
|
386
|
+
errorPath.requestsWithErrorsCount += 1;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (hasError) {
|
|
390
|
+
this.queryLatencyStats.requestsWithErrorsCount++;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
getTypeStat(parentType: string, sizeEstimator: SizeEstimator): OurTypeStat {
|
|
395
|
+
const existing = this.perTypeStat[parentType];
|
|
396
|
+
if (existing) {
|
|
397
|
+
return existing;
|
|
398
|
+
}
|
|
399
|
+
sizeEstimator.bytes += estimatedBytesForString(parentType);
|
|
400
|
+
const typeStat = new OurTypeStat();
|
|
401
|
+
this.perTypeStat[parentType] = typeStat;
|
|
402
|
+
return typeStat;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
class OurQueryLatencyStats implements Required<IQueryLatencyStats> {
|
|
407
|
+
latencyCount: DurationHistogram = new DurationHistogram();
|
|
408
|
+
requestCount = 0;
|
|
409
|
+
requestsWithoutFieldInstrumentation = 0;
|
|
410
|
+
cacheHits = 0;
|
|
411
|
+
persistedQueryHits = 0;
|
|
412
|
+
persistedQueryMisses = 0;
|
|
413
|
+
cacheLatencyCount: DurationHistogram = new DurationHistogram();
|
|
414
|
+
rootErrorStats: OurPathErrorStats = new OurPathErrorStats();
|
|
415
|
+
requestsWithErrorsCount = 0;
|
|
416
|
+
publicCacheTtlCount: DurationHistogram = new DurationHistogram();
|
|
417
|
+
privateCacheTtlCount: DurationHistogram = new DurationHistogram();
|
|
418
|
+
registeredOperationCount = 0;
|
|
419
|
+
forbiddenOperationCount = 0;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
class OurPathErrorStats implements Required<IPathErrorStats> {
|
|
423
|
+
children: { [k: string]: OurPathErrorStats } = Object.create(null);
|
|
424
|
+
errorsCount = 0;
|
|
425
|
+
requestsWithErrorsCount = 0;
|
|
426
|
+
|
|
427
|
+
getChild(subPath: string, sizeEstimator: SizeEstimator): OurPathErrorStats {
|
|
428
|
+
const existing = this.children[subPath];
|
|
429
|
+
if (existing) {
|
|
430
|
+
return existing;
|
|
431
|
+
}
|
|
432
|
+
const child = new OurPathErrorStats();
|
|
433
|
+
this.children[subPath] = child;
|
|
434
|
+
// Include a few bytes in the estimate for the numbers etc.
|
|
435
|
+
sizeEstimator.bytes += estimatedBytesForString(subPath) + 4;
|
|
436
|
+
return child;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
class OurTypeStat implements Required<ITypeStat> {
|
|
441
|
+
perFieldStat: { [k: string]: OurFieldStat } = Object.create(null);
|
|
442
|
+
|
|
443
|
+
getFieldStat(
|
|
444
|
+
fieldName: string,
|
|
445
|
+
returnType: string,
|
|
446
|
+
sizeEstimator: SizeEstimator,
|
|
447
|
+
): OurFieldStat {
|
|
448
|
+
const existing = this.perFieldStat[fieldName];
|
|
449
|
+
if (existing) {
|
|
450
|
+
return existing;
|
|
451
|
+
}
|
|
452
|
+
// Rough estimate of 10 bytes for the numbers in the FieldStat.
|
|
453
|
+
sizeEstimator.bytes +=
|
|
454
|
+
estimatedBytesForString(fieldName) +
|
|
455
|
+
estimatedBytesForString(returnType) +
|
|
456
|
+
10;
|
|
457
|
+
const fieldStat = new OurFieldStat(returnType);
|
|
458
|
+
this.perFieldStat[fieldName] = fieldStat;
|
|
459
|
+
return fieldStat;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
ensureCountsAreIntegers() {
|
|
463
|
+
for (const fieldStat of Object.values(this.perFieldStat)) {
|
|
464
|
+
fieldStat.ensureCountsAreIntegers();
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
class OurFieldStat implements Required<IFieldStat> {
|
|
470
|
+
errorsCount = 0;
|
|
471
|
+
observedExecutionCount = 0;
|
|
472
|
+
// Note that this number isn't necessarily an integer while it is being
|
|
473
|
+
// aggregated. Before encoding as a protobuf we call ensureCountsAreIntegers
|
|
474
|
+
// which floors it.
|
|
475
|
+
estimatedExecutionCount = 0;
|
|
476
|
+
requestsWithErrorsCount = 0;
|
|
477
|
+
latencyCount: DurationHistogram = new DurationHistogram();
|
|
478
|
+
|
|
479
|
+
constructor(readonly returnType: string) {}
|
|
480
|
+
|
|
481
|
+
ensureCountsAreIntegers() {
|
|
482
|
+
// This is the only one that ever can receive non-integers.
|
|
483
|
+
this.estimatedExecutionCount = Math.floor(this.estimatedExecutionCount);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function estimatedBytesForString(s: string) {
|
|
488
|
+
// 2 is for the tag (field ID + wire type) plus the encoded length. (The
|
|
489
|
+
// encoded length takes up more than 1 byte for strings that are longer than
|
|
490
|
+
// 127 bytes, but this is an estimate.)
|
|
491
|
+
return 2 + Buffer.byteLength(s);
|
|
492
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Trace } from '@apollo/usage-reporting-protobuf';
|
|
2
|
+
import type { VariableValueOptions } from './options.js';
|
|
3
|
+
|
|
4
|
+
// Creates trace details from request variables, given a specification for modifying
|
|
5
|
+
// values of private or sensitive variables.
|
|
6
|
+
// The details will include all variable names and their (possibly hidden or modified) values.
|
|
7
|
+
// If sendVariableValues is {all: bool}, {none: bool} or {exceptNames: Array}, the option will act similarly to
|
|
8
|
+
// to the to-be-deprecated options.privateVariables, except that the redacted variable
|
|
9
|
+
// names will still be visible in the UI even if the values are hidden.
|
|
10
|
+
// If sendVariableValues is null or undefined, we default to the {none: true} case.
|
|
11
|
+
export function makeTraceDetails(
|
|
12
|
+
variables: Record<string, any>,
|
|
13
|
+
sendVariableValues?: VariableValueOptions,
|
|
14
|
+
operationString?: string,
|
|
15
|
+
): Trace.Details {
|
|
16
|
+
const details = new Trace.Details();
|
|
17
|
+
const variablesToRecord = (() => {
|
|
18
|
+
if (sendVariableValues && 'transform' in sendVariableValues) {
|
|
19
|
+
const originalKeys = Object.keys(variables);
|
|
20
|
+
try {
|
|
21
|
+
// Custom function to allow user to specify what variablesJson will look like
|
|
22
|
+
const modifiedVariables = sendVariableValues.transform({
|
|
23
|
+
variables: variables,
|
|
24
|
+
operationString: operationString,
|
|
25
|
+
});
|
|
26
|
+
return cleanModifiedVariables(originalKeys, modifiedVariables);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
// If the custom function provided by the user throws an exception,
|
|
29
|
+
// change all the variable values to an appropriate error message.
|
|
30
|
+
return handleVariableValueTransformError(originalKeys);
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
return variables;
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
36
|
+
|
|
37
|
+
// Note: we explicitly do *not* include the details.rawQuery field. The
|
|
38
|
+
// Studio web app currently does nothing with this other than store it in
|
|
39
|
+
// the database and offer it up via its GraphQL API, and sending it means
|
|
40
|
+
// that using calculateSignature to hide sensitive data in the query
|
|
41
|
+
// string is ineffective.
|
|
42
|
+
Object.keys(variablesToRecord).forEach((name) => {
|
|
43
|
+
if (
|
|
44
|
+
!sendVariableValues ||
|
|
45
|
+
('none' in sendVariableValues && sendVariableValues.none) ||
|
|
46
|
+
('all' in sendVariableValues && !sendVariableValues.all) ||
|
|
47
|
+
('exceptNames' in sendVariableValues &&
|
|
48
|
+
// We assume that most users will have only a few variables values to hide,
|
|
49
|
+
// or will just set {none: true}; we can change this
|
|
50
|
+
// linear-time operation if it causes real performance issues.
|
|
51
|
+
sendVariableValues.exceptNames.includes(name)) ||
|
|
52
|
+
('onlyNames' in sendVariableValues &&
|
|
53
|
+
!sendVariableValues.onlyNames.includes(name))
|
|
54
|
+
) {
|
|
55
|
+
// Special case for private variables. Note that this is a different
|
|
56
|
+
// representation from a variable containing the empty string, as that
|
|
57
|
+
// will be sent as '""'.
|
|
58
|
+
details.variablesJson![name] = '';
|
|
59
|
+
} else {
|
|
60
|
+
try {
|
|
61
|
+
details.variablesJson![name] =
|
|
62
|
+
typeof variablesToRecord[name] === 'undefined'
|
|
63
|
+
? ''
|
|
64
|
+
: JSON.stringify(variablesToRecord[name]);
|
|
65
|
+
} catch (e) {
|
|
66
|
+
details.variablesJson![name] = JSON.stringify(
|
|
67
|
+
'[Unable to convert value to JSON]',
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return details;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function handleVariableValueTransformError(
|
|
76
|
+
variableNames: string[],
|
|
77
|
+
): Record<string, any> {
|
|
78
|
+
const modifiedVariables = Object.create(null);
|
|
79
|
+
variableNames.forEach((name) => {
|
|
80
|
+
modifiedVariables[name] = '[PREDICATE_FUNCTION_ERROR]';
|
|
81
|
+
});
|
|
82
|
+
return modifiedVariables;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Helper for makeTraceDetails() to enforce that the keys of a modified 'variables'
|
|
86
|
+
// matches that of the original 'variables'
|
|
87
|
+
function cleanModifiedVariables(
|
|
88
|
+
originalKeys: Array<string>,
|
|
89
|
+
modifiedVariables: Record<string, any>,
|
|
90
|
+
): Record<string, any> {
|
|
91
|
+
const cleanedVariables: Record<string, any> = Object.create(null);
|
|
92
|
+
originalKeys.forEach((name) => {
|
|
93
|
+
cleanedVariables[name] = modifiedVariables[name];
|
|
94
|
+
});
|
|
95
|
+
return cleanedVariables;
|
|
96
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import MIMEType from 'whatwg-mimetype';
|
|
2
|
+
import { BadRequestError } from './internalErrorClasses.js';
|
|
3
|
+
import type { HeaderMap } from './utils/HeaderMap.js';
|
|
4
|
+
|
|
5
|
+
// Our recommended set of CSRF prevention headers. Operations that do not
|
|
6
|
+
// provide a content-type such as `application/json` (in practice, this
|
|
7
|
+
// means GET operations) must include at least one of these headers.
|
|
8
|
+
// Apollo Client Web's default behavior is to always sends a
|
|
9
|
+
// `content-type` even for `GET`, and Apollo iOS and Apollo Kotlin always
|
|
10
|
+
// send `x-apollo-operation-name`. So if you set
|
|
11
|
+
// `csrfPreventionRequestHeaders: true` then any `GET` operation from these
|
|
12
|
+
// three client projects and any `POST` operation at all should work
|
|
13
|
+
// successfully; if you need `GET`s from another kind of client to work,
|
|
14
|
+
// just add `apollo-require-preflight: true` to their requests.
|
|
15
|
+
export const recommendedCsrfPreventionRequestHeaders = [
|
|
16
|
+
'x-apollo-operation-name',
|
|
17
|
+
'apollo-require-preflight',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
// See https://fetch.spec.whatwg.org/#cors-safelisted-request-header
|
|
21
|
+
const NON_PREFLIGHTED_CONTENT_TYPES = [
|
|
22
|
+
'application/x-www-form-urlencoded',
|
|
23
|
+
'multipart/form-data',
|
|
24
|
+
'text/plain',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// We don't want random websites to be able to execute actual GraphQL operations
|
|
28
|
+
// from a user's browser unless our CORS policy supports it. It's not good
|
|
29
|
+
// enough just to ensure that the browser can't read the response from the
|
|
30
|
+
// operation; we also want to prevent CSRF, where the attacker can cause side
|
|
31
|
+
// effects with an operation or can measure the timing of a read operation. Our
|
|
32
|
+
// goal is to ensure that we don't run the context function or execute the
|
|
33
|
+
// GraphQL operation until the browser has evaluated the CORS policy, which
|
|
34
|
+
// means we want all operations to be pre-flighted. We can do that by only
|
|
35
|
+
// processing operations that have at least one header set that appears to be
|
|
36
|
+
// manually set by the JS code rather than by the browser automatically.
|
|
37
|
+
//
|
|
38
|
+
// POST requests generally have a content-type `application/json`, which is
|
|
39
|
+
// sufficient to trigger preflighting. So we take extra care with requests that
|
|
40
|
+
// specify no content-type or that specify one of the three non-preflighted
|
|
41
|
+
// content types. For those operations, we require (if this feature is enabled)
|
|
42
|
+
// one of a set of specific headers to be set. By ensuring that every operation
|
|
43
|
+
// either has a custom content-type or sets one of these headers, we know we
|
|
44
|
+
// won't execute operations at the request of origins who our CORS policy will
|
|
45
|
+
// block.
|
|
46
|
+
export function preventCsrf(
|
|
47
|
+
headers: HeaderMap,
|
|
48
|
+
csrfPreventionRequestHeaders: string[],
|
|
49
|
+
) {
|
|
50
|
+
const contentType = headers.get('content-type');
|
|
51
|
+
|
|
52
|
+
// We have to worry about CSRF if it looks like this may have been a
|
|
53
|
+
// non-preflighted request. If we see a content-type header that is not one of
|
|
54
|
+
// the three CORS-safelisted MIME types (see
|
|
55
|
+
// https://fetch.spec.whatwg.org/#cors-safelisted-request-header) then we know
|
|
56
|
+
// it was preflighted and we don't have to worry.
|
|
57
|
+
if (contentType !== undefined) {
|
|
58
|
+
const contentTypeParsed = MIMEType.parse(contentType);
|
|
59
|
+
if (contentTypeParsed === null) {
|
|
60
|
+
// If we got null, then parsing the content-type failed... which is
|
|
61
|
+
// actually *ok* because that would lead to a preflight. (For example, the
|
|
62
|
+
// header is empty, or doesn't have a slash, or has bad characters.) The
|
|
63
|
+
// scary CSRF case is only if there's *not* an error. So it is actually
|
|
64
|
+
// fine for us to just `return` here. (That said, it would also be
|
|
65
|
+
// reasonable to reject such requests with provided yet unparsable
|
|
66
|
+
// Content-Type here.)
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!NON_PREFLIGHTED_CONTENT_TYPES.includes(contentTypeParsed.essence)) {
|
|
70
|
+
// We managed to parse a MIME type that was not one of the
|
|
71
|
+
// CORS-safelisted ones. (Probably application/json!) That means that if
|
|
72
|
+
// the client is a browser, the browser must have applied CORS
|
|
73
|
+
// preflighting and we don't have to worry about CSRF.
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Either there was no content-type, or the content-type parsed properly as
|
|
79
|
+
// one of the three CORS-safelisted values. Let's look for another header that
|
|
80
|
+
// (if this was a browser) must have been set by the user's code and would
|
|
81
|
+
// have caused a preflight.
|
|
82
|
+
if (
|
|
83
|
+
csrfPreventionRequestHeaders.some((header) => {
|
|
84
|
+
const value = headers.get(header);
|
|
85
|
+
return value !== undefined && value.length > 0;
|
|
86
|
+
})
|
|
87
|
+
) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
throw new BadRequestError(
|
|
92
|
+
`This operation has been blocked as a potential Cross-Site Request Forgery ` +
|
|
93
|
+
`(CSRF). Please either specify a 'content-type' header (with a type that ` +
|
|
94
|
+
`is not one of ${NON_PREFLIGHTED_CONTENT_TYPES.join(', ')}) or provide ` +
|
|
95
|
+
`a non-empty value for one of the following headers: ${csrfPreventionRequestHeaders.join(
|
|
96
|
+
', ',
|
|
97
|
+
)}\n`,
|
|
98
|
+
);
|
|
99
|
+
}
|