776 lines
36 KiB
JavaScript
776 lines
36 KiB
JavaScript
"use strict";
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
var t = {};
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
t[p] = s[p];
|
|
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
t[p[i]] = s[p[i]];
|
|
}
|
|
return t;
|
|
};
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ApolloServerBase = void 0;
|
|
const graphql_tools_1 = require("graphql-tools");
|
|
const net_1 = require("net");
|
|
const tls_1 = require("tls");
|
|
const loglevel_1 = __importDefault(require("loglevel"));
|
|
const graphql_1 = require("graphql");
|
|
const resolvable_1 = __importDefault(require("@josephg/resolvable"));
|
|
const apollo_server_caching_1 = require("apollo-server-caching");
|
|
const runtimeSupportsUploads_1 = __importDefault(require("./utils/runtimeSupportsUploads"));
|
|
const apollo_server_errors_1 = require("apollo-server-errors");
|
|
const index_1 = require("./index");
|
|
const playground_1 = require("./playground");
|
|
const schemaHash_1 = require("./utils/schemaHash");
|
|
const isDirectiveDefined_1 = require("./utils/isDirectiveDefined");
|
|
const requestPipeline_1 = require("./requestPipeline");
|
|
const apollo_server_env_1 = require("apollo-server-env");
|
|
const apollo_tools_1 = require("@apollographql/apollo-tools");
|
|
const apollo_tracing_1 = require("apollo-tracing");
|
|
const apollo_cache_control_1 = require("apollo-cache-control");
|
|
const runHttpQuery_1 = require("./runHttpQuery");
|
|
const isNodeLike_1 = __importDefault(require("./utils/isNodeLike"));
|
|
const determineApolloConfig_1 = require("./determineApolloConfig");
|
|
const plugin_1 = require("./plugin");
|
|
const internalPlugin_1 = require("./plugin/internalPlugin");
|
|
const NoIntrospection = (context) => ({
|
|
Field(node) {
|
|
if (node.name.value === '__schema' || node.name.value === '__type') {
|
|
context.reportError(new graphql_1.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', [node]));
|
|
}
|
|
},
|
|
});
|
|
const forbidUploadsForTesting = process && process.env.NODE_ENV === 'test' && !runtimeSupportsUploads_1.default;
|
|
function approximateObjectSize(obj) {
|
|
return Buffer.byteLength(JSON.stringify(obj), 'utf8');
|
|
}
|
|
class UnreachableCaseError extends Error {
|
|
constructor(val) {
|
|
super(`Unreachable case: ${val}`);
|
|
}
|
|
}
|
|
class ApolloServerBase {
|
|
constructor(config) {
|
|
this.graphqlPath = '/graphql';
|
|
this.requestOptions = Object.create(null);
|
|
this.plugins = [];
|
|
this.toDispose = new Set();
|
|
this.toDisposeLast = new Set();
|
|
if (!config)
|
|
throw new Error('ApolloServer requires options.');
|
|
this.config = config;
|
|
const { context, resolvers, schema, schemaDirectives, modules, typeDefs, parseOptions = {}, introspection, mocks, mockEntireSchema, extensions, subscriptions, uploads, playground, plugins, gateway, cacheControl, experimental_approximateDocumentStoreMiB, stopOnTerminationSignals, apollo, engine } = config, requestOptions = __rest(config, ["context", "resolvers", "schema", "schemaDirectives", "modules", "typeDefs", "parseOptions", "introspection", "mocks", "mockEntireSchema", "extensions", "subscriptions", "uploads", "playground", "plugins", "gateway", "cacheControl", "experimental_approximateDocumentStoreMiB", "stopOnTerminationSignals", "apollo", "engine"]);
|
|
if (engine !== undefined && apollo) {
|
|
throw new Error('You cannot provide both `engine` and `apollo` to `new ApolloServer()`. ' +
|
|
'For details on how to migrate all of your options out of `engine`, see ' +
|
|
'https://go.apollo.dev/s/migration-engine-plugins');
|
|
}
|
|
if (config.logger) {
|
|
this.logger = config.logger;
|
|
}
|
|
else {
|
|
const loglevelLogger = loglevel_1.default.getLogger('apollo-server');
|
|
if (this.config.debug === true) {
|
|
loglevelLogger.setLevel(loglevel_1.default.levels.DEBUG);
|
|
}
|
|
else {
|
|
loglevelLogger.setLevel(loglevel_1.default.levels.INFO);
|
|
}
|
|
this.logger = loglevelLogger;
|
|
}
|
|
this.apolloConfig = determineApolloConfig_1.determineApolloConfig(apollo, engine, this.logger);
|
|
if (gateway && (modules || schema || typeDefs || resolvers)) {
|
|
throw new Error('Cannot define both `gateway` and any of: `modules`, `schema`, `typeDefs`, or `resolvers`');
|
|
}
|
|
this.parseOptions = parseOptions;
|
|
this.context = context;
|
|
const isDev = process.env.NODE_ENV !== 'production';
|
|
if ((typeof introspection === 'boolean' && !introspection) ||
|
|
(introspection === undefined && !isDev)) {
|
|
const noIntro = [NoIntrospection];
|
|
requestOptions.validationRules = requestOptions.validationRules
|
|
? requestOptions.validationRules.concat(noIntro)
|
|
: noIntro;
|
|
}
|
|
if (!requestOptions.cache) {
|
|
requestOptions.cache = new apollo_server_caching_1.InMemoryLRUCache();
|
|
}
|
|
if (requestOptions.persistedQueries !== false) {
|
|
const _a = requestOptions.persistedQueries || Object.create(null), { cache: apqCache = requestOptions.cache } = _a, apqOtherOptions = __rest(_a, ["cache"]);
|
|
requestOptions.persistedQueries = Object.assign({ cache: new apollo_server_caching_1.PrefixingKeyValueCache(apqCache, requestPipeline_1.APQ_CACHE_PREFIX) }, apqOtherOptions);
|
|
}
|
|
else {
|
|
delete requestOptions.persistedQueries;
|
|
}
|
|
this.requestOptions = requestOptions;
|
|
this.disableUploadsIfSchemaDoesNotUseUploadScalar = false;
|
|
if (uploads !== false && !forbidUploadsForTesting) {
|
|
if (this.supportsUploads()) {
|
|
if (!runtimeSupportsUploads_1.default) {
|
|
printNodeFileUploadsMessage(this.logger);
|
|
throw new Error('`graphql-upload` is no longer supported on Node.js < v8.5.0. ' +
|
|
'See https://bit.ly/gql-upload-node-6.');
|
|
}
|
|
if (uploads === true) {
|
|
this.uploadsConfig = {};
|
|
warnAboutUploads(this.logger, false);
|
|
}
|
|
else if (typeof uploads === 'undefined') {
|
|
this.uploadsConfig = {};
|
|
this.disableUploadsIfSchemaDoesNotUseUploadScalar = true;
|
|
}
|
|
else {
|
|
this.uploadsConfig = uploads;
|
|
warnAboutUploads(this.logger, false);
|
|
}
|
|
}
|
|
else if (uploads) {
|
|
throw new Error('This implementation of ApolloServer does not support file uploads because the environment cannot accept multi-part forms');
|
|
}
|
|
}
|
|
if (gateway && subscriptions !== false) {
|
|
throw new Error([
|
|
'Subscriptions are not yet compatible with the gateway.',
|
|
"Set `subscriptions: false` in Apollo Server's constructor to",
|
|
'explicitly disable subscriptions (which are on by default)',
|
|
'and allow for gateway functionality.',
|
|
].join(' '));
|
|
}
|
|
else if (subscriptions !== false) {
|
|
if (this.supportsSubscriptions()) {
|
|
if (subscriptions === true || typeof subscriptions === 'undefined') {
|
|
this.subscriptionServerOptions = {
|
|
path: this.graphqlPath,
|
|
};
|
|
}
|
|
else if (typeof subscriptions === 'string') {
|
|
this.subscriptionServerOptions = { path: subscriptions };
|
|
}
|
|
else {
|
|
this.subscriptionServerOptions = Object.assign({ path: this.graphqlPath }, subscriptions);
|
|
}
|
|
this.subscriptionsPath = this.subscriptionServerOptions.path;
|
|
}
|
|
else if (subscriptions) {
|
|
throw new Error('This implementation of ApolloServer does not support GraphQL subscriptions.');
|
|
}
|
|
}
|
|
this.playgroundOptions = playground_1.createPlaygroundOptions(playground);
|
|
this.ensurePluginInstantiation(plugins);
|
|
if (typeof stopOnTerminationSignals === 'boolean'
|
|
? stopOnTerminationSignals
|
|
: typeof engine === 'object' &&
|
|
typeof engine.handleSignals === 'boolean'
|
|
? engine.handleSignals
|
|
: isNodeLike_1.default && process.env.NODE_ENV !== 'test') {
|
|
const signals = ['SIGINT', 'SIGTERM'];
|
|
let receivedSignal = false;
|
|
signals.forEach((signal) => {
|
|
const handler = () => __awaiter(this, void 0, void 0, function* () {
|
|
if (receivedSignal) {
|
|
return;
|
|
}
|
|
receivedSignal = true;
|
|
try {
|
|
yield this.stop();
|
|
}
|
|
catch (e) {
|
|
this.logger.error(`stop() threw during ${signal} shutdown`);
|
|
this.logger.error(e);
|
|
process.exit(1);
|
|
}
|
|
process.kill(process.pid, signal);
|
|
});
|
|
process.on(signal, handler);
|
|
this.toDisposeLast.add(() => __awaiter(this, void 0, void 0, function* () {
|
|
process.removeListener(signal, handler);
|
|
}));
|
|
});
|
|
}
|
|
if (gateway) {
|
|
this.state = { phase: 'initialized with gateway', gateway };
|
|
this.requestOptions.executor = gateway.executor;
|
|
}
|
|
else {
|
|
this.state = {
|
|
phase: 'initialized with schema',
|
|
schemaDerivedData: this.generateSchemaDerivedData(this.constructSchema()),
|
|
};
|
|
this.schema = this.state.schemaDerivedData.schema;
|
|
}
|
|
if (this.serverlessFramework()) {
|
|
this.ensureStarting();
|
|
}
|
|
}
|
|
setGraphQLPath(path) {
|
|
this.graphqlPath = path;
|
|
}
|
|
start() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (this.serverlessFramework()) {
|
|
throw new Error('When using an ApolloServer subclass from a serverless framework ' +
|
|
"package, you don't need to call start(); just call createHandler().");
|
|
}
|
|
return yield this._start();
|
|
});
|
|
}
|
|
_start() {
|
|
var _a;
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const initialState = this.state;
|
|
if (initialState.phase !== 'initialized with gateway' &&
|
|
initialState.phase !== 'initialized with schema') {
|
|
throw new Error(`called start() with surprising state ${initialState.phase}`);
|
|
}
|
|
const barrier = resolvable_1.default();
|
|
this.state = { phase: 'starting', barrier };
|
|
let loadedSchema = false;
|
|
try {
|
|
const schemaDerivedData = initialState.phase === 'initialized with schema'
|
|
? initialState.schemaDerivedData
|
|
: this.generateSchemaDerivedData(yield this.startGatewayAndLoadSchema(initialState.gateway));
|
|
loadedSchema = true;
|
|
this.state = {
|
|
phase: 'invoking serverWillStart',
|
|
barrier,
|
|
schemaDerivedData,
|
|
};
|
|
const service = {
|
|
logger: this.logger,
|
|
schema: schemaDerivedData.schema,
|
|
schemaHash: schemaDerivedData.schemaHash,
|
|
apollo: this.apolloConfig,
|
|
serverlessFramework: this.serverlessFramework(),
|
|
engine: {
|
|
serviceID: this.apolloConfig.graphId,
|
|
apiKeyHash: this.apolloConfig.keyHash,
|
|
},
|
|
};
|
|
if ((_a = this.requestOptions.persistedQueries) === null || _a === void 0 ? void 0 : _a.cache) {
|
|
service.persistedQueries = {
|
|
cache: this.requestOptions.persistedQueries.cache,
|
|
};
|
|
}
|
|
const serverListeners = (yield Promise.all(this.plugins.map((plugin) => plugin.serverWillStart && plugin.serverWillStart(service)))).filter((maybeServerListener) => typeof maybeServerListener === 'object' &&
|
|
!!maybeServerListener.serverWillStop);
|
|
this.toDispose.add(() => __awaiter(this, void 0, void 0, function* () {
|
|
yield Promise.all(serverListeners.map(({ serverWillStop }) => serverWillStop === null || serverWillStop === void 0 ? void 0 : serverWillStop()));
|
|
}));
|
|
this.state = { phase: 'started', schemaDerivedData };
|
|
}
|
|
catch (error) {
|
|
this.state = { phase: 'failed to start', error, loadedSchema };
|
|
throw error;
|
|
}
|
|
finally {
|
|
barrier.resolve();
|
|
}
|
|
});
|
|
}
|
|
willStart() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
this.ensureStarting();
|
|
});
|
|
}
|
|
ensureStarted() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
while (true) {
|
|
switch (this.state.phase) {
|
|
case 'initialized with gateway':
|
|
case 'initialized with schema':
|
|
try {
|
|
yield this._start();
|
|
}
|
|
catch (_a) {
|
|
}
|
|
break;
|
|
case 'starting':
|
|
case 'invoking serverWillStart':
|
|
yield this.state.barrier;
|
|
break;
|
|
case 'failed to start':
|
|
this.logStartupError(this.state.error);
|
|
throw new Error('This data graph is missing a valid configuration. More details may be available in the server logs.');
|
|
case 'started':
|
|
return this.state.schemaDerivedData;
|
|
case 'stopping':
|
|
throw new Error('Cannot execute GraphQL operations while the server is stopping.');
|
|
case 'stopped':
|
|
throw new Error('Cannot execute GraphQL operations after the server has stopped.');
|
|
default:
|
|
throw new UnreachableCaseError(this.state);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
ensureStarting() {
|
|
if (this.state.phase === 'initialized with gateway' ||
|
|
this.state.phase === 'initialized with schema') {
|
|
this._start().catch((e) => this.logStartupError(e));
|
|
}
|
|
}
|
|
logStartupError(err) {
|
|
const prelude = this.serverlessFramework()
|
|
? 'An error occurred during Apollo Server startup.'
|
|
: 'Apollo Server was started implicitly and an error occurred during startup. ' +
|
|
'(Consider calling `await server.start()` immediately after ' +
|
|
'`server = new ApolloServer()` so you can handle these errors directly before ' +
|
|
'starting your web server.)';
|
|
this.logger.error(prelude +
|
|
' All GraphQL requests will now fail. The startup error ' +
|
|
'was: ' +
|
|
((err && err.message) || err));
|
|
}
|
|
startGatewayAndLoadSchema(gateway) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const unsubscriber = gateway.onSchemaChange((schema) => {
|
|
if (this.state.phase === 'started') {
|
|
this.state.schemaDerivedData = this.generateSchemaDerivedData(schema);
|
|
}
|
|
});
|
|
this.toDispose.add(() => __awaiter(this, void 0, void 0, function* () { return unsubscriber(); }));
|
|
const engineConfig = this.apolloConfig.keyHash && this.apolloConfig.graphId
|
|
? {
|
|
apiKeyHash: this.apolloConfig.keyHash,
|
|
graphId: this.apolloConfig.graphId,
|
|
graphVariant: this.apolloConfig.graphVariant,
|
|
}
|
|
: undefined;
|
|
const config = yield gateway.load({
|
|
apollo: this.apolloConfig,
|
|
engine: engineConfig,
|
|
});
|
|
this.toDispose.add(() => __awaiter(this, void 0, void 0, function* () { var _a; return yield ((_a = gateway.stop) === null || _a === void 0 ? void 0 : _a.call(gateway)); }));
|
|
return config.schema;
|
|
});
|
|
}
|
|
constructSchema() {
|
|
const { schema, modules, typeDefs, resolvers, schemaDirectives, parseOptions, } = this.config;
|
|
if (schema) {
|
|
return schema;
|
|
}
|
|
if (modules) {
|
|
const { schema, errors } = apollo_tools_1.buildServiceDefinition(modules);
|
|
if (errors && errors.length > 0) {
|
|
throw new Error(errors.map((error) => error.message).join('\n\n'));
|
|
}
|
|
return schema;
|
|
}
|
|
if (!typeDefs) {
|
|
throw Error('Apollo Server requires either an existing schema, modules or typeDefs');
|
|
}
|
|
const augmentedTypeDefs = Array.isArray(typeDefs) ? typeDefs : [typeDefs];
|
|
if (!isDirectiveDefined_1.isDirectiveDefined(augmentedTypeDefs, 'cacheControl')) {
|
|
augmentedTypeDefs.push(index_1.gql `
|
|
enum CacheControlScope {
|
|
PUBLIC
|
|
PRIVATE
|
|
}
|
|
|
|
directive @cacheControl(
|
|
maxAge: Int
|
|
scope: CacheControlScope
|
|
) on FIELD_DEFINITION | OBJECT | INTERFACE
|
|
`);
|
|
}
|
|
if (this.uploadsConfig) {
|
|
const { GraphQLUpload } = require('@apollographql/graphql-upload-8-fork');
|
|
if (Array.isArray(resolvers)) {
|
|
if (resolvers.every((resolver) => !resolver.Upload)) {
|
|
resolvers.push({ Upload: GraphQLUpload });
|
|
}
|
|
}
|
|
else {
|
|
if (resolvers && !resolvers.Upload) {
|
|
resolvers.Upload = GraphQLUpload;
|
|
}
|
|
}
|
|
augmentedTypeDefs.push(index_1.gql `
|
|
scalar Upload
|
|
`);
|
|
}
|
|
return graphql_tools_1.makeExecutableSchema({
|
|
typeDefs: augmentedTypeDefs,
|
|
schemaDirectives,
|
|
resolvers,
|
|
parseOptions,
|
|
});
|
|
}
|
|
generateSchemaDerivedData(schema) {
|
|
const schemaHash = schemaHash_1.generateSchemaHash(schema);
|
|
const { mocks, mockEntireSchema, extensions: _extensions } = this.config;
|
|
if (mocks || (typeof mockEntireSchema !== 'undefined' && mocks !== false)) {
|
|
graphql_tools_1.addMockFunctionsToSchema({
|
|
schema,
|
|
mocks: typeof mocks === 'boolean' || typeof mocks === 'undefined'
|
|
? {}
|
|
: mocks,
|
|
preserveResolvers: typeof mockEntireSchema === 'undefined' ? false : !mockEntireSchema,
|
|
});
|
|
}
|
|
const extensions = [];
|
|
extensions.push(...(_extensions || []));
|
|
const documentStore = this.initializeDocumentStore();
|
|
let disableUploads = false;
|
|
if (this.disableUploadsIfSchemaDoesNotUseUploadScalar) {
|
|
const ast = graphql_1.parse(graphql_1.printSchema(schema));
|
|
disableUploads = true;
|
|
graphql_1.visit(ast, {
|
|
NamedType(node) {
|
|
if (node.name.value === 'Upload') {
|
|
disableUploads = false;
|
|
}
|
|
}
|
|
});
|
|
if (!disableUploads) {
|
|
warnAboutUploads(this.logger, true);
|
|
}
|
|
}
|
|
return {
|
|
schema,
|
|
schemaHash,
|
|
extensions,
|
|
documentStore,
|
|
disableUploads,
|
|
};
|
|
}
|
|
disableUploads() {
|
|
return this.state.phase !== 'started' || this.state.schemaDerivedData.disableUploads;
|
|
}
|
|
stop() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (this.state.phase === 'stopped') {
|
|
if (this.state.stopError) {
|
|
throw this.state.stopError;
|
|
}
|
|
return;
|
|
}
|
|
if (this.state.phase === 'stopping') {
|
|
yield this.state.barrier;
|
|
const state = this.state;
|
|
if (state.phase !== 'stopped') {
|
|
throw Error(`Surprising post-stopping state ${state.phase}`);
|
|
}
|
|
if (state.stopError) {
|
|
throw state.stopError;
|
|
}
|
|
return;
|
|
}
|
|
this.state = { phase: 'stopping', barrier: resolvable_1.default() };
|
|
try {
|
|
yield Promise.all([...this.toDispose].map((dispose) => dispose()));
|
|
if (this.subscriptionServer)
|
|
this.subscriptionServer.close();
|
|
yield Promise.all([...this.toDisposeLast].map((dispose) => dispose()));
|
|
}
|
|
catch (stopError) {
|
|
this.state = { phase: 'stopped', stopError };
|
|
return;
|
|
}
|
|
this.state = { phase: 'stopped', stopError: null };
|
|
});
|
|
}
|
|
installSubscriptionHandlers(server) {
|
|
if (!this.subscriptionServerOptions) {
|
|
if (this.config.gateway) {
|
|
throw Error('Subscriptions are not supported when operating as a gateway');
|
|
}
|
|
if (this.supportsSubscriptions()) {
|
|
throw Error('Subscriptions are disabled, due to subscriptions set to false in the ApolloServer constructor');
|
|
}
|
|
else {
|
|
throw Error('Subscriptions are not supported, choose an integration, such as apollo-server-express that allows persistent connections');
|
|
}
|
|
}
|
|
const { SubscriptionServer } = require('subscriptions-transport-ws');
|
|
const { onDisconnect, onConnect, keepAlive, path, } = this.subscriptionServerOptions;
|
|
let schema;
|
|
switch (this.state.phase) {
|
|
case 'initialized with schema':
|
|
case 'invoking serverWillStart':
|
|
case 'started':
|
|
schema = this.state.schemaDerivedData.schema;
|
|
break;
|
|
case 'initialized with gateway':
|
|
case 'starting':
|
|
case 'failed to start':
|
|
case 'stopping':
|
|
case 'stopped':
|
|
throw new Error(`Can't install subscription handlers when state is ${this.state.phase}`);
|
|
default:
|
|
throw new UnreachableCaseError(this.state);
|
|
}
|
|
this.subscriptionServer = SubscriptionServer.create({
|
|
schema,
|
|
execute: graphql_1.execute,
|
|
subscribe: graphql_1.subscribe,
|
|
onConnect: onConnect
|
|
? onConnect
|
|
: (connectionParams) => (Object.assign({}, connectionParams)),
|
|
onDisconnect: onDisconnect,
|
|
onOperation: (message, connection) => __awaiter(this, void 0, void 0, function* () {
|
|
connection.formatResponse = (value) => (Object.assign(Object.assign({}, value), { errors: value.errors &&
|
|
apollo_server_errors_1.formatApolloErrors([...value.errors], {
|
|
formatter: this.requestOptions.formatError,
|
|
debug: this.requestOptions.debug,
|
|
}) }));
|
|
connection.formatError = this.requestOptions.formatError;
|
|
let context = this.context ? this.context : { connection };
|
|
try {
|
|
context =
|
|
typeof this.context === 'function'
|
|
? yield this.context({ connection, payload: message.payload })
|
|
: context;
|
|
}
|
|
catch (e) {
|
|
throw apollo_server_errors_1.formatApolloErrors([e], {
|
|
formatter: this.requestOptions.formatError,
|
|
debug: this.requestOptions.debug,
|
|
})[0];
|
|
}
|
|
return Object.assign(Object.assign({}, connection), { context });
|
|
}),
|
|
keepAlive,
|
|
validationRules: this.requestOptions.validationRules,
|
|
}, server instanceof net_1.Server || server instanceof tls_1.Server
|
|
? {
|
|
server,
|
|
path,
|
|
}
|
|
: server);
|
|
}
|
|
supportsSubscriptions() {
|
|
return false;
|
|
}
|
|
supportsUploads() {
|
|
return false;
|
|
}
|
|
serverlessFramework() {
|
|
return false;
|
|
}
|
|
ensurePluginInstantiation(plugins = []) {
|
|
var _a, _b;
|
|
const pluginsToInit = [];
|
|
if (this.config.tracing) {
|
|
pluginsToInit.push(apollo_tracing_1.plugin());
|
|
}
|
|
if (this.config.cacheControl !== false) {
|
|
let cacheControlOptions = {};
|
|
if (typeof this.config.cacheControl === 'boolean' &&
|
|
this.config.cacheControl === true) {
|
|
cacheControlOptions = {
|
|
stripFormattedExtensions: false,
|
|
calculateHttpHeaders: false,
|
|
defaultMaxAge: 0,
|
|
};
|
|
}
|
|
else {
|
|
cacheControlOptions = Object.assign({ stripFormattedExtensions: true, calculateHttpHeaders: true, defaultMaxAge: 0 }, this.config.cacheControl);
|
|
}
|
|
pluginsToInit.push(apollo_cache_control_1.plugin(cacheControlOptions));
|
|
}
|
|
pluginsToInit.push(...plugins);
|
|
this.plugins = pluginsToInit.map((plugin) => {
|
|
if (typeof plugin === 'function') {
|
|
return plugin();
|
|
}
|
|
return plugin;
|
|
});
|
|
const alreadyHavePluginWithInternalId = (id) => this.plugins.some((p) => internalPlugin_1.pluginIsInternal(p) && p.__internal_plugin_id__() === id);
|
|
{
|
|
const alreadyHavePlugin = alreadyHavePluginWithInternalId('UsageReporting');
|
|
const { engine } = this.config;
|
|
const disabledViaLegacyOption = engine === false ||
|
|
(typeof engine === 'object' && engine.reportTiming === false);
|
|
if (alreadyHavePlugin) {
|
|
if (engine !== undefined) {
|
|
throw Error("You can't combine the legacy `new ApolloServer({engine})` option with directly " +
|
|
'creating an ApolloServerPluginUsageReporting plugin. See ' +
|
|
'https://go.apollo.dev/s/migration-engine-plugins');
|
|
}
|
|
}
|
|
else if (this.apolloConfig.key && !disabledViaLegacyOption) {
|
|
this.plugins.unshift(typeof engine === 'object'
|
|
? plugin_1.ApolloServerPluginUsageReportingFromLegacyOptions(engine)
|
|
: plugin_1.ApolloServerPluginUsageReporting());
|
|
}
|
|
}
|
|
{
|
|
const alreadyHavePlugin = alreadyHavePluginWithInternalId('SchemaReporting');
|
|
const enabledViaEnvVar = process.env.APOLLO_SCHEMA_REPORTING === 'true';
|
|
const { engine } = this.config;
|
|
const enabledViaLegacyOption = typeof engine === 'object' &&
|
|
(engine.reportSchema || engine.experimental_schemaReporting);
|
|
if (alreadyHavePlugin || enabledViaEnvVar || enabledViaLegacyOption) {
|
|
if (this.config.gateway) {
|
|
throw new Error([
|
|
"Schema reporting is not yet compatible with the gateway. If you're",
|
|
'interested in using schema reporting with the gateway, please',
|
|
'contact Apollo support. To set up managed federation, see',
|
|
'https://go.apollo.dev/s/managed-federation',
|
|
].join(' '));
|
|
}
|
|
}
|
|
if (alreadyHavePlugin) {
|
|
if (engine !== undefined) {
|
|
throw Error("You can't combine the legacy `new ApolloServer({engine})` option with directly " +
|
|
'creating an ApolloServerPluginSchemaReporting plugin. See ' +
|
|
'https://go.apollo.dev/s/migration-engine-plugins');
|
|
}
|
|
}
|
|
else if (!this.apolloConfig.key) {
|
|
if (enabledViaEnvVar) {
|
|
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})');
|
|
}
|
|
if (enabledViaLegacyOption) {
|
|
throw new Error("You've enabled schema reporting in the `engine` argument to `new ApolloServer()`, " +
|
|
'but you also need to provide your Apollo API key, via the APOLLO_KEY environment ' +
|
|
'variable or via `new ApolloServer({apollo: {key})');
|
|
}
|
|
}
|
|
else if (enabledViaEnvVar || enabledViaLegacyOption) {
|
|
const options = {};
|
|
if (typeof engine === 'object') {
|
|
options.initialDelayMaxMs = (_a = engine.schemaReportingInitialDelayMaxMs) !== null && _a !== void 0 ? _a : engine.experimental_schemaReportingInitialDelayMaxMs;
|
|
options.overrideReportedSchema = (_b = engine.overrideReportedSchema) !== null && _b !== void 0 ? _b : engine.experimental_overrideReportedSchema;
|
|
options.endpointUrl = engine.schemaReportingUrl;
|
|
}
|
|
this.plugins.push(plugin_1.ApolloServerPluginSchemaReporting(options));
|
|
}
|
|
}
|
|
{
|
|
const alreadyHavePlugin = alreadyHavePluginWithInternalId('InlineTrace');
|
|
const { engine } = this.config;
|
|
if (alreadyHavePlugin) {
|
|
if (engine !== undefined) {
|
|
throw Error("You can't combine the legacy `new ApolloServer({engine})` option with directly " +
|
|
'creating an ApolloServerPluginInlineTrace plugin. See ' +
|
|
'https://go.apollo.dev/s/migration-engine-plugins');
|
|
}
|
|
}
|
|
else if (this.config.engine !== false) {
|
|
const options = {
|
|
__onlyIfSchemaIsFederated: true,
|
|
};
|
|
if (typeof engine === 'object') {
|
|
options.rewriteError = engine.rewriteError;
|
|
}
|
|
this.plugins.push(plugin_1.ApolloServerPluginInlineTrace(options));
|
|
}
|
|
}
|
|
}
|
|
initializeDocumentStore() {
|
|
return new apollo_server_caching_1.InMemoryLRUCache({
|
|
maxSize: Math.pow(2, 20) * (this.experimental_approximateDocumentStoreMiB || 30),
|
|
sizeCalculator: approximateObjectSize,
|
|
});
|
|
}
|
|
graphQLServerOptions(integrationContextArgument) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const { schema, schemaHash, documentStore, extensions, } = yield this.ensureStarted();
|
|
let context = this.context ? this.context : {};
|
|
try {
|
|
context =
|
|
typeof this.context === 'function'
|
|
? yield this.context(integrationContextArgument || {})
|
|
: context;
|
|
}
|
|
catch (error) {
|
|
context = () => {
|
|
throw error;
|
|
};
|
|
}
|
|
return Object.assign({ schema,
|
|
schemaHash, logger: this.logger, plugins: this.plugins, documentStore,
|
|
extensions,
|
|
context, persistedQueries: this.requestOptions
|
|
.persistedQueries, fieldResolver: this.requestOptions.fieldResolver, parseOptions: this.parseOptions }, this.requestOptions);
|
|
});
|
|
}
|
|
executeOperation(request, integrationContextArgument) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const options = yield this.graphQLServerOptions(integrationContextArgument);
|
|
if (typeof options.context === 'function') {
|
|
options.context = options.context();
|
|
}
|
|
else if (typeof options.context === 'object') {
|
|
options.context = runHttpQuery_1.cloneObject(options.context);
|
|
}
|
|
const requestCtx = {
|
|
logger: this.logger,
|
|
schema: options.schema,
|
|
schemaHash: options.schemaHash,
|
|
request: Object.assign(Object.assign({}, request), { query: request.query && typeof request.query !== 'string'
|
|
? graphql_1.print(request.query)
|
|
: request.query }),
|
|
context: options.context || Object.create(null),
|
|
cache: options.cache,
|
|
metrics: {},
|
|
response: {
|
|
http: {
|
|
headers: new apollo_server_env_1.Headers(),
|
|
},
|
|
},
|
|
debug: options.debug,
|
|
};
|
|
return requestPipeline_1.processGraphQLRequest(options, requestCtx);
|
|
});
|
|
}
|
|
}
|
|
exports.ApolloServerBase = ApolloServerBase;
|
|
function printNodeFileUploadsMessage(logger) {
|
|
logger.error([
|
|
'*****************************************************************',
|
|
'* *',
|
|
'* ERROR! Manual intervention is necessary for Node.js < v8.5.0! *',
|
|
'* *',
|
|
'*****************************************************************',
|
|
'',
|
|
'The third-party `graphql-upload` package, which is used to implement',
|
|
'file uploads in Apollo Server 2.x, no longer supports Node.js LTS',
|
|
'versions prior to Node.js v8.5.0.',
|
|
'',
|
|
'Deployments which NEED file upload capabilities should update to',
|
|
'Node.js >= v8.5.0 to continue using uploads.',
|
|
'',
|
|
'If this server DOES NOT NEED file uploads and wishes to continue',
|
|
'using this version of Node.js, uploads can be disabled by adding:',
|
|
'',
|
|
' uploads: false,',
|
|
'',
|
|
'...to the options for Apollo Server and re-deploying the server.',
|
|
'',
|
|
'For more information, see https://bit.ly/gql-upload-node-6.',
|
|
'',
|
|
].join('\n'));
|
|
}
|
|
function warnAboutUploads(logger, implicit) {
|
|
logger.error([
|
|
'The third-party `graphql-upload` package is enabled in your server',
|
|
(implicit
|
|
? 'because you use the `Upload` scalar in your schema.'
|
|
: 'because you explicitly enabled it with the `uploads` option.'),
|
|
'This package is vulnerable to Cross-Site Request Forgery (CSRF) attacks.',
|
|
'We recommend you either disable uploads if it is not a necessary part of',
|
|
'your server, or upgrade to Apollo Server 3.7 and enable CSRF prevention.',
|
|
'See https://go.apollo.dev/s/graphql-upload-csrf for more details.',
|
|
].join('\n'));
|
|
}
|
|
//# sourceMappingURL=ApolloServer.js.map
|