# How packages, connections, capabilities and services fit together

Here is an app calling one outside API, with nothing left out: it books a
collection with a courier. Acme Couriers publishes no package, so the app
describes its API itself, in `shared/providers/`. With an installed package,
`jadpo package add` brings these package files and you write only the
connection, the setting and the action.

The connection goes in `app.jadpo`. `connections:` and its keys are built
in, `couriers` is your name for it, `AcmeCouriers.v1` is the package below,
and `shipping` is the domain whose actions may call it.

`app.jadpo`:

```jadpo
application {
    connections: {
        couriers: {
            package: AcmeCouriers.v1
            domains: [shipping]
            credential: config.couriers_api_key
            environment: config.couriers_environment
        }
    }
}
```

The secret and which of the courier's hosts to use are settings.
`ProviderEnvironment` is built in, and is `.sandbox` or `.live`.

`config.jadpo`:

```jadpo
config {
    couriers_api_key: Text {
        secret: true
    }
    couriers_environment: ProviderEnvironment {
        default: ProviderEnvironment.sandbox
    }
}
```

The package names itself and says how the API is reached.

`shared/providers/acme_couriers/v1/package.jadpo`:

```jadpo
/// Acme Couriers' booking API, written from its documentation.
package AcmeCouriers.v1 {
    licence: Licence.proprietary
    jadpo: "1.0"
}
```

`licence:` is required, and `Licence.proprietary` suits a package only your
app uses. `jadpo:` is also required: it is the lowest Jadpo version the
package says it needs, a major and minor number as text. Jadpo checks only that
form and compares the number with nothing yet, so `"1.0"` passes on every
release, even one before 1.0.

`shared/providers/acme_couriers/v1/provider.jadpo`:

```jadpo
/// Acme Couriers' booking API.
provider {
    protocol: Protocol.json_http
    hosts: {
        live: "https://api.acme-couriers.example"
        sandbox: "https://sandbox.acme-couriers.example"
    }
    credential: CredentialScheme.bearer
}
```

