@graphql-tools/url-loader 7.2.1-alpha-0dcd17c0.0 → 7.2.1

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.
@@ -0,0 +1 @@
1
+ export declare function addCancelToResponseStream<T>(resultStream: AsyncIterable<T>, controller: AbortController): AsyncIterator<T | undefined, any, undefined>;
@@ -0,0 +1,3 @@
1
+ import { fetch as crossFetch } from 'cross-fetch';
2
+ export declare type AsyncFetchFn = typeof crossFetch;
3
+ export declare const defaultAsyncFetch: AsyncFetchFn;
@@ -0,0 +1,6 @@
1
+ export declare const defaultSyncFetch: SyncFetchFn;
2
+ export declare type SyncFetchFn = (input: RequestInfo, init?: RequestInit) => SyncResponse;
3
+ export declare type SyncResponse = Omit<Response, 'json' | 'text'> & {
4
+ json: () => any;
5
+ text: () => string;
6
+ };
@@ -0,0 +1,2 @@
1
+ import { ExecutionResult } from 'graphql';
2
+ export declare function handleEventStreamResponse(response: Response): Promise<AsyncIterableIterator<ExecutionResult>>;
@@ -0,0 +1,2 @@
1
+ import { ExecutionResult } from 'graphql';
2
+ export declare function handlePart(part: string): false | ExecutionResult;
@@ -0,0 +1,7 @@
1
+ /// <reference types="node" />
2
+ import type { Readable } from 'stream';
3
+ export declare function handleReadable(readable: Readable): AsyncGenerator<import("graphql").ExecutionResult<{
4
+ [key: string]: any;
5
+ }, {
6
+ [key: string]: any;
7
+ }>, void, unknown>;
@@ -0,0 +1 @@
1
+ export declare function handleReadableStream(stream: ReadableStream<Uint8Array>): AsyncGenerator<ReadableStreamDefaultReadValueResult<Uint8Array>, void, unknown>;
@@ -0,0 +1,6 @@
1
+ import { ExecutionResult } from 'graphql';
2
+ export declare function handleMultipartMixedResponse(response: Response): Promise<AsyncIterableIterator<ExecutionResult<{
3
+ [key: string]: any;
4
+ }, {
5
+ [key: string]: any;
6
+ }> | undefined>>;
package/index.d.ts CHANGED
@@ -6,14 +6,9 @@ import { ClientOptions } from 'graphql-ws';
6
6
  import { ClientOptions as GraphQLSSEClientOptions } from 'graphql-sse';
7
7
  import WebSocket from 'isomorphic-ws';
8
8
  import FormData from 'form-data';
9
- import { FetchEventSourceInit } from '@ardatan/fetch-event-source';
10
9
  import { ConnectionParamsOptions } from 'subscriptions-transport-ws';
11
- export declare type AsyncFetchFn = typeof import('cross-fetch').fetch;
12
- export declare type SyncFetchFn = (input: RequestInfo, init?: RequestInit) => SyncResponse;
13
- export declare type SyncResponse = Omit<Response, 'json' | 'text'> & {
14
- json: () => any;
15
- text: () => string;
16
- };
10
+ import { AsyncFetchFn } from './defaultAsyncFetch';
11
+ import { SyncFetchFn } from './defaultSyncFetch';
17
12
  export declare type FetchFn = AsyncFetchFn | SyncFetchFn;
18
13
  export declare type AsyncImportFn = (moduleName: string) => PromiseLike<any>;
19
14
  export declare type SyncImportFn = (moduleName: string) => any;
@@ -66,10 +61,6 @@ export interface LoadFromUrlOptions extends BaseLoaderOptions, Partial<Introspec
66
61
  * Use multipart for POST requests
67
62
  */
68
63
  multipart?: boolean;
69
- /**
70
- * Additional options to pass to the constructor of the underlying EventSource instance.
71
- */
72
- eventSourceOptions?: FetchEventSourceInit;
73
64
  /**
74
65
  * Handle URL as schema SDL
75
66
  */
