Production client state

A Tacenta client is a device identity with live encrypted sessions. Its exported state is private key material, not a cache: persist it from the first signed-in session and treat its protection as part of the integration.

The rule to start with

Keep the newest exported state after sign-in and after every send or receive. On the next launch, restore that state for the same user and device. Restoring an older copy can rewind session state; the sealed paths on Swift and Kotlin are designed to refuse a rollback when the app supplies a secure store.

const currentState = await client.exportState();
await appPrivateStore.save(userId, currentState);

// On the next launch, restore the same device identity.
const restoredState = await appPrivateStore.load(userId);
const restoredClient = await tenant.signInWithState(user, password, restoredState);

TypeScript spelling shown. Use the equivalent state methods in Swift, Kotlin or Rust; the language guides name each one.

Choose storage for the platform

TypeScript
The browser head has no sealed-state or secure-store hook yet. IndexedDB is neither encrypted nor private from scripts running on the same origin. Protect the bytes under an app-controlled key, keep third-party scripts out of the page and use a strict content-security policy. The TypeScript README explains the browser trust boundary.
Swift
Use the sealed state methods with a SecureStore backed by the Keychain. Keep the wrapping key and rollback counter separate from the exported blob, choose a device-only accessibility class and decide your backup and migration policy. The Swift guide includes a starting implementation.
Kotlin
Use the sealed state methods with a Keystore-backed SecureStore. The wrapping key and monotonic counter must not be stored beside the state blob, and backup must not restore an older counter. The Android guide covers the Keystore and backup considerations.
Rust
Rust also exposes the sealed state path through a SecureStore. Supply it from the host's secret store, keep its wrapping key and counter separate from the exported blob and retain only the latest successful checkpoint.

Receive without competing with yourself

Run one receive loop per client. A message is delivered to whichever receive() or inbound() call is waiting, so two concurrent consumers make delivery ownership unclear in the application. A pending receive does not block another send on the same client.

for await (const message of client.inbound()) {
  await saveLatestState(client);
  await handleMessage(message);
}

Handle failures by kind

Every SDK exposes a stable error kind and a human-readable detail. Branch on the kind, keep the detail for a log line, and leave unknown future kinds to a safe fallback. Do not delete persisted state after a state error: it may be altered, stale or protected by a store that is temporarily unavailable. The SDK surface lists the shared error kinds and their meaning.

Before you ship

Continue

This guide covers the state an application owns. The SDK pages show the exact spelling in each language, and the Assurance page describes the evidence behind the protocol and product claims.