import { __assign, __extends, __rest } from "tslib"; import { ApolloLink } from "../core/index.js"; import { Observable, hasDirectives, removeClientSetsFromDocument, } from "../../utilities/index.js"; import { fromError } from "../utils/index.js"; import { serializeFetchParameter, selectURI, parseAndCheckHttpResponse, checkFetcher, selectHttpOptionsAndBodyInternal, defaultPrinter, fallbackHttpConfig, } from "../http/index.js"; import { BatchLink } from "../batch/index.js"; import { filterOperationVariables } from "../utils/filterOperationVariables.js"; /** * Transforms Operation for into HTTP results. * context can include the headers property, which will be passed to the fetch function */ var BatchHttpLink = /** @class */ (function (_super) { __extends(BatchHttpLink, _super); function BatchHttpLink(fetchParams) { var _this = _super.call(this) || this; var _a = fetchParams || {}, _b = _a.uri, uri = _b === void 0 ? "/graphql" : _b, // use default global fetch if nothing is passed in fetcher = _a.fetch, _c = _a.print, print = _c === void 0 ? defaultPrinter : _c, includeExtensions = _a.includeExtensions, preserveHeaderCase = _a.preserveHeaderCase, batchInterval = _a.batchInterval, batchDebounce = _a.batchDebounce, batchMax = _a.batchMax, batchKey = _a.batchKey, _d = _a.includeUnusedVariables, includeUnusedVariables = _d === void 0 ? false : _d, requestOptions = __rest(_a, ["uri", "fetch", "print", "includeExtensions", "preserveHeaderCase", "batchInterval", "batchDebounce", "batchMax", "batchKey", "includeUnusedVariables"]); // dev warnings to ensure fetch is present checkFetcher(fetcher); //fetcher is set here rather than the destructuring to ensure fetch is //declared before referencing it. Reference in the destructuring would cause //a ReferenceError if (!fetcher) { fetcher = fetch; } var linkConfig = { http: { includeExtensions: includeExtensions, preserveHeaderCase: preserveHeaderCase }, options: requestOptions.fetchOptions, credentials: requestOptions.credentials, headers: requestOptions.headers, }; _this.batchDebounce = batchDebounce; _this.batchInterval = batchInterval || 10; _this.batchMax = batchMax || 10; var batchHandler = function (operations) { var chosenURI = selectURI(operations[0], uri); var context = operations[0].getContext(); var clientAwarenessHeaders = {}; if (context.clientAwareness) { var _a = context.clientAwareness, name_1 = _a.name, version = _a.version; if (name_1) { clientAwarenessHeaders["apollographql-client-name"] = name_1; } if (version) { clientAwarenessHeaders["apollographql-client-version"] = version; } } var contextConfig = { http: context.http, options: context.fetchOptions, credentials: context.credentials, headers: __assign(__assign({}, clientAwarenessHeaders), context.headers), }; var queries = operations.map(function (_a) { var query = _a.query; if (hasDirectives(["client"], query)) { return removeClientSetsFromDocument(query); } return query; }); // If we have a query that returned `null` after removing client-only // fields, it indicates a query that is using all client-only fields. if (queries.some(function (query) { return !query; })) { return fromError(new Error("BatchHttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or enable the `transformOptions.removeClientFields` option.")); } //uses fallback, link, and then context to build options var optsAndBody = operations.map(function (operation, index) { var result = selectHttpOptionsAndBodyInternal(__assign(__assign({}, operation), { query: queries[index] }), print, fallbackHttpConfig, linkConfig, contextConfig); if (result.body.variables && !includeUnusedVariables) { result.body.variables = filterOperationVariables(result.body.variables, operation.query); } return result; }); var loadedBody = optsAndBody.map(function (_a) { var body = _a.body; return body; }); var options = optsAndBody[0].options; // There's no spec for using GET with batches. if (options.method === "GET") { return fromError(new Error("apollo-link-batch-http does not support GET requests")); } try { options.body = serializeFetchParameter(loadedBody, "Payload"); } catch (parseError) { return fromError(parseError); } var controller; if (!options.signal && typeof AbortController !== "undefined") { controller = new AbortController(); options.signal = controller.signal; } return new Observable(function (observer) { fetcher(chosenURI, options) .then(function (response) { // Make the raw response available in the context. operations.forEach(function (operation) { return operation.setContext({ response: response }); }); return response; }) .then(parseAndCheckHttpResponse(operations)) .then(function (result) { controller = undefined; // we have data and can send it to back up the link chain observer.next(result); observer.complete(); return result; }) .catch(function (err) { controller = undefined; // if it is a network error, BUT there is graphql result info // fire the next observer before calling error // this gives apollo-client (and react-apollo) the `graphqlErrors` and `networkErrors` // to pass to UI // this should only happen if we *also* have data as part of the response key per // the spec if (err.result && err.result.errors && err.result.data) { // if we dont' call next, the UI can only show networkError because AC didn't // get andy graphqlErrors // this is graphql execution result info (i.e errors and possibly data) // this is because there is no formal spec how errors should translate to // http status codes. So an auth error (401) could have both data // from a public field, errors from a private field, and a status of 401 // { // user { // this will have errors // firstName // } // products { // this is public so will have data // cost // } // } // // the result of above *could* look like this: // { // data: { products: [{ cost: "$10" }] }, // errors: [{ // message: 'your session has timed out', // path: [] // }] // } // status code of above would be a 401 // in the UI you want to show data where you can, errors as data where you can // and use correct http status codes observer.next(err.result); } observer.error(err); }); return function () { // XXX support canceling this request // https://developers.google.com/web/updates/2017/09/abortable-fetch if (controller) controller.abort(); }; }); }; batchKey = batchKey || (function (operation) { var context = operation.getContext(); var contextConfig = { http: context.http, options: context.fetchOptions, credentials: context.credentials, headers: context.headers, }; //may throw error if config not serializable return selectURI(operation, uri) + JSON.stringify(contextConfig); }); _this.batcher = new BatchLink({ batchDebounce: _this.batchDebounce, batchInterval: _this.batchInterval, batchMax: _this.batchMax, batchKey: batchKey, batchHandler: batchHandler, }); return _this; } BatchHttpLink.prototype.request = function (operation) { return this.batcher.request(operation); }; return BatchHttpLink; }(ApolloLink)); export { BatchHttpLink }; //# sourceMappingURL=batchHttpLink.js.map