@graphql-tools/executor-http 1.1.9 → 1.1.10-alpha-e8c01415b3b19676af5ff8b818bc152e3293f9e4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +480 -0
  2. package/dist/index.cjs +546 -0
  3. package/{typings → dist}/index.d.cts +28 -25
  4. package/{typings → dist}/index.d.ts +28 -25
  5. package/dist/index.js +543 -0
  6. package/package.json +38 -46
  7. package/cjs/createFormDataFromVariables.js +0 -76
  8. package/cjs/createTimeoutSignal.js +0 -1
  9. package/cjs/defaultPrintFn.js +0 -14
  10. package/cjs/handleEventStreamResponse.js +0 -55
  11. package/cjs/handleMultipartMixedResponse.js +0 -48
  12. package/cjs/index.js +0 -314
  13. package/cjs/isGraphQLUpload.js +0 -7
  14. package/cjs/isLiveQueryOperationDefinitionNode.js +0 -8
  15. package/cjs/package.json +0 -1
  16. package/cjs/prepareGETUrl.js +0 -26
  17. package/esm/createFormDataFromVariables.js +0 -72
  18. package/esm/createTimeoutSignal.js +0 -1
  19. package/esm/defaultPrintFn.js +0 -10
  20. package/esm/handleEventStreamResponse.js +0 -50
  21. package/esm/handleMultipartMixedResponse.js +0 -44
  22. package/esm/index.js +0 -310
  23. package/esm/isGraphQLUpload.js +0 -3
  24. package/esm/isLiveQueryOperationDefinitionNode.js +0 -5
  25. package/esm/prepareGETUrl.js +0 -22
  26. package/typings/createFormDataFromVariables.d.cts +0 -10
  27. package/typings/createFormDataFromVariables.d.ts +0 -10
  28. package/typings/createTimeoutSignal.d.cts +0 -0
  29. package/typings/createTimeoutSignal.d.ts +0 -0
  30. package/typings/defaultPrintFn.d.cts +0 -2
  31. package/typings/defaultPrintFn.d.ts +0 -2
  32. package/typings/handleEventStreamResponse.d.cts +0 -4
  33. package/typings/handleEventStreamResponse.d.ts +0 -4
  34. package/typings/handleMultipartMixedResponse.d.cts +0 -2
  35. package/typings/handleMultipartMixedResponse.d.ts +0 -2
  36. package/typings/isGraphQLUpload.d.cts +0 -9
  37. package/typings/isGraphQLUpload.d.ts +0 -9
  38. package/typings/isLiveQueryOperationDefinitionNode.d.cts +0 -2
  39. package/typings/isLiveQueryOperationDefinitionNode.d.ts +0 -2
  40. package/typings/prepareGETUrl.d.cts +0 -7
  41. package/typings/prepareGETUrl.d.ts +0 -7
