Skip to content

Realtime events ​

realtime (default false) is the entity's realtime subtree. false disables it entirely; any object — even {} — turns it on.

  • events (optional, unset behaves like {}): a per-event opt-out. { patched: false } suppresses patched publishes; created/updated/deleted/restored still fire.
  • subscribableFields (unset by default): an allowlist a transport (for example @kavo/sse) can read and enforce on a subscription's outgoing payload. Core carries the value but does not narrow anything with it itself; that's the transport's job.
  • onPublishError (unset by default): called when a transport's publish rejects or throws. A transport failure never fails the write that produced the event. This is the only way to observe that failure, since core has no ambient logger (ADR-0005).

Publishing needs both halves: realtime set to an object on the entity (set here or via defaults), and at least one transport in realtimeTransports (see Module setup's global config). Either alone is a no-op.

A custom operation (Custom operations) publishes nothing by default. A kind: "write", cardinality: "one" custom operation can opt in by naming which of the five event ids its write counts as:

ts
operations: {
  markPaidOne: {
    kind: "write",
    handler: { execute: (input, context) => context.repository.patch(input.id, { paidAt: new Date() }) },
    realtimeEvent: "updated",
  },
}

Declaring realtimeEvent on a read, or on a cardinality: "many" operation, is a bootstrap error — a realtime event describes exactly one row.

Events are not authorized per subscriber. A published event goes to every subscriber of its channel. policy, filter.apply, and the field allowlists shape what REST returns, but they are not evaluated again for each subscriber of a realtime event. A subscription's own filter narrows which events it receives, not whether the subscriber may see them, and it never narrows a deleted event: @kavo/sse delivers every deleted event to every subscriber of the channel, since a deleted row has no current state to match against. @kavo/sse performs no authentication or authorization of its own. Gate who may open a stream in the host (a guard or proxy on the mounted route), and only enable realtime on an entity whose every row may reach every subscriber that gate admits. Use subscribableFields to keep fields off the wire.

See Realtime for the full event and channel model, and @kavo/sse's own README for the first transport implementation: collection channels, subscribe-time filtering, and subscribableFields payload narrowing.

See Settings for the rest of KavoSettings.