@graphql-tools/executor-http
Advanced tools
Comparing version 1.2.3-alpha-eeb5a1d4d585f1315b38da3d023b25283b3ac051 to 1.2.3-alpha-f0b9caef8c2ed033b8a6a3ec3a6b5fa38c7c67bd
# @graphql-tools/executor-http | ||
## 1.2.3-alpha-eeb5a1d4d585f1315b38da3d023b25283b3ac051 | ||
## 1.2.3-alpha-f0b9caef8c2ed033b8a6a3ec3a6b5fa38c7c67bd | ||
### Patch Changes | ||
- [#376](https://github.com/graphql-hive/gateway/pull/376) [`eeb5a1d`](https://github.com/graphql-hive/gateway/commit/eeb5a1d4d585f1315b38da3d023b25283b3ac051) Thanks [@ardatan](https://github.com/ardatan)! - No need to handle event listeners inside HTTP Executor thanks to the improvements with `@graphql-tools/utils`'s `registerAbortSignalListener` to avoid Node.js warnings when multiple event listeners registered to an `AbortSignal` | ||
- [#381](https://github.com/graphql-hive/gateway/pull/381) [`55eb1b4`](https://github.com/graphql-hive/gateway/commit/55eb1b4d14aec7b3e6c7bcf9f596bc01192d022c) Thanks [@ardatan](https://github.com/ardatan)! - dependencies updates: | ||
- Added dependency [`@graphql-tools/executor-common@workspace:^` ↗︎](https://www.npmjs.com/package/@graphql-tools/executor-common/v/workspace:^) (to `dependencies`) | ||
- [#381](https://github.com/graphql-hive/gateway/pull/381) [`55eb1b4`](https://github.com/graphql-hive/gateway/commit/55eb1b4d14aec7b3e6c7bcf9f596bc01192d022c) Thanks [@ardatan](https://github.com/ardatan)! - This is a bugfix with some internal changes, no user action is needed. This bugfix and improvement is done to improve the stability of some components of the gateway; | ||
Like HMAC Upstream Signature plugin, different components of the gateway were using different ways of serializing the execution request. | ||
Some of them were ignoring `variables` if it is empty, some of not, this was causing the signature generation to be different for the same query. | ||
For example, it was working as expected in Proxy mode, but not working as expected in Federation Gateway mode. | ||
With this change, now we have a shared helper to serialize the upstream execution request with a memoized `print` function for query AST etc to have a consistent serialization so consistent signature generation for HMAC. | ||
For example instead of using `print`, you should use `defaultPrintFn` that memoizes `print` operation and also used the string version of it parsed before by Envelop/Yoga. | ||
```diff | ||
-import { print } from 'graphql'; | ||
-const query = print(parsedQuery); | ||
+import { defaultPrintFn } from '@graphql-tools/executor-common'; | ||
+const query = defaultPrintFn(parsedQuery); | ||
``` | ||
Or instead of creating objects from `ExecutionRequest`, use `serializeExecutionRequest` helper. | ||
```diff | ||
-const serializedRequest = { | ||
- query: print(executionRequest.document), | ||
- variables: executionRequest.variables, | ||
- operationName: executionRequest.operationName, | ||
- extensions: executionRequest.extensions, | ||
-}; | ||
+import { serializeExecutionRequest } from '@graphql-tools/executor-common'; | ||
+const serializedRequest = serializeExecutionRequest(executionRequest); | ||
``` | ||
- Updated dependencies [[`55eb1b4`](https://github.com/graphql-hive/gateway/commit/55eb1b4d14aec7b3e6c7bcf9f596bc01192d022c)]: | ||
- @graphql-tools/executor-common@0.0.1-alpha-f0b9caef8c2ed033b8a6a3ec3a6b5fa38c7c67bd | ||
## 1.2.2 | ||
@@ -10,0 +45,0 @@ |
@@ -83,8 +83,2 @@ import { ExecutionRequest, DisposableSyncExecutor, DisposableAsyncExecutor } from '@graphql-tools/utils'; | ||
} | ||
type SerializedRequest = { | ||
query?: string; | ||
variables?: Record<string, any>; | ||
operationName?: string; | ||
extensions?: any; | ||
}; | ||
type HeadersConfig = Record<string, string>; | ||
@@ -102,2 +96,2 @@ declare function buildHTTPExecutor(options?: Omit<HTTPExecutorOptions, 'fetch'> & { | ||
export { type AsyncFetchFn, type AsyncImportFn, type FetchFn, type HTTPExecutorOptions, type HeadersConfig, type RegularFetchFn, type SerializedRequest, type SyncFetchFn, type SyncImportFn, type SyncResponse, buildHTTPExecutor, isLiveQueryOperationDefinitionNode }; | ||
export { type AsyncFetchFn, type AsyncImportFn, type FetchFn, type HTTPExecutorOptions, type HeadersConfig, type RegularFetchFn, type SyncFetchFn, type SyncImportFn, type SyncResponse, buildHTTPExecutor, isLiveQueryOperationDefinitionNode }; |
import { abortSignalAny } from '@graphql-hive/gateway-abort-signal-any'; | ||
import { isAsyncIterable, isPromise, mapMaybePromise, memoize1, createGraphQLError, inspect, mapAsyncIterator, mergeIncrementalResult, getOperationASTFromRequest } from '@graphql-tools/utils'; | ||
import { defaultPrintFn, serializeExecutionRequest } from '@graphql-tools/executor-common'; | ||
import { isAsyncIterable, isPromise, mapMaybePromise, createGraphQLError, inspect, mapAsyncIterator, mergeIncrementalResult, memoize1, getOperationASTFromRequest } from '@graphql-tools/utils'; | ||
import { DisposableSymbols } from '@whatwg-node/disposablestack'; | ||
@@ -7,4 +8,4 @@ import { File, FormData, TextEncoder, crypto, TextDecoder, fetch } from '@whatwg-node/fetch'; | ||
import { extractFiles, isExtractableFile } from 'extract-files'; | ||
import { stripIgnoredCharacters, print, GraphQLError } from 'graphql'; | ||
import { Repeater } from '@repeaterjs/repeater'; | ||
import { GraphQLError } from 'graphql'; | ||
import { meros as meros$1 } from 'meros/browser'; | ||
@@ -123,6 +124,2 @@ import { meros } from 'meros/node'; | ||
const defaultPrintFn = memoize1(function defaultPrintFn2(document) { | ||
return stripIgnoredCharacters(print(document)); | ||
}); | ||
function createAbortErrorReason() { | ||
@@ -288,8 +285,25 @@ return new Error("Executor was disposed."); | ||
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; | ||
const disposeCtrl = new AbortController(); | ||
const sharedSignal = createSignalWrapper(disposeCtrl.signal); | ||
const baseExecutor = (request, excludeQuery) => { | ||
if (disposeCtrl.signal.aborted) { | ||
return createResultForAbort(disposeCtrl.signal.reason); | ||
if (sharedSignal.aborted) { | ||
return createResultForAbort(sharedSignal.reason); | ||
} | ||
@@ -323,3 +337,3 @@ const fetchFn = request.extensions?.fetch ?? options?.fetch ?? fetch; | ||
} | ||
const signals = [disposeCtrl.signal]; | ||
const signals = [sharedSignal]; | ||
const signalFromRequest = request.signal || request.info?.signal; | ||
@@ -335,3 +349,3 @@ if (signalFromRequest) { | ||
} | ||
const signal = signals.length > 1 ? abortSignalAny(signals) : signals[0]; | ||
const signal = abortSignalAny(signals); | ||
const upstreamErrorExtensions = { | ||
@@ -344,8 +358,7 @@ request: { | ||
let serializeFn = function serialize() { | ||
return { | ||
query: excludeQuery ? void 0 : printFn(request.document), | ||
variables: (request.variables && Object.keys(request.variables).length) > 0 ? request.variables : void 0, | ||
operationName: request.operationName ? request.operationName : void 0, | ||
extensions: request.extensions && Object.keys(request.extensions).length > 0 ? request.extensions : void 0 | ||
}; | ||
return serializeExecutionRequest({ | ||
executionRequest: request, | ||
excludeQuery, | ||
printFn | ||
}); | ||
}; | ||
@@ -360,8 +373,10 @@ if (options?.apq) { | ||
}; | ||
return { | ||
query: excludeQuery ? void 0 : query, | ||
variables: (request.variables && Object.keys(request.variables).length) > 0 ? request.variables : void 0, | ||
operationName: request.operationName ? request.operationName : void 0, | ||
extensions | ||
}; | ||
return serializeExecutionRequest({ | ||
executionRequest: { | ||
...request, | ||
extensions | ||
}, | ||
excludeQuery, | ||
printFn | ||
}); | ||
}); | ||
@@ -548,4 +563,4 @@ }; | ||
function retryAttempt() { | ||
if (disposeCtrl.signal.aborted) { | ||
return createResultForAbort(disposeCtrl.signal.reason); | ||
if (sharedSignal.aborted) { | ||
return createResultForAbort(sharedSignal.reason); | ||
} | ||
@@ -552,0 +567,0 @@ attempt++; |
{ | ||
"name": "@graphql-tools/executor-http", | ||
"version": "1.2.3-alpha-eeb5a1d4d585f1315b38da3d023b25283b3ac051", | ||
"version": "1.2.3-alpha-f0b9caef8c2ed033b8a6a3ec3a6b5fa38c7c67bd", | ||
"type": "module", | ||
@@ -43,2 +43,3 @@ "description": "A set of utils for faster development of GraphQL tools", | ||
"@graphql-hive/gateway-abort-signal-any": "^0.0.2", | ||
"@graphql-tools/executor-common": "0.0.1-alpha-f0b9caef8c2ed033b8a6a3ec3a6b5fa38c7c67bd", | ||
"@graphql-tools/utils": "^10.7.0", | ||
@@ -45,0 +46,0 @@ "@repeaterjs/repeater": "^3.0.4", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
74687
1338
11
+ Added@graphql-tools/executor-common@0.0.1-alpha-f0b9caef8c2ed033b8a6a3ec3a6b5fa38c7c67bd
+ Added@envelop/core@5.0.3(transitive)
+ Added@envelop/types@5.0.0(transitive)
+ Added@graphql-tools/executor-common@0.0.1-alpha-f0b9caef8c2ed033b8a6a3ec3a6b5fa38c7c67bd(transitive)