A *resource* is a group of the API's operations. This one has one operation,
which takes a `CreateBooking` and answers with a `Booking`, two types the
package declares. `changes: true` says the call changes something at the
courier. `idempotent: true` says the call is safe to send again, here because
repeating it books one collection, so Jadpo may retry it. `source:
PackageSource.written` tells whoever reviews the package that a person wrote
this operation from the courier's documentation, rather than importing it
([Provenance and confirmation](/docs/where-packages-come-from.md#provenance-and-confirmation)).

`shared/providers/acme_couriers/v1/resources/bookings.jadpo`:

```jadpo
public resource bookings {
    create: {
        method: HttpMethod.post
        path: "/v1/bookings"
        input: CreateBooking
        output: Booking
        changes: true
        idempotent: true
        source: PackageSource.written
    }
}
```

`shared/providers/acme_couriers/v1/types/create_booking.jadpo`:

```jadpo
/// What booking a collection takes.
public type CreateBooking = Object {
    postcode: Text
}
```

`shared/providers/acme_couriers/v1/types/booking.jadpo`:

```jadpo
/// A booked collection.
public type Booking = Object {
    id: Text
}
```

The action calls the operation through the connection. `use app` brings in
the connection, and `use shared/providers/acme_couriers` brings in the
package, whose public names are written `AcmeCouriers.<name>`.

`domains/shipping/actions/book.jadpo`:

```jadpo
use app { couriers }
use shared/providers/acme_couriers

/// Books a collection with the courier, through its connection.
action book(request: AcmeCouriers.CreateBooking) -> AcmeCouriers.Booking {
    return couriers.bookings.create(request)
}
```

Run `jadpo records update` once, which writes down the hosts the app can reach,
then check the project:

```sh
jadpo check
```

```text
Not yet confirmed
  Record each with `jadpo package record`, which checks a sandbox answer
  against its types (agent)
    couriers.bookings.create

checked: 1 unconfirmed, 8 files
```

The check passes. "Not yet confirmed" means no real answer from the courier
has been checked against the types you wrote, so they are only as right as what
you read. It doesn't fail the check, and `jadpo approval` shows a person what
ships unconfirmed. To confirm the call, put a sandbox key in `.env.local` and run `jadpo package record
couriers bookings.create --input '{"postcode": "M1 1AA"}'`, which calls the
sandbox once, checks the answer and keeps it as a recording in the package
([Provenance and confirmation](/docs/where-packages-come-from.md#provenance-and-confirmation)).

A database and mail are connections too. They use a *driver* built into Jadpo,
so there is no package to write. `email:` says which connection sends the
app's email, whichever provider it is, which makes email a *capability*.

`app.jadpo`:

```jadpo
application {
    connections: {
        main: {
            driver: Driver.postgres
            url: config.database_url
        }
        mail: {
            driver: Driver.smtp
            host: config.smtp_host
            credential: {
                username: config.smtp_username
                password: config.smtp_password
            }
        }
    }
    email: {
        connection: mail
        from: config.mail_sender
    }
}
```

`config.jadpo`:

```jadpo
config {
    database_url: PostgresUrl
    mail_sender: Email
    smtp_host: Hostname
    smtp_password: Text {
        secret: true
    }
    smtp_username: Text
}
```

## What each one is

| Term | What it is | Declared in | Runs |
|---|---|---|---|
| **Package** | Jadpo source shared between apps, laid out as `shared/` is. A *library package* holds types, failures and pure functions (`Postcodes.uk.parse`); a *provider package* describes one outside API: its operations, types, failures, webhook events and how it is reached ([Kinds of package](/docs/kinds-of-package.md), [The package format](/docs/the-package-format.md)) | `packages/<name>/<version>/` when installed; the app's own in `shared/providers/` | Compiled into the app and run in its process. A package is never a process, a container or native code of its own |
| **Provider** | The outside API a provider package describes: Stripe, a courier, another Jadpo app. The package's `provider.jadpo` says how it is reached | Nowhere in the app: it is the other end of the call | Wherever its owner runs it: on the internet (`hosts:`), or at an address a setting gives (`host:` on the connection) |
| **Connection** | One named entry in `connections:` in `app.jadpo`: a built-in driver (`driver: Driver.x`) or a provider package (`package: X.vN`), with its settings, its credential and the domains whose actions may call it. One connection is one resource: a database, a store of files, one account at a provider ([Connecting in `app.jadpo`](/docs/connecting-in-app-jadpo.md)) | `app.jadpo`, its values read from `config.jadpo` settings | Opened by the runtime, inside the app |
| **Driver** | Native code in Jadpo's runtime that speaks one protocol: PostgreSQL, SMTP, the disk, Cloudflare Queues, OpenAI-compatible model servers, OpenID Connect. Redis and S3 aren't built yet. Drivers arrive only with a Jadpo release, never in a package ([No presets, no dependencies](/docs/the-package-format.md#no-presets-no-dependencies)) | `driver:` on a connection | Inside the app, talking to a server the operator runs |
| **Capability** | A job Jadpo itself does, with one API in app code whatever fills it: `database`, `email`, `files`, `ai` and the rest. One connection fills it: a driver, or a provider package whose `provides/<capability>.jadpo` maps the job onto its operations ([Capabilities](/docs/capabilities.md)) | Chosen in `app.jadpo`: `email: { connection: mail }`, `store: sheets` on a `File` field | Wherever the connection that fills it runs |
| **Built-in service** | A backend feature Jadpo provides, so the app installs nothing: feature flags, rate limits, files, email, audit, search ([Built-in services](/docs/built-in-services.md)). Email, files and search do their outside work through a capability; flags, rate limits and audit keep their state in the app's own stores | Where [Built-in services](/docs/built-in-services.md) says: `flags.jadpo`, `rate_limit:`, `type X = EmailMessage`, `File` fields | Inside the app's runtime. It is a feature, not a process or a container |

A *service run by Jadpo* is a seventh term, for a thing that isn't built yet:
[Running a service in a container](/docs/running-a-service-in-a-container.md).

## Two words that mean two things

**`runs:`** is one key with two jobs, depending on where it is written:

| Written on | It says | Looks like | Built |
|---|---|---|---|
| A deployable, in `app.jadpo` | Which background work that deployable runs ([`runs:`](/docs/declared-deployables.md#runs-the-background-work-it-runs)) | `runs: [Trigger.schedules]` | Yes |
| A provider, in a package's `provider.jadpo` | The container Jadpo starts for that provider ([Running a service in a container](/docs/running-a-service-in-a-container.md)) | `runs: { image: "…" port: 3000 }` | Not yet |

**"Service"** has two meanings too. A *built-in service*, such as feature
flags, is part of Jadpo's runtime, inside the app's process. A *service run
by Jadpo* would be a container beside it, and isn't built yet.

## How they relate

```text
the app's process: jadpo dev's interpreter, or a native or Workers deployable
│
├── domain code ── calls ──► library package             pure functions, in process
│
├── domain code ── calls ──► connection: provider package ── HTTPS ──► provider's API
│                                                    on the internet (hosts:), or at host:
│
└── built-in services: flags, rate limits, email, files, search, ...
       │ outside work goes through a capability
       └──► capability: email, files, database, ai, ...
              filled by one connection, either
              ├── a built-in driver ──────────── its protocol ──► a server the operator runs:
              │                                                  PostgreSQL, SMTP
              └── a provider package's provides/ ── HTTPS ──────► provider's API:
                                                                 Resend
```

- **Code calls a provider's operations only through a connection**, from
  an action in a domain the connection lists: `couriers.bookings.create(...)`
  ([Calling](/docs/calling.md)).
- **Code never names what fills a capability.** It writes an
  `EmailMessage` type or a `File` field, and `app.jadpo` picks the
  connection, so changing provider changes `app.jadpo` and its settings,
  never domain code.
- **One provider package can be both.** Resend's fills `email` through
  `provides/email.jadpo`, and the domains its connection lists can call its
  own operation, `emails.send`, as any provider's.
- **Packages fill capabilities and never invent them**, never bring a
  driver and never depend on another package.
- **Anything that keeps data is the operator's.** PostgreSQL and an SMTP
  server are reached through a driver at the address a setting gives; Jadpo
  never runs them. The operator may run them in Docker or anywhere else, and
  the app sees only the address.

## Where each runs

| | `jadpo dev` | `jadpo test` | Native deployable | Workers deployable |
|---|---|---|---|---|
| Library package | In process | In process | Compiled in | Compiled in |
| Provider package's calls | Faked by default, from its recordings or generated answers; operations named in `development: { sandbox: }` go to the sandbox, never live ([Provider calls in development](/docs/provider-calls-in-development.md)) | Always faked; a test scripts answers with `fakes:` ([Tests and fakes](/docs/tests-and-fakes.md)) | HTTPS to the live or sandbox host the connection's `environment:` picks, or to its `host:` | The same, through the Worker's `fetch` |
| Database, `Driver.postgres` | The address its setting gives, else a disposable PostgreSQL started from the machine's PostgreSQL tools | A copy per test on a disposable PostgreSQL, or on `JADPO_TEST_DATABASE_URL`'s server | The operator's PostgreSQL | The operator's PostgreSQL, through Hyperdrive |
| Email, by SMTP or a mail package | Caught in the dev inbox | Caught in `email.sent` | The SMTP server, or the mail package's API | The same; SMTP on port 587 only |
| Files | The disk driver, in `.jadpo/files/` | An in-memory store | The disk driver, on one server | None yet: Workers has no disk, and the S3 driver isn't built |

`jadpo check` refuses a deployable whose target can't run a connection
it reaches, naming what to use instead: on Workers the disk and SMTP on
port 25 ([Capabilities](/docs/capabilities.md), "Targets").

**An app needs no Docker or Podman** to be checked, tested, run in
`jadpo dev` or built. The disposable PostgreSQL comes from the machine's own
PostgreSQL tools, a native deployable is one binary
([A native deployable](/docs/a-native-deployable.md)) and a Workers
deployable is a Worker. Neither is an image.

## What is built of these

Of what this page describes, these aren't built yet: running a service in a
container; the Redis and S3 drivers; OAuth grants; the `cache`, `publishing`,
`documents`, `bot_check` and `scanning` capabilities; an outside engine for
`search`; the hosted registry; importers other than `openapi`; and choosing
a provider when deploying.

Of the built-in services, flags, rate limits, files, audit and search are
partly built, email is built, and documents, bot protection and the
`telemetry:` section aren't built yet. Each page's "What is built" table is
the record: this page's [What is built](/docs/external-services-built.md) and
[Built-in services'](/docs/built-in-services-built.md).
