NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #3292 most downloaded on npm
A set of utils for faster development of GraphQL tools
Last release 28 days ago
08 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 59 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
3654 releases · first in 2020
One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
When a selection set for a computed field needs to be merged, resolve that required selection set fully then resolve the computed field. In the follow
#6469
0e87805
Thanks @User!! - Handle merged selection sets in the computed fields;
When a selection set for a computed field needs to be merged, resolve that required selection set
fully then resolve the computed field. In the following case, the selection set for the author
field in the Post type is merged with the selection set for the authorId field in the
Comment type.
type Query {
feed: [Post!]!
}
type Post {
id: ID! @computed(selectionSet: "{ comments { authorId } }")
}
type Comment {
id: ID!
authorId: ID!
}
type User {
id: ID!
name: String!
}
type Post {
id: ID!
comments: [Comment!]!
}
type Comment {
id: ID!
}
Nothing published for this version
Nothing published for this version
In the following test case, totalOrdersPrices needs userOrders which needs lastName from initial Query.user. So the bug was skipping the dependencies
#6437
3188051
Thanks @User, @(),
@{, @{, @{,
@{, @{! - Fix the bug happens when a merged field
is a computed field requires another computed field requires a field from the initial subschema.
In the following test case, totalOrdersPrices needs userOrders which needs lastName from
initial Query.user. So the bug was skipping the dependencies of userOrders because it assumed
lastName already there by mistake.
const schema1 = makeExecutableSchema({
typeDefs: /* GraphQL */ `
type User {
id: ID!
firstName: String!
lastName: String!
address: String
}
type Query {
}
`,
resolvers: {
Query: {
=> {
return {
id: 1,
firstName: 'Jake',
lastName: 'Dawkins',
address: 'everywhere',
};
},
},
},
});
const schema2 = makeExecutableSchema({
typeDefs: /* GraphQL */ `
type UserOrder {
id: ID!
}
type User {
id: ID!
totalOrdersPrices: Int
aggregatedOrdersByStatus: Int
}
type Query {
userWithOrderDetails(userId: ID!, userOrderIds: [ID]): User
}
`,
resolvers: {
Query: {
userWithOrderDetails: (_root, { userId, userOrderIds }) => {
return {
id: userId,
userOrders: userOrderIds?.map((userOrderId: string) => ({ id: userOrderId })),
};
},
},
totalOrdersPrices(user) {
if (user.userOrders instanceof Error) {
return user.userOrders;
}
if (!user.userOrders) {
throw new Error('UserOrders is required');
}
return 0;
},
aggregatedOrdersByStatus(user) {
if (user.userOrders instanceof Error) {
return user.userOrders;
}
if (!user.userOrders) {
throw new Error('UserOrders is required');
}
return 1;
},
},
},
});
const schema3 = makeExecutableSchema({
typeDefs: /* GraphQL */ `
type User {
id: ID!
userOrders: [UserOrder!]
}
type UserOrder {
id: ID!
}
type Query {
userWithOrders(id: ID!, lastName: String): User
}
`,
resolvers: {
Query: {
userWithOrders: (_root, { id, lastName }) => {
return {
id,
lastName,
};
},
},
userOrders(user) {
if (!user.lastName) {
throw new Error('LastName is required');
}
return [
{
id: `${user.lastName}1`,
},
];
},
},
},
});
const stitchedSchema = stitchSchemas({
subschemas: [
{
schema: schema1,
},
{
schema: schema2,
merge: {
selectionSet: '{ id }',
fieldName: 'userWithOrderDetails',
args: ({ id, userOrders }: { id: string; userOrders: any[] }) => ({
userId: id,
userOrderIds: userOrders?.map?.(({ id }: { id: string }) => id),
}),
fields: {
totalOrdersPrices: {
selectionSet: '{ userOrders { id } }',
computed: true,
},
aggregatedOrdersByStatus: {
selectionSet: '{ userOrders { id } }',
computed: true,
},
},
},
},
},
{
schema: schema3,
merge: {
selectionSet: '{ id }',
fieldName: 'userWithOrders',
args: ({ id, lastName }: { id: string; lastName: string }) => ({
id,
lastName,
}),
fields: {
userOrders: {
selectionSet: '{ lastName }',
computed: true,
},
},
},
},
},
],
});
const res = await normalizedExecutor({
schema: stitchedSchema,
document: parse(/* GraphQL */ `
query User {
user {
aggregatedOrdersByStatus
totalOrdersPrices
}
}
`),
});
expect(res).toEqual({
data: {
aggregatedOrdersByStatus: 1,
totalOrdersPrices: 0,
},
},
});
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Added dependency `@repeaterjs/repeater@^3.0.6` ↗︎ (to dependencies)
#6420
a867bbc
Thanks @ardatan! - dependencies updates:
@repeaterjs/repeater@^3.0.6 ↗︎
(to dependencies)#6420
a867bbc
Thanks @ardatan! - Pass operation directives correctly to the
subschema;
query {
hello @someDir
}
#6418
da93c08
Thanks @ardatan! - Fix extra inline fragments for all abstract types
in the upstream schema call
If there are two subschemas like below, the final Node interface is implemented by both Oven
and Toaster while they are not implemented in both schemas. In this case the query
{ products { id ... on Node { id } } } will need to be transformed to
{ products { id ... on Oven { id } ... on Node { id } } } for the first subschema. But
previously the query planner was automatically creating inline fragments for all possible types
which was not optimal. Now it adds inline fragments only if this case is seen.
type Query {
products: [Product]
}
union Product = Oven | Toaster
interface Node {
id: ID!
}
type Oven {
id: ID!
}
type Toaster implements Node {
id: ID!
warranty: Int
}
And another one like below;
interface Node {
id: ID!
}
type Oven implements Node {
id: ID!
warranty: Int
}
Updated dependencies
[a867bbc]:
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
### Patch Changes - #6403 `3803897` Thanks @ardatan! - Cleanup extra fields, empty inline fragments and duplicate \_\_typename fields
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
`33e8146` Thanks @ardatan! - Fail on query planning phase if the query plan is not successful before the actual execution
Nothing published for this version
Nothing published for this version
`d54b21a` Thanks @ardatan! - If an abstract type on the gateway resolves to a type that does not exist on the gateway, return null instead of showing
d54b21a
Thanks @ardatan! - If an abstract type on the gateway resolves to a
type that does not exist on the gateway, return null instead of showing an error to the user
d54b21a
Thanks @ardatan! - If an enum value coming from the subschema is not
available on gateway, do not show an error to the user but return null instead
Nothing published for this version
Nothing published for this version
Instead of transforming the AggregateError itself to a GraphQL located error.
#6356
8094c37
Thanks @enisdenjo! - AggregateError errors are GraphQL located
errors
Instead of transforming the AggregateError itself to a GraphQL located error.
This is because of two reasons:
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
### Patch Changes - #6312 `7b6f77a` Thanks @ardatan! - Use native Promise.withResolvers when possible
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →