"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseBatchHttpLink = exports.BatchHttpLink = void 0;
const rxjs_1 = require("rxjs");
const link_1 = require("@apollo/client/link");
const batch_1 = require("@apollo/client/link/batch");
const client_awareness_1 = require("@apollo/client/link/client-awareness");
const http_1 = require("@apollo/client/link/http");
const environment_1 = require("@apollo/client/utilities/environment");
const internal_1 = require("@apollo/client/utilities/internal");
const globals_1 = require("@apollo/client/utilities/internal/globals");
const filterOperationVariables_js_1 = require("../utils/filterOperationVariables.cjs");
const backupFetch = (0, globals_1.maybe)(() => fetch);
/**
 * Transforms Operation for into HTTP results.
 * context can include the headers property, which will be passed to the fetch function
 */
class BatchHttpLink extends link_1.ApolloLink {
    constructor(options = {}) {
        const { left, right, request } = link_1.ApolloLink.concat(new client_awareness_1.ClientAwarenessLink(options), new BaseBatchHttpLink(options));
        super(request);
        Object.assign(this, { left, right });
    }
}
exports.BatchHttpLink = BatchHttpLink;
class BaseBatchHttpLink extends link_1.ApolloLink {
    batchDebounce;
    batchInterval;
    batchMax;
    batcher;
    constructor(fetchParams) {
        super();
        let { uri = "/graphql", 
        // use default global fetch if nothing is passed in
        fetch: preferredFetch, print = http_1.defaultPrinter, includeExtensions, preserveHeaderCase, batchInterval, batchDebounce, batchMax, batchKey, includeUnusedVariables = false, ...requestOptions } = fetchParams || {};
        if (environment_1.__DEV__) {
            // Make sure at least one of preferredFetch, window.fetch, or backupFetch
            // is defined, so requests won't fail at runtime.
            (0, http_1.checkFetcher)(preferredFetch || backupFetch);
        }
        const linkConfig = {
            http: (0, internal_1.compact)({ includeExtensions, preserveHeaderCase }),
            options: requestOptions.fetchOptions,
            credentials: requestOptions.credentials,
            headers: requestOptions.headers,
        };
        this.batchDebounce = batchDebounce;
        this.batchInterval = batchInterval || 10;
        this.batchMax = batchMax || 10;
        const batchHandler = (operations) => {
            const chosenURI = (0, http_1.selectURI)(operations[0], uri);
            const context = operations[0].getContext();
            const contextConfig = {
                http: context.http,
                options: context.fetchOptions,
                credentials: context.credentials,
                headers: context.headers,
            };
            //uses fallback, link, and then context to build options
            const optsAndBody = operations.map((operation) => {
                const result = (0, http_1.selectHttpOptionsAndBodyInternal)(operation, print, http_1.fallbackHttpConfig, linkConfig, contextConfig);
                if (result.body.variables && !includeUnusedVariables) {
                    result.body.variables = (0, filterOperationVariables_js_1.filterOperationVariables)(result.body.variables, operation.query);
                }
                return result;
            });
            const loadedBody = optsAndBody.map(({ body }) => body);
            const options = optsAndBody[0].options;
            // There's no spec for using GET with batches.
            if (options.method === "GET") {
                return (0, rxjs_1.throwError)(() => new Error("apollo-link-batch-http does not support GET requests"));
            }
            try {
                options.body = (0, http_1.serializeFetchParameter)(loadedBody, "Payload");
            }
            catch (parseError) {
                return (0, rxjs_1.throwError)(() => parseError);
            }
            let controller;
            if (!options.signal && typeof AbortController !== "undefined") {
                controller = new AbortController();
                options.signal = controller.signal;
            }
            return new rxjs_1.Observable((observer) => {
                // Prefer BatchHttpLink.Options.fetch (preferredFetch) if provided, and
                // otherwise fall back to the *current* global window.fetch function
                // (see issue #7832), or (if all else fails) the backupFetch function we
                // saved when this module was first evaluated. This last option protects
                // against the removal of window.fetch, which is unlikely but not
                // impossible.
                const currentFetch = preferredFetch || (0, globals_1.maybe)(() => fetch) || backupFetch;
                currentFetch(chosenURI, options)
                    .then((response) => {
                    // Make the raw response available in the context.
                    operations.forEach((operation) => operation.setContext({ response }));
                    return response;
                })
                    .then((0, http_1.parseAndCheckHttpResponse)(operations))
                    .then((result) => {
                    controller = undefined;
                    // we have data and can send it to back up the link chain
                    observer.next(result);
                    observer.complete();
                    return result;
                })
                    .catch((err) => {
                    controller = undefined;
                    observer.error(err);
                });
                return () => {
                    // XXX support canceling this request
                    // https://developers.google.com/web/updates/2017/09/abortable-fetch
                    if (controller)
                        controller.abort();
                };
            });
        };
        batchKey =
            batchKey ||
                ((operation) => {
                    const context = operation.getContext();
                    const contextConfig = {
                        http: context.http,
                        options: context.fetchOptions,
                        credentials: context.credentials,
                        headers: context.headers,
                    };
                    //may throw error if config not serializable
                    return (0, http_1.selectURI)(operation, uri) + JSON.stringify(contextConfig);
                });
        this.batcher = new batch_1.BatchLink({
            batchDebounce: this.batchDebounce,
            batchInterval: this.batchInterval,
            batchMax: this.batchMax,
            batchKey,
            batchHandler,
        });
    }
    request(operation) {
        return this.batcher.request(operation);
    }
}
exports.BaseBatchHttpLink = BaseBatchHttpLink;
//# sourceMappingURL=batchHttpLink.cjs.map
