Where packages live
On this page
packages/ holds only packages you installed. Code your app's authors
wrote lives where the rest of their code lives, whatever kind it is:
app.jadpodomains/ shipping/libraries/... the app's helpers for one domainshared/ libraries/... the app's helpers for several domains providers/ acme_couriers/v1/ the app's own integration, in the package formatpackages/ 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,providemappings, actions, subscribers and services. Who may call one is still decided by the connection'sdomains:list. - A
useline shows where a name comes from.use packages/postcodesis always installed code, anduse shared/providers/acme_couriersis 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 changesjadpo.lock, the folder and theuselines, 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:
/// 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 } }}
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)}
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).
Names
- Provider brand names are reserved. Jadpo ships the list of curated
provider names, and an app's own integration cannot take one, so
Stripein code always means the official package. - 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 (
jadpo rename). - 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.
- Creating an integration checks the registry and warns when the name is taken.
- A package is named in UpperCamelCase with its own version label, such
as
Stripe.v2024_06_20orPostcodes.v2. Its folder is the name in lower_snake_case with the version below it.
Markdown for agents: /docs/where-packages-live.md.Built from Jadpo main at a707efb.