"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.chooseContentTypeForSingleResultResponse = exports.MEDIA_TYPES = exports.isImplicitlyInstallablePlugin = exports.internalExecuteOperation = exports.ApolloServer = void 0;
const utils_isnodelike_1 = require("@apollo/utils.isnodelike");
const utils_keyvaluecache_1 = require("@apollo/utils.keyvaluecache");
const schema_1 = require("@graphql-tools/schema");
const resolvable_js_1 = __importDefault(require("./utils/resolvable.js"));
const graphql_1 = require("graphql");
const loglevel_1 = __importDefault(require("loglevel"));
const negotiator_1 = __importDefault(require("negotiator"));
const cachePolicy_js_1 = require("./cachePolicy.js");
const determineApolloConfig_js_1 = require("./determineApolloConfig.js");
const errorNormalize_js_1 = require("./errorNormalize.js");
const index_js_1 = require("./errors/index.js");
const httpBatching_js_1 = require("./httpBatching.js");
const internalPlugin_js_1 = require("./internalPlugin.js");
const preventCsrf_js_1 = require("./preventCsrf.js");
const requestPipeline_js_1 = require("./requestPipeline.js");
const runHttpQuery_js_1 = require("./runHttpQuery.js");
const HeaderMap_js_1 = require("./utils/HeaderMap.js");
const UnreachableCaseError_js_1 = require("./utils/UnreachableCaseError.js");
const computeCoreSchemaHash_js_1 = require("./utils/computeCoreSchemaHash.js");
const isDefined_js_1 = require("./utils/isDefined.js");
const schemaManager_js_1 = require("./utils/schemaManager.js");
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', {
                nodes: [node],
                extensions: {
                    validationErrorCode: index_js_1.ApolloServerValidationErrorCode.INTROSPECTION_DISABLED,
                },
            }));
        }
    },
});
function defaultLogger() {
    const loglevelLogger = loglevel_1.default.getLogger('apollo-server');
    loglevelLogger.setLevel(loglevel_1.default.levels.INFO);
    return loglevelLogger;
}
class ApolloServer {
    constructor(config) {
        const nodeEnv = config.nodeEnv ?? process.env.NODE_ENV ?? '';
        this.logger = config.logger ?? defaultLogger();
        const apolloConfig = (0, determineApolloConfig_js_1.determineApolloConfig)(config.apollo, this.logger);
        const isDev = nodeEnv !== 'production';
        if (config.cache &&
            config.cache !== 'bounded' &&
            utils_keyvaluecache_1.PrefixingKeyValueCache.prefixesAreUnnecessaryForIsolation(config.cache)) {
            throw new Error('You cannot pass a cache returned from ' +
                '`PrefixingKeyValueCache.cacheDangerouslyDoesNotNeedPrefixesForIsolation`' +
                'to `new ApolloServer({ cache })`, because Apollo Server may use it for ' +
                'multiple features whose cache keys must be distinct from each other.');
        }
        const state = config.gateway
            ?
                {
                    phase: 'initialized',
                    schemaManager: new schemaManager_js_1.SchemaManager({
                        gateway: config.gateway,
                        apolloConfig,
                        schemaDerivedDataProvider: (schema) => ApolloServer.generateSchemaDerivedData(schema, config.documentStore),
                        logger: this.logger,
                    }),
                }
            :
                {
                    phase: 'initialized',
                    schemaManager: new schemaManager_js_1.SchemaManager({
                        apiSchema: ApolloServer.constructSchema(config),
                        schemaDerivedDataProvider: (schema) => ApolloServer.generateSchemaDerivedData(schema, config.documentStore),
                        logger: this.logger,
                    }),
                };
        const introspectionEnabled = config.introspection ?? isDev;
        const hideSchemaDetailsFromClientErrors = config.hideSchemaDetailsFromClientErrors ?? false;
        this.cache =
            config.cache === undefined || config.cache === 'bounded'
                ? new utils_keyvaluecache_1.InMemoryLRUCache()
                : config.cache;
        this.internals = {
            formatError: config.formatError,
            rootValue: config.rootValue,
            validationRules: [
                ...(config.validationRules ?? []),
                ...(introspectionEnabled ? [] : [NoIntrospection]),
            ],
            hideSchemaDetailsFromClientErrors,
            dangerouslyDisableValidation: config.dangerouslyDisableValidation ?? false,
            fieldResolver: config.fieldResolver,
            includeStacktraceInErrorResponses: config.includeStacktraceInErrorResponses ??
                (nodeEnv !== 'production' && nodeEnv !== 'test'),
            persistedQueries: config.persistedQueries === false
                ? undefined
                : {
                    ...config.persistedQueries,
                    cache: new utils_keyvaluecache_1.PrefixingKeyValueCache(config.persistedQueries?.cache ?? this.cache, requestPipeline_js_1.APQ_CACHE_PREFIX),
                },
            nodeEnv,
            allowBatchedHttpRequests: config.allowBatchedHttpRequests ?? false,
            apolloConfig,
            plugins: config.plugins ?? [],
            parseOptions: config.parseOptions ?? {},
            state,
            stopOnTerminationSignals: config.stopOnTerminationSignals,
            gatewayExecutor: null,
            csrfPreventionRequestHeaders: config.csrfPrevention === true || config.csrfPrevention === undefined
                ? preventCsrf_js_1.recommendedCsrfPreventionRequestHeaders
                : config.csrfPrevention === false
                    ? null
                    : (config.csrfPrevention.requestHeaders ??
                        preventCsrf_js_1.recommendedCsrfPreventionRequestHeaders),
            status400ForVariableCoercionErrors: config.status400ForVariableCoercionErrors ?? false,
            __testing_incrementalExecutionResults: config.__testing_incrementalExecutionResults,
            stringifyResult: config.stringifyResult ?? runHttpQuery_js_1.prettyJSONStringify,
        };
    }
    async start() {
        return await this._start(false);
    }
    startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests() {
        this._start(true).catch((e) => this.logStartupError(e));
    }
    async _start(startedInBackground) {
        if (this.internals.state.phase !== 'initialized') {
            throw new Error(`You should only call 'start()' or ` +
                `'startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()' ` +
                `once on your ApolloServer.`);
        }
        const schemaManager = this.internals.state.schemaManager;
        const barrier = (0, resolvable_js_1.default)();
        this.internals.state = {
            phase: 'starting',
            barrier,
            schemaManager,
            startedInBackground,
        };
        try {
            await this.addDefaultPlugins();
            const toDispose = [];
            const executor = await schemaManager.start();
            if (executor) {
                this.internals.gatewayExecutor = executor;
            }
            toDispose.push(async () => {
                await schemaManager.stop();
            });
            const schemaDerivedData = schemaManager.getSchemaDerivedData();
            const service = {
                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) => typeof maybeTaggedServerListener.serverListener === 'object');
            taggedServerListeners.forEach(({ serverListener: { schemaDidLoadOrUpdate } }) => {
                if (schemaDidLoadOrUpdate) {
                    schemaManager.onSchemaLoadOrUpdate(schemaDidLoadOrUpdate);
                }
            });
            const serverWillStops = taggedServerListeners
                .map((l) => l.serverListener.serverWillStop)
                .filter(isDefined_js_1.isDefined);
            if (serverWillStops.length) {
                toDispose.push(async () => {
                    await Promise.all(serverWillStops.map((serverWillStop) => serverWillStop()));
                });
            }
            const drainServerCallbacks = taggedServerListeners
                .map((l) => l.serverListener.drainServer)
                .filter(isDefined_js_1.isDefined);
            const drainServers = drainServerCallbacks.length
                ? async () => {
                    await Promise.all(drainServerCallbacks.map((drainServer) => drainServer()));
                }
                : null;
            let taggedServerListenersWithRenderLandingPage = taggedServerListeners.filter((l) => l.serverListener.renderLandingPage);
            if (taggedServerListenersWithRenderLandingPage.length > 1) {
                taggedServerListenersWithRenderLandingPage =
                    taggedServerListenersWithRenderLandingPage.filter((l) => !l.installedImplicitly);
            }
            let landingPage = 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) {
            const error = (0, errorNormalize_js_1.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();
        }
    }
    maybeRegisterTerminationSignalHandlers(signals, startedInBackground) {
        const toDisposeLast = [];
        if (this.internals.stopOnTerminationSignals === false ||
            (this.internals.stopOnTerminationSignals === undefined &&
                !(utils_isnodelike_1.isNodeLike &&
                    this.internals.nodeEnv !== 'test' &&
                    !startedInBackground))) {
            return toDisposeLast;
        }
        let receivedSignal = false;
        const signalHandler = async (signal) => {
            if (receivedSignal) {
                return;
            }
            receivedSignal = true;
            try {
                await this.stop();
            }
            catch (e) {
                this.logger.error(`stop() threw during ${signal} shutdown`);
                this.logger.error(e);
                process.exit(1);
            }
            process.kill(process.pid, signal);
        };
        signals.forEach((signal) => {
            process.on(signal, signalHandler);
            toDisposeLast.push(async () => {
                process.removeListener(signal, signalHandler);
            });
        });
        return toDisposeLast;
    }
    async _ensureStarted() {
        while (true) {
            switch (this.internals.state.phase) {
                case 'initialized':
                    throw new Error('You need to call `server.start()` before using your Apollo Server.');
                case 'starting':
                    await this.internals.state.barrier;
                    break;
                case 'failed to start':
                    this.logStartupError(this.internals.state.error);
                    throw new Error('This data graph is missing a valid configuration. More details may be available in the server logs.');
                case 'started':
                case '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_js_1.UnreachableCaseError(this.internals.state);
            }
        }
    }
    assertStarted(expressionForError) {
        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 +
                '`');
        }
    }
    logStartupError(err) {
        this.logger.error('An error occurred during Apollo Server startup. All GraphQL requests ' +
            'will now fail. The startup error was: ' +
            (err?.message || err));
    }
    static constructSchema(config) {
        if (config.schema) {
            return config.schema;
        }
        const { typeDefs, resolvers } = config;
        const augmentedTypeDefs = Array.isArray(typeDefs) ? typeDefs : [typeDefs];
        return (0, schema_1.makeExecutableSchema)({
            typeDefs: augmentedTypeDefs,
            resolvers,
        });
    }
    static generateSchemaDerivedData(schema, providedDocumentStore) {
        (0, graphql_1.assertValidSchema)(schema);
        return {
            schema,
            documentStore: providedDocumentStore === undefined
                ? new utils_keyvaluecache_1.InMemoryLRUCache()
                : providedDocumentStore,
            documentStoreKeyPrefix: providedDocumentStore
                ? `${(0, computeCoreSchemaHash_js_1.computeCoreSchemaHash)((0, graphql_1.printSchema)(schema))}:`
                : '',
        };
    }
    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');
            case 'stopped':
                if (this.internals.state.stopError) {
                    throw this.internals.state.stopError;
                }
                return;
            case 'stopping':
            case 'draining': {
                await this.internals.state.barrier;
                const state = this.internals.state;
                if (state.phase !== 'stopped') {
                    throw Error(`Surprising post-stopping state ${state.phase}`);
                }
                if (state.stopError) {
                    throw state.stopError;
                }
                return;
            }
            case 'started':
                break;
            default:
                throw new UnreachableCaseError_js_1.UnreachableCaseError(this.internals.state);
        }
        const barrier = (0, resolvable_js_1.default)();
        const { schemaManager, drainServers, landingPage, toDispose, toDisposeLast, } = this.internals.state;
        this.internals.state = {
            phase: 'draining',
            barrier,
            schemaManager,
            landingPage,
        };
        try {
            await drainServers?.();
            this.internals.state = { phase: 'stopping', barrier };
            await Promise.all([...toDispose].map((dispose) => dispose()));
            await Promise.all([...toDisposeLast].map((dispose) => dispose()));
        }
        catch (stopError) {
            this.internals.state = {
                phase: 'stopped',
                stopError: stopError,
            };
            barrier.resolve();
            throw stopError;
        }
        this.internals.state = { phase: 'stopped', stopError: null };
    }
    async addDefaultPlugins() {
        const { plugins, apolloConfig, nodeEnv, hideSchemaDetailsFromClientErrors, } = this.internals;
        const isDev = nodeEnv !== 'production';
        const alreadyHavePluginWithInternalId = (id) => plugins.some((p) => (0, internalPlugin_js_1.pluginIsInternal)(p) && p.__internal_plugin_id__ === id);
        const pluginsByInternalID = new Map();
        for (const p of plugins) {
            if ((0, internalPlugin_js_1.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.`);
                }
            }
        }
        {
            if (!alreadyHavePluginWithInternalId('CacheControl')) {
                const { ApolloServerPluginCacheControl } = await Promise.resolve().then(() => __importStar(require('./plugin/cacheControl/index.js')));
                plugins.push(ApolloServerPluginCacheControl());
            }
        }
        {
            const alreadyHavePlugin = alreadyHavePluginWithInternalId('UsageReporting');
            if (!alreadyHavePlugin && apolloConfig.key) {
                if (apolloConfig.graphRef) {
                    const { ApolloServerPluginUsageReporting } = await Promise.resolve().then(() => __importStar(require('./plugin/usageReporting/index.js')));
                    plugins.unshift(ApolloServerPluginUsageReporting({
                        __onlyIfSchemaIsNotSubgraph: true,
                    }));
                }
                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`.');
                }
            }
        }
        {
            const alreadyHavePlugin = alreadyHavePluginWithInternalId('SchemaReporting');
            const enabledViaEnvVar = process.env.APOLLO_SCHEMA_REPORTING === 'true';
            if (!alreadyHavePlugin && enabledViaEnvVar) {
                if (apolloConfig.key) {
                    const { ApolloServerPluginSchemaReporting } = await Promise.resolve().then(() => __importStar(require('./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})');
                }
            }
        }
        {
            const alreadyHavePlugin = alreadyHavePluginWithInternalId('InlineTrace');
            if (!alreadyHavePlugin) {
                const { ApolloServerPluginInlineTrace } = await Promise.resolve().then(() => __importStar(require('./plugin/inlineTrace/index.js')));
                plugins.push(ApolloServerPluginInlineTrace({ __onlyIfSchemaIsSubgraph: true }));
            }
        }
        const alreadyHavePlugin = alreadyHavePluginWithInternalId('LandingPageDisabled');
        if (!alreadyHavePlugin) {
            const { ApolloServerPluginLandingPageLocalDefault, ApolloServerPluginLandingPageProductionDefault, } = await Promise.resolve().then(() => __importStar(require('./plugin/landingPage/default/index.js')));
            const plugin = isDev
                ? ApolloServerPluginLandingPageLocalDefault()
                : ApolloServerPluginLandingPageProductionDefault();
            if (!isImplicitlyInstallablePlugin(plugin)) {
                throw Error('default landing page plugin should be implicitly installable?');
            }
            plugin.__internal_installed_implicitly__ = true;
            plugins.push(plugin);
        }
        {
            const alreadyHavePlugin = alreadyHavePluginWithInternalId('DisableSuggestions');
            if (hideSchemaDetailsFromClientErrors && !alreadyHavePlugin) {
                const { ApolloServerPluginDisableSuggestions } = await Promise.resolve().then(() => __importStar(require('./plugin/disableSuggestions/index.js')));
                plugins.push(ApolloServerPluginDisableSuggestions());
            }
        }
    }
    addPlugin(plugin) {
        if (this.internals.state.phase !== 'initialized') {
            throw new Error("Can't add plugins after the server has started");
        }
        this.internals.plugins.push(plugin);
    }
    async executeHTTPGraphQLRequest({ httpGraphQLRequest, context, }) {
        try {
            let runningServerState;
            try {
                runningServerState = await this._ensureStarted();
            }
            catch (error) {
                return await this.errorResponse(error, httpGraphQLRequest);
            }
            if (runningServerState.landingPage &&
                this.prefersHTML(httpGraphQLRequest)) {
                let renderedHtml;
                if (typeof runningServerState.landingPage.html === 'string') {
                    renderedHtml = runningServerState.landingPage.html;
                }
                else {
                    try {
                        renderedHtml = await runningServerState.landingPage.html();
                    }
                    catch (maybeError) {
                        const error = (0, errorNormalize_js_1.ensureError)(maybeError);
                        this.logger.error(`Landing page \`html\` function threw: ${error}`);
                        return await this.errorResponse(error, httpGraphQLRequest);
                    }
                }
                return {
                    headers: new HeaderMap_js_1.HeaderMap([['content-type', 'text/html']]),
                    body: {
                        kind: 'complete',
                        string: renderedHtml,
                    },
                };
            }
            if (this.internals.csrfPreventionRequestHeaders) {
                (0, preventCsrf_js_1.preventCsrf)(httpGraphQLRequest.headers, this.internals.csrfPreventionRequestHeaders);
            }
            let contextValue;
            try {
                contextValue = await context();
            }
            catch (maybeError) {
                const error = (0, errorNormalize_js_1.ensureError)(maybeError);
                try {
                    await Promise.all(this.internals.plugins.map(async (plugin) => plugin.contextCreationDidFail?.({
                        error,
                    })));
                }
                catch (pluginError) {
                    this.logger.error(`contextCreationDidFail hook threw: ${pluginError}`);
                }
                return await this.errorResponse((0, errorNormalize_js_1.ensureGraphQLError)(error, 'Context creation failed: '), httpGraphQLRequest);
            }
            return await (0, httpBatching_js_1.runPotentiallyBatchedHttpQuery)(this, httpGraphQLRequest, contextValue, runningServerState.schemaManager.getSchemaDerivedData(), this.internals);
        }
        catch (maybeError_) {
            const maybeError = maybeError_;
            if (maybeError instanceof graphql_1.GraphQLError &&
                maybeError.extensions.code === index_js_1.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 await this.errorResponse(maybeError, httpGraphQLRequest);
        }
    }
    async errorResponse(error, requestHead) {
        const { formattedErrors, httpFromErrors } = (0, errorNormalize_js_1.normalizeAndFormatErrors)([error], {
            includeStacktraceInErrorResponses: this.internals.includeStacktraceInErrorResponses,
            formatError: this.internals.formatError,
        });
        return {
            status: httpFromErrors.status ?? 500,
            headers: new HeaderMap_js_1.HeaderMap([
                ...httpFromErrors.headers,
                [
                    'content-type',
                    chooseContentTypeForSingleResultResponse(requestHead) ??
                        exports.MEDIA_TYPES.APPLICATION_JSON,
                ],
            ]),
            body: {
                kind: 'complete',
                string: await this.internals.stringifyResult({
                    errors: formattedErrors,
                }),
            },
        };
    }
    prefersHTML(request) {
        const acceptHeader = request.headers.get('accept');
        return (request.method === 'GET' &&
            !!acceptHeader &&
            new negotiator_1.default({
                headers: { accept: acceptHeader },
            }).mediaType([
                exports.MEDIA_TYPES.APPLICATION_JSON,
                exports.MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON,
                exports.MEDIA_TYPES.MULTIPART_MIXED_EXPERIMENTAL,
                exports.MEDIA_TYPES.MULTIPART_MIXED_NO_DEFER_SPEC,
                exports.MEDIA_TYPES.TEXT_HTML,
            ]) === exports.MEDIA_TYPES.TEXT_HTML);
    }
    async executeOperation(request, options = {}) {
        if (this.internals.state.phase === 'initialized') {
            await this.start();
        }
        const schemaDerivedData = (await this._ensureStarted()).schemaManager.getSchemaDerivedData();
        const graphQLRequest = {
            ...request,
            query: request.query && typeof request.query !== 'string'
                ? (0, graphql_1.print)(request.query)
                : request.query,
        };
        const response = await internalExecuteOperation({
            server: this,
            graphQLRequest,
            internals: this.internals,
            schemaDerivedData,
            sharedResponseHTTPGraphQLHead: null,
        }, options);
        return response;
    }
}
exports.ApolloServer = ApolloServer;
async function internalExecuteOperation({ server, graphQLRequest, internals, schemaDerivedData, sharedResponseHTTPGraphQLHead, }, options) {
    const requestContext = {
        logger: server.logger,
        cache: server.cache,
        schema: schemaDerivedData.schema,
        request: graphQLRequest,
        response: {
            http: sharedResponseHTTPGraphQLHead ?? (0, runHttpQuery_js_1.newHTTPGraphQLHead)(),
        },
        contextValue: cloneObject(options?.contextValue ?? {}),
        metrics: {},
        overallCachePolicy: (0, cachePolicy_js_1.newCachePolicy)(),
        requestIsBatched: sharedResponseHTTPGraphQLHead !== null,
    };
    try {
        return await (0, requestPipeline_js_1.processGraphQLRequest)(schemaDerivedData, server, internals, requestContext);
    }
    catch (maybeError) {
        const error = (0, errorNormalize_js_1.ensureError)(maybeError);
        await Promise.all(internals.plugins.map(async (plugin) => plugin.unexpectedErrorProcessingRequest?.({
            requestContext,
            error,
        })));
        server.logger.error(`Unexpected error processing request: ${error}`);
        throw new Error('Internal server error');
    }
}
exports.internalExecuteOperation = internalExecuteOperation;
function isImplicitlyInstallablePlugin(p) {
    return '__internal_installed_implicitly__' in p;
}
exports.isImplicitlyInstallablePlugin = isImplicitlyInstallablePlugin;
exports.MEDIA_TYPES = {
    APPLICATION_JSON: 'application/json; charset=utf-8',
    APPLICATION_JSON_GRAPHQL_CALLBACK: 'application/json; callbackSpec=1.0; charset=utf-8',
    APPLICATION_GRAPHQL_RESPONSE_JSON: 'application/graphql-response+json; charset=utf-8',
    MULTIPART_MIXED_NO_DEFER_SPEC: 'multipart/mixed',
    MULTIPART_MIXED_EXPERIMENTAL: 'multipart/mixed; deferSpec=20220824',
    TEXT_HTML: 'text/html',
};
function chooseContentTypeForSingleResultResponse(head) {
    const acceptHeader = head.headers.get('accept');
    if (!acceptHeader) {
        return exports.MEDIA_TYPES.APPLICATION_JSON;
    }
    else {
        const preferred = new negotiator_1.default({
            headers: { accept: head.headers.get('accept') },
        }).mediaType([
            exports.MEDIA_TYPES.APPLICATION_JSON,
            exports.MEDIA_TYPES.APPLICATION_GRAPHQL_RESPONSE_JSON,
            exports.MEDIA_TYPES.APPLICATION_JSON_GRAPHQL_CALLBACK,
        ]);
        if (preferred) {
            return preferred;
        }
        else {
            return null;
        }
    }
}
exports.chooseContentTypeForSingleResultResponse = chooseContentTypeForSingleResultResponse;
function cloneObject(object) {
    return Object.assign(Object.create(Object.getPrototypeOf(object)), object);
}
//# sourceMappingURL=ApolloServer.js.map