@graphql-tools/executor 1.0.0 → 1.1.0-alpha-20230522102854-674fb2cd
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/cjs/execution/execute.js +57 -10
- package/cjs/execution/normalizedExecutor.js +1 -1
- package/cjs/execution/promiseForObject.js +9 -4
- package/esm/execution/execute.js +57 -10
- package/esm/execution/normalizedExecutor.js +1 -1
- package/esm/execution/promiseForObject.js +9 -4
- package/package.json +1 -1
- package/typings/execution/execute.d.cts +3 -1
- package/typings/execution/execute.d.ts +3 -1
- package/typings/execution/promiseForObject.d.cts +1 -1
- package/typings/execution/promiseForObject.d.ts +1 -1
package/cjs/execution/execute.js
CHANGED
|
@@ -135,7 +135,7 @@ exports.getFragmentsFromDocument = (0, utils_1.memoize1)(function getFragmentsFr
|
|
|
135
135
|
* @internal
|
|
136
136
|
*/
|
|
137
137
|
function buildExecutionContext(args) {
|
|
138
|
-
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, } = args;
|
|
138
|
+
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args;
|
|
139
139
|
// If the schema used for execution is invalid, throw an error.
|
|
140
140
|
(0, graphql_1.assertValidSchema)(schema);
|
|
141
141
|
const fragments = (0, exports.getFragmentsFromDocument)(document);
|
|
@@ -184,6 +184,7 @@ function buildExecutionContext(args) {
|
|
|
184
184
|
subscribeFieldResolver: subscribeFieldResolver ?? exports.defaultFieldResolver,
|
|
185
185
|
subsequentPayloads: new Set(),
|
|
186
186
|
errors: [],
|
|
187
|
+
signal,
|
|
187
188
|
};
|
|
188
189
|
}
|
|
189
190
|
exports.buildExecutionContext = buildExecutionContext;
|
|
@@ -226,13 +227,26 @@ function executeOperation(exeContext) {
|
|
|
226
227
|
* for fields that must be executed serially.
|
|
227
228
|
*/
|
|
228
229
|
function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) {
|
|
230
|
+
let abortErrorThrown = false;
|
|
229
231
|
return (0, utils_1.promiseReduce)(fields, (results, [responseName, fieldNodes]) => {
|
|
230
232
|
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name);
|
|
233
|
+
if (exeContext.signal?.aborted) {
|
|
234
|
+
results[responseName] = null;
|
|
235
|
+
return results;
|
|
236
|
+
}
|
|
231
237
|
return new value_or_promise_1.ValueOrPromise(() => executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath)).then(result => {
|
|
232
238
|
if (result === undefined) {
|
|
233
239
|
return results;
|
|
234
240
|
}
|
|
235
241
|
results[responseName] = result;
|
|
242
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
243
|
+
exeContext.errors.push((0, utils_1.createGraphQLError)('Execution aborted', {
|
|
244
|
+
nodes: fieldNodes,
|
|
245
|
+
path: (0, utils_1.pathToArray)(fieldPath),
|
|
246
|
+
originalError: exeContext.signal?.reason,
|
|
247
|
+
}));
|
|
248
|
+
abortErrorThrown = true;
|
|
249
|
+
}
|
|
236
250
|
return results;
|
|
237
251
|
});
|
|
238
252
|
}, Object.create(null)).resolve();
|
|
@@ -244,8 +258,13 @@ function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields
|
|
|
244
258
|
function executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord) {
|
|
245
259
|
const results = Object.create(null);
|
|
246
260
|
let containsPromise = false;
|
|
261
|
+
let abortErrorThrown = false;
|
|
247
262
|
try {
|
|
248
263
|
for (const [responseName, fieldNodes] of fields) {
|
|
264
|
+
if (exeContext.signal?.aborted) {
|
|
265
|
+
results[responseName] = null;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
249
268
|
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name);
|
|
250
269
|
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath, asyncPayloadRecord);
|
|
251
270
|
if (result !== undefined) {
|
|
@@ -254,12 +273,20 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
254
273
|
containsPromise = true;
|
|
255
274
|
}
|
|
256
275
|
}
|
|
276
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
277
|
+
exeContext.errors.push((0, utils_1.createGraphQLError)('Execution aborted', {
|
|
278
|
+
nodes: fieldNodes,
|
|
279
|
+
path: (0, utils_1.pathToArray)(fieldPath),
|
|
280
|
+
originalError: exeContext.signal?.reason,
|
|
281
|
+
}));
|
|
282
|
+
abortErrorThrown = true;
|
|
283
|
+
}
|
|
257
284
|
}
|
|
258
285
|
}
|
|
259
286
|
catch (error) {
|
|
260
287
|
if (containsPromise) {
|
|
261
288
|
// Ensure that any promises returned by other fields are handled, as they may also reject.
|
|
262
|
-
return (0, promiseForObject_js_1.promiseForObject)(results).finally(() => {
|
|
289
|
+
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal).finally(() => {
|
|
263
290
|
throw error;
|
|
264
291
|
});
|
|
265
292
|
}
|
|
@@ -272,7 +299,7 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
272
299
|
// Otherwise, results is a map from field name to the result of resolving that
|
|
273
300
|
// field, which is possibly a promise. Return a promise that will return this
|
|
274
301
|
// same map, but with any promises replaced with the values they resolved to.
|
|
275
|
-
return (0, promiseForObject_js_1.promiseForObject)(results);
|
|
302
|
+
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal);
|
|
276
303
|
}
|
|
277
304
|
/**
|
|
278
305
|
* Implements the "Executing fields" section of the spec
|
|
@@ -450,6 +477,14 @@ function getStreamValues(exeContext, fieldNodes, path) {
|
|
|
450
477
|
* recursively until all the results are completed.
|
|
451
478
|
*/
|
|
452
479
|
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) {
|
|
480
|
+
exeContext.signal?.addEventListener('abort', () => {
|
|
481
|
+
iterator.return?.();
|
|
482
|
+
exeContext.errors.push((0, utils_1.createGraphQLError)('Execution aborted', {
|
|
483
|
+
nodes: fieldNodes,
|
|
484
|
+
path: (0, utils_1.pathToArray)(path),
|
|
485
|
+
originalError: exeContext.signal?.reason,
|
|
486
|
+
}));
|
|
487
|
+
});
|
|
453
488
|
const errors = asyncPayloadRecord?.errors ?? exeContext.errors;
|
|
454
489
|
const stream = getStreamValues(exeContext, fieldNodes, path);
|
|
455
490
|
let containsPromise = false;
|
|
@@ -759,10 +794,14 @@ function subscribe(args) {
|
|
|
759
794
|
return mapSourceToResponse(exeContext, resultOrStream);
|
|
760
795
|
}
|
|
761
796
|
exports.subscribe = subscribe;
|
|
762
|
-
function flattenIncrementalResults(incrementalResults) {
|
|
797
|
+
function flattenIncrementalResults(incrementalResults, signal) {
|
|
763
798
|
const subsequentIterator = incrementalResults.subsequentResults;
|
|
764
799
|
let initialResultSent = false;
|
|
765
800
|
let done = false;
|
|
801
|
+
signal?.addEventListener('abort', () => {
|
|
802
|
+
done = true;
|
|
803
|
+
subsequentIterator.throw?.(signal?.reason);
|
|
804
|
+
});
|
|
766
805
|
return {
|
|
767
806
|
[Symbol.asyncIterator]() {
|
|
768
807
|
return this;
|
|
@@ -794,9 +833,9 @@ function flattenIncrementalResults(incrementalResults) {
|
|
|
794
833
|
};
|
|
795
834
|
}
|
|
796
835
|
exports.flattenIncrementalResults = flattenIncrementalResults;
|
|
797
|
-
async function* ensureAsyncIterable(someExecutionResult) {
|
|
836
|
+
async function* ensureAsyncIterable(someExecutionResult, signal) {
|
|
798
837
|
if ('initialResult' in someExecutionResult) {
|
|
799
|
-
yield* flattenIncrementalResults(someExecutionResult);
|
|
838
|
+
yield* flattenIncrementalResults(someExecutionResult, signal);
|
|
800
839
|
}
|
|
801
840
|
else {
|
|
802
841
|
yield someExecutionResult;
|
|
@@ -812,7 +851,7 @@ function mapSourceToResponse(exeContext, resultOrStream) {
|
|
|
812
851
|
// the GraphQL specification. The `execute` function provides the
|
|
813
852
|
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
|
|
814
853
|
// "ExecuteQuery" algorithm, for which `execute` is also used.
|
|
815
|
-
return (0, flattenAsyncIterable_js_1.flattenAsyncIterable)((0, utils_1.mapAsyncIterator)(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload))), async function* (error) {
|
|
854
|
+
return (0, flattenAsyncIterable_js_1.flattenAsyncIterable)((0, utils_1.mapAsyncIterator)(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload)), exeContext.signal), async function* (error) {
|
|
816
855
|
const wrappedError = (0, utils_1.createGraphQLError)(error.message, {
|
|
817
856
|
originalError: error,
|
|
818
857
|
nodes: [exeContext.operation],
|
|
@@ -868,13 +907,13 @@ function executeSubscription(exeContext) {
|
|
|
868
907
|
throw (0, graphql_1.locatedError)(error, fieldNodes, (0, utils_1.pathToArray)(path));
|
|
869
908
|
});
|
|
870
909
|
}
|
|
871
|
-
return assertEventStream(result);
|
|
910
|
+
return assertEventStream(result, exeContext.signal);
|
|
872
911
|
}
|
|
873
912
|
catch (error) {
|
|
874
913
|
throw (0, graphql_1.locatedError)(error, fieldNodes, (0, utils_1.pathToArray)(path));
|
|
875
914
|
}
|
|
876
915
|
}
|
|
877
|
-
function assertEventStream(result) {
|
|
916
|
+
function assertEventStream(result, signal) {
|
|
878
917
|
if (result instanceof Error) {
|
|
879
918
|
throw result;
|
|
880
919
|
}
|
|
@@ -882,7 +921,15 @@ function assertEventStream(result) {
|
|
|
882
921
|
if (!(0, utils_1.isAsyncIterable)(result)) {
|
|
883
922
|
throw (0, utils_1.createGraphQLError)('Subscription field must return Async Iterable. ' + `Received: ${(0, utils_1.inspect)(result)}.`);
|
|
884
923
|
}
|
|
885
|
-
return
|
|
924
|
+
return {
|
|
925
|
+
[Symbol.asyncIterator]() {
|
|
926
|
+
const asyncIterator = result[Symbol.asyncIterator]();
|
|
927
|
+
signal?.addEventListener('abort', () => {
|
|
928
|
+
asyncIterator.return?.();
|
|
929
|
+
});
|
|
930
|
+
return asyncIterator;
|
|
931
|
+
},
|
|
932
|
+
};
|
|
886
933
|
}
|
|
887
934
|
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext) {
|
|
888
935
|
const asyncPayloadRecord = new DeferredFragmentRecord({
|
|
@@ -15,7 +15,7 @@ function normalizedExecutor(args) {
|
|
|
15
15
|
return new value_or_promise_1.ValueOrPromise(() => (0, execute_js_1.execute)(args))
|
|
16
16
|
.then((result) => {
|
|
17
17
|
if ('initialResult' in result) {
|
|
18
|
-
return (0, execute_js_1.flattenIncrementalResults)(result);
|
|
18
|
+
return (0, execute_js_1.flattenIncrementalResults)(result, args.signal);
|
|
19
19
|
}
|
|
20
20
|
return result;
|
|
21
21
|
})
|
|
@@ -8,11 +8,16 @@ exports.promiseForObject = void 0;
|
|
|
8
8
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
9
9
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
10
10
|
*/
|
|
11
|
-
async function promiseForObject(object) {
|
|
11
|
+
async function promiseForObject(object, signal) {
|
|
12
12
|
const resolvedObject = Object.create(null);
|
|
13
|
-
await Promise
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
await new Promise((resolve, reject) => {
|
|
14
|
+
signal?.addEventListener('abort', () => {
|
|
15
|
+
resolve();
|
|
16
|
+
});
|
|
17
|
+
Promise.all(Object.entries(object).map(async ([key, value]) => {
|
|
18
|
+
resolvedObject[key] = await value;
|
|
19
|
+
})).then(() => resolve(), reject);
|
|
20
|
+
});
|
|
16
21
|
return resolvedObject;
|
|
17
22
|
}
|
|
18
23
|
exports.promiseForObject = promiseForObject;
|
package/esm/execution/execute.js
CHANGED
|
@@ -129,7 +129,7 @@ export const getFragmentsFromDocument = memoize1(function getFragmentsFromDocume
|
|
|
129
129
|
* @internal
|
|
130
130
|
*/
|
|
131
131
|
export function buildExecutionContext(args) {
|
|
132
|
-
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, } = args;
|
|
132
|
+
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args;
|
|
133
133
|
// If the schema used for execution is invalid, throw an error.
|
|
134
134
|
assertValidSchema(schema);
|
|
135
135
|
const fragments = getFragmentsFromDocument(document);
|
|
@@ -178,6 +178,7 @@ export function buildExecutionContext(args) {
|
|
|
178
178
|
subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver,
|
|
179
179
|
subsequentPayloads: new Set(),
|
|
180
180
|
errors: [],
|
|
181
|
+
signal,
|
|
181
182
|
};
|
|
182
183
|
}
|
|
183
184
|
function buildPerEventExecutionContext(exeContext, payload) {
|
|
@@ -219,13 +220,26 @@ function executeOperation(exeContext) {
|
|
|
219
220
|
* for fields that must be executed serially.
|
|
220
221
|
*/
|
|
221
222
|
function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) {
|
|
223
|
+
let abortErrorThrown = false;
|
|
222
224
|
return promiseReduce(fields, (results, [responseName, fieldNodes]) => {
|
|
223
225
|
const fieldPath = addPath(path, responseName, parentType.name);
|
|
226
|
+
if (exeContext.signal?.aborted) {
|
|
227
|
+
results[responseName] = null;
|
|
228
|
+
return results;
|
|
229
|
+
}
|
|
224
230
|
return new ValueOrPromise(() => executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath)).then(result => {
|
|
225
231
|
if (result === undefined) {
|
|
226
232
|
return results;
|
|
227
233
|
}
|
|
228
234
|
results[responseName] = result;
|
|
235
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
236
|
+
exeContext.errors.push(createGraphQLError('Execution aborted', {
|
|
237
|
+
nodes: fieldNodes,
|
|
238
|
+
path: pathToArray(fieldPath),
|
|
239
|
+
originalError: exeContext.signal?.reason,
|
|
240
|
+
}));
|
|
241
|
+
abortErrorThrown = true;
|
|
242
|
+
}
|
|
229
243
|
return results;
|
|
230
244
|
});
|
|
231
245
|
}, Object.create(null)).resolve();
|
|
@@ -237,8 +251,13 @@ function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields
|
|
|
237
251
|
function executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord) {
|
|
238
252
|
const results = Object.create(null);
|
|
239
253
|
let containsPromise = false;
|
|
254
|
+
let abortErrorThrown = false;
|
|
240
255
|
try {
|
|
241
256
|
for (const [responseName, fieldNodes] of fields) {
|
|
257
|
+
if (exeContext.signal?.aborted) {
|
|
258
|
+
results[responseName] = null;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
242
261
|
const fieldPath = addPath(path, responseName, parentType.name);
|
|
243
262
|
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath, asyncPayloadRecord);
|
|
244
263
|
if (result !== undefined) {
|
|
@@ -247,12 +266,20 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
247
266
|
containsPromise = true;
|
|
248
267
|
}
|
|
249
268
|
}
|
|
269
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
270
|
+
exeContext.errors.push(createGraphQLError('Execution aborted', {
|
|
271
|
+
nodes: fieldNodes,
|
|
272
|
+
path: pathToArray(fieldPath),
|
|
273
|
+
originalError: exeContext.signal?.reason,
|
|
274
|
+
}));
|
|
275
|
+
abortErrorThrown = true;
|
|
276
|
+
}
|
|
250
277
|
}
|
|
251
278
|
}
|
|
252
279
|
catch (error) {
|
|
253
280
|
if (containsPromise) {
|
|
254
281
|
// Ensure that any promises returned by other fields are handled, as they may also reject.
|
|
255
|
-
return promiseForObject(results).finally(() => {
|
|
282
|
+
return promiseForObject(results, exeContext.signal).finally(() => {
|
|
256
283
|
throw error;
|
|
257
284
|
});
|
|
258
285
|
}
|
|
@@ -265,7 +292,7 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
265
292
|
// Otherwise, results is a map from field name to the result of resolving that
|
|
266
293
|
// field, which is possibly a promise. Return a promise that will return this
|
|
267
294
|
// same map, but with any promises replaced with the values they resolved to.
|
|
268
|
-
return promiseForObject(results);
|
|
295
|
+
return promiseForObject(results, exeContext.signal);
|
|
269
296
|
}
|
|
270
297
|
/**
|
|
271
298
|
* Implements the "Executing fields" section of the spec
|
|
@@ -442,6 +469,14 @@ function getStreamValues(exeContext, fieldNodes, path) {
|
|
|
442
469
|
* recursively until all the results are completed.
|
|
443
470
|
*/
|
|
444
471
|
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) {
|
|
472
|
+
exeContext.signal?.addEventListener('abort', () => {
|
|
473
|
+
iterator.return?.();
|
|
474
|
+
exeContext.errors.push(createGraphQLError('Execution aborted', {
|
|
475
|
+
nodes: fieldNodes,
|
|
476
|
+
path: pathToArray(path),
|
|
477
|
+
originalError: exeContext.signal?.reason,
|
|
478
|
+
}));
|
|
479
|
+
});
|
|
445
480
|
const errors = asyncPayloadRecord?.errors ?? exeContext.errors;
|
|
446
481
|
const stream = getStreamValues(exeContext, fieldNodes, path);
|
|
447
482
|
let containsPromise = false;
|
|
@@ -748,10 +783,14 @@ export function subscribe(args) {
|
|
|
748
783
|
}
|
|
749
784
|
return mapSourceToResponse(exeContext, resultOrStream);
|
|
750
785
|
}
|
|
751
|
-
export function flattenIncrementalResults(incrementalResults) {
|
|
786
|
+
export function flattenIncrementalResults(incrementalResults, signal) {
|
|
752
787
|
const subsequentIterator = incrementalResults.subsequentResults;
|
|
753
788
|
let initialResultSent = false;
|
|
754
789
|
let done = false;
|
|
790
|
+
signal?.addEventListener('abort', () => {
|
|
791
|
+
done = true;
|
|
792
|
+
subsequentIterator.throw?.(signal?.reason);
|
|
793
|
+
});
|
|
755
794
|
return {
|
|
756
795
|
[Symbol.asyncIterator]() {
|
|
757
796
|
return this;
|
|
@@ -782,9 +821,9 @@ export function flattenIncrementalResults(incrementalResults) {
|
|
|
782
821
|
},
|
|
783
822
|
};
|
|
784
823
|
}
|
|
785
|
-
async function* ensureAsyncIterable(someExecutionResult) {
|
|
824
|
+
async function* ensureAsyncIterable(someExecutionResult, signal) {
|
|
786
825
|
if ('initialResult' in someExecutionResult) {
|
|
787
|
-
yield* flattenIncrementalResults(someExecutionResult);
|
|
826
|
+
yield* flattenIncrementalResults(someExecutionResult, signal);
|
|
788
827
|
}
|
|
789
828
|
else {
|
|
790
829
|
yield someExecutionResult;
|
|
@@ -800,7 +839,7 @@ function mapSourceToResponse(exeContext, resultOrStream) {
|
|
|
800
839
|
// the GraphQL specification. The `execute` function provides the
|
|
801
840
|
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
|
|
802
841
|
// "ExecuteQuery" algorithm, for which `execute` is also used.
|
|
803
|
-
return flattenAsyncIterable(mapAsyncIterator(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload))), async function* (error) {
|
|
842
|
+
return flattenAsyncIterable(mapAsyncIterator(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload)), exeContext.signal), async function* (error) {
|
|
804
843
|
const wrappedError = createGraphQLError(error.message, {
|
|
805
844
|
originalError: error,
|
|
806
845
|
nodes: [exeContext.operation],
|
|
@@ -856,13 +895,13 @@ function executeSubscription(exeContext) {
|
|
|
856
895
|
throw locatedError(error, fieldNodes, pathToArray(path));
|
|
857
896
|
});
|
|
858
897
|
}
|
|
859
|
-
return assertEventStream(result);
|
|
898
|
+
return assertEventStream(result, exeContext.signal);
|
|
860
899
|
}
|
|
861
900
|
catch (error) {
|
|
862
901
|
throw locatedError(error, fieldNodes, pathToArray(path));
|
|
863
902
|
}
|
|
864
903
|
}
|
|
865
|
-
function assertEventStream(result) {
|
|
904
|
+
function assertEventStream(result, signal) {
|
|
866
905
|
if (result instanceof Error) {
|
|
867
906
|
throw result;
|
|
868
907
|
}
|
|
@@ -870,7 +909,15 @@ function assertEventStream(result) {
|
|
|
870
909
|
if (!isAsyncIterable(result)) {
|
|
871
910
|
throw createGraphQLError('Subscription field must return Async Iterable. ' + `Received: ${inspect(result)}.`);
|
|
872
911
|
}
|
|
873
|
-
return
|
|
912
|
+
return {
|
|
913
|
+
[Symbol.asyncIterator]() {
|
|
914
|
+
const asyncIterator = result[Symbol.asyncIterator]();
|
|
915
|
+
signal?.addEventListener('abort', () => {
|
|
916
|
+
asyncIterator.return?.();
|
|
917
|
+
});
|
|
918
|
+
return asyncIterator;
|
|
919
|
+
},
|
|
920
|
+
};
|
|
874
921
|
}
|
|
875
922
|
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext) {
|
|
876
923
|
const asyncPayloadRecord = new DeferredFragmentRecord({
|
|
@@ -12,7 +12,7 @@ export function normalizedExecutor(args) {
|
|
|
12
12
|
return new ValueOrPromise(() => execute(args))
|
|
13
13
|
.then((result) => {
|
|
14
14
|
if ('initialResult' in result) {
|
|
15
|
-
return flattenIncrementalResults(result);
|
|
15
|
+
return flattenIncrementalResults(result, args.signal);
|
|
16
16
|
}
|
|
17
17
|
return result;
|
|
18
18
|
})
|
|
@@ -5,10 +5,15 @@
|
|
|
5
5
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
6
6
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
7
7
|
*/
|
|
8
|
-
export async function promiseForObject(object) {
|
|
8
|
+
export async function promiseForObject(object, signal) {
|
|
9
9
|
const resolvedObject = Object.create(null);
|
|
10
|
-
await Promise
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
await new Promise((resolve, reject) => {
|
|
11
|
+
signal?.addEventListener('abort', () => {
|
|
12
|
+
resolve();
|
|
13
|
+
});
|
|
14
|
+
Promise.all(Object.entries(object).map(async ([key, value]) => {
|
|
15
|
+
resolvedObject[key] = await value;
|
|
16
|
+
})).then(() => resolve(), reject);
|
|
17
|
+
});
|
|
13
18
|
return resolvedObject;
|
|
14
19
|
}
|
package/package.json
CHANGED
|
@@ -44,6 +44,7 @@ export interface ExecutionContext<TVariables = any, TContext = any> {
|
|
|
44
44
|
subscribeFieldResolver: GraphQLFieldResolver<any, TContext>;
|
|
45
45
|
errors: Array<GraphQLError>;
|
|
46
46
|
subsequentPayloads: Set<AsyncPayloadRecord>;
|
|
47
|
+
signal?: AbortSignal;
|
|
47
48
|
}
|
|
48
49
|
export interface FormattedExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> {
|
|
49
50
|
errors?: ReadonlyArray<GraphQLFormattedError>;
|
|
@@ -108,6 +109,7 @@ export interface ExecutionArgs<TData = any, TVariables = any, TContext = any> {
|
|
|
108
109
|
fieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
109
110
|
typeResolver?: Maybe<GraphQLTypeResolver<any, TContext>>;
|
|
110
111
|
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
112
|
+
signal?: AbortSignal;
|
|
111
113
|
}
|
|
112
114
|
/**
|
|
113
115
|
* Implements the "Executing requests" section of the GraphQL specification,
|
|
@@ -203,7 +205,7 @@ export declare const defaultFieldResolver: GraphQLFieldResolver<unknown, unknown
|
|
|
203
205
|
* Accepts an object with named arguments.
|
|
204
206
|
*/
|
|
205
207
|
export declare function subscribe<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<AsyncGenerator<SingularExecutionResult<TData> | InitialIncrementalExecutionResult<TData> | SubsequentIncrementalExecutionResult<TData>, void, void> | SingularExecutionResult<TData>>;
|
|
206
|
-
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData
|
|
208
|
+
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData>, signal?: AbortSignal): AsyncGenerator<SubsequentIncrementalExecutionResult<TData, Record<string, unknown>>, void, void>;
|
|
207
209
|
declare class DeferredFragmentRecord {
|
|
208
210
|
type: 'defer';
|
|
209
211
|
errors: Array<GraphQLError>;
|
|
@@ -44,6 +44,7 @@ export interface ExecutionContext<TVariables = any, TContext = any> {
|
|
|
44
44
|
subscribeFieldResolver: GraphQLFieldResolver<any, TContext>;
|
|
45
45
|
errors: Array<GraphQLError>;
|
|
46
46
|
subsequentPayloads: Set<AsyncPayloadRecord>;
|
|
47
|
+
signal?: AbortSignal;
|
|
47
48
|
}
|
|
48
49
|
export interface FormattedExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> {
|
|
49
50
|
errors?: ReadonlyArray<GraphQLFormattedError>;
|
|
@@ -108,6 +109,7 @@ export interface ExecutionArgs<TData = any, TVariables = any, TContext = any> {
|
|
|
108
109
|
fieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
109
110
|
typeResolver?: Maybe<GraphQLTypeResolver<any, TContext>>;
|
|
110
111
|
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
112
|
+
signal?: AbortSignal;
|
|
111
113
|
}
|
|
112
114
|
/**
|
|
113
115
|
* Implements the "Executing requests" section of the GraphQL specification,
|
|
@@ -203,7 +205,7 @@ export declare const defaultFieldResolver: GraphQLFieldResolver<unknown, unknown
|
|
|
203
205
|
* Accepts an object with named arguments.
|
|
204
206
|
*/
|
|
205
207
|
export declare function subscribe<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<AsyncGenerator<SingularExecutionResult<TData> | InitialIncrementalExecutionResult<TData> | SubsequentIncrementalExecutionResult<TData>, void, void> | SingularExecutionResult<TData>>;
|
|
206
|
-
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData
|
|
208
|
+
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData>, signal?: AbortSignal): AsyncGenerator<SubsequentIncrementalExecutionResult<TData, Record<string, unknown>>, void, void>;
|
|
207
209
|
declare class DeferredFragmentRecord {
|
|
208
210
|
type: 'defer';
|
|
209
211
|
errors: Array<GraphQLError>;
|
|
@@ -8,5 +8,5 @@ type ResolvedObject<TData> = {
|
|
|
8
8
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
9
9
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
10
10
|
*/
|
|
11
|
-
export declare function promiseForObject<TData>(object: TData): Promise<ResolvedObject<TData>>;
|
|
11
|
+
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal): Promise<ResolvedObject<TData>>;
|
|
12
12
|
export {};
|
|
@@ -8,5 +8,5 @@ type ResolvedObject<TData> = {
|
|
|
8
8
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
9
9
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
10
10
|
*/
|
|
11
|
-
export declare function promiseForObject<TData>(object: TData): Promise<ResolvedObject<TData>>;
|
|
11
|
+
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal): Promise<ResolvedObject<TData>>;
|
|
12
12
|
export {};
|