events
Per-app pub/sub with history. For what events are for (and how the change feed ties services together), see the Event Store.
import { events } from "@lodekit/sdk";emit() and list() work in the browser and in server functions. watch()
is client-only — it throws when called on the server.
events.emit()
Section titled “events.emit()”emit(type: string, payload?: Record<string, unknown>, opts?: { ttl?: number }): Promise<LodekitEvent>type— the event type. Must match/^[a-z0-9-]+$/, max 128 characters.payload— an optional JSON object, max 8 KB.opts.ttl— time to live in seconds, up to 30 days.
Publishes an event and resolves to the stored LodekitEvent. The event’s app,
kind, and component are stamped by the engine (kind: "app", app = component = your app id) — an app cannot forge events as another sender or
emit into another app’s stream.
Example
Section titled “Example”const ev = await events.emit("export-finished", { slug: stat.slug, plantCount: allPlants.length,});// ev.id, ev.ts; ev.app === ev.component === your app idevents.watch()
Section titled “events.watch()”watch(filter: { type?: string | string[] }, cb: (event: LodekitEvent) => void): () => voidfilter.type— a type, or an array of types. Omit it to receive every event.cb— called with each matching event as it arrives.
Subscribes to live events and returns an unsubscribe function. Client-only:
there is no EventSource on the server, so calling watch() in a server
function throws. All watchers on a page share one EventSource connection —
it opens with the first watcher and closes with the last unsubscribe.
Example
Section titled “Example”Greenhouse refreshes its conservatory whenever its data changes:
useEffect( () => events.watch({ type: ["db-store-change", "kv-store-change"] }, () => void router.invalidate()), [router]);Filtering on the payload happens in your callback:
events.watch({ type: "file-store-change" }, (ev) => { const slug = (ev.payload as { slug?: string } | undefined)?.slug; if (slug?.startsWith(`photo-${id}-`)) refresh();});events.list()
Section titled “events.list()”list(opts?: { type?: string; after?: number; before?: number; limit?: number;}): Promise<{ records: LodekitEvent[]; next: number | null }>opts.type— only events of this type.opts.after— only events with an id greater than this.opts.before— only events with an id less than this.opts.limit— page size.
Reads event history. Every event carries a monotonically increasing id that
doubles as the replay offset: pass the returned next back as after to
resume where you left off; null means you’re caught up.
Example
Section titled “Example”let after: number | undefined;do { const page = await events.list({ type: "export-finished", after }); for (const ev of page.records) { // ev.payload } after = page.next ?? undefined;} while (after !== undefined);Platform event types
Section titled “Platform event types”The platform emits events into your app’s namespace as things change — these are the types worth watching:
| Type | Emitted when |
|---|---|
build-state |
Your app’s build starts, succeeds, or fails |
server-state |
Your app’s worker starts, stops, or crashes |
kv-store-change |
A kv entry is written, deleted, or expires |
db-store-change |
A database write lands |
file-store-change |
A file is put, deleted, or expires |
tasks-change |
A task run is queued or changes state |
settings-change |
The person changes a setting in the dashboard |
secrets-change |
A secret slot is linked or unlinked |
Change-feed payloads carry identity only — keys, slugs, ops — never values. On a change event, re-read the data you care about through its handle.
LodekitEvent
Section titled “LodekitEvent”interface LodekitEvent<T extends Record<string, unknown> = Record<string, unknown>> { id: number; ts: number; ns: string; source: string; type: string; payload: T | null;}id— monotonic row id; the replay offset forlist().ts— ms-epoch timestamp.ns— the namespace the event lives in (your app id).source— who emitted it: your app id, or the platform for the types above.type— the event type.payload— the payload object, ornullif none was given.