feat: add graphile-realtime-subscriptions plugin (Phase 3a)#1103
Merged
pyramation merged 2 commits intomainfrom May 10, 2026
Merged
feat: add graphile-realtime-subscriptions plugin (Phase 3a)#1103pyramation merged 2 commits intomainfrom
pyramation merged 2 commits intomainfrom
Conversation
PostGraphile v5 plugin that discovers tables with @realtime smart tag and generates per-table GraphQL subscription fields (onXxxChanged). - Discovers subscriber tables via pgRegistry @realtime tag - Generates onXxxChanged subscription fields with optional id argument - Creates XxxSubscriptionPayload types with event + row fields - Uses pgSubscriber.listen() on per-table NOTIFY channels - Enforces RLS via resource.get() on authenticated connection - Includes preset wrapper for convenient plugin inclusion - 20 unit tests covering discovery, types, plans, and preset
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new PostGraphile v5 plugin package (
graphile-realtime-subscriptions) that discovers tables tagged with@realtimeviapgRegistryand generates per-table GraphQL subscription fields.For each
@realtime-tagged table (e.g.projects), the plugin generates:onProjectsChanged(id: UUID): ProjectsSubscriptionPayloadsubscription fieldProjectsSubscriptionPayloadtype withevent: String!(INSERT/UPDATE/DELETE) andprojects: Projects(re-queried row)The plugin uses
pgSubscriber.listen()on per-table NOTIFY channels (realtime:{schema}.{table}) and enforces RLS by re-querying throughresource.get()on the authenticated connection.This depends on the per-table NOTIFY trigger added in constructive-db#1090.
Package contents
src/plugin.ts— table discovery via@realtimetag, type definition generation, Grafast plan generationsrc/preset.ts— convenience preset wrappersrc/types.ts— options interface (empty for Phase 3a, reserved for 3b+)__tests__/plugin.test.ts— 18 unit tests covering discovery, type generation, plan wiring, NOTIFY channel naming__tests__/preset.test.ts— 2 unit tests for preset structureReview & Testing Checklist for Human
(grafastContext() as any).get('pgSubscriber')is the correct Grafast v5 API — this uses a type cast to escape the context type system. Confirm this is how other plugins (or Graphile's own code) accesspgSubscriberat plan time, or whether there's a typed accessor. If there's a proper API, theas anycast should be replaced.subscribePlan/plan/ payload resolver pattern matches Graphile v5 subscription conventions — the current pattern useslisten()→object()insubscribePlan, passes through inplan, then re-queries in the payload type resolver. Confirm this is idiomatic for extendSchema-based subscriptions.id, ALL table events still wake the subscription; filtering happens only at the re-query layer (resource.get({ id })). This is intentional for Phase 3a simplicity but means unnecessary wake-ups. Confirm this is acceptable.as GraphileConfig.Presetcast in preset.ts — the preset uses a type assertion, suggesting the return shape may not fully match the Preset type. Verify this won't cause issues when composed with other presets.Suggested test plan: Add the plugin to a PostGraphile preset in a local dev environment, run introspection to confirm
onXxxChangedfields appear on@realtime-tagged tables, then test a subscription with a real INSERT/UPDATE/DELETE to verify the NOTIFY → re-query → payload flow works end-to-end.Notes
pnpm-lock.yamldiff is large but is entirely formatting changes (pnpm version whitespace normalization), not dependency changes.pnpm buildpasses cleanly across the full workspace with this plugin included.Link to Devin session: https://app.devin.ai/sessions/19485cf5cc58416a9f86068563d512f5
Requested by: @pyramation