@@ -1,17 +1,19 @@
1
- import { DocumentNode, GraphQLResolveInfo } from 'graphql';
2
- import { AsyncExecutor, DisposableAsyncExecutor, DisposableSyncExecutor, ExecutionRequest, SyncExecutor } from '@graphql-tools/utils';
3
- import { isLiveQueryOperationDefinitionNode } from './isLiveQueryOperationDefinitionNode.js';
4
- export type SyncFetchFn = (url: string, init?: RequestInit, context?: any, info?: GraphQLResolveInfo) => SyncResponse;
5
- export type SyncResponse = Omit<Response, 'json' | 'text'> & {
1
+ import { ExecutionRequest, DisposableSyncExecutor, SyncExecutor, DisposableAsyncExecutor, AsyncExecutor } from '@graphql-tools/utils';
2
+ import { OperationDefinitionNode, GraphQLResolveInfo, DocumentNode } from 'graphql';
3
+
4
+ declare const isLiveQueryOperationDefinitionNode: (node: OperationDefinitionNode) => boolean | undefined;
5
+
6
+ type SyncFetchFn = (url: string, init?: RequestInit, context?: any, info?: GraphQLResolveInfo) => SyncResponse;
7
+ type SyncResponse = Omit<Response, 'json' | 'text'> & {
6
8
  json: () => any;
7
9
  text: () => string;
8
10
  };
9
- export type AsyncFetchFn = (url: string, options?: RequestInit, context?: any, info?: GraphQLResolveInfo) => Promise<Response> | Response;
10
- export type RegularFetchFn = (url: string) => Promise<Response> | Response;
11
- export type FetchFn = AsyncFetchFn | SyncFetchFn | RegularFetchFn;
12
- export type AsyncImportFn = (moduleName: string) => PromiseLike<any>;
13
- export type SyncImportFn = (moduleName: string) => any;
14
- export interface HTTPExecutorOptions {
11
+ type AsyncFetchFn = (url: string, options?: RequestInit, context?: any, info?: GraphQLResolveInfo) => Promise<Response> | Response;
12
+ type RegularFetchFn = (url: string) => Promise<Response> | Response;
13
+ type FetchFn = AsyncFetchFn | SyncFetchFn | RegularFetchFn;
14
+ type AsyncImportFn = (moduleName: string) => PromiseLike<any>;
15
+ type SyncImportFn = (moduleName: string) => any;
16
+ interface HTTPExecutorOptions {
15
17
  endpoint?: string;
16
18
  fetch?: FetchFn;
17
19
  /**
@@ -59,45 +61,46 @@ export interface HTTPExecutorOptions {
59
61
  */
60
62
  disposable?: boolean;
61
63
  }
62
- export type HeadersConfig = Record<string, string>;
63
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
64
+ type HeadersConfig = Record<string, string>;
65
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
64
66
  fetch: SyncFetchFn;
65
67
  disposable: true;
66
68
  }): DisposableSyncExecutor<any, HTTPExecutorOptions>;
67
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
69
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
68
70
  fetch: SyncFetchFn;
69
71
  disposable: false;
70
72
  }): SyncExecutor<any, HTTPExecutorOptions>;
71
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & {
73
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & {
72
74
  fetch: SyncFetchFn;
73
75
  }): SyncExecutor<any, HTTPExecutorOptions>;
74
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
76
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
75
77
  fetch: AsyncFetchFn;
76
78
  disposable: true;
77
79
  }): DisposableAsyncExecutor<any, HTTPExecutorOptions>;
78
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
80
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
79
81
  fetch: AsyncFetchFn;
80
82
  disposable: false;
81
83
  }): AsyncExecutor<any, HTTPExecutorOptions>;
82
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & {
84
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & {
83
85
  fetch: AsyncFetchFn;
84
86
  }): AsyncExecutor<any, HTTPExecutorOptions>;
85
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
87
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
86
88
  fetch: RegularFetchFn;
87
89
  disposable: true;
88
90
  }): DisposableAsyncExecutor<any, HTTPExecutorOptions>;
89
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
91
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
90
92
  fetch: RegularFetchFn;
91
93
  disposable: false;
92
94
  }): AsyncExecutor<any, HTTPExecutorOptions>;
93
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & {
95
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & {
94
96
  fetch: RegularFetchFn;
95
97
  }): AsyncExecutor<any, HTTPExecutorOptions>;
96
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
98
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
97
99
  disposable: true;
98
100
  }): DisposableAsyncExecutor<any, HTTPExecutorOptions>;
99
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
101
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & {
100
102
  disposable: false;
101
103
  }): AsyncExecutor<any, HTTPExecutorOptions>;