@@ -123,9 +114,8 @@ export declare class UrlLoader implements Loader<LoadFromUrlOptions> {
123
114
  buildHTTPExecutor(endpoint: string, fetch: AsyncFetchFn, options?: LoadFromUrlOptions): AsyncExecutor<any, ExecutionExtensions>;
124
115
  buildWSExecutor(subscriptionsEndpoint: string, webSocketImpl: typeof WebSocket, connectionParams?: ClientOptions['connectionParams']): AsyncExecutor;
125
116
  buildWSLegacyExecutor(subscriptionsEndpoint: string, webSocketImpl: typeof WebSocket, connectionParams?: ConnectionParamsOptions): AsyncExecutor;
126
- buildSSEExecutor(endpoint: string, fetch: AsyncFetchFn, options?: Omit<LoadFromUrlOptions, 'subscriptionEndpoint'>): AsyncExecutor<any, ExecutionExtensions>;
127
117
  buildGraphQLSSEExecutor(endpoint: string, fetch: AsyncFetchFn, options?: Omit<LoadFromUrlOptions, 'subscriptionEndpoint'>): AsyncExecutor;
128
- getFetch(customFetch: LoadFromUrlOptions['customFetch'], importFn: AsyncImportFn): PromiseLike<AsyncFetchFn>;
118
+ getFetch(customFetch: LoadFromUrlOptions['customFetch'], importFn: AsyncImportFn): PromiseLike<AsyncFetchFn> | AsyncFetchFn;
129
119
  getFetch(customFetch: LoadFromUrlOptions['customFetch'], importFn: SyncImportFn): SyncFetchFn;
130
120
  private getDefaultMethodFromOptions;
131
121
  getWebSocketImpl(importFn: AsyncImportFn, options?: LoadFromUrlOptions): PromiseLike<typeof WebSocket>;
package/index.js CHANGED
@@ -26,25 +26,31 @@ function _interopNamespace(e) {
26
26
  const graphql = require('graphql');
27
27
  const utils = require('@graphql-tools/utils');
28
28
  const validUrl = require('valid-url');
29
- const crossFetch = require('cross-fetch');
30
29
  const wrap = require('@graphql-tools/wrap');
31
30
  const graphqlWs = require('graphql-ws');
32
31
  const graphqlSse = require('graphql-sse');
33
32
  const WebSocket = _interopDefault(require('isomorphic-ws'));
34
- const syncFetchImported = _interopDefault(require('sync-fetch'));
35
33
  const isPromise = _interopDefault(require('is-promise'));
36
34
  const extractFiles = require('extract-files');
37
35
  const FormData = _interopDefault(require('form-data'));
38
- const fetchEventSource = require('@ardatan/fetch-event-source');
39
36
  const subscriptionsTransportWs = require('subscriptions-transport-ws');
40
37
  const AbortController = _interopDefault(require('abort-controller'));
41
- const meros = require('meros');
42
- const _ = _interopDefault(require('lodash'));
43
38
  const valueOrPromise = require('value-or-promise');
44
39
  const graphqlLiveQuery = require('@n1ru4l/graphql-live-query');
40
+ const crossFetch = require('cross-fetch');
41
+ const syncFetchImported = _interopDefault(require('sync-fetch'));
42
+ const node = require('meros/node');
43
+ const browser = require('meros/browser');
44
+ const _ = _interopDefault(require('lodash'));
45
45
 
46
- /* eslint-disable no-case-declarations */
47
- const syncFetch = (input, init) => {
46
+ const defaultAsyncFetch = async (input, init) => {
47
+ if (typeof fetch !== 'undefined') {
48
+ return fetch(input, init);
49
+ }
50
+ return crossFetch.fetch(input, init);
51
+ };
52
+
53
+ const defaultSyncFetch = (input, init) => {
48
54
  if (typeof input === 'string') {
49
55
  init === null || init === void 0 ? true : delete init.signal;
50
56
  }
@@ -53,6 +59,124 @@ const syncFetch = (input, init) => {
53
59
  }
54
60
  return syncFetchImported(input, init);
55
61
  };
62
+
63
+ /* eslint-disable */
64
+ function isIncomingMessage(body) {
65
+ return body != null && typeof body === 'object' && 'pipe' in body;
66
+ }
67
+ async function handleMultipartMixedResponse(response) {
68
+ const body = await response.body;
69
+ const contentType = response.headers.get('content-type') || '';
70
+ let asyncIterator;
71
+ if (isIncomingMessage(body)) {
72
+ // Meros/node expects headers as an object map with the content-type prop
73
+ body.headers = {
74
+ 'content-type': contentType,
75
+ };
76
+ // And it expects `IncomingMessage` and `node-fetch` returns `body` as `Promise<PassThrough>`
77
+ asyncIterator = (await node.meros(body));
78
+ }
79
+ else {
80
+ // Nothing is needed for regular `Response`.
81
+ asyncIterator = (await browser.meros(response));
82
+ }
83
+ const executionResult = {};
84
+ return utils.mapAsyncIterator(asyncIterator, (part) => {
85
+ if (part.json) {
86
+ const chunk = part.body;
87
+ if (chunk.path) {
88
+ if (chunk.data) {
89
+ const path = ['data'];
90
+ _.set(executionResult, path.concat(chunk.path), chunk.data);
91
+ }
92
+ if (chunk.errors) {
93
+ executionResult.errors = (executionResult.errors || []).concat(chunk.errors);
94
+ }
95
+ }
96
+ else {
97
+ if (chunk.data) {
98
+ executionResult.data = chunk.data;
99
+ }
100
+ if (chunk.errors) {
101
+ executionResult.errors = chunk.errors;
102
+ }
103
+ }
104
+ return executionResult;
105
+ }
106
+ });
107
+ }
108
+
109
+ function handlePart(part) {
110
+ const eventStr = part.split('event: ')[1];
111
+ const dataStr = part.split('data: ')[1];
112
+ const data = JSON.parse(dataStr);
113
+ if (data.payload && eventStr) {
114
+ if (eventStr === 'complete') {
115
+ return false;
116
+ }
117
+ else {
118
+ return data.payload;
119
+ }
120
+ }
121
+ return data;
122
+ }
123
+
124
+ async function* handleReadable(readable) {
125
+ outer: for await (const chunk of readable) {
126
+ const chunkStr = chunk.toString();
127
+ for (const part of chunkStr.split('\n\n')) {
128
+ if (part) {
129
+ const result = handlePart(part);
130
+ if (result === false) {
131
+ break outer;
132
+ }
133
+ yield result;
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ /* eslint-disable no-labels */
140
+ async function* handleReadableStream(stream) {
141
+ const decoder = new TextDecoder();
142
+ const reader = stream.getReader();
143
+ try {
144
+ let result;
145
+ outer: while (!(result = await reader.read()).done) {
146
+ const chunk = decoder.decode(result.value);
147
+ for (const part of chunk.toString().split('\n\n')) {
148
+ if (part) {
149
+ const executionResult = handlePart(part);
150
+ if (executionResult === false) {
151
+ break outer;
152
+ }
153
+ yield result;
154
+ }
155
+ }
156
+ }
157
+ }
158
+ finally {
159
+ reader.releaseLock();
160
+ }
161
+ }
162
+
163
+ /* eslint-disable */
164
+ async function handleEventStreamResponse(response) {
165
+ const body = await response.body;
166
+ if (body) {
167
+ if ('pipe' in body) {
168
+ return handleReadable(body);
169
+ }
170
+ return handleReadableStream(body);
171
+ }
172
+ throw new Error('Body is null???');
173
+ }
174
+
175
+ function addCancelToResponseStream(resultStream, controller) {
176
+ return utils.withCancel(resultStream, () => controller.abort());
177
+ }
178
+
179
+ /* eslint-disable no-case-declarations */
56
180
  const asyncImport = (moduleName) => new Promise(function (resolve) { resolve(_interopNamespace(require(moduleName))); });
57
181
  const syncImport = (moduleName) => require(moduleName);
58
182
  (function (SubscriptionProtocol) {
@@ -218,7 +342,7 @@ class UrlLoader {
218
342
  extensions,
219
343
  }),
220
344
  headers: {
221
- accept: 'application/json, multipart/mixed',
345
+ accept: 'application/json, multipart/mixed, text/event-stream',
222
346
  'content-type': 'application/json',
223
347
  ...headers,
224
348
  },
@@ -228,41 +352,12 @@ class UrlLoader {
228
352
  }
229
353
  })
230
354
  .then((fetchResult) => {
231
- const response = {};
232
- const contentType = fetchResult.headers.get
233
- ? fetchResult.headers.get('content-type')
234
- : fetchResult['content-type'];
235
- if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/mixed')) {
236
- return meros.meros(fetchResult).then(maybeStream => {
237
- if (utils.isAsyncIterable(maybeStream)) {
238
- return utils.withCancel(utils.mapAsyncIterator(maybeStream, part => {
239
- if (part.json) {
240
- const chunk = part.body;
241
- if (chunk.path) {
242
- if (chunk.data) {
243
- const path = ['data'];
244
- _.merge(response, _.set({}, path.concat(chunk.path), chunk.data));
245
- }
246
- if (chunk.errors) {
247
- response.errors = (response.errors || []).concat(chunk.errors);
248
- }
249
- }
250
- else {
251
- if (chunk.data) {
252
- response.data = chunk.data;
253
- }
254
- if (chunk.errors) {
255
- response.errors = chunk.errors;
256
- }
257
- }
258
- return response;
259
- }
260
- }), () => controller.abort());
261
- }
262
- else {
263
- return maybeStream.json();
264
- }
265
- });
355
+ const contentType = fetchResult.headers.get('content-type');
356
+ if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('text/event-stream')) {
357
+ return handleEventStreamResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
358
+ }
359
+ else if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/mixed')) {
360
+ return handleMultipartMixedResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
266
361
  }
267
362
  return fetchResult.json();
268
363
  })
@@ -315,52 +410,6 @@ class UrlLoader {
315
410
  }));
316
411
  };
317
412
  }
