The @karnak19/pbkit-realtime package provides a plugin that generates typed realtime subscription helpers using PocketBase’s built-in SSE system.
Install
Section titled “Install”The plugin runs at generation time, so it is a dev dependency. pocketbase is
the runtime peer (already required by the generated client).
bun add -d @karnak19/pbkit-realtimeAdd the plugin to your pbkit.config.ts:
import { realtimePlugin } from "@karnak19/pbkit-realtime"
export default { input: "https://my-pb.example.com", output: "./src/generated", plugins: [realtimePlugin],}After running bunx pbkit generate, a realtime.gen.ts file is created alongside types.gen.ts, client.gen.ts, and sdk.gen.ts.
Generated output
Section titled “Generated output”The plugin generates shared types and one subscribeTo{Collection}() function per non-excluded collection:
Shared types
Section titled “Shared types”export type RealtimeAction = "create" | "update" | "delete"
export interface RealtimeEvent<T> { action: RealtimeAction record: T}Subscription functions
Section titled “Subscription functions”export function subscribeToArticles( callback: (event: RealtimeEvent<ArticlesRecord>) => void, options?: { filter?: string; id?: string },): Promise<() => Promise<void>>Each function:
- Accepts a typed callback receiving
RealtimeEvent<{Collection}Record> - Accepts optional
filter(PocketBase filter string) andid(subscribe to a specific record) - Returns
Promise<() => Promise<void>>— resolves with an async unsubscribe callback (PocketBase’sUnsubscribeFunc);awaitit to surface unsubscribe errors
Usage example
Section titled “Usage example”Subscribe to all changes
Section titled “Subscribe to all changes”import { subscribeToArticles } from "./generated/realtime.gen"
const unsub = await subscribeToArticles((event) => { if (event.action === "create") { console.log("New article:", event.record.title) } if (event.action === "update") { console.log("Updated article:", event.record.id) } if (event.action === "delete") { console.log("Deleted article:", event.record.id) }})
// Later, when you no longer need the subscriptionawait unsub()Subscribe with a filter
Section titled “Subscribe with a filter”const unsub = await subscribeToArticles( (event) => { console.log("Published article changed:", event.record.title) }, { filter: 'status = "published"' },)Subscribe to a specific record
Section titled “Subscribe to a specific record”const unsub = await subscribeToArticles( (event) => { console.log("Article updated:", event.record.title) }, { id: "RECORD_ID" },)React component example
Section titled “React component example”import { subscribeToComments } from "./generated/realtime.gen"import { useEffect, useState } from "react"
function LiveComments({ articleId }: { articleId: string }) { const [comments, setComments] = useState([])
useEffect(() => { let unsub: (() => Promise<void>) | undefined
subscribeToComments( (event) => { if (event.action === "create") { setComments((prev) => [...prev, event.record]) } }, { filter: `article = "${articleId}"` }, ).then((fn) => { unsub = fn })
return () => { unsub?.() } }, [articleId])
return ( <ul> {comments.map((c) => ( <li key={c.id}>{c.content}</li> ))} </ul> )}Avoid interpolating untrusted input directly into filter strings. Prefer constructing filters server-side or validating IDs before inserting them.
Collection filtering
Section titled “Collection filtering”The plugin respects the collections config — excluded collections won’t generate subscription functions:
export default { collections: { logs: { exclude: true }, }, plugins: [realtimePlugin],}Framework-agnostic
Section titled “Framework-agnostic”The generated helpers use the PocketBase client directly via client.collection(name).subscribe(). No framework-specific imports — works with React, Vue, Svelte, Solid, or any JavaScript environment.
Combining with other plugins
Section titled “Combining with other plugins”All plugins can be used together:
import { tanstack } from "@karnak19/pbkit-tanstack"import { zodPlugin } from "@karnak19/pbkit-zod"import { realtimePlugin } from "@karnak19/pbkit-realtime"
export default { input: "https://my-pb.example.com", output: "./src/generated", plugins: [tanstack({ framework: "react" }), zodPlugin, realtimePlugin],}