` block
*/
template: SfcBlock | null;
/**
* The common `
`,
env,
);
console.log(env.sfcBlocks);
```
## Options
### customBlocks
- Type: `string[]`
- Default: `[]`
- Details:
SFC custom blocks to be extracted.
By default, only `
`;
};
function ApolloServerPluginLandingPageDefault(maybeVersion, config) {
const version = maybeVersion ?? '_latest';
return {
__internal_installed_implicitly__: false,
async serverWillStart() {
return {
async renderLandingPage() {
const html = `
Apollo Server
${config.embed
? 'graphRef' in config && config.graphRef
? (0, getEmbeddedHTML_js_1.getEmbeddedExplorerHTML)(version, config)
: (0, getEmbeddedHTML_js_1.getEmbeddedSandboxHTML)(version, config)
: getNonEmbeddedLandingPageHTML(version, config)}
`;
return { html };
},
};
},
};
}
//# sourceMappingURL=index.js.map(/dist/cjs/plugin/usageReporting/stats.js*"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OurContextualizedStats = exports.OurReport = exports.SizeEstimator = void 0;
const usage_reporting_protobuf_1 = require("@apollo/usage-reporting-protobuf");
const durationHistogram_js_1 = require("./durationHistogram.js");
const iterateOverTrace_js_1 = require("./iterateOverTrace.js");
class SizeEstimator {
constructor() {
this.bytes = 0;
}
}
exports.SizeEstimator = SizeEstimator;
class OurReport {
constructor(header) {
this.header = header;
this.tracesPerQuery = Object.create(null);
this.endTime = null;
this.operationCount = 0;
this.sizeEstimator = new SizeEstimator();
}
ensureCountsAreIntegers() {
for (const tracesAndStats of Object.values(this.tracesPerQuery)) {
tracesAndStats.ensureCountsAreIntegers();
}
}
addTrace({ statsReportKey, trace, asTrace, referencedFieldsByType, maxTraceBytes = 10 * 1024 * 1024, }) {
const tracesAndStats = this.getTracesAndStats({
statsReportKey,
referencedFieldsByType,
});
if (asTrace) {
const encodedTrace = usage_reporting_protobuf_1.Trace.encode(trace).finish();
if (!isNaN(maxTraceBytes) && encodedTrace.length > maxTraceBytes) {
tracesAndStats.statsWithContext.addTrace(trace, this.sizeEstimator);
}
else {
tracesAndStats.trace.push(encodedTrace);
this.sizeEstimator.bytes += 2 + encodedTrace.length;
}
}
else {
tracesAndStats.statsWithContext.addTrace(trace, this.sizeEstimator);
}
}
getTracesAndStats({ statsReportKey, referencedFieldsByType, }) {
const existing = this.tracesPerQuery[statsReportKey];
if (existing) {
return existing;
}
this.sizeEstimator.bytes += estimatedBytesForString(statsReportKey);
for (const [typeName, referencedFieldsForType] of Object.entries(referencedFieldsByType)) {
this.sizeEstimator.bytes += 2 + 2;
if (referencedFieldsForType.isInterface) {
this.sizeEstimator.bytes += 2;
}
this.sizeEstimator.bytes += estimatedBytesForString(typeName);
for (const fieldName of referencedFieldsForType.fieldNames) {
this.sizeEstimator.bytes += estimatedBytesForString(fieldName);
}
}
return (this.tracesPerQuery[statsReportKey] = new OurTracesAndStats(referencedFieldsByType));
}
}
exports.OurReport = OurReport;
class OurTracesAndStats {
constructor(referencedFieldsByType) {
this.referencedFieldsByType = referencedFieldsByType;
this.trace = [];
this.statsWithContext = new StatsByContext();
this.internalTracesContributingToStats = [];
}
ensureCountsAreIntegers() {
this.statsWithContext.ensureCountsAreIntegers();
}
}
class StatsByContext {
constructor() {
this.map = Object.create(null);
}
toArray() {
return Object.values(this.map);
}
ensureCountsAreIntegers() {
for (const contextualizedStats of Object.values(this.map)) {
contextualizedStats.ensureCountsAreIntegers();
}
}
addTrace(trace, sizeEstimator) {
this.getContextualizedStats(trace, sizeEstimator).addTrace(trace, sizeEstimator);
}
getContextualizedStats(trace, sizeEstimator) {
const statsContext = {
clientName: trace.clientName,
clientVersion: trace.clientVersion,
};
const statsContextKey = JSON.stringify(statsContext);
const existing = this.map[statsContextKey];
if (existing) {
return existing;
}
sizeEstimator.bytes +=
20 +
estimatedBytesForString(trace.clientName) +
estimatedBytesForString(trace.clientVersion);
const contextualizedStats = new OurContextualizedStats(statsContext);
this.map[statsContextKey] = contextualizedStats;
return contextualizedStats;
}
}
class OurContextualizedStats {
constructor(context) {
this.context = context;
this.queryLatencyStats = new OurQueryLatencyStats();
this.perTypeStat = Object.create(null);
}
ensureCountsAreIntegers() {
for (const typeStat of Object.values(this.perTypeStat)) {
typeStat.ensureCountsAreIntegers();
}
}
addTrace(trace, sizeEstimator) {
const { fieldExecutionWeight } = trace;
if (!fieldExecutionWeight) {
this.queryLatencyStats.requestsWithoutFieldInstrumentation++;
}
this.queryLatencyStats.requestCount++;
if (trace.fullQueryCacheHit) {
this.queryLatencyStats.cacheLatencyCount.incrementDuration(trace.durationNs);
this.queryLatencyStats.cacheHits++;
}
else {
this.queryLatencyStats.latencyCount.incrementDuration(trace.durationNs);
}
if (!trace.fullQueryCacheHit && trace.cachePolicy?.maxAgeNs != null) {
switch (trace.cachePolicy.scope) {
case usage_reporting_protobuf_1.Trace.CachePolicy.Scope.PRIVATE:
this.queryLatencyStats.privateCacheTtlCount.incrementDuration(trace.cachePolicy.maxAgeNs);
break;
case usage_reporting_protobuf_1.Trace.CachePolicy.Scope.PUBLIC:
this.queryLatencyStats.publicCacheTtlCount.incrementDuration(trace.cachePolicy.maxAgeNs);
break;
}
}
if (trace.persistedQueryHit) {
this.queryLatencyStats.persistedQueryHits++;
}
if (trace.persistedQueryRegister) {
this.queryLatencyStats.persistedQueryMisses++;
}
if (trace.forbiddenOperation) {
this.queryLatencyStats.forbiddenOperationCount++;
}
if (trace.registeredOperation) {
this.queryLatencyStats.registeredOperationCount++;
}
let hasError = false;
const traceNodeStats = (node, path) => {
if (node.error?.length) {
hasError = true;
let currPathErrorStats = this.queryLatencyStats.rootErrorStats;
path.toArray().forEach((subPath) => {
currPathErrorStats = currPathErrorStats.getChild(subPath, sizeEstimator);
});
currPathErrorStats.requestsWithErrorsCount += 1;
currPathErrorStats.errorsCount += node.error.length;
}
if (fieldExecutionWeight) {
const fieldName = node.originalFieldName || node.responseName;
if (node.parentType &&
fieldName &&
node.type &&
node.endTime != null &&
node.startTime != null &&
node.endTime >= node.startTime) {
const typeStat = this.getTypeStat(node.parentType, sizeEstimator);
const fieldStat = typeStat.getFieldStat(fieldName, node.type, sizeEstimator);
fieldStat.errorsCount += node.error?.length ?? 0;
fieldStat.observedExecutionCount++;
fieldStat.estimatedExecutionCount += fieldExecutionWeight;
fieldStat.requestsWithErrorsCount +=
(node.error?.length ?? 0) > 0 ? 1 : 0;
fieldStat.latencyCount.incrementDuration(node.endTime - node.startTime, fieldExecutionWeight);
}
}
return false;
};
(0, iterateOverTrace_js_1.iterateOverTrace)(trace, traceNodeStats, true);
if (hasError) {
this.queryLatencyStats.requestsWithErrorsCount++;
}
}
getTypeStat(parentType, sizeEstimator) {
const existing = this.perTypeStat[parentType];
if (existing) {
return existing;
}
sizeEstimator.bytes += estimatedBytesForString(parentType);
const typeStat = new OurTypeStat();
this.perTypeStat[parentType] = typeStat;
return typeStat;
}
}
exports.OurContextualizedStats = OurContextualizedStats;
class OurQueryLatencyStats {
constructor() {
this.latencyCount = new durationHistogram_js_1.DurationHistogram();
this.requestCount = 0;
this.requestsWithoutFieldInstrumentation = 0;
this.cacheHits = 0;
this.persistedQueryHits = 0;
this.persistedQueryMisses = 0;
this.cacheLatencyCount = new durationHistogram_js_1.DurationHistogram();
this.rootErrorStats = new OurPathErrorStats();
this.requestsWithErrorsCount = 0;
this.publicCacheTtlCount = new durationHistogram_js_1.DurationHistogram();
this.privateCacheTtlCount = new durationHistogram_js_1.DurationHistogram();
this.registeredOperationCount = 0;
this.forbiddenOperationCount = 0;
}
}
class OurPathErrorStats {
constructor() {
this.children = Object.create(null);
this.errorsCount = 0;
this.requestsWithErrorsCount = 0;
}
getChild(subPath, sizeEstimator) {
const existing = this.children[subPath];
if (existing) {
return existing;
}
const child = new OurPathErrorStats();
this.children[subPath] = child;
sizeEstimator.bytes += estimatedBytesForString(subPath) + 4;
return child;
}
}
class OurTypeStat {
constructor() {
this.perFieldStat = Object.create(null);
}
getFieldStat(fieldName, returnType, sizeEstimator) {
const existing = this.perFieldStat[fieldName];
if (existing) {
return existing;
}
sizeEstimator.bytes +=
estimatedBytesForString(fieldName) +
estimatedBytesForString(returnType) +
10;
const fieldStat = new OurFieldStat(returnType);
this.perFieldStat[fieldName] = fieldStat;
return fieldStat;
}
ensureCountsAreIntegers() {
for (const fieldStat of Object.values(this.perFieldStat)) {
fieldStat.ensureCountsAreIntegers();
}
}
}
class OurFieldStat {
constructor(returnType) {
this.returnType = returnType;
this.errorsCount = 0;
this.observedExecutionCount = 0;
this.estimatedExecutionCount = 0;
this.requestsWithErrorsCount = 0;
this.latencyCount = new durationHistogram_js_1.DurationHistogram();
}
ensureCountsAreIntegers() {
this.estimatedExecutionCount = Math.floor(this.estimatedExecutionCount);
}
}
function estimatedBytesForString(s) {
return 2 + Buffer.byteLength(s);
}
//# sourceMappingURL=stats.js.map/dist/esm/errors/index.js import { GraphQLError } from 'graphql';
export var ApolloServerErrorCode;
(function (ApolloServerErrorCode) {
ApolloServerErrorCode["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
ApolloServerErrorCode["GRAPHQL_PARSE_FAILED"] = "GRAPHQL_PARSE_FAILED";
ApolloServerErrorCode["GRAPHQL_VALIDATION_FAILED"] = "GRAPHQL_VALIDATION_FAILED";
ApolloServerErrorCode["PERSISTED_QUERY_NOT_FOUND"] = "PERSISTED_QUERY_NOT_FOUND";
ApolloServerErrorCode["PERSISTED_QUERY_NOT_SUPPORTED"] = "PERSISTED_QUERY_NOT_SUPPORTED";
ApolloServerErrorCode["BAD_USER_INPUT"] = "BAD_USER_INPUT";
ApolloServerErrorCode["OPERATION_RESOLUTION_FAILURE"] = "OPERATION_RESOLUTION_FAILURE";
ApolloServerErrorCode["BAD_REQUEST"] = "BAD_REQUEST";
})(ApolloServerErrorCode || (ApolloServerErrorCode = {}));
export var ApolloServerValidationErrorCode;
(function (ApolloServerValidationErrorCode) {
ApolloServerValidationErrorCode["INTROSPECTION_DISABLED"] = "INTROSPECTION_DISABLED";
})(ApolloServerValidationErrorCode || (ApolloServerValidationErrorCode = {}));
export function unwrapResolverError(error) {
if (error instanceof GraphQLError && error.path && error.originalError) {
return error.originalError;
}
return error;
}
//# sourceMappingURL=index.js.map&/dist/esm/externalTypes/context.js.map~{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/externalTypes/context.ts"],"names":[],"mappings":""}/dist/esm/utils/HeaderMap.jshexport class HeaderMap extends Map {
set(key, value) {
return super.set(key.toLowerCase(), value);
}
get(key) {
return super.get(key.toLowerCase());
}
delete(key) {
return super.delete(key.toLowerCase());
}
has(key) {
return super.has(key.toLowerCase());
}
}
//# sourceMappingURL=HeaderMap.js.map$/dist/esm/determineApolloConfig.d.tsimport type { ApolloConfig, ApolloConfigInput } from './externalTypes/index.js';
export declare function determineApolloConfig(input: ApolloConfigInput | undefined): ApolloConfig;
//# sourceMappingURL=determineApolloConfig.d.ts.map%/src/externalTypes/requestPipeline.tsV// This file defines the GraphQLRequestContext type which is an argument to most
// plugin hooks, as well as a variety of variants on it which assert that
// particular sub-fields are set by a particular point in the request pipeline.
import type { WithRequired } from '@apollo/utils.withrequired';
import type { Trace } from '@apollo/usage-reporting-protobuf';
import type { BaseContext } from './context.js';
import type {
GraphQLInProgressResponse,
GraphQLRequest,
GraphQLResponse,
} from './graphql.js';
import type { Logger } from '@apollo/utils.logger';
import type { KeyValueCache } from '@apollo/utils.keyvaluecache';
import type {
DocumentNode,
GraphQLError,
GraphQLSchema,
OperationDefinitionNode,
} from 'graphql';
import type { CachePolicy } from '@apollo/cache-control-types';
export interface GraphQLRequestMetrics {
// It would be more accurate to call this fieldLevelInstrumentation (it is
// true if the hook of that name returns truthy) but for backwards
// compatibility we keep this name (this field is read by `@apollo/gateway` to
// decide whether or not to send the apollo-federation-include-trace header).
captureTraces?: boolean;
persistedQueryHit?: boolean;
persistedQueryRegister?: boolean;
responseCacheHit?: boolean;
forbiddenOperation?: boolean;
registeredOperation?: boolean;
startHrTime?: [number, number];
queryPlanTrace?: Trace.QueryPlanNode;
}
export interface GraphQLRequestContext {
readonly logger: Logger;
readonly cache: KeyValueCache;
readonly request: GraphQLRequest;
readonly response: GraphQLInProgressResponse;
readonly schema: GraphQLSchema;
readonly contextValue: TContext;
readonly queryHash?: string;
readonly document?: DocumentNode;
readonly source?: string;
// `operationName` is set based on the operation AST, so it is defined even if
// no `request.operationName` was passed in. It will be set to `null` for an
// anonymous operation, or if `requestName.operationName` was passed in but
// doesn't resolve to an operation in the document.
readonly operationName?: string | null;
readonly operation?: OperationDefinitionNode;
/**
* Unformatted errors which have occurred during the request. Note that these
* are present earlier in the request pipeline and differ from **formatted**
* errors which are the result of running the user-configurable `formatError`
* transformation function over specific errors; these can eventually be found
* in `response.result.errors`.
*/
readonly errors?: ReadonlyArray;
readonly metrics: GraphQLRequestMetrics;
readonly overallCachePolicy: CachePolicy;
/**
* True if this request is part of a potentially multi-operation batch. Note
* that if this is true, `response.http` will be shared with the other
* operations in the batch.
*/
readonly requestIsBatched: boolean;
}
export type GraphQLRequestContextDidResolveSource<
TContext extends BaseContext,
> = WithRequired, 'source' | 'queryHash'>;
export type GraphQLRequestContextParsingDidStart =
GraphQLRequestContextDidResolveSource;
export type GraphQLRequestContextValidationDidStart<
TContext extends BaseContext,
> = GraphQLRequestContextParsingDidStart &
WithRequired, 'document'>;
export type GraphQLRequestContextDidResolveOperation<
TContext extends BaseContext,
> = GraphQLRequestContextValidationDidStart &
WithRequired, 'operationName'>;
export type GraphQLRequestContextDidEncounterErrors<
TContext extends BaseContext,
> = WithRequired, 'errors'>;
export type GraphQLRequestContextResponseForOperation<
TContext extends BaseContext,
> = WithRequired<
GraphQLRequestContext,
'source' | 'document' | 'operation' | 'operationName'
>;
export type GraphQLRequestContextExecutionDidStart<
TContext extends BaseContext,
> = GraphQLRequestContextParsingDidStart &
WithRequired<
GraphQLRequestContext,
'document' | 'operation' | 'operationName'
>;
export type GraphQLRequestContextWillSendResponse<
TContext extends BaseContext,
> = GraphQLRequestContextDidResolveSource & {
readonly response: GraphQLResponse;
};
export type GraphQLRequestContextDidEncounterSubsequentErrors<
TContext extends BaseContext,
> = GraphQLRequestContextWillSendResponse;
export type GraphQLRequestContextWillSendSubsequentPayload<
TContext extends BaseContext,
> = GraphQLRequestContextWillSendResponse;
//dist/esm/plugin/landingPage/default/index.d.tsimport type { ApolloServerPlugin } from '../../../externalTypes/index.js';
import type { ApolloServerPluginLandingPageLocalDefaultOptions, ApolloServerPluginLandingPageProductionDefaultOptions } from './types.js';
export type { ApolloServerPluginLandingPageLocalDefaultOptions, ApolloServerPluginLandingPageProductionDefaultOptions, };
export declare function ApolloServerPluginLandingPageLocalDefault(options?: ApolloServerPluginLandingPageLocalDefaultOptions): ApolloServerPlugin;
export declare function ApolloServerPluginLandingPageProductionDefault(options?: ApolloServerPluginLandingPageProductionDefaultOptions): ApolloServerPlugin;
//# sourceMappingURL=index.d.ts.map,/dist/esm/plugin/usageReporting/options.d.ts import type { GraphQLError, DocumentNode } from 'graphql';
import type { GraphQLRequestContextDidResolveOperation, GraphQLRequestContext, GraphQLRequestContextWillSendResponse, BaseContext } from '../../externalTypes/index.js';
import type { Logger } from '@apollo/utils.logger';
import type { Trace } from '@apollo/usage-reporting-protobuf';
import type { Fetcher } from '@apollo/utils.fetcher';
export interface ApolloServerPluginUsageReportingOptions {
sendTraces?: boolean;
sendVariableValues?: VariableValueOptions;
sendHeaders?: SendValuesBaseOptions;
sendErrors?: SendErrorsOptions;
fieldLevelInstrumentation?: number | ((request: GraphQLRequestContextDidResolveOperation) => Promise);
includeRequest?: (request: GraphQLRequestContextDidResolveOperation | GraphQLRequestContextWillSendResponse) => Promise;
generateClientInfo?: GenerateClientInfo;
overrideReportedSchema?: string;
sendUnexecutableOperationDocuments?: boolean;
experimental_sendOperationAsTrace?: (trace: Trace, statsReportKey: string) => boolean;
sendReportsImmediately?: boolean;
fetcher?: Fetcher;
reportIntervalMs?: number;
maxUncompressedReportSize?: number;
maxAttempts?: number;
minimumRetryDelayMs?: number;
requestTimeoutMs?: number;
logger?: Logger;
reportErrorFunction?: (err: Error) => void;
endpointUrl?: string;
debugPrintReports?: boolean;
calculateSignature?: (ast: DocumentNode, operationName: string) => string;
}
export declare type SendValuesBaseOptions = {
onlyNames: Array;
} | {
exceptNames: Array;
} | {
all: true;
} | {
none: true;
};
declare type VariableValueTransformOptions = {
variables: Record;
operationString?: string;
};
export declare type VariableValueOptions = {
transform: (options: VariableValueTransformOptions) => Record;
} | SendValuesBaseOptions;
export declare type SendErrorsOptions = {
unmodified: true;
} | {
masked: true;
} | {
transform: (err: GraphQLError) => GraphQLError | null;
};
export interface ClientInfo {
clientName?: string;
clientVersion?: string;
}
export declare type GenerateClientInfo = (requestContext: GraphQLRequestContext) => ClientInfo;
export {};
//# sourceMappingURL=options.d.ts.map%/src/plugin/usageReporting/options.tsK import type { GraphQLError, DocumentNode } from 'graphql';
import type {
GraphQLRequestContextDidResolveOperation,
GraphQLRequestContext,
GraphQLRequestContextWillSendResponse,
BaseContext,
} from '../../externalTypes/index.js';
import type { Logger } from '@apollo/utils.logger';
import type { Trace } from '@apollo/usage-reporting-protobuf';
import type { Fetcher } from '@apollo/utils.fetcher';
export interface ApolloServerPluginUsageReportingOptions<
TContext extends BaseContext,
> {
//#region Configure exactly which data should be sent to Apollo.
/**
* Apollo Server's usage reports describe each individual request in one of
* two ways: as a "trace" (a detailed description of the specific request,
* including a query plan and resolver tree with timings and errors, as well
* as optional details like variable values and HTTP headers), or as part of
* aggregated "stats" (where invocations of the same operation from the same
* client program are aggregated together rather than described individually).
* Apollo Server uses an heuristic to decide which operations to describe as
* traces and which to aggregate as stats.
*
* By setting the `sendTraces` option to `false`, Apollo Server will describe
* *all* operations as stats; individual requests will never be broken out
* into separate traces. If you set `sendTraces: false`, then Apollo Studio's
* Traces view won't show any traces (other Studio functionality will be
* unaffected).
*
* Note that the values of `sendVariableValues`, `sendHeaders`, and
* `sendUnexecutableOperationDocuments` are irrelevant if you set
* `sendTraces: false`, because those options control data that is contained
* only in traces (not in stats).
*
* Setting `sendTraces: false` does *NOT* imply `fieldLevelInstrumentation:
* 0`. Apollo Server can still take advantage of field-level instrumentation
* (either directly for monolith servers, or via federated tracing for
* Gateways) in order to accurately report field execution usage in "stats".
* This option only controls whether data is sent to Apollo's servers as
* traces, not whether traces are internally used to learn about usage.
*/
sendTraces?: boolean;
/**
* By default, Apollo Server does not send the values of any GraphQL variables
* to Apollo's servers, because variable values often contain the private data
* of your app's users. If you'd like variable values to be included in
* traces, set this option. This option can take several forms:
* - { none: true }: don't send any variable values (DEFAULT)
* - { all: true}: send all variable values
* - { transform: ... }: a custom function for modifying variable values. The
* function receives `variables` and `operationString` and should return a
* record of `variables` with the same keys as the `variables` it receives
* (added variables will be ignored and removed variables will be reported
* with an empty value). For security reasons, if an error occurs within
* this function, all variable values will be replaced with
* `[PREDICATE_FUNCTION_ERROR]`.
* - { exceptNames: ... }: a case-sensitive list of names of variables whose
* values should not be sent to Apollo servers
* - { onlyNames: ... }: A case-sensitive list of names of variables whose
* values will be sent to Apollo servers
*
* Defaults to not sending any variable values if both this parameter and the
* deprecated `privateVariables` are not set. The report will indicate each
* private variable key whose value was redacted by { none: true } or {
* exceptNames: [...] }.
*
* The value of this option is not relevant if you set `sendTraces: false`,
* because variable values only appear in traces.
*/
sendVariableValues?: VariableValueOptions;
/**
* By default, Apollo Server does not send the HTTP request headers and values
* to Apollo's servers, as these headers may contain your users' private data.
* If you'd like this information included in traces, set this option. This
* option can take several forms:
*
* - { none: true } to drop all HTTP request headers (DEFAULT)
* - { all: true } to send the values of all HTTP request headers
* - { exceptNames: Array } A case-insensitive list of names of HTTP
* headers whose values should not be sent to Apollo servers
* - { onlyNames: Array }: A case-insensitive list of names of HTTP
* headers whose values will be sent to Apollo servers
*
* Unlike with sendVariableValues, names of dropped headers are not reported.
* The headers 'authorization', 'cookie', and 'set-cookie' are never reported.
*
* The value of this option is not relevant if you set `sendTraces: false`,
* because request headers only appear in traces.
*/
sendHeaders?: SendValuesBaseOptions;
/**
* By default, if a trace contains errors, the errors are reported to Apollo
* servers with the message ``. The errors are associated with
* specific paths in the operation, but do not include the original error
* message or any extensions such as the error `code`, as those details may
* contain your users' private data. The extension `maskedBy:
* 'ApolloServerPluginUsageReporting'` is added.
*
* If you'd like details about the error included in traces, set this option.
* This option can take several forms:
*
* - { masked: true }: mask error messages and omit extensions (DEFAULT)
* - { unmodified: true }: send all error messages and extensions to Apollo
* servers
* - { transform: ... }: a custom function for transforming errors. This
* function receives a `GraphQLError` and may return a `GraphQLError`
* (either a new error, or its potentially-modified argument) or `null`.
* This error is used in the report to Apollo servers; if `null`, the error
* is not included in traces or error statistics.
*
* If you set `sendTraces: false`, then the only relevant aspect of this
* option is whether you return `null` from a `transform` function or not
* (which affects aggregated error statistics).
*/
sendErrors?: SendErrorsOptions;
/**
* This option allows you to choose if Apollo Server should calculate detailed
* per-field statistics for a particular request. It is only called for
* executable operations: operations which parse and validate properly and
* which do not have an unknown operation name. It is not called if an
* `includeRequest` hook is provided and returns false.
*
* You can either pass an async function or a number. The function receives a
* `GraphQLRequestContext`. (The effect of passing a number is described
* later.) Your function can return a boolean or a number; returning false is
* equivalent to returning 0 and returning true is equivalent to returning 1.
*
* Returning false (or 0) means that Apollo Server will only pay attention to
* overall properties of the operation, like what GraphQL operation is
* executing and how long the entire operation takes to execute, and not
* anything about field-by-field execution.
*
* If you return false (or 0), this operation *will* still contribute to most
* features of Studio, such as schema checks, the Operations page, and the
* "referencing operations" statistic on the Fields page, etc.
*
* If you return false (or 0), this operation will *not* contribute to the
* "field executions" statistic on the Fields page or to the execution timing
* hints optionally displayed in Studio Explorer or in vscode-graphql.
* Additionally, this operation will not produce a trace that can be viewed on
* the Traces section of the Operations page.
*
* Returning false (or 0) for some or all operations can improve your server's
* performance, as the overhead of calculating complete traces is not always
* negligible. This is especially the case if this server is an Apollo
* Gateway, as captured traces are transmitted from the subgraph to the
* Gateway in-band inside the actual GraphQL response.
*
* Returning a positive number means that Apollo Server will track each field
* execution and send Apollo Studio statistics on how many times each field
* was executed and what the per-field performance was. Apollo Server sends
* both a precise observed execution count and an estimated execution count.
* The former is calculated by counting each field execution as 1, and the
* latter is calculated by counting each field execution as the number
* returned from this hook, which can be thought of as a weight.
*
* Passing a number `x` (which should be between 0 and 1 inclusive) for
* `fieldLevelInstrumentation` is equivalent to passing the function `async ()
* => Math.random() < x ? 1/x : 0`. For example, if you pass 0.01, then 99%
* of the time this function will return 0, and 1% of the time this function
* will return 100. So 99% of the time Apollo Server will not track field
* executions, and 1% of the time Apollo Server will track field executions
* and send them to Apollo Studio both as an exact observed count and as an
* "estimated" count which is 100 times higher. Generally, the weights you
* return should be roughly the reciprocal of the probability that the
* function returns non-zero; however, you're welcome to craft a more
* sophisticated function, such as one that uses a higher probability for
* rarer operations and a lower probability for more common operations.
*
* (Note that returning true here does *not* mean that the data derived from
* field-level instrumentation must be transmitted to Apollo Studio's servers
* in the form of a trace; it may still be aggregated locally to statistics.
* Similarly, setting `sendTraces: false` does not affect
* `fieldLevelInstrumentation`. But either way this operation will contribute
* to the "field executions" statistic and timing hints.)
*
* The default `fieldLevelInstrumentation` is a function that always returns
* true.
*/
fieldLevelInstrumentation?:
| number
| ((
request: GraphQLRequestContextDidResolveOperation,
) => Promise);
/**
* This option allows you to choose if a particular request should be
* represented in the usage reporting sent to Apollo servers. By default, all
* requests are included. If this async predicate function is specified, its
* return value will determine whether a given request is included.
*
* Note that returning false here means that the operation will be completely
* ignored by all Apollo Studio features. If you merely want to improve
* performance by skipping the field-level execution trace, set the
* `fieldLevelInstrumentation` option instead of this one.
*
* The predicate function receives the request context. If validation and
* parsing of the request succeeds, the function will receive the request
* context in the
* [`GraphQLRequestContextDidResolveOperation`](https://www.apollographql.com/docs/apollo-server/integrations/plugins/#didresolveoperation)
* phase, which permits tracing based on dynamic properties, e.g., HTTP
* headers or the `operationName` (when available). Otherwise it will receive
* the request context in the
* [`GraphQLRequestContextWillSendResponse`](https://www.apollographql.com/docs/apollo-server/integrations/plugins/#willsendresponse)
* phase:
*
* (If you don't want any usage reporting at all, don't use this option:
* instead, either avoid specifying an Apollo API key, or use
* ApolloServerPluginUsageReportingDisabled to prevent this plugin from being
* created by default.)
*
* **Example:**
*
* ```js
* includeRequest(requestContext) {
* // Always include `query HomeQuery { ... }`.
* if (requestContext.operationName === "HomeQuery") return true;
*
* // Omit if the "report-to-apollo" header is set to "false".
* if (requestContext.request.http?.headers?.get("report-to-apollo") === "false") {
* return false;
* }
*
* // Otherwise include.
* return true;
* },
* ```
*
*/
includeRequest?: (
request:
| GraphQLRequestContextDidResolveOperation
| GraphQLRequestContextWillSendResponse,
) => Promise;
/**
* By default, this plugin associates client information such as name
* and version with user requests based on HTTP headers starting with
* `apollographql-client-`. If you have another way of communicating
* client information to your server, tell the plugin how it works
* with this option.
*/
generateClientInfo?: GenerateClientInfo;
/**
* If you are using the `overrideReportedSchema` option to the schema
* reporting plugin (`ApolloServerPluginSchemaReporting`), you should
* pass the same value here as well, so that the schema ID associated
* with requests in this plugin's usage reports matches the schema
* ID that the other plugin reports.
*/
overrideReportedSchema?: string;
/**
* Whether to include the entire document in the trace if the operation
* was a GraphQL parse or validation error (i.e. failed the GraphQL parse or
* validation phases). This will be included as a separate field on the trace
* and the operation name and signature will always be reported with a constant
* identifier. Whether the operation was a parse failure or a validation
* failure will be embedded within the stats report key itself.
*
* The value of this option is not relevant if you set `sendTraces: false`,
* because unexecutable operation documents only appear in traces.
*/
sendUnexecutableOperationDocuments?: boolean;
/**
* This plugin sends information about operations to Apollo's servers in two
* forms: as detailed operation traces of single operations and as summarized
* statistics of many operations. Each individual operation is described in
* exactly one of those ways. This hook lets you select which operations are
* sent as traces and which are sent as statistics. The default is a heuristic
* that tries to send one trace for each rough duration bucket for each
* operation each minute, plus more if the operations have errors. (Note that
* Apollo's servers perform their own sampling on received traces; not all
* traces sent to Apollo's servers can be later retrieved via the trace UI.)
*
* If you just want to send all operations as stats, set `sendTraces: false`
* instead of using this experimental hook.
*
* This option is highly experimental and may change or be removed in future
* versions.
*/
experimental_sendOperationAsTrace?: (
trace: Trace,
statsReportKey: string,
) => boolean;
//#endregion
//#region Configure the mechanics of communicating with Apollo's servers.
/**
* Sends a usage report after every request. This options is useful for
* stateless environments like Amazon Lambda where processes handle only a
* small number of requests before terminating. It defaults to true when the
* ApolloServer was started in the background with
* `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests`
* (generally used with serverless frameworks), or false otherwise. (Note that
* "immediately" does not mean synchronously with completing the response, but
* "very soon", such as after a setImmediate call.)
*/
sendReportsImmediately?: boolean;
/**
* Specifies which Fetch API implementation to use when sending usage reports.
*/
fetcher?: Fetcher;
/**
* How often to send reports to Apollo. We'll also send reports when the
* report gets big; see maxUncompressedReportSize.
*/
reportIntervalMs?: number;
/**
* We send a report when the report size will become bigger than this size in
* bytes (default: 4MB). (This is a rough limit --- we ignore the size of the
* report header and some other top level bytes. We just add up the lengths of
* the serialized traces and signatures.)
*/
maxUncompressedReportSize?: number;
/**
* Reporting is retried with exponential backoff up to this many times
* (including the original request). Defaults to 5.
*/
maxAttempts?: number;
/**
* Minimum back-off for retries. Defaults to 100ms.
*/
minimumRetryDelayMs?: number;
/**
* Timeout for each individual attempt to send a report to Apollo. (This is
* for each HTTP POST, not for all potential retries.) Defaults to 30 seconds
* (30000ms).
*/
requestTimeoutMs?: number;
/**
* A logger interface to be used for output and errors. When not provided
* it will default to the server's own `logger` implementation and use
* `console` when that is not available.
*/
logger?: Logger;
/**
* By default, if an error occurs when sending trace reports to Apollo
* servers, its message will be sent to the `error` method on the logger
* specified with the `logger` option to this plugin or to ApolloServer (or to
* `console.error` by default). Specify this function to process errors in a
* different way. (The difference between using this option and using a logger
* is that this option receives the actual Error object whereas `logger.error`
* only receives its message.)
*/
reportErrorFunction?: (err: Error) => void;
//#endregion
//#region Internal and non-recommended options
/**
* The URL base that we send reports to (not including the path). This option
* only needs to be set for testing and Apollo-internal uses.
*/
endpointUrl?: string;
/**
* If set, prints all reports as JSON when they are sent. (Note that for
* technical reasons, traces embedded in a report are printed separately when
* they are added to a report.) Reports are sent through `logger.info`.
*/
debugPrintReports?: boolean;
/**
* Specify the function for creating a signature for a query. See signature.ts
* for details. This option is not recommended, as Apollo's servers make assumptions
* about how the signature relates to the operation you executed.
*/
calculateSignature?: (ast: DocumentNode, operationName: string) => string;
//#endregion
}
export type SendValuesBaseOptions =
| { onlyNames: Array }
| { exceptNames: Array }
| { all: true }
| { none: true };
type VariableValueTransformOptions = {
variables: Record;
operationString?: string;
};
export type VariableValueOptions =
| {
transform: (
options: VariableValueTransformOptions,
) => Record;
}
| SendValuesBaseOptions;
export type SendErrorsOptions =
| { unmodified: true }
| { masked: true }
| { transform: (err: GraphQLError) => GraphQLError | null };
export interface ClientInfo {
clientName?: string;
clientVersion?: string;
}
export type GenerateClientInfo = (
requestContext: GraphQLRequestContext,
) => ClientInfo;
/dist/esm/runHttpQuery.js#import { chooseContentTypeForSingleResultResponse, internalExecuteOperation, MEDIA_TYPES, } from './ApolloServer.js';
import { Kind } from 'graphql';
import { BadRequestError } from './internalErrorClasses.js';
import { URLSearchParams } from 'url';
import Negotiator from 'negotiator';
import { HeaderMap } from './utils/HeaderMap.js';
function fieldIfString(o, fieldName) {
const value = o[fieldName];
if (typeof value === 'string') {
return value;
}
return undefined;
}
function searchParamIfSpecifiedOnce(searchParams, paramName) {
const values = searchParams.getAll(paramName);
switch (values.length) {
case 0:
return undefined;
case 1:
return values[0];
default:
throw new BadRequestError(`The '${paramName}' search parameter may only be specified once.`);
}
}
function jsonParsedSearchParamIfSpecifiedOnce(searchParams, fieldName) {
const value = searchParamIfSpecifiedOnce(searchParams, fieldName);
if (value === undefined) {
return undefined;
}
let hopefullyRecord;
try {
hopefullyRecord = JSON.parse(value);
}
catch {
throw new BadRequestError(`The ${fieldName} search parameter contains invalid JSON.`);
}
if (!isStringRecord(hopefullyRecord)) {
throw new BadRequestError(`The ${fieldName} search parameter should contain a JSON-encoded object.`);
}
return hopefullyRecord;
}
function fieldIfRecord(o, fieldName) {
const value = o[fieldName];
if (isStringRecord(value)) {
return value;
}
return undefined;
}
function isStringRecord(o) {
return (!!o && typeof o === 'object' && !Buffer.isBuffer(o) && !Array.isArray(o));
}
function isNonEmptyStringRecord(o) {
return isStringRecord(o) && Object.keys(o).length > 0;
}
function ensureQueryIsStringOrMissing(query) {
if (!query || typeof query === 'string') {
return;
}
if (query.kind === Kind.DOCUMENT) {
throw new BadRequestError("GraphQL queries must be strings. It looks like you're sending the " +
'internal graphql-js representation of a parsed query in your ' +
'request instead of a request in the GraphQL query language. You ' +
'can convert an AST to a string using the `print` function from ' +
'`graphql`, or use a client like `apollo-client` which converts ' +
'the internal representation to a string for you.');
}
else {
throw new BadRequestError('GraphQL queries must be strings.');
}
}
export async function runHttpQuery({ server, httpRequest, contextValue, schemaDerivedData, internals, sharedResponseHTTPGraphQLHead, }) {
let graphQLRequest;
switch (httpRequest.method) {
case 'POST': {
if (!isNonEmptyStringRecord(httpRequest.body)) {
throw new BadRequestError('POST body missing, invalid Content-Type, or JSON object has no keys.');
}
ensureQueryIsStringOrMissing(httpRequest.body.query);
if (typeof httpRequest.body.variables === 'string') {
throw new BadRequestError('`variables` in a POST body should be provided as an object, not a recursively JSON-encoded string.');
}
if (typeof httpRequest.body.extensions === 'string') {
throw new BadRequestError('`extensions` in a POST body should be provided as an object, not a recursively JSON-encoded string.');
}
graphQLRequest = {
query: fieldIfString(httpRequest.body, 'query'),
operationName: fieldIfString(httpRequest.body, 'operationName'),
variables: fieldIfRecord(httpRequest.body, 'variables'),
extensions: fieldIfRecord(httpRequest.body, 'extensions'),
http: httpRequest,
};
break;
}
case 'GET': {
const searchParams = new URLSearchParams(httpRequest.search);
graphQLRequest = {
query: searchParamIfSpecifiedOnce(searchParams, 'query'),
operationName: searchParamIfSpecifiedOnce(searchParams, 'operationName'),
variables: jsonParsedSearchParamIfSpecifiedOnce(searchParams, 'variables'),
extensions: jsonParsedSearchParamIfSpecifiedOnce(searchParams, 'extensions'),
http: httpRequest,
};
break;
}
default:
throw new BadRequestError('Apollo Server supports only GET/POST requests.', {
extensions: {
http: {
status: 405,
headers: new HeaderMap([['allow', 'GET, POST']]),
},
},
});
}
const graphQLResponse = await internalExecuteOperation({
server,
graphQLRequest,
internals,
schemaDerivedData,
sharedResponseHTTPGraphQLHead,
}, { contextValue });
if (graphQLResponse.body.kind === 'single') {
if (!graphQLResponse.http.headers.get('content-type')) {
const contentType = chooseContentTypeForSingleResultResponse(httpRequest);
if (contentType === null) {
throw new BadRequestError(`An 'accept' header was provided for this request which does not accept ` +
`${MEDIA_TYPES.APPLICATION_JSON} or ${MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON}`, { extensions: { http: { status: 406 } } });
}
graphQLResponse.http.headers.set('content-type', contentType);
}
return {
...graphQLResponse.http,
body: {
kind: 'complete',
string: prettyJSONStringify(orderExecutionResultFields(graphQLResponse.body.singleResult)),
},
};
}
const acceptHeader = httpRequest.headers.get('accept');
if (!(acceptHeader &&
new Negotiator({
headers: { accept: httpRequest.headers.get('accept') },
}).mediaType([
MEDIA_TYPES.MULTIPART_MIXED_NO_DEFER_SPEC,
MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL,
]) === MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL)) {
throw new BadRequestError('Apollo server received an operation that uses incremental delivery ' +
'(@defer or @stream), but the client does not accept multipart/mixed ' +
'HTTP responses. To enable incremental delivery support, add the HTTP ' +
"header 'Accept: multipart/mixed; deferSpec=20220824'.", { extensions: { http: { status: 406 } } });
}
graphQLResponse.http.headers.set('content-type', 'multipart/mixed; boundary="-"; deferSpec=20220824');
return {
...graphQLResponse.http,
body: {
kind: 'chunked',
asyncIterator: writeMultipartBody(graphQLResponse.body.initialResult, graphQLResponse.body.subsequentResults),
},
};
}
async function* writeMultipartBody(initialResult, subsequentResults) {
yield `\r\n---\r\ncontent-type: application/json; charset=utf-8\r\n\r\n${JSON.stringify(orderInitialIncrementalExecutionResultFields(initialResult))}\r\n---${initialResult.hasNext ? '' : '--'}\r\n`;
for await (const result of subsequentResults) {
yield `content-type: application/json; charset=utf-8\r\n\r\n${JSON.stringify(orderSubsequentIncrementalExecutionResultFields(result))}\r\n---${result.hasNext ? '' : '--'}\r\n`;
}
}
function orderExecutionResultFields(result) {
return {
errors: result.errors,
data: result.data,
extensions: result.extensions,
};
}
function orderInitialIncrementalExecutionResultFields(result) {
return {
hasNext: result.hasNext,
errors: result.errors,
data: result.data,
incremental: orderIncrementalResultFields(result.incremental),
extensions: result.extensions,
};
}
function orderSubsequentIncrementalExecutionResultFields(result) {
return {
hasNext: result.hasNext,
incremental: orderIncrementalResultFields(result.incremental),
extensions: result.extensions,
};
}
function orderIncrementalResultFields(incremental) {
return incremental?.map((i) => ({
hasNext: i.hasNext,
errors: i.errors,
path: i.path,
label: i.label,
data: i.data,
items: i.items,
extensions: i.extensions,
}));
}
export function prettyJSONStringify(value) {
return JSON.stringify(value) + '\n';
}
export function newHTTPGraphQLHead(status) {
return {
status,
headers: new HeaderMap(),
};
}
export function mergeHTTPGraphQLHead(target, source) {
if (source.status) {
target.status = source.status;
}
if (source.headers) {
for (const [name, value] of source.headers) {
target.headers.set(name, value);
}
}
}
//# sourceMappingURL=runHttpQuery.js.map/dist/cjs/runHttpQuery.js&"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeHTTPGraphQLHead = exports.newHTTPGraphQLHead = exports.prettyJSONStringify = exports.runHttpQuery = void 0;
const ApolloServer_js_1 = require("./ApolloServer.js");
const graphql_1 = require("graphql");
const internalErrorClasses_js_1 = require("./internalErrorClasses.js");
const url_1 = require("url");
const negotiator_1 = __importDefault(require("negotiator"));
const HeaderMap_js_1 = require("./utils/HeaderMap.js");
function fieldIfString(o, fieldName) {
const value = o[fieldName];
if (typeof value === 'string') {
return value;
}
return undefined;
}
function searchParamIfSpecifiedOnce(searchParams, paramName) {
const values = searchParams.getAll(paramName);
switch (values.length) {
case 0:
return undefined;
case 1:
return values[0];
default:
throw new internalErrorClasses_js_1.BadRequestError(`The '${paramName}' search parameter may only be specified once.`);
}
}
function jsonParsedSearchParamIfSpecifiedOnce(searchParams, fieldName) {
const value = searchParamIfSpecifiedOnce(searchParams, fieldName);
if (value === undefined) {
return undefined;
}
let hopefullyRecord;
try {
hopefullyRecord = JSON.parse(value);
}
catch {
throw new internalErrorClasses_js_1.BadRequestError(`The ${fieldName} search parameter contains invalid JSON.`);
}
if (!isStringRecord(hopefullyRecord)) {
throw new internalErrorClasses_js_1.BadRequestError(`The ${fieldName} search parameter should contain a JSON-encoded object.`);
}
return hopefullyRecord;
}
function fieldIfRecord(o, fieldName) {
const value = o[fieldName];
if (isStringRecord(value)) {
return value;
}
return undefined;
}
function isStringRecord(o) {
return (!!o && typeof o === 'object' && !Buffer.isBuffer(o) && !Array.isArray(o));
}
function isNonEmptyStringRecord(o) {
return isStringRecord(o) && Object.keys(o).length > 0;
}
function ensureQueryIsStringOrMissing(query) {
if (!query || typeof query === 'string') {
return;
}
if (query.kind === graphql_1.Kind.DOCUMENT) {
throw new internalErrorClasses_js_1.BadRequestError("GraphQL queries must be strings. It looks like you're sending the " +
'internal graphql-js representation of a parsed query in your ' +
'request instead of a request in the GraphQL query language. You ' +
'can convert an AST to a string using the `print` function from ' +
'`graphql`, or use a client like `apollo-client` which converts ' +
'the internal representation to a string for you.');
}
else {
throw new internalErrorClasses_js_1.BadRequestError('GraphQL queries must be strings.');
}
}
async function runHttpQuery({ server, httpRequest, contextValue, schemaDerivedData, internals, sharedResponseHTTPGraphQLHead, }) {
let graphQLRequest;
switch (httpRequest.method) {
case 'POST': {
if (!isNonEmptyStringRecord(httpRequest.body)) {
throw new internalErrorClasses_js_1.BadRequestError('POST body missing, invalid Content-Type, or JSON object has no keys.');
}
ensureQueryIsStringOrMissing(httpRequest.body.query);
if (typeof httpRequest.body.variables === 'string') {
throw new internalErrorClasses_js_1.BadRequestError('`variables` in a POST body should be provided as an object, not a recursively JSON-encoded string.');
}
if (typeof httpRequest.body.extensions === 'string') {
throw new internalErrorClasses_js_1.BadRequestError('`extensions` in a POST body should be provided as an object, not a recursively JSON-encoded string.');
}
graphQLRequest = {
query: fieldIfString(httpRequest.body, 'query'),
operationName: fieldIfString(httpRequest.body, 'operationName'),
variables: fieldIfRecord(httpRequest.body, 'variables'),
extensions: fieldIfRecord(httpRequest.body, 'extensions'),
http: httpRequest,
};
break;
}
case 'GET': {
const searchParams = new url_1.URLSearchParams(httpRequest.search);
graphQLRequest = {
query: searchParamIfSpecifiedOnce(searchParams, 'query'),
operationName: searchParamIfSpecifiedOnce(searchParams, 'operationName'),
variables: jsonParsedSearchParamIfSpecifiedOnce(searchParams, 'variables'),
extensions: jsonParsedSearchParamIfSpecifiedOnce(searchParams, 'extensions'),
http: httpRequest,
};
break;
}
default:
throw new internalErrorClasses_js_1.BadRequestError('Apollo Server supports only GET/POST requests.', {
extensions: {
http: {
status: 405,
headers: new HeaderMap_js_1.HeaderMap([['allow', 'GET, POST']]),
},
},
});
}
const graphQLResponse = await (0, ApolloServer_js_1.internalExecuteOperation)({
server,
graphQLRequest,
internals,
schemaDerivedData,
sharedResponseHTTPGraphQLHead,
}, { contextValue });
if (graphQLResponse.body.kind === 'single') {
if (!graphQLResponse.http.headers.get('content-type')) {
const contentType = (0, ApolloServer_js_1.chooseContentTypeForSingleResultResponse)(httpRequest);
if (contentType === null) {
throw new internalErrorClasses_js_1.BadRequestError(`An 'accept' header was provided for this request which does not accept ` +
`${ApolloServer_js_1.MEDIA_TYPES.APPLICATION_JSON} or ${ApolloServer_js_1.MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON}`, { extensions: { http: { status: 406 } } });
}
graphQLResponse.http.headers.set('content-type', contentType);
}
return {
...graphQLResponse.http,
body: {
kind: 'complete',
string: prettyJSONStringify(orderExecutionResultFields(graphQLResponse.body.singleResult)),
},
};
}
const acceptHeader = httpRequest.headers.get('accept');
if (!(acceptHeader &&
new negotiator_1.default({
headers: { accept: httpRequest.headers.get('accept') },
}).mediaType([
ApolloServer_js_1.MEDIA_TYPES.MULTIPART_MIXED_NO_DEFER_SPEC,
ApolloServer_js_1.MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL,
]) === ApolloServer_js_1.MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL)) {
throw new internalErrorClasses_js_1.BadRequestError('Apollo server received an operation that uses incremental delivery ' +
'(@defer or @stream), but the client does not accept multipart/mixed ' +
'HTTP responses. To enable incremental delivery support, add the HTTP ' +
"header 'Accept: multipart/mixed; deferSpec=20220824'.", { extensions: { http: { status: 406 } } });
}
graphQLResponse.http.headers.set('content-type', 'multipart/mixed; boundary="-"; deferSpec=20220824');
return {
...graphQLResponse.http,
body: {
kind: 'chunked',
asyncIterator: writeMultipartBody(graphQLResponse.body.initialResult, graphQLResponse.body.subsequentResults),
},
};
}
exports.runHttpQuery = runHttpQuery;
async function* writeMultipartBody(initialResult, subsequentResults) {
yield `\r\n---\r\ncontent-type: application/json; charset=utf-8\r\n\r\n${JSON.stringify(orderInitialIncrementalExecutionResultFields(initialResult))}\r\n---${initialResult.hasNext ? '' : '--'}\r\n`;
for await (const result of subsequentResults) {
yield `content-type: application/json; charset=utf-8\r\n\r\n${JSON.stringify(orderSubsequentIncrementalExecutionResultFields(result))}\r\n---${result.hasNext ? '' : '--'}\r\n`;
}
}
function orderExecutionResultFields(result) {
return {
errors: result.errors,
data: result.data,
extensions: result.extensions,
};
}
function orderInitialIncrementalExecutionResultFields(result) {
return {
hasNext: result.hasNext,
errors: result.errors,
data: result.data,
incremental: orderIncrementalResultFields(result.incremental),
extensions: result.extensions,
};
}
function orderSubsequentIncrementalExecutionResultFields(result) {
return {
hasNext: result.hasNext,
incremental: orderIncrementalResultFields(result.incremental),
extensions: result.extensions,
};
}
function orderIncrementalResultFields(incremental) {
return incremental?.map((i) => ({
hasNext: i.hasNext,
errors: i.errors,
path: i.path,
label: i.label,
data: i.data,
items: i.items,
extensions: i.extensions,
}));
}
function prettyJSONStringify(value) {
return JSON.stringify(value) + '\n';
}
exports.prettyJSONStringify = prettyJSONStringify;
function newHTTPGraphQLHead(status) {
return {
status,
headers: new HeaderMap_js_1.HeaderMap(),
};
}
exports.newHTTPGraphQLHead = newHTTPGraphQLHead;
function mergeHTTPGraphQLHead(target, source) {
if (source.status) {
target.status = source.status;
}
if (source.headers) {
for (const [name, value] of source.headers) {
target.headers.set(name, value);
}
}
}
exports.mergeHTTPGraphQLHead = mergeHTTPGraphQLHead;
//# sourceMappingURL=runHttpQuery.js.map1/dist/cjs/plugin/landingPage/default/types.js.mapč{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/plugin/landingPage/default/types.ts"],"names":[],"mappings":""}#/dist/esm/utils/urlForHttpServer.jsmimport { format } from 'url';
export function urlForHttpServer(httpServer) {
const { address, port } = httpServer.address();
const hostname = address === '' || address === '::' ? 'localhost' : address;
return format({
protocol: 'http',
hostname,
port,
pathname: '/',
});
}
//# sourceMappingURL=urlForHttpServer.js.map,/dist/esm/plugin/usageReporting/index.js.mapĮ{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugin/usageReporting/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAC"}6/dist/cjs/plugin/schemaReporting/schemaReporter.js.map
{"version":3,"file":"schemaReporter.js","sourceRoot":"","sources":["../../../../src/plugin/schemaReporting/schemaReporter.ts"],"names":[],"mappings":";;;;;;AAAA,4DAA+B;AAU/B,yEAAmE;AAEtD,QAAA,eAAe,GAAG;;;;;;;;;;;;;CAa9B,CAAC;AAGF,MAAa,cAAc;IAczB,YAAY,OASX;QACC,IAAI,CAAC,OAAO,GAAG;YACb,cAAc,EAAE,kBAAkB;YAClC,WAAW,EAAE,OAAO,CAAC,MAAM;YAC3B,2BAA2B,EAAE,mCAAmC;YAChE,8BAA8B,EAAE,kCAAc;SAC/C,CAAC;QAEF,IAAI,CAAC,WAAW;YACd,OAAO,CAAC,WAAW;gBACnB,4DAA4D,CAAC;QAE/D,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC;QACnE,IAAI,CAAC,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC;QACrE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,oBAAK,CAAC;IAC1C,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAEM,KAAK;QACV,IAAI,CAAC,SAAS,GAAG,UAAU,CACzB,GAAG,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAC9C,IAAI,CAAC,yBAAyB,CAC/B,CAAC;IACJ,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,IAAI,CAAC,SAAS,EAAE;YAClB,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;SAC5B;IACH,CAAC;IAEO,KAAK,CAAC,4BAA4B,CAAC,sBAA+B;QACxE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAG3B,IAAI,IAAI,CAAC,OAAO,EAAE;YAAE,OAAO;QAC3B,IAAI;YACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC;YAC/D,IAAI,CAAC,MAAM,EAAE;gBACX,OAAO;aACR;YACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;gBACnB,IAAI,CAAC,SAAS,GAAG,UAAU,CACzB,GAAG,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,MAAM,CAAC,cAAc,CAAC,EAC9D,MAAM,CAAC,SAAS,GAAG,IAAI,CACxB,CAAC;aACH;YACD,OAAO;SACR;QAAC,OAAO,KAAK,EAAE;YAId,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,kEAAkE,KAAK,EAAE,CAC1E,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;gBACnB,IAAI,CAAC,SAAS,GAAG,UAAU,CACzB,GAAG,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAC9C,IAAI,CAAC,0BAA0B,CAChC,CAAC;aACH;SACF;IACH,CAAC;IAEM,KAAK,CAAC,YAAY,CACvB,cAAuB;QAEvB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC;YAC9C,MAAM,EAAE,IAAI,CAAC,YAAY;YACzB,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;SACpD,CAAC,CAAC;QAEH,IAAI,MAAM,EAAE;YACV,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;SAC/D;QAED,SAAS,wBAAwB,CAAC,IAAS;YACzC,OAAO;gBACL,4CAA4C;gBAC5C,mDAAmD;gBACnD,mCAAmC;gBACnC,oBAAoB;gBACpB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aACrB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;QAED,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YAC/B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC;SACjD;QAED,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,KAAK,sBAAsB,EAAE;YAC3D,OAAO,IAAI,CAAC,YAAY,CAAC;SAC1B;aAAM,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,KAAK,mBAAmB,EAAE;YAC/D,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;gBACE,8CAA8C;gBAC9C,IAAI,CAAC,YAAY,CAAC,OAAO;gBACzB,kDAAkD;aACnD,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;YACF,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;SACb;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,WAAW,CACvB,SAAwC;QAExC,MAAM,OAAO,GAAmB;YAC9B,KAAK,EAAE,uBAAe;YACtB,SAAS;SACV,CAAC;QAEF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE;YACxD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE;YACpB,MAAM,IAAI,KAAK,CACb;gBACE,mCAAmC,YAAY,CAAC,MAAM,OAAO;gBAC7D,sCAAsC;aACvC,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;SACH;QAED,IAAI;YAGF,OAAO,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC;SAClC;QAAC,OAAO,KAAK,EAAE;YACd,MAAM,IAAI,KAAK,CACb;gBACE,mCAAmC;gBACnC,kCAAkC;gBAClC,iEAAiE;gBACjE,KAAK;aACN,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;SACH;IACH,CAAC;CACF;AAhLD,wCAgLC"} /plugin/inlineTrace/package.json{
"name": "@apollo/server/plugin/inlineTrace",
"type": "module",
"main": "../../dist/cjs/plugin/inlineTrace/index.js",
"module": "../../dist/esm/plugin/inlineTrace/index.js",
"types": "../../dist/esm/plugin/inlineTrace/index.d.ts",
"sideEffects": false
}
=/dist/esm/plugin/landingPage/default/getEmbeddedHTML.d.ts.mapS{"version":3,"file":"getEmbeddedHTML.d.ts","sourceRoot":"","sources":["../../../../../src/plugin/landingPage/default/getEmbeddedHTML.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6DAA6D,EAC7D,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAmBjB,eAAO,MAAM,uBAAuB,YACzB,MAAM,UACP,6DAA6D,WAmEtE,CAAC;AAEF,eAAO,MAAM,sBAAsB,YACxB,MAAM,UACP,iBAAiB,WA+B1B,CAAC"}&/dist/esm/externalTypes/plugins.js.map~{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../../src/externalTypes/plugins.ts"],"names":[],"mappings":""}!/plugin/cacheControl/package.json{
"name": "@apollo/server/plugin/cacheControl",
"type": "module",
"main": "../../dist/cjs/plugin/cacheControl/index.js",
"module": "../../dist/esm/plugin/cacheControl/index.js",
"types": "../../dist/esm/plugin/cacheControl/index.d.ts",
"sideEffects": false
}
'/dist/esm/plugin/schemaIsFederated.d.tsģimport { GraphQLSchema } from 'graphql';
export declare function schemaIsFederated(schema: GraphQLSchema): boolean;
//# sourceMappingURL=schemaIsFederated.d.ts.map/standalone/package.json{
"name": "@apollo/server/standalone",
"type": "module",
"main": "../dist/cjs/standalone/index.js",
"module": "../dist/esm/standalone/index.js",
"types": "../dist/esm/standalone/index.d.ts",
"sideEffects": false
}/dist/cjs/errorNormalize.js.map{"version":3,"file":"errorNormalize.js","sourceRoot":"","sources":["../../src/errorNormalize.ts"],"names":[],"mappings":";;;AAEA,qCAIiB;AACjB,gDAA0D;AAE1D,uDAA6E;AAC7E,uDAAiD;AAUjD,SAAgB,wBAAwB,CACtC,MAA8B,EAC9B,UAMI,EAAE;IAKN,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,IAAA,oCAAkB,GAAE,CAAC;IAE5C,OAAO;QACL,cAAc;QACd,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACpC,IAAI;gBACF,OAAO,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;aAC/C;YAAC,OAAO,eAAe,EAAE;gBACxB,IAAI,OAAO,CAAC,iCAAiC,EAAE;oBAG7C,OAAO,WAAW,CAAC,eAAe,CAAC,CAAC;iBACrC;qBAAM;oBAEL,OAAO;wBACL,OAAO,EAAE,uBAAuB;wBAChC,UAAU,EAAE,EAAE,IAAI,EAAE,gCAAqB,CAAC,qBAAqB,EAAE;qBAClE,CAAC;iBACH;aACF;QACH,CAAC,CAAC;KACH,CAAC;IAEF,SAAS,WAAW,CAAC,UAAmB;QACtC,MAAM,YAAY,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAEpD,MAAM,UAAU,GAA2B;YACzC,GAAG,YAAY,CAAC,UAAU;YAC1B,IAAI,EACF,YAAY,CAAC,UAAU,CAAC,IAAI;gBAC5B,gCAAqB,CAAC,qBAAqB;SAC9C,CAAC;QAEF,IAAI,wBAAwB,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;YAC7C,IAAA,sCAAoB,EAAC,cAAc,EAAE;gBACnC,OAAO,EAAE,IAAI,wBAAS,EAAE;gBACxB,GAAG,UAAU,CAAC,IAAI;aACnB,CAAC,CAAC;YACH,OAAO,UAAU,CAAC,IAAI,CAAC;SACxB;QAED,IAAI,OAAO,CAAC,iCAAiC,EAAE;YAK7C,UAAU,CAAC,UAAU,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;SACzD;QAED,OAAO,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC;IAClD,CAAC;AACH,CAAC;AAjED,4DAiEC;AAED,SAAgB,WAAW,CAAC,UAAmB;IAC7C,OAAO,UAAU,YAAY,KAAK;QAChC,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,IAAI,sBAAY,CAAC,0BAA0B,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AACxE,CAAC;AAJD,kCAIC;AAED,SAAgB,kBAAkB,CAChC,UAAmB,EACnB,iCAAyC,EAAE;IAE3C,MAAM,KAAK,GAAU,WAAW,CAAC,UAAU,CAAC,CAAC;IAE7C,OAAO,KAAK,YAAY,sBAAY;QAClC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,sBAAY,CAAC,8BAA8B,GAAG,KAAK,CAAC,OAAO,EAAE;YAC/D,aAAa,EAAE,KAAK;SACrB,CAAC,CAAC;AACT,CAAC;AAXD,gDAWC;AAED,SAAS,wBAAwB,CAAC,CAAU;IAC1C,OAAO,CACL,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,OAAQ,CAAS,CAAC,MAAM,KAAK,QAAQ,CAAC;QAC3D,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,IAAK,CAAS,CAAC,OAAO,YAAY,GAAG,CAAC,CACzD,CAAC;AACJ,CAAC"}#/src/plugin/usageReporting/index.tsexport { ApolloServerPluginUsageReporting } from './plugin.js';
export type {
ApolloServerPluginUsageReportingOptions,
SendValuesBaseOptions,
VariableValueOptions,
SendErrorsOptions,
ClientInfo,
GenerateClientInfo,
} from './options.js';
,/dist/cjs/incrementalDeliveryPolyfill.js.map{"version":3,"file":"incrementalDeliveryPolyfill.js","sourceRoot":"","sources":["../../src/incrementalDeliveryPolyfill.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAgF;AA+EhF,IAAI,uCAAuC,GAO3B,SAAS,CAAC;AAE1B,KAAK,UAAU,kBAAkB;IAC/B,IAAI,uCAAuC,KAAK,SAAS,EAAE;QACzD,OAAO;KACR;IACD,MAAM,OAAO,GAAG,wDAAa,SAAS,GAAC,CAAC;IACxC,IAAI,kCAAkC,IAAI,OAAO,EAAE;QACjD,uCAAuC,GAAI,OAAe;aACvD,gCAAgC,CAAC;KACrC;SAAM;QACL,uCAAuC,GAAG,IAAI,CAAC;KAChD;AACH,CAAC;AAEM,KAAK,UAAU,oBAAoB,CACxC,IAAmB;IAEnB,MAAM,kBAAkB,EAAE,CAAC;IAC3B,IAAI,uCAAuC,EAAE;QAC3C,OAAO,uCAAuC,CAAC,IAAI,CAAC,CAAC;KACtD;IACD,OAAO,IAAA,iBAAO,EAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AARD,oDAQC"}&/dist/esm/determineApolloConfig.js.map{"version":3,"file":"determineApolloConfig.js","sourceRoot":"","sources":["../../src/determineApolloConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAKtD,MAAM,UAAU,qBAAqB,CACnC,KAAoC;IAEpC,MAAM,YAAY,GAAiB,EAAE,CAAC;IAEtC,MAAM,EACJ,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,GAAG,OAAO,CAAC,GAAG,CAAC;IAGhB,IAAI,KAAK,EAAE,GAAG,EAAE;QACd,YAAY,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;KAC9B;SAAM,IAAI,UAAU,EAAE;QACrB,YAAY,CAAC,GAAG,GAAG,UAAU,CAAC;KAC/B;IAGD,IAAI,YAAY,CAAC,GAAG,EAAE;QACpB,YAAY,CAAC,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC;aACxC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC;aACxB,MAAM,CAAC,KAAK,CAAC,CAAC;KAClB;IAGD,IAAI,KAAK,EAAE,QAAQ,EAAE;QACnB,YAAY,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;KACxC;SAAM,IAAI,gBAAgB,EAAE;QAC3B,YAAY,CAAC,QAAQ,GAAG,gBAAgB,CAAC;KAC1C;IAGD,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,IAAI,eAAe,CAAC;IAClD,MAAM,YAAY,GAAG,KAAK,EAAE,YAAY,IAAI,oBAAoB,CAAC;IAEjE,IAAI,YAAY,CAAC,QAAQ,EAAE;QACzB,IAAI,OAAO,EAAE;YACX,MAAM,IAAI,KAAK,CACb,yDAAyD;gBACvD,4EAA4E,CAC/E,CAAC;SACH;QACD,IAAI,YAAY,EAAE;YAChB,MAAM,IAAI,KAAK,CACb,8DAA8D;gBAC5D,iFAAiF,CACpF,CAAC;SACH;KACF;SAAM,IAAI,OAAO,EAAE;QAKlB,YAAY,CAAC,QAAQ,GAAG,YAAY;YAClC,CAAC,CAAC,GAAG,OAAO,IAAI,YAAY,EAAE;YAC9B,CAAC,CAAC,OAAO,CAAC;KACb;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}/dist/esm/cachePolicy.js.map{"version":3,"file":"cachePolicy.js","sourceRoot":"","sources":["../../src/cachePolicy.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,SAAS;QAChB,QAAQ,CAAC,IAAe;YACtB,IACE,IAAI,CAAC,MAAM,KAAK,SAAS;gBACzB,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EACxD;gBACA,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;aAC3B;YACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE;gBACxD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;aACzB;QACH,CAAC;QACD,OAAO,CAAC,IAAe;YACrB,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE;gBAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;aAC3B;YACD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE;gBAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;aACzB;QACH,CAAC;QACD,iBAAiB;YACf,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;gBAClD,OAAO,IAAI,CAAC;aACb;YACD,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,QAAQ,EAAE,CAAC;QAChE,CAAC;KACF,CAAC;AACJ,CAAC"}#/src/incrementalDeliveryPolyfill.tsimport { execute, ExecutionArgs, ExecutionResult, GraphQLError } from 'graphql';
// This file "polyfills" graphql@17's experimentalExecuteIncrementally (by
// returning a function that does not understand incremental directives if
// you're using graphql@16). The types defined in this file are largely copied
// from graphql-js.
interface ObjMap {
[key: string]: T;
}
export interface GraphQLExperimentalInitialIncrementalExecutionResult<
TData = ObjMap,
TExtensions = ObjMap,
> extends ExecutionResult {
hasNext: boolean;
incremental?: ReadonlyArray<
GraphQLExperimentalIncrementalResult
>;
extensions?: TExtensions;
}
export interface GraphQLExperimentalSubsequentIncrementalExecutionResult<
TData = ObjMap,
TExtensions = ObjMap,
> {
hasNext: boolean;
incremental?: ReadonlyArray<
GraphQLExperimentalIncrementalResult
>;
extensions?: TExtensions;
}
type GraphQLExperimentalIncrementalResult<
TData = ObjMap,
TExtensions = ObjMap,
> =
| GraphQLExperimentalIncrementalDeferResult
| GraphQLExperimentalIncrementalStreamResult;
interface GraphQLExperimentalIncrementalDeferResult<
TData = ObjMap,
TExtensions = ObjMap,
> extends ExecutionResult {
path?: ReadonlyArray;
label?: string;
}
interface GraphQLExperimentalIncrementalStreamResult<
TData = Array,
TExtensions = ObjMap,
> {
errors?: ReadonlyArray;
items?: TData | null;
path?: ReadonlyArray;
label?: string;
extensions?: TExtensions;
}
export interface GraphQLExperimentalIncrementalExecutionResults<
TData = ObjMap,
TExtensions = ObjMap,
> {
initialResult: GraphQLExperimentalInitialIncrementalExecutionResult<
TData,
TExtensions
>;
subsequentResults: AsyncGenerator<
GraphQLExperimentalSubsequentIncrementalExecutionResult,
void,
void
>;
}
type PromiseOrValue = Promise | T;
// This starts as undefined and is set to a function or null by running
// tryToLoadGraphQL17(). If graphql-js 17 is installed, it is set to the
// experimentalExecuteIncrementally function from that package; otherwise it is
// set to null.
let graphqlExperimentalExecuteIncrementally:
| ((
args: ExecutionArgs,
) => PromiseOrValue<
ExecutionResult | GraphQLExperimentalIncrementalExecutionResults
>)
| null
| undefined = undefined;
async function tryToLoadGraphQL17() {
if (graphqlExperimentalExecuteIncrementally !== undefined) {
return;
}
const graphql = await import('graphql');
if ('experimentalExecuteIncrementally' in graphql) {
graphqlExperimentalExecuteIncrementally = (graphql as any)
.experimentalExecuteIncrementally;
} else {
graphqlExperimentalExecuteIncrementally = null;
}
}
export async function executeIncrementally(
args: ExecutionArgs,
): Promise {
await tryToLoadGraphQL17();
if (graphqlExperimentalExecuteIncrementally) {
return graphqlExperimentalExecuteIncrementally(args);
}
return execute(args);
}
/dist/cjs/httpBatching.js 0"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runPotentiallyBatchedHttpQuery = void 0;
const runHttpQuery_js_1 = require("./runHttpQuery.js");
const internalErrorClasses_js_1 = require("./internalErrorClasses.js");
async function runBatchedHttpQuery({ server, batchRequest, body, contextValue, schemaDerivedData, internals, }) {
if (body.length === 0) {
throw new internalErrorClasses_js_1.BadRequestError('No operations found in request.');
}
const sharedResponseHTTPGraphQLHead = (0, runHttpQuery_js_1.newHTTPGraphQLHead)();
const responseBodies = await Promise.all(body.map(async (bodyPiece) => {
const singleRequest = {
...batchRequest,
body: bodyPiece,
};
const response = await (0, runHttpQuery_js_1.runHttpQuery)({
server,
httpRequest: singleRequest,
contextValue,
schemaDerivedData,
internals,
sharedResponseHTTPGraphQLHead,
});
if (response.body.kind === 'chunked') {
throw Error('Incremental delivery is not implemented for batch requests');
}
return response.body.string;
}));
return {
...sharedResponseHTTPGraphQLHead,
body: { kind: 'complete', string: `[${responseBodies.join(',')}]` },
};
}
async function runPotentiallyBatchedHttpQuery(server, httpGraphQLRequest, contextValue, schemaDerivedData, internals) {
if (!(httpGraphQLRequest.method === 'POST' &&
Array.isArray(httpGraphQLRequest.body))) {
return await (0, runHttpQuery_js_1.runHttpQuery)({
server,
httpRequest: httpGraphQLRequest,
contextValue,
schemaDerivedData,
internals,
sharedResponseHTTPGraphQLHead: null,
});
}
if (internals.allowBatchedHttpRequests) {
return await runBatchedHttpQuery({
server,
batchRequest: httpGraphQLRequest,
body: httpGraphQLRequest.body,
contextValue,
schemaDerivedData,
internals,
});
}
throw new internalErrorClasses_js_1.BadRequestError('Operation batching disabled.');
}
exports.runPotentiallyBatchedHttpQuery = runPotentiallyBatchedHttpQuery;
//# sourceMappingURL=httpBatching.js.map/dist/esm/preventCsrf.d.ts.map{"version":3,"file":"preventCsrf.d.ts","sourceRoot":"","sources":["../../src/preventCsrf.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAYtD,eAAO,MAAM,uCAAuC,UAGnD,CAAC;AA4BF,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,EAClB,4BAA4B,EAAE,MAAM,EAAE,QAmDvC"}./dist/esm/utils/schemaInstrumentation.d.ts.map{"version":3,"file":"schemaInstrumentation.d.ts","sourceRoot":"","sources":["../../../src/utils/schemaInstrumentation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAMd,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EACV,WAAW,EAEZ,MAAM,2BAA2B,CAAC;AAEnC,eAAO,MAAM,yCAAyC,eAErD,CAAC;AACF,eAAO,MAAM,uBAAuB,eAA0C,CAAC;AAC/E,QAAA,MAAM,oBAAoB,eAAuC,CAAC;AAElE,wBAAgB,+BAA+B,CAAC,QAAQ,SAAS,WAAW,EAC1E,MAAM,EAAE,aAAa,GAAG;IAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAA;CAAE;;EAuB7D;AAED,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,aAAa,GAAG;IAAE,CAAC,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3D,OAAO,CAET;AA4DD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,QAmBpD"};/dist/cjs/plugin/landingPage/default/getEmbeddedHTML.js.map{"version":3,"file":"getEmbeddedHTML.js","sourceRoot":"","sources":["../../../../../src/plugin/landingPage/default/getEmbeddedHTML.ts"],"names":[],"mappings":";;;AAcA,SAAS,sBAAsB,CAAC,MAAyB;IACvD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;SAC1B,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC;SACvB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC;SACvB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC;SACvB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AAC7B,CAAC;AAEM,MAAM,uBAAuB,GAAG,CACrC,OAAe,EACf,MAAqE,EACrE,EAAE;IAqBF,MAAM,oCAAoC,GAAG;QAC3C,cAAc,EAAE,EAAE;QAClB,oBAAoB,EAAE,KAAK;QAC3B,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;KAC3D,CAAC;IACF,MAAM,sBAAsB,GAC1B;QACE,GAAG,MAAM;QACT,MAAM,EAAE,qBAAqB;QAC7B,YAAY,EAAE;YACZ,GAAG,MAAM;YACT,cAAc,EAAE;gBACd,GAAG,oCAAoC,CAAC,cAAc;aACvD;SACF;QACD,oBAAoB,EAClB,oCAAoC,CAAC,oBAAoB;KAC5D,CAAC;IAEJ,OAAO;;;;;;;;;;;;;;iEAcwD,OAAO;;;iCAGvC,sBAAsB,CACnD,sBAAsB,CACvB;;;;;;CAMF,CAAC;AACF,CAAC,CAAC;AArEW,QAAA,uBAAuB,2BAqElC;AAEK,MAAM,sBAAsB,GAAG,CACpC,OAAe,EACf,MAAyB,EACzB,EAAE;IACF,OAAO;;;;;;;;;;;;;;gEAcuD,OAAO;;;;;;sBAMjD,MAAM,CAAC,cAAc,IAAI,OAAO;oBAClC,sBAAsB,CAAC;QACrC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;QACtC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,SAAS;QACxC,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,SAAS;KACrC,CAAC;;;CAGL,CAAC;AACF,CAAC,CAAC;AAjCW,QAAA,sBAAsB,0BAiCjC"},/dist/esm/utils/computeCoreSchemaHash.js.map={"version":3,"file":"computeCoreSchemaHash.js","sourceRoot":"","sources":["../../../src/utils/computeCoreSchemaHash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAMtD,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3D,CAAC"}/src/ApolloServer.tsimport { isNodeLike } from '@apollo/utils.isnodelike';
import type { Logger } from '@apollo/utils.logger';
import { makeExecutableSchema } from '@graphql-tools/schema';
import resolvable, { Resolvable } from '@josephg/resolvable';
import {
assertValidSchema,
DocumentNode,
GraphQLError,
GraphQLFieldResolver,
GraphQLFormattedError,
GraphQLSchema,
ParseOptions,
print,
TypedQueryDocumentNode,
ValidationContext,
ValidationRule,
} from 'graphql';
import {
type KeyValueCache,
InMemoryLRUCache,
PrefixingKeyValueCache,
} from '@apollo/utils.keyvaluecache';
import loglevel from 'loglevel';
import Negotiator from 'negotiator';
import * as uuid from 'uuid';
import { newCachePolicy } from './cachePolicy.js';
import { determineApolloConfig } from './determineApolloConfig.js';
import {
ensureError,
ensureGraphQLError,
normalizeAndFormatErrors,
} from './errorNormalize.js';
import {
ApolloServerErrorCode,
ApolloServerValidationErrorCode,
} from './errors/index.js';
import type {
ApolloServerPlugin,
BaseContext,
GraphQLRequest,
GraphQLResponse,
GraphQLServerListener,
GraphQLServerContext,
HTTPGraphQLRequest,
HTTPGraphQLResponse,
LandingPage,
ApolloConfig,
ApolloServerOptions,
DocumentStore,
PersistedQueryOptions,
ContextThunk,
GraphQLRequestContext,
HTTPGraphQLHead,
} from './externalTypes/index.js';
import { runPotentiallyBatchedHttpQuery } from './httpBatching.js';
import { InternalPluginId, pluginIsInternal } from './internalPlugin.js';
import {
preventCsrf,
recommendedCsrfPreventionRequestHeaders,
} from './preventCsrf.js';
import { APQ_CACHE_PREFIX, processGraphQLRequest } from './requestPipeline.js';
import { newHTTPGraphQLHead, prettyJSONStringify } from './runHttpQuery.js';
import { SchemaManager } from './utils/schemaManager.js';
import { isDefined } from './utils/isDefined.js';
import { UnreachableCaseError } from './utils/UnreachableCaseError.js';
import type { WithRequired } from '@apollo/utils.withrequired';
import type { ApolloServerOptionsWithStaticSchema } from './externalTypes/constructor.js';
import type { GatewayExecutor } from '@apollo/server-gateway-interface';
import type { GraphQLExperimentalIncrementalExecutionResults } from './incrementalDeliveryPolyfill.js';
import { HeaderMap } from './utils/HeaderMap.js';
import type {
ExecuteOperationOptions,
VariableValues,
} from './externalTypes/graphql.js';
const NoIntrospection: ValidationRule = (context: ValidationContext) => ({
Field(node) {
if (node.name.value === '__schema' || node.name.value === '__type') {
context.reportError(
new GraphQLError(
'GraphQL introspection is not allowed by Apollo Server, but the query contained __schema or __type. To enable introspection, pass introspection: true to ApolloServer in production',
{
nodes: [node],
extensions: {
validationErrorCode:
ApolloServerValidationErrorCode.INTROSPECTION_DISABLED,
},
},
),
);
}
},
});
export type SchemaDerivedData = {
schema: GraphQLSchema;
// A store that, when enabled (default), will store the parsed and validated
// versions of operations in-memory, allowing subsequent parses/validates
// on the same operation to be executed immediately.
documentStore: DocumentStore | null;
};
type RunningServerState = {
schemaManager: SchemaManager;
landingPage: LandingPage | null;
};
type ServerState =
| {
phase: 'initialized';
schemaManager: SchemaManager;
}
| {
phase: 'starting';
barrier: Resolvable;
schemaManager: SchemaManager;
// This is set to true if you called
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests
// instead of start. The main purpose is that assertStarted allows you to
// still be in the starting phase if this is set. (This is the serverless
// use case.)
startedInBackground: boolean;
}
| {
phase: 'failed to start';
error: Error;
}
| ({
phase: 'started';
drainServers: (() => Promise) | null;
toDispose: (() => Promise)[];
toDisposeLast: (() => Promise)[];
} & RunningServerState)
| ({
phase: 'draining';
barrier: Resolvable;
} & RunningServerState)
| {
phase: 'stopping';
barrier: Resolvable;
}
| {
phase: 'stopped';
stopError: Error | null;
};
export interface ApolloServerInternals {
state: ServerState;
gatewayExecutor: GatewayExecutor | null;
formatError?: (
formattedError: GraphQLFormattedError,
error: unknown,
) => GraphQLFormattedError;
includeStacktraceInErrorResponses: boolean;
persistedQueries?: WithRequired;
nodeEnv: string;
allowBatchedHttpRequests: boolean;
apolloConfig: ApolloConfig;
plugins: ApolloServerPlugin[];
parseOptions: ParseOptions;
// `undefined` means we figure out what to do during _start (because
// the default depends on whether or not we used the background version
// of start).
stopOnTerminationSignals: boolean | undefined;
csrfPreventionRequestHeaders: string[] | null;
rootValue?: ((parsedQuery: DocumentNode) => unknown) | unknown;
validationRules: Array;
fieldResolver?: GraphQLFieldResolver;
__testing_incrementalExecutionResults?: GraphQLExperimentalIncrementalExecutionResults;
}
function defaultLogger(): Logger {
const loglevelLogger = loglevel.getLogger('apollo-server');
loglevelLogger.setLevel(loglevel.levels.INFO);
return loglevelLogger;
}
// We really want to prevent this from being legal:
//
// const s: ApolloServer<{}> =
// new ApolloServer<{importantContextField: boolean}>({ ... });
// s.executeOperation({query}, {contextValue: {}});
//
// ie, if you declare an ApolloServer whose context values must be of a certain
// type, you can't assign it to a variable whose context values are less
// constrained and then pass in a context value missing important fields.
//
// We also want this to be illegal:
//
// const sBase = new ApolloServer<{}>({ ... });
// const s: ApolloServer<{importantContextField: boolean}> = sBase;
// s.addPlugin({async requestDidStart({contextValue: {importantContextField}}) { ... }})
// sBase.executeOperation({query}, {contextValue: {}});
//
// so you shouldn't be able to assign an ApolloServer to a variable whose
// context values are more constrained, either. So we want to declare that
// ApolloServer is *invariant* in TContext, which we do with `in out` (a
// TypeScript 4.7 feature).
export class ApolloServer {
private internals: ApolloServerInternals;
public readonly cache: KeyValueCache;
public readonly logger: Logger;
constructor(config: ApolloServerOptions) {
const nodeEnv = config.nodeEnv ?? process.env.NODE_ENV ?? '';
this.logger = config.logger ?? defaultLogger();
const apolloConfig = determineApolloConfig(config.apollo);
const isDev = nodeEnv !== 'production';
const state: ServerState = config.gateway
? // ApolloServer has been initialized but we have not yet tried to load the
// schema from the gateway. That will wait until `start()` or
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()`
// is called. (These may be called by other helpers; for example,
// `standaloneServer` calls `start` for you inside its `listen` method,
// and a serverless framework integration would call
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests
// for you.)
{
phase: 'initialized',
schemaManager: new SchemaManager({
gateway: config.gateway,
apolloConfig,
schemaDerivedDataProvider: (schema) =>
ApolloServer.generateSchemaDerivedData(
schema,
config.documentStore,
),
logger: this.logger,
}),
}
: // We construct the schema synchronously so that we can fail fast if the
// schema can't be constructed. (This used to be more important because we
// used to have a 'schema' field that was publicly accessible immediately
// after construction, though that field never actually worked with
// gateways.)
{
phase: 'initialized',
schemaManager: new SchemaManager({
apiSchema: ApolloServer.constructSchema(config),
schemaDerivedDataProvider: (schema) =>
ApolloServer.generateSchemaDerivedData(
schema,
config.documentStore,
),
logger: this.logger,
}),
};
const introspectionEnabled = config.introspection ?? isDev;
this.cache = config.cache ?? new InMemoryLRUCache();
// Note that we avoid calling methods on `this` before `this.internals` is assigned
// (thus a bunch of things being static methods above).
this.internals = {
formatError: config.formatError,
rootValue: config.rootValue,
validationRules: [
...(config.validationRules ?? []),
...(introspectionEnabled ? [] : [NoIntrospection]),
],
fieldResolver: config.fieldResolver,
includeStacktraceInErrorResponses:
config.includeStacktraceInErrorResponses ??
(nodeEnv !== 'production' && nodeEnv !== 'test'),
persistedQueries:
config.persistedQueries === false
? undefined
: {
...config.persistedQueries,
cache: new PrefixingKeyValueCache(
config.persistedQueries?.cache ?? this.cache,
APQ_CACHE_PREFIX,
),
},
nodeEnv,
allowBatchedHttpRequests: config.allowBatchedHttpRequests ?? false,
apolloConfig,
// Note that more plugins can be added before `start()` with `addPlugin()`
// (eg, plugins that want to take this ApolloServer as an argument), and
// `start()` will call `addDefaultPlugins` to add default plugins.
plugins: config.plugins ?? [],
parseOptions: config.parseOptions ?? {},
state,
stopOnTerminationSignals: config.stopOnTerminationSignals,
gatewayExecutor: null, // set by _start
csrfPreventionRequestHeaders:
config.csrfPrevention === true || config.csrfPrevention === undefined
? recommendedCsrfPreventionRequestHeaders
: config.csrfPrevention === false
? null
: config.csrfPrevention.requestHeaders ??
recommendedCsrfPreventionRequestHeaders,
__testing_incrementalExecutionResults:
config.__testing_incrementalExecutionResults,
};
}
// Awaiting a call to `start` ensures that a schema has been loaded and that
// all plugin `serverWillStart` hooks have been called. If either of these
// processes throw, `start` will (async) throw as well.
//
// If you're using `standaloneServer`, you don't need to call `start` yourself
// (in fact, it will throw if you do so); its `listen` method takes care of
// that for you.
//
// If instead you're using an integration package for a non-serverless
// framework (like Express), you must await a call to `start` immediately
// after creating your `ApolloServer`, before attaching it to your web
// framework and starting to accept requests. `start` should only be called
// once; if it throws and you'd like to retry, just create another
// `ApolloServer`. (Calling `start` was optional in Apollo Server 2, but in
// Apollo Server 3+ the functions like `expressMiddleware` use `assertStarted`
// to throw if `start` hasn't successfully completed.)
//
// Serverless integrations like Lambda do not support calling `start()`,
// because their lifecycle doesn't allow you to wait before assigning a
// handler or allowing the handler to be called. So they call
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()`
// instead, and don't really differentiate between startup failures and
// request failures. This is hopefully appropriate for a "serverless"
// framework. Serverless startup failures result in returning a redacted error
// to the end user and logging the more detailed error.
public async start(): Promise {
return await this._start(false);
}
public startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests(): void {
this._start(true).catch((e) => this.logStartupError(e));
}
private async _start(startedInBackground: boolean): Promise {
if (this.internals.state.phase !== 'initialized') {
// If we wanted we could make this error detectable and change
// `standaloneServer` to change the message to say not to call start() at
// all.
throw new Error(
`You should only call 'start()' or ` +
`'startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()' ` +
`once on your ApolloServer.`,
);
}
const schemaManager = this.internals.state.schemaManager;
const barrier = resolvable();
this.internals.state = {
phase: 'starting',
barrier,
schemaManager,
startedInBackground,
};
try {
// Now that you can't call addPlugin any more, add default plugins like
// usage reporting if they're not already added.
await this.addDefaultPlugins();
const toDispose: (() => Promise)[] = [];
const executor = await schemaManager.start();
if (executor) {
this.internals.gatewayExecutor = executor;
}
toDispose.push(async () => {
await schemaManager.stop();
});
const schemaDerivedData = schemaManager.getSchemaDerivedData();
const service: GraphQLServerContext = {
logger: this.logger,
cache: this.cache,
schema: schemaDerivedData.schema,
apollo: this.internals.apolloConfig,
startedInBackground,
};
const taggedServerListeners = (
await Promise.all(
this.internals.plugins.map(async (plugin) => ({
serverListener:
plugin.serverWillStart && (await plugin.serverWillStart(service)),
installedImplicitly:
isImplicitlyInstallablePlugin(plugin) &&
plugin.__internal_installed_implicitly__,
})),
)
).filter(
(
maybeTaggedServerListener,
): maybeTaggedServerListener is {
serverListener: GraphQLServerListener;
installedImplicitly: boolean;
} => typeof maybeTaggedServerListener.serverListener === 'object',
);
taggedServerListeners.forEach(
({ serverListener: { schemaDidLoadOrUpdate } }) => {
if (schemaDidLoadOrUpdate) {
schemaManager.onSchemaLoadOrUpdate(schemaDidLoadOrUpdate);
}
},
);
const serverWillStops = taggedServerListeners
.map((l) => l.serverListener.serverWillStop)
.filter(isDefined);
if (serverWillStops.length) {
toDispose.push(async () => {
await Promise.all(
serverWillStops.map((serverWillStop) => serverWillStop()),
);
});
}
const drainServerCallbacks = taggedServerListeners
.map((l) => l.serverListener.drainServer)
.filter(isDefined);
const drainServers = drainServerCallbacks.length
? async () => {
await Promise.all(
drainServerCallbacks.map((drainServer) => drainServer()),
);
}
: null;
// Find the renderLandingPage callback, if one is provided. If the user
// installed ApolloServerPluginLandingPageDisabled then there may be none
// found. On the other hand, if the user installed a landingPage plugin,
// then both the implicit installation of
// ApolloServerPluginLandingPage*Default and the other plugin will be
// found; we skip the implicit plugin.
let taggedServerListenersWithRenderLandingPage =
taggedServerListeners.filter((l) => l.serverListener.renderLandingPage);
if (taggedServerListenersWithRenderLandingPage.length > 1) {
taggedServerListenersWithRenderLandingPage =
taggedServerListenersWithRenderLandingPage.filter(
(l) => !l.installedImplicitly,
);
}
let landingPage: LandingPage | null = null;
if (taggedServerListenersWithRenderLandingPage.length > 1) {
throw Error('Only one plugin can implement renderLandingPage.');
} else if (taggedServerListenersWithRenderLandingPage.length) {
landingPage = await taggedServerListenersWithRenderLandingPage[0]
.serverListener.renderLandingPage!();
}
const toDisposeLast = this.maybeRegisterTerminationSignalHandlers(
['SIGINT', 'SIGTERM'],
startedInBackground,
);
this.internals.state = {
phase: 'started',
schemaManager,
drainServers,
landingPage,
toDispose,
toDisposeLast,
};
} catch (maybeError: unknown) {
const error = ensureError(maybeError);
try {
await Promise.all(
this.internals.plugins.map(async (plugin) =>
plugin.startupDidFail?.({ error }),
),
);
} catch (pluginError) {
this.logger.error(`startupDidFail hook threw: ${pluginError}`);
}
this.internals.state = {
phase: 'failed to start',
error,
};
throw error;
} finally {
barrier.resolve();
}
}
private maybeRegisterTerminationSignalHandlers(
signals: NodeJS.Signals[],
startedInBackground: boolean,
): (() => Promise)[] {
const toDisposeLast: (() => Promise)[] = [];
// We handle signals if it was explicitly requested
// (stopOnTerminationSignals === true), or if we're in Node, not in a test,
// not in a serverless framework (which we guess based on whether they
// called
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests),
// and it wasn't explicitly turned off. (We only actually register the
// signal handlers once we've successfully started up, because there's
// nothing to stop otherwise.)
if (
this.internals.stopOnTerminationSignals === false ||
(this.internals.stopOnTerminationSignals === undefined &&
!(
isNodeLike &&
this.internals.nodeEnv !== 'test' &&
!startedInBackground
))
) {
return toDisposeLast;
}
let receivedSignal = false;
const signalHandler: NodeJS.SignalsListener = async (signal) => {
if (receivedSignal) {
// If we receive another SIGINT or SIGTERM while we're waiting
// for the server to stop, just ignore it.
return;
}
receivedSignal = true;
try {
await this.stop();
} catch (e) {
this.logger.error(`stop() threw during ${signal} shutdown`);
this.logger.error(e);
// Can't rely on the signal handlers being removed.
process.exit(1);
}
// Note: this.stop will call the toDisposeLast handlers below, so at
// this point this handler will have been removed and we can re-kill
// ourself to die with the appropriate signal exit status. this.stop
// takes care to call toDisposeLast last, so the signal handler isn't
// removed until after the rest of shutdown happens.
process.kill(process.pid, signal);
};
signals.forEach((signal) => {
process.on(signal, signalHandler);
toDisposeLast.push(async () => {
process.removeListener(signal, signalHandler);
});
});
return toDisposeLast;
}
// This method is called at the beginning of each GraphQL request by
// `executeHTTPGraphQLRequest` and `executeOperation`. Most of its logic is
// only helpful if you started the server in the background (ie, for
// serverless frameworks): unless you're in a serverless framework, you should
// have called `await server.start()` before the server got to the point of
// running GraphQL requests (`assertStarted` calls in the framework
// integrations verify that) and so the only cases for non-serverless
// frameworks that this should hit are 'started', 'stopping', and 'stopped'.
// But if you started the server in the background (with
// startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests), this
// lets the server wait until fully started before serving operations.
private async _ensureStarted(): Promise {
while (true) {
switch (this.internals.state.phase) {
case 'initialized':
// This error probably won't happen: serverless framework integrations
// should call
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests`
// for you, and other frameworks call `assertStarted` before setting
// things up enough to make calling this function possible.
throw new Error(
'You need to call `server.start()` before using your Apollo Server.',
);
case 'starting':
await this.internals.state.barrier;
// continue the while loop
break;
case 'failed to start':
// First we log the error that prevented startup (which means it will
// get logged once for every GraphQL operation).
this.logStartupError(this.internals.state.error);
// Now make the operation itself fail.
// We intentionally do not re-throw actual startup error as it may contain
// implementation details and this error will propagate to the client.
throw new Error(
'This data graph is missing a valid configuration. More details may be available in the server logs.',
);
case 'started':
case 'draining': // We continue to run operations while draining.
return this.internals.state;
case 'stopping':
case 'stopped':
this.logger.warn(
'A GraphQL operation was received during server shutdown. The ' +
'operation will fail. Consider draining the HTTP server on shutdown; ' +
'see https://go.apollo.dev/s/drain for details.',
);
throw new Error(
`Cannot execute GraphQL operations ${
this.internals.state.phase === 'stopping'
? 'while the server is stopping'
: 'after the server has stopped'
}.'`,
);
default:
throw new UnreachableCaseError(this.internals.state);
}
}
}
// Framework integrations should call this to ensure that you've properly
// started your server before you get anywhere close to actually listening for
// incoming requests.
//
// There's a special case that if you called
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests` and
// it hasn't finished starting up yet, this works too. This is intended for
// cases like a serverless integration (say, Google Cloud Functions) that
// calls
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests` for
// you and then immediately sets up an integration based on another middleware
// like `expressMiddleware` which calls this function. We'd like this to be
// OK, but we still want normal Express users to start their ApolloServer
// before setting up their HTTP server unless they know what they are doing
// well enough to call the function with the long name themselves.
public assertStarted(expressionForError: string) {
if (
this.internals.state.phase !== 'started' &&
this.internals.state.phase !== 'draining' &&
!(
this.internals.state.phase === 'starting' &&
this.internals.state.startedInBackground
)
) {
throw new Error(
'You must `await server.start()` before calling `' +
expressionForError +
'`',
);
}
}
// Given an error that occurred during Apollo Server startup, log it with a
// helpful message. This should happen when you call
// `startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests` (ie,
// in serverless frameworks); with other frameworks, you must `await
// server.start()` which will throw the startup error directly instead of
// logging. This gets called both immediately when the startup error happens,
// and on all subsequent requests.
private logStartupError(err: Error) {
this.logger.error(
'An error occurred during Apollo Server startup. All GraphQL requests ' +
'will now fail. The startup error was: ' +
(err?.message || err),
);
}
private static constructSchema(
config: ApolloServerOptionsWithStaticSchema,
): GraphQLSchema {
if (config.schema) {
return config.schema;
}
const { typeDefs, resolvers } = config;
const augmentedTypeDefs = Array.isArray(typeDefs) ? typeDefs : [typeDefs];
// For convenience, we allow you to pass a few options that we pass through
// to a particular version of `@graphql-tools/schema`'s
// `makeExecutableSchema`. If you want to use more of this function's
// features or have more control over the version of the packages used, just
// call it yourself like `new ApolloServer({schema:
// makeExecutableSchema(...)})`.
return makeExecutableSchema({
typeDefs: augmentedTypeDefs,
resolvers,
});
}
private static generateSchemaDerivedData(
schema: GraphQLSchema,
// null means don't use a documentStore at all.
// missing/undefined means use the default (creating a new one each
// time).
// defined means wrap this one in a random prefix for each new schema.
providedUnprefixedDocumentStore: DocumentStore | null | undefined,
): SchemaDerivedData {
// Instead of waiting for the first operation execution against the schema
// to find out if it's a valid schema or not, check right now. In the
// non-gateway case, if this throws then the `new ApolloServer` call will
// throw. In the gateway case if this throws then it will log a message and
// just not update the schema (although oddly the message will claim that
// the schema is updating).
assertValidSchema(schema);
return {
schema,
// The DocumentStore is schema-derived because we put documents in it
// after checking that they pass GraphQL validation against the schema and
// use this to skip validation as well as parsing. So we can't reuse the
// same DocumentStore for different schemas because that might make us
// treat invalid operations as valid. If we're using the default
// DocumentStore, then we just create it from scratch each time we get a
// new schema. If we're using a user-provided DocumentStore, then we use a
// random prefix each time we get a new schema.
documentStore:
providedUnprefixedDocumentStore === undefined
? new InMemoryLRUCache()
: providedUnprefixedDocumentStore === null
? null
: new PrefixingKeyValueCache(
providedUnprefixedDocumentStore,
`${uuid.v4()}:`,
),
};
}
public async stop() {
switch (this.internals.state.phase) {
case 'initialized':
case 'starting':
case 'failed to start':
throw Error(
'apolloServer.stop() should only be called after `await apolloServer.start()` has succeeded',
);
// Calling stop more than once should have the same result as the first time.
case 'stopped':
if (this.internals.state.stopError) {
throw this.internals.state.stopError;
}
return;
// Two parallel calls to stop; just wait for the other one to finish and
// do whatever it did.
case 'stopping':
case 'draining': {
await this.internals.state.barrier;
// The cast here is because TS doesn't understand that this.state can
// change during the await
// (https://github.com/microsoft/TypeScript/issues/9998).
const state = this.internals.state as ServerState;
if (state.phase !== 'stopped') {
throw Error(`Surprising post-stopping state ${state.phase}`);
}
if (state.stopError) {
throw state.stopError;
}
return;
}
case 'started':
// This is handled by the rest of the function.
break;
default:
throw new UnreachableCaseError(this.internals.state);
}
const barrier = resolvable();
const {
schemaManager,
drainServers,
landingPage,
toDispose,
toDisposeLast,
} = this.internals.state;
// Commit to stopping and start draining servers.
this.internals.state = {
phase: 'draining',
barrier,
schemaManager,
landingPage,
};
try {
await drainServers?.();
// Servers are drained. Prevent further operations from starting and call
// stop handlers.
this.internals.state = { phase: 'stopping', barrier };
// We run shutdown handlers in two phases because we don't want to turn
// off our signal listeners (ie, allow signals to kill the process) until
// we've done the important parts of shutdown like running serverWillStop
// handlers. (We can make this more generic later if it's helpful.)
await Promise.all([...toDispose].map((dispose) => dispose()));
await Promise.all([...toDisposeLast].map((dispose) => dispose()));
} catch (stopError) {
this.internals.state = {
phase: 'stopped',
stopError: stopError as Error,
};
barrier.resolve();
throw stopError;
}
this.internals.state = { phase: 'stopped', stopError: null };
}
private async addDefaultPlugins() {
const { plugins, apolloConfig, nodeEnv } = this.internals;
const isDev = nodeEnv !== 'production';
const alreadyHavePluginWithInternalId = (id: InternalPluginId) =>
plugins.some(
(p) => pluginIsInternal(p) && p.__internal_plugin_id__ === id,
);
// Make sure we're not trying to explicitly enable and disable the same
// feature. (Be careful: we are not trying to stop people from installing
// the same plugin twice if they have a use case for it, like two usage
// reporting plugins for different variants.)
//
// Note that this check doesn't work for the landing page plugin, because
// users can write their own landing page plugins and we don't know if a
// given plugin is a landing page plugin until the server has started.
const pluginsByInternalID = new Map<
InternalPluginId,
{ sawDisabled: boolean; sawNonDisabled: boolean }
>();
for (const p of plugins) {
if (pluginIsInternal(p)) {
const id = p.__internal_plugin_id__;
if (!pluginsByInternalID.has(id)) {
pluginsByInternalID.set(id, {
sawDisabled: false,
sawNonDisabled: false,
});
}
const seen = pluginsByInternalID.get(id)!;
if (p.__is_disabled_plugin__) {
seen.sawDisabled = true;
} else {
seen.sawNonDisabled = true;
}
if (seen.sawDisabled && seen.sawNonDisabled) {
throw new Error(
`You have tried to install both ApolloServerPlugin${id} and ` +
`ApolloServerPlugin${id}Disabled in your server. Please choose ` +
`whether or not you want to disable the feature and install the ` +
`appropriate plugin for your use case.`,
);
}
}
}
// Special case: cache control is on unless you explicitly disable it.
{
if (!alreadyHavePluginWithInternalId('CacheControl')) {
const { ApolloServerPluginCacheControl } = await import(
'./plugin/cacheControl/index.js'
);
plugins.push(ApolloServerPluginCacheControl());
}
}
// Special case: usage reporting is on by default (and first!) if you
// configure an API key.
{
const alreadyHavePlugin =
alreadyHavePluginWithInternalId('UsageReporting');
if (!alreadyHavePlugin && apolloConfig.key) {
if (apolloConfig.graphRef) {
// Keep this plugin first so it wraps everything. (Unfortunately despite
// the fact that the person who wrote this line also was the original
// author of the comment above in #1105, they don't quite understand why this was important.)
const { ApolloServerPluginUsageReporting } = await import(
'./plugin/usageReporting/index.js'
);
plugins.unshift(ApolloServerPluginUsageReporting());
} else {
this.logger.warn(
'You have specified an Apollo key but have not specified a graph ref; usage ' +
'reporting is disabled. To enable usage reporting, set the `APOLLO_GRAPH_REF` ' +
'environment variable to `your-graph-id@your-graph-variant`. To disable this ' +
'warning, install `ApolloServerPluginUsageReportingDisabled`.',
);
}
}
}
// Special case: schema reporting can be turned on via environment variable.
{
const alreadyHavePlugin =
alreadyHavePluginWithInternalId('SchemaReporting');
const enabledViaEnvVar = process.env.APOLLO_SCHEMA_REPORTING === 'true';
if (!alreadyHavePlugin && enabledViaEnvVar) {
if (apolloConfig.key) {
const { ApolloServerPluginSchemaReporting } = await import(
'./plugin/schemaReporting/index.js'
);
plugins.push(ApolloServerPluginSchemaReporting());
} else {
throw new Error(
"You've enabled schema reporting by setting the APOLLO_SCHEMA_REPORTING " +
'environment variable to true, but you also need to provide your ' +
'Apollo API key, via the APOLLO_KEY environment ' +
'variable or via `new ApolloServer({apollo: {key})',
);
}
}
}
// Special case: inline tracing is on by default for federated schemas.
{
const alreadyHavePlugin = alreadyHavePluginWithInternalId('InlineTrace');
if (!alreadyHavePlugin) {
// If we haven't explicitly disabled inline tracing via
// ApolloServerPluginInlineTraceDisabled or explicitly installed our own
// ApolloServerPluginInlineTrace, we set up inline tracing in "only if
// federated" mode. (This is slightly different than the
// pre-ApolloServerPluginInlineTrace where we would also avoid doing
// this if an API key was configured and log a warning.)
const { ApolloServerPluginInlineTrace } = await import(
'./plugin/inlineTrace/index.js'
);
plugins.push(
ApolloServerPluginInlineTrace({ __onlyIfSchemaIsFederated: true }),
);
}
}
// Special case: If we're not in production, show our default landing page.
//
// This works a bit differently from the other implicitly installed plugins,
// which rely entirely on the __internal_plugin_id__ to decide whether the
// plugin takes effect. That's because we want third-party plugins to be
// able to provide a landing page that overrides the default landing page,
// without them having to know about __internal_plugin_id__. So unless we
// actively disable the default landing page with
// ApolloServerPluginLandingPageDisabled, we install the default landing
// page, but with a special flag that _start() uses to ignore it if some
// other plugin defines a renderLandingPage callback. (We can't just look
// now to see if the plugin defines renderLandingPage because we haven't run
// serverWillStart yet.)
const alreadyHavePlugin = alreadyHavePluginWithInternalId(
'LandingPageDisabled',
);
if (!alreadyHavePlugin) {
const {
ApolloServerPluginLandingPageLocalDefault,
ApolloServerPluginLandingPageProductionDefault,
} = await import('./plugin/landingPage/default/index.js');
const plugin: ApolloServerPlugin = isDev
? ApolloServerPluginLandingPageLocalDefault()
: ApolloServerPluginLandingPageProductionDefault();
if (!isImplicitlyInstallablePlugin(plugin)) {
throw Error(
'default landing page plugin should be implicitly installable?',
);
}
plugin.__internal_installed_implicitly__ = true;
plugins.push(plugin);
}
}
public addPlugin(plugin: ApolloServerPlugin) {
if (this.internals.state.phase !== 'initialized') {
throw new Error("Can't add plugins after the server has started");
}
this.internals.plugins.push(plugin);
}
public async executeHTTPGraphQLRequest({
httpGraphQLRequest,
context,
}: {
httpGraphQLRequest: HTTPGraphQLRequest;
context: ContextThunk;
}): Promise {
try {
let runningServerState;
try {
runningServerState = await this._ensureStarted();
} catch (error: unknown) {
// This is typically either the masked error from when background startup
// failed, or related to invoking this function before startup or
// during/after shutdown (due to lack of draining).
return this.errorResponse(error, httpGraphQLRequest);
}
if (
runningServerState.landingPage &&
this.prefersHTML(httpGraphQLRequest)
) {
return {
headers: new HeaderMap([['content-type', 'text/html']]),
body: {
kind: 'complete',
string: runningServerState.landingPage.html,
},
};
}
// If enabled, check to ensure that this request was preflighted before doing
// anything real (such as running the context function).
if (this.internals.csrfPreventionRequestHeaders) {
preventCsrf(
httpGraphQLRequest.headers,
this.internals.csrfPreventionRequestHeaders,
);
}
let contextValue: TContext;
try {
contextValue = await context();
} catch (maybeError: unknown) {
const error = ensureError(maybeError);
try {
await Promise.all(
this.internals.plugins.map(async (plugin) =>
plugin.contextCreationDidFail?.({
error,
}),
),
);
} catch (pluginError) {
this.logger.error(
`contextCreationDidFail hook threw: ${pluginError}`,
);
}
// If some random function threw, add a helpful prefix when converting
// to GraphQLError. If it was already a GraphQLError, trust that the
// message was chosen thoughtfully and leave off the prefix.
return this.errorResponse(
ensureGraphQLError(error, 'Context creation failed: '),
httpGraphQLRequest,
);
}
return await runPotentiallyBatchedHttpQuery(
this,
httpGraphQLRequest,
contextValue,
runningServerState.schemaManager.getSchemaDerivedData(),
this.internals,
);
} catch (maybeError_: unknown) {
const maybeError = maybeError_; // fixes inference because catch vars are not const
if (
maybeError instanceof GraphQLError &&
maybeError.extensions.code === ApolloServerErrorCode.BAD_REQUEST
) {
try {
await Promise.all(
this.internals.plugins.map(async (plugin) =>
plugin.invalidRequestWasReceived?.({ error: maybeError }),
),
);
} catch (pluginError) {
this.logger.error(
`invalidRequestWasReceived hook threw: ${pluginError}`,
);
}
}
return this.errorResponse(maybeError, httpGraphQLRequest);
}
}
private errorResponse(
error: unknown,
requestHead: HTTPGraphQLHead,
): HTTPGraphQLResponse {
const { formattedErrors, httpFromErrors } = normalizeAndFormatErrors(
[error],
{
includeStacktraceInErrorResponses:
this.internals.includeStacktraceInErrorResponses,
formatError: this.internals.formatError,
},
);
return {
status: httpFromErrors.status ?? 500,
headers: new HeaderMap([
...httpFromErrors.headers,
[
'content-type',
// Note that we may change the default to
// 'application/graphql-response+json' by 2025 as encouraged by the
// graphql-over-http spec. It's maybe a bit bad for us to provide
// an application/json response if they send `accept: foo/bar`,
// but we're already providing some sort of bad request error, and
// it's probably more useful for them to fix the other error before
// they deal with the `accept` header.
chooseContentTypeForSingleResultResponse(requestHead) ??
MEDIA_TYPES.APPLICATION_JSON,
],
]),
body: {
kind: 'complete',
string: prettyJSONStringify({
errors: formattedErrors,
}),
},
};
}
private prefersHTML(request: HTTPGraphQLRequest): boolean {
const acceptHeader = request.headers.get('accept');
return (
request.method === 'GET' &&
!!acceptHeader &&
new Negotiator({
headers: { accept: acceptHeader },
}).mediaType([
// We need it to actively prefer text/html over less browser-y types;
// eg, `accept: */*' should still go for JSON. Negotiator does tiebreak
// by the order in the list we provide, so we put text/html last.
MEDIA_TYPES.APPLICATION_JSON,
MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON,
MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL,
MEDIA_TYPES.MULTIPART_MIXED_NO_DEFER_SPEC,
MEDIA_TYPES.TEXT_HTML,
]) === MEDIA_TYPES.TEXT_HTML
);
}
/**
* This method is primarily meant for testing: it allows you to execute a
* GraphQL operation via the request pipeline without going through the HTTP
* layer. Note that this means that any handling you do in your server at the
* HTTP level will not affect this call!
*
* For convenience, you can provide `request.query` either as a string or a
* DocumentNode, in case you choose to use the gql tag in your tests. This is
* just a convenience, not an optimization (we convert provided ASTs back into
* string).
*
* The second object is an optional options object which includes the optional
* `contextValue` object available in resolvers.
*
* You may specify the TData and TVariables generic types when calling this
* method; Apollo Server does not validate that the returned data actually
* matches the structure of TData. (Typically these types are created by a
* code generation tool.) Note that this does not enforce that `variables` is
* provided at all, just that it has the right type if provided.
*/
public async executeOperation<
TData = Record,
TVariables extends VariableValues = VariableValues,
>(
this: ApolloServer,
request: Omit, 'query'> & {
query?: string | DocumentNode | TypedQueryDocumentNode;
},
): Promise>;
public async executeOperation<
TData = Record,
TVariables extends VariableValues = VariableValues,
>(
request: Omit, 'query'> & {
query?: string | DocumentNode | TypedQueryDocumentNode;
},
options?: ExecuteOperationOptions,
): Promise>;
async executeOperation<
TData = Record,
TVariables extends VariableValues = VariableValues,
>(
request: Omit, 'query'> & {
// We should consider supporting TypedDocumentNode from
// `@graphql-typed-document-node/core` as well, as it is more popular than
// the newer built-in type.
query?: string | DocumentNode | TypedQueryDocumentNode;
},
options: ExecuteOperationOptions = {},
): Promise