102
- export declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'>): AsyncExecutor<any, HTTPExecutorOptions>;
103
- export { isLiveQueryOperationDefinitionNode };
104
+ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'>): AsyncExecutor<any, HTTPExecutorOptions>;
105
+
106
+ export { type AsyncFetchFn, type AsyncImportFn, type FetchFn, type HTTPExecutorOptions, type HeadersConfig, type RegularFetchFn, type SyncFetchFn, type SyncImportFn, type SyncResponse, buildHTTPExecutor, isLiveQueryOperationDefinitionNode };
package/dist/index.js ADDED
@@ -0,0 +1,543 @@
1
+ import { isAsyncIterable, isPromise, inspect, mapAsyncIterator, mergeIncrementalResult, memoize1, createGraphQLError, getOperationASTFromRequest } from '@graphql-tools/utils';
2
+ import { File, FormData, TextDecoderStream, fetch } from '@whatwg-node/fetch';
3
+ import { ValueOrPromise } from 'value-or-promise';
4
+ import { extractFiles, isExtractableFile } from 'extract-files';
5
+ import { stripIgnoredCharacters, print } from 'graphql';
6
+ import { Repeater } from '@repeaterjs/repeater';
7
+ import { meros as meros$1 } from 'meros/browser';
8
+ import { meros } from 'meros/node';
9
+
10
+ function isGraphQLUpload(upload) {
11
+ return typeof upload.createReadStream === "function";
12
+ }
13
+
14
+ function createFormDataFromVariables({
15
+ query,
16
+ variables,
17
+ operationName,
18
+ extensions
19
+ }, {
20
+ File: FileCtor = File,
21
+ FormData: FormDataCtor = FormData
22
+ }) {
23
+ const vars = Object.assign({}, variables);
24
+ const { clone, files } = extractFiles(
25
+ vars,
26
+ "variables",
27
+ (v) => isExtractableFile(v) || v?.promise || isAsyncIterable(v) || v?.then || typeof v?.arrayBuffer === "function"
28
+ );
29
+ if (files.size === 0) {
30
+ return JSON.stringify(
31
+ {
32
+ query,
33
+ variables,
34
+ operationName,
35
+ extensions
36
+ },
37
+ null,
38
+ 2
39
+ );
40
+ }
41
+ const map = {};
42
+ const uploads = [];
43
+ let currIndex = 0;
44
+ for (const [file, curr] of files) {
45
+ map[currIndex] = curr;
46
+ uploads[currIndex] = file;
47
+ currIndex++;
48
+ }
49
+ const form = new FormDataCtor();
50
+ form.append(
51
+ "operations",
52
+ JSON.stringify({
53
+ query,
54
+ variables: clone,
55
+ operationName,
56
+ extensions
57
+ })
58
+ );
59
+ form.append("map", JSON.stringify(map, null, 2));
60
+ function handleUpload(upload, i) {
61
+ const indexStr = i.toString();
62
+ if (upload != null) {
63
+ const filename = upload.filename || upload.name || upload.path || `blob-${indexStr}`;
64
+ if (isPromise(upload)) {
65
+ return upload.then(
66
+ (resolvedUpload) => handleUpload(resolvedUpload, i)
67
+ );
68
+ } else if (isBlob(upload)) {
69
+ form.append(indexStr, upload, filename);
70
+ } else if (isGraphQLUpload(upload)) {
71
+ const stream = upload.createReadStream();
72
+ const chunks = [];
73
+ return Promise.resolve().then(async () => {
74
+ for await (const chunk of stream) {
75
+ if (chunk) {
76
+ chunks.push(...chunk);
77
+ }
78
+ }
79
+ const blobPart = new Uint8Array(chunks);
80
+ form.append(
81
+ indexStr,
82
+ new FileCtor([blobPart], filename, { type: upload.mimetype }),
83
+ filename
84
+ );
85
+ });
86
+ } else {
87
+ form.append(indexStr, new FileCtor([upload], filename), filename);
88
+ }
89
+ }
90
+ }
91
+ return ValueOrPromise.all(
92
+ uploads.map(
93
+ (upload, i) => new ValueOrPromise(() => handleUpload(upload, i))
94
+ )
95
+ ).then(() => form).resolve();
96
+ }
97
+ function isBlob(obj) {
98
+ return typeof obj.arrayBuffer === "function";
99
+ }
100
+
101
+ const printCache = /* @__PURE__ */ new WeakMap();
102
+ function defaultPrintFn(document) {
103
+ let printed = printCache.get(document);
104
+ if (!printed) {
105
+ printed = stripIgnoredCharacters(print(document));
106
+ printCache.set(document, printed);
107
+ }
108
+ return printed;
109
+ }
110
+
111
+ const DELIM = "\n\n";
112
+ function isReadableStream(value) {
113
+ return value && typeof value.getReader === "function";
114
+ }
115
+ function handleEventStreamResponse(response) {
116
+ if (!isReadableStream(response.body)) {
117
+ throw new Error(
118
+ "Response body is expected to be a readable stream but got; " + inspect(response.body)
119
+ );
120
+ }
121
+ const decodedBody = response.body.pipeThrough(new TextDecoderStream());
122
+ return new Repeater(async (push, stop) => {
123
+ let currChunk = "";
124
+ let cancelled = false;
125
+ stop.finally(() => {
126
+ cancelled = true;
127
+ });
128
+ try {
129
+ for await (const value of decodedBody) {
130
+ if (cancelled) {
131
+ return stop();
132
+ }
133
+ currChunk += value;
134
+ for (; ; ) {
135
+ const delimIndex = currChunk.indexOf(DELIM);
136
+ if (delimIndex === -1) {
137
+ break;
138
+ }
139
+ const msg = currChunk.slice(0, delimIndex);
140
+ currChunk = currChunk.slice(delimIndex + DELIM.length);
141
+ const dataStr = msg.split("data:")[1]?.trim();
142
+ if (dataStr) {
143
+ const data = JSON.parse(dataStr);
144
+ await push(data.payload || data);
145
+ }
146
+ const event = msg.split("event:")[1]?.trim();
147
+ if (event === "complete") {
148
+ cancelled = true;
149
+ return stop();
150
+ }
151
+ }
152
+ }
153
+ return stop();
154
+ } catch (e) {
155
+ cancelled = true;
156
+ return stop(e);
157
+ }
158
+ });
159
+ }
160
+
161
+ function isIncomingMessage(body) {
162
+ return body != null && typeof body === "object" && "pipe" in body;
163
+ }
164
+ async function handleMultipartMixedResponse(response) {
165
+ const body = response.body;
166
+ const contentType = response.headers.get("content-type") || "";
167
+ let asyncIterator;
168
+ if (isIncomingMessage(body)) {
169
+ body.headers = {
170
+ "content-type": contentType
171
+ };
172
+ const result = await meros(body);
173
+ if ("next" in result) {
174
+ asyncIterator = result;
175
+ }
176
+ } else {
177
+ const result = await meros$1(response);
178
+ if ("next" in result) {
179
+ asyncIterator = result;
180
+ }
181
+ }
182
+ const executionResult = {};
183
+ if (asyncIterator == null) {
184
+ return executionResult;
185
+ }
186
+ const resultStream = mapAsyncIterator(asyncIterator, (part) => {
187
+ if (part.json) {
188
+ const incrementalResult = part.body;
189
+ mergeIncrementalResult({
190
+ incrementalResult,
191
+ executionResult
192
+ });
193
+ }
194
+ return executionResult;
195
+ });
196
+ return resultStream;
197
+ }
198
+
199
+ const isLiveQueryOperationDefinitionNode = memoize1(
200
+ function isLiveQueryOperationDefinitionNode2(node) {
201
+ return node.operation === "query" && node.directives?.some((directive) => directive.name.value === "live");
202
+ }
203
+ );
204
+
205
+ function prepareGETUrl({
206
+ baseUrl = "",
207
+ query,
208
+ variables,
209
+ operationName,
210
+ extensions
211
+ }) {
212
+ const dummyHostname = "https://dummyhostname.com";
213
+ const validUrl = baseUrl.startsWith("http") ? baseUrl : baseUrl?.startsWith("/") ? `${dummyHostname}${baseUrl}` : `${dummyHostname}/${baseUrl}`;
214
+ const urlObj = new URL(validUrl);
215
+ urlObj.searchParams.set("query", stripIgnoredCharacters(query));
216
+ if (variables && Object.keys(variables).length > 0) {
217
+ urlObj.searchParams.set("variables", JSON.stringify(variables));
218
+ }
219
+ if (operationName) {
220
+ urlObj.searchParams.set("operationName", operationName);
221
+ }
222
+ if (extensions) {
223
+ urlObj.searchParams.set("extensions", JSON.stringify(extensions));
224
+ }
225
+ const finalUrl = urlObj.toString().replace(dummyHostname, "");
226
+ return finalUrl;
227
+ }
228
+
229
+ function buildHTTPExecutor(options) {
230
+ const printFn = options?.print ?? defaultPrintFn;
231
+ let disposeCtrl;
232
+ const baseExecutor = (request) => {
233
+ if (disposeCtrl?.signal.aborted) {
234
+ return createResultForAbort(disposeCtrl.signal);
235
+ }
236
+ const fetchFn = request.extensions?.fetch ?? options?.fetch ?? fetch;
237
+ let method = request.extensions?.method || options?.method;
238
+ const operationAst = getOperationASTFromRequest(request);
239
+ const operationType = operationAst.operation;
240
+ if ((options?.useGETForQueries || request.extensions?.useGETForQueries) && operationType === "query") {
241
+ method = "GET";
242
+ }
243
+ let accept = "application/graphql-response+json, application/json, multipart/mixed";
244
+ if (operationType === "subscription" || isLiveQueryOperationDefinitionNode(operationAst)) {
245
+ method ||= "GET";
246
+ accept = "text/event-stream";
247
+ } else {
248
+ method ||= "POST";
249
+ }
250
+ const endpoint = request.extensions?.endpoint || options?.endpoint || "/graphql";
251
+ const headers = { accept };
252
+ if (options?.headers) {
253
+ Object.assign(
254
+ headers,
255
+ typeof options?.headers === "function" ? options.headers(request) : options?.headers
256
+ );
257
+ }
258
+ if (request.extensions?.headers) {
259
+ const { headers: headersFromExtensions, ...restExtensions } = request.extensions;
260
+ Object.assign(headers, headersFromExtensions);
261
+ request.extensions = restExtensions;
262
+ }
263
+ const query = printFn(request.document);
264
+ let signal = disposeCtrl?.signal;
265
+ let clearTimeoutFn = () => {
266
+ };
267
+ if (options?.timeout) {
268
+ const timeoutCtrl = new AbortController();
269
+ signal = timeoutCtrl.signal;
270
+ disposeCtrl?.signal.addEventListener("abort", clearTimeoutFn);
271
+ const timeoutId = setTimeout(() => {
272
+ if (!timeoutCtrl.signal.aborted) {
273
+ timeoutCtrl.abort("timeout");
274
+ }
275
+ disposeCtrl?.signal.removeEventListener("abort", clearTimeoutFn);
276
+ }, options.timeout);
277
+ clearTimeoutFn = () => {
278
+ clearTimeout(timeoutId);
279
+ };
280
+ }
281
+ const upstreamErrorExtensions = {
282
+ request: {
283
+ method
284
+ },
285
+ response: {}
286
+ };
287
+ return new ValueOrPromise(() => {
288
+ switch (method) {
289
+ case "GET": {
290
+ const finalUrl = prepareGETUrl({
291
+ baseUrl: endpoint,
292
+ query,
293
+ variables: request.variables,
294
+ operationName: request.operationName,
295
+ extensions: request.extensions
296
+ });
297
+ const fetchOptions = {
298
+ method: "GET",
299
+ headers,
300
+ signal
301
+ };
302
+ if (options?.credentials != null) {
303
+ fetchOptions.credentials = options.credentials;
304
+ }
305
+ upstreamErrorExtensions.request.url = finalUrl;
306
+ return fetchFn(finalUrl, fetchOptions, request.context, request.info);
307
+ }
308
+ case "POST": {
309
+ const body = {
310
+ query,
311
+ variables: request.variables,
312
+ operationName: request.operationName,
313
+ extensions: request.extensions
314
+ };
315
+ upstreamErrorExtensions.request.body = body;
316
+ return new ValueOrPromise(
317
+ () => createFormDataFromVariables(body, {
318
+ File: options?.File,
319
+ FormData: options?.FormData
320
+ })
321
+ ).then((body2) => {
322
+ if (typeof body2 === "string" && !headers["content-type"]) {
323
+ upstreamErrorExtensions.request.body = body2;
324
+ headers["content-type"] = "application/json";
325
+ }
326
+ const fetchOptions = {
327
+ method: "POST",
328
+ body: body2,
329
+ headers,
330
+ signal
331
+ };
332
+ if (options?.credentials != null) {
333
+ fetchOptions.credentials = options.credentials;
334
+ }
335
+ return fetchFn(
336
+ endpoint,
337
+ fetchOptions,
338
+ request.context,
339
+ request.info
340
+ );
341
+ }).resolve();
342
+ }
343
+ }
344
+ }).then((fetchResult) => {
345
+ upstreamErrorExtensions.response.status = fetchResult.status;
346
+ upstreamErrorExtensions.response.statusText = fetchResult.statusText;
347
+ Object.defineProperty(upstreamErrorExtensions.response, "headers", {
348
+ get() {
349
+ return Object.fromEntries(fetchResult.headers.entries());
350
+ }
351
+ });
352
+ clearTimeoutFn();
353
+ if (options?.retry != null && !fetchResult.status.toString().startsWith("2")) {
354
+ throw new Error(
355
+ fetchResult.statusText || `Upstream HTTP Error: ${fetchResult.status}`
356
+ );
357
+ }
358
+ const contentType = fetchResult.headers.get("content-type");
359
+ if (contentType?.includes("text/event-stream")) {
360
+ return handleEventStreamResponse(fetchResult);
361
+ } else if (contentType?.includes("multipart/mixed")) {
362
+ return handleMultipartMixedResponse(fetchResult);
363
+ }
364
+ return fetchResult.text();
365
+ }).then((result) => {
366
+ if (typeof result === "string") {
367
+ upstreamErrorExtensions.response.body = result;
368
+ if (result) {
369
+ try {
370
+ const parsedResult = JSON.parse(result);
371
+ upstreamErrorExtensions.response.body = parsedResult;
372
+ if (parsedResult.data == null && (parsedResult.errors == null || parsedResult.errors.length === 0)) {
373
+ return {
374
+ errors: [
375
+ createGraphQLError(
376
+ 'Unexpected empty "data" and "errors" fields in result: ' + result,
377
+ {
378
+ extensions: upstreamErrorExtensions
379
+ }
380
+ )
381
+ ]
382
+ };
383
+ }
384
+ if (Array.isArray(parsedResult.errors)) {
385
+ return {
386
+ ...parsedResult,
387
+ errors: parsedResult.errors.map(
388
+ ({
389
+ message,
390
+ ...options2
391
+ }) => createGraphQLError(message, {
392
+ ...options2,
393
+ extensions: {
394
+ code: "DOWNSTREAM_SERVICE_ERROR",
395
+ ...options2.extensions || {}
396
+ }
397
+ })
398
+ )
399
+ };
400
+ }
401
+ return parsedResult;
402
+ } catch (e) {
403
+ return {
404
+ errors: [
405
+ createGraphQLError(
406
+ `Unexpected response: ${JSON.stringify(result)}`,
407
+ {
408
+ extensions: upstreamErrorExtensions,
409
+ originalError: e
410
+ }
411
+ )
412
+ ]
413
+ };
414
+ }
415
+ }
416
+ } else {
417
+ return result;
418
+ }
419
+ }).catch((e) => {
420
+ if (e.name === "AggregateError") {
421
+ return {
422
+ errors: e.errors.map(
423
+ (e2) => coerceFetchError(e2, {
424
+ signal,
425
+ endpoint,
426
+ upstreamErrorExtensions
427
+ })
428
+ )
429
+ };
430
+ }
431
+ return {
432
+ errors: [
433
+ coerceFetchError(e, {
434
+ signal,
435
+ endpoint,
436
+ upstreamErrorExtensions
437
+ })
438
+ ]
439
+ };
440
+ }).resolve();
441
+ };
442
+ let executor = baseExecutor;
443
+ if (options?.retry != null) {
444
+ executor = function retryExecutor(request) {
445
+ let result;
446
+ let attempt = 0;
447
+ function retryAttempt() {
448
+ if (disposeCtrl?.signal.aborted) {
449
+ return createResultForAbort(disposeCtrl.signal);
450
+ }
451
+ attempt++;
452
+ if (attempt > options.retry) {
453
+ if (result != null) {
454
+ return result;
455
+ }
456
+ return {
457
+ errors: [createGraphQLError("No response returned from fetch")]
458
+ };
459
+ }
460
+ return new ValueOrPromise(() => baseExecutor(request)).then((res) => {
461
+ result = res;
462
+ if (result?.errors?.length) {
463
+ return retryAttempt();
464
+ }
465
+ return result;
466
+ }).resolve();
467
+ }
468
+ return retryAttempt();
469
+ };
470
+ }
471
+ if (!options?.disposable) {
472
+ disposeCtrl = void 0;
473
+ return executor;
474
+ }
475
+ disposeCtrl = new AbortController();
476
+ Object.defineProperties(executor, {
477
+ [Symbol.dispose]: {
478
+ get() {
479
+ return function dispose() {
480
+ return disposeCtrl.abort(createAbortErrorReason());
481
+ };
482
+ }
483
+ },
484
+ [Symbol.asyncDispose]: {
485
+ get() {
486
+ return function asyncDispose() {
487
+ return disposeCtrl.abort(createAbortErrorReason());
488
+ };
489
+ }
490
+ }
491
+ });
492
+ return executor;
493
+ }
494
+ function coerceFetchError(e, {
495
+ signal,
496
+ endpoint,
497
+ upstreamErrorExtensions
498
+ }) {
499
+ if (typeof e === "string") {
500
+ return createGraphQLError(e, {
501
+ extensions: upstreamErrorExtensions
502
+ });
503
+ } else if (e.name === "GraphQLError") {
504
+ return e;
505
+ } else if (e.name === "TypeError" && e.message === "fetch failed") {
506
+ return createGraphQLError(`fetch failed to ${endpoint}`, {
507
+ extensions: upstreamErrorExtensions,
508
+ originalError: e
509
+ });
510
+ } else if (e.name === "AbortError" && signal?.reason) {
511
+ return createGraphQLErrorForAbort(signal, {
512
+ extensions: upstreamErrorExtensions
513
+ });
514
+ } else if (e.message) {
515
+ return createGraphQLError(e.message, {
516
+ extensions: upstreamErrorExtensions,
517
+ originalError: e
518
+ });
519
+ } else {
520
+ return createGraphQLError("Unknown error", {
521
+ extensions: upstreamErrorExtensions,
522
+ originalError: e
523
+ });
524
+ }
525
+ }
526
+ function createAbortErrorReason() {
527
+ return new Error("Executor was disposed.");
528
+ }
529
+ function createGraphQLErrorForAbort(signal, extensions) {
530
+ return createGraphQLError(
531
+ "The operation was aborted. reason: " + signal.reason,
532
+ {
533
+ extensions
534
+ }
535
+ );
536
+ }
537
+ function createResultForAbort(signal, extensions) {
538
+ return {
539
+ errors: [createGraphQLErrorForAbort(signal, extensions)]
540
+ };
541
+ }
542
+
543
+ export { buildHTTPExecutor, isLiveQueryOperationDefinitionNode };