<!--
Sitemap:
- [Tempo Accounts SDK - Getting Started](/docs/): Set up the Tempo Accounts SDK to create, manage, and interact with accounts on Tempo.
- [Deploying to Production](/docs/production): Things to consider before deploying your application with the Tempo Accounts SDK to production.
- [FAQ](/docs/faq): Frequently asked questions about the Tempo Accounts SDK.
- [Connect Accounts](/docs/guides/connect-accounts): Connect a Tempo account in your application.
- [Authentication](/docs/guides/authentication): Authenticate connected accounts against your own server with a signed SIWE challenge.
- [Identity](/docs/guides/identity): Request and verify identity claims about a connected account, starting with a verified email.
- [Transfers](/docs/guides/transfers): Send stablecoin transfers from a connected Tempo account, initiated either by the user or by your server.
- [Spend Permissions](/docs/guides/spend-permissions): Authorize spend limits, call scopes, and expiries so repeat transfers can be signed without a confirmation prompt.
- [React Native](/docs/guides/react-native): Set up Tempo Accounts in a React Native app.
- [Subscriptions](/docs/guides/subscriptions): Charge recurring payments from a connected Tempo account.
- [Fee Sponsorship](/docs/guides/fee-sponsorship): Sponsor transaction fees from a server-controlled policy.
- [Deposits](/docs/guides/deposits): Open the Tempo deposit flow from a connected account and let the user choose deposit details.
- [Swaps](/docs/guides/swaps): Open the Tempo swap flow from a connected account with optional pre-filled intent fields.
- [Theming](/docs/guides/theming): Match embedded account surfaces to your product.
- [CLI](/docs/guides/cli): Authorize and use Tempo accounts from command-line tools.
- [Adapters](/docs/adapters/): Choose the signing adapter for your Tempo Accounts SDK integration.
- [Tempo Wallet Adapter](/docs/adapters/tempo-wallet): Use Tempo Wallet as the hosted universal wallet adapter.
- [WebAuthn Adapter](/docs/adapters/webauthn): Use domain-bound passkeys as the account signing adapter.
- [Turnkey Adapter](/docs/adapters/turnkey): Use Turnkey-managed wallet accounts as the account signing adapter.
- [Privy Adapter](/docs/adapters/privy): Use Privy embedded wallets as the account signing adapter.
- [Private Key Adapter](/docs/adapters/private-key): Sign in-process with a `secp256k1` private key.
- [Custom Adapter](/docs/adapters/custom): Author your own adapter with the `Adapter.define` API.
- [Adapters](/docs/api/adapters): Pluggable adapters for the Tempo Accounts SDK Provider.
- [dialog](/docs/api/dialog): Adapter for the Tempo Wallet dialog, an embedded iframe or popup for account management.
- [local](/docs/api/local): Key-agnostic adapter for defining arbitrary account types and signing mechanisms.
- [mobileWebAuth](/docs/api/mobileWebAuth): Mobile web auth adapter for browser-session wallet requests.
- [postMessage](/docs/api/postMessage): Connect to wallet from anywhere on the web
- [privy](/docs/api/privy): React adapter backed by Privy sessions and embedded Ethereum wallets.
- [secp256k1](/docs/api/secp256k1): Adapter that signs in-process with a `secp256k1` private key.
- [turnkey](/docs/api/turnkey): Adapter backed by Turnkey client sessions.
- [webAuthn](/docs/api/webAuthn): Adapter for passkey-based accounts using WebAuthn registration and authentication.
- [Dialog](/docs/api/dialogs): Dialog modes for embedding the Tempo Wallet.
- [Dialog.iframe](/docs/api/dialog.iframe): Embed the Tempo Wallet auth UI in an iframe dialog element.
- [Dialog.popup](/docs/api/dialog.popup): Open the Tempo Wallet auth UI in a popup window.
- [Expiry](/docs/api/expiry): Utility functions for computing access key expiry timestamps.
- [Provider](/docs/api/provider): Create an EIP-1193 provider for managing accounts on Tempo.
- [Rpc](/docs/api/rpc): Per-method Zod schemas and shared building blocks for the Accounts JSON-RPC surface.
- [Schema](/docs/api/schema): Zod-based JSON-RPC schema definitions for the Accounts provider.
- [TrustedHosts](/docs/api/trustedHosts): Trusted host mappings and matching helpers for dialog adapters.
- [WebAuthnCeremony](/docs/api/webauthnceremony): Pluggable strategy for WebAuthn registration and authentication ceremonies.
- [WebAuthnCeremony.from](/docs/api/webauthnceremony.from): Create a WebAuthnCeremony from a custom implementation.
- [WebAuthnCeremony.server](/docs/api/webauthnceremony.server): Server-backed WebAuthn ceremony that delegates to a remote handler.
- [CLI](/docs/cli/provider): Create a Provider for CLI environments.
- [eth_accounts](/docs/rpc/eth_accounts): Get the addresses of the currently connected accounts.
- [eth_chainId](/docs/rpc/eth_chainId): Get the chain ID of the currently active chain.
- [eth_fillTransaction](/docs/rpc/eth_fillTransaction): Fills missing transaction fields and returns wallet-aware metadata.
- [eth_requestAccounts](/docs/rpc/eth_requestAccounts): Request access to user accounts, prompting the user to connect if needed.
- [eth_sendTransaction](/docs/rpc/eth_sendTransaction): Send a transaction from the connected account.
- [eth_sendTransactionSync](/docs/rpc/eth_sendTransactionSync): Send a transaction and wait for the receipt.
- [eth_signTransaction](/docs/rpc/eth_signTransaction): Sign a transaction without broadcasting it.
- [eth_signTypedData_v4](/docs/rpc/eth_signTypedData_v4): Sign EIP-712 typed structured data with the connected account.
- [personal_sign](/docs/rpc/personal_sign): Sign a message with the connected account.
- [wallet_authorizeAccessKey](/docs/rpc/wallet_authorizeAccessKey): Authorize an access key for delegated transaction signing.
- [wallet_connect](/docs/rpc/wallet_connect): Connect account(s) with optional capabilities like access key authorization.
- [wallet_deposit](/docs/rpc/wallet_deposit): Open the wallet deposit flow with optional pre-filled fields.
- [wallet_depositZone](/docs/rpc/wallet_depositZone): Open the wallet zone-deposit flow with optional pre-filled fields.
- [wallet_disconnect](/docs/rpc/wallet_disconnect): Disconnect the connected account(s).
- [wallet_getBalances](/docs/rpc/wallet_getBalances): Get token balances for an account.
- [wallet_getCallsStatus](/docs/rpc/wallet_getCallsStatus): Get the status of a batch of calls sent via wallet_sendCalls.
- [wallet_getCapabilities](/docs/rpc/wallet_getCapabilities): Get account capabilities for specified chains.
- [wallet_revokeAccessKey](/docs/rpc/wallet_revokeAccessKey): Revoke a previously authorized access key.
- [wallet_send](/docs/rpc/wallet_send): Open the wallet send-token flow with optional pre-filled fields.
- [wallet_sendCalls](/docs/rpc/wallet_sendCalls): Send a batch of calls from the connected account.
- [wallet_swap](/docs/rpc/wallet_swap): Open the wallet swap flow with optional pre-filled swap intent fields.
- [wallet_switchEthereumChain](/docs/rpc/wallet_switchEthereumChain): Switch the provider's active chain.
- [wallet_withdrawZone](/docs/rpc/wallet_withdrawZone): Open the wallet zone-withdraw flow with optional pre-filled fields.
- [Remote](/docs/api/remote): Bridge that runs inside the wallet's iframe/popup and serves RPC requests from the host SDK.
- [Remote.create](/docs/api/remote.create): Create a remote context bound to a Messenger and Provider.
- [Remote.useEnsureVisibility](/docs/api/remote.useEnsureVisibility): React hook that monitors iframe visibility and falls back to a popup when occluded.
- [Remote.useState](/docs/api/remote.useState): React hook to subscribe to a remote context's state store.
- [Remote.useTheme](/docs/api/remote.useTheme): React hook that applies theme overrides from URL search params and live messenger updates.
- [Remote.validateSearch](/docs/api/remote.validateSearch): Validate an RPC request payload from URL search params.
- [Tempo Accounts Server Handlers](/docs/server/): Configure server-side Tempo Accounts SDK handlers for relaying wallet RPC requests, composing backends, and managing WebAuthn ceremonies.
- [Handler.auth](/docs/server/handler.auth): Server handler that issues SIWE-based authentication challenges and sessions.
- [Handler.codeAuth](/docs/server/handler.codeAuth): Server handler for the device-code (PKCE) access-key bootstrap flow.
- [Handler.compose](/docs/server/handler.compose): Compose multiple server handlers into a single handler.
- [Handler.exchange](/docs/server/handler.exchange): Server handler that returns Stablecoin DEX quotes and ready-to-submit calls.
- [Handler.relay](/docs/server/handler.relay): Server handler that proxies certain RPC requests with wallet-aware enrichment.
- [Handler.webAuthn](/docs/server/handler.webAuthn): Server-side WebAuthn ceremony handler for registration and authentication.
- [hc](/docs/server/hc): Typed RPC client for handlers built with the Tempo Accounts SDK.
- [Identity.verify](/docs/server/identity.verify): Verify a wallet-issued identity token (verified email) against an issuer's JWKS.
- [Kv](/docs/server/kv): Key-value store adapters for server-side persistence.
- [Kv.cloudflare](/docs/server/kv.cloudflare): Kv adapter backed by a Cloudflare Workers KV namespace.
- [Kv.durableObject](/docs/server/kv.durableObject): Kv adapter backed by a Cloudflare Durable Object with atomic take and create.
- [Kv.from](/docs/server/kv.from): Wrap a custom Kv-shaped object so the SDK accepts it as a Kv.
- [Kv.memory](/docs/server/kv.memory): In-memory Kv adapter for tests and single-process deployments.
- [Keystore](/docs/api/keystore): Pluggable backends for key material.
- [Keystore.p256](/docs/api/keystore.p256): Pure-JS P-256 keystore.
- [Keystore.secp256k1](/docs/api/keystore.secp256k1): Pure-JS secp256k1 keystore.
- [Keystore.webCryptoP256](/docs/api/keystore.webCryptoP256): WebCrypto P-256 keystore.
- [Storage](/docs/api/storage): Pluggable storage adapters for persisting provider state.
- [Storage.combine](/docs/api/storage.combine): Combine multiple Storage adapters into one.
- [Storage.cookie](/docs/api/storage.cookie): Cookie-backed Storage adapter.
- [Storage.from](/docs/api/storage.from): Create a Storage adapter from a custom implementation.
- [Storage.idb](/docs/api/storage.idb): IndexedDB-backed Storage adapter.
- [Storage.localStorage](/docs/api/storage.localStorage): localStorage-backed Storage adapter.
- [Storage.memory](/docs/api/storage.memory): In-memory Storage adapter.
- [asyncStorage](/docs/api/storage.asyncStorage): React Native Storage adapter backed by AsyncStorage.
- [secureMmkv](/docs/api/storage.secureMmkv): Encrypted React Native Storage adapter backed by MMKV.
- [Tempo Accounts SDK](/index): The fastest way to add stablecoins to your application.
- [Secp256k1 Adapter](/docs/adapters/secp256k1): Sign in-process with a `secp256k1` private key.
- [Bring Your Auth](/docs/enterprise/bring-your-auth/): Connect enterprise auth and signing systems to Tempo accounts.
- [Hosted Universal Wallets](/docs/enterprise/hosted-universal-wallets): Stub for hosting a universal wallet on your own domain.
- [Handler.feePayer (Deprecated)](/docs/server/handler.feePayer): Deprecated — use Handler.relay with feePayer option instead.
- [tempoWallet](/docs/wagmi/tempoWallet): Wagmi connector for the Tempo Wallet dialog.
- [webAuthn](/docs/wagmi/webAuthn): Wagmi connector for passkey-based WebAuthn accounts.
- [AWS KMS](/docs/enterprise/bring-your-auth/aws-kms): Stub for integrating AWS KMS-backed signing with the Tempo Accounts SDK.
- [Custom Auth](/docs/enterprise/bring-your-auth/custom): Stub for first-party enterprise auth and signing integrations.
- [Privy](/docs/enterprise/bring-your-auth/privy): Enterprise notes for integrating Privy-backed auth with the Tempo Accounts SDK.
- [Turnkey](/docs/enterprise/bring-your-auth/turnkey): Stub for integrating Turnkey-backed signing with the Tempo Accounts SDK.
-->

