Skip to content

Sources, consumers and triggers

A source is a named stream of events. It is what the owner grants and what a consumer reads. There are two ways to declare one:

  • sources in connecting, fed by one of the realm’s channels: { channel: "updates", description: "..." }. The description is required and may not be blank; the owner reads it when deciding.
  • dataPipes.sources, a stream the realm’s own handlers publish to: { stream: "events", type: "note.changed" }. At most 128; the name, stream and type are each at most 256 bytes.

A name may be declared one way or the other, never both.

A consumer is a handler that reads one source. Declare it in connecting ({ source, handler, assistant? }) or in dataPipes.consumers ({ handler }, at most 128). A dataPipes consumer’s handler is written namespace.verb, and must be a handler the realm declares: defineRealm checks it at compile time, and synth refuses one the realm does not declare, since the host refuses that consumer and every trigger bound to it. dataPipes takes only sources and consumers, and data-pipes.yml is at most 64 KiB.

The consumer is handed each event as its first argument and as ctx.frame, and the host checkpoints only after the handler succeeds. Delivery is at least once, so give every effect its own idempotency key. assistant: true asks for the separate grant that lets the consumer call ctx.assistant.chat; the owner also pairs each sender the assistant may answer (see pairing).

A consumer may read another realm’s source. The owner grants each consumer one exact source: a host channel’s source, a source from the same realm, or a source another installed realm declares. The realm does not name the other realm; the owner picks the source at approval, and the consumer receives whatever that source carries.

A trigger narrows what a consumer sees and says what it may do:

handlers: {
record: { namespace: "notes" },
index: { namespace: "notes" },
},
dataPipes: {
sources: { changes: { stream: "notes", type: "note.changed" } },
consumers: { index: { handler: "notes.index" } },
},
triggers: {
"on-change": { source: "changes", consumer: "index", mode: "observe", input: ["eventId", "payload"] },
},
  • The key is [a-z][a-z0-9-]{0,63}. source and consumer name dataPipes declarations, which synth checks.
  • input picks from offset, eventId, streamId, type, occurredAt, gap and payload, each once; left out, the consumer gets all seven. description is at most 512 characters.
  • mode: "observe" lets the handler read and refuses, for the whole invocation, every publish, every write proposal and every approved API write. mode: "apply" type-checks, and the host refuses it at bind time.
  • One trigger naming a missing source, consumer or handler stops delivery to every consumer of that installation until it is fixed, so check trigger names with care. The full behaviour is in the trigger profile.