@graphql-tools/utils
13.1.3 · 22 Oct 2026MIT25.7M / weekRepositoryHomepagenpmAtom feed
186 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.
- 13.x · latest line
13.1.3
22 Oct 2026mapSchemanow remaps directive argument defaults the same way it already remaps field argument defaults.Use case:
UserRoleis remapped to internal ids, and@authdefaults toUSER.const schema = mapSchema(originalSchema, { [MapperKind.ENUM_VALUE]: (valueConfig, typeName, _schema, externalValue) => { if (typeName === 'UserRole' && externalValue === 'USER') { return { ...valueConfig, value: '3user' }; } return valueConfig; }, }); // directive @auth(role: UserRole = USER) schema.getDirective('auth').args.find(arg => arg.name === 'role').defaultValue; // before: "USER" // after: "3user"mapSchemaserializes the stored default with the source type before parsing with the remapped type, so an internal value that matches another enum name (USER->"ADMIN") stays"ADMIN"instead of being parsed as that name.forEachDefaultValuewalks directive arguments too, somakeExecutableSchemaenum resolvers get the same result.Published
Executortypes include/// <reference lib="esnext.disposable" preserve="true" />so consumers do not needskipLibCheckor a fullesnextlib just to import this package.Use case: an app with
"lib": ["es2022"]or["es2024"]andskipLibCheck: falsethat imports@graphql-tools/utils:import type { Executor } from '@graphql-tools/utils'; export const executor: Executor = async request => { // ... };Executorcan return aDisposable/AsyncIterableresult. Those names live in TypeScript'sesnext.disposablelib, which is not part ofes2022/es2024. Without the preserved reference,tscreportsCannot find name 'Disposable'. With it, the published.d.tspulls in that lib for the consumer automatically.
13.1.2
22 Oct 2026printSchemaWithDirectivesno longer turns unquoted directive argument literals into strings.In GraphQL SDL, an unquoted identifier in value position is an
EnumValueAST node. A quoted value is aStringValue. Those are different kinds even when the argument type is a custom scalar rather than anenumtype.parseLiteralon that scalar receives the original kind, so a custom scalar can treatargument_valueand"argument_value"as different inputs.The printer was reconstructing directive arguments from JS values.
valueFromASTUntypedmaps both kinds to the same string, andastFromValuethen emits aStringValue. The printed SDL became@directive(arg: "argument_value")even though the schema AST still had@directive(arg: argument_value).That is a round-trip / fidelity bug: loaders, schema diffs, snapshots, and subgraph publishes see different SDL, and a scalar that distinguishes the two kinds changes meaning. Default scalars coerce both to the same JS string, so many runtime paths do not notice.
When the original AST is still the source of truth,
printSchemaWithDirectivesnow keeps those directive argument nodes, including nested list and input-object values. If directive values are supplied only through extensions (code-first), JS strings are still printed as strings because the original kind is not available.Fixes #8557
13.1.1
20 Oct 2026INCREMENTAL_DELIVERY_SPECSis the shared HTTP contract forincrementalSpec. Each row maps an Accept / Content-Type parameter (deferSpec=20220824,incrementalSpec=v0.2, ...) to the executor payload id ('v0.1'|'v0.2').GraphQL Yoga, Hive Gateway, HTTP executors, and other servers should look up this table instead of hardcoding spec strings. When a later incremental spec ships, the work stays in graphql-tools: add a row here and an executor publisher. Consumers bump
@graphql-tools/utils/@graphql-tools/executor. Accept negotiation, Content-Type echo, and 406 for unknown spec params keep working without a Yoga / Gateway / executor-http patch for the new identifier.Unknown values for a registered parameter name stay unsupported (HTTP 406). Helpers:
lookupIncrementalDeliverySpec,getMultipartContentType,getDefaultIncrementalDeliverySpec,getIncrementalSpecParameterNames.
13.1.0
20 Oct 2026@graphql-tools/executorcan publish both incremental delivery payload formats from one execution kernel. PassincrementalSpec: 'v0.1' | 'v0.2'onexecute/subscribe/normalizedExecutor(also onExecutionRequestforexecutorFromSchema).'v0.1'remains the default and keeps the existingpath/labelpatches used withmultipart/mixed;deferSpec=20220824.'v0.2'emits Apollo incremental v0.2 payloads (pendingwithidandpath,incrementalwithidand optionalsubPath,completed) used withmultipart/mixed;incrementalSpec=v0.2.Field execution,
@defer/@streamscheduling, andAbortSignalcancellation are shared. Spec-specific JSON is built by a publisher: v0.1 still yields{ incremental, hasNext }; v0.2 assigns ids when a pending group is first announced, groups streamed items under one pending path, and reports completion separately. Nested@deferpatches are collected as children of the parent patch so v0.2 can announce the inner fragment only after the parent is pending, without making the nested fragment wait on the parent's promise (v0.1 sibling completion is unchanged aside from incremental array order).Publisher state (
Map/Setof ids) is allocated only for'v0.2'.StreamGroupis created only for v0.2 and only when items are actually streamed. v0.2 stream completion uses an open-count on the group instead of scanningsubsequentPayloads.mergeIncrementalResultstill merges v0.1path/itemspatches. For v0.2 it recordspendingids on the execution result, writes deferreddataatpending.path + subPath, appends streameditemsonto the list atpending.path, and foldscompleted.errorsintoerrors.visitResultflattens nested deferred patches so result visiting still sees fields that live under a child@defer.
13.0.2
19 Oct 2026Add
asGetArgumentValuesVariablesandcoerceGetVariableValuesResulthelpers for GraphQL 16/17VariableValuescompatibility when callinggetArgumentValues/ normalizinggetVariableValuesresults for helpers likeshouldIncludeNode.
13.0.1
19 Oct 2026Align
memoize4third-level cache initialization with thelet+ reassignment pattern used bymemoize3/memoize5.Previously a nested
const cache4insideif (!cache4)shadowed the outer binding. Runtime behavior was already safe (that branch stores the map and returns), but the declaration was easy to misread and fragile if the early return were removed. The helper now assigns to the outerlet cache4instead, with regression tests for the third-level cache path.
13.0.0
19 Oct 2026- breaking
Drop GraphQL v14/v15 support and require Node.js >= 22.18.
On Node.js ≥26.1 (and ≥24.16 where backported),
fs.globfollowSymlinksis used.On older engines, symlink directories are discovered only under each pattern’s literal prefix (not the whole
cwd) and patterns are re-rooted.
Major Changes
- breaking
Drop GraphQL v14/v15 support and require Node.js >= 22.18.
graphqlpeer range is now^16.0.0 || ^17.0.0.engines.nodeis now>=22.18.0(Nodefs.glob+ Babel 8).Dev tooling and
@graphql-tools/graphql-tag-pluckmove to Babel 8 (@babel/core/ parser / traverse / types).The standalone
cross-inspectpackage is discontinued. Useinspectfrom@graphql-tools/utilsinstead (Nodeutil.inspectviaprocess.getBuiltinModule, with a smallJSON.stringify/Stringfallback).
Removed
@graphql-tools/utilsexportsRemoved Use instead getArgumentValuesimport { getArgumentValues } from 'graphql'coerceInputs/graphqlJSCompatgraphql@16+ APIs ( getArgumentValues, etc.)createDeferred/createDeferredPromiseconst { promise, resolve, reject } = Promise.withResolvers()createGraphQLErrornew GraphQLError(message, options)fromgraphqlmapMaybePromisehandleMaybePromisefrom@whatwg-node/promise-helpersisPromise/fakePromise/mapAsyncIterator/MaybePromise@whatwg-node/promise-helpersregisterAbortSignalListener/getAbortPromiseAbortSignalAPIs (throwIfAborted,addEventListener('abort', …, { once: true }),AbortSignal.any, …)withCancel/getAsyncIterableWithCancel/getAsyncIteratorWithCancelHandle cancellation on the async iterator’s return()(or your transport abort path)debugTimerStart/debugTimerEndYour own timing / console.timeif neededPromiseWithResolvers(type)Built-in PromiseWithResolvers<T>/ return type ofPromise.withResolvers()inspectand the WeakMapmemoize1…memoize2of5helpers remain on@graphql-tools/utils(inspect is no longer re-exported fromcross-inspect).File matching (
globby→fs.glob)Loaders and
@graphql-tools/load-filesnow use Node’sfs.globthrough:import { matchFiles, matchFilesSync } from '@graphql-tools/load-files';Directory symlinks are followed for recursive (
**) patterns:On Node.js ≥26.1 (and ≥24.16 where backported),
fs.globfollowSymlinksis used.On older engines, symlink directories are discovered only under each pattern’s literal prefix (not the whole
cwd) and patterns are re-rooted.Non-recursive / literal patterns skip the symlink walk entirely.
@graphql-tools/executorhot-path caches (collectSubfields, argument coercion,@streamdetection) usememoize2/memoize3from utils.collectSubFieldsin utils stays unmemoized so the executor can own a single memoize3 layer.Errors and other cleanup
Prefer
new GraphQLError(message, options)fromgraphql. Experimental schemacoordinatesupport remains onlocatedError/relocatedError/getSchemaCoordinate.Removed GraphQL versions older than 16 compatibility branches (error construction, validation rule name suffixes,
URL.canParsefallback).Promise helpers should be imported from
@whatwg-node/promise-helpers(handleMaybePromise,isPromise,fakePromise,mapAsyncIterator,MaybePromise) rather than re-exported from utils.
Patch Changes
dependencies updates:
Updated dependency
@graphql-typed-document-node/core@^3.2.0↗︎ (from^3.1.1, independencies)Removed dependency
cross-inspect@1.0.1↗︎ (fromdependencies)Updated dependency
graphql@^16.0.0 || ^17.0.0↗︎ (from^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0, inpeerDependencies)
- 12.x
12.1.0
15 Oct 2026Fix: Preserve symbol-keyed GraphQL extensions when building, merging, or extracting schemas.
GraphQL.js v17 allows
string | symbolkeys on schema/type/fieldextensions(viatoObjMapWithSymbols).@graphql-toolswas dropping those symbol keys in two places:utils: coerce GraphQL 17 argument defaults in getArgumentValues via local input coercion (defaults, missing variables, nested sources)
Keep argument types of defined directives when pruning so that unused directives such as
@key(fields: _FieldSet!)retain their full definitions instead of losing the argument together with its type.
Minor Changes
Fix: Preserve symbol-keyed GraphQL extensions when building, merging, or extracting schemas.
GraphQL.js v17 allows
string | symbolkeys on schema/type/fieldextensions(viatoObjMapWithSymbols).@graphql-toolswas dropping those symbol keys in two places:mergeDeeponly walked enumerable string keys (for...in), so symbol extensions were lost when applyingschemaExtensions.extractExtensionsFromSchemadid not copy non-enumerable own symbol keys (enumerable symbols already survive object rest/spread; the explicit loop covers the non-enumerable case).
Example (bug)
import { makeExecutableSchema } from '@graphql-tools/schema' const META = Symbol('META') const schema = makeExecutableSchema({ typeDefs: /* GraphQL */ ` type Query { hello: String } `, schemaExtensions: { schemaExtensions: { [META]: { source: 'app' }, tagged: true, }, types: {}, }, }) // Before: only string keys survived // schema.extensions === { tagged: true } // After: symbol keys are preserved // schema.extensions[META] === { source: 'app' } // schema.extensions.tagged === trueSchema extension merge/extract and resolver merging always enable
{ enumerable: true, nonEnumerable: true }so symbol keys survive in tools' own merge/extract paths on every supported GraphQL.js major. (GraphQL.js itself may still drop symbol keys from field configs below v17 when rebuilding types.)mergeDeepAPImergeDeepnow accepts an options object. The old positional boolean arguments still work but are deprecated.import { mergeDeep } from '@graphql-tools/utils' // Deprecated (still supported) mergeDeep([a, b], false, true, false, true) // ^proto ^arrays ^len ^non-enumerable symbols only // Preferred mergeDeep([a, b], { respectPrototype: false, respectArrays: true, respectArrayLength: false, respectSymbols: { enumerable: true, // merge `obj[sym] = value` keys nonEnumerable: true, // copy defineProperty(..., { enumerable: false }) symbols }, })respectSymbolsdefaults to{ enumerable: false, nonEnumerable: false }(symbols dropped), matching the historical default. The legacy 5th positional flag still maps to{ nonEnumerable: true }only.Resolver map types (
IResolvers/ field resolverextensionsand type__extensions) now useExtensionsObject(Record<string | symbol, any>), so symbol-keyed resolver extensions type-check under GraphQL.js v17+.Patch Changes
utils: coerce GraphQL 17 argument defaults in getArgumentValues via local input coercion (defaults, missing variables, nested sources)
Keep argument types of defined directives when pruning so that unused directives such as
@key(fields: _FieldSet!)retain their full definitions instead of losing the argument together with its type.
12.0.4
12 Oct 2026Skip empty and whitespace-only
descriptionvalues ingetDescriptionNode/printSchemaWithDirectives, so loaders that setdescription: ""no longer emit""""""in printed SDL.
12.0.3
30 Sep 2026Compare incremental path keys to
__proto__at the property access insetObjectKeyPath, in addition to the existingisSafeObjectKeycheck.
12.0.2
30 Sep 2026- security
Fix prototype pollution in
mergeIncrementalResultPath segments are now rejected unless they are primitive strings or numbers, and keys named
__proto__,constructororprototypeare still blocked. Previously a non-primitive segment such as["__proto__"]bypassed the string equality guard and was coerced into a write onObject.prototype.Also exports shared
isSafeObjectKey/isDangerousObjectKeyhelpers used by this path walker and other package call sites.@graphql-tools/mergeand@graphql-tools/mockare patched so they ship with the new imports;updateInternalDependenciesraises their utils floor when12.0.2is versioned. dependencies updates:
12.0.1
7 Sep 2026- security
Fix prototype pollution in
mergeDeepSource keys named
__proto__,constructororprototypeare now skipped at every recursion level, and the check for an existing key useshasOwnPropertyinstead ofin, so inherited properties are never used as merge targets.Previously, merging untrusted data such as
JSON.parse('{"constructor":{"__proto__":{"call":"x"}}}')could reach and overwrite properties onObject.prototypeorFunction.prototype. Omit mutation/subscription from
printSchemaWithDirectiveswhen those root types are no longer present on the schema (e.g. afterpruneSchema).Allow
%in paths checked byisValidPath(e.g. directories from URL-encoded repo names).
Patch Changes
Omit mutation/subscription from
printSchemaWithDirectiveswhen those root types are no longer present on the schema (e.g. afterpruneSchema).Allow
%in paths checked byisValidPath(e.g. directories from URL-encoded repo names).Clean up
observableToAsyncIterablequeues and unsubscribe when the observable completes, so iterators do not retain references afterdone. Fixes leak detection flakes related to #8057.Prefer runtime
descriptionvalues over staleastNodedescriptions inprintSchemaWithDirectives/getDescriptionNode. Fixes #5508.- security
Fix prototype pollution in
mergeDeepSource keys named
__proto__,constructororprototypeare now skipped at every recursion level, and the check for an existing key useshasOwnPropertyinstead ofin, so inherited properties are never used as merge targets.Previously, merging untrusted data such as
JSON.parse('{"constructor":{"__proto__":{"call":"x"}}}')could reach and overwrite properties onObject.prototypeorFunction.prototype.
- 11.x
11.2.2
17 Jul 2026Reading the note…
11.2.1
17 Jul 2026Reading the note…
11.2.0
6 Jul 2026Reading the note…
11.1.1
28 Jun 2026Reading the note…
11.1.0
23 Apr 2026Reading the note…
11.0.1
9 Apr 2026Reading the note…
11.0.0
7 Jan 2026Reading the note…
- 10.x
10.11.0
28 Nov 2025Reading the note…
10.10.3
12 Nov 2025Reading the note…
10.10.2
11 Nov 2025Reading the note…
10.10.1
4 Nov 2025Reading the note…
10.10.0
30 Oct 2025Reading the note…
10.9.1
21 Jul 2025Reading the note…
10.9.0
17 Jul 2025Reading the note…
10.8.6
13 Mar 2025Reading the note…
10.8.5
13 Mar 2025Reading the note…
10.8.4
3 Mar 2025Reading the note…
10.8.3
25 Feb 2025Reading the note…
10.8.2
21 Feb 2025Reading the note…
10.8.1
10 Feb 2025Reading the note…
10.8.0
10 Feb 2025Reading the note…
10.7.2
6 Jan 2025Reading the note…
10.7.1
2 Jan 2025Reading the note…
10.7.0
24 Dec 2024Reading the note…
10.6.4
14 Dec 2024Reading the note…
10.6.3
13 Dec 2024Reading the note…
10.6.2
4 Dec 2024Reading the note…
10.6.1
27 Nov 2024Reading the note…
10.6.0
22 Nov 2024Reading the note…
10.5.6
13 Nov 2024Reading the note…
10.5.5
15 Oct 2024Reading the note…
10.5.4
16 Aug 2024Reading the note…
10.5.3
14 Aug 2024Reading the note…
10.5.2
12 Aug 2024Reading the note…
10.5.1
12 Aug 2024Reading the note…
10.5.0
12 Aug 2024Reading the note…
10.4.0
11 Aug 2024Reading the note…