# `Kv`

Minimal key-value store interface used by the SDK's server primitives (e.g. SIWE nonce store, WebAuthn session store, CLI device-code store).

Values are JSON-serialized when stored. TTLs are optional; consumers that need expiry pass `{ ttl }` (in seconds) to `set` and the implementation lazily evicts (memory) or relies on the backing store's native expiry (Cloudflare KV).

## Usage

```ts
import { Kv } from 'accounts/server'

// In-memory (for development/testing).
const kv = Kv.memory()

// Cloudflare Workers KV (eventually consistent — no atomic `take` or `create`).
const kv = Kv.cloudflare(env.MY_KV_NAMESPACE)

// Cloudflare Durable Object (linearizable — atomic `take` and `create` available).
const kv = Kv.durableObject(env.NONCE_DO)
```

## Adapters

### Kv.memory(options?)

Creates an in-memory key-value store backed by a `Map`. Lazily evicts expired entries on read/write. Useful for development and testing, and for single-process deployments.

```ts
const kv = Kv.memory()
const kv = Kv.memory({ now: () => fakeClock.now })
```

#### memory.Options

```ts
type memory.Options = {
  /** Clock function for TTL accounting. Defaults to `Date.now`. */
  now?: (() => number) | undefined
}
```

### Kv.cloudflare(namespace)

