-
Notifications
You must be signed in to change notification settings - Fork 352
feat(live-query): pollingInterval
#8793
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds polling-based invalidation to the live-query plugin alongside existing mutation-based invalidation. Updates type schemas (TS, JSON, YAML GraphQL) to model a union of invalidation strategies, introduces disposal lifecycle for timers, adds a new dependency, and updates docs and generated markdown. Two changeset entries record versioning. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Plugin as LiveQuery Plugin
participant PubSub as PubSub
participant Timer as Polling Timer
participant Schema as GraphQL Schema
rect rgba(200,240,255,0.2)
note over Plugin: Initialization
Plugin->>PubSub: create pubsub
Plugin->>Timer: setInterval(pollingInterval) for each polling rule
Plugin-->>Plugin: register dispose to clear timers
end
rect rgba(220,255,220,0.2)
note over Timer,PubSub: Polling-based invalidation
Timer-->>PubSub: publish("live-query:invalidate", paths)
end
rect rgba(255,245,200,0.2)
note over Schema,PubSub: Mutation-based invalidation
Client->>Schema: execute Mutation.field
Schema-->>PubSub: publish("live-query:invalidate", paths)
end
PubSub-->>Client: notify subscribers to re-evaluate queries
rect rgba(255,220,220,0.2)
note over Plugin,Timer: Disposal / Destroy
Client->>Plugin: destroy / [dispose]()
Plugin->>Timer: clearInterval(all)
Plugin->>PubSub: unsubscribe destroy listener
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Apollo Federation Subgraph Compatibility Results
Learn more: |
🚀 Snapshot Release (
|
| Package | Version | Info |
|---|---|---|
@graphql-mesh/cache-cfw-kv |
0.105.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/cache-file |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/cache-inmemory-lru |
0.8.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/cache-localforage |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/cache-redis |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/cache-upstash-redis |
0.1.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/compose-cli |
1.4.19-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/fusion-composition |
0.8.18-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/include |
0.3.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/apollo-link |
0.106.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/cli |
0.100.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/config |
0.108.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/graphql |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/grpc |
0.108.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/json-schema |
0.109.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/mongoose |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/mysql |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/neo4j |
0.107.12-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/odata |
0.106.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/openapi |
0.109.21-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/postgraphile |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/raml |
0.109.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/soap |
0.107.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/supergraph |
0.10.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/thrift |
0.106.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/tuql |
0.105.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/http |
0.106.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/merger-bare |
0.105.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/merger-stitching |
0.105.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/migrate-config-cli |
1.6.20-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/runtime |
0.106.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/store |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-cache |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-encapsulate |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-extend |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-federation |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-filter-schema |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-hive |
0.104.16-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-hoist-field |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-naming-convention |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-prefix |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-prune |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-rate-limit |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-rename |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-replace-field |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-resolvers-composition |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-transfer-schema |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transform-type-merging |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/types |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/urql-exchange |
0.106.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/utils |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/json-schema |
0.109.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/mysql |
0.9.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/neo4j |
0.11.12-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/odata |
0.2.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/openapi |
0.109.21-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/raml |
0.109.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/soap |
0.107.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/sqlite |
0.8.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@omnigraph/thrift |
0.9.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-deduplicate-request |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-hive |
0.104.16-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-http-cache |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-http-details-extensions |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-jit |
0.2.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-live-query |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-mock |
0.105.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-newrelic |
0.104.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-operation-field-permissions |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-operation-headers |
1.4.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-rate-limit |
0.105.2-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-response-cache |
0.104.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-snapshot |
0.104.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/plugin-statsd |
0.104.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-grpc |
0.3.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-mysql |
0.9.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-neo4j |
0.10.12-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-odata |
0.2.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-rest |
0.9.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-soap |
0.10.15-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-sqlite |
0.9.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
@graphql-mesh/transport-thrift |
0.9.14-alpha-20250922151901-2100ea6ff399fc0053cc422e3cc6ab17fe79be1c |
npm ↗︎ unpkg ↗︎ |
💻 Website PreviewThe latest changes are available as preview in: https://e4847730.graphql-mesh.pages.dev |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (10)
.changeset/@graphql-mesh_plugin-live-query-8793-dependencies.md (1)
5-5: Fix markdownlint MD007 (unordered list indentation).Unindent the bullet to top level. While here, small copy edit for clarity.
--- "@graphql-mesh/plugin-live-query": patch --- -dependencies updates: - - Added dependency [`@whatwg-node/disposablestack@^0.0.6` ↗︎](https://www.npmjs.com/package/@whatwg-node/disposablestack/v/0.0.6) (to `dependencies`) +Dependency updates: +- Added dependency [`@whatwg-node/disposablestack@^0.0.6` ↗︎](https://www.npmjs.com/package/@whatwg-node/disposablestack/v/0.0.6) (to `dependencies`)packages/legacy/types/src/config-schema.json (4)
2464-2476: Update description to reflect union (mutation or polling).Current text implies only mutation-based invalidation.
Apply:
- "description": "Invalidate a query or queries when a specific operation is done without an error (Any of: LiveQueryInvalidationByMutation, LiveQueryInvalidationByPolling)" + "description": "Invalidate queries either after a mutation completes without error or on a fixed polling interval (Any of: LiveQueryInvalidationByMutation, LiveQueryInvalidationByPolling)"
2504-2516: Grammar: “affect” not “effect”.Fix description for clarity.
- "description": "Path to the operation that could effect it. In a form: Mutation.something. Note that wildcard is not supported in this field." + "description": "Path to the operation that could affect it. In a form: Mutation.something. Note that wildcard is not supported in this field."
2519-2535: Constrain and document pollingInterval; describe invalidate targets.Add units and a sane minimum to prevent accidental hot loops; clarify target format.
"LiveQueryInvalidationByPolling": { "additionalProperties": false, "type": "object", "title": "LiveQueryInvalidationByPolling", "properties": { "pollingInterval": { - "type": "integer" + "type": "integer", + "minimum": 1, + "description": "Polling interval in milliseconds (must be >= 1)." }, "invalidate": { "type": "array", "items": { "type": "string" }, - "additionalItems": false + "additionalItems": false, + "description": "Schema coordinates to invalidate on each poll (e.g. \"Query.products\")." } }, "required": ["pollingInterval", "invalidate"] },
2536-2536: Back-compat alias for renamed type.If external tooling referenced
#/definitions/LiveQueryInvalidation, keep a deprecated alias to avoid breakage.}, + "LiveQueryInvalidation": { + "description": "Deprecated alias. Use LiveQueryInvalidationByMutation.", + "allOf": [{ "$ref": "#/definitions/LiveQueryInvalidationByMutation" }] + }, "LiveQueryIndexBy": {website/src/generated-markdown/LiveQueryInvalidationByPolling.generated.md (1)
2-3: Clarify units in docs (milliseconds).Reflect schema units to reduce confusion.
-* `pollingInterval` (type: `Int`, required) +* `pollingInterval` (type: `Int`, required) — interval in milliseconds * `invalidate` (type: `Array of String`, required)Note: this file is generated—please update the JSON schema descriptions and re-generate.
website/src/generated-markdown/LiveQueryInvalidationByMutation.generated.md (1)
2-3: Grammar: “affect” not “effect”.Consistency with schema text.
-* `field` (type: `String`, required) - Path to the operation that could effect it. In a form: Mutation.something. Note that wildcard is not supported in this field. +* `field` (type: `String`, required) - Path to the operation that could affect it. In a form: Mutation.something. Note that wildcard is not supported in this field.Note: update the schema description so regenerated docs pick this up.
packages/plugins/live-query/yaml-config.graphql (2)
43-49: Doc fix: “affect”, not “effect”.Small wording tweak for clarity.
Apply:
- Path to the operation that could effect it. In a form: Mutation.something. Note that wildcard is not supported in this field. + Path to the operation that could affect it. Use the form "Mutation.something". Wildcards are not supported.
51-60: Clarify semantics and constraints for polling invalidation.Explicitly require a positive interval and pluralize the description of coordinates.
Apply:
- """ - Polling interval in milliseconds - """ + """ + Polling interval in milliseconds. Must be a positive integer (> 0). + """ ... - """ - Schema coordinate of the query to be polled - """ - invalidate: [String!]! + """ + Schema coordinates of the queries to invalidate on each interval (e.g., "Query.products"). + """ + invalidate: [String!]!Also consider stating that the list must be non-empty to avoid no-op timers.
packages/plugins/live-query/src/useInvalidateByResult.ts (1)
42-47: Unsubscribedestroylistener on dispose, not only whendestroyfires.Eliminates a latent subscription leak if consumers dispose without publishing
destroy.Apply:
- const id = pubsub.subscribe('destroy', () => { + let destroySubId: number | undefined; + destroySubId = pubsub.subscribe('destroy', () => { for (const timer of timers) { clearInterval(timer); } - pubsub.unsubscribe(id); + if (destroySubId != null) { + pubsub.unsubscribe(destroySubId); + destroySubId = undefined; + } }); ... - [DisposableSymbols.dispose]() { - for (const timer of timers) { - clearInterval(timer); - } - }, + [DisposableSymbols.dispose]() { + for (const timer of timers) { + clearInterval(timer); + } + if (destroySubId != null) { + pubsub.unsubscribe(destroySubId); + destroySubId = undefined; + } + },Also applies to: 86-90
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (11)
.changeset/@graphql-mesh_plugin-live-query-8793-dependencies.md(1 hunks).changeset/social-camels-mate.md(1 hunks)packages/legacy/types/src/config-schema.json(3 hunks)packages/legacy/types/src/config.ts(2 hunks)packages/plugins/live-query/package.json(1 hunks)packages/plugins/live-query/src/useInvalidateByResult.ts(3 hunks)packages/plugins/live-query/yaml-config.graphql(1 hunks)website/src/generated-markdown/LiveQueryIndexBy.generated.md(1 hunks)website/src/generated-markdown/LiveQueryInvalidationByMutation.generated.md(1 hunks)website/src/generated-markdown/LiveQueryInvalidationByPolling.generated.md(1 hunks)website/src/pages/docs/plugins/live-queries.mdx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/plugins/live-query/src/useInvalidateByResult.ts (4)
packages/legacy/types/src/pubsub.ts (4)
MeshPubSub(14-24)HivePubSub(6-6)toMeshPubSub(164-175)DisposableSymbols(135-137)packages/legacy/types/src/config.ts (2)
LiveQueryInvalidationByMutation(2187-2193)LiveQueryInvalidationByPolling(2194-2197)packages/cache/inmemory-lru/src/index.ts (1)
DisposableSymbols(68-74)packages/cache/redis/src/index.ts (1)
DisposableSymbols(132-134)
🪛 markdownlint-cli2 (0.18.1)
.changeset/@graphql-mesh_plugin-live-query-8793-dependencies.md
5-5: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
🔇 Additional comments (6)
.changeset/@graphql-mesh_plugin-live-query-8793-dependencies.md (1)
5-5: Sanity check the dependency range and module format.^0.0.6 effectively pins to 0.0.6 only; confirm that’s intended, and that the package’s module format (ESM/CJS) aligns with how the plugin imports it.
website/src/generated-markdown/LiveQueryIndexBy.generated.md (1)
2-3: LGTM. Clear and consistent with schema.packages/legacy/types/src/config.ts (1)
2156-2159: No action required — JSDoc already includes pollingpackages/legacy/types/src/config.ts (≈ lines 2156–2159) already documents LiveQueryInvalidationByMutation and LiveQueryInvalidationByPolling, so regeneration is not required.
Likely an incorrect or invalid review comment.
packages/plugins/live-query/yaml-config.graphql (2)
62-65: LGTM: annotateLiveQueryIndexBywith@md.Public docs visibility improvement looks good.
41-41: Config mismatch: examples useinvalidateByPollingbut schema exposesinvalidations(union).Repo search returned no matches for
invalidateByPolling/invalidations— unable to verify. Verify where polling is configured and either:
- expose
invalidateByPollingon LiveQueryConfig, or- update docs/examples to use the
invalidationsunion shape (see packages/plugins/live-query/yaml-config.graphql:41).Re-run locally: rg -n --glob '!/node_modules/' -S -e '\binvalidateByPolling\b' -e '\binvalidations\b' -e 'LiveQueryConfig' -e 'LiveQueryInvalidation'
packages/plugins/live-query/src/useInvalidateByResult.ts (1)
25-25: Nit: timer type is fine; keep it.
Set<ReturnType<typeof setInterval>>is portable across Node/DOM. No change needed.
| ```yaml | ||
| plugins: | ||
| - live-query: | ||
| invalidations: | ||
| - pollingInterval: 10000 # Polling interval in milliseconds | ||
| invalidate: | ||
| - Query.products | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align example with actual plugin key.
Use liveQuery to match config docs and schema.
plugins:
- - live-query:
+ - liveQuery:
invalidations:
- pollingInterval: 10000 # Polling interval in milliseconds
invalidate:
- Query.products📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```yaml | |
| plugins: | |
| - live-query: | |
| invalidations: | |
| - pollingInterval: 10000 # Polling interval in milliseconds | |
| invalidate: | |
| - Query.products | |
| ``` | |
| plugins: | |
| - liveQuery: | |
| invalidations: | |
| - pollingInterval: 10000 # Polling interval in milliseconds | |
| invalidate: | |
| - Query.products |
🤖 Prompt for AI Agents
In .changeset/social-camels-mate.md around lines 8 to 15, the plugin key in the
example uses "live-query" but the actual config/schema expects "liveQuery";
update the YAML example to use the correct key "liveQuery" (preserve the nested
structure and options such as invalidations, pollingInterval and invalidate
entries) so the docs match the implementation.
| "@graphql-mesh/types": "^0.104.13", | ||
| "@graphql-mesh/utils": "^0.104.13", | ||
| "@n1ru4l/in-memory-live-query-store": "^0.10.0", | ||
| "@whatwg-node/disposablestack": "^0.0.6", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify new dependency compatibility (Node 16+) and licensing.
Please confirm @whatwg-node/disposablestack@^0.0.6 fully supports Node >=16 (your engine range) and add it to any third‑party allowlist/SBOM if required.
Run:
🏁 Script executed:
#!/bin/bash
# Check engine constraints and latest version
npm view @whatwg-node/disposablestack version engines
# Inspect license
npm view @whatwg-node/disposablestack licenseLength of output: 52
Block merge — @whatwg-node/disposablestack@^0.0.6 requires Node >=18.0.0
- File: packages/plugins/live-query/package.json (line 45): "@whatwg-node/disposablestack": "^0.0.6"
- npm metadata: engines.node = '>=18.0.0'; license = MIT.
Remediation: either bump repo engines to ">=18.0.0", pin to a version that supports Node 16 (if available), or remove/replace the dependency; if accepted, add to SBOM/third‑party allowlist.
🤖 Prompt for AI Agents
packages/plugins/live-query/package.json around line 45: the dependency
"@whatwg-node/disposablestack": "^0.0.6" requires Node >=18.0.0; fix by either
(A) bump the repository engines field to ">=18.0.0" (update root and any
package-level package.json engines, adjust CI workflows to use Node 18, and run
tests), or (B) pin this dependency to a version that supports Node 16 (find the
latest compatible version, update this package.json, run install and tests), or
(C) remove or replace the dependency with a Node-16-compatible equivalent and
update code accordingly; whichever option you choose, update the
SBOM/third‑party allowlist and document the change in the PR.
| type MeshPubSub, | ||
| type YamlConfig, | ||
| } from '@graphql-mesh/types'; | ||
| import { DisposableSymbols } from '@whatwg-node/disposablestack'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import Disposable type to match DisposableSymbols usage and return type.
Avoid relying on ambient types; ensures the returned object structurally satisfies the library’s Disposable.
Apply:
-import { DisposableSymbols } from '@whatwg-node/disposablestack';
+import { DisposableSymbols, type Disposable } from '@whatwg-node/disposablestack';
...
-export function useInvalidateByResult(params: InvalidateByResultParams): Plugin & Disposable {
+export function useInvalidateByResult(params: InvalidateByResultParams): Plugin & Disposable {Also applies to: 23-23
🤖 Prompt for AI Agents
In packages/plugins/live-query/src/useInvalidateByResult.ts around lines 12 and
23, the file imports only DisposableSymbols but uses/returns a Disposable
structurally; add an explicit import for the Disposable type from
'@whatwg-node/disposablestack' and use that type annotation for the returned
object (and any local variables/parameters) so the return type matches the
library's Disposable interface rather than relying on ambient structural typing.
| export function useInvalidateByResult(params: InvalidateByResultParams): Plugin & Disposable { | ||
| const liveQueryInvalidationFactoryMap = new Map<string, ResolverDataBasedFactory<string>[]>(); | ||
| const timers = new Set<ReturnType<typeof setInterval>>(); | ||
| const pubsub = toMeshPubSub(params.pubsub); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard toMeshPubSub result (typed as possibly undefined).
Prevents a runtime crash and TypeScript error if the conversion ever yields undefined.
Apply:
- const pubsub = toMeshPubSub(params.pubsub);
+ const pubsub = toMeshPubSub(params.pubsub);
+ if (!pubsub) {
+ throw new Error('Live Query plugin requires a pubsub instance.');
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const pubsub = toMeshPubSub(params.pubsub); | |
| const pubsub = toMeshPubSub(params.pubsub); | |
| if (!pubsub) { | |
| throw new Error('Live Query plugin requires a pubsub instance.'); | |
| } |
🤖 Prompt for AI Agents
In packages/plugins/live-query/src/useInvalidateByResult.ts around line 26, the
call to toMeshPubSub(params.pubsub) returns a value typed as possibly undefined
but is used directly; add a guard to handle undefined (either throw a clear
error or return early) and update typing control flow so subsequent code treats
pubsub as non-undefined. Specifically, check if the result is falsy immediately
after the call, log or throw a descriptive error referencing params.pubsub, and
only proceed when pubsub is defined so TypeScript and runtime are safe.
| params.invalidations.forEach(liveQueryInvalidation => { | ||
| const rawInvalidationPaths = liveQueryInvalidation.invalidate; | ||
| const factories = rawInvalidationPaths.map(rawInvalidationPath => | ||
| getInterpolatedStringFactory(rawInvalidationPath), | ||
| ); | ||
| liveQueryInvalidationFactoryMap.set(liveQueryInvalidation.field, factories); | ||
| if ('pollingInterval' in liveQueryInvalidation) { | ||
| timers.add( | ||
| setInterval(() => { | ||
| pubsub.publish('live-query:invalidate', liveQueryInvalidation.invalidate); | ||
| }, liveQueryInvalidation.pollingInterval), | ||
| ); | ||
| } else if ('field' in liveQueryInvalidation) { | ||
| liveQueryInvalidationFactoryMap.set(liveQueryInvalidation.field, factories); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don’t overwrite same‑field invalidations; validate interval; avoid unnecessary factory creation.
- Current
setoverwrites earlier entries for the samefield. Merge factories instead. - Reject non‑positive
pollingIntervalto prevent hot loops. - Only build factories for field‑based rules.
Apply:
- params.invalidations.forEach(liveQueryInvalidation => {
- const rawInvalidationPaths = liveQueryInvalidation.invalidate;
- const factories = rawInvalidationPaths.map(rawInvalidationPath =>
- getInterpolatedStringFactory(rawInvalidationPath),
- );
- if ('pollingInterval' in liveQueryInvalidation) {
- timers.add(
- setInterval(() => {
- pubsub.publish('live-query:invalidate', liveQueryInvalidation.invalidate);
- }, liveQueryInvalidation.pollingInterval),
- );
- } else if ('field' in liveQueryInvalidation) {
- liveQueryInvalidationFactoryMap.set(liveQueryInvalidation.field, factories);
- }
- });
+ for (const inv of params.invalidations) {
+ if ('pollingInterval' in inv) {
+ if (inv.pollingInterval <= 0) {
+ throw new Error('pollingInterval must be a positive integer (> 0).');
+ }
+ if (inv.invalidate.length === 0) {
+ params.logger.warn('Skipping polling invalidation with empty "invalidate" list.');
+ continue;
+ }
+ timers.add(
+ setInterval(() => {
+ pubsub.publish('live-query:invalidate', inv.invalidate);
+ }, inv.pollingInterval),
+ );
+ } else if ('field' in inv) {
+ const factories = inv.invalidate.map(p => getInterpolatedStringFactory(p));
+ const existing = liveQueryInvalidationFactoryMap.get(inv.field) ?? [];
+ existing.push(...factories);
+ liveQueryInvalidationFactoryMap.set(inv.field, existing);
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| params.invalidations.forEach(liveQueryInvalidation => { | |
| const rawInvalidationPaths = liveQueryInvalidation.invalidate; | |
| const factories = rawInvalidationPaths.map(rawInvalidationPath => | |
| getInterpolatedStringFactory(rawInvalidationPath), | |
| ); | |
| liveQueryInvalidationFactoryMap.set(liveQueryInvalidation.field, factories); | |
| if ('pollingInterval' in liveQueryInvalidation) { | |
| timers.add( | |
| setInterval(() => { | |
| pubsub.publish('live-query:invalidate', liveQueryInvalidation.invalidate); | |
| }, liveQueryInvalidation.pollingInterval), | |
| ); | |
| } else if ('field' in liveQueryInvalidation) { | |
| liveQueryInvalidationFactoryMap.set(liveQueryInvalidation.field, factories); | |
| } | |
| }); | |
| for (const inv of params.invalidations) { | |
| if ('pollingInterval' in inv) { | |
| if (inv.pollingInterval <= 0) { | |
| throw new Error('pollingInterval must be a positive integer (> 0).'); | |
| } | |
| if (inv.invalidate.length === 0) { | |
| params.logger.warn('Skipping polling invalidation with empty "invalidate" list.'); | |
| continue; | |
| } | |
| timers.add( | |
| setInterval(() => { | |
| pubsub.publish('live-query:invalidate', inv.invalidate); | |
| }, inv.pollingInterval), | |
| ); | |
| } else if ('field' in inv) { | |
| const factories = inv.invalidate.map(p => getInterpolatedStringFactory(p)); | |
| const existing = liveQueryInvalidationFactoryMap.get(inv.field) ?? []; | |
| existing.push(...factories); | |
| liveQueryInvalidationFactoryMap.set(inv.field, existing); | |
| } | |
| } |
🤖 Prompt for AI Agents
In packages/plugins/live-query/src/useInvalidateByResult.ts around lines 27 to
41, the current loop always creates factories for every invalidation, overwrites
entries in liveQueryInvalidationFactoryMap when multiple rules target the same
field, and accepts non‑positive pollingInterval values; change it so that
factories are only created for field‑based rules (do not call
getInterpolatedStringFactory for polling‑type invalidations), when a rule has a
'field' merge the new factories with any existing array in
liveQueryInvalidationFactoryMap instead of replacing it, and when a rule has a
'pollingInterval' validate that pollingInterval is a positive number (reject or
throw if <= 0) before creating the timer; ensure timers.add only receives the
setInterval id and preserve existing behavior for publishing invalidation
values.
| ### Polling Based Invalidation | ||
|
|
||
| You can also invalidate queries in a polling interval by specifying the schema coordinate of the | ||
| query to be polled. | ||
|
|
||
| ```yaml filename=".meshrc.yaml" | ||
| plugins: | ||
| - live-query: | ||
| invalidations: | ||
| - pollingInterval: 10000 # Polling interval in milliseconds | ||
| invalidate: | ||
| - Query.products | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plugin key mismatch: use liveQuery (camelCase), not live-query.
All other examples and the Plugin schema use liveQuery. The current snippet will not load the plugin.
-plugins:
- - live-query:
+plugins:
+ - liveQuery:
invalidations:
- pollingInterval: 10000 # Polling interval in milliseconds
invalidate:
- Query.products🤖 Prompt for AI Agents
In website/src/pages/docs/plugins/live-queries.mdx around lines 95 to 107, the
YAML example uses the wrong plugin key "live-query"; update it to the camelCase
key "liveQuery" so it matches the plugin schema and other examples; keep the
rest of the YAML (pollingInterval and invalidate block) unchanged.
|
Hey @ardatan I think I found an issue.
Repro:
Expected outcome:
Please let me know if you need any more information from my side. |
Closes #8757
Support polling in an interval by milliseconds