Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 5 Nov 2026. What's built · Install 0.3.0
jadpo
ReferenceEvents

Background workEvents

Subscribers

On this page

A subscriber reacts to an event: each time the event is committed, it runs an action. It names one event in on: and the action to run in run:. Inside run:, event is the event delivered. This one keeps a note of each TodoCompleted from Declaring an event:

domains/planning/subscribers/update_statistics.jadpo:

example
use planning/actions { note_todo }use planning/events { TodoCompleted }/// Counts each completed todo.subscriber update_statistics {    on: TodoCompleted    run: note_todo(event)}

domains/planning/actions/note_todo.jadpo:

example
use planning/entities { TodoNotFound, TodoNote }use planning/events { TodoCompleted }/// Keeps a note of a completed todo.action note_todo(completed: TodoCompleted) fails TodoNotFound -> TodoNote {    return attempt TodoNote.create {        set: {            todo_id: completed.todo_id            completed_at: completed.completed_at        }    }}

domains/planning/entities/todo_note.jadpo:

example
use planning/entities { Todo }/// A note that a todo was completed, kept for statistics.entity TodoNote {    id: Uuid    todo_id: Todo.id {        on_delete: OnDelete.cascade    }    completed_at: Instant    policy: {        create: [Access.system]        read: [Access.system]    }}

A subscriber has no person behind it, so TodoNote and the Todo it refers to let Access.system in.

What a subscriber holds

A subscriber holds three things, and nothing else (subscriber.item_invalid):

  • on:, the event type. Another domain's event must be public and imported.
  • run:, a call of an action in the subscriber's own domain (subscriber.run_invalid). Its arguments are event or fields read through it, such as event.todo_id (subscriber.argument_invalid), and they are type-checked against the action's parameters.
  • retry:, optionally (Retries and giving up).

One event each

A subscriber listens for one event. To react to two events, write two subscribers.

Each subscriber on its own

Every subscriber of an event gets its own delivery. One failing doesn't affect the others. Nothing that happens in a subscriber reaches the action that emitted the event, which has already committed and returned. A subscriber's action may emit further events.

Runs as the system

A subscriber runs as the system (Access.system, Policy and background work), not as the user who caused the event. If it needs to know who, put a field such as by: User.id in the event. What its action could reach whose list doesn't name Access.system is policy.system_grant_missing, so a write it could never make fails at jadpo check, not as a failed delivery.

The system may write a FieldAccess.server_only field, as any other, where the record's own list names Access.system: the field keeps out requests, and the system is none.

What a subscriber stores from its event

Jadpo checks that a subscriber doesn't store a value from its event where people who may not read the value could see it.

What an event carries is everything any emit of it put there, apart from what a request sent. Along a chain of events, it also includes what a subscriber's action emits from the event it was given. That is because each action's emits, and those of the actions it calls, count as part of what it passes to its callers.

What the subscriber's action stores from what it is passed is checked where the subscriber passes it, as a call is (Policy), and refused with policy.output_field_unproved at the argument. What decided an emit, and any reject in its action, go with every field of the event.

A value from an event has left its record

The record a value came from may change or move between the emit and the delivery. So a value an event carries is checked as though it came from any record of its entity. Of the field's readers, only "anyone signed in" and roles held across the whole app carry over.

The one link kept is the tenant. When the event's tenant field came from the same record as a value, that record was the tenant's, and the subscriber is limited to that tenant. So the value may be stored wherever that tenant's roles may read it.

A subscriber that needs more passes the event's ids and reads the current state, as Declaring an event advises.

Markdown for agents: /docs/subscribers.md.Built from Jadpo main at aee2e8f.