Creates a key-value store backed by a Cloudflare Workers KV namespace (or compatible binding). Uses the underlying store's native `expirationTtl` for TTL — Cloudflare KV's minimum TTL is 60 seconds, enforced by the platform independent of what's passed here.

**Not safe for one-time-consume or unique-key semantics.** Cloudflare KV is eventually consistent across data centers — concurrent read+delete races can let the same key be "consumed" twice, and concurrent create-if-absent checks can race. The optional [`take`](#take-key-optional) and [`create`](#create-key-value-options-optional) methods are intentionally NOT implemented. Use [`Kv.durableObject`](#kv-durableobject-namespace-options) (or another linearizable backend) when strict atomicity is required.

* **namespace** — Cloudflare KV namespace binding.

### Kv.durableObject(namespace, options?)

Adapts a Cloudflare Durable Object namespace into a `Kv` with atomic [`take`](#take-key-optional) and [`create`](#create-key-value-options-optional). Unlike `Kv.cloudflare`, a Durable Object's storage is single-actor and linearizable — `take` (read+delete) and `create` (create-if-absent) are guaranteed atomic across concurrent callers, which makes this the recommended backend for SIWE challenge nonce storage on Cloudflare Workers.

Pair with [`NonceStorage`](#noncestorage) (or your own DO class implementing the same fetch protocol).

```ts
// wrangler.jsonc
// {
//   "durable_objects": {
//     "bindings": [{ "name": "NONCE_DO", "class_name": "NonceStorage" }]
//   },
//   "migrations": [{ "tag": "v1", "new_classes": ["NonceStorage"] }]
// }

// worker.ts
import { Handler, Kv, NonceStorage } from 'accounts/server'
export { NonceStorage }

export default {
  fetch(req, env) {
    const handler = Handler.auth({
      store: Kv.durableObject(env.NONCE_DO),
      origin: 'https://app.example.com',
    })
    return handler.fetch(req)
  },
}
```

#### durableObject.Namespace

Minimal shape of a Cloudflare Durable Object namespace binding. Compatible with `DurableObjectNamespace` from `@cloudflare/workers-types`.

```ts
type durableObject.Namespace = {
  idFromName: (name: string) => unknown
  get: (id: unknown) => { fetch: (input: string, init?: unknown) => Promise<Response> }
}
```

#### durableObject.Options

```ts
type durableObject.Options = {
  /**
   * Durable Object instance name. Defaults to `'default'` (a single
   * shared actor). Use a per-tenant name if you need isolation.
   */
  name?: string | undefined
}
```

### Kv.from(kv)

Wraps an existing `Kv`-shaped object so the SDK accepts it as a `Kv`. Useful when adapting a custom backend.

```ts
const kv = Kv.from({
  async get(key) { /* ... */ },
  async set(key, value, options) { /* ... */ },
  async delete(key) { /* ... */ },
  async take(key) { /* ... */ }, // optional
})
```

## NonceStorage

Reference Durable Object class implementing the [`Kv.durableObject`](#kv-durableobject-namespace-options) fetch protocol. Export from your Worker entry and bind it under `class_name: "NonceStorage"` in `wrangler.jsonc`.

The class is framework-agnostic — it doesn't import `cloudflare:workers` so it works with both the legacy DO API (`fetch(req)` only) and the newer `extends DurableObject` API.

```ts
import { NonceStorage } from 'accounts/server'

export { NonceStorage }
```

### NonceStorage.State

Subset of `DurableObjectState` actually used by `NonceStorage`.

```ts
type NonceStorage.State = {
  storage: {
    get: <T = unknown>(key: string) => Promise<T | undefined>
    put: (key: string, value: unknown) => Promise<void>
    delete: (key: string) => Promise<void>
  }
}
```

### NonceStorage.Entry

Internal storage shape: value plus optional absolute expiry timestamp (ms).

```ts
type NonceStorage.Entry = { value: unknown; expiresAt?: number }
```

## Interface

```ts
type Kv = {
  /** Read a value by key. Returns `undefined` when missing or expired. */
  get: <value = unknown>(key: string) => Promise<value | undefined>
  /** Write a value. When `ttl` is set, the entry expires after the given duration in seconds. */
  set: (key: string, value: unknown, options?: set.Options) => Promise<void>
  /** Delete a value by key. */
  delete: (key: string) => Promise<void>
  /**
   * Atomic create-if-absent. Optional — see below.
   */
  create?: (key: string, value: unknown, options?: set.Options) => Promise<boolean>
  /**
   * Atomic read-and-delete. Optional — see below.
   */
  take?: <value = unknown>(key: string) => Promise<value | undefined>
}

type set.Options = {
  /** Time-to-live in seconds. After this duration, `get` returns `undefined`. */
  ttl?: number | undefined
}
```

### `create(key, value, options?)` (optional)

Atomic create-if-absent. Returns `true` when the value was written, or `false` when a non-expired value already exists.

Backends with a linearizable create primitive should implement this so consumers can reject duplicates atomically. Consumers may fall back to `get` then `set` when strict atomicity is not required.

| Adapter            | `create` implemented?                                                        |
| ------------------ | ---------------------------------------------------------------------------- |
| `Kv.memory`        | ✅ atomic in-process                                                         |
| `Kv.durableObject` | ✅ linearizable                                                              |
| `Kv.cloudflare`    | ❌ (eventually consistent — see [`Kv.cloudflare`](#kv-cloudflare-namespace)) |

### `take(key)` (optional)

Atomic read-and-delete. Returns the value if present, `undefined` if missing or expired. Across concurrent callers, exactly one observer receives a non-`undefined` return for a given key, and the key is removed exactly once.

Required for one-time-consume semantics (e.g. SIWE challenge nonces). Backends without a linearizable read+delete primitive (e.g. eventually-consistent stores like Cloudflare KV) should leave this undefined; the consuming handler will refuse to accept the store at construction time and fall back to a different backend (e.g. a Durable Object).

| Adapter            | `take` implemented?                                                          |
| ------------------ | ---------------------------------------------------------------------------- |
| `Kv.memory`        | ✅ atomic in-process                                                         |
| `Kv.durableObject` | ✅ linearizable                                                              |
| `Kv.cloudflare`    | ❌ (eventually consistent — see [`Kv.cloudflare`](#kv-cloudflare-namespace)) |
