@graphql-tools/url-loader 7.12.3 → 7.13.0-alpha-6a17be13.0

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,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addCancelToResponseStream = void 0;
4
+ const utils_1 = require("@graphql-tools/utils");
5
+ function addCancelToResponseStream(resultStream, controller) {
6
+ return (0, utils_1.withCancel)(resultStream, () => {
7
+ if (!controller.signal.aborted) {
8
+ controller.abort();
9
+ }
10
+ });
11
+ }
12
+ exports.addCancelToResponseStream = addCancelToResponseStream;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultAsyncFetch = void 0;
4
+ const fetch_1 = require("@whatwg-node/fetch");
5
+ const defaultAsyncFetch = async (input, init) => {
6
+ return (0, fetch_1.fetch)(input, init);
7
+ };
8
+ exports.defaultAsyncFetch = defaultAsyncFetch;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultSyncFetch = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const sync_fetch_1 = tslib_1.__importDefault(require("sync-fetch"));
6
+ const defaultSyncFetch = (input, init) => {
7
+ if (typeof input === 'string') {
8
+ init === null || init === void 0 ? true : delete init.signal;
9
+ }
10
+ else {
11
+ delete input.signal;
12
+ }
13
+ return (0, sync_fetch_1.default)(input, init);
14
+ };
15
+ exports.defaultSyncFetch = defaultSyncFetch;
@@ -1,14 +1,17 @@
1
+ "use strict";
1
2
  /* eslint-disable no-labels */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.handleAsyncIterable = void 0;
2
5
  let decodeUint8Array;
3
6
  if (globalThis.Buffer) {
4
7
  decodeUint8Array = uint8Array => globalThis.Buffer.from(uint8Array).toString('utf-8');
5
8
  }
6
9
  else {
7
10
  const textDecoder = new TextDecoder();
8
- decodeUint8Array = uint8Array => textDecoder.decode(uint8Array);
11
+ decodeUint8Array = uint8Array => textDecoder.decode(uint8Array, { stream: true });
9
12
  }
