# Subscribers

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.

`domains/planning/subscribers/update_statistics.jadpo`:

```jadpo
// domains/planning/subscribers/update_statistics.jadpo
subscriber update_statistics {
    on: TodoCompleted
    run: count_completion(event)
}
```

## 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](retries-and-giving-up.md)).

## 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`,
[Background work](background-work.md)), 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 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 `emit`s, 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](policy.md)), 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](declaring-an-event.md) advises.
