# Declared deployables

An app can be built into several programs, for example a Worker that
serves its public API and a server that runs its back office.
`application { deployables: { } }` in `app.jadpo` names each one, what it
serves, what it runs and what it is built for:

```jadpo
application {
    apis: {
        main: {
            prefix: /
        }
        backstage: {
            prefix: /backstage
        }
    }
    connections: {
        cache: {
            driver: Driver.redis
        }
    }
    rate_limits: {
        store: cache
    }
    deployables: {
        decline rate_limits.counted_in_memory: "One instance of `web` is enough until Redis's driver comes"
        web: {
            serves: [main]
            runs: [Trigger.subscribers]
            target: Target.wasm
        }
        back_office: {
            serves: [backstage]
            runs: [Trigger.schedules]
            target: Target.native
        }
    }
}
```

```text
$ jadpo build
  worker    build/target/web/wrangler.json
  module    build/target/web/web.wasm
  size      8.1 MB, 2.9 MB gzipped
  build     b_1c5e09d2a7f3
  serves    main
  runs      subscribers
  calls     pdf 2 at once in each instance

  binary    build/target/back_office/back_office
  build     b_e20fc10f5474
  serves    backstage
  runs      schedules

  commit    8d113e6
  settings  DATABASE_URL

✓ built  web and back_office · wasm and native in 61.3 s
→ jadpo migrate apply  they start only once their database has every migration
```

## `serves:`, the APIs it answers

`serves:` lists APIs by name: those `apis:` declares, or `main`, and
`webhooks` once a connection receives webhooks. A deployable answers only
those APIs' routes, each API's `openapi.json` among them, and a webhook
only when it serves `webhooks`. Every deployable answers its health
checks. Two deployables may serve one API.

## `runs:`, the background work it runs

`runs:` lists the background work it runs:

- `Trigger.schedules`: the app's schedules, each entity's purge, each
  poll, and a batch run picked up again;
- `Trigger.subscribers`: each delivery of an event or an email, after its
  action commits and from the outbox, and the queues `receiving:` reads.

An action it serves still writes its events to the outbox, for a
deployable that runs them. A delivery in a deployable that doesn't run
subscribers, or a batch run in one that doesn't run schedules, waits for
one that does. Every deployable's tick deletes what has expired, which
any instance may.

## `target:`, what it is built for

`target:` is `Target.native`, a server, or `Target.wasm`, WebAssembly on
Cloudflare Workers. A deployable with no `target:` has none, like the
`app` of an app that declares no deployables, and is built natively
([design notes](https://github.com/jadpo-dev/jadpo/blob/main/docs/language/notes/14-tooling.md), "A deployable's target when none is
declared").

## What each reaches

A deployable reaches everything its work can lead to. From the routes of
the APIs it serves, the webhooks' replies, the actions its schedules and
subscribers run and the batch runs it carries on, through every callable
they call, to the connections they use: a store of files, a provider's
operation, a package's action, `ai:`'s model. With them come its polls,
the webhooks it receives and the queues `receiving:` reads. Where it runs
subscribers, it also reaches `email:`'s connection, through which the
app's emails and the sign-in email are delivered, unless
`magic_link: { send: }` names an action that sends the sign-in email.

It also reaches what Jadpo runs by name: the action `on_first_sign_in:`
names, where it serves an API; the action `magic_link: { send: }` names,
and every email's templates, where it runs subscribers; and every provider
package's `decode:` and `encode:`.

## What each holds

A deployable's program holds only what it reaches: those callables, the
routes of the APIs it serves, its schedules and the subscribers' actions
only where it runs them, the connections it reaches with every database,
and the settings those read. So it reads no other setting as it starts. A
subscriber it doesn't run is still listed, so what it emits waits for the
deployable that does.

An app's wording and its stores are kept whole, and so is who signs in.
But a sign-in method's `signing_key:` is kept only where the deployable
serves an API that takes that method, and `origin:` only where it serves
one that takes browser sessions. So a Worker that only runs the
subscribers starts without either.

## Its target, checked

A deployable that declares a target is refused each connection it reaches
whose driver that target can't run, and the error names the alternative
(`deployable.target_unsupported`; [External
services](11-integrations.md)):

| Target | Refused | Use instead |
|---|---|---|
| Workers | The disk | A package over S3's API, such as Cloudflare R2 |
| Workers | A service Jadpo runs without `host:` | `host:`, with where it is hosted |
| Workers | SMTP on port 25 | Port 587 |
| Native | A Cloudflare queue, which only a Worker receives | A package over Cloudflare's HTTP pull API |
| Native | Cloudflare's rate-limiting binding as the store of its rate limits | Redis |

A deployable built for Workers that serves an API needs a store for its
rate limits, `rate_limits: { store: }` ([Rate
limits](16-built-in-services.md#rate-limits); `rate_limits.store_required`).
Until Redis's driver comes, a Redis store there would leave each instance
counting in its own memory. That is a judgement call, which a `decline`
line answers, as `web` above does (`rate_limits.counted_in_memory`).

A deployable built for Workers is refused a `client_address:` source other
than `cloudflare`, at its `source:` ([Client
addresses](10-configuration-and-time.md#client-addresses)).

A deployable built for Workers that reaches a connection with
`max_concurrent:` is listed under "On Workers" once `jadpo check` passes,
and `jadpo build` says so on the Worker's `calls` line. Workers runs as
many instances as traffic needs, and each counts the cap on its own
([External services design notes](https://github.com/jadpo-dev/jadpo/blob/main/docs/language/notes/11-integrations.md)).

## Nothing left unserved

Once `deployables:` is declared, every API with routes needs a deployable
that serves it, and the app's schedules and subscribers need one that runs
them (`deployable.unserved`). A route with `settle:` is served only where
subscribers run (`deployable.settle_unrun`).

## The build

`jadpo build` builds every deployable, and `jadpo build <deployable>` one.
Each goes into `build/target/<deployable>/` with the documents of the APIs
it serves, and its Rust into `build/rust/<deployable>/`. They are all
compiled into a cargo target in your cache folder, shared by every project
built for the same host and set of locales, so the runtime crates compile
once for them all ([design notes](https://github.com/jadpo-dev/jadpo/blob/main/docs/language/notes/14-tooling.md), "Where
deployables are compiled").

A name the app doesn't declare is `cli.build_arguments`, with the nearest.
A deployable built for `Target.wasm` is built for Workers ([A Workers
deployable](#a-workers-deployable)).

Each binary's stamp names it, and its build id is its own. The id digests
the deployable's program, so a change it doesn't reach leaves it alone
([Records and manifest](records-and-manifest.md)). `jadpo check` writes
each deployable's target and build id in the manifest, with no build id
while the project has errors. `settings` lists the variables the
deployables read, each once.
