@graphql-tools/executor-http
Advanced tools
Comparing version 1.1.10-alpha-6bf80c3816666dd2031fd93cfc3ac9173e3387a2 to 1.1.10-alpha-6cd46043df995f699f266bf5658f5290737c8ba1
# @graphql-tools/executor-http | ||
## 1.1.10-alpha-6bf80c3816666dd2031fd93cfc3ac9173e3387a2 | ||
## 1.1.10-alpha-6cd46043df995f699f266bf5658f5290737c8ba1 | ||
@@ -11,2 +11,8 @@ ### Patch Changes | ||
- [#180](https://github.com/graphql-hive/gateway/pull/180) [`693d50a`](https://github.com/graphql-hive/gateway/commit/693d50a529e688d7720f490308db2d474a64b6cc) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: | ||
- Added dependency [`@whatwg-node/disposablestack@^0.0.5` ↗︎](https://www.npmjs.com/package/@whatwg-node/disposablestack/v/0.0.5) (to `dependencies`) | ||
- [#180](https://github.com/graphql-hive/gateway/pull/180) [`12c7bfe`](https://github.com/graphql-hive/gateway/commit/12c7bfe7bdd9d78320e46d9dfcb8162f7225676a) Thanks [@ardatan](https://github.com/ardatan)! - Use new explicit resource management internally | ||
- [#98](https://github.com/graphql-hive/gateway/pull/98) [`697308d`](https://github.com/graphql-hive/gateway/commit/697308df3b2dd96f28dc65a5f5361a911077e022) Thanks [@ardatan](https://github.com/ardatan)! - Bun support by using native Bun API whenever possible | ||
@@ -13,0 +19,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { ExecutionRequest, DisposableSyncExecutor, SyncExecutor, DisposableAsyncExecutor, AsyncExecutor } from '@graphql-tools/utils'; | ||
import { ExecutionRequest, DisposableSyncExecutor, DisposableAsyncExecutor } from '@graphql-tools/utils'; | ||
import { OperationDefinitionNode, GraphQLResolveInfo, DocumentNode } from 'graphql'; | ||
@@ -60,3 +60,3 @@ | ||
* Enable [Explicit Resource Management](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management) | ||
* @default false | ||
* @deprecated The executors are always disposable, and this option will be removed in the next major version, there is no need to have a flag for this. | ||
*/ | ||
@@ -66,43 +66,13 @@ disposable?: boolean; | ||
type HeadersConfig = Record<string, string>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & { | ||
fetch: SyncFetchFn; | ||
disposable: true; | ||
}): DisposableSyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
fetch: SyncFetchFn; | ||
disposable: false; | ||
}): SyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & { | ||
fetch: SyncFetchFn; | ||
}): SyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
fetch: AsyncFetchFn; | ||
disposable: true; | ||
}): DisposableAsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
fetch: AsyncFetchFn; | ||
disposable: false; | ||
}): AsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & { | ||
fetch: AsyncFetchFn; | ||
}): AsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
fetch: RegularFetchFn; | ||
disposable: true; | ||
}): DisposableAsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
fetch: RegularFetchFn; | ||
disposable: false; | ||
}): AsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & { | ||
fetch: RegularFetchFn; | ||
}): AsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
disposable: true; | ||
}): DisposableAsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch' | 'disposable'> & { | ||
disposable: false; | ||
}): AsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'>): AsyncExecutor<any, HTTPExecutorOptions>; | ||
declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'>): DisposableAsyncExecutor<any, HTTPExecutorOptions>; | ||
export { type AsyncFetchFn, type AsyncImportFn, type FetchFn, type HTTPExecutorOptions, type HeadersConfig, type RegularFetchFn, type SyncFetchFn, type SyncImportFn, type SyncResponse, buildHTTPExecutor, isLiveQueryOperationDefinitionNode }; |
@@ -1,2 +0,3 @@ | ||
import { isAsyncIterable, isPromise, fakePromise, inspect, mapAsyncIterator, mergeIncrementalResult, memoize1, getOperationASTFromRequest, createGraphQLError } from '@graphql-tools/utils'; | ||
import { isAsyncIterable, isPromise, fakePromise, createGraphQLError, inspect, mapAsyncIterator, mergeIncrementalResult, memoize1, getOperationASTFromRequest, mapMaybePromise } from '@graphql-tools/utils'; | ||
import { DisposableSymbols } from '@whatwg-node/disposablestack'; | ||
import { File, FormData, TextDecoder, fetch } from '@whatwg-node/fetch'; | ||
@@ -91,7 +92,14 @@ import { ValueOrPromise } from 'value-or-promise'; | ||
} | ||
return ValueOrPromise.all( | ||
uploads.map( | ||
(upload, i) => new ValueOrPromise(() => handleUpload(upload, i)) | ||
) | ||
).then(() => form).resolve(); | ||
const jobs = []; | ||
for (const i in uploads) { | ||
const upload = uploads[i]; | ||
const job = handleUpload(upload, Number(i)); | ||
if (isPromise(job)) { | ||
jobs.push(job); | ||
} | ||
} | ||
if (jobs.length > 0) { | ||
return Promise.all(jobs).then(() => form); | ||
} | ||
return form; | ||
} | ||
@@ -112,2 +120,16 @@ function isBlob(obj) { | ||
function createAbortErrorReason() { | ||
return new Error("Executor was disposed."); | ||
} | ||
function createGraphQLErrorForAbort(reason, extensions) { | ||
return createGraphQLError("The operation was aborted. reason: " + reason, { | ||
extensions | ||
}); | ||
} | ||
function createResultForAbort(reason, extensions) { | ||
return { | ||
errors: [createGraphQLErrorForAbort(reason, extensions)] | ||
}; | ||
} | ||
const DELIM = "\n\n"; | ||
@@ -117,3 +139,3 @@ function isReadableStream(value) { | ||
} | ||
function handleEventStreamResponse(response) { | ||
function handleEventStreamResponse(signal, response) { | ||
const body = response.body; | ||
@@ -134,2 +156,6 @@ if (!isReadableStream(body)) { | ||
async function pump() { | ||
if (signal.aborted) { | ||
await push(createResultForAbort(signal)); | ||
return stop(); | ||
} | ||
if (!body?.locked) { | ||
@@ -234,8 +260,25 @@ return stop(); | ||
function createSignalWrapper(signal) { | ||
const listeners = /* @__PURE__ */ new Set(); | ||
signal.onabort = (event) => { | ||
for (const listener of listeners) { | ||
listener(event); | ||
} | ||
}; | ||
return Object.assign(signal, { | ||
addEventListener(_type, listener) { | ||
listeners.add(listener); | ||
}, | ||
removeEventListener(_type, listener) { | ||
listeners.delete(listener); | ||
} | ||
}); | ||
} | ||
function buildHTTPExecutor(options) { | ||
const printFn = options?.print ?? defaultPrintFn; | ||
let disposeCtrl; | ||
const disposeCtrl = new AbortController(); | ||
const sharedSignal = createSignalWrapper(disposeCtrl.signal); | ||
const baseExecutor = (request) => { | ||
if (disposeCtrl?.signal.aborted) { | ||
return createResultForAbort(disposeCtrl.signal); | ||
if (sharedSignal.aborted) { | ||
return createResultForAbort(sharedSignal.reason); | ||
} | ||
@@ -270,18 +313,8 @@ const fetchFn = request.extensions?.fetch ?? options?.fetch ?? fetch; | ||
const query = printFn(request.document); | ||
let signal = disposeCtrl?.signal; | ||
let clearTimeoutFn = () => { | ||
}; | ||
let signal = sharedSignal; | ||
if (options?.timeout) { | ||
const timeoutCtrl = new AbortController(); | ||
signal = timeoutCtrl.signal; | ||
disposeCtrl?.signal.addEventListener("abort", clearTimeoutFn); | ||
const timeoutId = setTimeout(() => { | ||
if (!timeoutCtrl.signal.aborted) { | ||
timeoutCtrl.abort("timeout"); | ||
} | ||
disposeCtrl?.signal.removeEventListener("abort", clearTimeoutFn); | ||
}, options.timeout); | ||
clearTimeoutFn = () => { | ||
clearTimeout(timeoutId); | ||
}; | ||
signal = AbortSignal.any([ | ||
sharedSignal, | ||
AbortSignal.timeout(options.timeout) | ||
]); | ||
} | ||
@@ -323,28 +356,29 @@ const upstreamErrorExtensions = { | ||
upstreamErrorExtensions.request.body = body; | ||
return new ValueOrPromise( | ||
() => createFormDataFromVariables(body, { | ||
return mapMaybePromise( | ||
createFormDataFromVariables(body, { | ||
File: options?.File, | ||
FormData: options?.FormData | ||
}) | ||
).then((body2) => { | ||
if (typeof body2 === "string" && !headers["content-type"]) { | ||
upstreamErrorExtensions.request.body = body2; | ||
headers["content-type"] = "application/json"; | ||
}), | ||
(body2) => { | ||
if (typeof body2 === "string" && !headers["content-type"]) { | ||
upstreamErrorExtensions.request.body = body2; | ||
headers["content-type"] = "application/json"; | ||
} | ||
const fetchOptions = { | ||
method: "POST", | ||
body: body2, | ||
headers, | ||
signal | ||
}; | ||
if (options?.credentials != null) { | ||
fetchOptions.credentials = options.credentials; | ||
} | ||
return fetchFn( | ||
endpoint, | ||
fetchOptions, | ||
request.context, | ||
request.info | ||
); | ||
} | ||
const fetchOptions = { | ||
method: "POST", | ||
body: body2, | ||
headers, | ||
signal | ||
}; | ||
if (options?.credentials != null) { | ||
fetchOptions.credentials = options.credentials; | ||
} | ||
return fetchFn( | ||
endpoint, | ||
fetchOptions, | ||
request.context, | ||
request.info | ||
); | ||
}).resolve(); | ||
); | ||
} | ||
@@ -360,3 +394,2 @@ } | ||
}); | ||
clearTimeoutFn(); | ||
if (options?.retry != null && !fetchResult.status.toString().startsWith("2")) { | ||
@@ -369,3 +402,3 @@ throw new Error( | ||
if (contentType?.includes("text/event-stream")) { | ||
return handleEventStreamResponse(fetchResult); | ||
return handleEventStreamResponse(signal, fetchResult); | ||
} else if (contentType?.includes("multipart/mixed")) { | ||
@@ -458,4 +491,4 @@ return handleMultipartMixedResponse(fetchResult); | ||
function retryAttempt() { | ||
if (disposeCtrl?.signal.aborted) { | ||
return createResultForAbort(disposeCtrl.signal); | ||
if (sharedSignal.aborted) { | ||
return createResultForAbort(sharedSignal.reason); | ||
} | ||
@@ -471,3 +504,3 @@ attempt++; | ||
} | ||
return new ValueOrPromise(() => baseExecutor(request)).then((res) => { | ||
return mapMaybePromise(baseExecutor(request), (res) => { | ||
result = res; | ||
@@ -478,3 +511,3 @@ if (result?.errors?.length) { | ||
return result; | ||
}).resolve(); | ||
}); | ||
} | ||
@@ -484,9 +517,4 @@ return retryAttempt(); | ||
} | ||
if (!options?.disposable) { | ||
disposeCtrl = void 0; | ||
return executor; | ||
} | ||
disposeCtrl = new AbortController(); | ||
Object.defineProperties(executor, { | ||
[Symbol.dispose]: { | ||
[DisposableSymbols.dispose]: { | ||
get() { | ||
@@ -498,3 +526,3 @@ return function dispose() { | ||
}, | ||
[Symbol.asyncDispose]: { | ||
[DisposableSymbols.asyncDispose]: { | ||
get() { | ||
@@ -525,4 +553,4 @@ return function asyncDispose() { | ||
}); | ||
} else if (e.name === "AbortError" && signal?.reason) { | ||
return createGraphQLErrorForAbort(signal, { | ||
} else if (e.name === "AbortError" && signal.reason) { | ||
return createGraphQLErrorForAbort(signal.reason, { | ||
extensions: upstreamErrorExtensions | ||
@@ -542,19 +570,3 @@ }); | ||
} | ||
function createAbortErrorReason() { | ||
return new Error("Executor was disposed."); | ||
} | ||
function createGraphQLErrorForAbort(signal, extensions) { | ||
return createGraphQLError( | ||
"The operation was aborted. reason: " + signal.reason, | ||
{ | ||
extensions | ||
} | ||
); | ||
} | ||
function createResultForAbort(signal, extensions) { | ||
return { | ||
errors: [createGraphQLErrorForAbort(signal, extensions)] | ||
}; | ||
} | ||
export { buildHTTPExecutor, isLiveQueryOperationDefinitionNode }; |
{ | ||
"name": "@graphql-tools/executor-http", | ||
"version": "1.1.10-alpha-6bf80c3816666dd2031fd93cfc3ac9173e3387a2", | ||
"version": "1.1.10-alpha-6cd46043df995f699f266bf5658f5290737c8ba1", | ||
"type": "module", | ||
@@ -44,2 +44,3 @@ "description": "A set of utils for faster development of GraphQL tools", | ||
"@repeaterjs/repeater": "^3.0.4", | ||
"@whatwg-node/disposablestack": "^0.0.5", | ||
"@whatwg-node/fetch": "^0.10.0", | ||
@@ -46,0 +47,0 @@ "extract-files": "^11.0.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61043
9
1167