# Where packages live

`packages/` holds only packages you installed. Code your app's authors
wrote lives where the rest of their code lives, whatever kind it is:

```text
app.jadpo
domains/
    shipping/libraries/...           the app's helpers for one domain
shared/
    libraries/...                    the app's helpers for several domains
    providers/
        acme_couriers/v1/            the app's own integration, in the package format
packages/                            installed only: in jadpo.lock, read-only
    stripe/v2024_06_20/
    postcodes/v2/
jadpo.lock
```

- **Installed packages are committed** under `packages/<name>/<version>/`.
  Agents read them with the tools they already use, reviewers see an
  upgrade as an ordinary diff (its surface diff included), and CI needs no
  fetch step. A build never fetches anything.
- **Installed packages are read-only.** The compiler refuses one whose
  files don't match its digest in `jadpo.lock`. A digest is a fingerprint
  of the files, so any change to them shows.
- **Your app's own integrations live in
  `shared/providers/<name>/<version>/`**, in exactly the package format.
  They can have everything an installed provider can: types, failures,
  pure functions, decoding, recordings, fakes, `provide` mappings, actions,
  subscribers and services. Who may call one is still decided by the
  connection's `domains:` list.
- **A `use` line shows where a name comes from.** `use packages/postcodes`
  is always installed code, and `use shared/providers/acme_couriers` is
  the app's own. The only differences between the two are where the code
  sits, whether you can edit it and whether the publishing bar applies. So
  replacing your own integration with an official package later changes
  `jadpo.lock`, the folder and the `use` lines, and not the code that
  calls it.
- **Publishing moves code out of the app.** A package other apps depend on
  gets its own repository and versions. Every app installs it into
  `packages/`, the one it started in included.

## Two versions side by side

Two versions of one package can be held at once: a provider during an
upgrade, a candidate version while the upgrade plan compiles the app
against it, or two library versions while callers move across. Each is
its own package in its own folder, both installed or both the app's own.
While two are held, every name written through either carries its
version, such as `Postcodes.v3.UkPostcode`. One `use` line brings in both,
because it names the package's folder.

Here the app's own `Postcodes` is held at `v2` and `v3` while callers move
across:

```jadpo
/// Reading UK postcodes.
public library uk {
    /// Reads a UK postcode as it is written, spaces around it left out.
    function standard_form(postcode_text: WrittenPostcode) fails InvalidPostcode -> UkPostcode {
        return attempt UkPostcode(text.upper(text.trim(postcode_text))) {
            invalid: InvalidPostcode
        }
    }
}
```

```jadpo
use shared/providers/postcodes

/// Reads a customer's postcode, as callers did before the upgrade.
action read_postcode(
    written: Postcodes.v2.WrittenPostcode
) fails Postcodes.v2.InvalidPostcode -> Postcodes.v2.UkPostcode {
    return attempt Postcodes.v2.uk.standard_form(written)
}
```

```jadpo
use shared/providers/postcodes

/// Reads a customer's postcode with the next version.
action read_typed_postcode(
    written: Postcodes.v3.WrittenPostcode
) fails Postcodes.v3.InvalidPostcode -> Postcodes.v3.UkPostcode {
    return attempt Postcodes.v3.uk.standard_form(written)
}
```

A name without its version while two are held is
`package.version_needed`. Once the old version goes, a name that still
carries the version is `package.version_unneeded`, whose suggested edit
drops it. Both are listed under "Package errors".

While two versions of a library package that carries translations are
held, the app words each under a key that carries the version,
`postcodes_v3: { }`, as its names do
([Jadpo's and packages' text](/docs/failures-for-client-apps.md#jadpos-and-packages-text)).

## Names

- **Some provider brand names are reserved.** `Stripe`, `Twilio` and `GitHub`
  are kept for official packages, none of which exists yet. An app's own
  integration can't take one (`package.reserved_name`), so `Stripe` in code
  can only ever mean the official package. Name yours something else, such as
  `StripeApi.v1`.
- **Two packages never share a name in code.** Installing a registry package
  whose name one of the app's own integrations or libraries already uses
  stops and asks for the app's own to be renamed first (by hand, since
  `jadpo rename` isn't built yet).
- **A package's name can't clash with any other name.** Domain, library
  and standard-library names are unique among themselves, and a package's
  name joins them. Installing a package refuses one whose name the app
  already uses for a domain, a library or any declaration.
- **Registry names are scoped by publisher**: a package's identity in the
  registry is `@publisher/name`, such as `@acme/postcodes`, and Jadpo's
  official packages are `@jadpo/…`. In code a package keeps its own name
  and version label (`Postcodes.v2`), so two publishers' packages with one
  code name can't be installed in the same app. `jadpo package add` takes
  the scoped name, and the lock's `registry` source records it
  ([The registry protocol](/docs/the-public-registry.md#the-registry-protocol)).
- A package is named in UpperCamelCase with its own version label, such
  as `Stripe.v2024_06_20` or `Postcodes.v2`. Its folder is the name in
  lower_snake_case with the version below it.
