# Connecting in `app.jadpo`

A connection is how your app reaches a database, a mail server or a
provider's API. You declare each one once, in `connections:` in
`app.jadpo`. Each entry is either a built-in driver (`driver: Driver.x`)
or a package (`package: X.vN`), with the typed settings that driver or
package declares. A connection to a package also names the domains whose
actions may call it, the credential from `config.jadpo`, and which of the
package's hosts to use.

```jadpo
// app.jadpo
application {
    connections: {
        main: {
            driver: Driver.postgres
            url: config.database_url
        }
        stripe: {
            package: Stripe.v2024_06_20
            domains: [payments]
            credential: config.stripe_secret_key
            environment: config.stripe_environment
            webhooks: {
                secret: config.stripe_webhook_secret
            }
            erasure: {
                key: User.stripe_customer_id
            }
            development: {
                sandbox: [payment_intents.retrieve, customers]
            }
        }
        couriers: {
            package: AcmeCouriers.v1
            domains: [shipping]
            credential: config.couriers_api_key
            environment: config.couriers_environment
            timeout: 5s
        }
        rates: {
            package: ExchangeRates.v1
            domains: [finance]
            credential: config.rates_key
            polls: {
                latest: 6h
            }
        }
        pdfs: {
            package: Gotenberg.v8
            domains: [billing]
            outbound: ["fonts.googleapis.com"]
        }
    }
}
```

- **`domains:`** lists the domains whose actions may call the connection.
  No other domain can.
- **`environment:`** is a `ProviderEnvironment` setting, `.sandbox` or
  `.live`, which picks between the package's hosts. Calls are HTTPS only,
  and redirects and proxies are always refused.
- **The credential** is a `secret: true` setting
  ([Configuration and time](configuration-and-time.md)). The package
  says how it is sent, and code can never read it. For a provider that
  acts for each user, the credential is an `OAuthGrant` instead.
- **`host:`** gives the address of a package with no fixed host: another
  Jadpo app, a self-hosted product, or a service already running
  elsewhere.
- **`timeout:` and `retry:`** override the default time limit and retries.
  `max_concurrent:` may lower the package's limit on calls at once.
- **`webhooks:`** gives the webhook secret and, for webhooks that need a
  reply, `replies:` (see "Receiving from outside", further down this page).
- **`polls:`** changes a poll's interval, **`outbound:`** grants a service
  the hosts its package asks for, **`erasure:`** names the field holding
  the person's key at this provider, and **`development:`** lists what
  reaches the sandbox in `jadpo dev`. Each has its own section below.
- **A package's own `settings:`** are given by name, such as
  `message_stream: "outbound"`.

Two versions of one package are two connections, used side by side while
callers move across. A library package needs no connection: any domain
brings it in with a `use` line.

Two connections: one to the app's own integration with fixed live and
sandbox hosts, and one to an integration with no fixed host, reached at
the address a setting gives and taking a setting of its own. The
`package:` line names the package by its name and version, as the lock
does, with no `use` line.

```jadpo
application {
    connections: {
        couriers: {
            package: AcmeCouriers.v1
            domains: [shipping]
            credential: config.couriers_api_key
            environment: config.couriers_environment
            timeout: 5s
        }
        ledger: {
            package: Ledger.v1
            domains: [billing]
            credential: config.ledger_token
            host: config.ledger_address
            account: "shop"
        }
    }
}
```

```jadpo
config {
    couriers_api_key: Text {
        secret: true
    }
    couriers_environment: ProviderEnvironment
    ledger_address: Url
    ledger_token: Text {
        secret: true
    }
}
```

```jadpo
/// The ledger's API, at the address each deployment gives.
provider {
    protocol: Protocol.json_http
    credential: CredentialScheme.bearer
    settings: {
        account: Text
    }
}
```

A package declares its own settings in `provider.jadpo`'s `settings:`, each
a plain value (`Text`, `Int`, `Decimal`, `Bool` or `Duration`), and every
connection to it gives each one by name, written out or read from a
setting of that type (`account: config.ledger_account`).

A connection's name shares one namespace with the app's domains and
libraries, so `billing.<name>` always means one thing. A connection named
like a domain or a library is an error, reported at the connection,
because that is the name you can change in `app.jadpo` without moving any
code:

```jadpo
application {
    connections: {
        billing: {
            driver: Driver.postgres
            url: config.database_url
        }
    }
}
```

```text
error: Connection `billing` is named like domain `billing`
 --> app.jadpo:3:9
  |
3 |         billing: {
  |         ^^^^^^^ already a domain
  reason: Connections share one namespace with domains and libraries, so `billing.<name>` means one thing; it is already the domain `billing`.
  next: Rename the connection, such as `billing_api`, and the calls through it (agent)
  rule: semantic.duplicate_declaration
  help: https://jadpo.dev/docs/errors/semantic.duplicate_declaration

check failed: 1 error, 4 files
```

## The network report

The network report lists every host your app can reach, so a reviewer
sees a new one before it ships. `jadpo check` writes it to
`build/report/network.md`, with a `.json` twin, once the connections
read cleanly. Each row gives a host, the connection that reaches it, when
(a package's environment setting picks its live or sandbox host), what
for (a package, or a driver's capability) and the domains that use it.

The report is built for small diffs, as
[the permissions report](the-permissions-report.md) is. Rows are
in order of connection and host, each host is shown as written, and there
are no times or totals. So a new connection or a changed host is a
one-line change in review. For the app above:

| Connection | Host | When | For | Domains |
|---|---|---|---|---|
| `couriers` | `https://api.acme-couriers.example` | `config.couriers_environment` is `live` | `AcmeCouriers.v1` | `shipping` |
| `couriers` | `https://sandbox.acme-couriers.example` | `config.couriers_environment` is `sandbox` | `AcmeCouriers.v1` | `shipping` |
| `ledger` | the address in `config.ledger_address` | always | `Ledger.v1` | `billing` |

A database or cache connection is listed at the address in its `url:`
setting, for the domains whose entities it stores. A database's `For`
says `without TLS` when its connection says `tls: false`, and names the
setting its server's certificate is checked against when it names an
`authority:` ([PostgreSQL over TLS](stores.md#postgresql-over-tls)). A
store of files on the disk driver reaches no host and isn't listed. A
package Jadpo runs (`runs:`) is listed as the service it runs from its
image.

Not built yet: the hosts a service run by Jadpo asks for aren't in the
report until services are built.
