@graphql-tools/executor
Advanced tools
Comparing version
@@ -153,2 +153,3 @@ "use strict"; | ||
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args; | ||
signal?.throwIfAborted(); | ||
// If the schema used for execution is invalid, throw an error. | ||
@@ -208,2 +209,24 @@ (0, graphql_1.assertValidSchema)(schema); | ||
} | ||
signal?.throwIfAborted(); | ||
let onSignalAbort; | ||
let signalPromise; | ||
if (signal) { | ||
const listeners = new Set(); | ||
const signalDeferred = (0, promise_helpers_1.createDeferredPromise)(); | ||
signalPromise = signalDeferred.promise; | ||
const sharedListener = () => { | ||
signalDeferred.reject(signal.reason); | ||
signal.removeEventListener('abort', sharedListener); | ||
}; | ||
signal.addEventListener('abort', sharedListener, { once: true }); | ||
signalPromise.catch(() => { | ||
for (const listener of listeners) { | ||
listener(); | ||
} | ||
listeners.clear(); | ||
}); | ||
onSignalAbort = handler => { | ||
listeners.add(handler); | ||
}; | ||
} | ||
return { | ||
@@ -222,2 +245,4 @@ schema, | ||
signal, | ||
onSignalAbort, | ||
signalPromise, | ||
}; | ||
@@ -297,3 +322,3 @@ } | ||
catch (error) { | ||
if (containsPromise) { | ||
if (error !== exeContext.signal?.reason && containsPromise) { | ||
// Ensure that any promises returned by other fields are handled, as they may also reject. | ||
@@ -315,3 +340,3 @@ return (0, promise_helpers_1.handleMaybePromise)(() => (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal), () => { | ||
// same map, but with any promises replaced with the values they resolved to. | ||
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal); | ||
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal, exeContext.signalPromise); | ||
} | ||
@@ -335,2 +360,3 @@ /** | ||
try { | ||
exeContext.signal?.throwIfAborted(); | ||
// Build a JS object of arguments from the field.arguments AST, using the | ||
@@ -517,4 +543,5 @@ // variables scope to fulfill any variable references. | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) { | ||
if (exeContext.signal && iterator.return) { | ||
(0, utils_1.registerAbortSignalListener)(exeContext.signal, () => { | ||
exeContext.signal?.throwIfAborted(); | ||
if (iterator.return) { | ||
exeContext.onSignalAbort?.(() => { | ||
iterator.return?.(); | ||
@@ -961,7 +988,9 @@ }); | ||
if ((0, utils_1.isPromise)(result)) { | ||
return result.then(assertEventStream).then(undefined, error => { | ||
return result | ||
.then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort)) | ||
.then(undefined, error => { | ||
throw (0, graphql_1.locatedError)(error, fieldNodes, (0, utils_1.pathToArray)(path)); | ||
}); | ||
} | ||
return assertEventStream(result, exeContext.signal); | ||
return assertEventStream(result, exeContext.signal, exeContext.onSignalAbort); | ||
} | ||
@@ -972,3 +1001,4 @@ catch (error) { | ||
} | ||
function assertEventStream(result, signal) { | ||
function assertEventStream(result, signal, onSignalAbort) { | ||
signal?.throwIfAborted(); | ||
if (result instanceof Error) { | ||
@@ -981,3 +1011,3 @@ throw result; | ||
} | ||
if (signal) { | ||
if (onSignalAbort) { | ||
return { | ||
@@ -987,3 +1017,3 @@ [Symbol.asyncIterator]() { | ||
if (asyncIterator.return) { | ||
(0, utils_1.registerAbortSignalListener)(signal, () => { | ||
onSignalAbort?.(() => { | ||
asyncIterator.return?.(); | ||
@@ -1216,3 +1246,2 @@ }); | ||
let isDone = false; | ||
const abortPromise = exeContext.signal ? (0, utils_1.getAbortPromise)(exeContext.signal) : undefined; | ||
async function next() { | ||
@@ -1223,4 +1252,4 @@ if (isDone) { | ||
const subSequentPayloadPromises = Array.from(exeContext.subsequentPayloads).map(record => record.promise); | ||
if (abortPromise) { | ||
await Promise.race([abortPromise, ...subSequentPayloadPromises]); | ||
if (exeContext.signalPromise) { | ||
await Promise.race([exeContext.signalPromise, ...subSequentPayloadPromises]); | ||
} | ||
@@ -1227,0 +1256,0 @@ else { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.promiseForObject = promiseForObject; | ||
const utils_1 = require("@graphql-tools/utils"); | ||
const promise_helpers_1 = require("@whatwg-node/promise-helpers"); | ||
@@ -13,3 +12,4 @@ /** | ||
*/ | ||
function promiseForObject(object, signal) { | ||
function promiseForObject(object, signal, signalPromise) { | ||
signal?.throwIfAborted(); | ||
const resolvedObject = Object.create(null); | ||
@@ -21,3 +21,3 @@ const promises = []; | ||
}); | ||
if ((0, utils_1.isPromise)(valueSet$)) { | ||
if ((0, promise_helpers_1.isPromise)(valueSet$)) { | ||
promises.push(valueSet$); | ||
@@ -30,7 +30,6 @@ } | ||
const promiseAll = promises.length === 1 ? promises[0] : Promise.all(promises); | ||
if (signal) { | ||
const abortPromise = (0, utils_1.getAbortPromise)(signal); | ||
return Promise.race([abortPromise, promiseAll]).then(() => resolvedObject); | ||
if (signalPromise) { | ||
return Promise.race([signalPromise, promiseAll]).then(() => resolvedObject); | ||
} | ||
return promiseAll.then(() => resolvedObject); | ||
} |
import { assertValidSchema, getDirectiveValues, GraphQLError, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, Kind, locatedError, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, versionInfo, } from 'graphql'; | ||
import { collectSubFields as _collectSubfields, addPath, collectFields, createGraphQLError, fakePromise, getAbortPromise, getArgumentValues, getDefinedRootType, GraphQLStreamDirective, inspect, isAsyncIterable, isIterableObject, isObjectLike, isPromise, mapAsyncIterator, memoize1, memoize3, pathToArray, promiseReduce, registerAbortSignalListener, } from '@graphql-tools/utils'; | ||
import { collectSubFields as _collectSubfields, addPath, collectFields, createGraphQLError, fakePromise, getArgumentValues, getDefinedRootType, GraphQLStreamDirective, inspect, isAsyncIterable, isIterableObject, isObjectLike, isPromise, mapAsyncIterator, memoize1, memoize3, pathToArray, promiseReduce, } from '@graphql-tools/utils'; | ||
import { DisposableSymbols } from '@whatwg-node/disposablestack'; | ||
import { handleMaybePromise } from '@whatwg-node/promise-helpers'; | ||
import { createDeferredPromise, handleMaybePromise } from '@whatwg-node/promise-helpers'; | ||
import { coerceError } from './coerceError.js'; | ||
@@ -140,2 +140,3 @@ import { flattenAsyncIterable } from './flattenAsyncIterable.js'; | ||
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args; | ||
signal?.throwIfAborted(); | ||
// If the schema used for execution is invalid, throw an error. | ||
@@ -195,2 +196,24 @@ assertValidSchema(schema); | ||
} | ||
signal?.throwIfAborted(); | ||
let onSignalAbort; | ||
let signalPromise; | ||
if (signal) { | ||
const listeners = new Set(); | ||
const signalDeferred = createDeferredPromise(); | ||
signalPromise = signalDeferred.promise; | ||
const sharedListener = () => { | ||
signalDeferred.reject(signal.reason); | ||
signal.removeEventListener('abort', sharedListener); | ||
}; | ||
signal.addEventListener('abort', sharedListener, { once: true }); | ||
signalPromise.catch(() => { | ||
for (const listener of listeners) { | ||
listener(); | ||
} | ||
listeners.clear(); | ||
}); | ||
onSignalAbort = handler => { | ||
listeners.add(handler); | ||
}; | ||
} | ||
return { | ||
@@ -209,2 +232,4 @@ schema, | ||
signal, | ||
onSignalAbort, | ||
signalPromise, | ||
}; | ||
@@ -284,3 +309,3 @@ } | ||
catch (error) { | ||
if (containsPromise) { | ||
if (error !== exeContext.signal?.reason && containsPromise) { | ||
// Ensure that any promises returned by other fields are handled, as they may also reject. | ||
@@ -302,3 +327,3 @@ return handleMaybePromise(() => promiseForObject(results, exeContext.signal), () => { | ||
// same map, but with any promises replaced with the values they resolved to. | ||
return promiseForObject(results, exeContext.signal); | ||
return promiseForObject(results, exeContext.signal, exeContext.signalPromise); | ||
} | ||
@@ -322,2 +347,3 @@ /** | ||
try { | ||
exeContext.signal?.throwIfAborted(); | ||
// Build a JS object of arguments from the field.arguments AST, using the | ||
@@ -504,4 +530,5 @@ // variables scope to fulfill any variable references. | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) { | ||
if (exeContext.signal && iterator.return) { | ||
registerAbortSignalListener(exeContext.signal, () => { | ||
exeContext.signal?.throwIfAborted(); | ||
if (iterator.return) { | ||
exeContext.onSignalAbort?.(() => { | ||
iterator.return?.(); | ||
@@ -946,7 +973,9 @@ }); | ||
if (isPromise(result)) { | ||
return result.then(assertEventStream).then(undefined, error => { | ||
return result | ||
.then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort)) | ||
.then(undefined, error => { | ||
throw locatedError(error, fieldNodes, pathToArray(path)); | ||
}); | ||
} | ||
return assertEventStream(result, exeContext.signal); | ||
return assertEventStream(result, exeContext.signal, exeContext.onSignalAbort); | ||
} | ||
@@ -957,3 +986,4 @@ catch (error) { | ||
} | ||
function assertEventStream(result, signal) { | ||
function assertEventStream(result, signal, onSignalAbort) { | ||
signal?.throwIfAborted(); | ||
if (result instanceof Error) { | ||
@@ -966,3 +996,3 @@ throw result; | ||
} | ||
if (signal) { | ||
if (onSignalAbort) { | ||
return { | ||
@@ -972,3 +1002,3 @@ [Symbol.asyncIterator]() { | ||
if (asyncIterator.return) { | ||
registerAbortSignalListener(signal, () => { | ||
onSignalAbort?.(() => { | ||
asyncIterator.return?.(); | ||
@@ -1201,3 +1231,2 @@ }); | ||
let isDone = false; | ||
const abortPromise = exeContext.signal ? getAbortPromise(exeContext.signal) : undefined; | ||
async function next() { | ||
@@ -1208,4 +1237,4 @@ if (isDone) { | ||
const subSequentPayloadPromises = Array.from(exeContext.subsequentPayloads).map(record => record.promise); | ||
if (abortPromise) { | ||
await Promise.race([abortPromise, ...subSequentPayloadPromises]); | ||
if (exeContext.signalPromise) { | ||
await Promise.race([exeContext.signalPromise, ...subSequentPayloadPromises]); | ||
} | ||
@@ -1212,0 +1241,0 @@ else { |
@@ -1,3 +0,2 @@ | ||
import { getAbortPromise, isPromise } from '@graphql-tools/utils'; | ||
import { handleMaybePromise } from '@whatwg-node/promise-helpers'; | ||
import { handleMaybePromise, isPromise } from '@whatwg-node/promise-helpers'; | ||
/** | ||
@@ -10,3 +9,4 @@ * This function transforms a JS object `Record<string, Promise<T>>` into | ||
*/ | ||
export function promiseForObject(object, signal) { | ||
export function promiseForObject(object, signal, signalPromise) { | ||
signal?.throwIfAborted(); | ||
const resolvedObject = Object.create(null); | ||
@@ -26,7 +26,6 @@ const promises = []; | ||
const promiseAll = promises.length === 1 ? promises[0] : Promise.all(promises); | ||
if (signal) { | ||
const abortPromise = getAbortPromise(signal); | ||
return Promise.race([abortPromise, promiseAll]).then(() => resolvedObject); | ||
if (signalPromise) { | ||
return Promise.race([signalPromise, promiseAll]).then(() => resolvedObject); | ||
} | ||
return promiseAll.then(() => resolvedObject); | ||
} |
{ | ||
"name": "@graphql-tools/executor", | ||
"version": "1.4.5-alpha-20250313124234-a3d061232db9cefabe856272b6dab452fbb71cf4", | ||
"version": "1.4.5", | ||
"sideEffects": false, | ||
@@ -9,3 +9,3 @@ "peerDependencies": { | ||
"dependencies": { | ||
"@graphql-tools/utils": "10.8.5-alpha-20250313124234-a3d061232db9cefabe856272b6dab452fbb71cf4", | ||
"@graphql-tools/utils": "^10.8.5", | ||
"@graphql-typed-document-node/core": "^3.2.0", | ||
@@ -12,0 +12,0 @@ "@repeaterjs/repeater": "^3.0.4", |
@@ -47,2 +47,4 @@ import { DocumentNode, FieldNode, FragmentDefinitionNode, GraphQLError, GraphQLField, GraphQLFieldResolver, GraphQLFormattedError, GraphQLObjectType, GraphQLSchema, GraphQLTypeResolver, OperationDefinitionNode } from 'graphql'; | ||
signal?: AbortSignal; | ||
onSignalAbort?(handler: () => void): void; | ||
signalPromise?: Promise<never>; | ||
} | ||
@@ -49,0 +51,0 @@ export interface FormattedExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> { |
@@ -1,2 +0,2 @@ | ||
import { MaybePromise } from '@graphql-tools/utils'; | ||
import { MaybePromise } from '@whatwg-node/promise-helpers'; | ||
type ResolvedObject<TData> = { | ||
@@ -12,3 +12,3 @@ [TKey in keyof TData]: TData[TKey] extends Promise<infer TValue> ? TValue : TData[TKey]; | ||
*/ | ||
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal): MaybePromise<ResolvedObject<TData>>; | ||
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal, signalPromise?: Promise<never>): MaybePromise<ResolvedObject<TData>>; | ||
export {}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
176239
1.14%3672
1.6%1
-50%+ Added
- Removed
Updated