318
- buildSSEExecutor(endpoint, fetch, options) {
319
- return async ({ document, variables, extensions, operationName }) => {
320
- const controller = new AbortController();
321
- const query = graphql.print(document);
322
- const finalUrl = this.prepareGETUrl({ baseUrl: endpoint, query, variables, operationName, extensions });
323
- return utils.observableToAsyncIterable({
324
- subscribe: observer => {
325
- const headers = Object.assign({}, (options === null || options === void 0 ? void 0 : options.headers) || {}, (extensions === null || extensions === void 0 ? void 0 : extensions.headers) || {});
326
- fetchEventSource.fetchEventSource(finalUrl, {
327
- credentials: 'include',
328
- headers,
329
- method: 'GET',
330
- onerror: error => {
331
- observer.error(error);
332
- },
333
- onmessage: event => {
334
- observer.next(JSON.parse(event.data || '{}'));
335
- },
336
- onopen: async (response) => {
337
- const contentType = response.headers.get('content-type');
338
- if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('text/event-stream'))) {
339
- let error;
340
- try {
341
- const { errors } = await response.json();
342
- error = errors[0];
343
- }
344
- catch (error) {
345
- // Failed to parse body
346
- }
347
- if (error) {
348
- throw error;
349
- }
350
- throw new Error(`Expected content-type to be ${'text/event-stream'} but got "${contentType}".`);
351
- }
352
- },
353
- fetch,
354
- signal: controller.signal,
355
- ...((options === null || options === void 0 ? void 0 : options.eventSourceOptions) || {}),
356
- });
357
- return {
358
- unsubscribe: () => controller.abort(),
359
- };
360
- },
361
- });
362
- };
363
- }
364
413
  buildGraphQLSSEExecutor(endpoint, fetch, options = {}) {
365
414
  const { headers } = options;
366
415
  const client = graphqlSse.createClient({
@@ -394,18 +443,15 @@ class UrlLoader {
394
443
  .then(module => (fetchFnName ? module[fetchFnName] : module))
395
444
  .resolve();
396
445
  }
397
- else {
446
+ else if (typeof customFetch === 'function') {
398
447
  return customFetch;
399
448
  }
400
449
  }
401
450
  if (importFn === asyncImport) {
402
- if (typeof fetch === 'undefined') {
403
- return crossFetch.fetch;
404
- }
405
- return fetch;
451
+ return defaultAsyncFetch;
406
452
  }
407
453
  else {
408
- return syncFetch;
454
+ return defaultSyncFetch;
409
455
  }
410
456
  }
411
457
  getDefaultMethodFromOptions(method, defaultMethod) {
@@ -428,7 +474,10 @@ class UrlLoader {
428
474
  }
429
475
  async buildSubscriptionExecutor(subscriptionsEndpoint, fetch, options) {
430
476
  if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === exports.SubscriptionProtocol.SSE) {
431
- return this.buildSSEExecutor(subscriptionsEndpoint, fetch, options);
477
+ return this.buildHTTPExecutor(subscriptionsEndpoint, fetch, {
478
+ ...options,
479
+ method: 'GET',
480
+ });
432
481
  }
433
482
  else if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === exports.SubscriptionProtocol.GRAPHQL_SSE) {
434
483
  if (!(options === null || options === void 0 ? void 0 : options.subscriptionsEndpoint)) {
@@ -459,7 +508,7 @@ class UrlLoader {
459
508
  if (!operationAst) {
460
509
  throw new Error(`No valid operations found: ${params.operationName || ''}`);
461
510
  }
462
- if (params.operationType === 'subscription' ||
511
+ if (operationAst.operation === 'subscription' ||
463
512
  graphqlLiveQuery.isLiveQueryOperationDefinitionNode(operationAst, params.variables)) {
464
513
  return subscriptionExecutor(params);
465
514
  }
package/index.mjs CHANGED
@@ -1,25 +1,31 @@
1
1
  import { print, getOperationAST, buildASTSchema, buildSchema } from 'graphql';
2
- import { isAsyncIterable, observableToAsyncIterable, parseGraphQLSDL, withCancel, mapAsyncIterator } from '@graphql-tools/utils';
2
+ import { mapAsyncIterator, withCancel, isAsyncIterable, observableToAsyncIterable, parseGraphQLSDL } from '@graphql-tools/utils';
3
3
  import { isWebUri } from 'valid-url';
4
- import { fetch as fetch$1 } from 'cross-fetch';
5
4
  import { introspectSchema, wrapSchema } from '@graphql-tools/wrap';
6
5
  import { createClient } from 'graphql-ws';
7
6
  import { createClient as createClient$1 } from 'graphql-sse';
8
7
  import WebSocket from 'isomorphic-ws';
9
- import syncFetchImported from 'sync-fetch';
10
8
  import isPromise from 'is-promise';
11
9
  import { extractFiles, isExtractableFile } from 'extract-files';
12
10
  import FormData from 'form-data';
13
- import { fetchEventSource } from '@ardatan/fetch-event-source';
14
11
  import { SubscriptionClient } from 'subscriptions-transport-ws';
15
12
  import AbortController from 'abort-controller';
16
- import { meros } from 'meros';
17
- import _ from 'lodash';
18
13
  import { ValueOrPromise } from 'value-or-promise';
19
14
  import { isLiveQueryOperationDefinitionNode } from '@n1ru4l/graphql-live-query';
15
+ import { fetch as fetch$1 } from 'cross-fetch';
16
+ import syncFetchImported from 'sync-fetch';
17
+ import { meros } from 'meros/node';
18
+ import { meros as meros$1 } from 'meros/browser';
19
+ import _ from 'lodash';
20
20
 
21
- /* eslint-disable no-case-declarations */
22
- const syncFetch = (input, init) => {
21
+ const defaultAsyncFetch = async (input, init) => {
22
+ if (typeof fetch !== 'undefined') {
23
+ return fetch(input, init);
24
+ }
25
+ return fetch$1(input, init);
26
+ };
27
+
28
+ const defaultSyncFetch = (input, init) => {
23
29
  if (typeof input === 'string') {
24
30
  init === null || init === void 0 ? true : delete init.signal;
25
31
  }
@@ -28,6 +34,124 @@ const syncFetch = (input, init) => {
28
34
  }
29
35
  return syncFetchImported(input, init);
30
36
  };
37
+
38
+ /* eslint-disable */
39
+ function isIncomingMessage(body) {
40
+ return body != null && typeof body === 'object' && 'pipe' in body;
41
+ }
42
+ async function handleMultipartMixedResponse(response) {
43
+ const body = await response.body;
44
+ const contentType = response.headers.get('content-type') || '';
45
+ let asyncIterator;
46
+ if (isIncomingMessage(body)) {
47
+ // Meros/node expects headers as an object map with the content-type prop
48
+ body.headers = {
49
+ 'content-type': contentType,
50
+ };
51
+ // And it expects `IncomingMessage` and `node-fetch` returns `body` as `Promise<PassThrough>`
52
+ asyncIterator = (await meros(body));
53
+ }
54
+ else {
55
+ // Nothing is needed for regular `Response`.
56
+ asyncIterator = (await meros$1(response));
57
+ }
58
+ const executionResult = {};
59
+ return mapAsyncIterator(asyncIterator, (part) => {
60
+ if (part.json) {
61
+ const chunk = part.body;
62
+ if (chunk.path) {
63
+ if (chunk.data) {
64
+ const path = ['data'];
65
+ _.set(executionResult, path.concat(chunk.path), chunk.data);
66
+ }
67
+ if (chunk.errors) {
68
+ executionResult.errors = (executionResult.errors || []).concat(chunk.errors);
69
+ }
70
+ }
71
+ else {
72
+ if (chunk.data) {
73
+ executionResult.data = chunk.data;
74
+ }
75
+ if (chunk.errors) {
76
+ executionResult.errors = chunk.errors;
77
+ }
78
+ }
79
+ return executionResult;
80
+ }
81
+ });
82
+ }
83
+
84
+ function handlePart(part) {
85
+ const eventStr = part.split('event: ')[1];
86
+ const dataStr = part.split('data: ')[1];
87
+ const data = JSON.parse(dataStr);
88
+ if (data.payload && eventStr) {
89
+ if (eventStr === 'complete') {
90
+ return false;
91
+ }
92
+ else {
93
+ return data.payload;
94
+ }
95
+ }
96
+ return data;
97
+ }
98
+
99
+ async function* handleReadable(readable) {
100
+ outer: for await (const chunk of readable) {
101
+ const chunkStr = chunk.toString();
102
+ for (const part of chunkStr.split('\n\n')) {
103
+ if (part) {
104
+ const result = handlePart(part);
105
+ if (result === false) {
106
+ break outer;
107
+ }
108
+ yield result;
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ /* eslint-disable no-labels */
115
+ async function* handleReadableStream(stream) {
116
+ const decoder = new TextDecoder();
117
+ const reader = stream.getReader();
118
+ try {
119
+ let result;
120
+ outer: while (!(result = await reader.read()).done) {
121
+ const chunk = decoder.decode(result.value);
122
+ for (const part of chunk.toString().split('\n\n')) {
123
+ if (part) {
124
+ const executionResult = handlePart(part);
125
+ if (executionResult === false) {
126
+ break outer;
127
+ }
128
+ yield result;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ finally {
134
+ reader.releaseLock();
135
+ }
136
+ }
137
+
138
+ /* eslint-disable */
139
+ async function handleEventStreamResponse(response) {
140
+ const body = await response.body;
141
+ if (body) {
142
+ if ('pipe' in body) {
143
+ return handleReadable(body);
144
+ }
145
+ return handleReadableStream(body);
146
+ }
147
+ throw new Error('Body is null???');
148
+ }
149
+
150
+ function addCancelToResponseStream(resultStream, controller) {
151
+ return withCancel(resultStream, () => controller.abort());
152
+ }
153
+
154
+ /* eslint-disable no-case-declarations */
31
155
  const asyncImport = (moduleName) => import(moduleName);
32
156
  const syncImport = (moduleName) => require(moduleName);
33
157
  var SubscriptionProtocol;
@@ -194,7 +318,7 @@ class UrlLoader {
194
318
  extensions,
195
319
  }),
196
320
  headers: {
197
- accept: 'application/json, multipart/mixed',
321
+ accept: 'application/json, multipart/mixed, text/event-stream',
198
322
  'content-type': 'application/json',
199
323
  ...headers,
200
324
  },
@@ -204,41 +328,12 @@ class UrlLoader {
204
328
  }
205
329
  })
206
330
  .then((fetchResult) => {
207
- const response = {};
208
- const contentType = fetchResult.headers.get
209
- ? fetchResult.headers.get('content-type')
210
- : fetchResult['content-type'];
211
- if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/mixed')) {
212
- return meros(fetchResult).then(maybeStream => {
213
- if (isAsyncIterable(maybeStream)) {
214
- return withCancel(mapAsyncIterator(maybeStream, part => {
215
- if (part.json) {
216
- const chunk = part.body;
217
- if (chunk.path) {
218
- if (chunk.data) {
219
- const path = ['data'];
220
- _.merge(response, _.set({}, path.concat(chunk.path), chunk.data));
221
- }
222
- if (chunk.errors) {
223
- response.errors = (response.errors || []).concat(chunk.errors);
224
- }
225
- }
226
- else {
227
- if (chunk.data) {
228
- response.data = chunk.data;
229
- }
230
- if (chunk.errors) {
231
- response.errors = chunk.errors;
232
- }
233
- }
234
- return response;
235
- }
236
- }), () => controller.abort());
237
- }
238
- else {
239
- return maybeStream.json();
240
- }
241
- });
331
+ const contentType = fetchResult.headers.get('content-type');
332
+ if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('text/event-stream')) {
333
+ return handleEventStreamResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
334
+ }
335
+ else if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/mixed')) {
336
+ return handleMultipartMixedResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
242
337
  }
243
338
  return fetchResult.json();
244
339
  })
@@ -291,52 +386,6 @@ class UrlLoader {
291
386
  }));
292
387
  };
293
388
  }
294
- buildSSEExecutor(endpoint, fetch, options) {
295
- return async ({ document, variables, extensions, operationName }) => {
296
- const controller = new AbortController();
297
- const query = print(document);
298
- const finalUrl = this.prepareGETUrl({ baseUrl: endpoint, query, variables, operationName, extensions });
299
- return observableToAsyncIterable({
300
- subscribe: observer => {
301
- const headers = Object.assign({}, (options === null || options === void 0 ? void 0 : options.headers) || {}, (extensions === null || extensions === void 0 ? void 0 : extensions.headers) || {});
302
- fetchEventSource(finalUrl, {
303
- credentials: 'include',
304
- headers,
305
- method: 'GET',
306
- onerror: error => {
307
- observer.error(error);
308
- },
309
- onmessage: event => {
310
- observer.next(JSON.parse(event.data || '{}'));
311
- },
312
- onopen: async (response) => {
313
- const contentType = response.headers.get('content-type');
314
- if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('text/event-stream'))) {
315
- let error;
316
- try {
317
- const { errors } = await response.json();
318
- error = errors[0];
319
- }
320
- catch (error) {
321
- // Failed to parse body
322
- }
323
- if (error) {
324
- throw error;
325
- }
326
- throw new Error(`Expected content-type to be ${'text/event-stream'} but got "${contentType}".`);
327
- }
328
- },
329
- fetch,
330
- signal: controller.signal,
331
- ...((options === null || options === void 0 ? void 0 : options.eventSourceOptions) || {}),
332
- });
333
- return {
334
- unsubscribe: () => controller.abort(),
335
- };
336
- },
337
- });
338
- };
339
- }
340
389
  buildGraphQLSSEExecutor(endpoint, fetch, options = {}) {
341
390
  const { headers } = options;
342
391
  const client = createClient$1({
@@ -370,18 +419,15 @@ class UrlLoader {
370
419
  .then(module => (fetchFnName ? module[fetchFnName] : module))
371
420
  .resolve();
372
421
  }
373
- else {
422
+ else if (typeof customFetch === 'function') {
374
423
  return customFetch;
375
424
  }
376
425
  }
377
426
  if (importFn === asyncImport) {
378
- if (typeof fetch === 'undefined') {
379
- return fetch$1;
380
- }
381
- return fetch;
427
+ return defaultAsyncFetch;
382
428
  }
383
429
  else {
384
- return syncFetch;
430
+ return defaultSyncFetch;
385
431
  }
386
432
  }
387
433
  getDefaultMethodFromOptions(method, defaultMethod) {
@@ -404,7 +450,10 @@ class UrlLoader {
404
450
  }
405
451
  async buildSubscriptionExecutor(subscriptionsEndpoint, fetch, options) {
406
452
  if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === SubscriptionProtocol.SSE) {
407
- return this.buildSSEExecutor(subscriptionsEndpoint, fetch, options);
453
+ return this.buildHTTPExecutor(subscriptionsEndpoint, fetch, {
454
+ ...options,
455
+ method: 'GET',
456
+ });
408
457
  }
409
458
  else if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === SubscriptionProtocol.GRAPHQL_SSE) {
410
459
  if (!(options === null || options === void 0 ? void 0 : options.subscriptionsEndpoint)) {
@@ -435,7 +484,7 @@ class UrlLoader {
435
484
  if (!operationAst) {
436
485
  throw new Error(`No valid operations found: ${params.operationName || ''}`);
437
486
  }
438
- if (params.operationType === 'subscription' ||
487
+ if (operationAst.operation === 'subscription' ||
439
488
  isLiveQueryOperationDefinitionNode(operationAst, params.variables)) {
440
489
  return subscriptionExecutor(params);
441
490
  }
package/package.json CHANGED
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "@graphql-tools/url-loader",
3
- "version": "7.2.1-alpha-0dcd17c0.0",
3
+ "version": "7.2.1",
4
4
  "description": "A set of utils for faster development of GraphQL tools",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
7
  "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
8
8
  },
9
9
  "dependencies": {
10
- "@ardatan/fetch-event-source": "2.0.2",
11
- "@graphql-tools/delegate": "8.3.0-alpha-0dcd17c0.0",
12
- "@graphql-tools/utils": "8.4.0-alpha-0dcd17c0.0",
13
- "@graphql-tools/wrap": "8.2.0-alpha-0dcd17c0.0",
10
+ "@graphql-tools/delegate": "^8.2.0",
11
+ "@graphql-tools/utils": "^8.2.0",
12
+ "@graphql-tools/wrap": "^8.1.0",
14
13
  "@n1ru4l/graphql-live-query": "0.8.1",
15
14
  "@types/websocket": "1.0.4",
16
15
  "@types/ws": "^8.0.0",