@graphql-tools/url-loader 7.12.2-alpha-b93d3b57.0 → 7.12.4
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.
- package/esm/addCancelToResponseStream.js +8 -0
- package/esm/defaultAsyncFetch.js +4 -0
- package/esm/defaultSyncFetch.js +10 -0
- package/esm/event-stream/handleEventStreamResponse.js +14 -0
- package/esm/event-stream/handleReadable.js +27 -0
- package/esm/event-stream/handleReadableStream.js +127 -0
- package/esm/handleMultipartMixedResponse.js +48 -0
- package/esm/index.js +607 -0
- package/esm/utils.js +22 -0
- package/package.json +1 -1
- package/typings/addCancelToResponseStream.d.ts +1 -0
- package/typings/defaultAsyncFetch.d.ts +3 -0
- package/typings/defaultSyncFetch.d.ts +6 -0
- package/typings/event-stream/handleEventStreamResponse.d.ts +2 -0
- package/typings/event-stream/handleReadable.d.ts +1 -0
- package/typings/event-stream/handleReadableStream.d.ts +15 -0
- package/typings/handleMultipartMixedResponse.d.ts +2 -0
- package/typings/index.d.ts +151 -0
- package/typings/utils.d.ts +23 -0
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* eslint-disable no-labels */
|
|
2
|
+
let decodeUint8Array;
|
|
3
|
+
if (globalThis.Buffer) {
|
|
4
|
+
decodeUint8Array = uint8Array => globalThis.Buffer.from(uint8Array).toString('utf-8');
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
const textDecoder = new TextDecoder();
|
|
8
|
+
decodeUint8Array = uint8Array => textDecoder.decode(uint8Array);
|
|
9
|
+
}
|
|
10
|
+
export async function* handleReadable(readable) {
|
|
11
|
+
outer: for await (const chunk of readable) {
|
|
12
|
+
const chunkStr = typeof chunk === 'string' ? chunk : decodeUint8Array(chunk);
|
|
13
|
+
for (const part of chunkStr.split('\n\n')) {
|
|
14
|
+
if (part) {
|
|
15
|
+
const eventStr = part.split('event: ')[1];
|
|
16
|
+
const dataStr = part.split('data: ')[1];
|
|
17
|
+
if (eventStr === 'complete') {
|
|
18
|
+
break outer;
|
|
19
|
+
}
|
|
20
|
+
if (dataStr) {
|
|
21
|
+
const data = JSON.parse(dataStr);
|
|
22
|
+
yield data.payload || data;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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';
|
|
5
|
+
function isIncomingMessage(body) {
|
|
6
|
+
return body != null && typeof body === 'object' && 'pipe' in body;
|
|
7
|
+
}
|
|
8
|
+
export async function handleMultipartMixedResponse(response) {
|
|
9
|
+
const body = await response.body;
|
|
10
|
+
const contentType = response.headers.get('content-type') || '';
|
|
11
|
+
let asyncIterator;
|
|
12
|
+
if (isIncomingMessage(body)) {
|
|
13
|
+
// Meros/node expects headers as an object map with the content-type prop
|
|
14
|
+
body.headers = {
|
|
15
|
+
'content-type': contentType,
|
|
16
|
+
};
|
|
17
|
+
// And it expects `IncomingMessage` and `node-fetch` returns `body` as `Promise<PassThrough>`
|
|
18
|
+
asyncIterator = (await merosIncomingMessage(body));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// Nothing is needed for regular `Response`.
|
|
22
|
+
asyncIterator = (await merosReadableStream(response));
|
|
23
|
+
}
|
|
24
|
+
const executionResult = {};
|
|
25
|
+
return mapAsyncIterator(asyncIterator, (part) => {
|
|
26
|
+
if (part.json) {
|
|
27
|
+
const chunk = part.body;
|
|
28
|
+
if (chunk.path) {
|
|
29
|
+
if (chunk.data) {
|
|
30
|
+
const path = ['data'];
|
|
31
|
+
dset(executionResult, path.concat(chunk.path), chunk.data);
|
|
32
|
+
}
|
|
33
|
+
if (chunk.errors) {
|
|
34
|
+
executionResult.errors = (executionResult.errors || []).concat(chunk.errors);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
if (chunk.data) {
|
|
39
|
+
executionResult.data = chunk.data;
|
|
40
|
+
}
|
|
41
|
+
if (chunk.errors) {
|
|
42
|
+
executionResult.errors = chunk.errors;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return executionResult;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
/* eslint-disable no-case-declarations */
|
|
2
|
+
/// <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);
|
|
19
|
+
const syncImport = (moduleName) => require(moduleName);
|
|
20
|
+
export var SubscriptionProtocol;
|
|
21
|
+
(function (SubscriptionProtocol) {
|
|
22
|
+
SubscriptionProtocol["WS"] = "WS";
|
|
23
|
+
/**
|
|
24
|
+
* Use legacy web socket protocol `graphql-ws` instead of the more current standard `graphql-transport-ws`
|
|
25
|
+
*/
|
|
26
|
+
SubscriptionProtocol["LEGACY_WS"] = "LEGACY_WS";
|
|
27
|
+
/**
|
|
28
|
+
* Use SSE for subscription instead of WebSocket
|
|
29
|
+
*/
|
|
30
|
+
SubscriptionProtocol["SSE"] = "SSE";
|
|
31
|
+
/**
|
|
32
|
+
* Use `graphql-sse` for subscriptions
|
|
33
|
+
*/
|
|
34
|
+
SubscriptionProtocol["GRAPHQL_SSE"] = "GRAPHQL_SSE";
|
|
35
|
+
})(SubscriptionProtocol || (SubscriptionProtocol = {}));
|
|
36
|
+
function isCompatibleUri(uri) {
|
|
37
|
+
try {
|
|
38
|
+
// eslint-disable-next-line no-new
|
|
39
|
+
new URL(uri);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch (_a) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* This loader loads a schema from a URL. The loaded schema is a fully-executable,
|
|
48
|
+
* remote schema since it's created using [@graphql-tools/wrap](/docs/remote-schemas).
|
|
49
|
+
*
|
|
50
|
+
* ```
|
|
51
|
+
* const schema = await loadSchema('http://localhost:3000/graphql', {
|
|
52
|
+
* loaders: [
|
|
53
|
+
* new UrlLoader(),
|
|
54
|
+
* ]
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export class UrlLoader {
|
|
59
|
+
createFormDataFromVariables({ query, variables, operationName, extensions, }) {
|
|
60
|
+
const vars = Object.assign({}, variables);
|
|
61
|
+
const { clone, files } = extractFiles(vars, 'variables', ((v) => isExtractableFile(v) ||
|
|
62
|
+
(v === null || v === void 0 ? void 0 : v.promise) ||
|
|
63
|
+
isAsyncIterable(v) ||
|
|
64
|
+
(v === null || v === void 0 ? void 0 : v.then) ||
|
|
65
|
+
typeof (v === null || v === void 0 ? void 0 : v.arrayBuffer) === 'function'));
|
|
66
|
+
const map = {};
|
|
67
|
+
const uploads = [];
|
|
68
|
+
let currIndex = 0;
|
|
69
|
+
for (const [file, curr] of files) {
|
|
70
|
+
map[currIndex] = curr;
|
|
71
|
+
uploads[currIndex] = file;
|
|
72
|
+
currIndex++;
|
|
73
|
+
}
|
|
74
|
+
const form = new FormData();
|
|
75
|
+
form.append('operations', JSON.stringify({
|
|
76
|
+
query,
|
|
77
|
+
variables: clone,
|
|
78
|
+
operationName,
|
|
79
|
+
extensions,
|
|
80
|
+
}));
|
|
81
|
+
form.append('map', JSON.stringify(map));
|
|
82
|
+
function handleUpload(upload, i) {
|
|
83
|
+
const indexStr = i.toString();
|
|
84
|
+
if (upload != null) {
|
|
85
|
+
const filename = upload.filename || upload.name || upload.path || `blob-${indexStr}`;
|
|
86
|
+
if (isPromiseLike(upload)) {
|
|
87
|
+
return upload.then((resolvedUpload) => handleUpload(resolvedUpload, i));
|
|
88
|
+
// If Blob
|
|
89
|
+
}
|
|
90
|
+
else if (isBlob(upload)) {
|
|
91
|
+
return upload.arrayBuffer().then((arrayBuffer) => {
|
|
92
|
+
form.append(indexStr, new File([arrayBuffer], filename, { type: upload.type }), filename);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else if (isGraphQLUpload(upload)) {
|
|
96
|
+
const stream = upload.createReadStream();
|
|
97
|
+
const chunks = [];
|
|
98
|
+
return Promise.resolve().then(async () => {
|
|
99
|
+
for await (const chunk of stream) {
|
|
100
|
+
if (chunk) {
|
|
101
|
+
chunks.push(...chunk);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const blobPart = new Uint8Array(chunks);
|
|
105
|
+
form.append(indexStr, new File([blobPart], filename, { type: upload.mimetype }), filename);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
form.append(indexStr, new File([upload], filename), filename);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return ValueOrPromise.all(uploads.map((upload, i) => new ValueOrPromise(() => handleUpload(upload, i))))
|
|
114
|
+
.then(() => form)
|
|
115
|
+
.resolve();
|
|
116
|
+
}
|
|
117
|
+
prepareGETUrl({ baseUrl, query, variables, operationName, extensions, }) {
|
|
118
|
+
const HTTP_URL = switchProtocols(baseUrl, {
|
|
119
|
+
wss: 'https',
|
|
120
|
+
ws: 'http',
|
|
121
|
+
});
|
|
122
|
+
const dummyHostname = 'https://dummyhostname.com';
|
|
123
|
+
const validUrl = HTTP_URL.startsWith('http')
|
|
124
|
+
? HTTP_URL
|
|
125
|
+
: HTTP_URL.startsWith('/')
|
|
126
|
+
? `${dummyHostname}${HTTP_URL}`
|
|
127
|
+
: `${dummyHostname}/${HTTP_URL}`;
|
|
128
|
+
const urlObj = new URL(validUrl);
|
|
129
|
+
urlObj.searchParams.set('query', query);
|
|
130
|
+
if (variables && Object.keys(variables).length > 0) {
|
|
131
|
+
urlObj.searchParams.set('variables', JSON.stringify(variables));
|
|
132
|
+
}
|
|
133
|
+
if (operationName) {
|
|
134
|
+
urlObj.searchParams.set('operationName', operationName);
|
|
135
|
+
}
|
|
136
|
+
if (extensions) {
|
|
137
|
+
urlObj.searchParams.set('extensions', JSON.stringify(extensions));
|
|
138
|
+
}
|
|
139
|
+
const finalUrl = urlObj.toString().replace(dummyHostname, '');
|
|
140
|
+
return finalUrl;
|
|
141
|
+
}
|
|
142
|
+
buildHTTPExecutor(initialEndpoint, fetch, options) {
|
|
143
|
+
const defaultMethod = this.getDefaultMethodFromOptions(options === null || options === void 0 ? void 0 : options.method, 'POST');
|
|
144
|
+
const HTTP_URL = switchProtocols(initialEndpoint, {
|
|
145
|
+
wss: 'https',
|
|
146
|
+
ws: 'http',
|
|
147
|
+
});
|
|
148
|
+
const executor = (request) => {
|
|
149
|
+
var _a, _b;
|
|
150
|
+
const controller = new AbortController();
|
|
151
|
+
let method = defaultMethod;
|
|
152
|
+
const operationAst = getOperationASTFromRequest(request);
|
|
153
|
+
const operationType = operationAst.operation;
|
|
154
|
+
if ((options === null || options === void 0 ? void 0 : options.useGETForQueries) && operationType === 'query') {
|
|
155
|
+
method = 'GET';
|
|
156
|
+
}
|
|
157
|
+
let accept = 'application/json, multipart/mixed';
|
|
158
|
+
if (operationType === 'subscription' || isLiveQueryOperationDefinitionNode(operationAst)) {
|
|
159
|
+
method = 'GET';
|
|
160
|
+
accept = 'text/event-stream';
|
|
161
|
+
}
|
|
162
|
+
const endpoint = ((_a = request.extensions) === null || _a === void 0 ? void 0 : _a.endpoint) || HTTP_URL;
|
|
163
|
+
const headers = Object.assign({
|
|
164
|
+
accept,
|
|
165
|
+
}, 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);
|
|
167
|
+
const requestBody = {
|
|
168
|
+
query,
|
|
169
|
+
variables: request.variables,
|
|
170
|
+
operationName: request.operationName,
|
|
171
|
+
extensions: request.extensions,
|
|
172
|
+
};
|
|
173
|
+
let timeoutId;
|
|
174
|
+
if (options === null || options === void 0 ? void 0 : options.timeout) {
|
|
175
|
+
timeoutId = setTimeout(() => {
|
|
176
|
+
if (!controller.signal.aborted) {
|
|
177
|
+
controller.abort();
|
|
178
|
+
}
|
|
179
|
+
}, options.timeout);
|
|
180
|
+
}
|
|
181
|
+
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(() => {
|
|
183
|
+
switch (method) {
|
|
184
|
+
case 'GET':
|
|
185
|
+
const finalUrl = this.prepareGETUrl({
|
|
186
|
+
baseUrl: endpoint,
|
|
187
|
+
...requestBody,
|
|
188
|
+
});
|
|
189
|
+
return fetch(finalUrl, {
|
|
190
|
+
method: 'GET',
|
|
191
|
+
...(credentials != null ? { credentials } : {}),
|
|
192
|
+
headers,
|
|
193
|
+
signal: controller.signal,
|
|
194
|
+
});
|
|
195
|
+
case 'POST':
|
|
196
|
+
if (options === null || options === void 0 ? void 0 : options.multipart) {
|
|
197
|
+
return new ValueOrPromise(() => this.createFormDataFromVariables(requestBody))
|
|
198
|
+
.then(form => fetch(endpoint, {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
...(credentials != null ? { credentials } : {}),
|
|
201
|
+
body: form,
|
|
202
|
+
headers,
|
|
203
|
+
signal: controller.signal,
|
|
204
|
+
}))
|
|
205
|
+
.resolve();
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
return fetch(endpoint, {
|
|
209
|
+
method: 'POST',
|
|
210
|
+
...(credentials != null ? { credentials } : {}),
|
|
211
|
+
body: JSON.stringify(requestBody),
|
|
212
|
+
headers: {
|
|
213
|
+
'content-type': 'application/json',
|
|
214
|
+
...headers,
|
|
215
|
+
},
|
|
216
|
+
signal: controller.signal,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
.then((fetchResult) => {
|
|
222
|
+
if (timeoutId != null) {
|
|
223
|
+
clearTimeout(timeoutId);
|
|
224
|
+
}
|
|
225
|
+
// Retry should respect HTTP Errors
|
|
226
|
+
if ((options === null || options === void 0 ? void 0 : options.retry) != null && !fetchResult.status.toString().startsWith('2')) {
|
|
227
|
+
throw new Error(fetchResult.statusText || `HTTP Error: ${fetchResult.status}`);
|
|
228
|
+
}
|
|
229
|
+
const contentType = fetchResult.headers.get('content-type');
|
|
230
|
+
if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('text/event-stream')) {
|
|
231
|
+
return handleEventStreamResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
|
|
232
|
+
}
|
|
233
|
+
else if (contentType === null || contentType === void 0 ? void 0 : contentType.includes('multipart/mixed')) {
|
|
234
|
+
return handleMultipartMixedResponse(fetchResult).then(resultStream => addCancelToResponseStream(resultStream, controller));
|
|
235
|
+
}
|
|
236
|
+
return fetchResult.text();
|
|
237
|
+
})
|
|
238
|
+
.then(result => {
|
|
239
|
+
if (typeof result === 'string') {
|
|
240
|
+
if (result) {
|
|
241
|
+
return JSON.parse(result);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
.resolve();
|
|
249
|
+
};
|
|
250
|
+
if ((options === null || options === void 0 ? void 0 : options.retry) != null) {
|
|
251
|
+
return function retryExecutor(request) {
|
|
252
|
+
let result;
|
|
253
|
+
let error;
|
|
254
|
+
let attempt = 0;
|
|
255
|
+
function retryAttempt() {
|
|
256
|
+
attempt++;
|
|
257
|
+
if (attempt > options.retry) {
|
|
258
|
+
if (result != null) {
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
if (error != null) {
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
throw new Error('No result');
|
|
265
|
+
}
|
|
266
|
+
return new ValueOrPromise(() => executor(request))
|
|
267
|
+
.then(res => {
|
|
268
|
+
var _a;
|
|
269
|
+
result = res;
|
|
270
|
+
if ((_a = result === null || result === void 0 ? void 0 : result.errors) === null || _a === void 0 ? void 0 : _a.length) {
|
|
271
|
+
return retryAttempt();
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
})
|
|
275
|
+
.catch((e) => {
|
|
276
|
+
error = e;
|
|
277
|
+
return retryAttempt();
|
|
278
|
+
})
|
|
279
|
+
.resolve();
|
|
280
|
+
}
|
|
281
|
+
return retryAttempt();
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return executor;
|
|
285
|
+
}
|
|
286
|
+
buildWSExecutor(subscriptionsEndpoint, webSocketImpl, connectionParams) {
|
|
287
|
+
const WS_URL = switchProtocols(subscriptionsEndpoint, {
|
|
288
|
+
https: 'wss',
|
|
289
|
+
http: 'ws',
|
|
290
|
+
});
|
|
291
|
+
const subscriptionClient = createClient({
|
|
292
|
+
url: WS_URL,
|
|
293
|
+
webSocketImpl,
|
|
294
|
+
connectionParams,
|
|
295
|
+
lazy: true,
|
|
296
|
+
});
|
|
297
|
+
return ({ document, variables, operationName, extensions }) => {
|
|
298
|
+
const query = print(document);
|
|
299
|
+
return observableToAsyncIterable({
|
|
300
|
+
subscribe: observer => {
|
|
301
|
+
const unsubscribe = subscriptionClient.subscribe({
|
|
302
|
+
query,
|
|
303
|
+
variables: variables,
|
|
304
|
+
operationName,
|
|
305
|
+
extensions,
|
|
306
|
+
}, observer);
|
|
307
|
+
return {
|
|
308
|
+
unsubscribe,
|
|
309
|
+
};
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
buildWSLegacyExecutor(subscriptionsEndpoint, WebSocketImpl, options) {
|
|
315
|
+
const WS_URL = switchProtocols(subscriptionsEndpoint, {
|
|
316
|
+
https: 'wss',
|
|
317
|
+
http: 'ws',
|
|
318
|
+
});
|
|
319
|
+
const observerById = new Map();
|
|
320
|
+
let websocket = null;
|
|
321
|
+
const ensureWebsocket = () => {
|
|
322
|
+
websocket = new WebSocketImpl(WS_URL, 'graphql-ws', {
|
|
323
|
+
followRedirects: true,
|
|
324
|
+
headers: options === null || options === void 0 ? void 0 : options.headers,
|
|
325
|
+
rejectUnauthorized: false,
|
|
326
|
+
skipUTF8Validation: true,
|
|
327
|
+
});
|
|
328
|
+
websocket.onopen = () => {
|
|
329
|
+
let payload = {};
|
|
330
|
+
switch (typeof (options === null || options === void 0 ? void 0 : options.connectionParams)) {
|
|
331
|
+
case 'function':
|
|
332
|
+
payload = options === null || options === void 0 ? void 0 : options.connectionParams();
|
|
333
|
+
break;
|
|
334
|
+
case 'object':
|
|
335
|
+
payload = options === null || options === void 0 ? void 0 : options.connectionParams;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
websocket.send(JSON.stringify({
|
|
339
|
+
type: LEGACY_WS.CONNECTION_INIT,
|
|
340
|
+
payload,
|
|
341
|
+
}));
|
|
342
|
+
};
|
|
343
|
+
};
|
|
344
|
+
const cleanupWebsocket = () => {
|
|
345
|
+
if (websocket != null && observerById.size === 0) {
|
|
346
|
+
websocket.send(JSON.stringify({
|
|
347
|
+
type: LEGACY_WS.CONNECTION_TERMINATE,
|
|
348
|
+
}));
|
|
349
|
+
websocket.terminate();
|
|
350
|
+
websocket = null;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
return function legacyExecutor(request) {
|
|
354
|
+
const id = Date.now().toString();
|
|
355
|
+
return observableToAsyncIterable({
|
|
356
|
+
subscribe(observer) {
|
|
357
|
+
ensureWebsocket();
|
|
358
|
+
if (websocket == null) {
|
|
359
|
+
throw new Error(`WebSocket connection is not found!`);
|
|
360
|
+
}
|
|
361
|
+
websocket.onmessage = event => {
|
|
362
|
+
const data = JSON.parse(event.data.toString('utf-8'));
|
|
363
|
+
switch (data.type) {
|
|
364
|
+
case LEGACY_WS.CONNECTION_ACK: {
|
|
365
|
+
if (websocket == null) {
|
|
366
|
+
throw new Error(`WebSocket connection is not found!`);
|
|
367
|
+
}
|
|
368
|
+
websocket.send(JSON.stringify({
|
|
369
|
+
type: LEGACY_WS.START,
|
|
370
|
+
id,
|
|
371
|
+
payload: {
|
|
372
|
+
query: print(request.document),
|
|
373
|
+
variables: request.variables,
|
|
374
|
+
operationName: request.operationName,
|
|
375
|
+
},
|
|
376
|
+
}));
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
case LEGACY_WS.CONNECTION_ERROR: {
|
|
380
|
+
observer.error(data.payload);
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
case LEGACY_WS.CONNECTION_KEEP_ALIVE: {
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
case LEGACY_WS.DATA: {
|
|
387
|
+
observer.next(data.payload);
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
case LEGACY_WS.COMPLETE: {
|
|
391
|
+
if (websocket == null) {
|
|
392
|
+
throw new Error(`WebSocket connection is not found!`);
|
|
393
|
+
}
|
|
394
|
+
websocket.send(JSON.stringify({
|
|
395
|
+
type: LEGACY_WS.CONNECTION_TERMINATE,
|
|
396
|
+
}));
|
|
397
|
+
observer.complete();
|
|
398
|
+
cleanupWebsocket();
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
return {
|
|
404
|
+
unsubscribe: () => {
|
|
405
|
+
websocket === null || websocket === void 0 ? void 0 : websocket.send(JSON.stringify({
|
|
406
|
+
type: LEGACY_WS.STOP,
|
|
407
|
+
id,
|
|
408
|
+
}));
|
|
409
|
+
cleanupWebsocket();
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
getFetch(customFetch, importFn) {
|
|
417
|
+
if (customFetch) {
|
|
418
|
+
if (typeof customFetch === 'string') {
|
|
419
|
+
const [moduleName, fetchFnName] = customFetch.split('#');
|
|
420
|
+
return new ValueOrPromise(() => importFn(moduleName))
|
|
421
|
+
.then(module => (fetchFnName ? module[fetchFnName] : module))
|
|
422
|
+
.resolve();
|
|
423
|
+
}
|
|
424
|
+
else if (typeof customFetch === 'function') {
|
|
425
|
+
return customFetch;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (importFn === asyncImport) {
|
|
429
|
+
return defaultAsyncFetch;
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
return defaultSyncFetch;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
getDefaultMethodFromOptions(method, defaultMethod) {
|
|
436
|
+
if (method) {
|
|
437
|
+
defaultMethod = method;
|
|
438
|
+
}
|
|
439
|
+
return defaultMethod;
|
|
440
|
+
}
|
|
441
|
+
getWebSocketImpl(importFn, options) {
|
|
442
|
+
if (typeof (options === null || options === void 0 ? void 0 : options.webSocketImpl) === 'string') {
|
|
443
|
+
const [moduleName, webSocketImplName] = options.webSocketImpl.split('#');
|
|
444
|
+
return new ValueOrPromise(() => importFn(moduleName))
|
|
445
|
+
.then(importedModule => (webSocketImplName ? importedModule[webSocketImplName] : importedModule))
|
|
446
|
+
.resolve();
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
const websocketImpl = (options === null || options === void 0 ? void 0 : options.webSocketImpl) || WebSocket;
|
|
450
|
+
return websocketImpl;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
buildSubscriptionExecutor(subscriptionsEndpoint, fetch, importFn, options) {
|
|
454
|
+
if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === SubscriptionProtocol.SSE) {
|
|
455
|
+
return this.buildHTTPExecutor(subscriptionsEndpoint, fetch, options);
|
|
456
|
+
}
|
|
457
|
+
else if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === SubscriptionProtocol.GRAPHQL_SSE) {
|
|
458
|
+
if (!(options === null || options === void 0 ? void 0 : options.subscriptionsEndpoint)) {
|
|
459
|
+
// when no custom subscriptions endpoint is specified,
|
|
460
|
+
// graphql-sse is recommended to be used on `/graphql/stream`
|
|
461
|
+
subscriptionsEndpoint += '/stream';
|
|
462
|
+
}
|
|
463
|
+
return this.buildHTTPExecutor(subscriptionsEndpoint, fetch, options);
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
const webSocketImpl$ = new ValueOrPromise(() => this.getWebSocketImpl(importFn, options));
|
|
467
|
+
const executor$ = webSocketImpl$.then(webSocketImpl => {
|
|
468
|
+
if ((options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) === SubscriptionProtocol.LEGACY_WS) {
|
|
469
|
+
return this.buildWSLegacyExecutor(subscriptionsEndpoint, webSocketImpl, options);
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
return this.buildWSExecutor(subscriptionsEndpoint, webSocketImpl, options === null || options === void 0 ? void 0 : options.connectionParams);
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
return request => executor$.then(executor => executor(request)).resolve();
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
getExecutor(endpoint, importFn, options) {
|
|
479
|
+
const fetch$ = new ValueOrPromise(() => this.getFetch(options === null || options === void 0 ? void 0 : options.customFetch, importFn));
|
|
480
|
+
const httpExecutor$ = fetch$.then(fetch => {
|
|
481
|
+
return this.buildHTTPExecutor(endpoint, fetch, options);
|
|
482
|
+
});
|
|
483
|
+
if ((options === null || options === void 0 ? void 0 : options.subscriptionsEndpoint) != null || (options === null || options === void 0 ? void 0 : options.subscriptionsProtocol) !== SubscriptionProtocol.SSE) {
|
|
484
|
+
const subscriptionExecutor$ = fetch$.then(fetch => {
|
|
485
|
+
const subscriptionsEndpoint = (options === null || options === void 0 ? void 0 : options.subscriptionsEndpoint) || endpoint;
|
|
486
|
+
return this.buildSubscriptionExecutor(subscriptionsEndpoint, fetch, importFn, options);
|
|
487
|
+
});
|
|
488
|
+
// eslint-disable-next-line no-inner-declarations
|
|
489
|
+
function getExecutorByRequest(request) {
|
|
490
|
+
const operationAst = getOperationASTFromRequest(request);
|
|
491
|
+
if (operationAst.operation === 'subscription' ||
|
|
492
|
+
isLiveQueryOperationDefinitionNode(operationAst, request.variables)) {
|
|
493
|
+
return subscriptionExecutor$;
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
return httpExecutor$;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return request => getExecutorByRequest(request)
|
|
500
|
+
.then(executor => executor(request))
|
|
501
|
+
.resolve();
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
return request => httpExecutor$.then(executor => executor(request)).resolve();
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
getExecutorAsync(endpoint, options) {
|
|
508
|
+
return this.getExecutor(endpoint, asyncImport, options);
|
|
509
|
+
}
|
|
510
|
+
getExecutorSync(endpoint, options) {
|
|
511
|
+
return this.getExecutor(endpoint, syncImport, options);
|
|
512
|
+
}
|
|
513
|
+
handleSDL(pointer, fetch, options) {
|
|
514
|
+
const defaultMethod = this.getDefaultMethodFromOptions(options === null || options === void 0 ? void 0 : options.method, 'GET');
|
|
515
|
+
return new ValueOrPromise(() => fetch(pointer, {
|
|
516
|
+
method: defaultMethod,
|
|
517
|
+
headers: options.headers,
|
|
518
|
+
}))
|
|
519
|
+
.then(response => response.text())
|
|
520
|
+
.then(schemaString => parseGraphQLSDL(pointer, schemaString, options))
|
|
521
|
+
.resolve();
|
|
522
|
+
}
|
|
523
|
+
async load(pointer, options) {
|
|
524
|
+
if (!isCompatibleUri(pointer)) {
|
|
525
|
+
return [];
|
|
526
|
+
}
|
|
527
|
+
let source = {
|
|
528
|
+
location: pointer,
|
|
529
|
+
};
|
|
530
|
+
let executor;
|
|
531
|
+
if ((options === null || options === void 0 ? void 0 : options.handleAsSDL) || pointer.endsWith('.graphql') || pointer.endsWith('.graphqls')) {
|
|
532
|
+
const fetch = await this.getFetch(options === null || options === void 0 ? void 0 : options.customFetch, asyncImport);
|
|
533
|
+
source = await this.handleSDL(pointer, fetch, options);
|
|
534
|
+
if (!source.schema && !source.document && !source.rawSDL) {
|
|
535
|
+
throw new Error(`Invalid SDL response`);
|
|
536
|
+
}
|
|
537
|
+
source.schema =
|
|
538
|
+
source.schema ||
|
|
539
|
+
(source.document
|
|
540
|
+
? buildASTSchema(source.document, options)
|
|
541
|
+
: source.rawSDL
|
|
542
|
+
? buildSchema(source.rawSDL, options)
|
|
543
|
+
: undefined);
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
executor = this.getExecutorAsync(pointer, options);
|
|
547
|
+
source.schema = await introspectSchema(executor, {}, options);
|
|
548
|
+
}
|
|
549
|
+
if (!source.schema) {
|
|
550
|
+
throw new Error(`Invalid introspected schema`);
|
|
551
|
+
}
|
|
552
|
+
if (options === null || options === void 0 ? void 0 : options.endpoint) {
|
|
553
|
+
executor = this.getExecutorAsync(options.endpoint, options);
|
|
554
|
+
}
|
|
555
|
+
if (executor) {
|
|
556
|
+
source.schema = wrapSchema({
|
|
557
|
+
schema: source.schema,
|
|
558
|
+
executor,
|
|
559
|
+
batch: options === null || options === void 0 ? void 0 : options.batch,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
return [source];
|
|
563
|
+
}
|
|
564
|
+
loadSync(pointer, options) {
|
|
565
|
+
if (!isCompatibleUri(pointer)) {
|
|
566
|
+
return [];
|
|
567
|
+
}
|
|
568
|
+
let source = {
|
|
569
|
+
location: pointer,
|
|
570
|
+
};
|
|
571
|
+
let executor;
|
|
572
|
+
if ((options === null || options === void 0 ? void 0 : options.handleAsSDL) || pointer.endsWith('.graphql') || pointer.endsWith('.graphqls')) {
|
|
573
|
+
const fetch = this.getFetch(options === null || options === void 0 ? void 0 : options.customFetch, syncImport);
|
|
574
|
+
source = this.handleSDL(pointer, fetch, options);
|
|
575
|
+
if (!source.schema && !source.document && !source.rawSDL) {
|
|
576
|
+
throw new Error(`Invalid SDL response`);
|
|
577
|
+
}
|
|
578
|
+
source.schema =
|
|
579
|
+
source.schema ||
|
|
580
|
+
(source.document
|
|
581
|
+
? buildASTSchema(source.document, options)
|
|
582
|
+
: source.rawSDL
|
|
583
|
+
? buildSchema(source.rawSDL, options)
|
|
584
|
+
: undefined);
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
executor = this.getExecutorSync(pointer, options);
|
|
588
|
+
source.schema = introspectSchema(executor, {}, options);
|
|
589
|
+
}
|
|
590
|
+
if (!source.schema) {
|
|
591
|
+
throw new Error(`Invalid introspected schema`);
|
|
592
|
+
}
|
|
593
|
+
if (options === null || options === void 0 ? void 0 : options.endpoint) {
|
|
594
|
+
executor = this.getExecutorSync(options.endpoint, options);
|
|
595
|
+
}
|
|
596
|
+
if (executor) {
|
|
597
|
+
source.schema = wrapSchema({
|
|
598
|
+
schema: source.schema,
|
|
599
|
+
executor,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
return [source];
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function switchProtocols(pointer, protocolMap) {
|
|
606
|
+
return Object.entries(protocolMap).reduce((prev, [source, target]) => prev.replace(`${source}://`, `${target}://`).replace(`${source}:\\`, `${target}:\\`), pointer);
|
|
607
|
+
}
|
package/esm/utils.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function isBlob(obj) {
|
|
2
|
+
return typeof obj.arrayBuffer === 'function';
|
|
3
|
+
}
|
|
4
|
+
export function isGraphQLUpload(upload) {
|
|
5
|
+
return typeof upload.createReadStream === 'function';
|
|
6
|
+
}
|
|
7
|
+
export function isPromiseLike(obj) {
|
|
8
|
+
return typeof obj.then === 'function';
|
|
9
|
+
}
|
|
10
|
+
export var LEGACY_WS;
|
|
11
|
+
(function (LEGACY_WS) {
|
|
12
|
+
LEGACY_WS["CONNECTION_INIT"] = "connection_init";
|
|
13
|
+
LEGACY_WS["CONNECTION_ACK"] = "connection_ack";
|
|
14
|
+
LEGACY_WS["CONNECTION_ERROR"] = "connection_error";
|
|
15
|
+
LEGACY_WS["CONNECTION_KEEP_ALIVE"] = "ka";
|
|
16
|
+
LEGACY_WS["START"] = "start";
|
|
17
|
+
LEGACY_WS["STOP"] = "stop";
|
|
18
|
+
LEGACY_WS["CONNECTION_TERMINATE"] = "connection_terminate";
|
|
19
|
+
LEGACY_WS["DATA"] = "data";
|
|
20
|
+
LEGACY_WS["ERROR"] = "error";
|
|
21
|
+
LEGACY_WS["COMPLETE"] = "complete";
|
|
22
|
+
})(LEGACY_WS || (LEGACY_WS = {}));
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function addCancelToResponseStream<T>(resultStream: AsyncIterable<T>, controller: AbortController): AsyncIterable<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function handleReadable(readable: AsyncIterable<Uint8Array | string>): AsyncGenerator<any, void, unknown>;
|
|
@@ -0,0 +1,15 @@
|
|
|
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>;
|
|
@@ -0,0 +1,2 @@
|
|
|
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>>;
|
|
@@ -0,0 +1,151 @@
|
|
|
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 {};
|
|
@@ -0,0 +1,23 @@
|
|
|
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 {};
|