10
- export async function* handleReadable(readable) {
11
- outer: for await (const chunk of readable) {
13
+ async function* handleAsyncIterable(asyncIterable) {
14
+ outer: for await (const chunk of asyncIterable) {
12
15
  const chunkStr = typeof chunk === 'string' ? chunk : decodeUint8Array(chunk);
13
16
  for (const part of chunkStr.split('\n\n')) {
14
17
  if (part) {
@@ -25,3 +28,4 @@ export async function* handleReadable(readable) {
25
28
  }
26
29
  }
27
30
  }
31
+ exports.handleAsyncIterable = handleAsyncIterable;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleEventStreamResponse = void 0;
4
+ const utils_1 = require("@graphql-tools/utils");
5
+ const handleAsyncIterable_js_1 = require("./handleAsyncIterable.js");
6
+ const handleReadableStream_js_1 = require("./handleReadableStream.js");
7
+ async function handleEventStreamResponse(response) {
8
+ // node-fetch returns body as a promise so we need to resolve it
9
+ const body = response.body;
10
+ if (body) {
11
+ if ((0, utils_1.isAsyncIterable)(body)) {
12
+ return (0, handleAsyncIterable_js_1.handleAsyncIterable)(body);
13
+ }
14
+ return (0, handleReadableStream_js_1.handleReadableStream)(body);
15
+ }
16
+ throw new Error('Response body is expected to be a readable stream but got; ' + (0, utils_1.inspect)(body));
17
+ }
18
+ exports.handleEventStreamResponse = handleEventStreamResponse;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ /* eslint-disable no-labels */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.handleReadableStream = void 0;
5
+ async function* handleReadableStream(readableStream) {
6
+ const textDecoderStream = new TextDecoderStream();
7
+ const decodedStream = readableStream.pipeThrough(textDecoderStream);
8
+ const reader = decodedStream.getReader();
9
+ outer: while (true) {
10
+ const { value, done } = await reader.read();
11
+ if (value) {
12
+ for (const part of value.split('\n\n')) {
13
+ if (part) {
14
+ const eventStr = part.split('event: ')[1];
15
+ const dataStr = part.split('data: ')[1];
16
+ if (eventStr === 'complete') {
17
+ break outer;
18
+ }
19
+ if (dataStr) {
20
+ const data = JSON.parse(dataStr);
21
+ yield data.payload || data;
22
+ }
23
+ }
24
+ }
25
+ }
26
+ if (done) {
27
+ break;
28
+ }
29
+ }
30
+ }
31
+ exports.handleReadableStream = handleReadableStream;
@@ -1,11 +1,14 @@
1
- import { meros as merosIncomingMessage } from 'meros/node';
2
- import { meros as merosReadableStream } from 'meros/browser';
3
- import { mapAsyncIterator } from '@graphql-tools/utils';
4
- import { dset } from 'dset/merge';
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleMultipartMixedResponse = void 0;
4
+ const node_1 = require("meros/node");
5
+ const browser_1 = require("meros/browser");
6
+ const utils_1 = require("@graphql-tools/utils");
7
+ const merge_1 = require("dset/merge");
5
8
  function isIncomingMessage(body) {
6
9
  return body != null && typeof body === 'object' && 'pipe' in body;
7
10
  }
8
- export async function handleMultipartMixedResponse(response) {
11
+ async function handleMultipartMixedResponse(response) {
9
12
  const body = await response.body;
10
13
  const contentType = response.headers.get('content-type') || '';
11
14
  let asyncIterator;
@@ -15,20 +18,20 @@ export async function handleMultipartMixedResponse(response) {
15
18
  'content-type': contentType,
16
19
  };
17
20
  // And it expects `IncomingMessage` and `node-fetch` returns `body` as `Promise<PassThrough>`
18
- asyncIterator = (await merosIncomingMessage(body));
21
+ asyncIterator = (await (0, node_1.meros)(body));
19
22
  }
20
23
  else {
21
24
  // Nothing is needed for regular `Response`.
22
- asyncIterator = (await merosReadableStream(response));
25
+ asyncIterator = (await (0, browser_1.meros)(response));
23
26
  }
24
27
  const executionResult = {};
25
- return mapAsyncIterator(asyncIterator, (part) => {
28
+ return (0, utils_1.mapAsyncIterator)(asyncIterator, (part) => {
26
29
  if (part.json) {
27
30
  const chunk = part.body;
28
31
  if (chunk.path) {
29
32
  if (chunk.data) {
30
33
  const path = ['data'];
31
- dset(executionResult, path.concat(chunk.path), chunk.data);
34
+ (0, merge_1.dset)(executionResult, path.concat(chunk.path), chunk.data);
32
35
  }
33
36
  if (chunk.errors) {
34
37
  executionResult.errors = (executionResult.errors || []).concat(chunk.errors);
@@ -46,3 +49,4 @@ export async function handleMultipartMixedResponse(response) {
46
49
  }
47
50
  });
48
51
  }
52
+ exports.handleMultipartMixedResponse = handleMultipartMixedResponse;
@@ -1,23 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UrlLoader = exports.SubscriptionProtocol = void 0;
4
+ const tslib_1 = require("tslib");
1
5
  /* eslint-disable no-case-declarations */
2
6
  /// <reference lib="dom" />
3
- import { print, buildASTSchema, buildSchema } from 'graphql';
4
- import { observableToAsyncIterable, isAsyncIterable, parseGraphQLSDL, getOperationASTFromRequest, } from '@graphql-tools/utils';
5
- import { introspectSchema, wrapSchema } from '@graphql-tools/wrap';
6
- import { createClient } from 'graphql-ws';
7
- import WebSocket from 'isomorphic-ws';
8
- import { extractFiles, isExtractableFile } from 'extract-files';
9
- import { ValueOrPromise } from 'value-or-promise';
10
- import { isLiveQueryOperationDefinitionNode } from '@n1ru4l/graphql-live-query';
11
- import { defaultAsyncFetch } from './defaultAsyncFetch.js';
12
- import { defaultSyncFetch } from './defaultSyncFetch.js';
13
- import { handleMultipartMixedResponse } from './handleMultipartMixedResponse.js';
14
- import { handleEventStreamResponse } from './event-stream/handleEventStreamResponse.js';
15
- import { addCancelToResponseStream } from './addCancelToResponseStream.js';
16
- import { AbortController, FormData, File } from '@whatwg-node/fetch';
17
- import { isBlob, isGraphQLUpload, isPromiseLike, LEGACY_WS } from './utils.js';
18
- const asyncImport = (moduleName) => import(moduleName);
7
+ const graphql_1 = require("graphql");
8
+ const utils_1 = require("@graphql-tools/utils");
9
+ const wrap_1 = require("@graphql-tools/wrap");
10
+ const graphql_ws_1 = require("graphql-ws");
11
+ const isomorphic_ws_1 = tslib_1.__importDefault(require("isomorphic-ws"));
12
+ const extract_files_1 = require("extract-files");
13
+ const value_or_promise_1 = require("value-or-promise");
14
+ const graphql_live_query_1 = require("@n1ru4l/graphql-live-query");
15
+ const defaultAsyncFetch_js_1 = require("./defaultAsyncFetch.js");
16
+ const defaultSyncFetch_js_1 = require("./defaultSyncFetch.js");
17
+ const handleMultipartMixedResponse_js_1 = require("./handleMultipartMixedResponse.js");
18
+ const handleEventStreamResponse_js_1 = require("./event-stream/handleEventStreamResponse.js");
19
+ const addCancelToResponseStream_js_1 = require("./addCancelToResponseStream.js");
20
+ const fetch_1 = require("@whatwg-node/fetch");
21
+ const utils_js_1 = require("./utils.js");
22
+ const asyncImport = (moduleName) => Promise.resolve().then(() => tslib_1.__importStar(require(moduleName)));
19
23
  const syncImport = (moduleName) => require(moduleName);
20
- export var SubscriptionProtocol;
24
+ var SubscriptionProtocol;
21
25
  (function (SubscriptionProtocol) {
22
26
  SubscriptionProtocol["WS"] = "WS";
23
27
  /**
@@ -32,7 +36,7 @@ export var SubscriptionProtocol;
32
36
  * Use `graphql-sse` for subscriptions
33
37
  */
34
38
  SubscriptionProtocol["GRAPHQL_SSE"] = "GRAPHQL_SSE";
35
- })(SubscriptionProtocol || (SubscriptionProtocol = {}));
39
+ })(SubscriptionProtocol = exports.SubscriptionProtocol || (exports.SubscriptionProtocol = {}));
36
40
  function isCompatibleUri(uri) {
37
41
  try {
38
42
  // eslint-disable-next-line no-new
@@ -55,12 +59,12 @@ function isCompatibleUri(uri) {
55
59
  * });
56
60
  * ```
57
61
  */
58
- export class UrlLoader {
62
+ class UrlLoader {
59
63
  createFormDataFromVariables({ query, variables, operationName, extensions, }) {
60
64
  const vars = Object.assign({}, variables);
61
- const { clone, files } = extractFiles(vars, 'variables', ((v) => isExtractableFile(v) ||
65
+ const { clone, files } = (0, extract_files_1.extractFiles)(vars, 'variables', ((v) => (0, extract_files_1.isExtractableFile)(v) ||
62
66
  (v === null || v === void 0 ? void 0 : v.promise) ||
63
- isAsyncIterable(v) ||
67
+ (0, utils_1.isAsyncIterable)(v) ||
64
68
  (v === null || v === void 0 ? void 0 : v.then) ||
65
69
  typeof (v === null || v === void 0 ? void 0 : v.arrayBuffer) === 'function'));
66
70
  const map = {};
@@ -71,7 +75,7 @@ export class UrlLoader {
71
75
  uploads[currIndex] = file;
72
76
  currIndex++;
73
77
  }
74
- const form = new FormData();
78
+ const form = new fetch_1.FormData();
75
79
  form.append('operations', JSON.stringify({
76
80
  query,
77
81
  variables: clone,
@@ -83,16 +87,16 @@ export class UrlLoader {
83
87
  const indexStr = i.toString();
84
88
  if (upload != null) {
85
89
  const filename = upload.filename || upload.name || upload.path || `blob-${indexStr}`;
86
- if (isPromiseLike(upload)) {
90
+ if ((0, utils_js_1.isPromiseLike)(upload)) {
87
91
  return upload.then((resolvedUpload) => handleUpload(resolvedUpload, i));
88
92
  // If Blob
89
93
  }
90
- else if (isBlob(upload)) {
94
+ else if ((0, utils_js_1.isBlob)(upload)) {
91
95
  return upload.arrayBuffer().then((arrayBuffer) => {
92
- form.append(indexStr, new File([arrayBuffer], filename, { type: upload.type }), filename);
96
+ form.append(indexStr, new fetch_1.File([arrayBuffer], filename, { type: upload.type }), filename);
93
97
  });
94
98
  }
95
- else if (isGraphQLUpload(upload)) {
99
+ else if ((0, utils_js_1.isGraphQLUpload)(upload)) {
96
100
  const stream = upload.createReadStream();
97
101
  const chunks = [];
98
102
  return Promise.resolve().then(async () => {
@@ -102,15 +106,15 @@ export class UrlLoader {
102
106
  }
103
107
  }
104
108
  const blobPart = new Uint8Array(chunks);
105
- form.append(indexStr, new File([blobPart], filename, { type: upload.mimetype }), filename);
109
+ form.append(indexStr, new fetch_1.File([blobPart], filename, { type: upload.mimetype }), filename);
106
110
  });
107
111
  }
108
112
  else {
109
- form.append(indexStr, new File([upload], filename), filename);
113
+ form.append(indexStr, new fetch_1.File([upload], filename), filename);
110
114
  }
111
115
  }
112
116
  }
113
- return ValueOrPromise.all(uploads.map((upload, i) => new ValueOrPromise(() => handleUpload(upload, i))))
117
+ return value_or_promise_1.ValueOrPromise.all(uploads.map((upload, i) => new value_or_promise_1.ValueOrPromise(() => handleUpload(upload, i))))
114
118
  .then(() => form)
115
119
  .resolve();
116
120
  }
@@ -147,15 +151,15 @@ export class UrlLoader {
147
151
  });
148
152
  const executor = (request) => {
149
153
  var _a, _b;
150
- const controller = new AbortController();
154
+ const controller = new fetch_1.AbortController();
151
155
  let method = defaultMethod;
152
- const operationAst = getOperationASTFromRequest(request);
156
+ const operationAst = (0, utils_1.getOperationASTFromRequest)(request);
153
157
  const operationType = operationAst.operation;
154
158
  if ((options === null || options === void 0 ? void 0 : options.useGETForQueries) && operationType === 'query') {
155
159
  method = 'GET';
156
160
  }
157
161
  let accept = 'application/json, multipart/mixed';
158
- if (operationType === 'subscription' || isLiveQueryOperationDefinitionNode(operationAst)) {
162
+ if (operationType === 'subscription' || (0, graphql_live_query_1.isLiveQueryOperationDefinitionNode)(operationAst)) {
159
163
  method = 'GET';
160
164
  accept = 'text/event-stream';
161
165
  }
@@ -163,7 +167,7 @@ export class UrlLoader {
163
167
  const headers = Object.assign({
164
168
  accept,
165
169
  }, options === null || options === void 0 ? void 0 : options.headers, ((_b = request.extensions) === null || _b === void 0 ? void 0 : _b.headers) || {});
166
- const query = print(request.document);
170
+ const query = (0, graphql_1.print)(request.document);
167
171
  const requestBody = {
168
172
  query,
169
173
  variables: request.variables,
@@ -179,7 +183,7 @@ export class UrlLoader {
179
183
  }, options.timeout);
180
184
  }
181
185
  const credentials = (options === null || options === void 0 ? void 0 : options.credentials) !== 'disable' ? (options === null || options === void 0 ? void 0 : options.credentials) || 'same-origin' : null;
182
- return new ValueOrPromise(() => {
186
+ return new value_or_promise_1.ValueOrPromise(() => {
183
187
  switch (method) {
184
188
  case 'GET':
185
189
  const finalUrl = this.prepareGETUrl({
@@ -194,7 +198,7 @@ export class UrlLoader {
194
198
  });
195
199
  case 'POST':
196
200
  if (options === null || options === void 0 ? void 0 : options.multipart) {
197
- return new ValueOrPromise(() => this.createFormDataFromVariables(requestBody))
201
+ return new value_or_promise_1.ValueOrPromise(() => this.createFormDataFromVariables(requestBody))
198
202
  .then(form => fetch(endpoint, {
199
203
  method: 'POST',
200
204
  ...(credentials != null ? { credentials } : {}),
@@ -228,10 +232,10 @@ export class UrlLoader {
228
232
  }
229
233
  const contentType = fetchResult.headers.get('content-type');
230
234
  if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('text/event-stream')) {
231
- return handleEventStreamResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
235
+ return (0, handleEventStreamResponse_js_1.handleEventStreamResponse)(fetchResult).then(resultStream => (0, addCancelToResponseStream_js_1.addCancelToResponseStream)(resultStream, controller));
232
236
  }
233
237
  else if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/mixed')) {
234
- return handleMultipartMixedResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
238
+ return (0, handleMultipartMixedResponse_js_1.handleMultipartMixedResponse)(fetchResult).then(resultStream => (0, addCancelToResponseStream_js_1.addCancelToResponseStream)(resultStream, controller));
235
239
  }
236
240
  return fetchResult.text();
237
241
  })
@@ -263,7 +267,7 @@ export class UrlLoader {
263
267
  }
264
268
  throw new Error('No result');
265
269
  }
266
- return new ValueOrPromise(() => executor(request))
270
+ return new value_or_promise_1.ValueOrPromise(() => executor(request))
267
271
  .then(res => {
268
272
  var _a;
269
273
  result = res;
@@ -288,15 +292,15 @@ export class UrlLoader {
288
292
  https: 'wss',
289
293
  http: 'ws',
290
294
  });
291
- const subscriptionClient = createClient({
295
+ const subscriptionClient = (0, graphql_ws_1.createClient)({
292
296
  url: WS_URL,
293
297
  webSocketImpl,
294
298
  connectionParams,
295
299
  lazy: true,
296
300
  });
297
301
  return ({ document, variables, operationName, extensions }) => {
298
- const query = print(document);
299
- return observableToAsyncIterable({
302
+ const query = (0, graphql_1.print)(document);
303
+ return (0, utils_1.observableToAsyncIterable)({
300
304
  subscribe: observer => {
301
305
  const unsubscribe = subscriptionClient.subscribe({
302
306
  query,
@@ -336,7 +340,7 @@ export class UrlLoader {
336
340
  break;
337
341
  }
338
342
  websocket.send(JSON.stringify({
339
- type: LEGACY_WS.CONNECTION_INIT,
343
+ type: utils_js_1.LEGACY_WS.CONNECTION_INIT,
340
344
  payload,
341
345
  }));
342
346
  };
@@ -344,7 +348,7 @@ export class UrlLoader {
344
348
  const cleanupWebsocket = () => {
345
349
  if (websocket != null && observerById.size === 0) {
346
350
  websocket.send(JSON.stringify({
347
- type: LEGACY_WS.CONNECTION_TERMINATE,
351
+ type: utils_js_1.LEGACY_WS.CONNECTION_TERMINATE,
348
352
  }));
349
353
  websocket.terminate();
350
354
  websocket = null;
@@ -352,7 +356,7 @@ export class UrlLoader {
352
356
  };
353
357
  return function legacyExecutor(request) {
354
358
  const id = Date.now().toString();
355
- return observableToAsyncIterable({
359
+ return (0, utils_1.observableToAsyncIterable)({
356
360
  subscribe(observer) {
357
361
  ensureWebsocket();
358
362
  if (websocket == null) {
@@ -361,38 +365,38 @@ export class UrlLoader {
361
365
  websocket.onmessage = event => {
362
366
  const data = JSON.parse(event.data.toString('utf-8'));
363
367
  switch (data.type) {
364
- case LEGACY_WS.CONNECTION_ACK: {
368
+ case utils_js_1.LEGACY_WS.CONNECTION_ACK: {
365
369
  if (websocket == null) {
366
370
  throw new Error(`WebSocket connection is not found!`);
367
371
  }
368
372
  websocket.send(JSON.stringify({
369
- type: LEGACY_WS.START,
373
+ type: utils_js_1.LEGACY_WS.START,
370
374
  id,
371
375
  payload: {
372
- query: print(request.document),
376
+ query: (0, graphql_1.print)(request.document),
373
377
  variables: request.variables,
374
378
  operationName: request.operationName,
375
379
  },
376
380
  }));
377
381
  break;
378
382
  }
379
- case LEGACY_WS.CONNECTION_ERROR: {
383
+ case utils_js_1.LEGACY_WS.CONNECTION_ERROR: {
380
384
  observer.error(data.payload);
381
385
  break;
382
386
  }
383
- case LEGACY_WS.CONNECTION_KEEP_ALIVE: {
387
+ case utils_js_1.LEGACY_WS.CONNECTION_KEEP_ALIVE: {
384
388
  break;
385
389
  }
386
- case LEGACY_WS.DATA: {
390
+ case utils_js_1.LEGACY_WS.DATA: {
387
391
  observer.next(data.payload);
388
392
  break;
389
393
  }
390
- case LEGACY_WS.COMPLETE: {
394
+ case utils_js_1.LEGACY_WS.COMPLETE: {
391
395
  if (websocket == null) {
392
396
  throw new Error(`WebSocket connection is not found!`);
393
397
  }
394
398
  websocket.send(JSON.stringify({
395
- type: LEGACY_WS.CONNECTION_TERMINATE,
399
+ type: utils_js_1.LEGACY_WS.CONNECTION_TERMINATE,
396
400
  }));
397
401
  observer.complete();
398
402
  cleanupWebsocket();
@@ -403,7 +407,7 @@ export class UrlLoader {
403
407
  return {
404
408
  unsubscribe: () => {
405
409
  websocket === null || websocket === void 0 ? void 0 : websocket.send(JSON.stringify({
406
- type: LEGACY_WS.STOP,
410
+ type: utils_js_1.LEGACY_WS.STOP,
407
411
  id,
408
412
  }));
409
413
  cleanupWebsocket();
@@ -417,7 +421,7 @@ export class UrlLoader {
417
421
  if (customFetch) {
418
422
  if (typeof customFetch === 'string') {
419
423
  const [moduleName, fetchFnName] = customFetch.split('#');
420
- return new ValueOrPromise(() => importFn(moduleName))
424
+ return new value_or_promise_1.ValueOrPromise(() => importFn(moduleName))
421
425
  .then(module => (fetchFnName ? module[fetchFnName] : module))
422
426
  .resolve();
423
427
  }
@@ -426,10 +430,10 @@ export class UrlLoader {
426
430
  }
427
431
  }
428
432
  if (importFn === asyncImport) {
429
- return defaultAsyncFetch;
433
+ return defaultAsyncFetch_js_1.defaultAsyncFetch;
430
434
  }
431
435
  else {
432
- return defaultSyncFetch;
436
+ return defaultSyncFetch_js_1.defaultSyncFetch;
433
437
  }
434
438
  }
435
439
  getDefaultMethodFromOptions(method, defaultMethod) {
@@ -441,12 +445,12 @@ export class UrlLoader {
441
445
  getWebSocketImpl(importFn, options) {
442
446
  if (typeof (options === null || options === void 0 ? void 0 : options.webSocketImpl) === 'string') {
443
447
  const [moduleName, webSocketImplName] = options.webSocketImpl.split('#');
444
- return new ValueOrPromise(() => importFn(moduleName))
448
+ return new value_or_promise_1.ValueOrPromise(() => importFn(moduleName))
445
449
  .then(importedModule => (webSocketImplName ? importedModule[webSocketImplName] : importedModule))
446
450
  .resolve();
447
451
  }
448
452
  else {
449
- const websocketImpl = (options === null || options === void 0 ? void 0 : options.webSocketImpl) || WebSocket;
453
+ const websocketImpl = (options === null || options === void 0 ? void 0 : options.webSocketImpl) || isomorphic_ws_1.default;
450
454
  return websocketImpl;
451
455
  }
452
456
  }
@@ -463,7 +467,7 @@ export class UrlLoader {
463
467
  return this.buildHTTPExecutor(subscriptionsEndpoint, fetch, options);
464
468
  }
465
469
  else {
466
- const webSocketImpl$ = new ValueOrPromise(() => this.getWebSocketImpl(importFn, options));
470
+ const webSocketImpl$ = new value_or_promise_1.ValueOrPromise(() => this.getWebSocketImpl(importFn, options));
467
471
  const executor$ = webSocketImpl$.then(webSocketImpl => {
468
472
  if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === SubscriptionProtocol.LEGACY_WS) {
469
473
  return this.buildWSLegacyExecutor(subscriptionsEndpoint, webSocketImpl, options);
@@ -476,7 +480,7 @@ export class UrlLoader {
476
480
  }
477
481
  }
478
482
  getExecutor(endpoint, importFn, options) {
479
- const fetch$ = new ValueOrPromise(() => this.getFetch(options === null || options === void 0 ? void 0 : options.customFetch, importFn));
483
+ const fetch$ = new value_or_promise_1.ValueOrPromise(() => this.getFetch(options === null || options === void 0 ? void 0 : options.customFetch, importFn));
480
484
  const httpExecutor$ = fetch$.then(fetch => {
481
485
  return this.buildHTTPExecutor(endpoint, fetch, options);
482
486
  });
@@ -487,9 +491,9 @@ export class UrlLoader {
487
491
  });
488
492
  // eslint-disable-next-line no-inner-declarations
489
493
  function getExecutorByRequest(request) {
490
- const operationAst = getOperationASTFromRequest(request);
494
+ const operationAst = (0, utils_1.getOperationASTFromRequest)(request);
491
495
  if (operationAst.operation === 'subscription' ||
492
- isLiveQueryOperationDefinitionNode(operationAst, request.variables)) {
496
+ (0, graphql_live_query_1.isLiveQueryOperationDefinitionNode)(operationAst, request.variables)) {
493
497
  return subscriptionExecutor$;
494
498
  }
495
499
  else {
@@ -512,12 +516,12 @@ export class UrlLoader {
512
516
  }
513
517
  handleSDL(pointer, fetch, options) {
514
518
  const defaultMethod = this.getDefaultMethodFromOptions(options === null || options === void 0 ? void 0 : options.method, 'GET');
515
- return new ValueOrPromise(() => fetch(pointer, {
519
+ return new value_or_promise_1.ValueOrPromise(() => fetch(pointer, {
516
520
  method: defaultMethod,
517
521
  headers: options.headers,
518
522
  }))
519
523
  .then(response => response.text())
520
- .then(schemaString => parseGraphQLSDL(pointer, schemaString, options))
524
+ .then(schemaString => (0, utils_1.parseGraphQLSDL)(pointer, schemaString, options))
521
525
  .resolve();
522
526
  }
523
527
  async load(pointer, options) {
@@ -537,14 +541,14 @@ export class UrlLoader {
537
541
  source.schema =
538
542
  source.schema ||
539
543
  (source.document
540
- ? buildASTSchema(source.document, options)
544
+ ? (0, graphql_1.buildASTSchema)(source.document, options)
541
545
  : source.rawSDL
542
- ? buildSchema(source.rawSDL, options)
546
+ ? (0, graphql_1.buildSchema)(source.rawSDL, options)
543
547
  : undefined);
544
548
  }
545
549
  else {
546
550
  executor = this.getExecutorAsync(pointer, options);
547
- source.schema = await introspectSchema(executor, {}, options);
551
+ source.schema = await (0, wrap_1.introspectSchema)(executor, {}, options);
548
552
  }
549
553
  if (!source.schema) {
550
554
  throw new Error(`Invalid introspected schema`);
@@ -553,7 +557,7 @@ export class UrlLoader {
553
557
  executor = this.getExecutorAsync(options.endpoint, options);
554
558
  }
555
559
  if (executor) {
556
- source.schema = wrapSchema({
560
+ source.schema = (0, wrap_1.wrapSchema)({
557
561
  schema: source.schema,
558
562
  executor,
559
563
  batch: options === null || options === void 0 ? void 0 : options.batch,
@@ -578,14 +582,14 @@ export class UrlLoader {
578
582
  source.schema =
579
583
  source.schema ||
580
584
  (source.document
581
- ? buildASTSchema(source.document, options)
585
+ ? (0, graphql_1.buildASTSchema)(source.document, options)
582
586
  : source.rawSDL
583
- ? buildSchema(source.rawSDL, options)
587
+ ? (0, graphql_1.buildSchema)(source.rawSDL, options)
584
588
  : undefined);
585
589
  }
586
590
  else {
587
591
  executor = this.getExecutorSync(pointer, options);
588
- source.schema = introspectSchema(executor, {}, options);
592
+ source.schema = (0, wrap_1.introspectSchema)(executor, {}, options);
589
593
  }
590
594
  if (!source.schema) {
591
595
  throw new Error(`Invalid introspected schema`);
@@ -594,7 +598,7 @@ export class UrlLoader {
594
598
  executor = this.getExecutorSync(options.endpoint, options);
595
599
  }
596
600
  if (executor) {
597
- source.schema = wrapSchema({
601
+ source.schema = (0, wrap_1.wrapSchema)({
598
602
  schema: source.schema,
599
603
  executor,
600
604
  });
@@ -602,6 +606,7 @@ export class UrlLoader {
602
606
  return [source];
603
607
  }
604
608
  }
609
+ exports.UrlLoader = UrlLoader;
605
610
  function switchProtocols(pointer, protocolMap) {
606
611
  return Object.entries(protocolMap).reduce((prev, [source, target]) => prev.replace(`${source}://`, `${target}://`).replace(`${source}:\\`, `${target}:\\`), pointer);
607
612
  }
@@ -1,13 +1,19 @@
1
- export function isBlob(obj) {
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LEGACY_WS = exports.isPromiseLike = exports.isGraphQLUpload = exports.isBlob = void 0;
4
+ function isBlob(obj) {
2
5
  return typeof obj.arrayBuffer === 'function';
3
6
  }
4
- export function isGraphQLUpload(upload) {
7
+ exports.isBlob = isBlob;
8
+ function isGraphQLUpload(upload) {
5
9
  return typeof upload.createReadStream === 'function';
6
10
  }
7
- export function isPromiseLike(obj) {
11
+ exports.isGraphQLUpload = isGraphQLUpload;
12
+ function isPromiseLike(obj) {
8
13
  return typeof obj.then === 'function';
9
14
  }
10
- export var LEGACY_WS;
15
+ exports.isPromiseLike = isPromiseLike;
16
+ var LEGACY_WS;
11
17
  (function (LEGACY_WS) {
12
18
  LEGACY_WS["CONNECTION_INIT"] = "connection_init";
13
19
  LEGACY_WS["CONNECTION_ACK"] = "connection_ack";
@@ -19,4 +25,4 @@ export var LEGACY_WS;
19
25
  LEGACY_WS["DATA"] = "data";
20
26
  LEGACY_WS["ERROR"] = "error";
21
27
  LEGACY_WS["COMPLETE"] = "complete";
22
- })(LEGACY_WS || (LEGACY_WS = {}));
28
+ })(LEGACY_WS = exports.LEGACY_WS || (exports.LEGACY_WS = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-tools/url-loader",
3
- "version": "7.12.3",
3
+ "version": "7.13.0-alpha-6a17be13.0",
4
4
  "description": "A set of utils for faster development of GraphQL tools",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -1,8 +0,0 @@
1
- import { withCancel } from '@graphql-tools/utils';
2
- export function addCancelToResponseStream(resultStream, controller) {
3
- return withCancel(resultStream, () => {
4
- if (!controller.signal.aborted) {
5
- controller.abort();
6
- }
7
- });
8
- }
@@ -1,4 +0,0 @@
1
- import { fetch } from '@whatwg-node/fetch';
2
- export const defaultAsyncFetch = async (input, init) => {
3
- return fetch(input, init);
4
- };
@@ -1,10 +0,0 @@
1
- import syncFetchImported from 'sync-fetch';
2
- export const defaultSyncFetch = (input, init) => {
3
- if (typeof input === 'string') {
4
- init === null || init === void 0 ? true : delete init.signal;
5
- }
6
- else {
7
- delete input.signal;
8
- }
9
- return syncFetchImported(input, init);
10
- };
@@ -1,14 +0,0 @@
1
- import { inspect, isAsyncIterable } from '@graphql-tools/utils';
2
- import { handleReadable } from './handleReadable.js';
3
- import { handleReadableStream } from './handleReadableStream.js';
4
- export async function handleEventStreamResponse(response) {
5
- // node-fetch returns body as a promise so we need to resolve it
6
- const body = await response.body;
7
- if (body) {
8
- if (isAsyncIterable(body)) {
9
- return handleReadable(body);
10
- }
11
- return handleReadableStream(body);
12
- }
13
- throw new Error('Response body is expected to be a readable stream but got; ' + inspect(body));
14
- }
@@ -1,127 +0,0 @@
1
- // Based on https://github.com/Azure/fetch-event-source/blob/main/src/parse.ts
2
- export async function* handleReadableStream(stream) {
3
- const decoder = new TextDecoder();
4
- const reader = stream.getReader();
5
- let buffer;
6
- let position = 0; // current read position
7
- let fieldLength = -1; // length of the `field` portion of the line
8
- let discardTrailingNewline = false;
9
- try {
10
- let result;
11
- let message = {
12
- data: '',
13
- event: '',
14
- id: '',
15
- retry: undefined,
16
- };
17
- while (!(result = await reader.read()).done) {
18
- const arr = result.value;
19
- if (buffer === undefined) {
20
- buffer = arr;
21
- position = 0;
22
- fieldLength = -1;
23
- }
24
- else {
25
- // we're still parsing the old line. Append the new bytes into buffer:
26
- buffer = concat(buffer, arr);
27
- }
28
- const bufLength = buffer.length;
29
- let lineStart = 0; // index where the current line starts
30
- while (position < bufLength) {
31
- if (discardTrailingNewline) {
32
- if (buffer[position] === 10 /* ControlChars.NewLine */) {
33
- lineStart = ++position; // skip to next char
34
- }
35
- discardTrailingNewline = false;
36
- }
37
- // start looking forward till the end of line:
38
- let lineEnd = -1; // index of the \r or \n char
39
- for (; position < bufLength && lineEnd === -1; ++position) {
40
- switch (buffer[position]) {
41
- case 58 /* ControlChars.Colon */: {
42
- if (fieldLength === -1) {
43
- // first colon in line
44
- fieldLength = position - lineStart;
45
- }
46
- break;
47
- }
48
- case 13 /* ControlChars.CarriageReturn */: {
49
- discardTrailingNewline = true;
50
- break;
51
- }
52
- case 10 /* ControlChars.NewLine */: {
53
- lineEnd = position;
54
- break;
55
- }
56
- }
57
- }
58
- if (lineEnd === -1) {
59
- // We reached the end of the buffer but the line hasn't ended.
60
- // Wait for the next arr and then continue parsing:
61
- break;
62
- }
63
- // we've reached the line end, send it out:
64
- const line = buffer.subarray(lineStart, lineEnd);
65
- if (line.length === 0) {
66
- // empty line denotes end of message. Trigger the callback and start a new message:
67
- if (message.event || message.data) {
68
- // NOT a server ping (":\n\n")
69
- yield JSON.parse(message.data);
70
- message = {
71
- data: '',
72
- event: '',
73
- id: '',
74
- retry: undefined,
75
- };
76
- }
77
- }
78
- else if (fieldLength > 0) {
79
- // exclude comments and lines with no values
80
- // line is of format "<field>:<value>" or "<field>: <value>"
81
- // https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
82
- const field = decoder.decode(line.subarray(0, fieldLength));
83
- const valueOffset = fieldLength + (line[fieldLength + 1] === 32 /* ControlChars.Space */ ? 2 : 1);
84
- const value = decoder.decode(line.subarray(valueOffset));
85
- switch (field) {
86
- case 'data':
87
- // if this message already has data, append the new value to the old.
88
- // otherwise, just set to the new value:
89
- message.data = message.data ? message.data + '\n' + value : value; // otherwise,
90
- break;
91
- case 'event':
92
- message.event = value;
93
- break;
94
- case 'id':
95
- message.id = value;
96
- break;
97
- case 'retry': {
98
- const retry = parseInt(value, 10);
99
- message.retry = retry;
100
- break;
101
- }
102
- }
103
- }
104
- lineStart = position; // we're now on the next line
105
- fieldLength = -1;
106
- }
107
- if (lineStart === bufLength) {
108
- buffer = undefined; // we've finished reading it
109
- }
110
- else if (lineStart !== 0) {
111
- // Create a new view into buffer beginning at lineStart so we don't
112
- // need to copy over the previous lines when we get the new arr:
113
- buffer = buffer.subarray(lineStart);
114
- position -= lineStart;
115
- }
116
- }
117
- }
118
- finally {
119
- reader.releaseLock();
120
- }
121
- }
122
- function concat(a, b) {
123
- const res = new Uint8Array(a.length + b.length);
124
- res.set(a);
125
- res.set(b, a.length);
126
- return res;
127
- }
@@ -1 +0,0 @@
1
- export declare function addCancelToResponseStream<T>(resultStream: AsyncIterable<T>, controller: AbortController): AsyncIterable<T>;
@@ -1,3 +0,0 @@
1
- import { fetch } from '@whatwg-node/fetch';
2
- export declare type AsyncFetchFn = typeof fetch;
3
- export declare const defaultAsyncFetch: AsyncFetchFn;
@@ -1,6 +0,0 @@
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
- };
@@ -1,2 +0,0 @@
1
- import { ExecutionResult } from 'graphql';
2
- export declare function handleEventStreamResponse(response: Response): Promise<AsyncGenerator<ExecutionResult>>;
@@ -1 +0,0 @@
1
- export declare function handleReadable(readable: AsyncIterable<Uint8Array | string>): AsyncGenerator<any, void, unknown>;
@@ -1,15 +0,0 @@
1
- /**
2
- * Represents a message sent in an event stream
3
- * https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format
4
- */
5
- export interface EventSourceMessage {
6
- /** The event ID to set the EventSource object's last event ID value. */
7
- id: string;
8
- /** A string identifying the type of event described. */
9
- event: string;
10
- /** The event data */
11
- data: string;
12
- /** The reconnection interval (in milliseconds) to wait before retrying the connection */
13
- retry?: number;
14
- }
15
- export declare function handleReadableStream(stream: ReadableStream<Uint8Array>): AsyncGenerator<any, void, unknown>;
@@ -1,2 +0,0 @@
1
- import type { ExecutionResult } from 'graphql';
2
- export declare function handleMultipartMixedResponse(response: Response): Promise<AsyncIterableIterator<ExecutionResult<import("graphql/jsutils/ObjMap").ObjMap<unknown>, import("graphql/jsutils/ObjMap").ObjMap<unknown>> | undefined>>;
@@ -1,151 +0,0 @@
1
- /// <reference types="ws" />
2
- /// <reference lib="dom" />
3
- import { IntrospectionOptions } from 'graphql';
4
- import { AsyncExecutor, Executor, SyncExecutor, Source, Loader, BaseLoaderOptions } from '@graphql-tools/utils';
5
- import { ClientOptions } from 'graphql-ws';
6
- import WebSocket from 'isomorphic-ws';
7
- import { AsyncFetchFn } from './defaultAsyncFetch.js';
8
- import { SyncFetchFn } from './defaultSyncFetch.js';
9
- export declare type FetchFn = AsyncFetchFn | SyncFetchFn;
10
- export declare type AsyncImportFn = (moduleName: string) => PromiseLike<any>;
11
- export declare type SyncImportFn = (moduleName: string) => any;
12
- declare type HeadersConfig = Record<string, string>;
13
- interface ExecutionExtensions {
14
- headers?: HeadersConfig;
15
- endpoint?: string;
16
- }
17
- export declare enum SubscriptionProtocol {
18
- WS = "WS",
19
- /**
20
- * Use legacy web socket protocol `graphql-ws` instead of the more current standard `graphql-transport-ws`
21
- */
22
- LEGACY_WS = "LEGACY_WS",
23
- /**
24
- * Use SSE for subscription instead of WebSocket
25
- */
26
- SSE = "SSE",
27
- /**
28
- * Use `graphql-sse` for subscriptions
29
- */
30
- GRAPHQL_SSE = "GRAPHQL_SSE"
31
- }
32
- /**
33
- * Additional options for loading from a URL
34
- */
35
- export interface LoadFromUrlOptions extends BaseLoaderOptions, Partial<IntrospectionOptions> {
36
- /**
37
- * Additional headers to include when querying the original schema
38
- */
39
- headers?: HeadersConfig;
40
- /**
41
- * A custom `fetch` implementation to use when querying the original schema.
42
- * Defaults to `cross-fetch`
43
- */
44
- customFetch?: FetchFn | string;
45
- /**
46
- * HTTP method to use when querying the original schema.
47
- */
48
- method?: 'GET' | 'POST';
49
- /**
50
- * Custom WebSocket implementation used by the loaded schema if subscriptions
51
- * are enabled
52
- */
53
- webSocketImpl?: typeof WebSocket | string;
54
- /**
55
- * Whether to use the GET HTTP method for queries when querying the original schema
56
- */
57
- useGETForQueries?: boolean;
58
- /**
59
- * Use multipart for POST requests
60
- */
61
- multipart?: boolean;
62
- /**
63
- * Handle URL as schema SDL
64
- */
65
- handleAsSDL?: boolean;
66
- /**
67
- * Regular HTTP endpoint; defaults to the pointer
68
- */
69
- endpoint?: string;
70
- /**
71
- * Subscriptions endpoint; defaults to the endpoint given as HTTP endpoint
72
- */
73
- subscriptionsEndpoint?: string;
74
- /**
75
- * Use specific protocol for subscriptions
76
- */
77
- subscriptionsProtocol?: SubscriptionProtocol;
78
- /**
79
- * @deprecated This is no longer used. Will be removed in the next release
80
- */
81
- graphqlSseOptions?: any;
82
- /**
83
- * Retry attempts
84
- */
85
- retry?: number;
86
- /**
87
- * Timeout in milliseconds
88
- */
89
- timeout?: number;
90
- /**
91
- * Request Credentials (default: 'same-origin')
92
- * You can pass `disable` if you don't want this to be set in `Request`
93
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
94
- */
95
- credentials?: RequestCredentials | 'disable';
96
- /**
97
- * Connection Parameters for WebSockets connection
98
- */
99
- connectionParams?: any;
100
- /**
101
- * Enable Batching
102
- */
103
- batch?: boolean;
104
- }
105
- /**
106
- * This loader loads a schema from a URL. The loaded schema is a fully-executable,
107
- * remote schema since it's created using [@graphql-tools/wrap](/docs/remote-schemas).
108
- *
109
- * ```
110
- * const schema = await loadSchema('http://localhost:3000/graphql', {
111
- * loaders: [
112
- * new UrlLoader(),
113
- * ]
114
- * });
115
- * ```
116
- */
117
- export declare class UrlLoader implements Loader<LoadFromUrlOptions> {
118
- createFormDataFromVariables<TVariables>({ query, variables, operationName, extensions, }: {
119
- query: string;
120
- variables: TVariables;
121
- operationName?: string;
122
- extensions?: any;
123
- }): FormData | Promise<FormData>;
124
- prepareGETUrl({ baseUrl, query, variables, operationName, extensions, }: {
125
- baseUrl: string;
126
- query: string;
127
- variables: any;
128
- operationName?: string;
129
- extensions?: any;
130
- }): string;
131
- buildHTTPExecutor(endpoint: string, fetch: SyncFetchFn, options?: LoadFromUrlOptions): SyncExecutor<any, ExecutionExtensions>;
132
- buildHTTPExecutor(endpoint: string, fetch: AsyncFetchFn, options?: LoadFromUrlOptions): AsyncExecutor<any, ExecutionExtensions>;
133
- buildWSExecutor(subscriptionsEndpoint: string, webSocketImpl: typeof WebSocket, connectionParams?: ClientOptions['connectionParams']): Executor;
134
- buildWSLegacyExecutor(subscriptionsEndpoint: string, WebSocketImpl: typeof WebSocket, options?: LoadFromUrlOptions): Executor;
135
- getFetch(customFetch: LoadFromUrlOptions['customFetch'], importFn: AsyncImportFn): PromiseLike<AsyncFetchFn> | AsyncFetchFn;
136
- getFetch(customFetch: LoadFromUrlOptions['customFetch'], importFn: SyncImportFn): SyncFetchFn;
137
- private getDefaultMethodFromOptions;
138
- getWebSocketImpl(importFn: AsyncImportFn, options?: LoadFromUrlOptions): PromiseLike<typeof WebSocket>;
139
- getWebSocketImpl(importFn: SyncImportFn, options?: LoadFromUrlOptions): typeof WebSocket;
140
- buildSubscriptionExecutor(subscriptionsEndpoint: string, fetch: SyncFetchFn, syncImport: SyncImportFn, options?: LoadFromUrlOptions): SyncExecutor;
141
- buildSubscriptionExecutor(subscriptionsEndpoint: string, fetch: AsyncFetchFn, asyncImport: AsyncImportFn, options?: LoadFromUrlOptions): AsyncExecutor;
142
- getExecutor(endpoint: string, asyncImport: AsyncImportFn, options?: Omit<LoadFromUrlOptions, 'endpoint'>): AsyncExecutor;
143
- getExecutor(endpoint: string, syncImport: SyncImportFn, options?: Omit<LoadFromUrlOptions, 'endpoint'>): SyncExecutor;
144
- getExecutorAsync(endpoint: string, options?: Omit<LoadFromUrlOptions, 'endpoint'>): AsyncExecutor;
145
- getExecutorSync(endpoint: string, options?: Omit<LoadFromUrlOptions, 'endpoint'>): SyncExecutor;
146
- handleSDL(pointer: string, fetch: SyncFetchFn, options: LoadFromUrlOptions): Source;
147
- handleSDL(pointer: string, fetch: AsyncFetchFn, options: LoadFromUrlOptions): Promise<Source>;
148
- load(pointer: string, options: LoadFromUrlOptions): Promise<Source[]>;
149
- loadSync(pointer: string, options: LoadFromUrlOptions): Source[];
150
- }
151
- export {};
@@ -1,23 +0,0 @@
1
- /// <reference types="node" />
2
- import type { Readable } from 'stream';
3
- export declare function isBlob(obj: any): obj is Blob;
4
- interface GraphQLUpload {
5
- filename: string;
6
- mimetype: string;
7
- createReadStream: () => Readable;
8
- }
9
- export declare function isGraphQLUpload(upload: any): upload is GraphQLUpload;
10
- export declare function isPromiseLike(obj: any): obj is PromiseLike<any>;
11
- export declare enum LEGACY_WS {
12
- CONNECTION_INIT = "connection_init",
13
- CONNECTION_ACK = "connection_ack",
14
- CONNECTION_ERROR = "connection_error",
15
- CONNECTION_KEEP_ALIVE = "ka",
16
- START = "start",
17
- STOP = "stop",
18
- CONNECTION_TERMINATE = "connection_terminate",
19
- DATA = "data",
20
- ERROR = "error",
21
- COMPLETE = "complete"
22
- }
23
- export {};