Package-level declarations
Types
Where to reach a server's account endpoints, plus the credentials to sign in with. Addresses are host:port strings. Used by the account flow (Client.signIn), which signs in and provisions this device under the account's handle (e.g. acme/alice).
A connected client: one signed-in user on one device. Every call is async. The calls take turns on the client, but a pending receive waits for mail outside that turn, so a send on the same client from another task goes through meanwhile. The Config/AccountConfig constructors below are the address layer under the `Tenant` handle, for callers that know their addresses.
Anything that can go wrong, as one case per kind an app can branch on: the same kinds as every other head (decision 0090). Swift sees an enum with a reason on each case; Kotlin a sealed exception class with one subclass per kind. A case may be added, so switch with a default.
A connected client: one signed-in user on one device. Every call is async. The calls take turns on the client, but a pending receive waits for mail outside that turn, so a send on the same client from another task goes through meanwhile. The Config/AccountConfig constructors below are the address layer under the `Tenant` handle, for callers that know their addresses.
Where to reach a Tacenta server, and who to connect as. Addresses are host:port strings. This is the pre-account path — register directly under a raw handle; for the account flow use `AccountConfig` with Client.signIn.
A client's inbound messages one at a time, from Client.inbound: each next is the next message in the order the relay delivered it, awaiting mail when nothing is buffered. It is receive flattened, on the same single-flight wait underneath. Swift iterates it as an AsyncSequence (for try await message in client.inbound()), Kotlin collects asFlow(); both are thin hand-written wrappers over next. It holds the client, so a loop over it keeps the client alive, and releasing both ends the wait. A message goes to whichever next is waiting, so run one loop per client.
A client's inbound messages one at a time, from Client.inbound: each next is the next message in the order the relay delivered it, awaiting mail when nothing is buffered. It is receive flattened, on the same single-flight wait underneath. Swift iterates it as an AsyncSequence (for try await message in client.inbound()), Kotlin collects asFlow(); both are thin hand-written wrappers over next. It holds the client, so a loop over it keeps the client alive, and releasing both ends the wait. A message goes to whichever next is waiting, so run one loop per client.
What the sign-in found (BR-15): whether the sessions a restored state carried are in use, or were discarded because the state was older than one already seen. Read it with Client.restoreOutcome after any sign-in.
Platform secure storage that holds the wrapping key for sealed state (decision 0078, anchor B). Implemented on the foreign side — iOS/macOS Keychain, Android Keystore — so the key lives where an attacker who can rewrite the state file cannot reach it. That separation is the whole of what sealing is worth: without it, an attacker who rewrites the blob rewrites the key too and the authenticator proves nothing.
Platform secure storage that holds the wrapping key for sealed state (decision 0078, anchor B). Implemented on the foreign side — iOS/macOS Keychain, Android Keystore — so the key lives where an attacker who can rewrite the state file cannot reach it. That separation is the whole of what sealing is worth: without it, an attacker who rewrites the blob rewrites the key too and the authenticator proves nothing.
One tenant's handle (decision record 0090): built from the API key and the server's name, it fetches the server's service document once to learn where the services are, and signs users up and in. Nothing above it sees a host or a port. Named Tenant on these heads (see the crate documentation); the same object is Tacenta in Rust and TypeScript.
One tenant's handle (decision record 0090): built from the API key and the server's name, it fetches the server's service document once to learn where the services are, and signs users up and in. Nothing above it sees a host or a port. Named Tenant on these heads (see the crate documentation); the same object is Tacenta in Rust and TypeScript.
Functions
Sign up a new user over TLS to a server presenting serverName, trusting the public web PKI: the address layer's TLS sibling of `sign_up`. An app uses Tenant.signUp, which finds the address itself.