
Security News
/Research
Popular node-ipc npm Package Infected with Credential Stealer
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.
@pothos/plugin-smart-subscriptions
Advanced tools
A Pothos plugin for turning queries into subscriptions
This plugin provides a way of turning queries into GraphQL subscriptions. Each field, Object, and Interface in a schema can define subscriptions to be registered when that field or type is used in a smart subscription.
The basic flow of a smart subscription is:
Run the query the smart subscription is based on and push the initial result of that query to the subscription
As the query is resolved, register any subscriptions defined on fields or types that where used in the query
When any of the subscriptions are triggered, re-execute the query and push the updated data to the subscription.
There are additional options which will allow only the sub-tree of a field/type that triggered a fetch to re-resolved.
This pattern makes it easy to define subscriptions without having to worry about what parts of your schema are accessible via the subscribe query, since any type or field can register a subscription.
npm install --save @pothos/plugin-smart-subscriptions
import SchemaBuilder from '@pothos/core';
import SmartSubscriptionsPlugin from '@pothos/plugin-smart-subscriptions';
const builder = new SchemaBuilder({
plugins: [SmartSubscriptionsPlugin],
smartSubscriptions: {
debounceDelay: number | null;
subscribe: (
name: string,
context: Context,
cb: (err: unknown, data?: unknown) => void,
) => Promise<void> | void;
unsubscribe: (name: string, context: Context) => Promise<void> | void;
},
});
const builder = new SchemaBuilder({
smartSubscriptions: {
...subscribeOptionsFromIterator((name, { pubsub }) => {
return pubsub.asyncIterableIterator(name);
}),
},
});
builder.queryFields((t) => ({
polls: t.field({
type: ['Poll'],
smartSubscription: true,
subscribe: (subscriptions, root, args, ctx, info) => {
subscriptions.register('poll-added')
subscriptions.register('poll-deleted')
},
resolve: (root, args, ctx, info) => {
return ctx.getThings();
},
}),
})
Adding smartSubscription: true to a query field creates a field of the same name on the
Subscriptions type. The subscribe option is optional, and shows how a field can register a
subscription.
This would be queried as:
subscription {
polls {
question
answers {
id
value
}
}
}
builder.objectType('Poll', {
subscribe: (subscriptions, poll, context) => {
subscriptions.register(`poll/${poll.id}`)
},
fields: (t) => ({
question: t.exposeString('question', {}),
answers: t.field({...}),
}),
});
This will create a new subscription for every Poll that is returned in the subscription. When the
query is updated to fetch a new set of results because a subscription event fired, the subscribe
call will be called again for each poll in the new result set.
builder.objectType('Poll', {
subscribe: (subscriptions, poll, context) => {
subscriptions.register(`poll/${poll.id}`, {
filter: (value) => true | false,
invalidateCache: (value) => context.PollCache.remove(poll.id),
refetch: (): => context.Polls.fetchByID(poll.id)!),
});
},
fields: (t) => ({
...
}),
});
Passing a filter function will filter the events, any only cause a re-fetch if it returns true.
invalidateCache is called before refetching data, to allow any cache invalidation to happen so
that when the new data is loaded, results are not stale.
refetch enables directly refetching the current object. When refetch is provided and a
subscription event fires for the current object, or any of its children, other parts of the query
that are not dependents of this object will no be refetched.
builder.objectType('Poll', {
fields: (t) => ({
question: t.exposeString('question', {}),
answers: t.field({
type: ['Answer'],
subscribe: (subscriptions, poll) => subscriptions.register(`poll-answers/${poll.id}`),
resolve: (parent, args, context, info) => {
return parent.answers;
},
}),
}),
});
builder.objectType('Poll', {
fields: (t) => ({
question: t.exposeString('question', {}),
answers: t.field({
type: ['Answer'],
canRefetch: true,
subscribe: (subscriptions, poll) =>
subscriptions.register(`poll-answers/${poll.id}`, {
filter: (value) => true | false,
invalidateCache: (value) => context.PollCache.remove(poll.id),
}),
resolve: (parent, args, context, info) => {
return parent.answers;
},
}),
}),
});
Similar to subscriptions on objects, fields can pass filter and invalidateCache functions when
registering a subscription. Rather than passing a refetch function, you can set canRefetch to
true in the field options. This will re-run the current resolve function to update it (and it's
children) without having to re-run the rest of the query.
filter and invalidateCache is typed as unknown. This should be
improved in the future.@stream queries)FAQs
A Pothos plugin for turning queries into subscriptions
The npm package @pothos/plugin-smart-subscriptions receives a total of 9,049 weekly downloads. As such, @pothos/plugin-smart-subscriptions popularity was classified as popular.
We found that @pothos/plugin-smart-subscriptions demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.

Security News
TeamPCP and BreachForums are promoting a Shai-Hulud supply chain attack contest with a $1,000 prize for the biggest package compromise.

Security News
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.