@arbidocs/client 0.5.77 → 0.5.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +86 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +275 -31
- package/dist/index.d.ts +275 -31
- package/dist/index.js +86 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/memory-persistence.ts","../src/http-transport.ts","../src/session.ts","../src/crypto/sodium.ts","../src/crypto/call-keys.ts","../src/crypto/chat-keys.ts","../src/crypto/keypairs.ts","../src/crypto/identity.ts","../src/crypto/credentials.ts","../src/crypto/recovery-key.ts","../src/crypto/secure-mail.ts","../src/storage/indexed-db.ts","../src/crypto/offline-sealer.ts","../src/middleware/bearer-auth.ts","../src/session-gate.ts","../src/workspace-keys.ts","../src/workspace-opens.ts","../src/middleware/auto-relogin.ts","../src/relogin/handler.ts","../src/relogin/reopen.ts","../src/auth/session-claims.ts","../src/auth/identity.ts","../src/auth/login.ts","../src/auth/register.ts","../src/auth/change-password.ts","../src/auth/disconnect-sso.ts","../src/client.ts","../src/websocket.ts","../src/logger.ts"],"names":["adapter","bytes","sodium","serverSessionKey","stored"],"mappings":"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","file":"index.js","sourcesContent":["import type { SessionKeys, SessionPersistence } from './relogin/types'\n\nfunction copy(keys: SessionKeys): SessionKeys {\n return {\n ...keys,\n signingPrivateKey: keys.signingPrivateKey.slice(),\n ...(keys.serverSessionKey ? { serverSessionKey: keys.serverSessionKey.slice() } : {}),\n }\n}\n\n/** Per-client memory only: no browser globals, files or process-wide shared identity. */\nexport function createMemorySessionPersistence(): SessionPersistence {\n let saved: SessionKeys | null = null\n const clear = () => {\n saved?.signingPrivateKey.fill(0)\n saved?.serverSessionKey?.fill(0)\n saved = null\n }\n return {\n async getSession() {\n return saved ? copy(saved) : null\n },\n async saveSession(keys) {\n const next = copy(keys)\n clear()\n saved = next\n },\n async clearSession() {\n clear()\n },\n }\n}\n","/** HTTP plumbing only: no token, workspace selection, response-body parsing or retries. */\nexport interface HttpRequestInfo {\n readonly method: string\n /** URL without credentials, query or fragment; hooks never receive bodies or headers. */\n readonly url: string\n}\nexport interface HttpResponseInfo extends HttpRequestInfo {\n readonly status: number\n readonly durationMs: number\n}\nexport interface HttpErrorInfo extends HttpRequestInfo {\n readonly error: unknown\n readonly durationMs: number\n}\nexport interface HttpTransportOptions {\n /** Fetch-compatible implementation; defaults to globalThis.fetch at request time. */\n fetch?: typeof globalThis.fetch\n /** Time until the adapter returns a Response (native fetch: headers). Disabled by default. */\n timeoutMs?: number\n onRequest?: (request: HttpRequestInfo) => void\n onResponse?: (response: HttpResponseInfo) => void\n onError?: (failure: HttpErrorInfo) => void\n}\nexport interface HttpTransport {\n readonly fetch: typeof globalThis.fetch\n readonly customFetch: boolean\n /** Use the same timeout/hooks with a specialized adapter, such as upload-progress XHR. */\n withFetch(adapter: typeof globalThis.fetch): typeof globalThis.fetch\n}\n\nexport function createHttpTransport(options: HttpTransportOptions = {}): HttpTransport {\n const { timeoutMs } = options\n if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) {\n throw new RangeError('transport.timeoutMs must be a positive finite number.')\n }\n const wrap =\n (adapter: typeof globalThis.fetch): typeof globalThis.fetch =>\n async (input, init) => {\n const url = new URL(input instanceof Request ? input.url : String(input), 'http://localhost')\n url.username = ''\n url.password = ''\n url.search = ''\n url.hash = ''\n const info: HttpRequestInfo = {\n method: (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase(),\n url: url.toString(),\n }\n options.onRequest?.(info)\n const started = performance.now()\n let timer: ReturnType<typeof setTimeout> | undefined\n let requestInit = init\n if (timeoutMs !== undefined) {\n const controller = new AbortController()\n const own = init?.signal ?? (input instanceof Request ? input.signal : undefined)\n timer = setTimeout(\n () =>\n controller.abort(\n new DOMException('Waiting for HTTP response timed out.', 'TimeoutError')\n ),\n timeoutMs\n )\n requestInit = {\n ...init,\n signal: own ? AbortSignal.any([own, controller.signal]) : controller.signal,\n }\n }\n let response: Response\n try {\n response = await adapter(input, requestInit)\n } catch (error) {\n options.onError?.({ ...info, error, durationMs: performance.now() - started })\n throw error\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n options.onResponse?.({\n ...info,\n status: response.status,\n durationMs: performance.now() - started,\n })\n return response\n }\n const adapter: typeof globalThis.fetch =\n options.fetch ?? ((input, init) => globalThis.fetch(input, init))\n return { fetch: wrap(adapter), customFetch: options.fetch !== undefined, withFetch: wrap }\n}\n","/**\n * SessionManager: the signed-in session's state, the one source the transport, the SDK and a host's\n * UI read: the token, the user, SSO mode, the server session key and whether a login finished.\n *\n * In memory by default. A browser host passes `storage` (`browserSessionStateStorage()`) so the\n * session survives a reload. Implements TokenProvider and AuthStateProvider for the middleware and the\n * re-login, without any framework.\n */\n\nimport type { components } from './schema'\nimport type { TokenProvider } from './middleware/types'\nimport type { AuthStateProvider } from './relogin/types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** The signed-in user as the login returned it (and as profile edits keep it). */\nexport type SessionUser = components['schemas']['UserResponse']\n\nexport interface SessionState {\n accessToken: string | null\n userEmail: string | null\n userExtId: string | null\n selectedWorkspaceId: string | null\n /** The account signs in through SSO: a re-login needs the SSO provider's token. */\n isSsoMode: boolean\n /** The signed-in user; `null` signed out (and for a session seeded with an email only). */\n user: SessionUser | null\n /**\n * A login finished on this device and was not signed out. A new tab (or an offline unlock) is\n * signed in with no token yet: the next request re-logs in.\n */\n signedIn: boolean\n /** This server session's key, which workspace keys are sealed to. In memory only. */\n serverSessionKey: Uint8Array | null\n}\n\n/** What a finished login puts in the session, all at once. */\nexport interface SessionSignIn {\n /** `null` for an offline unlock: no server session yet. */\n accessToken: string | null\n user: SessionUser\n isSsoMode: boolean\n serverSessionKey: Uint8Array | null\n}\n\n/** The part of the session kept across reloads (never the server session key). */\nexport type StoredSessionState = Pick<\n SessionState,\n 'accessToken' | 'userEmail' | 'userExtId' | 'isSsoMode' | 'user' | 'signedIn'\n>\n\n/** Where a browser keeps the session across reloads. */\nexport interface SessionStateStorage {\n load(): Partial<StoredSessionState> | null\n save(state: StoredSessionState): void\n}\n\nexport interface SessionManagerOptions {\n storage?: SessionStateStorage\n}\n\nexport interface SessionManager {\n /** The current state: the same object until something in it changes. */\n getState(): Readonly<SessionState>\n setAccessToken(token: string | null): void\n setUser(email: string, extId?: string): void\n /** Change the signed-in user's fields (a profile edit, a verified tick). */\n updateUser(patch: Partial<SessionUser>): void\n setSelectedWorkspace(id: string | null): void\n setSsoMode(isSsoMode: boolean): void\n setServerSessionKey(key: Uint8Array | null): void\n /** A login finished: token, user, SSO mode and server session key in one change. */\n signIn(session: SessionSignIn): void\n /** The session is over (logout, or it could not be recovered): drop the token and the user. */\n clear(): void\n subscribe(listener: (state: SessionState) => void): () => void\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\nfunction createInitialState(isSsoMode = false): SessionState {\n return {\n accessToken: null,\n userEmail: null,\n userExtId: null,\n selectedWorkspaceId: null,\n isSsoMode,\n user: null,\n signedIn: false,\n serverSessionKey: null,\n }\n}\n\nconst stored = (s: SessionState): StoredSessionState => ({\n accessToken: s.accessToken,\n userEmail: s.userEmail,\n userExtId: s.userExtId,\n isSsoMode: s.isSsoMode,\n user: s.user,\n signedIn: s.signedIn,\n})\n\nexport function createSessionManager(options: SessionManagerOptions = {}): SessionManager {\n const { storage } = options\n let state: SessionState = { ...createInitialState(), ...(storage?.load() ?? {}) }\n const listeners = new Set<(state: SessionState) => void>()\n\n function update(patch: Partial<SessionState>) {\n state = { ...state, ...patch }\n storage?.save(stored(state))\n const snapshot = state\n for (const listener of [...listeners]) listener(snapshot)\n }\n\n return {\n getState: () => state,\n\n setAccessToken: (accessToken) => update({ accessToken }),\n\n setUser(email, extId) {\n update({\n userEmail: email,\n userExtId: extId ?? state.userExtId,\n user: state.user ? { ...state.user, email } : null,\n })\n },\n\n updateUser(patch) {\n if (!state.user) return\n const user = { ...state.user, ...patch }\n update({ user, userEmail: user.email })\n },\n\n setSelectedWorkspace: (selectedWorkspaceId) => update({ selectedWorkspaceId }),\n\n setSsoMode: (isSsoMode) => update({ isSsoMode }),\n\n setServerSessionKey: (serverSessionKey) => update({ serverSessionKey }),\n\n signIn({ accessToken, user, isSsoMode, serverSessionKey }) {\n update({\n accessToken,\n user,\n userEmail: user.email,\n userExtId: user.external_id,\n isSsoMode,\n serverSessionKey,\n signedIn: true,\n })\n },\n\n // The SSO mode outlives a sign-out: it says how this deployment (or this user) signs in.\n clear: () => update(createInitialState(state.isSsoMode)),\n\n subscribe(listener) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n }\n}\n\n/** sessionStorage key of the access token: per tab, so each tab has its own server session. */\nexport const ACCESS_TOKEN_STORAGE_KEY = 'arbi_access_token'\nconst SESSION_STORAGE_KEY = 'arbi_session'\n\n/**\n * The browser's session storage: the access token per tab (sessionStorage), the user and the\n * signed-in flag per browser (localStorage), so a new tab is signed in and re-logs in for a token\n * of its own. The keys themselves stay in the encrypted IndexedDB store (`SessionPersistence`).\n */\nexport function browserSessionStateStorage(namespace?: string): SessionStateStorage {\n // Optional isolation for widgets/extension panels that connect to different deployments.\n // Existing application storage keys and per-tab token semantics stay unchanged.\n const suffix = namespace ? `:${namespace}` : ''\n const sessionKey = SESSION_STORAGE_KEY + suffix\n const accessTokenKey = ACCESS_TOKEN_STORAGE_KEY + suffix\n return {\n load() {\n try {\n const rest = JSON.parse(window.localStorage.getItem(sessionKey) ?? 'null') as Omit<\n StoredSessionState,\n 'accessToken'\n > | null\n const accessToken = window.sessionStorage.getItem(accessTokenKey)\n return { ...(rest ?? {}), accessToken }\n } catch {\n return null\n }\n },\n save({ accessToken, ...rest }) {\n try {\n if (accessToken) window.sessionStorage.setItem(accessTokenKey, accessToken)\n else window.sessionStorage.removeItem(accessTokenKey)\n if (rest.signedIn || rest.isSsoMode)\n window.localStorage.setItem(sessionKey, JSON.stringify(rest))\n else window.localStorage.removeItem(sessionKey)\n } catch {\n // Storage unavailable (private mode, quota): the session lives in memory only.\n }\n },\n }\n}\n\n// ============================================================================\n// Provider adapters\n// ============================================================================\n\n/**\n * Create a TokenProvider from a SessionManager\n */\nexport function createTokenProvider(session: SessionManager): TokenProvider {\n return {\n getAccessToken: () => session.getState().accessToken,\n }\n}\n\n/**\n * Create an AuthStateProvider from a SessionManager\n */\nexport function createAuthStateProvider(\n session: SessionManager,\n selectedWorkspace: () => string | null = () => session.getState().selectedWorkspaceId\n): AuthStateProvider {\n return {\n getUserEmail: () => session.getState().userEmail,\n\n isSsoMode: () => session.getState().isSsoMode,\n\n getSelectedWorkspaceId: selectedWorkspace,\n\n setAccessToken: (token: string) => session.setAccessToken(token),\n }\n}\n","/**\n * Layer 1: Pure libsodium wrappers\n *\n * All low-level cryptographic operations using libsodium-wrappers-sumo.\n * No application logic — just type-safe wrappers around sodium functions.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\nexport interface KeyPair {\n publicKey: Uint8Array\n secretKey: Uint8Array\n}\n\nexport interface UserKeypairs {\n signingKeyPair: KeyPair // Ed25519 for signing/authentication\n encryptionKeyPair: KeyPair // X25519 derived from Ed25519 for encryption\n}\n\n// ============================================================================\n// libsodium initialization\n// ============================================================================\n\nlet sodiumReady: Promise<void> | null = null\n\n/**\n * Initialize sodium library\n */\nexport async function initSodium(): Promise<void> {\n if (sodiumReady) {\n await sodiumReady\n return\n }\n\n sodiumReady = sodium.ready\n await sodiumReady\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Convert base64 string to Uint8Array\n */\nexport function base64ToBytes(base64String: string): Uint8Array {\n return sodium.from_base64(base64String, sodium.base64_variants.ORIGINAL)\n}\n\n/**\n * Convert Uint8Array to base64 string\n */\nexport function bytesToBase64(bytes: Uint8Array): string {\n return sodium.to_base64(bytes, sodium.base64_variants.ORIGINAL)\n}\n\n/**\n * Unpadded base64url (RFC 4648 §5): safe in URL fragments and query strings.\n */\nexport function bytesToBase64Url(bytes: Uint8Array): string {\n return sodium.to_base64(bytes, sodium.base64_variants.URLSAFE_NO_PADDING)\n}\n\n/** Inverse of {@link bytesToBase64Url}. Throws on anything that is not unpadded base64url. */\nexport function base64UrlToBytes(encoded: string): Uint8Array {\n return sodium.from_base64(encoded, sodium.base64_variants.URLSAFE_NO_PADDING)\n}\n\n/**\n * Base64 encode a Uint8Array (for compatibility with existing code)\n */\nexport function base64Encode(bytes: Uint8Array): string {\n const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join('')\n return btoa(binString)\n}\n\n/**\n * Base64 decode to Uint8Array (for compatibility with existing code)\n */\nexport function base64Decode(base64: string): Uint8Array {\n const binString = atob(base64)\n return Uint8Array.from(binString, (m) => m.codePointAt(0) || 0)\n}\n\n// ============================================================================\n// Core Cryptographic Functions\n// ============================================================================\n\n/**\n * Deterministic salt generation for Argon2id\n */\nfunction generateSalt(username: string, deploymentDomain: string): Uint8Array {\n if (!deploymentDomain) {\n throw new Error('Deployment domain must be provided for salt generation')\n }\n const normalized = username.toLowerCase()\n const saltString = `${normalized}|${deploymentDomain}`\n // Use SHA-256 to create a deterministic salt, then take first 16 bytes\n // (Argon2id requires exactly 16 bytes for salt)\n const hash = sodium.crypto_hash_sha256(sodium.from_string(saltString))\n return hash.slice(0, 16) // Return first 16 bytes\n}\n\n/**\n * Generate Ed25519 signing keypair and derive X25519 encryption keypair\n *\n * @param username - User's email/username\n * @param password - User's password\n * @param deploymentDomain - Deployment domain for salt derivation\n * @returns Object with Ed25519 signing keypair and derived X25519 encryption keypair\n */\nexport type DerivedKeyPairs = {\n signing: { publicKey: Uint8Array; privateKey: Uint8Array; publicKeyBase64: string }\n encryption: { publicKey: Uint8Array; privateKey: Uint8Array; publicKeyBase64: string }\n}\n\n// One pre-computed derivation, consumed by the next matching generateKeyPairs().\n// Argon2id is deterministic in (username, password, domain), so it can be started\n// while the user is still on the form and be finished by the time they submit.\n// Single entry, consume-once, short TTL: the password is already held in the form\n// state, and this must not turn into a long-lived credential cache.\nconst PREWARM_TTL_MS = 60_000\nlet prewarmed: {\n id: string\n promise: Promise<DerivedKeyPairs>\n timer: ReturnType<typeof setTimeout>\n} | null = null\n\nfunction prewarmId(username: string, password: string, deploymentDomain: string): string {\n return `${username}\\u0000${deploymentDomain}\\u0000${password}`\n}\n\nfunction dropPrewarmed(): void {\n if (prewarmed) clearTimeout(prewarmed.timer)\n prewarmed = null\n}\n\n/**\n * Start deriving the keypairs for these credentials in the background (best\n * effort — failures are swallowed; the real call will just derive again).\n * A later `generateKeyPairs` with the same arguments awaits this instead of\n * paying for Argon2 again.\n */\nexport function prewarmKeyPairs(\n username: string,\n password: string,\n deploymentDomain: string\n): void {\n if (!username || !password || !deploymentDomain) return\n const id = prewarmId(username, password, deploymentDomain)\n if (prewarmed?.id === id) return\n dropPrewarmed()\n const promise = deriveKeyPairs(username, password, deploymentDomain)\n promise.catch(() => {\n if (prewarmed?.promise === promise) dropPrewarmed()\n })\n prewarmed = { id, promise, timer: setTimeout(dropPrewarmed, PREWARM_TTL_MS) }\n}\n\nexport async function generateKeyPairs(\n username: string,\n password: string,\n deploymentDomain: string\n): Promise<DerivedKeyPairs> {\n if (prewarmed && prewarmed.id === prewarmId(username, password, deploymentDomain)) {\n const { promise } = prewarmed\n dropPrewarmed() // consume once\n try {\n return await promise\n } catch {\n // fall through and derive fresh\n }\n }\n return deriveKeyPairs(username, password, deploymentDomain)\n}\n\nasync function deriveKeyPairs(\n username: string,\n password: string,\n deploymentDomain: string\n): Promise<DerivedKeyPairs> {\n await initSodium()\n\n if (!deploymentDomain) {\n throw new Error('Deployment domain not available. Cannot generate keys.')\n }\n\n // Generate deterministic salt for key derivation\n const salt = generateSalt(username, deploymentDomain)\n\n // Derive seed using Argon2id\n const seed = sodium.crypto_pwhash(\n 32, // 32 bytes for Ed25519 seed\n password,\n salt,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n )\n\n // Generate Ed25519 signing keypair from seed\n const signingKeyPair = sodium.crypto_sign_seed_keypair(seed)\n\n // Derive X25519 encryption keypair from Ed25519 keypair\n const encryptionPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(signingKeyPair.publicKey)\n const encryptionPrivateKey = sodium.crypto_sign_ed25519_sk_to_curve25519(\n signingKeyPair.privateKey\n )\n\n return {\n signing: {\n publicKey: signingKeyPair.publicKey,\n privateKey: signingKeyPair.privateKey,\n publicKeyBase64: sodium.to_base64(signingKeyPair.publicKey, sodium.base64_variants.ORIGINAL),\n },\n encryption: {\n publicKey: encryptionPublicKey,\n privateKey: encryptionPrivateKey,\n publicKeyBase64: sodium.to_base64(encryptionPublicKey, sodium.base64_variants.ORIGINAL),\n },\n }\n}\n\n/**\n * Sign a message with Ed25519 private key\n *\n * @param message - Message to sign (string)\n * @param privateKey - Ed25519 private key (64 bytes)\n * @returns Base64-encoded signature\n */\nexport function signMessage(message: string, privateKey: Uint8Array): string {\n const messageBytes = sodium.from_string(message)\n const signature = sodium.crypto_sign_detached(messageBytes, privateKey)\n return base64Encode(signature)\n}\n\n/**\n * Seal a workspace key with the session's X25519 public key (SealedBox).\n * The result is sent to the backend in the /open request body.\n */\nexport async function sealKeyForSession(\n workspaceKey: Uint8Array,\n serverSessionPublicKey: Uint8Array\n): Promise<string> {\n await initSodium()\n return sealedBoxEncrypt(workspaceKey, serverSessionPublicKey)\n}\n\n/**\n * Decrypt data using SealedBox (anonymous decryption).\n *\n * @param encryptedBase64 - Base64-encoded SealedBox encrypted data\n * @param userEncryptionPrivateKey - User's X25519 private key (32 bytes)\n * @returns Decrypted data\n */\nexport function sealedBoxDecrypt(\n encryptedBase64: string,\n userEncryptionPrivateKey: Uint8Array\n): Uint8Array {\n const encrypted = base64ToBytes(encryptedBase64)\n\n // Get the public key from private key for SealedBox\n const publicKey = sodium.crypto_scalarmult_base(userEncryptionPrivateKey)\n\n // Decrypt using SealedBox\n const decrypted = sodium.crypto_box_seal_open(encrypted, publicKey, userEncryptionPrivateKey)\n\n return decrypted\n}\n\n/**\n * Encrypt data using SealedBox (anonymous encryption).\n *\n * @param message - Data to encrypt\n * @param publicKey - Recipient's X25519 public key (32 bytes)\n * @returns Base64-encoded encrypted data\n */\nexport function sealedBoxEncrypt(message: Uint8Array, publicKey: Uint8Array): string {\n // Encrypt using SealedBox\n const encrypted = sodium.crypto_box_seal(message, publicKey)\n\n return bytesToBase64(encrypted)\n}\n\n/**\n * Derive X25519 public key from X25519 private key\n * Used for instant re-login when we have stored private key\n */\nexport function derivePublicKey(privateKey: Uint8Array): Uint8Array {\n return sodium.crypto_scalarmult_base(privateKey)\n}\n\n/**\n * Derive X25519 keypair from Ed25519 keypair\n * Used when we have stored Ed25519 keys and need X25519 for encryption\n */\nexport function deriveEncryptionKeypairFromSigning(signingKeyPair: KeyPair): KeyPair {\n const encryptionPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(signingKeyPair.publicKey)\n const encryptionPrivateKey = sodium.crypto_sign_ed25519_sk_to_curve25519(signingKeyPair.secretKey)\n return {\n publicKey: encryptionPublicKey,\n secretKey: encryptionPrivateKey,\n }\n}\n\n/**\n * The X25519 encryption keypair of a 64-byte Ed25519 signing secret key (the\n * libsodium layout: 32-byte seed ‖ 32-byte public key). The caller owns the\n * returned secret key and should zero it when done.\n */\nexport function encryptionKeypairFromSigningKey(signingPrivateKey: Uint8Array): KeyPair {\n return deriveEncryptionKeypairFromSigning({\n publicKey: signingPrivateKey.slice(32, 64),\n secretKey: signingPrivateKey,\n })\n}\n\n/**\n * Open a workspace key sealed to the user (`wrapped_key` of `/v1/user/workspaces`)\n * with the user's Ed25519 signing secret key.\n */\nexport function unwrapWorkspaceKey(wrappedKey: string, signingPrivateKey: Uint8Array): Uint8Array {\n const { secretKey } = encryptionKeypairFromSigningKey(signingPrivateKey)\n try {\n return sealedBoxDecrypt(wrappedKey, secretKey)\n } finally {\n secretKey.fill(0)\n }\n}\n\n/**\n * Generate a random Ed25519 signing keypair.\n * Used for agent accounts that don't derive keys from a password.\n */\nexport function generateRandomSigningKeypair(): KeyPair {\n const kp = sodium.crypto_sign_keypair()\n return { publicKey: kp.publicKey, secretKey: kp.privateKey }\n}\n\n// ============================================================================\n// File Encryption (SecretBox envelope for MinIO direct upload)\n// ============================================================================\n\n/**\n * SecretBox-encrypt file bytes with the workspace key.\n *\n * Returns the wire format the server stores in MinIO:\n * `nonce(24) ‖ ciphertext ‖ tag(16)` — byte-for-byte identical to what\n * PyNaCl's `SecretBox(workspace_key).encrypt(raw)` produces and what the\n * server's `decrypt_file` expects. PUT the returned bytes directly to the\n * presigned upload URL returned by `/v1/document/upload-init`.\n */\nexport function encryptFile(raw: Uint8Array, workspaceKey: Uint8Array): Uint8Array {\n const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)\n const cipher = sodium.crypto_secretbox_easy(raw, nonce, workspaceKey)\n const combined = new Uint8Array(nonce.length + cipher.length)\n combined.set(nonce, 0)\n combined.set(cipher, nonce.length)\n return combined\n}\n\n/**\n * SecretBox-decrypt a file body downloaded from MinIO.\n * Input is the same `nonce ‖ ciphertext ‖ tag` wire format that `encryptFile`\n * produces.\n */\nexport function decryptFile(ciphertext: Uint8Array, workspaceKey: Uint8Array): Uint8Array {\n const nonce = ciphertext.slice(0, sodium.crypto_secretbox_NONCEBYTES)\n const cipher = ciphertext.slice(sodium.crypto_secretbox_NONCEBYTES)\n return sodium.crypto_secretbox_open_easy(cipher, nonce, workspaceKey)\n}\n\n/**\n * Workspace-scoped content hash for client-side dedup.\n *\n * HMAC-SHA256(workspace_key, raw_bytes) truncated to 16 hex chars — byte\n * compatible with the server's `create_content_hash` helper. The client\n * sends this to `/v1/document/upload-init` so the server can dedup without\n * ever seeing plaintext.\n */\nexport function createContentHash(content: Uint8Array, workspaceKey: Uint8Array): string {\n const mac = sodium.crypto_auth_hmacsha256(content, workspaceKey)\n let hex = ''\n for (let i = 0; i < mac.length; i++) {\n hex += mac[i].toString(16).padStart(2, '0')\n }\n return hex.slice(0, 16)\n}\n\n// ============================================================================\n// E2E Message Encryption (ECDH + Symmetric)\n// ============================================================================\n\n/**\n * Precompute shared secret for ECDH encryption.\n *\n * Call once per contact, cache for efficiency.\n *\n * @param theirPublicKeyBase64 - Other party's X25519 public key (base64)\n * @param myPrivateKey - Your X25519 private key (Uint8Array)\n * @returns 32-byte shared secret (Uint8Array)\n */\nexport async function computeSharedSecret(\n theirPublicKeyBase64: string,\n myPrivateKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n const theirPublicKey = base64ToBytes(theirPublicKeyBase64)\n return sodium.crypto_box_beforenm(theirPublicKey, myPrivateKey)\n}\n\n/**\n * Encrypt a message using precomputed shared secret.\n *\n * @param message - Plaintext message to encrypt\n * @param sharedSecret - Precomputed 32-byte shared secret\n * @returns Base64-encoded ciphertext (nonce prepended)\n */\nexport async function encryptMessageWithSharedSecret(\n message: string,\n sharedSecret: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const messageBytes = sodium.from_string(message)\n const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES)\n const ciphertext = sodium.crypto_box_easy_afternm(messageBytes, nonce, sharedSecret)\n\n const combined = new Uint8Array(nonce.length + ciphertext.length)\n combined.set(nonce, 0)\n combined.set(ciphertext, nonce.length)\n\n return bytesToBase64(combined)\n}\n\n/**\n * Decrypt a message using precomputed shared secret.\n *\n * @param encryptedBase64 - Base64-encoded ciphertext (nonce prepended)\n * @param sharedSecret - Precomputed 32-byte shared secret\n * @returns Decrypted plaintext message\n */\nexport async function decryptMessageWithSharedSecret(\n encryptedBase64: string,\n sharedSecret: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const combined = base64ToBytes(encryptedBase64)\n const nonce = combined.slice(0, sodium.crypto_box_NONCEBYTES)\n const ciphertext = combined.slice(sodium.crypto_box_NONCEBYTES)\n const decrypted = sodium.crypto_box_open_easy_afternm(ciphertext, nonce, sharedSecret)\n\n return sodium.to_string(decrypted)\n}\n\n/**\n * Encrypt a message for a specific recipient using ECDH (X25519 + XSalsa20-Poly1305).\n *\n * @param message - Plaintext message to encrypt\n * @param recipientPublicKeyBase64 - Recipient's X25519 public key (base64)\n * @param senderPrivateKey - Sender's X25519 private key (Uint8Array)\n * @returns Base64-encoded ciphertext (nonce prepended)\n */\nexport async function encryptMessage(\n message: string,\n recipientPublicKeyBase64: string,\n senderPrivateKey: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const recipientPublicKey = base64ToBytes(recipientPublicKeyBase64)\n const messageBytes = sodium.from_string(message)\n\n // Generate random nonce\n const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES)\n\n // Encrypt using crypto_box (ECDH + XSalsa20-Poly1305)\n const ciphertext = sodium.crypto_box_easy(\n messageBytes,\n nonce,\n recipientPublicKey,\n senderPrivateKey\n )\n\n // Prepend nonce to ciphertext for transmission\n const combined = new Uint8Array(nonce.length + ciphertext.length)\n combined.set(nonce, 0)\n combined.set(ciphertext, nonce.length)\n\n return bytesToBase64(combined)\n}\n\n/**\n * Decrypt a message from a specific sender using ECDH (X25519 + XSalsa20-Poly1305).\n *\n * @param encryptedBase64 - Base64-encoded ciphertext (nonce prepended)\n * @param senderPublicKeyBase64 - Sender's X25519 public key (base64)\n * @param recipientPrivateKey - Recipient's X25519 private key (Uint8Array)\n * @returns Decrypted plaintext message\n * @throws Error if decryption fails (wrong keys or tampered message)\n */\nexport async function decryptMessage(\n encryptedBase64: string,\n senderPublicKeyBase64: string,\n recipientPrivateKey: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const combined = base64ToBytes(encryptedBase64)\n const senderPublicKey = base64ToBytes(senderPublicKeyBase64)\n\n // Extract nonce and ciphertext\n const nonce = combined.slice(0, sodium.crypto_box_NONCEBYTES)\n const ciphertext = combined.slice(sodium.crypto_box_NONCEBYTES)\n\n // Decrypt using crypto_box_open (ECDH + XSalsa20-Poly1305)\n const decrypted = sodium.crypto_box_open_easy(\n ciphertext,\n nonce,\n senderPublicKey,\n recipientPrivateKey\n )\n\n return sodium.to_string(decrypted)\n}\n","/**\n * Call E2EE keys (LiveKit shared-key mode).\n *\n * Every call has one random 32-byte key K, generated in the creator's\n * browser. The server and the SFU never see it:\n * - in a call link it travels in the URL fragment (`#k=<base64url K>&v=<n>`),\n * which browsers never send to the server;\n * - invited / rung ARBI users get K sealed to their X25519 public key\n * (`crypto_box_seal`), stored server-side as an opaque blob;\n * - the call title is XSalsa20-Poly1305 (secretbox) ciphertext under K.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport {\n base64ToBytes,\n base64UrlToBytes,\n bytesToBase64,\n bytesToBase64Url,\n decryptFile,\n encryptFile,\n initSodium,\n sealedBoxDecrypt,\n} from './sodium'\n\nexport const CALL_KEY_BYTES = 32\n\n/** A fresh random call key. */\nexport async function generateCallKey(): Promise<Uint8Array> {\n await initSodium()\n return sodium.randombytes_buf(CALL_KEY_BYTES)\n}\n\n/** Seal K to a user's X25519 public key (base64) → base64 blob only that user can open. */\nexport async function sealCallKey(\n key: Uint8Array,\n recipientPublicKeyBase64: string\n): Promise<string> {\n await initSodium()\n return bytesToBase64(sodium.crypto_box_seal(key, base64ToBytes(recipientPublicKeyBase64)))\n}\n\n/** Open a sealed call key with our X25519 secret key. */\nexport async function openSealedCallKey(\n sealedBase64: string,\n encryptionSecretKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n const key = sealedBoxDecrypt(sealedBase64, encryptionSecretKey)\n if (key.length !== CALL_KEY_BYTES) throw new Error('Sealed call key has the wrong length')\n return key\n}\n\n/** Encrypt a call title under K (base64 of nonce ‖ secretbox). */\nexport async function encryptCallTitle(title: string, key: Uint8Array): Promise<string> {\n await initSodium()\n return bytesToBase64(encryptFile(sodium.from_string(title), key))\n}\n\n/** Decrypt a call title; null when it does not open under K (wrong / rotated key). */\nexport async function decryptCallTitle(\n ciphertext: string,\n key: Uint8Array\n): Promise<string | null> {\n await initSodium()\n try {\n return sodium.to_string(decryptFile(base64ToBytes(ciphertext), key))\n } catch {\n return null\n }\n}\n\n/** K as unpadded base64url (fragment-safe). */\nexport function encodeCallKey(key: Uint8Array): string {\n return bytesToBase64Url(key)\n}\n\n/** Inverse of {@link encodeCallKey}; null for anything that is not a 32-byte key. */\nexport function decodeCallKey(encoded: string): Uint8Array | null {\n if (!/^[A-Za-z0-9_-]+$/.test(encoded)) return null\n try {\n const key = base64UrlToBytes(encoded)\n return key.length === CALL_KEY_BYTES ? key : null\n } catch {\n return null\n }\n}\n\n/** The link fragment (without `#`) carrying K and the link version. */\nexport function buildCallFragment(key: Uint8Array, linkVersion: number): string {\n return `k=${encodeCallKey(key)}&v=${linkVersion}`\n}\n\n/** Parse `#k=…&v=…` (leading `#` optional). Null when there is no valid key. */\nexport function parseCallFragment(\n hash: string\n): { key: Uint8Array; linkVersion: number | null } | null {\n const params = new URLSearchParams(hash.replace(/^#/, ''))\n const encoded = params.get('k')\n if (!encoded) return null\n const key = decodeCallKey(encoded)\n if (!key) return null\n const v = Number(params.get('v'))\n return { key, linkVersion: Number.isInteger(v) && v > 0 ? v : null }\n}\n\n/** `<origin>/call/<id>#k=…&v=…` — the shareable call link (the key travels in the fragment only). */\nexport function buildCallLink(\n origin: string,\n callExtId: string,\n key: Uint8Array,\n linkVersion: number\n): string {\n return `${origin}/call/${callExtId}#${buildCallFragment(key, linkVersion)}`\n}\n\n/** Someone a call key can be sealed to: their user id and X25519 public key (base64). */\nexport interface CallPeer {\n external_id: string\n encryption_public_key?: string | null\n}\n\n/**\n * K sealed to each peer that has an encryption key, by user id. Agents and keyless users are\n * skipped, and so is `exclude` (the caller, who holds K already).\n */\nexport async function sealCallKeyForPeers(\n key: Uint8Array,\n peers: readonly CallPeer[],\n exclude?: string | null\n): Promise<Record<string, string>> {\n const out: Record<string, string> = {}\n for (const peer of peers) {\n if (!peer.encryption_public_key || peer.external_id === exclude) continue\n out[peer.external_id] = await sealCallKey(key, peer.encryption_public_key)\n }\n return out\n}\n\n/**\n * My copy of a call's K from the call row (`my_sealed_key`, sealed to me as its creator or an\n * invitee); null when I have none or it does not open.\n */\nexport async function openCallKeyOf(\n call: { my_sealed_key?: string | null },\n encryptionSecretKey: Uint8Array\n): Promise<Uint8Array | null> {\n if (!call.my_sealed_key) return null\n try {\n return await openSealedCallKey(call.my_sealed_key, encryptionSecretKey)\n } catch {\n return null\n }\n}\n","/**\n * Chat keys (`/v1/chats`). Every chat message, title and attachment manifest is\n * `base64(nonce ‖ secretbox(plaintext, chat key))`. The server never sees a chat key.\n *\n * - `direct` chat: the key is the two users' X25519 pair key,\n * `crypto_box_beforenm(peer_pk, my_sk)` (a self-chat uses my own public key).\n * `crypto_box_easy` is exactly `secretbox` under that key, so every legacy DM\n * ciphertext opens here unchanged.\n * - `group` / `meeting` chat: a random 32-byte key per epoch, sealed\n * (`crypto_box_seal`) to each member.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport {\n base64ToBytes,\n bytesToBase64,\n decryptFile,\n encryptFile,\n initSodium,\n sealedBoxDecrypt,\n} from './sodium'\n\nexport const CHAT_KEY_BYTES = 32\n\n/** The direct-chat key shared with `peerPublicKeyBase64` (my own public key for a self-chat). */\nexport async function deriveDirectChatKey(\n peerPublicKeyBase64: string,\n mySecretKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n return sodium.crypto_box_beforenm(base64ToBytes(peerPublicKeyBase64), mySecretKey)\n}\n\n/** A fresh random group/meeting epoch key. */\nexport async function generateChatKey(): Promise<Uint8Array> {\n await initSodium()\n return sodium.randombytes_buf(CHAT_KEY_BYTES)\n}\n\n/** Seal an epoch key to a member's X25519 public key (base64). */\nexport async function sealChatKey(key: Uint8Array, publicKeyBase64: string): Promise<string> {\n await initSodium()\n return bytesToBase64(sodium.crypto_box_seal(key, base64ToBytes(publicKeyBase64)))\n}\n\n/** Open an epoch key sealed to me. Throws when it is not mine or not a chat key. */\nexport async function openSealedChatKey(\n sealedBase64: string,\n mySecretKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n const key = sealedBoxDecrypt(sealedBase64, mySecretKey)\n if (key.length !== CHAT_KEY_BYTES) throw new Error('Sealed chat key has the wrong length')\n return key\n}\n\n/** Encrypt UTF-8 text under a chat key → base64(nonce ‖ secretbox). */\nexport async function encryptWithChatKey(plaintext: string, key: Uint8Array): Promise<string> {\n await initSodium()\n return bytesToBase64(encryptFile(sodium.from_string(plaintext), key))\n}\n\n/** Decrypt base64(nonce ‖ secretbox) under a chat key. Throws on a wrong key or tampering. */\nexport async function decryptWithChatKey(ciphertext: string, key: Uint8Array): Promise<string> {\n await initSodium()\n return sodium.to_string(decryptFile(base64ToBytes(ciphertext), key))\n}\n","/**\n * Layer 2: User keypair generation\n *\n * Generates Ed25519 signing and X25519 encryption keypairs from email + password.\n * Takes `deploymentDomain` as an explicit parameter (no window.RUNTIME_CONFIG).\n */\n\nimport { generateKeyPairs, type KeyPair, type UserKeypairs } from './sodium'\n\n/**\n * Generate user keypairs deterministically using Argon2id.\n *\n * Creates Ed25519 signing keypair and derives X25519 encryption keypair.\n * Ed25519 is used for authentication (signing), X25519 for encryption.\n *\n * This is a zero-knowledge system - the server never sees private keys.\n *\n * @param username - User's email/username\n * @param password - User's password\n * @param deploymentDomain - Deployment domain (used for salt derivation)\n * @returns Object with Ed25519 signing keypair and X25519 encryption keypair\n */\nexport async function generateUserKeypairs(\n username: string,\n password: string,\n deploymentDomain: string\n): Promise<UserKeypairs> {\n if (!deploymentDomain) {\n throw new Error('Deployment domain must be provided. Cannot generate keypairs.')\n }\n\n // Generate keypairs using the libsodium implementation\n const keypairs = await generateKeyPairs(username, password, deploymentDomain)\n\n const signingKeyPair: KeyPair = {\n publicKey: keypairs.signing.publicKey,\n secretKey: keypairs.signing.privateKey,\n }\n\n const encryptionKeyPair: KeyPair = {\n publicKey: keypairs.encryption.publicKey,\n secretKey: keypairs.encryption.privateKey,\n }\n\n return {\n signingKeyPair,\n encryptionKeyPair,\n }\n}\n","/**\n * The account identity and the password key that wraps it.\n *\n * The identity is a fixed Ed25519 keypair (its X25519 form is what workspace keys, mailbox keys and direct\n * messages are encrypted to). The password derives a separate \"password key\" (Argon2id, `generateUserKeypairs`)\n * that signs password logins and wraps the identity's secret key. Changing the password re-wraps the identity\n * and re-encrypts nothing.\n *\n * Accounts registered before this existed have no wrap: their password key IS the identity\n * (`wrapped_identity_key` is null in the login response).\n *\n * Same scheme as the Python SDK (`arbi_client.sdk.crypto`): BLAKE2b-256 keyed by the password key's seed over\n * a fixed context gives a SecretBox key; the wrap is base64 of `nonce(24) ‖ secretbox(identity secret key)`.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport { base64Decode, base64Encode, generateRandomSigningKeypair, type KeyPair } from './sodium'\n\nconst IDENTITY_WRAP_CONTEXT = 'arbi-identity-wrap-v1'\n\n/** The SecretBox key a password key wraps the identity under. Exported for the cross-implementation test. */\nexport function identityWrappingKey(passwordSecretKey: Uint8Array): Uint8Array {\n return sodium.crypto_generichash(\n 32,\n sodium.from_string(IDENTITY_WRAP_CONTEXT),\n passwordSecretKey.slice(0, 32)\n )\n}\n\n/** A fresh random identity (Ed25519; secretKey is the 64-byte form). */\nexport function generateIdentityKeypair(): KeyPair {\n return generateRandomSigningKeypair()\n}\n\n/** Wrap the identity's 64-byte Ed25519 secret key under a password key. */\nexport function wrapIdentityKey(\n identitySecretKey: Uint8Array,\n passwordSecretKey: Uint8Array\n): string {\n const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)\n const key = identityWrappingKey(passwordSecretKey)\n try {\n const boxed = sodium.crypto_secretbox_easy(identitySecretKey, nonce, key)\n const out = new Uint8Array(nonce.length + boxed.length)\n out.set(nonce)\n out.set(boxed, nonce.length)\n return base64Encode(out)\n } finally {\n key.fill(0)\n }\n}\n\n/**\n * The identity's 64-byte Ed25519 secret key a password key opens: unwrapped from `wrapped`, or the password key\n * itself when nothing is wrapped. Throws when the password key does not open the wrap (a wrong password).\n */\nexport function unwrapIdentityKey(\n wrapped: string | null | undefined,\n passwordSecretKey: Uint8Array\n): Uint8Array {\n if (!wrapped) return passwordSecretKey\n const bytes = base64Decode(wrapped)\n const nonce = bytes.slice(0, sodium.crypto_secretbox_NONCEBYTES)\n const key = identityWrappingKey(passwordSecretKey)\n try {\n return sodium.crypto_secretbox_open_easy(\n bytes.slice(sodium.crypto_secretbox_NONCEBYTES),\n nonce,\n key\n )\n } catch {\n throw new Error('Incorrect password')\n } finally {\n key.fill(0)\n }\n}\n","/**\n * Layer 3: High-level credential generation\n *\n * Generates registration, login, and password-change credentials.\n * Uses inline type definitions (structurally identical to OpenAPI schema types)\n * to avoid coupling the crypto module to the schema file.\n *\n * Two keys are in play (see ./identity.ts): the account identity, a fixed random Ed25519 keypair, and the\n * password key, derived from email + password, which signs password logins and wraps the identity.\n */\n\nimport { signMessage, base64Encode } from './sodium'\nimport { generateUserKeypairs } from './keypairs'\nimport { generateIdentityKeypair, wrapIdentityKey } from './identity'\n\n// ============================================================================\n// Inline types (structurally identical to OpenAPI schema equivalents)\n// ============================================================================\n\nexport interface RegisterRequest {\n email: string\n signing_key: string\n login_key?: string | null\n wrapped_identity_key?: string | null\n verification_credential: string\n given_name?: string | null\n family_name?: string | null\n picture?: string | null\n}\n\nexport interface LoginRequest {\n email: string\n signature: string\n timestamp: number\n sso_token?: string | null\n}\n\nexport interface ChangePasswordRequest {\n signature: string\n timestamp: number\n new_login_key: string\n wrapped_identity_key: string\n}\n\n// ============================================================================\n// Credential types\n// ============================================================================\n\n/**\n * Credentials returned by generate functions.\n * Contains both the backend request AND client-side private keys.\n * Private keys never leave the client.\n */\nexport interface RegistrationCredentials {\n request: RegisterRequest\n /** The new account's identity secret key (what the session keeps, and the recovery key). */\n signingPrivateKey: Uint8Array\n}\n\nexport interface LoginCredentials {\n request: LoginRequest\n /**\n * The password key that signed the request. Not the identity: open it from the response with\n * `unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey)`.\n */\n passwordPrivateKey: Uint8Array\n}\n\nexport interface KeyLoginCredentials {\n request: LoginRequest\n /** The identity secret key that signed the request (recovery key, session re-login). */\n signingPrivateKey: Uint8Array\n}\n\nexport interface PasswordChangeCredentials {\n request: ChangePasswordRequest\n}\n\n// ============================================================================\n// Credential generation functions\n// ============================================================================\n\nfunction signedNow(email: string, key: Uint8Array): { signature: string; timestamp: number } {\n const timestamp = Math.floor(Date.now() / 1000)\n return { signature: signMessage(`${email}|${timestamp}`, key), timestamp }\n}\n\n/**\n * Generate registration credentials: a random identity, wrapped under the password key.\n *\n * The server stores the identity public key (signing_key, and the X25519 key it derives from it), the password\n * key (login_key) and the wrapped identity.\n */\nexport async function generateRegistrationCredentials(\n registrationData: Omit<RegisterRequest, 'signing_key' | 'login_key' | 'wrapped_identity_key'>,\n password: string,\n deploymentDomain: string\n): Promise<RegistrationCredentials> {\n const { signingKeyPair: passwordKey } = await generateUserKeypairs(\n registrationData.email,\n password,\n deploymentDomain\n )\n const identity = generateIdentityKeypair()\n\n const request: RegisterRequest = {\n ...registrationData,\n signing_key: base64Encode(identity.publicKey),\n login_key: base64Encode(passwordKey.publicKey),\n wrapped_identity_key: wrapIdentityKey(identity.secretKey, passwordKey.secretKey),\n }\n\n return { request, signingPrivateKey: identity.secretKey }\n}\n\n/**\n * Generate password-login credentials: derive the password key and sign \"email|timestamp\" with it.\n */\nexport async function generateLoginCredentials(\n loginData: Omit<LoginRequest, 'signature' | 'timestamp'>,\n password: string,\n deploymentDomain: string\n): Promise<LoginCredentials> {\n const { signingKeyPair } = await generateUserKeypairs(loginData.email, password, deploymentDomain)\n return {\n request: { ...loginData, ...signedNow(loginData.email, signingKeyPair.secretKey) },\n passwordPrivateKey: signingKeyPair.secretKey,\n }\n}\n\n/**\n * Generate login credentials signed by the identity key itself (recovery key, session re-login).\n */\nexport function generateLoginCredentialsFromKey(\n loginData: Omit<LoginRequest, 'signature' | 'timestamp'>,\n signingPrivateKey: Uint8Array\n): KeyLoginCredentials {\n if (signingPrivateKey.length !== 64) {\n throw new Error('Invalid signing key: must be exactly 64 bytes')\n }\n return {\n request: { ...loginData, ...signedNow(loginData.email, signingPrivateKey) },\n signingPrivateKey,\n }\n}\n\n/**\n * Generate a password change: the identity is kept, re-wrapped under the new password key.\n *\n * Signed with the current password key when `currentPassword` is given (proves it), else with the identity key\n * (recovery: the user signed in with the recovery key and no longer knows the password).\n */\nexport async function generatePasswordChangeCredentials(\n params: {\n email: string\n identitySecretKey: Uint8Array\n newPassword: string\n currentPassword?: string\n },\n deploymentDomain: string\n): Promise<PasswordChangeCredentials> {\n const signer = params.currentPassword\n ? (await generateUserKeypairs(params.email, params.currentPassword, deploymentDomain))\n .signingKeyPair.secretKey\n : params.identitySecretKey\n const { signingKeyPair: newPasswordKey } = await generateUserKeypairs(\n params.email,\n params.newPassword,\n deploymentDomain\n )\n return {\n request: {\n ...signedNow(params.email, signer),\n new_login_key: base64Encode(newPasswordKey.publicKey),\n wrapped_identity_key: wrapIdentityKey(params.identitySecretKey, newPasswordKey.secretKey),\n },\n }\n}\n","/**\n * Recovery keys.\n *\n * The recovery key is the account's 64-byte Ed25519 signing secret key. It reaches the user as a\n * recovery link, `<origin>/recover?email=…[&sso=1]#KEY=<base64url bytes>` — the key travels in the\n * URL fragment, which browsers never send to a server — saved to a password manager or downloaded\n * inside a one-link HTML file.\n *\n * For SSO users the key is first wrapped with their Auth0 `sub`, so the link is useless without\n * also completing the SSO login: `nonce(24) ‖ secretbox(signing key, SHA-256(sub))`, 104 bytes.\n *\n * Older recovery files hold the raw bytes (64 plain, 104 SSO-wrapped); both are still accepted.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport { base64UrlToBytes, bytesToBase64Url, decryptFile, encryptFile, initSodium } from './sodium'\n\n/** Raw Ed25519 signing secret key. */\nexport const UNENCRYPTED_RECOVERY_KEY_SIZE = 64\n/** 24 (nonce) + 64 (key) + 16 (auth tag). */\nexport const ENCRYPTED_RECOVERY_KEY_SIZE = 104\n\n/** The error strings of the recovery flow. */\nexport const RECOVERY_KEY_ERRORS = {\n INVALID_SIZE: `Invalid recovery key: file must be ${UNENCRYPTED_RECOVERY_KEY_SIZE} or ${ENCRYPTED_RECOVERY_KEY_SIZE} bytes`,\n INVALID_FORMAT: 'Invalid recovery key format',\n READ_ERROR: 'Failed to read recovery key file',\n AUTH_FAILED: 'Recovery key does not match this account',\n ENCRYPTED_KEY_REQUIRES_SSO:\n 'This recovery key is encrypted with your SSO identity. Please use SSO login and then click \"Forgot Password\" to use this key.',\n DECRYPTION_FAILED:\n 'Failed to decrypt recovery key. This key may belong to a different SSO account.',\n} as const\n\nfunction assertSigningKey(signingPrivateKey: Uint8Array): void {\n if (signingPrivateKey.length !== UNENCRYPTED_RECOVERY_KEY_SIZE) {\n throw new Error('Invalid signing key: must be exactly 64 bytes')\n }\n}\n\n/** The secretbox key of an SSO recovery key: SHA-256 of the Auth0 `sub`. */\nfunction ssoWrappingKey(auth0Sub: string): Uint8Array {\n return sodium.crypto_hash_sha256(sodium.from_string(auth0Sub))\n}\n\n/** Wrap the signing key with the user's Auth0 `sub` (104 bytes: nonce ‖ secretbox). */\nexport async function encryptRecoveryKey(\n signingPrivateKey: Uint8Array,\n auth0Sub: string\n): Promise<Uint8Array> {\n await initSodium()\n assertSigningKey(signingPrivateKey)\n return encryptFile(signingPrivateKey, ssoWrappingKey(auth0Sub))\n}\n\n/** Unwrap an SSO recovery key. Throws when it belongs to another account or is damaged. */\nexport async function decryptRecoveryKey(\n encryptedKey: Uint8Array,\n auth0Sub: string\n): Promise<Uint8Array> {\n await initSodium()\n if (encryptedKey.length !== ENCRYPTED_RECOVERY_KEY_SIZE) {\n throw new Error(`Invalid encrypted key: expected ${ENCRYPTED_RECOVERY_KEY_SIZE} bytes`)\n }\n try {\n return decryptFile(encryptedKey, ssoWrappingKey(auth0Sub))\n } catch {\n throw new Error(RECOVERY_KEY_ERRORS.DECRYPTION_FAILED)\n }\n}\n\n/** Whether recovery key bytes of this length are SSO-wrapped. */\nexport function isEncryptedRecoveryKey(byteLength: number): boolean {\n return byteLength === ENCRYPTED_RECOVERY_KEY_SIZE\n}\n\n/** A timestamped name for the downloadable recovery file. */\nexport function getRecoveryKeyFilename(): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)\n return `arbi-recovery-${timestamp}.html`\n}\n\n/**\n * The recovery link for already-prepared key bytes (raw, or SSO-wrapped with `sso`). The email\n * goes in the query (it is visible during a normal login anyway); the key goes in the fragment.\n */\nexport function buildRecoveryUrl(args: {\n origin: string\n email: string\n keyBytes: Uint8Array\n sso: boolean\n}): string {\n const params = new URLSearchParams({ email: args.email })\n if (args.sso) params.set('sso', '1')\n return `${args.origin}/recover?${params.toString()}#KEY=${bytesToBase64Url(args.keyBytes)}`\n}\n\n/** A parsed recovery link. `isEncrypted`: the key is SSO-wrapped and needs the SSO login. */\nexport interface ParsedRecoveryUrl {\n email: string\n recoveryKey: Uint8Array\n isEncrypted: boolean\n}\n\n/** Read a recovery link's query and fragment. Null when it carries no email or no valid key. */\nexport function parseRecoveryUrl(search: string, hash: string): ParsedRecoveryUrl | null {\n const params = new URLSearchParams(search)\n const email = params.get('email')\n const keyMatch = /(?:^#|[&#])KEY=([A-Za-z0-9_-]+)/.exec(hash)\n if (!email || !keyMatch) return null\n try {\n return {\n email,\n recoveryKey: base64UrlToBytes(keyMatch[1]),\n isEncrypted: params.get('sso') === '1',\n }\n } catch {\n return null\n }\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\n/** The single-page HTML recovery file: one link to `url`, no external assets. */\nfunction buildRecoveryHtml(args: { email: string; url: string; ssoEncrypted: boolean }): string {\n const email = escapeHtml(args.email)\n const url = escapeHtml(args.url)\n const ssoNote = args.ssoEncrypted\n ? '<p class=\"note\">This recovery file is encrypted with your SSO identity — opening it on a different account will not work.</p>'\n : ''\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>ARBI Recovery</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<style>\n :root { color-scheme: light dark; }\n body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n max-width: 32rem; margin: 4rem auto; padding: 1.5rem; line-height: 1.5; }\n h1 { font-size: 1.25rem; margin-bottom: 0.25rem; }\n .email { font-weight: 600; }\n .btn { display: inline-block; padding: 0.75rem 1.25rem; margin-top: 1.5rem;\n background: #2563eb; color: #fff; text-decoration: none;\n border-radius: 0.5rem; font-weight: 600; }\n .btn:hover { background: #1d4ed8; }\n .note { font-size: 0.85rem; color: #6b7280; margin-top: 1.5rem; }\n details { margin-top: 1rem; font-size: 0.85rem; color: #6b7280; }\n code { word-break: break-all; }\n</style>\n</head>\n<body>\n <h1>ARBI account recovery</h1>\n <p>Click below to set a new password for <span class=\"email\">${email}</span>.</p>\n <p><a class=\"btn\" href=\"${url}\">Recover account</a></p>\n ${ssoNote}\n <details>\n <summary>If the button doesn't work, open this URL manually</summary>\n <p><code>${url}</code></p>\n </details>\n</body>\n</html>\n`\n}\n\n/** What a recovery link or file is made from. With `auth0Sub` the key is SSO-wrapped first. */\nexport interface RecoveryKeyParams {\n signingPrivateKey: Uint8Array\n email: string\n /** The app origin the link opens, e.g. `window.location.origin`. */\n origin: string\n auth0Sub?: string | null\n}\n\n/** The recovery link for an account (to save in a password manager, or inside the file). */\nexport async function createRecoveryUrl(params: RecoveryKeyParams): Promise<string> {\n assertSigningKey(params.signingPrivateKey)\n const keyBytes = params.auth0Sub\n ? await encryptRecoveryKey(params.signingPrivateKey, params.auth0Sub)\n : params.signingPrivateKey\n return buildRecoveryUrl({\n origin: params.origin,\n email: params.email,\n keyBytes,\n sso: !!params.auth0Sub,\n })\n}\n\n/** The downloadable recovery file: an HTML page holding the recovery link. */\nexport async function createRecoveryFile(\n params: RecoveryKeyParams\n): Promise<{ filename: string; html: string; url: string }> {\n const url = await createRecoveryUrl(params)\n return {\n filename: getRecoveryKeyFilename(),\n html: buildRecoveryHtml({ email: params.email, url, ssoEncrypted: !!params.auth0Sub }),\n url,\n }\n}\n\n/** The result of reading an uploaded raw recovery key file. */\nexport interface RecoveryKeyValidationResult {\n valid: boolean\n /** The key is SSO-wrapped. */\n isEncrypted: boolean\n /** The raw file bytes (wrapped or not). */\n data: Uint8Array | null\n error?: string\n}\n\n/** Read an uploaded raw recovery key file: 64 bytes (plain) or 104 (SSO-wrapped). */\nexport async function validateRecoveryKeyFile(file: Blob): Promise<RecoveryKeyValidationResult> {\n if (file.size !== UNENCRYPTED_RECOVERY_KEY_SIZE && file.size !== ENCRYPTED_RECOVERY_KEY_SIZE) {\n return {\n valid: false,\n isEncrypted: false,\n data: null,\n error: RECOVERY_KEY_ERRORS.INVALID_SIZE,\n }\n }\n try {\n const data = new Uint8Array(await file.arrayBuffer())\n return { valid: true, isEncrypted: isEncryptedRecoveryKey(data.length), data }\n } catch {\n return { valid: false, isEncrypted: false, data: null, error: RECOVERY_KEY_ERRORS.READ_ERROR }\n }\n}\n","/**\n * Secure mail delivery (`/v1/mail/secure`).\n *\n * The sender's browser builds the MIME message and seals it under a fresh random 32-byte message\n * key: `ciphertext` and `metadata_ciphertext` are each `base64(nonce ‖ secretbox(bytes, key))`. The\n * key reaches each recipient only in the link fragment (`fragment_key`), and the sender keeps it\n * sealed to their own X25519 public key (`sender_wrapped_key`). To claim a message the recipient\n * proves they hold the key (`claim_hash` = hex SHA-256 of it) and re-seals it to themselves.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport {\n base64ToBytes,\n bytesToBase64,\n decryptFile,\n encryptFile,\n initSodium,\n sealedBoxEncrypt,\n} from './sodium'\n\nexport const SECURE_MAIL_KEY_BYTES = 32\n\n/** The encrypted parts of a secure message, as `/secure/send` takes and `/secure/{id}` returns. */\nexport interface SecureMailCiphertexts {\n ciphertext: string\n metadata_ciphertext: string\n}\n\n/** A sealed message plus the key material the send request needs. */\nexport interface SealedSecureMail extends SecureMailCiphertexts {\n /** The message key, base64 — sent to recipients in the link fragment only. */\n fragment_key: string\n /** The message key sealed to the sender. */\n sender_wrapped_key: string\n}\n\n/** What the recipient posts to `/secure/{id}/claim`. */\nexport interface SecureMailClaim {\n claim_hash: string\n wrapped_key: string\n recipient_public_key: string\n}\n\n/**\n * Seal a raw MIME message and its JSON metadata under a fresh message key, and seal the key to the\n * sender. The key is zeroed before returning; only its base64 `fragment_key` remains.\n */\nexport async function sealSecureMail(\n raw: Uint8Array,\n metadata: unknown,\n senderPublicKey: Uint8Array\n): Promise<SealedSecureMail> {\n await initSodium()\n const key = sodium.randombytes_buf(SECURE_MAIL_KEY_BYTES)\n try {\n return {\n ciphertext: bytesToBase64(encryptFile(raw, key)),\n metadata_ciphertext: bytesToBase64(\n encryptFile(sodium.from_string(JSON.stringify(metadata)), key)\n ),\n fragment_key: bytesToBase64(key),\n sender_wrapped_key: sealedBoxEncrypt(key, senderPublicKey),\n }\n } finally {\n key.fill(0)\n }\n}\n\n/** The message key carried in a secure-mail link. Throws when it is not a 32-byte key. */\nexport function decodeSecureMailKey(fragmentKey: string): Uint8Array {\n let key: Uint8Array\n try {\n key = base64ToBytes(fragmentKey)\n } catch {\n throw new Error('Invalid secure message link')\n }\n if (key.length !== SECURE_MAIL_KEY_BYTES) {\n key.fill(0)\n throw new Error('Invalid secure message link')\n }\n return key\n}\n\n/** Open a secure message. Throws on a wrong key or a tampered part. */\nexport async function openSecureMail<T = unknown>(\n payload: SecureMailCiphertexts,\n key: Uint8Array\n): Promise<{ raw: Uint8Array; metadata: T }> {\n await initSodium()\n const raw = decryptFile(base64ToBytes(payload.ciphertext), key)\n const meta = decryptFile(base64ToBytes(payload.metadata_ciphertext), key)\n try {\n return { raw, metadata: JSON.parse(sodium.to_string(meta)) as T }\n } finally {\n meta.fill(0)\n }\n}\n\n/** The claim body proving possession of `key` and re-sealing it to the recipient. */\nexport async function secureMailClaim(\n key: Uint8Array,\n recipientPublicKey: Uint8Array\n): Promise<SecureMailClaim> {\n await initSodium()\n return {\n claim_hash: sodium.to_hex(sodium.crypto_hash_sha256(key)),\n wrapped_key: sealedBoxEncrypt(key, recipientPublicKey),\n recipient_public_key: bytesToBase64(recipientPublicKey),\n }\n}\n","/**\n * storage.ts - IndexedDB Storage Module\n *\n * Handles persistent storage of cryptographic keys and session data.\n *\n * Storage Strategy (with encryption-at-rest):\n * - Private keys encrypted with non-extractable Web Crypto AES-GCM key\n * - Wrapping key stored as opaque CryptoKey object (can't be exported)\n * - Session data persists across page refreshes\n *\n * Database Schema:\n * - Store: 'session' - User session data (encrypted private key only)\n * - Store: 'wrapping-key' - Non-extractable CryptoKey for encrypting private keys\n *\n * Security Model:\n * - Passive attacks (reading IndexedDB) get encrypted data + opaque CryptoKey\n * - Active attacks (calling decrypt) can still access keys (XSS with code execution)\n * - Defense-in-depth: Requires active XSS, not just storage access\n *\n * Ported from: /home/dev/ARBI/src/static/js/storage.js\n */\n\nimport { encryptionKeypairFromSigningKey, initSodium, type KeyPair } from '../crypto/sodium'\n\nconst DB_NAME = 'arbi-crypto'\nconst DB_VERSION = 2 // Incremented for new wrapping-key store\n\nlet db: IDBDatabase | null = null\n\n/**\n * Session held in memory when Web Crypto is unavailable (plain-HTTP origins other than\n * localhost, some embedded webviews). Encryption at rest needs a non-extractable CryptoKey,\n * which cannot exist there, so nothing is written to disk: the session works for the life\n * of the page and a reload means signing in again. Never a plaintext-at-rest fallback.\n */\nlet memorySession: SessionData | null = null\n\n/** True when sessions can be persisted (encrypted at rest) rather than held in memory only. */\nexport function canPersistSession(): boolean {\n return !!crypto?.subtle\n}\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/**\n * SessionData in IndexedDB - PERSISTED ENCRYPTED DATA\n * Everything needed to resume session without re-login:\n * - signingPrivateKey: Ed25519 private key (64 bytes, encrypted at rest)\n * Used for authentication (signing). X25519 encryption key is derived from this.\n * - serverSessionKey: Server session key for workspace key encryption (encrypted at rest)\n * - userExtId: User external ID (not sensitive, stored in plain text)\n *\n * Note: accessToken is stored in Zustand (persisted separately), not here.\n */\nexport interface SessionData {\n /** The account identity's Ed25519 secret key (64 bytes) - X25519 derived from this */\n signingPrivateKey: Uint8Array\n serverSessionKey?: Uint8Array\n userExtId?: string\n /**\n * The identity wrapped under the password key, as the last login returned it (null: the password key is\n * the identity). Lets a typed password be checked, and the identity opened, without the server (offline\n * unlock, step-up confirmations). Ciphertext under the password key, so it is stored as is.\n */\n wrappedIdentityKey?: string | null\n}\n\n/**\n * How session is stored in IndexedDB (with ALL sensitive data encrypted)\n */\ninterface StoredSession {\n id: string\n encryptedSigningPrivateKey: Uint8Array\n signingPrivateKeyIV: Uint8Array\n encryptedServerSessionKey?: Uint8Array\n serverSessionKeyIV?: Uint8Array\n userExtId?: string\n wrappedIdentityKey?: string | null\n timestamp: number\n}\n\ninterface WrappingKeyData {\n id: string\n key: CryptoKey\n created: number\n}\n\n// ============================================================================\n// Database Initialization\n// ============================================================================\n\n/**\n * Initialize IndexedDB database.\n *\n * Creates two object stores:\n * - 'session': Stores user session data (with encrypted private key)\n * - 'wrapping-key': Stores non-extractable CryptoKey for key encryption\n */\nexport async function initializeDatabase(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION)\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to open IndexedDB:', request.error)\n reject(request.error)\n }\n\n request.onsuccess = () => {\n db = request.result\n resolve(db)\n }\n\n request.onupgradeneeded = (event) => {\n const database = (event.target as IDBOpenDBRequest).result\n\n // Create 'session' store if it doesn't exist\n if (!database.objectStoreNames.contains('session')) {\n database.createObjectStore('session', { keyPath: 'id' })\n }\n\n // Create 'wrapping-key' store if it doesn't exist (v2+)\n if (!database.objectStoreNames.contains('wrapping-key')) {\n database.createObjectStore('wrapping-key', { keyPath: 'id' })\n }\n }\n })\n}\n\n/**\n * Ensure database is initialized before operations.\n */\nasync function ensureDatabase(): Promise<void> {\n if (!db) {\n await initializeDatabase()\n }\n}\n\n// ============================================================================\n// Wrapping Key Management (Web Crypto Non-Extractable Keys)\n// ============================================================================\n\n/**\n * Generate or retrieve the non-extractable wrapping key.\n *\n * This key is used to encrypt private keys before storing in IndexedDB.\n * - Generated once per browser (survives page refreshes)\n * - Stored as opaque CryptoKey object in IndexedDB\n * - Non-extractable: XSS can't dump the raw key bytes\n * - Can still be used for encrypt/decrypt operations\n *\n * @returns Non-extractable AES-GCM key\n */\nasync function getOrCreateWrappingKey(): Promise<CryptoKey> {\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['wrapping-key'], 'readwrite')\n const store = transaction.objectStore('wrapping-key')\n const request = store.get('master')\n\n request.onsuccess = () => {\n const result = request.result as WrappingKeyData | undefined\n\n if (result?.key) {\n resolve(result.key)\n } else {\n // Generate new non-extractable wrapping key\n // We need to generate the key and store it, but the transaction will auto-commit\n // after this callback. So we need to open a NEW transaction for the put.\n if (!crypto?.subtle) {\n reject(\n new Error(\n 'Web Crypto API not available. Ensure the page is served over HTTPS or localhost.'\n )\n )\n return\n }\n crypto.subtle\n .generateKey(\n {\n name: 'AES-GCM',\n length: 256,\n },\n false, // ❌ NON-EXTRACTABLE - Can't be exported!\n ['encrypt', 'decrypt']\n )\n .then((key) => {\n // Open a NEW transaction to store the key\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const putTransaction = db.transaction(['wrapping-key'], 'readwrite')\n const putStore = putTransaction.objectStore('wrapping-key')\n const putRequest = putStore.put({\n id: 'master',\n key: key,\n created: Date.now(),\n } as WrappingKeyData)\n\n putRequest.onsuccess = () => {\n resolve(key)\n }\n\n putRequest.onerror = () => {\n reject(new Error('Failed to store wrapping key'))\n }\n })\n .catch((error) => {\n const errorMsg = error instanceof Error ? error.message : String(error)\n reject(new Error(`Failed to generate wrapping key: ${errorMsg}`))\n })\n }\n }\n\n request.onerror = () => {\n reject(new Error('Failed to retrieve wrapping key from IndexedDB'))\n }\n })\n}\n\n/**\n * Encrypt data using the non-extractable wrapping key.\n *\n * @param data - Data to encrypt\n * @returns Encrypted data and IV\n */\nasync function encryptWithWrappingKey(\n data: Uint8Array\n): Promise<{ ciphertext: Uint8Array; iv: Uint8Array }> {\n const wrappingKey = await getOrCreateWrappingKey()\n\n // Generate random IV for AES-GCM\n const iv = crypto.getRandomValues(new Uint8Array(12))\n\n // Encrypt the data\n const ciphertext = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv: iv,\n },\n wrappingKey,\n data as BufferSource\n )\n\n return {\n ciphertext: new Uint8Array(ciphertext),\n iv: iv,\n }\n}\n\n/**\n * Decrypt data using the non-extractable wrapping key.\n *\n * @param ciphertext - Encrypted data\n * @param iv - Initialization vector\n * @returns Decrypted data\n */\nasync function decryptWithWrappingKey(ciphertext: Uint8Array, iv: Uint8Array): Promise<Uint8Array> {\n const wrappingKey = await getOrCreateWrappingKey()\n\n const decrypted = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n },\n wrappingKey,\n ciphertext as BufferSource\n )\n\n return new Uint8Array(decrypted)\n}\n\n// ============================================================================\n// Session Storage\n// ============================================================================\n\n/**\n * Store session data in IndexedDB (ALL data encrypted at rest).\n *\n * Stores everything needed to resume session without re-login:\n * - signingPrivateKey: User's Ed25519 private key (ENCRYPTED)\n * - serverSessionKey: Server session key (ENCRYPTED)\n * - userExtId: User external ID (plain text, not sensitive)\n *\n * Note: accessToken is NOT stored here - it's in Zustand (persisted separately).\n *\n * @param sessionData - Complete session data to persist\n */\nexport async function saveSession(sessionData: SessionData): Promise<void> {\n // Without Web Crypto (non-secure context, Tracking Prevention, embedded widgets) keep the\n // session in memory only: it works until the page is closed or refreshed, never at rest.\n if (!canPersistSession()) {\n memorySession = sessionData\n return\n }\n\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n try {\n // Encrypt the signing private key (required)\n const encryptedSigningKey = await encryptWithWrappingKey(sessionData.signingPrivateKey)\n\n // Encrypt optional fields if present\n let encryptedServerSessionKey: { ciphertext: Uint8Array; iv: Uint8Array } | undefined\n\n if (sessionData.serverSessionKey) {\n encryptedServerSessionKey = await encryptWithWrappingKey(sessionData.serverSessionKey)\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['session'], 'readwrite')\n const store = transaction.objectStore('session')\n\n const data: StoredSession = {\n id: 'current',\n encryptedSigningPrivateKey: encryptedSigningKey.ciphertext,\n signingPrivateKeyIV: encryptedSigningKey.iv,\n encryptedServerSessionKey: encryptedServerSessionKey?.ciphertext,\n serverSessionKeyIV: encryptedServerSessionKey?.iv,\n userExtId: sessionData.userExtId,\n wrappedIdentityKey: sessionData.wrappedIdentityKey ?? null,\n timestamp: Date.now(),\n }\n\n const request = store.put(data)\n\n request.onsuccess = () => {\n resolve()\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to save session:', request.error)\n reject(request.error)\n }\n })\n } catch (error) {\n console.error('[STORAGE] Failed to encrypt session data:', error)\n throw error\n }\n}\n\n/**\n * Retrieve session data from IndexedDB (with decrypted private key).\n *\n * @returns Session data or null if not found\n */\nexport async function getSession(): Promise<SessionData | null> {\n if (!canPersistSession()) {\n return memorySession\n }\n\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['session'], 'readonly')\n const store = transaction.objectStore('session')\n const request = store.get('current')\n\n request.onsuccess = async () => {\n const result = request.result as StoredSession | undefined\n\n if (result) {\n try {\n // Decrypt the signing private key (required)\n const signingPrivateKey = await decryptWithWrappingKey(\n result.encryptedSigningPrivateKey,\n result.signingPrivateKeyIV\n )\n\n // Decrypt optional fields if present\n let serverSessionKey\n\n if (result.encryptedServerSessionKey && result.serverSessionKeyIV) {\n serverSessionKey = await decryptWithWrappingKey(\n result.encryptedServerSessionKey,\n result.serverSessionKeyIV\n )\n }\n\n resolve({\n signingPrivateKey,\n serverSessionKey,\n userExtId: result.userExtId,\n wrappedIdentityKey: result.wrappedIdentityKey ?? null,\n })\n } catch (error) {\n console.error('[STORAGE] Failed to decrypt session data:', error)\n reject(error)\n }\n } else {\n resolve(null)\n }\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to get session:', request.error)\n reject(request.error)\n }\n })\n}\n\n/**\n * Replace the stored wrapped identity (after a password change), keeping the rest of the session.\n *\n * @param wrappedIdentityKey - The identity wrapped under the new password key\n */\nexport async function updateWrappedIdentityKey(wrappedIdentityKey: string): Promise<void> {\n const existingSession = await getSession()\n if (!existingSession) {\n throw new Error('No existing session to update')\n }\n await saveSession({ ...existingSession, wrappedIdentityKey })\n}\n\n/**\n * Clear session data from IndexedDB.\n */\nexport async function clearSession(): Promise<void> {\n memorySession = null\n if (!canPersistSession()) {\n return\n }\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['session'], 'readwrite')\n const store = transaction.objectStore('session')\n const request = store.delete('current')\n\n request.onsuccess = () => {\n resolve()\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to clear session:', request.error)\n reject(request.error)\n }\n })\n}\n\n/**\n * Clear the wrapping key from IndexedDB.\n *\n * ⚠️ WARNING: This will make all encrypted private keys unrecoverable!\n * Only call this during full logout/reset.\n */\nasync function clearWrappingKey(): Promise<void> {\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['wrapping-key'], 'readwrite')\n const store = transaction.objectStore('wrapping-key')\n const request = store.delete('master')\n\n request.onsuccess = () => {\n resolve()\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to clear wrapping key:', request.error)\n reject(request.error)\n }\n })\n}\n\n/**\n * Clear all data from IndexedDB (session + wrapping key).\n *\n * Used during logout to ensure all cryptographic material is removed.\n */\nexport async function clearAllData(): Promise<void> {\n memorySession = null\n if (!canPersistSession()) {\n return\n }\n await clearSession()\n await clearWrappingKey()\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if a session exists in IndexedDB.\n *\n * @returns True if session exists\n */\nexport async function hasSession(): Promise<boolean> {\n const session = await getSession()\n return session !== null\n}\n\n/**\n * The current user's X25519 encryption keypair, derived from the persisted\n * session signing key. Returns null when there is no session (no client-side\n * keys). This is the canonical way to obtain the user's own keypair — callers\n * should not re-derive it from `getSession()` themselves.\n */\nexport async function getUserEncryptionKeypair(): Promise<KeyPair | null> {\n await initSodium()\n const session = await getSession()\n if (!session?.signingPrivateKey) {\n return null\n }\n return encryptionKeypairFromSigningKey(session.signingPrivateKey)\n}\n","/**\n * Encryption at rest for offline stores (IndexedDB copies of mail, calendar, …).\n *\n * Keys are derived in memory from the user's own X25519 identity key (by default the one the session\n * store keeps, wrapped by a non-extractable WebCrypto key). Nothing derived here is ever written to disk.\n *\n * - `enc`: XSalsa20-Poly1305 (libsodium secretbox) key for record contents; each record gets a fresh\n * random nonce, stored in front of the ciphertext.\n * - `index`: keyed BLAKE2b key for blind index values, so ids never appear in plaintext.\n *\n * Both are BLAKE2b derivations of the identity secret key, domain-separated by a per-store namespace\n * (`<namespace>:enc`, `<namespace>:index`), so stores can't read each other's records.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport { getUserEncryptionKeypair } from '../storage/indexed-db'\nimport type { KeyPair } from './sodium'\n\ninterface Keys {\n enc: Uint8Array\n index: Uint8Array\n}\n\nexport interface OfflineSealer {\n sealBytes(plain: Uint8Array): Promise<Uint8Array>\n openBytes(sealed: Uint8Array): Promise<Uint8Array>\n sealJson(value: unknown): Promise<Uint8Array>\n openJson<T>(sealed: Uint8Array): Promise<T>\n /** A keyed hash of `parts`, used as an IndexedDB key so ids never appear in plaintext. */\n blind(...parts: string[]): Promise<string>\n /** Forget the derived keys (sign-out, or the offline data was removed). */\n forget(): void\n}\n\nexport interface OfflineSealerOptions {\n /** Builds the error thrown when no identity key is unlocked. */\n locked: () => Error\n /**\n * The identity keypair to derive from; the sealer zeroes its secret key after use. Defaults to\n * the signed-in session's ({@link getUserEncryptionKeypair}).\n */\n keypair?: () => Promise<KeyPair | null>\n}\n\n/**\n * libsodium type-checks its inputs with `instanceof Uint8Array`; bytes that come from another realm\n * (an IndexedDB structured clone, a TextEncoder of another global) fail that check. Re-wrap those.\n */\nfunction bytes(value: Uint8Array): Uint8Array {\n return value instanceof Uint8Array ? value : Uint8Array.from(value)\n}\n\n/** A sealer for one offline store, namespaced so stores can't read each other's records. */\nexport function createOfflineSealer(\n namespace: string,\n { locked, keypair: getKeypair = getUserEncryptionKeypair }: OfflineSealerOptions\n): OfflineSealer {\n const ENC_LABEL = `${namespace}:enc`\n const INDEX_LABEL = `${namespace}:index`\n let cached: { publicKey: string; keys: Keys } | null = null\n\n async function keys(): Promise<Keys> {\n await sodium.ready\n const keypair = await getKeypair()\n if (!keypair) throw locked()\n const publicKey = sodium.to_hex(keypair.publicKey)\n if (cached?.publicKey === publicKey) {\n keypair.secretKey.fill(0)\n return cached.keys\n }\n const derived = {\n enc: sodium.crypto_generichash(32, ENC_LABEL, bytes(keypair.secretKey)),\n index: sodium.crypto_generichash(32, INDEX_LABEL, bytes(keypair.secretKey)),\n }\n keypair.secretKey.fill(0)\n cached = { publicKey, keys: derived }\n return derived\n }\n\n async function seal(plain: Uint8Array | string): Promise<Uint8Array> {\n const { enc } = await keys()\n const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)\n const box = sodium.crypto_secretbox_easy(\n typeof plain === 'string' ? plain : bytes(plain),\n nonce,\n enc\n )\n const out = new Uint8Array(nonce.length + box.length)\n out.set(nonce)\n out.set(box, nonce.length)\n return out\n }\n\n async function openBytes(sealed: Uint8Array): Promise<Uint8Array> {\n const { enc } = await keys()\n const nonceBytes = sodium.crypto_secretbox_NONCEBYTES\n const data = bytes(sealed)\n // Throws on a wrong key or tampered record; callers treat that record as missing.\n return sodium.crypto_secretbox_open_easy(\n data.subarray(nonceBytes),\n data.subarray(0, nonceBytes),\n enc\n )\n }\n\n return {\n sealBytes: (plain) => seal(plain),\n openBytes,\n sealJson: (value) => seal(JSON.stringify(value)),\n async openJson<T>(sealed: Uint8Array) {\n return JSON.parse(sodium.to_string(await openBytes(sealed))) as T\n },\n async blind(...parts) {\n const { index } = await keys()\n return sodium.to_hex(sodium.crypto_generichash(16, parts.join('\\u0000'), index))\n },\n forget() {\n cached?.keys.enc.fill(0)\n cached?.keys.index.fill(0)\n cached = null\n },\n }\n}\n","/**\n * Bearer Auth Middleware\n *\n * Injects Authorization header on every request using the provided TokenProvider.\n */\n\nimport type { Middleware } from 'openapi-fetch'\nimport type { BearerAuthMiddlewareConfig } from './types'\n\nexport function createBearerAuthMiddleware(config: BearerAuthMiddlewareConfig): Middleware {\n return {\n async onRequest({ request }) {\n const accessToken = config.tokenProvider.getAccessToken()\n if (accessToken) {\n request.headers.set('Authorization', `Bearer ${accessToken}`)\n }\n return request\n },\n }\n}\n","/**\n * The session gate: every authenticated request of a client runs under it, so a sign-out can stop\n * them all before the server revokes the token.\n *\n * A sign-out `close`s the gate: from then on no request starts (it fails at once with an\n * `AbortError`, without reaching the network) and no re-login runs; then it `abort`s what is in\n * flight. Only then does the server end the session, so nothing still running on the old token\n * comes back 401, and nothing a 401 would set off (a re-login, a workspace re-open, a retry) starts\n * a new server session behind the sign-out. Once the session is cleared the gate `reopen`s, for the\n * next sign-in.\n */\n\nimport type { Middleware } from 'openapi-fetch'\n\nexport interface SessionGate {\n /** Aborted when the session ends; a new one after `reopen`. */\n readonly signal: AbortSignal\n /** The session is ending: nothing new may start on it. */\n readonly closed: boolean\n /** Nothing new starts: requests fail at once with an `AbortError`, re-logins do not run. */\n close(): void\n /** Abort every request in flight on this session. */\n abort(): void\n /** The session is over: requests may start again (for the next sign-in). */\n reopen(): void\n}\n\n/** The error an aborted request fails with (`DOMException`'s `AbortError`). */\nfunction abortError(): Error {\n return new DOMException('The session ended.', 'AbortError')\n}\n\n/**\n * Whether `error` is a request (or work) that was aborted rather than one that failed: callers\n * treat it as nothing to report. Looks through `cause`, for an error wrapped by the SDK.\n */\nexport function isAbortError(error: unknown): boolean {\n for (let e = error, depth = 0; e && typeof e === 'object' && depth < 5; depth++) {\n if ((e as { name?: unknown }).name === 'AbortError') return true\n e = (e as { cause?: unknown }).cause\n }\n return false\n}\n\n/** A signal aborted when either is (`AbortSignal.any`, where the platform has it). */\nfunction eitherSignal(a: AbortSignal, b: AbortSignal | null | undefined): AbortSignal {\n if (!b) return a\n if (typeof AbortSignal.any === 'function') return AbortSignal.any([a, b])\n const controller = new AbortController()\n const abort = (signal: AbortSignal) => () => controller.abort(signal.reason)\n if (a.aborted || b.aborted) controller.abort((a.aborted ? a : b).reason)\n else {\n a.addEventListener('abort', abort(a), { once: true })\n b.addEventListener('abort', abort(b), { once: true })\n }\n return controller.signal\n}\n\nexport function createSessionGate(): SessionGate {\n let controller = new AbortController()\n let closed = false\n return {\n get signal() {\n return controller.signal\n },\n get closed() {\n return closed\n },\n close() {\n closed = true\n },\n abort() {\n controller.abort(abortError())\n },\n reopen() {\n if (controller.signal.aborted) controller = new AbortController()\n closed = false\n },\n }\n}\n\n/** The gate's signal on `init` (and the caller's own, if it has one); rejects once it is closed. */\nexport function gatedFetch(gate: SessionGate, fetch: typeof globalThis.fetch): typeof fetch {\n return (input, init) => {\n if (gate.closed) return Promise.reject(abortError())\n const own = init?.signal ?? (input instanceof Request ? input.signal : undefined)\n return fetch(input, { ...init, signal: eitherSignal(gate.signal, own) })\n }\n}\n\n/**\n * The first middleware of a client: each request carries the gate's signal (so a retry cloned\n * from it does too), and one asked for while the gate is closed is aborted before it is sent.\n */\nexport function createSessionGateMiddleware(gate: SessionGate): Middleware {\n return {\n onRequest({ request }) {\n const signal = gate.closed ? AbortSignal.abort(abortError()) : gate.signal\n return new Request(request, { signal: eitherSignal(signal, request.signal) })\n },\n }\n}\n","/**\n * The user's workspace keys on this client: what the workspace lists said (each workspace's key,\n * wrapped to the user, and which are public, with none), and depositing a workspace's key on the\n * server session without opening it (`/prime-key`).\n *\n * One per client, so every `Arbi` on the client (a host recreates its `Arbi` per session and per\n * opened workspace) and the client's own recovery share it: a list read once, by whoever read it,\n * serves every later open. A request refused with 409 `workspace_key_required` primes the\n * workspace it names and is sent again (see the auto re-login middleware).\n */\n\nimport type { CryptoProvider, SessionPersistence } from './relogin/types'\n\n/** A workspace as a workspace list has it (only what the keys need). */\nexport interface ListedWorkspaceKey {\n external_id: string\n wrapped_key?: string | null\n is_public?: boolean | null\n /** A member without an account key: a temporary grant whose key lives in the server session. */\n is_member?: boolean | null\n}\n\nexport interface WorkspaceKeys {\n /** Remember what a workspace list said. Returns the list. */\n remember<T extends ListedWorkspaceKey>(workspaces: T[]): T[]\n /**\n * The workspace's key, wrapped to the user: from what was remembered, else from a fresh list\n * (a workspace created or shared since), or a fresh list with `refresh` (a key that no longer\n * opens: access re-granted with a new key). `null` for a public workspace the user holds no key\n * for, or one they hold a temporary (session-scoped or fixed-expiry) grant to. Throws when the user cannot see the workspace.\n */\n wrappedKey(\n workspaceId: string,\n options?: { refresh?: boolean }\n ): Promise<{ wrappedKey: string | null; fromCache: boolean }>\n /**\n * Make a workspace usable for requests that name it, without opening it: its key, sealed to this\n * server session, is deposited with `/prime-key`. Once per server session (a re-login rotates\n * it); concurrent calls share one request; `force` deposits again (the server lost it).\n */\n prime(workspaceId: string, options?: { force?: boolean }): Promise<void>\n /** Forget these workspaces (deleted). */\n forget(workspaceIds: string[]): void\n /** Forget everything (another user, signed out). */\n clear(): void\n}\n\nexport interface WorkspaceKeysDeps {\n crypto: Pick<CryptoProvider, 'ensureReady' | 'sealKeyForSession'>\n /** The workspace key, unwrapped with the signing key. */\n unwrapWorkspaceKey(wrappedKey: string, signingPrivateKey: Uint8Array): Uint8Array\n persistence: SessionPersistence\n getAccessToken(): string | null\n /** The server session key in use (the session's), else the stored one is read. */\n getServerSessionKey(): Uint8Array | null\n listWorkspaces(accessToken: string): Promise<ListedWorkspaceKey[] | null>\n /** POST `/v1/workspace/{id}/prime-key`; throws when refused. */\n primeKey(accessToken: string, workspaceId: string, sealedKey: string): Promise<void>\n}\n\nexport function createWorkspaceKeys(deps: WorkspaceKeysDeps): WorkspaceKeys {\n const wrapped = new Map<string, string>()\n const keyless = new Set<string>()\n let listing: Promise<void> | null = null\n /** Workspaces primed on this server session, by the session key they were sealed to. */\n const primed = new Map<string, Promise<void>>()\n let primedFor: Uint8Array | null = null\n\n function remember<T extends ListedWorkspaceKey>(workspaces: T[]): T[] {\n for (const ws of workspaces) {\n if (ws.wrapped_key) {\n wrapped.set(ws.external_id, ws.wrapped_key)\n keyless.delete(ws.external_id)\n } else if (ws.is_public || ws.is_member) keyless.add(ws.external_id)\n }\n return workspaces\n }\n\n /** One list read at a time: concurrent misses share it. */\n function readList(): Promise<void> {\n listing ??= (async () => {\n try {\n const token = deps.getAccessToken()\n if (!token) throw new Error('Not signed in')\n const list = await deps.listWorkspaces(token)\n if (!list) throw new Error('Failed to fetch workspaces')\n remember(list)\n } finally {\n listing = null\n }\n })()\n return listing\n }\n\n async function wrappedKey(workspaceId: string, { refresh = false } = {}) {\n if (!refresh) {\n const cached = wrapped.get(workspaceId)\n if (cached) return { wrappedKey: cached, fromCache: true }\n if (keyless.has(workspaceId)) return { wrappedKey: null, fromCache: true }\n }\n wrapped.delete(workspaceId)\n keyless.delete(workspaceId)\n await readList()\n const fresh = wrapped.get(workspaceId)\n if (fresh) return { wrappedKey: fresh, fromCache: false }\n if (keyless.has(workspaceId)) return { wrappedKey: null, fromCache: false }\n throw new Error(`Workspace ${workspaceId} not found or has no encryption key`)\n }\n\n async function sealedFor(workspaceId: string, serverSessionKey: Uint8Array, refresh: boolean) {\n const stored = await deps.persistence.getSession()\n if (!stored?.signingPrivateKey) throw new Error('No stored identity to unlock the workspace')\n const { wrappedKey: key, fromCache } = await wrappedKey(workspaceId, { refresh })\n if (!key) throw new Error(`Workspace ${workspaceId} is public: it has no key to deposit`)\n try {\n await deps.crypto.ensureReady()\n return await deps.crypto.sealKeyForSession(\n deps.unwrapWorkspaceKey(key, stored.signingPrivateKey),\n serverSessionKey\n )\n } catch (error) {\n // A remembered key that no longer opens: access was re-granted with a new key.\n if (!fromCache) throw error\n return sealedFor(workspaceId, serverSessionKey, true)\n }\n }\n\n async function serverSessionKey(): Promise<Uint8Array> {\n const key =\n deps.getServerSessionKey() ?? (await deps.persistence.getSession())?.serverSessionKey\n if (!key) throw new Error('No server session to unlock the workspace for')\n return key\n }\n\n function prime(workspaceId: string, { force = false } = {}): Promise<void> {\n const sessionKey = deps.getServerSessionKey()\n if (sessionKey !== primedFor) {\n primed.clear()\n primedFor = sessionKey\n }\n const pending = primed.get(workspaceId)\n if (pending && !force) return pending\n const run = (async () => {\n const token = deps.getAccessToken()\n if (!token) throw new Error('Not signed in')\n const sealed = await sealedFor(workspaceId, await serverSessionKey(), false)\n await deps.primeKey(token, workspaceId, sealed)\n })()\n primed.set(workspaceId, run)\n run.catch(() => {\n if (primed.get(workspaceId) === run) primed.delete(workspaceId)\n })\n return run\n }\n\n return {\n remember,\n wrappedKey,\n prime,\n forget(workspaceIds) {\n for (const id of workspaceIds) {\n wrapped.delete(id)\n keyless.delete(id)\n primed.delete(id)\n }\n },\n clear() {\n wrapped.clear()\n keyless.clear()\n primed.clear()\n primedFor = null\n },\n }\n}\n\n/** The workspace a 409 `{detail: {code: \"workspace_key_required\", workspace_ext_id}}` names. */\nexport function workspaceKeyRequiredOf(body: unknown): string | null {\n const detail = (body as { detail?: unknown } | null | undefined)?.detail\n if (!detail || typeof detail !== 'object') return null\n const d = detail as { code?: unknown; workspace_ext_id?: unknown }\n return d.code === 'workspace_key_required' && typeof d.workspace_ext_id === 'string'\n ? d.workspace_ext_id\n : null\n}\n","/**\n * Workspace opens, one at a time.\n *\n * The server keeps ONE open (\"active\") workspace per session, and every `POST /workspace/{id}/open`\n * replaces it. Every request that does not name its workspace reads that one. Two opens in flight\n * at once can land in either order, so the server may end on a workspace the client already left\n * while the client believes the other is open: the next lists read would return the wrong\n * workspace's data. So every open on a client goes through this queue (the SDK's\n * `selectWorkspace`, the re-open after a lost workspace, the re-open after a re-login, the\n * open-all): the server applies them in the order they were asked for, and ends on the last.\n *\n * The queue also says when the active workspace may have changed: `generation` moves whenever an\n * open that may change it starts (or one fails, leaving it unknown), so a read can tell whether\n * its response may belong to another workspace than the one it was issued for.\n */\n\nexport interface WorkspaceOpens {\n /**\n * Run `open` alone: after every open queued before it, before any queued after it. `target` is\n * read when it starts: the workspace it leaves active, or `null` when that is not one known\n * workspace (an open-all).\n */\n run<T>(target: () => string | null, open: () => Promise<T>): Promise<T>\n /** An open is running or waiting. */\n readonly busy: boolean\n /** Moves whenever an open that may change the server's active workspace starts or fails. */\n readonly generation: number\n /** The workspace the last open left active on the server; `null` when unknown. */\n readonly active: string | null\n /** Resolves once no open is running or waiting. */\n idle(): Promise<void>\n /** The server session changed (a login, a re-login, a sign-out): nothing is known to be open. */\n reset(): void\n}\n\nexport function createWorkspaceOpens(): WorkspaceOpens {\n let tail: Promise<unknown> = Promise.resolve()\n let pending = 0\n let generation = 0\n let active: string | null = null\n\n return {\n run<T>(target: () => string | null, open: () => Promise<T>): Promise<T> {\n pending++\n const result = tail.then(async () => {\n const workspaceId = target()\n if (workspaceId === null || workspaceId !== active) {\n generation++\n active = null\n }\n try {\n const value = await open()\n active = workspaceId\n return value\n } catch (error) {\n // The server may or may not have applied it.\n generation++\n active = null\n throw error\n }\n })\n const done = () => {\n pending--\n }\n tail = result.then(done, done)\n return result\n },\n get busy() {\n return pending > 0\n },\n get generation() {\n return generation\n },\n get active() {\n return active\n },\n async idle() {\n // An open queued while waiting extends the tail: wait for that one too.\n for (let current = tail; ; current = tail) {\n await current\n if (current === tail && pending === 0) return\n }\n },\n reset() {\n generation++\n active = null\n },\n }\n}\n","/**\n * Auto Re-login Middleware\n *\n * Handles 401 and 400 responses by triggering re-login and retrying the request.\n * Framework-agnostic — the actual re-login logic is provided via ReloginHandler.\n *\n * Clones the request in onRequest (before the body stream is consumed)\n * so that POST/PUT requests with bodies can be retried after re-login.\n */\n\nimport type { Middleware } from 'openapi-fetch'\nimport type { AutoReloginMiddlewareConfig } from './types'\nimport { workspaceKeyRequiredOf } from '../workspace-keys'\n\nconst NO_ACTIVE_WORKSPACE = /no active workspace/i\n\n/** The workspace a 409 `workspace_key_required` names, or null. */\nasync function keyRequiredWorkspace(response: Response): Promise<string | null> {\n try {\n return workspaceKeyRequiredOf(await response.clone().json())\n } catch {\n return null\n }\n}\n\nasync function isNoActiveWorkspace(response: Response): Promise<boolean> {\n try {\n return NO_ACTIVE_WORKSPACE.test(await response.clone().text())\n } catch {\n return false\n }\n}\n\nfunction safeClone(request: Request): Request | null {\n try {\n return request.clone()\n } catch {\n return null\n }\n}\n\nexport function createAutoReloginMiddleware(config: AutoReloginMiddlewareConfig): Middleware {\n // Store a pre-consumption clone keyed by request identity.\n // WeakMap ensures entries are garbage-collected when the Request is.\n const cloneCache = new WeakMap<Request, Request>()\n\n return {\n async onRequest({ request }) {\n // Clone before body is consumed by fetch(), so we can retry later\n try {\n cloneCache.set(request, request.clone())\n } catch {\n // Cloning can fail for certain exotic request types; proceed without cache\n }\n },\n\n async onResponse({ response, request }) {\n // 409 `workspace_key_required`: the request named a workspace whose key this session does\n // not hold. Deposit it (without opening the workspace) and send the request again, once:\n // it never ran. The retry bypasses this middleware, so it cannot loop.\n if (response.status === 409 && config.primeWorkspaceHandler) {\n const workspaceId = await keyRequiredWorkspace(response)\n if (workspaceId) {\n if (!(await config.primeWorkspaceHandler(workspaceId))) return response\n const retry = cloneCache.get(request) ?? safeClone(request)\n if (retry) return (config.fetch ?? globalThis.fetch)(retry)\n config.onRetryCloneFailed?.()\n return response\n }\n }\n\n // 400 \"No active workspace - call /open first\": the server session lost the open workspace.\n // Re-open it (or re-login, which re-opens) and retry ONCE, whatever the method: the request\n // never ran, so a retry is safe. The retry bypasses this middleware, so it cannot loop.\n if (response.status === 400 && (await isNoActiveWorkspace(response))) {\n let token: string | null = null\n let recovered = (await config.reopenWorkspaceHandler?.()) ?? false\n if (!recovered) {\n token = await config.reloginHandler()\n recovered = token !== null\n }\n if (!recovered) return response\n const retry = cloneCache.get(request) ?? safeClone(request)\n if (retry) {\n if (token) retry.headers.set('Authorization', `Bearer ${token}`)\n return (config.fetch ?? globalThis.fetch)(retry)\n }\n config.onRetryCloneFailed?.()\n return response\n }\n\n // Handle 400 errors on protected endpoints - try instant re-login once\n if (response.status === 400) {\n const isSafeMethod = ['GET', 'HEAD', 'DELETE'].includes(request.method)\n\n if (isSafeMethod) {\n const newToken = await config.reloginHandler()\n if (newToken) {\n const retryRequest = cloneCache.get(request) ?? request.clone()\n retryRequest.headers.set('Authorization', `Bearer ${newToken}`)\n return (config.fetch ?? globalThis.fetch)(retryRequest)\n }\n }\n }\n\n if (response.status === 401) {\n const excludePatterns = config.reloginExcludePatterns ?? []\n const isExcluded = excludePatterns.some((pattern) => request.url.includes(pattern))\n\n // Retry ALL requests after re-login, not just safe methods\n if (!isExcluded) {\n const newToken = await config.reloginHandler()\n if (newToken) {\n const cached = cloneCache.get(request)\n if (cached) {\n cached.headers.set('Authorization', `Bearer ${newToken}`)\n return (config.fetch ?? globalThis.fetch)(cached)\n }\n // Fallback: try cloning directly (works for bodyless requests)\n try {\n const retryRequest = request.clone()\n retryRequest.headers.set('Authorization', `Bearer ${newToken}`)\n return (config.fetch ?? globalThis.fetch)(retryRequest)\n } catch {\n console.warn('[API] Could not retry request after re-login (body already consumed)')\n config.onRetryCloneFailed?.()\n }\n }\n }\n }\n\n return response\n },\n }\n}\n","/**\n * Re-login Handler Factory\n *\n * Framework-agnostic instant re-login using stored private key.\n * All app-specific dependencies (state management, crypto, storage,\n * API transport) are injected via provider interfaces.\n *\n * Zero external dependencies beyond TypeScript types.\n */\n\nimport type { ReloginDeps, ReloginFailure } from './types'\n\n/**\n * Cooldown period after a successful re-login.\n * Prevents a second login from overwriting the session key in the DB\n * before the first login's workspace-open call completes.\n *\n * The race: WebSocket auth failure triggers a delayed `instantReLogin()` (via dynamic import)\n * that arrives after the middleware's re-login has already completed, causing a second /login\n * that regenerates the server session key and invalidates in-flight workspace-open requests.\n */\nconst RELOGIN_COOLDOWN_MS = 5_000\n\n/**\n * Create a re-login handler with injected dependencies.\n *\n * Returns a function: `() => Promise<string | null>`\n * Resolves to the new access token, or null on failure.\n *\n * Includes two layers of protection:\n * 1. Debounce: concurrent calls share the same in-flight promise.\n * 2. Cooldown: calls within RELOGIN_COOLDOWN_MS of a success return the cached token.\n */\nexport function createReloginHandler(deps: ReloginDeps): () => Promise<string | null> {\n let reloginPromise: Promise<string | null> | null = null\n let lastSuccessToken: string | null = null\n let lastSuccessTime = 0\n\n return function instantReLogin(): Promise<string | null> {\n // Layer 1: debounce — concurrent calls share the same promise\n if (reloginPromise) {\n return reloginPromise\n }\n\n // Layer 2: cooldown — recent success returns cached token\n const elapsed = Date.now() - lastSuccessTime\n if (lastSuccessToken && elapsed < RELOGIN_COOLDOWN_MS) {\n return Promise.resolve(lastSuccessToken)\n }\n\n // Precondition check BEFORE the shared promise is created. During a login's\n // reset window (completeLogin briefly sets auth.user = null) any gated query\n // that 401s will call here with no email yet. If that transient \"abort\"\n // resolved INSIDE the shared promise, Layer-1 debounce would hand the same\n // null result to a concurrent/subsequent caller that DOES have an email —\n // poisoning a relogin that would otherwise succeed and triggering a spurious\n // logout. The cold-start `ensureReady()` (libsodium WASM) widens this window\n // on the very first login, which is exactly when users hit it. Resolving the\n // no-email case here (not in the shared promise) keeps it from sticking.\n const userEmail = deps.authState.getUserEmail()\n if (!userEmail) {\n console.warn('[API] Re-login aborted: no user email')\n deps.onReloginFailed?.('not-ready')\n return Promise.resolve(null)\n }\n\n const fail = (reason: ReloginFailure): null => {\n deps.onReloginFailed?.(reason)\n return null\n }\n\n reloginPromise = (async () => {\n try {\n await deps.crypto.ensureReady()\n\n const session = await deps.persistence.getSession()\n if (!session) {\n console.warn('[API] Re-login aborted: no session')\n return fail('not-ready')\n }\n\n // Derive encryption key from signing key (for workspace key decryption)\n // Ed25519 secret key is 64 bytes: [32-byte seed][32-byte public key]\n const ed25519PublicKey = session.signingPrivateKey.slice(32, 64)\n const encryptionKeyPair = deps.crypto.deriveEncryptionKeypair({\n publicKey: ed25519PublicKey,\n secretKey: session.signingPrivateKey,\n })\n\n // Create timestamp and signature for login\n const timestamp = Math.floor(Date.now() / 1000)\n const message = `${userEmail}|${timestamp}`\n const signature = deps.crypto.signMessage(message, session.signingPrivateKey)\n\n // An SSO session re-logs in with the provider's token, and ONLY an SSO session asks for one:\n // the provider's cache can hold a session from another deployment on the same tenant, and\n // sending that token to this deployment's login is refused (401) and logs the user out.\n let ssoToken: string | null = null\n if (deps.authState.isSsoMode()) {\n try {\n ssoToken = (await deps.sso?.getToken()) ?? null\n } catch (error) {\n console.error('[API] Failed to get SSO token:', error)\n }\n if (!ssoToken) {\n console.warn('[API] Re-login aborted: SSO account but no token available')\n return fail('refused')\n }\n }\n\n // Perform login via injected provider\n const loginResult = await deps.loginProvider.login({\n email: userEmail,\n signature,\n timestamp,\n ssoToken: ssoToken ?? undefined,\n })\n\n if (loginResult === 'unreachable') {\n console.warn('[API] Re-login failed: server unreachable')\n return fail('unreachable')\n }\n if (!loginResult) {\n console.warn('[API] Re-login failed')\n return fail('refused')\n }\n\n // Save new session key (so it survives page reload)\n await deps.persistence.saveSession({\n signingPrivateKey: session.signingPrivateKey,\n serverSessionKey: loginResult.sessionKey,\n userExtId: loginResult.userExtId,\n wrappedIdentityKey: loginResult.wrappedIdentityKey ?? null,\n })\n\n // Notify consumers (e.g. cache update) — must await so session key\n // is propagated to React Query before workspace re-open\n await deps.onReloginSuccess?.({\n email: userEmail,\n accessToken: loginResult.accessToken,\n userExtId: loginResult.userExtId,\n serverSessionKey: loginResult.sessionKey,\n })\n\n // Track the best token we have — starts as user-scoped, may upgrade to workspace-scoped\n const activeToken = loginResult.accessToken\n\n deps.authState.setAccessToken(activeToken)\n\n // Re-open currently selected workspace (keys are re-encrypted with new session key)\n const selectedWorkspaceId = deps.authState.getSelectedWorkspaceId()\n if (selectedWorkspaceId) {\n try {\n const wrappedKey = await deps.workspaceKeyRefreshProvider.getWrappedKey(\n loginResult.accessToken,\n selectedWorkspaceId\n )\n\n if (wrappedKey) {\n const workspaceKey = deps.crypto.sealedBoxDecrypt(\n wrappedKey,\n encryptionKeyPair.secretKey\n )\n\n const encryptedWorkspaceKey = await deps.crypto.sealKeyForSession(\n workspaceKey,\n loginResult.sessionKey\n )\n\n // Call /open to store key on session and set active workspace\n if (deps.workspaceOpenProvider) {\n await deps.workspaceOpenProvider.openWorkspace(\n loginResult.accessToken,\n selectedWorkspaceId,\n encryptedWorkspaceKey\n )\n }\n }\n } catch (error) {\n console.error('[API] Failed to re-open workspace after re-login:', error)\n }\n }\n\n console.info('[API] Re-login successful')\n lastSuccessToken = activeToken\n lastSuccessTime = Date.now()\n return activeToken\n } catch (error) {\n console.error('[API] Re-login error:', error)\n lastSuccessToken = null\n lastSuccessTime = 0\n return fail('refused')\n } finally {\n reloginPromise = null\n }\n })()\n\n return reloginPromise\n }\n}\n","/**\n * Workspace re-open (no re-login)\n *\n * The server keeps \"which workspace is open, and its key sealed for this session\" on the session.\n * When that state is gone while the access token is still valid (a server restart, a rotated\n * session, an expired workspace session), requests fail with 400 \"No active workspace - call\n * /open first\". Re-opening needs no new login: unwrap the workspace key with the stored signing\n * key, seal it for the stored server session key, POST /open.\n */\n\nimport type {\n AuthStateProvider,\n CryptoProvider,\n SessionPersistence,\n WorkspaceKeyRefreshProvider,\n WorkspaceOpenProvider,\n} from './types'\n\nexport interface ReopenDeps {\n crypto: Pick<\n CryptoProvider,\n 'ensureReady' | 'deriveEncryptionKeypair' | 'sealedBoxDecrypt' | 'sealKeyForSession'\n >\n persistence: SessionPersistence\n authState: Pick<AuthStateProvider, 'getSelectedWorkspaceId'>\n getAccessToken(): string | null\n workspaceKeyRefreshProvider: WorkspaceKeyRefreshProvider\n workspaceOpenProvider: WorkspaceOpenProvider\n}\n\n/**\n * Returns `reopenWorkspace()`: resolves true when the selected workspace is open again on the\n * server session, false when it cannot be (nothing selected, no stored keys, server refused).\n * Concurrent calls share one in-flight attempt.\n */\nexport function createWorkspaceReopener(deps: ReopenDeps): () => Promise<boolean> {\n let inFlight: Promise<boolean> | null = null\n\n return function reopenWorkspace(): Promise<boolean> {\n if (inFlight) return inFlight\n inFlight = (async () => {\n try {\n const workspaceId = deps.authState.getSelectedWorkspaceId()\n const accessToken = deps.getAccessToken()\n if (!workspaceId || !accessToken) return false\n\n const session = await deps.persistence.getSession()\n if (!session?.signingPrivateKey || !session.serverSessionKey) return false\n\n await deps.crypto.ensureReady()\n const wrappedKey = await deps.workspaceKeyRefreshProvider.getWrappedKey(\n accessToken,\n workspaceId\n )\n if (!wrappedKey) return false\n\n const encryptionKeyPair = deps.crypto.deriveEncryptionKeypair({\n publicKey: session.signingPrivateKey.slice(32, 64),\n secretKey: session.signingPrivateKey,\n })\n const workspaceKey = deps.crypto.sealedBoxDecrypt(wrappedKey, encryptionKeyPair.secretKey)\n const sealed = await deps.crypto.sealKeyForSession(workspaceKey, session.serverSessionKey)\n const opened = await deps.workspaceOpenProvider.openWorkspace(\n accessToken,\n workspaceId,\n sealed\n )\n return opened === true\n } catch (error) {\n console.error('[API] Failed to re-open workspace:', error)\n return false\n } finally {\n inFlight = null\n }\n })()\n return inFlight\n }\n}\n\nexport interface OpenAllDeps {\n crypto: Pick<CryptoProvider, 'ensureReady' | 'sealKeyForSession' | 'fromBase64'>\n persistence: SessionPersistence\n getAccessToken(): string | null\n /** The session's own X25519 key (the token's `sk` claim), which workspace keys are sealed to. */\n getSessionKey(accessToken: string): string | null\n /** The workspace key, unwrapped with the signing key. */\n unwrapWorkspaceKey(wrappedKey: string, signingPrivateKey: Uint8Array): Uint8Array\n listWorkspaces(\n accessToken: string\n ): Promise<Array<{ external_id: string; wrapped_key?: string | null }> | null>\n workspaceOpenProvider: WorkspaceOpenProvider\n /**\n * The workspace to open last, so the session's active workspace ends on it (each `/open` makes\n * its workspace the active one): the selected workspace.\n */\n lastWorkspace?: () => string | null\n}\n\n/**\n * Returns `openAllWorkspaces()`: seal every workspace key the user holds to this server session\n * (`/open` each, sequentially), so a session derived from it (an MCP session copies the browser\n * session's keys) can reach every workspace. Best-effort: a workspace that fails is logged and\n * skipped. Sequential on purpose: the server's per-session key store is a read-modify-write, so\n * parallel opens overwrite each other.\n */\nexport function createAllWorkspacesOpener(deps: OpenAllDeps): () => Promise<void> {\n return async function openAllWorkspaces(): Promise<void> {\n const accessToken = deps.getAccessToken()\n if (!accessToken) return\n await deps.crypto.ensureReady()\n const session = await deps.persistence.getSession()\n if (!session?.signingPrivateKey) return\n const sessionKey = deps.getSessionKey(accessToken)\n if (!sessionKey) return\n const sessionKeyBytes = deps.crypto.fromBase64(sessionKey)\n\n let workspaces: Array<{ external_id: string; wrapped_key?: string | null }> | null\n try {\n workspaces = await deps.listWorkspaces(accessToken)\n } catch {\n return\n }\n const last = deps.lastWorkspace?.() ?? null\n const ordered = [...(workspaces ?? [])].sort(\n (a, b) => Number(a.external_id === last) - Number(b.external_id === last)\n )\n for (const ws of ordered) {\n if (!ws.wrapped_key || !ws.external_id) continue\n try {\n const workspaceKey = deps.unwrapWorkspaceKey(ws.wrapped_key, session.signingPrivateKey)\n const sealed = await deps.crypto.sealKeyForSession(workspaceKey, sessionKeyBytes)\n await deps.workspaceOpenProvider.openWorkspace(accessToken, ws.external_id, sealed)\n } catch (error) {\n console.warn(`[API] Failed to open workspace ${ws.external_id}:`, error)\n }\n }\n }\n}\n","/**\n * The one reader of the access token's claims. Unverified decode: the server signs and checks the\n * token; a client reads it only to know which session it is on and when the token runs out, never\n * to authorize anything.\n */\n\n/** What a client reads from an ARBI access token. */\nexport interface SessionClaims {\n /** The `sk` claim: the session's X25519 public key (base64), which workspace keys are sealed to. */\n sessionKey: string | null\n /** The short id (first 12 characters of `sk`) the session is listed under in `GET /v1/user/sessions`. */\n sessionId: string | null\n /** The `exp` claim in milliseconds since the epoch, or null when the token has none. */\n expiresAt: number | null\n}\n\n/** A JWT's claims, or `null` for a missing, opaque or malformed token. */\nexport function readSessionClaims(token: string | null | undefined): SessionClaims | null {\n const payload = token?.split('.')[1]\n if (!payload) return null\n let claims: unknown\n try {\n const binary = atob(payload.replace(/-/g, '+').replace(/_/g, '/'))\n claims = JSON.parse(\n new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)))\n ) as unknown\n } catch {\n return null\n }\n if (typeof claims !== 'object' || claims === null) return null\n const { sk, exp } = claims as { sk?: unknown; exp?: unknown }\n const sessionKey = typeof sk === 'string' && sk ? sk : null\n return {\n sessionKey,\n sessionId: sessionKey ? sessionKey.slice(0, 12) : null,\n expiresAt: typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : null,\n }\n}\n","/**\n * Opening the account identity with a password (see ../crypto/identity.ts).\n */\n\nimport {\n base64Encode,\n encryptionKeypairFromSigningKey,\n generateUserKeypairs,\n unwrapIdentityKey,\n} from '../crypto'\nimport { getSession } from '../storage'\n\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n return a.length === b.length && a.every((byte, i) => byte === b[i])\n}\n\nfunction encryptionPublicKeyOf(identitySecretKey: Uint8Array): string {\n return base64Encode(encryptionKeypairFromSigningKey(identitySecretKey).publicKey)\n}\n\n/**\n * The identity a password login opened: unwrapped from the response with the password key that signed it (or\n * the password key itself for an account whose password key is its identity). Refuses an identity that is not\n * the account's, so a wrong wrap cannot become the session's key.\n */\nexport function identityFromLoginResponse(\n passwordPrivateKey: Uint8Array,\n response: { wrapped_identity_key?: string | null; user: { encryption_public_key: string } }\n): Uint8Array {\n const identity = unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey)\n if (encryptionPublicKeyOf(identity) !== response.user.encryption_public_key) {\n throw new Error('The account key does not match this account')\n }\n return identity\n}\n\n/**\n * Check a typed password against the signed-in session and return the identity it opens (step-up\n * confirmations, offline unlock). Uses the wrap saved at the last login; throws \"Incorrect password\".\n */\nexport async function unlockIdentityWithPassword(\n email: string,\n password: string,\n deploymentDomain: string\n): Promise<Uint8Array> {\n const session = await getSession()\n if (!session?.signingPrivateKey) throw new Error('No active session found')\n const { signingKeyPair } = await generateUserKeypairs(email, password, deploymentDomain)\n const identity = unwrapIdentityKey(session.wrappedIdentityKey, signingKeyPair.secretKey)\n if (!bytesEqual(identity, session.signingPrivateKey)) throw new Error('Incorrect password')\n return session.signingPrivateKey\n}\n","/**\n * Login flow\n *\n * Signs \"email|timestamp\" (password key, or the identity key itself) → posts to /v1/user/login → opens the\n * identity → saves session\n */\n\nimport type createFetchClient from 'openapi-fetch'\nimport type { components, paths } from '../schema'\nimport type { SessionManager, SessionUser } from '../session'\nimport type { SessionPersistence } from '../relogin/types'\nimport { generateLoginCredentials, generateLoginCredentialsFromKey, base64ToBytes } from '../crypto'\nimport { identityFromLoginResponse } from './identity'\nimport { saveSession } from '../storage'\n\nexport type LoginResponse = components['schemas']['LoginResponse']\n\nexport interface LoginParams {\n email: string\n password: string\n /** An SSO account signs in with its provider's token too (the session is then in SSO mode). */\n ssoToken?: string\n /** Profile fields to use instead of the login response's (a new SSO account's provider name). */\n profile?: Partial<Pick<SessionUser, 'given_name' | 'family_name' | 'picture'>>\n}\n\nexport interface LoginWithKeyParams {\n email: string\n signingPrivateKey: Uint8Array\n ssoToken?: string\n}\n\n/**\n * The host's part of every sign-in (password, key, SSO), around the client's own: `before` runs once\n * the server accepted the login and the identity opened, before anything is stored, so the host can\n * clear the previous user's state; `after` runs once the session is signed in.\n */\nexport interface SignInHooks {\n before?(next: { user: LoginResponse['user'] }): Promise<void> | void\n after?(signedIn: { response: LoginResponse; serverSessionKey: Uint8Array }): void\n}\n\n/** A refused auth request: its message, and the server's `detail` and status for the caller. */\nexport function authRequestError(\n what: string,\n error: unknown,\n status: number | undefined\n): Error & { detail?: unknown; status?: number } {\n const detail =\n typeof error === 'object' && error !== null && 'detail' in error\n ? (error as { detail?: unknown }).detail\n : undefined\n const text = typeof detail === 'string' ? detail : 'Unknown error'\n return Object.assign(new Error(`${what} failed: ${text}`), { detail, status })\n}\n\n/** The signed-in user's profile as the login response carries it. */\nexport interface LoginProfile {\n givenName: string\n familyName: string | null\n /** Avatar image (data URL or URL), when set. */\n picture: string | null\n email: string\n /** True when the account signs in through an SSO provider (the email is managed there). */\n isSso: boolean\n /** Verified tick: passed an ID check under this name, not expired. */\n isIdentityVerified?: boolean\n}\n\nexport interface LoginResult {\n /** The login response itself (workspaces, a pending share, the user). */\n response?: LoginResponse\n accessToken: string\n userExtId?: string\n /** Owner's ext_id for agent accounts; null/undefined for human users */\n parentExtId?: string | null\n /** The profile from the login response, so hosts need no second request for the name. */\n profile?: LoginProfile\n /** The account identity's secret key (the session key material, and the recovery key). */\n signingPrivateKey: Uint8Array\n serverSessionKey: Uint8Array\n}\n\ninterface LoginDeps {\n fetchClient: ReturnType<typeof createFetchClient<paths>>\n session: SessionManager\n deploymentDomain: string\n /** Where the keys are kept (the bundled IndexedDB store by default). */\n persistence?: Pick<SessionPersistence, 'saveSession'>\n signIn?: SignInHooks\n}\n\nexport async function login(params: LoginParams, deps: LoginDeps): Promise<LoginResult> {\n const credentials = await generateLoginCredentials(\n {\n email: params.email,\n sso_token: params.ssoToken,\n },\n params.password,\n deps.deploymentDomain\n )\n\n return performLogin(\n credentials.request,\n { password: credentials.passwordPrivateKey },\n deps,\n params.profile\n )\n}\n\nexport async function loginWithKey(\n params: LoginWithKeyParams,\n deps: LoginDeps\n): Promise<LoginResult> {\n const credentials = generateLoginCredentialsFromKey(\n {\n email: params.email,\n sso_token: params.ssoToken,\n },\n params.signingPrivateKey\n )\n\n return performLogin(credentials.request, { identity: credentials.signingPrivateKey }, deps)\n}\n\nasync function performLogin(\n request: { email: string; signature: string; timestamp: number; sso_token?: string | null },\n signer: { password: Uint8Array } | { identity: Uint8Array },\n deps: LoginDeps,\n profile?: LoginParams['profile']\n): Promise<LoginResult> {\n const response = await deps.fetchClient.POST('/v1/user/login', {\n body: request,\n })\n\n if (response.error || !response.data) {\n throw authRequestError('Login', response.error, response.response?.status)\n }\n\n const data = response.data\n const serverSessionKey = base64ToBytes(data.session_key)\n // Before anything is cleared: a wrap this password does not open must not sign anyone out.\n const signingPrivateKey =\n 'password' in signer ? identityFromLoginResponse(signer.password, data) : signer.identity\n\n // The host clears the previous user's state (this may be someone else) before it is replaced.\n await deps.signIn?.before?.({ user: data.user })\n\n // Save session to IndexedDB\n await (deps.persistence?.saveSession ?? saveSession)({\n signingPrivateKey,\n serverSessionKey,\n userExtId: data.user.external_id ?? undefined,\n wrappedIdentityKey: data.wrapped_identity_key ?? null,\n })\n\n // Sign the session in: token, user, SSO mode and server key at once\n // The address signed in with: a re-login signs `email|timestamp` with it.\n const email = request.email\n deps.session.signIn({\n accessToken: data.access_token,\n isSsoMode: !!request.sso_token,\n serverSessionKey,\n user: {\n ...data.user,\n email,\n given_name: profile?.given_name ?? data.user.given_name ?? email.split('@')[0],\n family_name: profile?.family_name ?? data.user.family_name,\n picture: profile?.picture ?? data.user.picture ?? null,\n parent_ext_id: data.user.parent_ext_id ?? null,\n is_sso: data.user.is_sso ?? false,\n is_identity_verified: data.user.is_identity_verified ?? false,\n },\n })\n deps.signIn?.after?.({ response: data, serverSessionKey })\n\n return {\n response: data,\n accessToken: data.access_token,\n userExtId: data.user.external_id ?? undefined,\n parentExtId: data.user.parent_ext_id ?? null,\n profile: {\n givenName: data.user.given_name,\n familyName: data.user.family_name ?? null,\n picture: data.user.picture ?? null,\n email: data.user.email ?? request.email,\n isSso: data.user.is_sso === true,\n isIdentityVerified: data.user.is_identity_verified === true,\n },\n signingPrivateKey,\n serverSessionKey,\n }\n}\n","/**\n * Registration flow\n *\n * Generates Ed25519 keypair → posts to /v1/user/register\n */\n\nimport type createFetchClient from 'openapi-fetch'\nimport type { paths } from '../schema'\nimport type { SessionManager } from '../session'\nimport { generateRegistrationCredentials } from '../crypto'\nimport { authRequestError } from './login'\n\nexport interface RegisterParams {\n email: string\n password: string\n verificationCode: string\n firstName?: string\n lastName?: string\n picture?: string\n}\n\nexport interface RegisterResult {\n signingPrivateKey: Uint8Array\n}\n\nexport async function register(\n params: RegisterParams,\n deps: {\n fetchClient: ReturnType<typeof createFetchClient<paths>>\n session: SessionManager\n deploymentDomain: string\n }\n): Promise<RegisterResult> {\n const credentials = await generateRegistrationCredentials(\n {\n email: params.email,\n verification_credential: params.verificationCode,\n given_name: params.firstName,\n family_name: params.lastName,\n picture: params.picture,\n },\n params.password,\n deps.deploymentDomain\n )\n\n const response = await deps.fetchClient.POST('/v1/user/register', {\n body: credentials.request,\n })\n\n if (response.error) {\n throw authRequestError('Registration', response.error, response.response?.status)\n }\n\n return { signingPrivateKey: credentials.signingPrivateKey }\n}\n","/**\n * Change password flow\n *\n * The password only wraps the account identity (see ../crypto/identity.ts). Changing it derives the new password\n * key, re-wraps the session's identity under it and posts both to /v1/user/change_password: one request, O(1).\n * Workspace keys, mailbox keys and direct messages stay encrypted to the unchanged identity, so nothing is\n * re-encrypted, nothing can be missed and the other party of a conversation is unaffected. The recovery key\n * (the identity secret key) is unchanged too.\n */\n\nimport type createFetchClient from 'openapi-fetch'\nimport type { paths } from '../schema'\nimport { generatePasswordChangeCredentials } from '../crypto'\nimport { getSession, updateWrappedIdentityKey } from '../storage'\n\nexport interface ChangePasswordParams {\n email: string\n newPassword: string\n /** The current password. Omit in recovery mode: the session's identity key signs instead. */\n currentPassword?: string\n /**\n * The account identity's secret key. Omitted: read from the browser session store, which is then\n * updated with the new wrap (hosts with their own key store pass it and keep `wrappedIdentityKey`).\n */\n identitySecretKey?: Uint8Array\n}\n\nexport interface ChangePasswordResult {\n /** The identity wrapped under the new password key (what a password login now returns). */\n wrappedIdentityKey: string\n}\n\n/** Pull a readable message out of whatever shape a failed call carried (`{ detail }`, `Error`). */\nexport function passwordChangeErrorMessage(err: unknown): string {\n if (err instanceof Error) return err.message\n if (err && typeof err === 'object') {\n const obj = err as Record<string, unknown>\n if (typeof obj.detail === 'string') return obj.detail\n if (typeof obj.message === 'string') return obj.message\n if (Array.isArray(obj.detail)) {\n const msgs = obj.detail\n .map((d) =>\n d && typeof (d as { msg?: unknown }).msg === 'string' ? (d as { msg: string }).msg : null\n )\n .filter((m): m is string => m !== null)\n if (msgs.length) return msgs.join('; ')\n }\n }\n return 'Failed to change password'\n}\n\n/**\n * Change (or, in recovery mode, set) the master password of the signed-in account.\n */\nexport async function changePassword(\n params: ChangePasswordParams,\n deps: { fetchClient: ReturnType<typeof createFetchClient<paths>>; deploymentDomain: string }\n): Promise<ChangePasswordResult> {\n const fromStore = !params.identitySecretKey\n const identitySecretKey = params.identitySecretKey ?? (await getSession())?.signingPrivateKey\n if (!identitySecretKey) throw new Error('Sign in to change your password')\n\n const { request } = await generatePasswordChangeCredentials(\n {\n email: params.email,\n identitySecretKey,\n newPassword: params.newPassword,\n currentPassword: params.currentPassword,\n },\n deps.deploymentDomain\n )\n const response = await deps.fetchClient.POST('/v1/user/change_password', { body: request })\n if (response.error || !response.data)\n throw response.error ?? new Error('Failed to change password')\n\n // The session keeps the identity; only the wrap that a password unlocks offline changes.\n if (fromStore) await updateWrappedIdentityKey(request.wrapped_identity_key)\n return { wrappedIdentityKey: request.wrapped_identity_key }\n}\n","/** Password-verified SSO disconnect. The identity stays fixed; only its password wrap and email change. */\nimport type createFetchClient from 'openapi-fetch'\nimport type { paths } from '../schema'\nimport { generateUserKeypairs, bytesToBase64, signMessage, wrapIdentityKey } from '../crypto'\nimport { updateWrappedIdentityKey } from '../storage'\nimport { unlockIdentityWithPassword } from './identity'\nimport { passwordChangeErrorMessage } from './change-password'\n\n// Narrow contracts for the new endpoints; reuse the app transport and its authentication middleware.\ntype SsoDisconnectPaths = {\n '/v1/user/sso-disconnect-code': {\n post: {\n requestBody: { content: { 'application/json': { new_email: string } } }\n responses: {\n 200: { content: { 'application/json': { detail: string } } }\n 400: { content: { 'application/json': { detail: string } } }\n }\n }\n }\n '/v1/user/disconnect-sso': {\n post: {\n requestBody: {\n content: {\n 'application/json': {\n new_email: string\n verification_code?: string\n timestamp: number\n signature: string\n new_login_key: string\n wrapped_identity_key: string\n }\n }\n }\n responses: {\n 200: { content: { 'application/json': { detail: string; email: string } } }\n 400: { content: { 'application/json': { detail: string } } }\n }\n }\n }\n}\n\nexport interface DisconnectSsoParams {\n email: string\n userExtId: string\n newEmail: string\n password: string\n code?: string\n}\n\ntype DisconnectSsoDeps = {\n fetchClient: ReturnType<typeof createFetchClient<paths>>\n deploymentDomain: string\n}\nconst endpointClient = (client: DisconnectSsoDeps['fetchClient']) =>\n client as unknown as ReturnType<typeof createFetchClient<SsoDisconnectPaths>>\n\n/** Verify a replacement email. Sending a code never changes the account or sign-in method. */\nexport async function requestSsoDisconnectCode(\n newEmail: string,\n deps: Pick<DisconnectSsoDeps, 'fetchClient'>\n): Promise<void> {\n const response = await endpointClient(deps.fetchClient).POST('/v1/user/sso-disconnect-code', {\n body: { new_email: newEmail.trim().toLowerCase() },\n })\n if (response.error) throw new Error(passwordChangeErrorMessage(response.error))\n}\n\n/** Confirm the master password, sign the exact change and preserve the same identity under the new email. */\nexport async function disconnectSso(\n params: DisconnectSsoParams,\n deps: DisconnectSsoDeps\n): Promise<{ email: string }> {\n const email = params.newEmail.trim().toLowerCase()\n const identity = await unlockIdentityWithPassword(\n params.email,\n params.password,\n deps.deploymentDomain\n )\n const current = await generateUserKeypairs(params.email, params.password, deps.deploymentDomain)\n const replacement = await generateUserKeypairs(email, params.password, deps.deploymentDomain)\n const timestamp = Math.floor(Date.now() / 1000)\n const newLoginKey = bytesToBase64(replacement.signingKeyPair.publicKey)\n const wrappedIdentityKey = wrapIdentityKey(identity, replacement.signingKeyPair.secretKey)\n const signature = signMessage(\n `disconnect-sso|${params.userExtId}|${email}|${timestamp}|${newLoginKey}|${wrappedIdentityKey}`,\n current.signingKeyPair.secretKey\n )\n const response = await endpointClient(deps.fetchClient).POST('/v1/user/disconnect-sso', {\n body: {\n new_email: email,\n verification_code: params.code || undefined,\n timestamp,\n signature,\n new_login_key: newLoginKey,\n wrapped_identity_key: wrappedIdentityKey,\n },\n })\n if (response.error) throw new Error(passwordChangeErrorMessage(response.error))\n await updateWrappedIdentityKey(wrappedIdentityKey)\n return { email }\n}\n","/**\n * createArbiClient() — SDK entry point\n *\n * Factory that wires together:\n * - SessionManager (in-memory state)\n * - Crypto providers (libsodium wrappers)\n * - Login / WorkspaceKeyRefresh providers (openapi-fetch transport)\n * - Relogin handler (zero-knowledge re-authentication)\n * - openapi-fetch client with 3 middleware layers\n * - High-level auth methods (register, login, logout, changePassword)\n *\n * Returns an ArbiClient object that SDK consumers interact with.\n */\n\nimport createFetchClient, { type Middleware } from 'openapi-fetch'\nimport { createMemorySessionPersistence } from './memory-persistence'\n\nimport {\n createHttpTransport,\n type HttpTransport,\n type HttpTransportOptions,\n} from './http-transport'\nimport type { paths } from './schema'\nimport {\n createSessionManager,\n createTokenProvider,\n createAuthStateProvider,\n type SessionManager,\n} from './session'\nimport {\n initSodium,\n signMessage,\n sealedBoxDecrypt,\n deriveEncryptionKeypairFromSigning,\n generateRandomSigningKeypair,\n sealKeyForSession,\n base64ToBytes,\n bytesToBase64,\n base64Encode,\n base64Decode,\n sealedBoxEncrypt,\n derivePublicKey,\n computeSharedSecret,\n encryptMessageWithSharedSecret,\n decryptMessageWithSharedSecret,\n encryptMessage,\n decryptMessage,\n generateUserKeypairs,\n unwrapWorkspaceKey,\n encryptionKeypairFromSigningKey,\n} from './crypto'\nimport { createBearerAuthMiddleware } from './middleware/bearer-auth'\nimport {\n createSessionGate,\n createSessionGateMiddleware,\n gatedFetch,\n isAbortError,\n} from './session-gate'\nimport { createWorkspaceKeys, type ListedWorkspaceKey, type WorkspaceKeys } from './workspace-keys'\nimport { createWorkspaceOpens, type WorkspaceOpens } from './workspace-opens'\nimport { createAutoReloginMiddleware } from './middleware/auto-relogin'\nimport { createAllWorkspacesOpener, createReloginHandler, createWorkspaceReopener } from './relogin'\nimport type {\n CryptoProvider,\n LoginProvider,\n OnReloginSuccess,\n ReloginFailure,\n SessionPersistence,\n SsoTokenSource,\n WorkspaceKeyRefreshProvider,\n WorkspaceOpenProvider,\n} from './relogin/types'\nimport { readSessionClaims } from './auth/session-claims'\nimport { clearAllData, getSession, saveSession } from './storage'\nimport {\n register,\n login,\n loginWithKey,\n changePassword,\n unlockIdentityWithPassword,\n type SignInHooks,\n} from './auth'\nimport type {\n RegisterParams,\n RegisterResult,\n LoginParams,\n LoginWithKeyParams,\n LoginResult,\n ChangePasswordParams,\n ChangePasswordResult,\n} from './auth'\n\n// ============================================================================\n// API path prefix — single source of truth for route matching\n// ============================================================================\n\nexport const API_PREFIX = '/v1' as const\n\n// ============================================================================\n// Client options\n// ============================================================================\n\nexport interface ArbiClientOptions {\n /** Shared HTTP adapter, header timeout and metadata hooks; no workspace or retry policy. */\n transport?: HttpTransportOptions\n /**\n * Base URL for the ARBI API (e.g. \"https://api.mydeployment.com\"; `''` for the page's own\n * origin). A function is read on every request: a host whose configuration arrives after the\n * client is made (a runtime config file) passes a getter.\n */\n baseUrl: string | (() => string)\n /** Deployment domain used for deterministic key derivation (e.g. \"mydeployment.com\") */\n deploymentDomain: string | (() => string)\n /** URL patterns that should never trigger re-login */\n reloginExcludePatterns?: string[]\n /** Include credentials (cookies) in requests. Default: true */\n credentials?: RequestCredentials\n /**\n * The session state (token, user, selected workspace, SSO mode), read on every request. Default:\n * an in-memory one. A host app that keeps the session in its own store passes an adapter over it;\n * its `clear()` is called when the session ends (logout, or a re-login the server refused).\n */\n session?: SessionManager\n /**\n * Where the signing key and server session key are kept between page loads. Browsers default to\n * the bundled encrypted IndexedDB store; without IndexedDB the default is per-client memory.\n * Supply an adapter explicitly to persist Node sessions beyond this instance.\n */\n persistence?: SessionPersistence\n /**\n * The workspace a re-login re-opens, when the host's navigation keeps it rather than the session\n * (`session.selectedWorkspaceId`).\n */\n selectedWorkspace?: () => string | null\n /** The SSO provider's token for re-logins of SSO accounts (see `SsoTokenSource`). */\n sso?: SsoTokenSource | null\n /**\n * Extra openapi-fetch middleware, run after the bearer token is added and before the re-login\n * middleware sees the response (e.g. a host's handling of 402 Payment Required).\n */\n middleware?: Middleware[]\n /** The host's part of every sign-in (`SignInHooks`): clear the previous user, then follow up. */\n signIn?: SignInHooks\n /** Optional callback when re-login succeeds */\n onReloginSuccess?: OnReloginSuccess\n /** A request re-logged in but could not be re-sent (its body was already consumed). */\n onRetryCloneFailed?: () => void\n /**\n * Optional user email to seed the in-memory session at creation time.\n * Ensures the auto-relogin middleware can re-authenticate even when\n * the client is constructed from cached credentials (no login call).\n */\n userEmail?: string\n}\n\n// ============================================================================\n// ArbiClient interface\n// ============================================================================\n\nexport interface ArbiClient {\n /** Session-gated HTTP for raw streaming/multipart adapters. Optional for existing host adapters. */\n http?: HttpTransport\n /** Type-safe openapi-fetch client with middleware */\n fetch: ReturnType<typeof createFetchClient<paths>>\n\n /** In-memory session state */\n session: SessionManager\n\n /**\n * The user's workspace keys: the wrapped keys the workspace lists returned (shared by everything\n * on this client), and depositing a workspace's key on the session without opening it. A request\n * refused with 409 `workspace_key_required` primes the workspace it names and is sent again.\n */\n workspaceKeys: WorkspaceKeys\n\n /**\n * Every workspace `/open` on this client, one at a time and in the order asked (the server keeps\n * one active workspace per session, so concurrent opens could leave it on a workspace the client\n * left). The SDK's `selectWorkspace` and the re-opens below all go through it.\n */\n workspaceOpens: WorkspaceOpens\n\n /** High-level auth operations */\n auth: {\n register(params: RegisterParams): Promise<RegisterResult>\n login(params: LoginParams): Promise<LoginResult>\n loginWithKey(params: LoginWithKeyParams): Promise<LoginResult>\n /**\n * Sign out: the server session ends (every session of the user with `everywhere`), the session\n * state is cleared and, with `everywhere`, so are the keys kept on this device. A single sign-out\n * keeps them, so the user can unlock offline. Best-effort on the server: offline still signs out.\n */\n logout(options?: { everywhere?: boolean }): Promise<void>\n /**\n * Sign in on this device with no server (offline): the password must open the identity saved\n * at the last login here. Signed in without a token; the next request online re-logs in.\n * Throws `'no-session'` (nothing saved here) or `'bad-password'`.\n */\n unlock(params: { email: string; password: string }): Promise<void>\n /**\n * After a reload: put the stored server session key back in the session. `false` (and the\n * session cleared) when the session says signed in but this device holds no keys.\n */\n restore(): Promise<boolean>\n changePassword(params: ChangePasswordParams): Promise<ChangePasswordResult>\n /**\n * Silent re-login with the stored key (and the SSO token for an SSO account); re-opens the\n * selected workspace. Concurrent calls share one attempt and a success is reused for 5s. The\n * new token, or `null`. When the server refused it the session is over: `session.clear()` runs\n * and `onSessionExpired` listeners fire. A login still finishing or an unreachable server\n * leaves the session alone.\n */\n relogin(): Promise<string | null>\n /** Re-open the selected workspace on the server session, without a new login */\n reopenWorkspace(): Promise<boolean>\n /**\n * Seal every workspace key the user holds to this server session, so a session derived from it\n * (an MCP session) reaches every workspace. Best-effort.\n */\n openAllWorkspaces(): Promise<void>\n /** Subscribe to \"the session could not be recovered\" (see `relogin`). Returns an unsubscribe. */\n onSessionExpired(listener: () => void): () => void\n /**\n * Subscribe to \"the session is ending\" (`logout`): called once nothing new can start on it and\n * before what is in flight is aborted and the server revokes the token, so a host stops its\n * own work on it (cancels its queries, closes its socket). Returns an unsubscribe.\n */\n onSigningOut(listener: () => void): () => void\n /** A `logout` is under way: no request starts and no re-login runs until it is done. */\n isSigningOut(): boolean\n /**\n * The current session's signal: aborted when a `logout` begins, before the server revokes the\n * token. Hand it to work that must stop with the session (a socket, a stream).\n */\n sessionSignal(): AbortSignal\n }\n\n /** Crypto utilities */\n crypto: {\n initSodium: typeof initSodium\n generateUserKeypairs(email: string, password: string): ReturnType<typeof generateUserKeypairs>\n signMessage: typeof signMessage\n sealedBoxDecrypt: typeof sealedBoxDecrypt\n sealedBoxEncrypt: typeof sealedBoxEncrypt\n sealKeyForSession: typeof sealKeyForSession\n deriveEncryptionKeypairFromSigning: typeof deriveEncryptionKeypairFromSigning\n generateRandomSigningKeypair: typeof generateRandomSigningKeypair\n derivePublicKey: typeof derivePublicKey\n base64ToBytes: typeof base64ToBytes\n bytesToBase64: typeof bytesToBase64\n base64Encode: typeof base64Encode\n base64Decode: typeof base64Decode\n computeSharedSecret: typeof computeSharedSecret\n encryptMessage: typeof encryptMessage\n decryptMessage: typeof decryptMessage\n encryptMessageWithSharedSecret: typeof encryptMessageWithSharedSecret\n decryptMessageWithSharedSecret: typeof decryptMessageWithSharedSecret\n }\n\n /** The same session-key persistence used by login and session recovery. */\n storage: {\n getSession: typeof getSession\n saveSession: typeof saveSession\n }\n}\n\n// ============================================================================\n// Retry wrapper for transient connection errors (ECONNREFUSED, ECONNRESET, etc.)\n// ============================================================================\n\nconst RETRYABLE_CODES = new Set([\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'ETIMEDOUT',\n 'UND_ERR_CONNECT_TIMEOUT',\n])\nconst MAX_RETRIES = 3\nconst BASE_DELAY_MS = 200\n\nfunction isRetryableError(err: unknown): boolean {\n if (!(err instanceof Error) || isAbortError(err)) return false\n // Node/undici errors nest the cause\n const cause = (err as { cause?: { code?: string } }).cause\n if (cause?.code && RETRYABLE_CODES.has(cause.code)) return true\n // Fallback: check message for known patterns\n const msg = err.message || ''\n return RETRYABLE_CODES.has(msg) || msg.includes('ECONNREFUSED') || msg.includes('ECONNRESET')\n}\n\nfunction createRetryFetch(fetch: typeof globalThis.fetch): typeof globalThis.fetch {\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n const maxRetries = method === 'GET' || method === 'HEAD' ? MAX_RETRIES : 0\n const signal = init?.signal ?? (input instanceof Request ? input.signal : undefined)\n let lastError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (signal?.aborted) throw signal.reason ?? new DOMException('Request aborted.', 'AbortError')\n try {\n const fetchInput = input instanceof Request ? input.clone() : input\n return await fetch(fetchInput, init)\n } catch (err) {\n lastError = err\n if (attempt < maxRetries && isRetryableError(err)) {\n await new Promise((r) => setTimeout(r, BASE_DELAY_MS * 2 ** attempt))\n continue\n }\n throw err\n }\n }\n throw lastError\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/** The deployment domain, read when it is used (a host may know it only after its config loaded). */\nconst HTTP_METHODS = ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE'] as const\n\n/** Every call of `fetchClient` goes to the base URL as of the call (openapi-fetch's per-request `baseUrl`). */\nfunction readBaseUrlPerRequest(\n fetchClient: ReturnType<typeof createFetchClient<paths>>,\n base: () => string\n): void {\n type Call = (url: unknown, init?: Record<string, unknown>) => unknown\n const methods = fetchClient as unknown as Record<string, Call> & {\n request: (method: unknown, url: unknown, init?: Record<string, unknown>) => unknown\n }\n for (const method of HTTP_METHODS) {\n const call = methods[method].bind(fetchClient)\n methods[method] = (url, init) => call(url, { ...init, baseUrl: base() })\n }\n const request = methods.request.bind(fetchClient)\n methods.request = (method, url, init) => request(method, url, { ...init, baseUrl: base() })\n}\n\nconst deploymentDomainOf = ({ deploymentDomain }: Pick<ArbiClientOptions, 'deploymentDomain'>) =>\n typeof deploymentDomain === 'function' ? deploymentDomain() : deploymentDomain\n\nexport function createArbiClient(options: ArbiClientOptions): ArbiClient {\n const { fetch, http, session, persistence, workspaceKeys, workspaceOpens, auth } =\n createTransport(options)\n const authDeps = {\n fetchClient: fetch,\n session,\n get deploymentDomain() {\n return deploymentDomainOf(options)\n },\n persistence,\n signIn: options.signIn,\n }\n\n return {\n fetch,\n http,\n workspaceKeys,\n workspaceOpens,\n session,\n\n auth: {\n register: (params) => register(params, authDeps),\n login: (params) => login(params, authDeps),\n loginWithKey: (params) => loginWithKey(params, authDeps),\n changePassword: (params) => changePassword(params, authDeps),\n ...auth,\n },\n\n crypto: {\n initSodium,\n generateUserKeypairs: (email, password) =>\n generateUserKeypairs(email, password, deploymentDomainOf(options)),\n signMessage,\n sealedBoxDecrypt,\n sealedBoxEncrypt,\n sealKeyForSession,\n deriveEncryptionKeypairFromSigning,\n generateRandomSigningKeypair,\n derivePublicKey,\n base64ToBytes,\n bytesToBase64,\n base64Encode,\n base64Decode,\n computeSharedSecret,\n encryptMessage,\n decryptMessage,\n encryptMessageWithSharedSecret,\n decryptMessageWithSharedSecret,\n },\n\n storage: {\n getSession: () => persistence.getSession(),\n saveSession: (data) => persistence.saveSession(data),\n },\n }\n}\n\n/** The session, the fetch client (bearer + host middleware + auto-re-login) and the recovery. */\nfunction createTransport(options: ArbiClientOptions): {\n fetch: ReturnType<typeof createFetchClient<paths>>\n http: HttpTransport\n session: SessionManager\n persistence: SessionPersistence\n workspaceKeys: WorkspaceKeys\n workspaceOpens: WorkspaceOpens\n auth: Pick<\n ArbiClient['auth'],\n | 'relogin'\n | 'reopenWorkspace'\n | 'openAllWorkspaces'\n | 'onSessionExpired'\n | 'onSigningOut'\n | 'isSigningOut'\n | 'sessionSignal'\n | 'logout'\n | 'restore'\n | 'unlock'\n >\n} {\n const {\n reloginExcludePatterns = [`${API_PREFIX}/user/login`, `${API_PREFIX}/user/logout`],\n credentials = 'include',\n sso = null,\n middleware = [],\n onReloginSuccess,\n onRetryCloneFailed,\n userEmail,\n } = options\n // Keep encrypted browser storage; Node/no-IndexedDB clients each own their memory adapter.\n const persistence: SessionPersistence =\n options.persistence ??\n (typeof indexedDB === 'undefined'\n ? createMemorySessionPersistence()\n : { getSession, saveSession, clearSession: clearAllData })\n const baseUrlOption = options.baseUrl\n /** The API base URL as of now. */\n const base = typeof baseUrlOption === 'function' ? baseUrlOption : () => baseUrlOption\n\n // 0. Create retry-aware fetch for resilience against transient connection errors. Every request\n // on the session runs under its gate, so a sign-out stops them before the token is revoked.\n const transport = createHttpTransport(options.transport)\n const retryFetch = createRetryFetch(transport.fetch)\n const gate = createSessionGate()\n const sessionFetch = gatedFetch(gate, retryFetch)\n const http: HttpTransport = {\n fetch: gatedFetch(gate, transport.fetch),\n customFetch: transport.customFetch,\n withFetch: (adapter) => gatedFetch(gate, transport.withFetch(adapter)),\n }\n\n // 1. The session state: the host's, or an in-memory one\n const session = options.session ?? createSessionManager()\n if (userEmail) session.setUser(userEmail)\n\n // 2. Create provider adapters\n const tokenProvider = createTokenProvider(session)\n const authState = createAuthStateProvider(session, options.selectedWorkspace)\n\n // 3. Create CryptoProvider\n const cryptoProvider: CryptoProvider = {\n ensureReady: initSodium,\n signMessage,\n deriveEncryptionKeypair: deriveEncryptionKeypairFromSigning,\n sealedBoxDecrypt,\n sealKeyForSession,\n fromBase64: base64ToBytes,\n }\n\n // 4. Create LoginProvider (raw fetch client for login — no middleware)\n const loginProvider: LoginProvider = {\n async login(payload) {\n const rawFetch = createFetchClient<paths>({\n baseUrl: base(),\n credentials,\n fetch: sessionFetch,\n })\n\n let response\n try {\n response = await rawFetch.POST('/v1/user/login', {\n body: {\n email: payload.email,\n signature: payload.signature,\n timestamp: payload.timestamp,\n sso_token: payload.ssoToken,\n },\n })\n } catch (error) {\n // An outage, not an expired session: the user must not be told to sign in again. (Or a\n // sign-out stopped it: nothing to report.)\n if (!isAbortError(error)) console.warn('[API] Login call unreachable:', error)\n return 'unreachable'\n }\n\n if (response.error || !response.data) {\n console.warn('[API] Login call failed:', response.error)\n return null\n }\n\n const data = response.data\n return {\n accessToken: data.access_token,\n sessionKey: base64ToBytes(data.session_key),\n userExtId: data.user.external_id ?? undefined,\n wrappedIdentityKey: data.wrapped_identity_key ?? null,\n }\n },\n }\n\n async function listWorkspaces(accessToken: string): Promise<ListedWorkspaceKey[] | null> {\n const response = await sessionFetch(`${base()}${API_PREFIX}/user/workspaces`, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n credentials,\n })\n return response.ok ? response.json() : null\n }\n\n // 5. The user's workspace keys: what the lists said, and depositing a key without opening.\n const workspaceKeys = createWorkspaceKeys({\n crypto: cryptoProvider,\n unwrapWorkspaceKey,\n persistence,\n getAccessToken: () => session.getState().accessToken,\n getServerSessionKey: () => session.getState().serverSessionKey,\n listWorkspaces,\n async primeKey(accessToken, workspaceId, sealedKey) {\n const response = await sessionFetch(\n `${base()}${API_PREFIX}/workspace/${workspaceId}/prime-key`,\n {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ workspace_key: sealedKey }),\n credentials,\n }\n )\n if (!response.ok) throw new Error(`Could not unlock the workspace (${response.status})`)\n },\n })\n // Another user's keys are not this one's: forget them when the session ends or changes hands.\n const workspaceOpens = createWorkspaceOpens()\n let keysUser = session.getState().signedIn ? session.getState().userExtId : null\n session.subscribe((state) => {\n const user = state.signedIn ? state.userExtId : null\n if (user !== keysUser) {\n workspaceKeys.clear()\n workspaceOpens.reset()\n }\n keysUser = user\n })\n\n const workspaceKeyRefreshProvider: WorkspaceKeyRefreshProvider = {\n async getWrappedKey(_accessToken, workspaceId) {\n return (await workspaceKeys.wrappedKey(workspaceId).catch(() => null))?.wrappedKey ?? null\n },\n }\n\n // 5b. Re-open provider: POST /open with the workspace key sealed for the session. Only the key\n // matters here, so the response leaves out the documents, conversations and tags.\n const rawWorkspaceOpenProvider: WorkspaceOpenProvider = {\n async openWorkspace(accessToken, workspaceId, encryptedWorkspaceKey) {\n const query = '?include_documents=false&include_conversations=false&include_tags=false'\n try {\n const response = await sessionFetch(\n `${base()}${API_PREFIX}/workspace/${workspaceId}/open${query}`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ workspace_key: encryptedWorkspaceKey }),\n credentials,\n }\n )\n return response.ok ? true : null\n } catch {\n return null\n }\n },\n }\n\n // Every open goes through the queue. A re-login's re-open runs only when no open is queued: the\n // queued ones (re-sent with the new token) leave the server on the latest workspace asked for,\n // and an open waiting behind one that is itself waiting for this re-login would never run.\n const workspaceOpenProvider: WorkspaceOpenProvider = {\n openWorkspace: (accessToken, workspaceId, encryptedWorkspaceKey) =>\n workspaceOpens.busy\n ? Promise.resolve(true)\n : workspaceOpens.run(\n () => workspaceId,\n () =>\n rawWorkspaceOpenProvider.openWorkspace(\n accessToken,\n workspaceId,\n encryptedWorkspaceKey\n )\n ),\n }\n\n // 6. The re-login (re-opens the selected workspace after the new login), the lighter workspace\n // re-opener (token still valid, server lost the open workspace) and the open-all.\n let lastFailure: ReloginFailure | null = null\n const expiredListeners = new Set<() => void>()\n const signingOutListeners = new Set<() => void>()\n const rawRelogin = createReloginHandler({\n crypto: cryptoProvider,\n persistence,\n authState,\n sso,\n loginProvider,\n workspaceKeyRefreshProvider,\n workspaceOpenProvider,\n // The new server session key goes into the session before the token: whatever re-renders on\n // the token reads the key that goes with it.\n async onReloginSuccess(data) {\n session.setServerSessionKey(data.serverSessionKey)\n await onReloginSuccess?.(data)\n },\n onReloginFailed: (reason) => {\n lastFailure = reason\n },\n })\n\n async function relogin(): Promise<string | null> {\n // A session being signed out is not recovered: a new login would outlive the sign-out.\n if (gate.closed) return null\n const tokenBefore = session.getState().accessToken\n const token = await rawRelogin()\n if (token) return token\n // A login that finished while this re-login failed (register then auto-login) put a fresh\n // session in place: retry with it rather than ending the session it just started.\n const tokenNow = session.getState().accessToken\n if (tokenNow && tokenNow !== tokenBefore) return tokenNow\n if (lastFailure === 'refused') {\n // Concurrent callers share one attempt: end the session once.\n lastFailure = null\n session.clear()\n for (const listener of [...expiredListeners]) listener()\n }\n return null\n }\n\n // The re-open reads the selected workspace when its turn comes, so it never re-opens one the\n // host has left meanwhile. Concurrent calls share one attempt.\n const reopenSelected = createWorkspaceReopener({\n crypto: cryptoProvider,\n persistence,\n authState,\n getAccessToken: () => session.getState().accessToken,\n workspaceKeyRefreshProvider,\n workspaceOpenProvider: rawWorkspaceOpenProvider,\n })\n let reopening: Promise<boolean> | null = null\n const reopenWorkspace = (): Promise<boolean> =>\n gate.closed\n ? Promise.resolve(false)\n : (reopening ??= workspaceOpens\n .run(() => authState.getSelectedWorkspaceId(), reopenSelected)\n .finally(() => {\n reopening = null\n }))\n\n const openEveryWorkspace = createAllWorkspacesOpener({\n crypto: cryptoProvider,\n persistence,\n getAccessToken: () => session.getState().accessToken,\n getSessionKey: (accessToken) => readSessionClaims(accessToken)?.sessionKey ?? null,\n unwrapWorkspaceKey,\n listWorkspaces: async (accessToken) => {\n const list = await listWorkspaces(accessToken)\n return list && workspaceKeys.remember(list)\n },\n workspaceOpenProvider: rawWorkspaceOpenProvider,\n lastWorkspace: () => authState.getSelectedWorkspaceId(),\n })\n // One queued open for all of them: nothing else opens in between, and the selected one is last.\n const openAllWorkspaces = () => workspaceOpens.run(() => null, openEveryWorkspace)\n\n // 7. Create openapi-fetch client with middleware\n const fetchClient = createFetchClient<paths>({\n baseUrl: base(),\n credentials,\n fetch: retryFetch,\n })\n if (typeof baseUrlOption === 'function') readBaseUrlPerRequest(fetchClient, base)\n\n // First, so the requests every later middleware sees (and retries) carry the session's signal.\n fetchClient.use(createSessionGateMiddleware(gate))\n fetchClient.use(createBearerAuthMiddleware({ tokenProvider }))\n // openapi-fetch runs onResponse in reverse order: the host's middleware sees a response after\n // the re-login middleware retried it.\n for (const m of middleware) fetchClient.use(m)\n fetchClient.use(\n createAutoReloginMiddleware({\n fetch: sessionFetch,\n reloginHandler: relogin,\n reloginExcludePatterns,\n reopenWorkspaceHandler: reopenWorkspace,\n primeWorkspaceHandler: (workspaceId) =>\n workspaceKeys.prime(workspaceId, { force: true }).then(\n () => true,\n (error: unknown) => {\n console.warn('[API] Could not unlock workspace', workspaceId, error)\n return false\n }\n ),\n onRetryCloneFailed,\n })\n )\n\n return {\n fetch: fetchClient,\n http,\n session,\n persistence,\n workspaceKeys,\n workspaceOpens,\n auth: {\n relogin,\n reopenWorkspace,\n openAllWorkspaces,\n onSigningOut(listener) {\n signingOutListeners.add(listener)\n return () => {\n signingOutListeners.delete(listener)\n }\n },\n isSigningOut: () => gate.closed,\n sessionSignal: () => gate.signal,\n async logout({ everywhere = false } = {}) {\n // The session's work stops BEFORE the server revokes its token: nothing new starts (no\n // request, no re-login, no workspace open), the host stops its own, and what is in flight\n // is aborted. Otherwise it comes back 401 on the revoked token, or a re-login on that 401\n // starts a new server session behind the sign-out.\n gate.close()\n for (const listener of [...signingOutListeners]) {\n try {\n listener()\n } catch (error) {\n console.warn('[API] A sign-out listener failed:', error)\n }\n }\n gate.abort()\n try {\n const accessToken = session.getState().accessToken\n if (accessToken) {\n // Outside the gate (it is closed): the one request of a session being signed out.\n const query = `?all_sessions=${everywhere}`\n await retryFetch(`${base()}${API_PREFIX}/user/logout${query}`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}` },\n credentials,\n }).catch((error: unknown) => console.warn('[API] Server logout failed:', error))\n }\n session.clear()\n if (everywhere) {\n if (persistence.clearSession) await persistence.clearSession()\n else if (typeof indexedDB !== 'undefined') await clearAllData()\n }\n } finally {\n gate.reopen()\n }\n },\n async unlock({ email, password }) {\n const saved = await persistence.getSession()\n if (!saved?.signingPrivateKey) throw new Error('no-session')\n let signingPrivateKey: Uint8Array\n try {\n signingPrivateKey = await unlockIdentityWithPassword(\n email,\n password,\n deploymentDomainOf(options)\n )\n } catch {\n throw new Error('bad-password')\n }\n // The encryption public key the login response would have carried, derived from the key.\n const { publicKey } = encryptionKeypairFromSigningKey(signingPrivateKey)\n session.signIn({\n accessToken: null,\n isSsoMode: false,\n serverSessionKey: saved.serverSessionKey ?? null,\n user: {\n email,\n given_name: email.split('@')[0],\n family_name: null,\n picture: null,\n external_id: saved.userExtId ?? '',\n parent_ext_id: null,\n encryption_public_key: bytesToBase64(publicKey),\n is_sso: false,\n is_identity_verified: false,\n temporary_access_only: false,\n },\n })\n },\n async restore() {\n if (!session.getState().signedIn) return false\n const keys = await persistence.getSession().catch(() => null)\n // A login that finished meanwhile has its own key: leave it.\n if (session.getState().serverSessionKey) return true\n if (keys?.signingPrivateKey && keys.serverSessionKey) {\n session.setServerSessionKey(keys.serverSessionKey)\n return true\n }\n session.clear()\n return false\n },\n onSessionExpired(listener) {\n expiredListeners.add(listener)\n return () => {\n expiredListeners.delete(listener)\n }\n },\n },\n }\n}\n","/**\n * WebSocket helpers — pure functions, no runtime dependencies.\n *\n * Consumers bring their own WebSocket implementation (browser native, Node 22+, ws package).\n * This module provides URL building, auth message creation, typed message parsing,\n * and type guards for the discriminated-union server messages.\n */\n\nimport type { components } from './schema'\nimport { API_PREFIX } from './client'\n\n// ==========================================\n// Type aliases from OpenAPI schema\n// ==========================================\n\nexport type WsAuthMessage = components['schemas']['AuthMessage']\nexport type WsAuthResultMessage = components['schemas']['AuthResultMessage']\nexport type WsTaskUpdateMessage = components['schemas']['TaskUpdateMessage']\nexport type WsBatchCompleteMessage = components['schemas']['BatchCompleteMessage']\nexport type WsConnectionClosedMessage = components['schemas']['ConnectionClosedMessage']\nexport type WsErrorMessage = components['schemas']['ErrorMessage']\nexport type WsPresenceUpdateMessage = components['schemas']['PresenceUpdateMessage']\nexport type WsNotificationResponse = components['schemas']['NotificationResponse']\nexport type WsResponseCompleteMessage = components['schemas']['ResponseCompleteMessage']\n\nexport type WsConversationMessagePostedMessage =\n components['schemas']['ConversationMessagePostedMessage']\nexport type WsChatMessageMessage = components['schemas']['ChatMessageMessage']\nexport type WsChatUpdatedMessage = components['schemas']['ChatUpdatedMessage']\nexport type WsChatReadMessage = components['schemas']['ChatReadMessage']\nexport type WsAgentDmStatusMessage = components['schemas']['AgentDmStatusMessage']\n\n/** Union of all server → client message types (discriminated on `type` field). */\nexport type WebSocketServerMessage =\n | WsTaskUpdateMessage\n | WsAuthResultMessage\n | WsConnectionClosedMessage\n | WsPresenceUpdateMessage\n | WsErrorMessage\n | WsNotificationResponse\n | WsBatchCompleteMessage\n | WsResponseCompleteMessage\n | WsConversationMessagePostedMessage\n | WsChatMessageMessage\n | WsChatUpdatedMessage\n | WsChatReadMessage\n | WsAgentDmStatusMessage\n\n/** Union of all client → server message types. */\nexport type WebSocketClientMessage = WsAuthMessage\n\n// ==========================================\n// Pure helper functions\n// ==========================================\n\n/**\n * Build a WebSocket URL from an HTTP(S) base URL.\n *\n * \"https://box-105.arbibox.com\" → \"wss://box-105.arbibox.com/v1/notifications/ws\"\n * \"http://localhost:8000\" → \"ws://localhost:8000/v1/notifications/ws\"\n */\nexport function buildWebSocketUrl(baseUrl: string): string {\n const wsScheme = baseUrl.startsWith('https') ? 'wss' : 'ws'\n const hostAndPath = baseUrl.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '')\n return `${wsScheme}://${hostAndPath}${API_PREFIX}/notifications/ws`\n}\n\n/**\n * Create the JSON auth message to send after WebSocket connection opens.\n * Returns the serialized JSON string ready to send.\n */\nexport function createAuthMessage(accessToken: string): string {\n const msg: WsAuthMessage = { type: 'auth', token: accessToken }\n return JSON.stringify(msg)\n}\n\n/**\n * Parse a raw WebSocket message string into a typed server message.\n * Returns `null` for unparseable data. Accepts any object with a string `type`\n * field — no hardcoded list of known types, so this stays valid as the schema evolves.\n */\nexport function parseServerMessage(data: string): WebSocketServerMessage | null {\n try {\n const parsed = JSON.parse(data)\n if (typeof parsed === 'object' && parsed !== null && typeof parsed.type === 'string') {\n return parsed as WebSocketServerMessage\n }\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Type guard to narrow a server message to a specific type by its `type` field value.\n *\n * Usage:\n * if (isMessageType(msg, 'task_update')) {\n * // msg is WsTaskUpdateMessage\n * }\n */\nexport function isMessageType<T extends WebSocketServerMessage>(\n msg: WebSocketServerMessage,\n type: T['type']\n): msg is T {\n return msg.type === type\n}\n","/**\n * One console logger for an ARBI frontend and its packages: errors always print; warnings, info\n * and debug lines print only when the host turns verbose logging on (in development, say:\n * `configureLogger({ verbose: import.meta.env.DEV })` at startup). The package never reads a\n * bundler's environment itself.\n */\n\nlet verbose = false\n\nexport interface LoggerOptions {\n /** Print `warn`, `info` and `debug` too. Off by default. */\n verbose: boolean\n}\n\nexport function configureLogger(options: LoggerOptions): void {\n verbose = options.verbose\n}\n\nexport const logger = {\n /** Always printed, production included. */\n error: (...args: unknown[]): void => {\n console.error(...args)\n },\n warn: (...args: unknown[]): void => {\n if (verbose) console.warn(...args)\n },\n info: (...args: unknown[]): void => {\n if (verbose) console.info(...args)\n },\n debug: (...args: unknown[]): void => {\n if (verbose) console.debug(...args)\n },\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/memory-persistence.ts","../src/http-transport.ts","../src/session.ts","../src/crypto/sodium.ts","../src/crypto/call-keys.ts","../src/crypto/chat-keys.ts","../src/crypto/keypairs.ts","../src/crypto/identity.ts","../src/crypto/credentials.ts","../src/crypto/recovery-key.ts","../src/crypto/secure-mail.ts","../src/storage/indexed-db.ts","../src/crypto/offline-sealer.ts","../src/middleware/bearer-auth.ts","../src/session-gate.ts","../src/workspace-keys.ts","../src/workspace-opens.ts","../src/middleware/auto-relogin.ts","../src/middleware/request-dedup.ts","../src/middleware/settings-write-breaker.ts","../src/relogin/handler.ts","../src/relogin/reopen.ts","../src/auth/session-claims.ts","../src/auth/identity.ts","../src/auth/login.ts","../src/auth/register.ts","../src/auth/change-password.ts","../src/auth/disconnect-sso.ts","../src/client.ts","../src/websocket.ts","../src/logger.ts"],"names":["adapter","bytes","sodium","serverSessionKey","stored"],"mappings":"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","file":"index.js","sourcesContent":["import type { SessionKeys, SessionPersistence } from './relogin/types'\n\nfunction copy(keys: SessionKeys): SessionKeys {\n return {\n ...keys,\n signingPrivateKey: keys.signingPrivateKey.slice(),\n ...(keys.serverSessionKey ? { serverSessionKey: keys.serverSessionKey.slice() } : {}),\n }\n}\n\n/** Per-client memory only: no browser globals, files or process-wide shared identity. */\nexport function createMemorySessionPersistence(): SessionPersistence {\n let saved: SessionKeys | null = null\n const clear = () => {\n saved?.signingPrivateKey.fill(0)\n saved?.serverSessionKey?.fill(0)\n saved = null\n }\n return {\n async getSession() {\n return saved ? copy(saved) : null\n },\n async saveSession(keys) {\n const next = copy(keys)\n clear()\n saved = next\n },\n async clearSession() {\n clear()\n },\n }\n}\n","/** HTTP plumbing only: no token, workspace selection, response-body parsing or retries. */\nexport interface HttpRequestInfo {\n readonly method: string\n /** URL without credentials, query or fragment; hooks never receive bodies or headers. */\n readonly url: string\n}\nexport interface HttpResponseInfo extends HttpRequestInfo {\n readonly status: number\n readonly durationMs: number\n}\nexport interface HttpErrorInfo extends HttpRequestInfo {\n readonly error: unknown\n readonly durationMs: number\n}\nexport interface HttpTransportOptions {\n /** Fetch-compatible implementation; defaults to globalThis.fetch at request time. */\n fetch?: typeof globalThis.fetch\n /** Time until the adapter returns a Response (native fetch: headers). Disabled by default. */\n timeoutMs?: number\n onRequest?: (request: HttpRequestInfo) => void\n onResponse?: (response: HttpResponseInfo) => void\n onError?: (failure: HttpErrorInfo) => void\n}\nexport interface HttpTransport {\n readonly fetch: typeof globalThis.fetch\n readonly customFetch: boolean\n /** Use the same timeout/hooks with a specialized adapter, such as upload-progress XHR. */\n withFetch(adapter: typeof globalThis.fetch): typeof globalThis.fetch\n}\n\nexport function createHttpTransport(options: HttpTransportOptions = {}): HttpTransport {\n const { timeoutMs } = options\n if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) {\n throw new RangeError('transport.timeoutMs must be a positive finite number.')\n }\n const wrap =\n (adapter: typeof globalThis.fetch): typeof globalThis.fetch =>\n async (input, init) => {\n const url = new URL(input instanceof Request ? input.url : String(input), 'http://localhost')\n url.username = ''\n url.password = ''\n url.search = ''\n url.hash = ''\n const info: HttpRequestInfo = {\n method: (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase(),\n url: url.toString(),\n }\n options.onRequest?.(info)\n const started = performance.now()\n let timer: ReturnType<typeof setTimeout> | undefined\n let requestInit = init\n if (timeoutMs !== undefined) {\n const controller = new AbortController()\n const own = init?.signal ?? (input instanceof Request ? input.signal : undefined)\n timer = setTimeout(\n () =>\n controller.abort(\n new DOMException('Waiting for HTTP response timed out.', 'TimeoutError')\n ),\n timeoutMs\n )\n requestInit = {\n ...init,\n signal: own ? AbortSignal.any([own, controller.signal]) : controller.signal,\n }\n }\n let response: Response\n try {\n response = await adapter(input, requestInit)\n } catch (error) {\n options.onError?.({ ...info, error, durationMs: performance.now() - started })\n throw error\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n options.onResponse?.({\n ...info,\n status: response.status,\n durationMs: performance.now() - started,\n })\n return response\n }\n const adapter: typeof globalThis.fetch =\n options.fetch ?? ((input, init) => globalThis.fetch(input, init))\n return { fetch: wrap(adapter), customFetch: options.fetch !== undefined, withFetch: wrap }\n}\n","/**\n * SessionManager: the signed-in session's state, the one source the transport, the SDK and a host's\n * UI read: the token, the user, SSO mode, the server session key and whether a login finished.\n *\n * In memory by default. A browser host passes `storage` (`browserSessionStateStorage()`) so the\n * session survives a reload. Implements TokenProvider and AuthStateProvider for the middleware and the\n * re-login, without any framework.\n */\n\nimport type { components } from './schema'\nimport type { TokenProvider } from './middleware/types'\nimport type { AuthStateProvider } from './relogin/types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** The signed-in user as the login returned it (and as profile edits keep it). */\nexport type SessionUser = components['schemas']['UserResponse']\n\nexport interface SessionState {\n accessToken: string | null\n userEmail: string | null\n userExtId: string | null\n selectedWorkspaceId: string | null\n /** The account signs in through SSO: a re-login needs the SSO provider's token. */\n isSsoMode: boolean\n /** The signed-in user; `null` signed out (and for a session seeded with an email only). */\n user: SessionUser | null\n /**\n * A login finished on this device and was not signed out. A new tab (or an offline unlock) is\n * signed in with no token yet: the next request re-logs in.\n */\n signedIn: boolean\n /** This server session's key, which workspace keys are sealed to. In memory only. */\n serverSessionKey: Uint8Array | null\n}\n\n/** What a finished login puts in the session, all at once. */\nexport interface SessionSignIn {\n /** `null` for an offline unlock: no server session yet. */\n accessToken: string | null\n user: SessionUser\n isSsoMode: boolean\n serverSessionKey: Uint8Array | null\n}\n\n/** The part of the session kept across reloads (never the server session key). */\nexport type StoredSessionState = Pick<\n SessionState,\n 'accessToken' | 'userEmail' | 'userExtId' | 'isSsoMode' | 'user' | 'signedIn'\n>\n\n/** Where a browser keeps the session across reloads. */\nexport interface SessionStateStorage {\n load(): Partial<StoredSessionState> | null\n save(state: StoredSessionState): void\n}\n\nexport interface SessionManagerOptions {\n storage?: SessionStateStorage\n}\n\nexport interface SessionManager {\n /** The current state: the same object until something in it changes. */\n getState(): Readonly<SessionState>\n setAccessToken(token: string | null): void\n setUser(email: string, extId?: string): void\n /** Change the signed-in user's fields (a profile edit, a verified tick). */\n updateUser(patch: Partial<SessionUser>): void\n setSelectedWorkspace(id: string | null): void\n setSsoMode(isSsoMode: boolean): void\n setServerSessionKey(key: Uint8Array | null): void\n /** A login finished: token, user, SSO mode and server session key in one change. */\n signIn(session: SessionSignIn): void\n /** The session is over (logout, or it could not be recovered): drop the token and the user. */\n clear(): void\n subscribe(listener: (state: SessionState) => void): () => void\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\nfunction createInitialState(isSsoMode = false): SessionState {\n return {\n accessToken: null,\n userEmail: null,\n userExtId: null,\n selectedWorkspaceId: null,\n isSsoMode,\n user: null,\n signedIn: false,\n serverSessionKey: null,\n }\n}\n\nconst stored = (s: SessionState): StoredSessionState => ({\n accessToken: s.accessToken,\n userEmail: s.userEmail,\n userExtId: s.userExtId,\n isSsoMode: s.isSsoMode,\n user: s.user,\n signedIn: s.signedIn,\n})\n\nexport function createSessionManager(options: SessionManagerOptions = {}): SessionManager {\n const { storage } = options\n let state: SessionState = { ...createInitialState(), ...(storage?.load() ?? {}) }\n const listeners = new Set<(state: SessionState) => void>()\n\n function update(patch: Partial<SessionState>) {\n state = { ...state, ...patch }\n storage?.save(stored(state))\n const snapshot = state\n for (const listener of [...listeners]) listener(snapshot)\n }\n\n return {\n getState: () => state,\n\n setAccessToken: (accessToken) => update({ accessToken }),\n\n setUser(email, extId) {\n update({\n userEmail: email,\n userExtId: extId ?? state.userExtId,\n user: state.user ? { ...state.user, email } : null,\n })\n },\n\n updateUser(patch) {\n if (!state.user) return\n const user = { ...state.user, ...patch }\n update({ user, userEmail: user.email })\n },\n\n setSelectedWorkspace: (selectedWorkspaceId) => update({ selectedWorkspaceId }),\n\n setSsoMode: (isSsoMode) => update({ isSsoMode }),\n\n setServerSessionKey: (serverSessionKey) => update({ serverSessionKey }),\n\n signIn({ accessToken, user, isSsoMode, serverSessionKey }) {\n update({\n accessToken,\n user,\n userEmail: user.email,\n userExtId: user.external_id,\n isSsoMode,\n serverSessionKey,\n signedIn: true,\n })\n },\n\n // The SSO mode outlives a sign-out: it says how this deployment (or this user) signs in.\n clear: () => update(createInitialState(state.isSsoMode)),\n\n subscribe(listener) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n }\n}\n\n/** sessionStorage key of the access token: per tab, so each tab has its own server session. */\nexport const ACCESS_TOKEN_STORAGE_KEY = 'arbi_access_token'\nconst SESSION_STORAGE_KEY = 'arbi_session'\n\n/**\n * The browser's session storage: the access token per tab (sessionStorage), the user and the\n * signed-in flag per browser (localStorage), so a new tab is signed in and re-logs in for a token\n * of its own. The keys themselves stay in the encrypted IndexedDB store (`SessionPersistence`).\n */\nexport function browserSessionStateStorage(namespace?: string): SessionStateStorage {\n // Optional isolation for widgets/extension panels that connect to different deployments.\n // Existing application storage keys and per-tab token semantics stay unchanged.\n const suffix = namespace ? `:${namespace}` : ''\n const sessionKey = SESSION_STORAGE_KEY + suffix\n const accessTokenKey = ACCESS_TOKEN_STORAGE_KEY + suffix\n return {\n load() {\n try {\n const rest = JSON.parse(window.localStorage.getItem(sessionKey) ?? 'null') as Omit<\n StoredSessionState,\n 'accessToken'\n > | null\n const accessToken = window.sessionStorage.getItem(accessTokenKey)\n return { ...(rest ?? {}), accessToken }\n } catch {\n return null\n }\n },\n save({ accessToken, ...rest }) {\n try {\n if (accessToken) window.sessionStorage.setItem(accessTokenKey, accessToken)\n else window.sessionStorage.removeItem(accessTokenKey)\n if (rest.signedIn || rest.isSsoMode)\n window.localStorage.setItem(sessionKey, JSON.stringify(rest))\n else window.localStorage.removeItem(sessionKey)\n } catch {\n // Storage unavailable (private mode, quota): the session lives in memory only.\n }\n },\n }\n}\n\n// ============================================================================\n// Provider adapters\n// ============================================================================\n\n/**\n * Create a TokenProvider from a SessionManager\n */\nexport function createTokenProvider(session: SessionManager): TokenProvider {\n return {\n getAccessToken: () => session.getState().accessToken,\n }\n}\n\n/**\n * Create an AuthStateProvider from a SessionManager\n */\nexport function createAuthStateProvider(\n session: SessionManager,\n selectedWorkspace: () => string | null = () => session.getState().selectedWorkspaceId\n): AuthStateProvider {\n return {\n getUserEmail: () => session.getState().userEmail,\n\n isSsoMode: () => session.getState().isSsoMode,\n\n getSelectedWorkspaceId: selectedWorkspace,\n\n setAccessToken: (token: string) => session.setAccessToken(token),\n }\n}\n","/**\n * Layer 1: Pure libsodium wrappers\n *\n * All low-level cryptographic operations using libsodium-wrappers-sumo.\n * No application logic — just type-safe wrappers around sodium functions.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\nexport interface KeyPair {\n publicKey: Uint8Array\n secretKey: Uint8Array\n}\n\nexport interface UserKeypairs {\n signingKeyPair: KeyPair // Ed25519 for signing/authentication\n encryptionKeyPair: KeyPair // X25519 derived from Ed25519 for encryption\n}\n\n// ============================================================================\n// libsodium initialization\n// ============================================================================\n\nlet sodiumReady: Promise<void> | null = null\n\n/**\n * Initialize sodium library\n */\nexport async function initSodium(): Promise<void> {\n if (sodiumReady) {\n await sodiumReady\n return\n }\n\n sodiumReady = sodium.ready\n await sodiumReady\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Convert base64 string to Uint8Array\n */\nexport function base64ToBytes(base64String: string): Uint8Array {\n return sodium.from_base64(base64String, sodium.base64_variants.ORIGINAL)\n}\n\n/**\n * Convert Uint8Array to base64 string\n */\nexport function bytesToBase64(bytes: Uint8Array): string {\n return sodium.to_base64(bytes, sodium.base64_variants.ORIGINAL)\n}\n\n/**\n * Unpadded base64url (RFC 4648 §5): safe in URL fragments and query strings.\n */\nexport function bytesToBase64Url(bytes: Uint8Array): string {\n return sodium.to_base64(bytes, sodium.base64_variants.URLSAFE_NO_PADDING)\n}\n\n/** Inverse of {@link bytesToBase64Url}. Throws on anything that is not unpadded base64url. */\nexport function base64UrlToBytes(encoded: string): Uint8Array {\n return sodium.from_base64(encoded, sodium.base64_variants.URLSAFE_NO_PADDING)\n}\n\n/**\n * Base64 encode a Uint8Array (for compatibility with existing code)\n */\nexport function base64Encode(bytes: Uint8Array): string {\n const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join('')\n return btoa(binString)\n}\n\n/**\n * Base64 decode to Uint8Array (for compatibility with existing code)\n */\nexport function base64Decode(base64: string): Uint8Array {\n const binString = atob(base64)\n return Uint8Array.from(binString, (m) => m.codePointAt(0) || 0)\n}\n\n// ============================================================================\n// Core Cryptographic Functions\n// ============================================================================\n\n/**\n * Deterministic salt generation for Argon2id\n */\nfunction generateSalt(username: string, deploymentDomain: string): Uint8Array {\n if (!deploymentDomain) {\n throw new Error('Deployment domain must be provided for salt generation')\n }\n const normalized = username.toLowerCase()\n const saltString = `${normalized}|${deploymentDomain}`\n // Use SHA-256 to create a deterministic salt, then take first 16 bytes\n // (Argon2id requires exactly 16 bytes for salt)\n const hash = sodium.crypto_hash_sha256(sodium.from_string(saltString))\n return hash.slice(0, 16) // Return first 16 bytes\n}\n\n/**\n * Generate Ed25519 signing keypair and derive X25519 encryption keypair\n *\n * @param username - User's email/username\n * @param password - User's password\n * @param deploymentDomain - Deployment domain for salt derivation\n * @returns Object with Ed25519 signing keypair and derived X25519 encryption keypair\n */\nexport type DerivedKeyPairs = {\n signing: { publicKey: Uint8Array; privateKey: Uint8Array; publicKeyBase64: string }\n encryption: { publicKey: Uint8Array; privateKey: Uint8Array; publicKeyBase64: string }\n}\n\n// One pre-computed derivation, consumed by the next matching generateKeyPairs().\n// Argon2id is deterministic in (username, password, domain), so it can be started\n// while the user is still on the form and be finished by the time they submit.\n// Single entry, consume-once, short TTL: the password is already held in the form\n// state, and this must not turn into a long-lived credential cache.\nconst PREWARM_TTL_MS = 60_000\nlet prewarmed: {\n id: string\n promise: Promise<DerivedKeyPairs>\n timer: ReturnType<typeof setTimeout>\n} | null = null\n\nfunction prewarmId(username: string, password: string, deploymentDomain: string): string {\n return `${username}\\u0000${deploymentDomain}\\u0000${password}`\n}\n\nfunction dropPrewarmed(): void {\n if (prewarmed) clearTimeout(prewarmed.timer)\n prewarmed = null\n}\n\n/**\n * Start deriving the keypairs for these credentials in the background (best\n * effort — failures are swallowed; the real call will just derive again).\n * A later `generateKeyPairs` with the same arguments awaits this instead of\n * paying for Argon2 again.\n */\nexport function prewarmKeyPairs(\n username: string,\n password: string,\n deploymentDomain: string\n): void {\n if (!username || !password || !deploymentDomain) return\n const id = prewarmId(username, password, deploymentDomain)\n if (prewarmed?.id === id) return\n dropPrewarmed()\n const promise = deriveKeyPairs(username, password, deploymentDomain)\n promise.catch(() => {\n if (prewarmed?.promise === promise) dropPrewarmed()\n })\n prewarmed = { id, promise, timer: setTimeout(dropPrewarmed, PREWARM_TTL_MS) }\n}\n\nexport async function generateKeyPairs(\n username: string,\n password: string,\n deploymentDomain: string\n): Promise<DerivedKeyPairs> {\n if (prewarmed && prewarmed.id === prewarmId(username, password, deploymentDomain)) {\n const { promise } = prewarmed\n dropPrewarmed() // consume once\n try {\n return await promise\n } catch {\n // fall through and derive fresh\n }\n }\n return deriveKeyPairs(username, password, deploymentDomain)\n}\n\nasync function deriveKeyPairs(\n username: string,\n password: string,\n deploymentDomain: string\n): Promise<DerivedKeyPairs> {\n await initSodium()\n\n if (!deploymentDomain) {\n throw new Error('Deployment domain not available. Cannot generate keys.')\n }\n\n // Generate deterministic salt for key derivation\n const salt = generateSalt(username, deploymentDomain)\n\n // Derive seed using Argon2id\n const seed = sodium.crypto_pwhash(\n 32, // 32 bytes for Ed25519 seed\n password,\n salt,\n sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,\n sodium.crypto_pwhash_ALG_ARGON2ID13\n )\n\n // Generate Ed25519 signing keypair from seed\n const signingKeyPair = sodium.crypto_sign_seed_keypair(seed)\n\n // Derive X25519 encryption keypair from Ed25519 keypair\n const encryptionPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(signingKeyPair.publicKey)\n const encryptionPrivateKey = sodium.crypto_sign_ed25519_sk_to_curve25519(\n signingKeyPair.privateKey\n )\n\n return {\n signing: {\n publicKey: signingKeyPair.publicKey,\n privateKey: signingKeyPair.privateKey,\n publicKeyBase64: sodium.to_base64(signingKeyPair.publicKey, sodium.base64_variants.ORIGINAL),\n },\n encryption: {\n publicKey: encryptionPublicKey,\n privateKey: encryptionPrivateKey,\n publicKeyBase64: sodium.to_base64(encryptionPublicKey, sodium.base64_variants.ORIGINAL),\n },\n }\n}\n\n/**\n * Sign a message with Ed25519 private key\n *\n * @param message - Message to sign (string)\n * @param privateKey - Ed25519 private key (64 bytes)\n * @returns Base64-encoded signature\n */\nexport function signMessage(message: string, privateKey: Uint8Array): string {\n const messageBytes = sodium.from_string(message)\n const signature = sodium.crypto_sign_detached(messageBytes, privateKey)\n return base64Encode(signature)\n}\n\n/**\n * Seal a workspace key with the session's X25519 public key (SealedBox).\n * The result is sent to the backend in the /open request body.\n */\nexport async function sealKeyForSession(\n workspaceKey: Uint8Array,\n serverSessionPublicKey: Uint8Array\n): Promise<string> {\n await initSodium()\n return sealedBoxEncrypt(workspaceKey, serverSessionPublicKey)\n}\n\n/**\n * Decrypt data using SealedBox (anonymous decryption).\n *\n * @param encryptedBase64 - Base64-encoded SealedBox encrypted data\n * @param userEncryptionPrivateKey - User's X25519 private key (32 bytes)\n * @returns Decrypted data\n */\nexport function sealedBoxDecrypt(\n encryptedBase64: string,\n userEncryptionPrivateKey: Uint8Array\n): Uint8Array {\n const encrypted = base64ToBytes(encryptedBase64)\n\n // Get the public key from private key for SealedBox\n const publicKey = sodium.crypto_scalarmult_base(userEncryptionPrivateKey)\n\n // Decrypt using SealedBox\n const decrypted = sodium.crypto_box_seal_open(encrypted, publicKey, userEncryptionPrivateKey)\n\n return decrypted\n}\n\n/**\n * Encrypt data using SealedBox (anonymous encryption).\n *\n * @param message - Data to encrypt\n * @param publicKey - Recipient's X25519 public key (32 bytes)\n * @returns Base64-encoded encrypted data\n */\nexport function sealedBoxEncrypt(message: Uint8Array, publicKey: Uint8Array): string {\n // Encrypt using SealedBox\n const encrypted = sodium.crypto_box_seal(message, publicKey)\n\n return bytesToBase64(encrypted)\n}\n\n/**\n * Derive X25519 public key from X25519 private key\n * Used for instant re-login when we have stored private key\n */\nexport function derivePublicKey(privateKey: Uint8Array): Uint8Array {\n return sodium.crypto_scalarmult_base(privateKey)\n}\n\n/**\n * Derive X25519 keypair from Ed25519 keypair\n * Used when we have stored Ed25519 keys and need X25519 for encryption\n */\nexport function deriveEncryptionKeypairFromSigning(signingKeyPair: KeyPair): KeyPair {\n const encryptionPublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(signingKeyPair.publicKey)\n const encryptionPrivateKey = sodium.crypto_sign_ed25519_sk_to_curve25519(signingKeyPair.secretKey)\n return {\n publicKey: encryptionPublicKey,\n secretKey: encryptionPrivateKey,\n }\n}\n\n/**\n * The X25519 encryption keypair of a 64-byte Ed25519 signing secret key (the\n * libsodium layout: 32-byte seed ‖ 32-byte public key). The caller owns the\n * returned secret key and should zero it when done.\n */\nexport function encryptionKeypairFromSigningKey(signingPrivateKey: Uint8Array): KeyPair {\n return deriveEncryptionKeypairFromSigning({\n publicKey: signingPrivateKey.slice(32, 64),\n secretKey: signingPrivateKey,\n })\n}\n\n/**\n * Open a workspace key sealed to the user (`wrapped_key` of `/v1/user/workspaces`)\n * with the user's Ed25519 signing secret key.\n */\nexport function unwrapWorkspaceKey(wrappedKey: string, signingPrivateKey: Uint8Array): Uint8Array {\n const { secretKey } = encryptionKeypairFromSigningKey(signingPrivateKey)\n try {\n return sealedBoxDecrypt(wrappedKey, secretKey)\n } finally {\n secretKey.fill(0)\n }\n}\n\n/**\n * Generate a random Ed25519 signing keypair.\n * Used for agent accounts that don't derive keys from a password.\n */\nexport function generateRandomSigningKeypair(): KeyPair {\n const kp = sodium.crypto_sign_keypair()\n return { publicKey: kp.publicKey, secretKey: kp.privateKey }\n}\n\n// ============================================================================\n// File Encryption (SecretBox envelope for MinIO direct upload)\n// ============================================================================\n\n/**\n * SecretBox-encrypt file bytes with the workspace key.\n *\n * Returns the wire format the server stores in MinIO:\n * `nonce(24) ‖ ciphertext ‖ tag(16)` — byte-for-byte identical to what\n * PyNaCl's `SecretBox(workspace_key).encrypt(raw)` produces and what the\n * server's `decrypt_file` expects. PUT the returned bytes directly to the\n * presigned upload URL returned by `/v1/document/upload-init`.\n */\nexport function encryptFile(raw: Uint8Array, workspaceKey: Uint8Array): Uint8Array {\n const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)\n const cipher = sodium.crypto_secretbox_easy(raw, nonce, workspaceKey)\n const combined = new Uint8Array(nonce.length + cipher.length)\n combined.set(nonce, 0)\n combined.set(cipher, nonce.length)\n return combined\n}\n\n/**\n * SecretBox-decrypt a file body downloaded from MinIO.\n * Input is the same `nonce ‖ ciphertext ‖ tag` wire format that `encryptFile`\n * produces.\n */\nexport function decryptFile(ciphertext: Uint8Array, workspaceKey: Uint8Array): Uint8Array {\n const nonce = ciphertext.slice(0, sodium.crypto_secretbox_NONCEBYTES)\n const cipher = ciphertext.slice(sodium.crypto_secretbox_NONCEBYTES)\n return sodium.crypto_secretbox_open_easy(cipher, nonce, workspaceKey)\n}\n\n/**\n * Workspace-scoped content hash for client-side dedup.\n *\n * HMAC-SHA256(workspace_key, raw_bytes) truncated to 16 hex chars — byte\n * compatible with the server's `create_content_hash` helper. The client\n * sends this to `/v1/document/upload-init` so the server can dedup without\n * ever seeing plaintext.\n */\nexport function createContentHash(content: Uint8Array, workspaceKey: Uint8Array): string {\n const mac = sodium.crypto_auth_hmacsha256(content, workspaceKey)\n let hex = ''\n for (let i = 0; i < mac.length; i++) {\n hex += mac[i].toString(16).padStart(2, '0')\n }\n return hex.slice(0, 16)\n}\n\n// ============================================================================\n// E2E Message Encryption (ECDH + Symmetric)\n// ============================================================================\n\n/**\n * Precompute shared secret for ECDH encryption.\n *\n * Call once per contact, cache for efficiency.\n *\n * @param theirPublicKeyBase64 - Other party's X25519 public key (base64)\n * @param myPrivateKey - Your X25519 private key (Uint8Array)\n * @returns 32-byte shared secret (Uint8Array)\n */\nexport async function computeSharedSecret(\n theirPublicKeyBase64: string,\n myPrivateKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n const theirPublicKey = base64ToBytes(theirPublicKeyBase64)\n return sodium.crypto_box_beforenm(theirPublicKey, myPrivateKey)\n}\n\n/**\n * Encrypt a message using precomputed shared secret.\n *\n * @param message - Plaintext message to encrypt\n * @param sharedSecret - Precomputed 32-byte shared secret\n * @returns Base64-encoded ciphertext (nonce prepended)\n */\nexport async function encryptMessageWithSharedSecret(\n message: string,\n sharedSecret: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const messageBytes = sodium.from_string(message)\n const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES)\n const ciphertext = sodium.crypto_box_easy_afternm(messageBytes, nonce, sharedSecret)\n\n const combined = new Uint8Array(nonce.length + ciphertext.length)\n combined.set(nonce, 0)\n combined.set(ciphertext, nonce.length)\n\n return bytesToBase64(combined)\n}\n\n/**\n * Decrypt a message using precomputed shared secret.\n *\n * @param encryptedBase64 - Base64-encoded ciphertext (nonce prepended)\n * @param sharedSecret - Precomputed 32-byte shared secret\n * @returns Decrypted plaintext message\n */\nexport async function decryptMessageWithSharedSecret(\n encryptedBase64: string,\n sharedSecret: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const combined = base64ToBytes(encryptedBase64)\n const nonce = combined.slice(0, sodium.crypto_box_NONCEBYTES)\n const ciphertext = combined.slice(sodium.crypto_box_NONCEBYTES)\n const decrypted = sodium.crypto_box_open_easy_afternm(ciphertext, nonce, sharedSecret)\n\n return sodium.to_string(decrypted)\n}\n\n/**\n * Encrypt a message for a specific recipient using ECDH (X25519 + XSalsa20-Poly1305).\n *\n * @param message - Plaintext message to encrypt\n * @param recipientPublicKeyBase64 - Recipient's X25519 public key (base64)\n * @param senderPrivateKey - Sender's X25519 private key (Uint8Array)\n * @returns Base64-encoded ciphertext (nonce prepended)\n */\nexport async function encryptMessage(\n message: string,\n recipientPublicKeyBase64: string,\n senderPrivateKey: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const recipientPublicKey = base64ToBytes(recipientPublicKeyBase64)\n const messageBytes = sodium.from_string(message)\n\n // Generate random nonce\n const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES)\n\n // Encrypt using crypto_box (ECDH + XSalsa20-Poly1305)\n const ciphertext = sodium.crypto_box_easy(\n messageBytes,\n nonce,\n recipientPublicKey,\n senderPrivateKey\n )\n\n // Prepend nonce to ciphertext for transmission\n const combined = new Uint8Array(nonce.length + ciphertext.length)\n combined.set(nonce, 0)\n combined.set(ciphertext, nonce.length)\n\n return bytesToBase64(combined)\n}\n\n/**\n * Decrypt a message from a specific sender using ECDH (X25519 + XSalsa20-Poly1305).\n *\n * @param encryptedBase64 - Base64-encoded ciphertext (nonce prepended)\n * @param senderPublicKeyBase64 - Sender's X25519 public key (base64)\n * @param recipientPrivateKey - Recipient's X25519 private key (Uint8Array)\n * @returns Decrypted plaintext message\n * @throws Error if decryption fails (wrong keys or tampered message)\n */\nexport async function decryptMessage(\n encryptedBase64: string,\n senderPublicKeyBase64: string,\n recipientPrivateKey: Uint8Array\n): Promise<string> {\n await initSodium()\n\n const combined = base64ToBytes(encryptedBase64)\n const senderPublicKey = base64ToBytes(senderPublicKeyBase64)\n\n // Extract nonce and ciphertext\n const nonce = combined.slice(0, sodium.crypto_box_NONCEBYTES)\n const ciphertext = combined.slice(sodium.crypto_box_NONCEBYTES)\n\n // Decrypt using crypto_box_open (ECDH + XSalsa20-Poly1305)\n const decrypted = sodium.crypto_box_open_easy(\n ciphertext,\n nonce,\n senderPublicKey,\n recipientPrivateKey\n )\n\n return sodium.to_string(decrypted)\n}\n","/**\n * Call E2EE keys (LiveKit shared-key mode).\n *\n * Every call has one random 32-byte key K, generated in the creator's\n * browser. The server and the SFU never see it:\n * - in a call link it travels in the URL fragment (`#k=<base64url K>&v=<n>`),\n * which browsers never send to the server;\n * - invited / rung ARBI users get K sealed to their X25519 public key\n * (`crypto_box_seal`), stored server-side as an opaque blob;\n * - the call title is XSalsa20-Poly1305 (secretbox) ciphertext under K.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport {\n base64ToBytes,\n base64UrlToBytes,\n bytesToBase64,\n bytesToBase64Url,\n decryptFile,\n encryptFile,\n initSodium,\n sealedBoxDecrypt,\n} from './sodium'\n\nexport const CALL_KEY_BYTES = 32\n\n/** A fresh random call key. */\nexport async function generateCallKey(): Promise<Uint8Array> {\n await initSodium()\n return sodium.randombytes_buf(CALL_KEY_BYTES)\n}\n\n/** Seal K to a user's X25519 public key (base64) → base64 blob only that user can open. */\nexport async function sealCallKey(\n key: Uint8Array,\n recipientPublicKeyBase64: string\n): Promise<string> {\n await initSodium()\n return bytesToBase64(sodium.crypto_box_seal(key, base64ToBytes(recipientPublicKeyBase64)))\n}\n\n/** Open a sealed call key with our X25519 secret key. */\nexport async function openSealedCallKey(\n sealedBase64: string,\n encryptionSecretKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n const key = sealedBoxDecrypt(sealedBase64, encryptionSecretKey)\n if (key.length !== CALL_KEY_BYTES) throw new Error('Sealed call key has the wrong length')\n return key\n}\n\n/** Encrypt a call title under K (base64 of nonce ‖ secretbox). */\nexport async function encryptCallTitle(title: string, key: Uint8Array): Promise<string> {\n await initSodium()\n return bytesToBase64(encryptFile(sodium.from_string(title), key))\n}\n\n/** Decrypt a call title; null when it does not open under K (wrong / rotated key). */\nexport async function decryptCallTitle(\n ciphertext: string,\n key: Uint8Array\n): Promise<string | null> {\n await initSodium()\n try {\n return sodium.to_string(decryptFile(base64ToBytes(ciphertext), key))\n } catch {\n return null\n }\n}\n\n/** K as unpadded base64url (fragment-safe). */\nexport function encodeCallKey(key: Uint8Array): string {\n return bytesToBase64Url(key)\n}\n\n/** Inverse of {@link encodeCallKey}; null for anything that is not a 32-byte key. */\nexport function decodeCallKey(encoded: string): Uint8Array | null {\n if (!/^[A-Za-z0-9_-]+$/.test(encoded)) return null\n try {\n const key = base64UrlToBytes(encoded)\n return key.length === CALL_KEY_BYTES ? key : null\n } catch {\n return null\n }\n}\n\n/** The link fragment (without `#`) carrying K and the link version. */\nexport function buildCallFragment(key: Uint8Array, linkVersion: number): string {\n return `k=${encodeCallKey(key)}&v=${linkVersion}`\n}\n\n/** Parse `#k=…&v=…` (leading `#` optional). Null when there is no valid key. */\nexport function parseCallFragment(\n hash: string\n): { key: Uint8Array; linkVersion: number | null } | null {\n const params = new URLSearchParams(hash.replace(/^#/, ''))\n const encoded = params.get('k')\n if (!encoded) return null\n const key = decodeCallKey(encoded)\n if (!key) return null\n const v = Number(params.get('v'))\n return { key, linkVersion: Number.isInteger(v) && v > 0 ? v : null }\n}\n\n/** `<origin>/call/<id>#k=…&v=…` — the shareable call link (the key travels in the fragment only). */\nexport function buildCallLink(\n origin: string,\n callExtId: string,\n key: Uint8Array,\n linkVersion: number\n): string {\n return `${origin}/call/${callExtId}#${buildCallFragment(key, linkVersion)}`\n}\n\n/** Someone a call key can be sealed to: their user id and X25519 public key (base64). */\nexport interface CallPeer {\n external_id: string\n encryption_public_key?: string | null\n}\n\n/**\n * K sealed to each peer that has an encryption key, by user id. Agents and keyless users are\n * skipped, and so is `exclude` (the caller, who holds K already).\n */\nexport async function sealCallKeyForPeers(\n key: Uint8Array,\n peers: readonly CallPeer[],\n exclude?: string | null\n): Promise<Record<string, string>> {\n const out: Record<string, string> = {}\n for (const peer of peers) {\n if (!peer.encryption_public_key || peer.external_id === exclude) continue\n out[peer.external_id] = await sealCallKey(key, peer.encryption_public_key)\n }\n return out\n}\n\n/**\n * My copy of a call's K from the call row (`my_sealed_key`, sealed to me as its creator or an\n * invitee); null when I have none or it does not open.\n */\nexport async function openCallKeyOf(\n call: { my_sealed_key?: string | null },\n encryptionSecretKey: Uint8Array\n): Promise<Uint8Array | null> {\n if (!call.my_sealed_key) return null\n try {\n return await openSealedCallKey(call.my_sealed_key, encryptionSecretKey)\n } catch {\n return null\n }\n}\n","/**\n * Chat keys (`/v1/chats`). Every chat message, title and attachment manifest is\n * `base64(nonce ‖ secretbox(plaintext, chat key))`. The server never sees a chat key.\n *\n * - `direct` chat: the key is the two users' X25519 pair key,\n * `crypto_box_beforenm(peer_pk, my_sk)` (a self-chat uses my own public key).\n * `crypto_box_easy` is exactly `secretbox` under that key, so every legacy DM\n * ciphertext opens here unchanged.\n * - `group` / `meeting` chat: a random 32-byte key per epoch, sealed\n * (`crypto_box_seal`) to each member.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport {\n base64ToBytes,\n bytesToBase64,\n decryptFile,\n encryptFile,\n initSodium,\n sealedBoxDecrypt,\n} from './sodium'\n\nexport const CHAT_KEY_BYTES = 32\n\n/** The direct-chat key shared with `peerPublicKeyBase64` (my own public key for a self-chat). */\nexport async function deriveDirectChatKey(\n peerPublicKeyBase64: string,\n mySecretKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n return sodium.crypto_box_beforenm(base64ToBytes(peerPublicKeyBase64), mySecretKey)\n}\n\n/** A fresh random group/meeting epoch key. */\nexport async function generateChatKey(): Promise<Uint8Array> {\n await initSodium()\n return sodium.randombytes_buf(CHAT_KEY_BYTES)\n}\n\n/** Seal an epoch key to a member's X25519 public key (base64). */\nexport async function sealChatKey(key: Uint8Array, publicKeyBase64: string): Promise<string> {\n await initSodium()\n return bytesToBase64(sodium.crypto_box_seal(key, base64ToBytes(publicKeyBase64)))\n}\n\n/** Open an epoch key sealed to me. Throws when it is not mine or not a chat key. */\nexport async function openSealedChatKey(\n sealedBase64: string,\n mySecretKey: Uint8Array\n): Promise<Uint8Array> {\n await initSodium()\n const key = sealedBoxDecrypt(sealedBase64, mySecretKey)\n if (key.length !== CHAT_KEY_BYTES) throw new Error('Sealed chat key has the wrong length')\n return key\n}\n\n/** Encrypt UTF-8 text under a chat key → base64(nonce ‖ secretbox). */\nexport async function encryptWithChatKey(plaintext: string, key: Uint8Array): Promise<string> {\n await initSodium()\n return bytesToBase64(encryptFile(sodium.from_string(plaintext), key))\n}\n\n/** Decrypt base64(nonce ‖ secretbox) under a chat key. Throws on a wrong key or tampering. */\nexport async function decryptWithChatKey(ciphertext: string, key: Uint8Array): Promise<string> {\n await initSodium()\n return sodium.to_string(decryptFile(base64ToBytes(ciphertext), key))\n}\n","/**\n * Layer 2: User keypair generation\n *\n * Generates Ed25519 signing and X25519 encryption keypairs from email + password.\n * Takes `deploymentDomain` as an explicit parameter (no window.RUNTIME_CONFIG).\n */\n\nimport { generateKeyPairs, type KeyPair, type UserKeypairs } from './sodium'\n\n/**\n * Generate user keypairs deterministically using Argon2id.\n *\n * Creates Ed25519 signing keypair and derives X25519 encryption keypair.\n * Ed25519 is used for authentication (signing), X25519 for encryption.\n *\n * This is a zero-knowledge system - the server never sees private keys.\n *\n * @param username - User's email/username\n * @param password - User's password\n * @param deploymentDomain - Deployment domain (used for salt derivation)\n * @returns Object with Ed25519 signing keypair and X25519 encryption keypair\n */\nexport async function generateUserKeypairs(\n username: string,\n password: string,\n deploymentDomain: string\n): Promise<UserKeypairs> {\n if (!deploymentDomain) {\n throw new Error('Deployment domain must be provided. Cannot generate keypairs.')\n }\n\n // Generate keypairs using the libsodium implementation\n const keypairs = await generateKeyPairs(username, password, deploymentDomain)\n\n const signingKeyPair: KeyPair = {\n publicKey: keypairs.signing.publicKey,\n secretKey: keypairs.signing.privateKey,\n }\n\n const encryptionKeyPair: KeyPair = {\n publicKey: keypairs.encryption.publicKey,\n secretKey: keypairs.encryption.privateKey,\n }\n\n return {\n signingKeyPair,\n encryptionKeyPair,\n }\n}\n","/**\n * The account identity and the password key that wraps it.\n *\n * The identity is a fixed Ed25519 keypair (its X25519 form is what workspace keys, mailbox keys and direct\n * messages are encrypted to). The password derives a separate \"password key\" (Argon2id, `generateUserKeypairs`)\n * that signs password logins and wraps the identity's secret key. Changing the password re-wraps the identity\n * and re-encrypts nothing.\n *\n * Accounts registered before this existed have no wrap: their password key IS the identity\n * (`wrapped_identity_key` is null in the login response).\n *\n * Same scheme as the Python SDK (`arbi_client.sdk.crypto`): BLAKE2b-256 keyed by the password key's seed over\n * a fixed context gives a SecretBox key; the wrap is base64 of `nonce(24) ‖ secretbox(identity secret key)`.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport { base64Decode, base64Encode, generateRandomSigningKeypair, type KeyPair } from './sodium'\n\nconst IDENTITY_WRAP_CONTEXT = 'arbi-identity-wrap-v1'\n\n/** The SecretBox key a password key wraps the identity under. Exported for the cross-implementation test. */\nexport function identityWrappingKey(passwordSecretKey: Uint8Array): Uint8Array {\n return sodium.crypto_generichash(\n 32,\n sodium.from_string(IDENTITY_WRAP_CONTEXT),\n passwordSecretKey.slice(0, 32)\n )\n}\n\n/** A fresh random identity (Ed25519; secretKey is the 64-byte form). */\nexport function generateIdentityKeypair(): KeyPair {\n return generateRandomSigningKeypair()\n}\n\n/** Wrap the identity's 64-byte Ed25519 secret key under a password key. */\nexport function wrapIdentityKey(\n identitySecretKey: Uint8Array,\n passwordSecretKey: Uint8Array\n): string {\n const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)\n const key = identityWrappingKey(passwordSecretKey)\n try {\n const boxed = sodium.crypto_secretbox_easy(identitySecretKey, nonce, key)\n const out = new Uint8Array(nonce.length + boxed.length)\n out.set(nonce)\n out.set(boxed, nonce.length)\n return base64Encode(out)\n } finally {\n key.fill(0)\n }\n}\n\n/**\n * The identity's 64-byte Ed25519 secret key a password key opens: unwrapped from `wrapped`, or the password key\n * itself when nothing is wrapped. Throws when the password key does not open the wrap (a wrong password).\n */\nexport function unwrapIdentityKey(\n wrapped: string | null | undefined,\n passwordSecretKey: Uint8Array\n): Uint8Array {\n if (!wrapped) return passwordSecretKey\n const bytes = base64Decode(wrapped)\n const nonce = bytes.slice(0, sodium.crypto_secretbox_NONCEBYTES)\n const key = identityWrappingKey(passwordSecretKey)\n try {\n return sodium.crypto_secretbox_open_easy(\n bytes.slice(sodium.crypto_secretbox_NONCEBYTES),\n nonce,\n key\n )\n } catch {\n throw new Error('Incorrect password')\n } finally {\n key.fill(0)\n }\n}\n","/**\n * Layer 3: High-level credential generation\n *\n * Generates registration, login, and password-change credentials.\n * Uses inline type definitions (structurally identical to OpenAPI schema types)\n * to avoid coupling the crypto module to the schema file.\n *\n * Two keys are in play (see ./identity.ts): the account identity, a fixed random Ed25519 keypair, and the\n * password key, derived from email + password, which signs password logins and wraps the identity.\n */\n\nimport { signMessage, base64Encode } from './sodium'\nimport { generateUserKeypairs } from './keypairs'\nimport { generateIdentityKeypair, wrapIdentityKey } from './identity'\n\n// ============================================================================\n// Inline types (structurally identical to OpenAPI schema equivalents)\n// ============================================================================\n\nexport interface RegisterRequest {\n email: string\n signing_key: string\n login_key?: string | null\n wrapped_identity_key?: string | null\n verification_credential: string\n given_name?: string | null\n family_name?: string | null\n picture?: string | null\n}\n\nexport interface LoginRequest {\n email: string\n signature: string\n timestamp: number\n sso_token?: string | null\n}\n\nexport interface ChangePasswordRequest {\n signature: string\n timestamp: number\n new_login_key: string\n wrapped_identity_key: string\n}\n\n// ============================================================================\n// Credential types\n// ============================================================================\n\n/**\n * Credentials returned by generate functions.\n * Contains both the backend request AND client-side private keys.\n * Private keys never leave the client.\n */\nexport interface RegistrationCredentials {\n request: RegisterRequest\n /** The new account's identity secret key (what the session keeps, and the recovery key). */\n signingPrivateKey: Uint8Array\n}\n\nexport interface LoginCredentials {\n request: LoginRequest\n /**\n * The password key that signed the request. Not the identity: open it from the response with\n * `unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey)`.\n */\n passwordPrivateKey: Uint8Array\n}\n\nexport interface KeyLoginCredentials {\n request: LoginRequest\n /** The identity secret key that signed the request (recovery key, session re-login). */\n signingPrivateKey: Uint8Array\n}\n\nexport interface PasswordChangeCredentials {\n request: ChangePasswordRequest\n}\n\n// ============================================================================\n// Credential generation functions\n// ============================================================================\n\nfunction signedNow(email: string, key: Uint8Array): { signature: string; timestamp: number } {\n const timestamp = Math.floor(Date.now() / 1000)\n return { signature: signMessage(`${email}|${timestamp}`, key), timestamp }\n}\n\n/**\n * Generate registration credentials: a random identity, wrapped under the password key.\n *\n * The server stores the identity public key (signing_key, and the X25519 key it derives from it), the password\n * key (login_key) and the wrapped identity.\n */\nexport async function generateRegistrationCredentials(\n registrationData: Omit<RegisterRequest, 'signing_key' | 'login_key' | 'wrapped_identity_key'>,\n password: string,\n deploymentDomain: string\n): Promise<RegistrationCredentials> {\n const { signingKeyPair: passwordKey } = await generateUserKeypairs(\n registrationData.email,\n password,\n deploymentDomain\n )\n const identity = generateIdentityKeypair()\n\n const request: RegisterRequest = {\n ...registrationData,\n signing_key: base64Encode(identity.publicKey),\n login_key: base64Encode(passwordKey.publicKey),\n wrapped_identity_key: wrapIdentityKey(identity.secretKey, passwordKey.secretKey),\n }\n\n return { request, signingPrivateKey: identity.secretKey }\n}\n\n/**\n * Generate password-login credentials: derive the password key and sign \"email|timestamp\" with it.\n */\nexport async function generateLoginCredentials(\n loginData: Omit<LoginRequest, 'signature' | 'timestamp'>,\n password: string,\n deploymentDomain: string\n): Promise<LoginCredentials> {\n const { signingKeyPair } = await generateUserKeypairs(loginData.email, password, deploymentDomain)\n return {\n request: { ...loginData, ...signedNow(loginData.email, signingKeyPair.secretKey) },\n passwordPrivateKey: signingKeyPair.secretKey,\n }\n}\n\n/**\n * Generate login credentials signed by the identity key itself (recovery key, session re-login).\n */\nexport function generateLoginCredentialsFromKey(\n loginData: Omit<LoginRequest, 'signature' | 'timestamp'>,\n signingPrivateKey: Uint8Array\n): KeyLoginCredentials {\n if (signingPrivateKey.length !== 64) {\n throw new Error('Invalid signing key: must be exactly 64 bytes')\n }\n return {\n request: { ...loginData, ...signedNow(loginData.email, signingPrivateKey) },\n signingPrivateKey,\n }\n}\n\n/**\n * Generate a password change: the identity is kept, re-wrapped under the new password key.\n *\n * Signed with the current password key when `currentPassword` is given (proves it), else with the identity key\n * (recovery: the user signed in with the recovery key and no longer knows the password).\n */\nexport async function generatePasswordChangeCredentials(\n params: {\n email: string\n identitySecretKey: Uint8Array\n newPassword: string\n currentPassword?: string\n },\n deploymentDomain: string\n): Promise<PasswordChangeCredentials> {\n const signer = params.currentPassword\n ? (await generateUserKeypairs(params.email, params.currentPassword, deploymentDomain))\n .signingKeyPair.secretKey\n : params.identitySecretKey\n const { signingKeyPair: newPasswordKey } = await generateUserKeypairs(\n params.email,\n params.newPassword,\n deploymentDomain\n )\n return {\n request: {\n ...signedNow(params.email, signer),\n new_login_key: base64Encode(newPasswordKey.publicKey),\n wrapped_identity_key: wrapIdentityKey(params.identitySecretKey, newPasswordKey.secretKey),\n },\n }\n}\n","/**\n * Recovery keys.\n *\n * The recovery key is the account's 64-byte Ed25519 signing secret key. It reaches the user as a\n * recovery link, `<origin>/recover?email=…[&sso=1]#KEY=<base64url bytes>` — the key travels in the\n * URL fragment, which browsers never send to a server — saved to a password manager or downloaded\n * inside a one-link HTML file.\n *\n * For SSO users the key is first wrapped with their Auth0 `sub`, so the link is useless without\n * also completing the SSO login: `nonce(24) ‖ secretbox(signing key, SHA-256(sub))`, 104 bytes.\n *\n * Older recovery files hold the raw bytes (64 plain, 104 SSO-wrapped); both are still accepted.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport { base64UrlToBytes, bytesToBase64Url, decryptFile, encryptFile, initSodium } from './sodium'\n\n/** Raw Ed25519 signing secret key. */\nexport const UNENCRYPTED_RECOVERY_KEY_SIZE = 64\n/** 24 (nonce) + 64 (key) + 16 (auth tag). */\nexport const ENCRYPTED_RECOVERY_KEY_SIZE = 104\n\n/** The error strings of the recovery flow. */\nexport const RECOVERY_KEY_ERRORS = {\n INVALID_SIZE: `Invalid recovery key: file must be ${UNENCRYPTED_RECOVERY_KEY_SIZE} or ${ENCRYPTED_RECOVERY_KEY_SIZE} bytes`,\n INVALID_FORMAT: 'Invalid recovery key format',\n READ_ERROR: 'Failed to read recovery key file',\n AUTH_FAILED: 'Recovery key does not match this account',\n ENCRYPTED_KEY_REQUIRES_SSO:\n 'This recovery key is encrypted with your SSO identity. Please use SSO login and then click \"Forgot Password\" to use this key.',\n DECRYPTION_FAILED:\n 'Failed to decrypt recovery key. This key may belong to a different SSO account.',\n} as const\n\nfunction assertSigningKey(signingPrivateKey: Uint8Array): void {\n if (signingPrivateKey.length !== UNENCRYPTED_RECOVERY_KEY_SIZE) {\n throw new Error('Invalid signing key: must be exactly 64 bytes')\n }\n}\n\n/** The secretbox key of an SSO recovery key: SHA-256 of the Auth0 `sub`. */\nfunction ssoWrappingKey(auth0Sub: string): Uint8Array {\n return sodium.crypto_hash_sha256(sodium.from_string(auth0Sub))\n}\n\n/** Wrap the signing key with the user's Auth0 `sub` (104 bytes: nonce ‖ secretbox). */\nexport async function encryptRecoveryKey(\n signingPrivateKey: Uint8Array,\n auth0Sub: string\n): Promise<Uint8Array> {\n await initSodium()\n assertSigningKey(signingPrivateKey)\n return encryptFile(signingPrivateKey, ssoWrappingKey(auth0Sub))\n}\n\n/** Unwrap an SSO recovery key. Throws when it belongs to another account or is damaged. */\nexport async function decryptRecoveryKey(\n encryptedKey: Uint8Array,\n auth0Sub: string\n): Promise<Uint8Array> {\n await initSodium()\n if (encryptedKey.length !== ENCRYPTED_RECOVERY_KEY_SIZE) {\n throw new Error(`Invalid encrypted key: expected ${ENCRYPTED_RECOVERY_KEY_SIZE} bytes`)\n }\n try {\n return decryptFile(encryptedKey, ssoWrappingKey(auth0Sub))\n } catch {\n throw new Error(RECOVERY_KEY_ERRORS.DECRYPTION_FAILED)\n }\n}\n\n/** Whether recovery key bytes of this length are SSO-wrapped. */\nexport function isEncryptedRecoveryKey(byteLength: number): boolean {\n return byteLength === ENCRYPTED_RECOVERY_KEY_SIZE\n}\n\n/** A timestamped name for the downloadable recovery file. */\nexport function getRecoveryKeyFilename(): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)\n return `arbi-recovery-${timestamp}.html`\n}\n\n/**\n * The recovery link for already-prepared key bytes (raw, or SSO-wrapped with `sso`). The email\n * goes in the query (it is visible during a normal login anyway); the key goes in the fragment.\n */\nexport function buildRecoveryUrl(args: {\n origin: string\n email: string\n keyBytes: Uint8Array\n sso: boolean\n}): string {\n const params = new URLSearchParams({ email: args.email })\n if (args.sso) params.set('sso', '1')\n return `${args.origin}/recover?${params.toString()}#KEY=${bytesToBase64Url(args.keyBytes)}`\n}\n\n/** A parsed recovery link. `isEncrypted`: the key is SSO-wrapped and needs the SSO login. */\nexport interface ParsedRecoveryUrl {\n email: string\n recoveryKey: Uint8Array\n isEncrypted: boolean\n}\n\n/** Read a recovery link's query and fragment. Null when it carries no email or no valid key. */\nexport function parseRecoveryUrl(search: string, hash: string): ParsedRecoveryUrl | null {\n const params = new URLSearchParams(search)\n const email = params.get('email')\n const keyMatch = /(?:^#|[&#])KEY=([A-Za-z0-9_-]+)/.exec(hash)\n if (!email || !keyMatch) return null\n try {\n return {\n email,\n recoveryKey: base64UrlToBytes(keyMatch[1]),\n isEncrypted: params.get('sso') === '1',\n }\n } catch {\n return null\n }\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\n/** The single-page HTML recovery file: one link to `url`, no external assets. */\nfunction buildRecoveryHtml(args: { email: string; url: string; ssoEncrypted: boolean }): string {\n const email = escapeHtml(args.email)\n const url = escapeHtml(args.url)\n const ssoNote = args.ssoEncrypted\n ? '<p class=\"note\">This recovery file is encrypted with your SSO identity — opening it on a different account will not work.</p>'\n : ''\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>ARBI Recovery</title>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<style>\n :root { color-scheme: light dark; }\n body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n max-width: 32rem; margin: 4rem auto; padding: 1.5rem; line-height: 1.5; }\n h1 { font-size: 1.25rem; margin-bottom: 0.25rem; }\n .email { font-weight: 600; }\n .btn { display: inline-block; padding: 0.75rem 1.25rem; margin-top: 1.5rem;\n background: #2563eb; color: #fff; text-decoration: none;\n border-radius: 0.5rem; font-weight: 600; }\n .btn:hover { background: #1d4ed8; }\n .note { font-size: 0.85rem; color: #6b7280; margin-top: 1.5rem; }\n details { margin-top: 1rem; font-size: 0.85rem; color: #6b7280; }\n code { word-break: break-all; }\n</style>\n</head>\n<body>\n <h1>ARBI account recovery</h1>\n <p>Click below to set a new password for <span class=\"email\">${email}</span>.</p>\n <p><a class=\"btn\" href=\"${url}\">Recover account</a></p>\n ${ssoNote}\n <details>\n <summary>If the button doesn't work, open this URL manually</summary>\n <p><code>${url}</code></p>\n </details>\n</body>\n</html>\n`\n}\n\n/** What a recovery link or file is made from. With `auth0Sub` the key is SSO-wrapped first. */\nexport interface RecoveryKeyParams {\n signingPrivateKey: Uint8Array\n email: string\n /** The app origin the link opens, e.g. `window.location.origin`. */\n origin: string\n auth0Sub?: string | null\n}\n\n/** The recovery link for an account (to save in a password manager, or inside the file). */\nexport async function createRecoveryUrl(params: RecoveryKeyParams): Promise<string> {\n assertSigningKey(params.signingPrivateKey)\n const keyBytes = params.auth0Sub\n ? await encryptRecoveryKey(params.signingPrivateKey, params.auth0Sub)\n : params.signingPrivateKey\n return buildRecoveryUrl({\n origin: params.origin,\n email: params.email,\n keyBytes,\n sso: !!params.auth0Sub,\n })\n}\n\n/** The downloadable recovery file: an HTML page holding the recovery link. */\nexport async function createRecoveryFile(\n params: RecoveryKeyParams\n): Promise<{ filename: string; html: string; url: string }> {\n const url = await createRecoveryUrl(params)\n return {\n filename: getRecoveryKeyFilename(),\n html: buildRecoveryHtml({ email: params.email, url, ssoEncrypted: !!params.auth0Sub }),\n url,\n }\n}\n\n/** The result of reading an uploaded raw recovery key file. */\nexport interface RecoveryKeyValidationResult {\n valid: boolean\n /** The key is SSO-wrapped. */\n isEncrypted: boolean\n /** The raw file bytes (wrapped or not). */\n data: Uint8Array | null\n error?: string\n}\n\n/** Read an uploaded raw recovery key file: 64 bytes (plain) or 104 (SSO-wrapped). */\nexport async function validateRecoveryKeyFile(file: Blob): Promise<RecoveryKeyValidationResult> {\n if (file.size !== UNENCRYPTED_RECOVERY_KEY_SIZE && file.size !== ENCRYPTED_RECOVERY_KEY_SIZE) {\n return {\n valid: false,\n isEncrypted: false,\n data: null,\n error: RECOVERY_KEY_ERRORS.INVALID_SIZE,\n }\n }\n try {\n const data = new Uint8Array(await file.arrayBuffer())\n return { valid: true, isEncrypted: isEncryptedRecoveryKey(data.length), data }\n } catch {\n return { valid: false, isEncrypted: false, data: null, error: RECOVERY_KEY_ERRORS.READ_ERROR }\n }\n}\n","/**\n * Secure mail delivery (`/v1/mail/secure`).\n *\n * The sender's browser builds the MIME message and seals it under a fresh random 32-byte message\n * key: `ciphertext` and `metadata_ciphertext` are each `base64(nonce ‖ secretbox(bytes, key))`. The\n * key reaches each recipient only in the link fragment (`fragment_key`), and the sender keeps it\n * sealed to their own X25519 public key (`sender_wrapped_key`). To claim a message the recipient\n * proves they hold the key (`claim_hash` = hex SHA-256 of it) and re-seals it to themselves.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport {\n base64ToBytes,\n bytesToBase64,\n decryptFile,\n encryptFile,\n initSodium,\n sealedBoxEncrypt,\n} from './sodium'\n\nexport const SECURE_MAIL_KEY_BYTES = 32\n\n/** The encrypted parts of a secure message, as `/secure/send` takes and `/secure/{id}` returns. */\nexport interface SecureMailCiphertexts {\n ciphertext: string\n metadata_ciphertext: string\n}\n\n/** A sealed message plus the key material the send request needs. */\nexport interface SealedSecureMail extends SecureMailCiphertexts {\n /** The message key, base64 — sent to recipients in the link fragment only. */\n fragment_key: string\n /** The message key sealed to the sender. */\n sender_wrapped_key: string\n}\n\n/** What the recipient posts to `/secure/{id}/claim`. */\nexport interface SecureMailClaim {\n claim_hash: string\n wrapped_key: string\n recipient_public_key: string\n}\n\n/**\n * Seal a raw MIME message and its JSON metadata under a fresh message key, and seal the key to the\n * sender. The key is zeroed before returning; only its base64 `fragment_key` remains.\n */\nexport async function sealSecureMail(\n raw: Uint8Array,\n metadata: unknown,\n senderPublicKey: Uint8Array\n): Promise<SealedSecureMail> {\n await initSodium()\n const key = sodium.randombytes_buf(SECURE_MAIL_KEY_BYTES)\n try {\n return {\n ciphertext: bytesToBase64(encryptFile(raw, key)),\n metadata_ciphertext: bytesToBase64(\n encryptFile(sodium.from_string(JSON.stringify(metadata)), key)\n ),\n fragment_key: bytesToBase64(key),\n sender_wrapped_key: sealedBoxEncrypt(key, senderPublicKey),\n }\n } finally {\n key.fill(0)\n }\n}\n\n/** The message key carried in a secure-mail link. Throws when it is not a 32-byte key. */\nexport function decodeSecureMailKey(fragmentKey: string): Uint8Array {\n let key: Uint8Array\n try {\n key = base64ToBytes(fragmentKey)\n } catch {\n throw new Error('Invalid secure message link')\n }\n if (key.length !== SECURE_MAIL_KEY_BYTES) {\n key.fill(0)\n throw new Error('Invalid secure message link')\n }\n return key\n}\n\n/** Open a secure message. Throws on a wrong key or a tampered part. */\nexport async function openSecureMail<T = unknown>(\n payload: SecureMailCiphertexts,\n key: Uint8Array\n): Promise<{ raw: Uint8Array; metadata: T }> {\n await initSodium()\n const raw = decryptFile(base64ToBytes(payload.ciphertext), key)\n const meta = decryptFile(base64ToBytes(payload.metadata_ciphertext), key)\n try {\n return { raw, metadata: JSON.parse(sodium.to_string(meta)) as T }\n } finally {\n meta.fill(0)\n }\n}\n\n/** The claim body proving possession of `key` and re-sealing it to the recipient. */\nexport async function secureMailClaim(\n key: Uint8Array,\n recipientPublicKey: Uint8Array\n): Promise<SecureMailClaim> {\n await initSodium()\n return {\n claim_hash: sodium.to_hex(sodium.crypto_hash_sha256(key)),\n wrapped_key: sealedBoxEncrypt(key, recipientPublicKey),\n recipient_public_key: bytesToBase64(recipientPublicKey),\n }\n}\n","/**\n * storage.ts - IndexedDB Storage Module\n *\n * Handles persistent storage of cryptographic keys and session data.\n *\n * Storage Strategy (with encryption-at-rest):\n * - Private keys encrypted with non-extractable Web Crypto AES-GCM key\n * - Wrapping key stored as opaque CryptoKey object (can't be exported)\n * - Session data persists across page refreshes\n *\n * Database Schema:\n * - Store: 'session' - User session data (encrypted private key only)\n * - Store: 'wrapping-key' - Non-extractable CryptoKey for encrypting private keys\n *\n * Security Model:\n * - Passive attacks (reading IndexedDB) get encrypted data + opaque CryptoKey\n * - Active attacks (calling decrypt) can still access keys (XSS with code execution)\n * - Defense-in-depth: Requires active XSS, not just storage access\n *\n * Ported from: /home/dev/ARBI/src/static/js/storage.js\n */\n\nimport { encryptionKeypairFromSigningKey, initSodium, type KeyPair } from '../crypto/sodium'\n\nconst DB_NAME = 'arbi-crypto'\nconst DB_VERSION = 2 // Incremented for new wrapping-key store\n\nlet db: IDBDatabase | null = null\n\n/**\n * Session held in memory when Web Crypto is unavailable (plain-HTTP origins other than\n * localhost, some embedded webviews). Encryption at rest needs a non-extractable CryptoKey,\n * which cannot exist there, so nothing is written to disk: the session works for the life\n * of the page and a reload means signing in again. Never a plaintext-at-rest fallback.\n */\nlet memorySession: SessionData | null = null\n\n/** True when sessions can be persisted (encrypted at rest) rather than held in memory only. */\nexport function canPersistSession(): boolean {\n return !!crypto?.subtle\n}\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/**\n * SessionData in IndexedDB - PERSISTED ENCRYPTED DATA\n * Everything needed to resume session without re-login:\n * - signingPrivateKey: Ed25519 private key (64 bytes, encrypted at rest)\n * Used for authentication (signing). X25519 encryption key is derived from this.\n * - serverSessionKey: Server session key for workspace key encryption (encrypted at rest)\n * - userExtId: User external ID (not sensitive, stored in plain text)\n *\n * Note: accessToken is stored in Zustand (persisted separately), not here.\n */\nexport interface SessionData {\n /** The account identity's Ed25519 secret key (64 bytes) - X25519 derived from this */\n signingPrivateKey: Uint8Array\n serverSessionKey?: Uint8Array\n userExtId?: string\n /**\n * The identity wrapped under the password key, as the last login returned it (null: the password key is\n * the identity). Lets a typed password be checked, and the identity opened, without the server (offline\n * unlock, step-up confirmations). Ciphertext under the password key, so it is stored as is.\n */\n wrappedIdentityKey?: string | null\n}\n\n/**\n * How session is stored in IndexedDB (with ALL sensitive data encrypted)\n */\ninterface StoredSession {\n id: string\n encryptedSigningPrivateKey: Uint8Array\n signingPrivateKeyIV: Uint8Array\n encryptedServerSessionKey?: Uint8Array\n serverSessionKeyIV?: Uint8Array\n userExtId?: string\n wrappedIdentityKey?: string | null\n timestamp: number\n}\n\ninterface WrappingKeyData {\n id: string\n key: CryptoKey\n created: number\n}\n\n// ============================================================================\n// Database Initialization\n// ============================================================================\n\n/**\n * Initialize IndexedDB database.\n *\n * Creates two object stores:\n * - 'session': Stores user session data (with encrypted private key)\n * - 'wrapping-key': Stores non-extractable CryptoKey for key encryption\n */\nexport async function initializeDatabase(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION)\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to open IndexedDB:', request.error)\n reject(request.error)\n }\n\n request.onsuccess = () => {\n db = request.result\n resolve(db)\n }\n\n request.onupgradeneeded = (event) => {\n const database = (event.target as IDBOpenDBRequest).result\n\n // Create 'session' store if it doesn't exist\n if (!database.objectStoreNames.contains('session')) {\n database.createObjectStore('session', { keyPath: 'id' })\n }\n\n // Create 'wrapping-key' store if it doesn't exist (v2+)\n if (!database.objectStoreNames.contains('wrapping-key')) {\n database.createObjectStore('wrapping-key', { keyPath: 'id' })\n }\n }\n })\n}\n\n/**\n * Ensure database is initialized before operations.\n */\nasync function ensureDatabase(): Promise<void> {\n if (!db) {\n await initializeDatabase()\n }\n}\n\n// ============================================================================\n// Wrapping Key Management (Web Crypto Non-Extractable Keys)\n// ============================================================================\n\n/**\n * Generate or retrieve the non-extractable wrapping key.\n *\n * This key is used to encrypt private keys before storing in IndexedDB.\n * - Generated once per browser (survives page refreshes)\n * - Stored as opaque CryptoKey object in IndexedDB\n * - Non-extractable: XSS can't dump the raw key bytes\n * - Can still be used for encrypt/decrypt operations\n *\n * @returns Non-extractable AES-GCM key\n */\nasync function getOrCreateWrappingKey(): Promise<CryptoKey> {\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['wrapping-key'], 'readwrite')\n const store = transaction.objectStore('wrapping-key')\n const request = store.get('master')\n\n request.onsuccess = () => {\n const result = request.result as WrappingKeyData | undefined\n\n if (result?.key) {\n resolve(result.key)\n } else {\n // Generate new non-extractable wrapping key\n // We need to generate the key and store it, but the transaction will auto-commit\n // after this callback. So we need to open a NEW transaction for the put.\n if (!crypto?.subtle) {\n reject(\n new Error(\n 'Web Crypto API not available. Ensure the page is served over HTTPS or localhost.'\n )\n )\n return\n }\n crypto.subtle\n .generateKey(\n {\n name: 'AES-GCM',\n length: 256,\n },\n false, // ❌ NON-EXTRACTABLE - Can't be exported!\n ['encrypt', 'decrypt']\n )\n .then((key) => {\n // Open a NEW transaction to store the key\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const putTransaction = db.transaction(['wrapping-key'], 'readwrite')\n const putStore = putTransaction.objectStore('wrapping-key')\n const putRequest = putStore.put({\n id: 'master',\n key: key,\n created: Date.now(),\n } as WrappingKeyData)\n\n putRequest.onsuccess = () => {\n resolve(key)\n }\n\n putRequest.onerror = () => {\n reject(new Error('Failed to store wrapping key'))\n }\n })\n .catch((error) => {\n const errorMsg = error instanceof Error ? error.message : String(error)\n reject(new Error(`Failed to generate wrapping key: ${errorMsg}`))\n })\n }\n }\n\n request.onerror = () => {\n reject(new Error('Failed to retrieve wrapping key from IndexedDB'))\n }\n })\n}\n\n/**\n * Encrypt data using the non-extractable wrapping key.\n *\n * @param data - Data to encrypt\n * @returns Encrypted data and IV\n */\nasync function encryptWithWrappingKey(\n data: Uint8Array\n): Promise<{ ciphertext: Uint8Array; iv: Uint8Array }> {\n const wrappingKey = await getOrCreateWrappingKey()\n\n // Generate random IV for AES-GCM\n const iv = crypto.getRandomValues(new Uint8Array(12))\n\n // Encrypt the data\n const ciphertext = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv: iv,\n },\n wrappingKey,\n data as BufferSource\n )\n\n return {\n ciphertext: new Uint8Array(ciphertext),\n iv: iv,\n }\n}\n\n/**\n * Decrypt data using the non-extractable wrapping key.\n *\n * @param ciphertext - Encrypted data\n * @param iv - Initialization vector\n * @returns Decrypted data\n */\nasync function decryptWithWrappingKey(ciphertext: Uint8Array, iv: Uint8Array): Promise<Uint8Array> {\n const wrappingKey = await getOrCreateWrappingKey()\n\n const decrypted = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n },\n wrappingKey,\n ciphertext as BufferSource\n )\n\n return new Uint8Array(decrypted)\n}\n\n// ============================================================================\n// Session Storage\n// ============================================================================\n\n/**\n * Store session data in IndexedDB (ALL data encrypted at rest).\n *\n * Stores everything needed to resume session without re-login:\n * - signingPrivateKey: User's Ed25519 private key (ENCRYPTED)\n * - serverSessionKey: Server session key (ENCRYPTED)\n * - userExtId: User external ID (plain text, not sensitive)\n *\n * Note: accessToken is NOT stored here - it's in Zustand (persisted separately).\n *\n * @param sessionData - Complete session data to persist\n */\nexport async function saveSession(sessionData: SessionData): Promise<void> {\n // Without Web Crypto (non-secure context, Tracking Prevention, embedded widgets) keep the\n // session in memory only: it works until the page is closed or refreshed, never at rest.\n if (!canPersistSession()) {\n memorySession = sessionData\n return\n }\n\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n try {\n // Encrypt the signing private key (required)\n const encryptedSigningKey = await encryptWithWrappingKey(sessionData.signingPrivateKey)\n\n // Encrypt optional fields if present\n let encryptedServerSessionKey: { ciphertext: Uint8Array; iv: Uint8Array } | undefined\n\n if (sessionData.serverSessionKey) {\n encryptedServerSessionKey = await encryptWithWrappingKey(sessionData.serverSessionKey)\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['session'], 'readwrite')\n const store = transaction.objectStore('session')\n\n const data: StoredSession = {\n id: 'current',\n encryptedSigningPrivateKey: encryptedSigningKey.ciphertext,\n signingPrivateKeyIV: encryptedSigningKey.iv,\n encryptedServerSessionKey: encryptedServerSessionKey?.ciphertext,\n serverSessionKeyIV: encryptedServerSessionKey?.iv,\n userExtId: sessionData.userExtId,\n wrappedIdentityKey: sessionData.wrappedIdentityKey ?? null,\n timestamp: Date.now(),\n }\n\n const request = store.put(data)\n\n request.onsuccess = () => {\n resolve()\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to save session:', request.error)\n reject(request.error)\n }\n })\n } catch (error) {\n console.error('[STORAGE] Failed to encrypt session data:', error)\n throw error\n }\n}\n\n/**\n * Retrieve session data from IndexedDB (with decrypted private key).\n *\n * @returns Session data or null if not found\n */\nexport async function getSession(): Promise<SessionData | null> {\n if (!canPersistSession()) {\n return memorySession\n }\n\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['session'], 'readonly')\n const store = transaction.objectStore('session')\n const request = store.get('current')\n\n request.onsuccess = async () => {\n const result = request.result as StoredSession | undefined\n\n if (result) {\n try {\n // Decrypt the signing private key (required)\n const signingPrivateKey = await decryptWithWrappingKey(\n result.encryptedSigningPrivateKey,\n result.signingPrivateKeyIV\n )\n\n // Decrypt optional fields if present\n let serverSessionKey\n\n if (result.encryptedServerSessionKey && result.serverSessionKeyIV) {\n serverSessionKey = await decryptWithWrappingKey(\n result.encryptedServerSessionKey,\n result.serverSessionKeyIV\n )\n }\n\n resolve({\n signingPrivateKey,\n serverSessionKey,\n userExtId: result.userExtId,\n wrappedIdentityKey: result.wrappedIdentityKey ?? null,\n })\n } catch (error) {\n console.error('[STORAGE] Failed to decrypt session data:', error)\n reject(error)\n }\n } else {\n resolve(null)\n }\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to get session:', request.error)\n reject(request.error)\n }\n })\n}\n\n/**\n * Replace the stored wrapped identity (after a password change), keeping the rest of the session.\n *\n * @param wrappedIdentityKey - The identity wrapped under the new password key\n */\nexport async function updateWrappedIdentityKey(wrappedIdentityKey: string): Promise<void> {\n const existingSession = await getSession()\n if (!existingSession) {\n throw new Error('No existing session to update')\n }\n await saveSession({ ...existingSession, wrappedIdentityKey })\n}\n\n/**\n * Clear session data from IndexedDB.\n */\nexport async function clearSession(): Promise<void> {\n memorySession = null\n if (!canPersistSession()) {\n return\n }\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['session'], 'readwrite')\n const store = transaction.objectStore('session')\n const request = store.delete('current')\n\n request.onsuccess = () => {\n resolve()\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to clear session:', request.error)\n reject(request.error)\n }\n })\n}\n\n/**\n * Clear the wrapping key from IndexedDB.\n *\n * ⚠️ WARNING: This will make all encrypted private keys unrecoverable!\n * Only call this during full logout/reset.\n */\nasync function clearWrappingKey(): Promise<void> {\n await ensureDatabase()\n\n if (!db) {\n throw new Error('Database not initialized')\n }\n\n return new Promise((resolve, reject) => {\n if (!db) {\n reject(new Error('Database not initialized'))\n return\n }\n\n const transaction = db.transaction(['wrapping-key'], 'readwrite')\n const store = transaction.objectStore('wrapping-key')\n const request = store.delete('master')\n\n request.onsuccess = () => {\n resolve()\n }\n\n request.onerror = () => {\n console.error('[STORAGE] Failed to clear wrapping key:', request.error)\n reject(request.error)\n }\n })\n}\n\n/**\n * Clear all data from IndexedDB (session + wrapping key).\n *\n * Used during logout to ensure all cryptographic material is removed.\n */\nexport async function clearAllData(): Promise<void> {\n memorySession = null\n if (!canPersistSession()) {\n return\n }\n await clearSession()\n await clearWrappingKey()\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if a session exists in IndexedDB.\n *\n * @returns True if session exists\n */\nexport async function hasSession(): Promise<boolean> {\n const session = await getSession()\n return session !== null\n}\n\n/**\n * The current user's X25519 encryption keypair, derived from the persisted\n * session signing key. Returns null when there is no session (no client-side\n * keys). This is the canonical way to obtain the user's own keypair — callers\n * should not re-derive it from `getSession()` themselves.\n */\nexport async function getUserEncryptionKeypair(): Promise<KeyPair | null> {\n await initSodium()\n const session = await getSession()\n if (!session?.signingPrivateKey) {\n return null\n }\n return encryptionKeypairFromSigningKey(session.signingPrivateKey)\n}\n","/**\n * Encryption at rest for offline stores (IndexedDB copies of mail, calendar, …).\n *\n * Keys are derived in memory from the user's own X25519 identity key (by default the one the session\n * store keeps, wrapped by a non-extractable WebCrypto key). Nothing derived here is ever written to disk.\n *\n * - `enc`: XSalsa20-Poly1305 (libsodium secretbox) key for record contents; each record gets a fresh\n * random nonce, stored in front of the ciphertext.\n * - `index`: keyed BLAKE2b key for blind index values, so ids never appear in plaintext.\n *\n * Both are BLAKE2b derivations of the identity secret key, domain-separated by a per-store namespace\n * (`<namespace>:enc`, `<namespace>:index`), so stores can't read each other's records.\n */\n\nimport sodium from 'libsodium-wrappers-sumo'\nimport { getUserEncryptionKeypair } from '../storage/indexed-db'\nimport type { KeyPair } from './sodium'\n\ninterface Keys {\n enc: Uint8Array\n index: Uint8Array\n}\n\nexport interface OfflineSealer {\n sealBytes(plain: Uint8Array): Promise<Uint8Array>\n openBytes(sealed: Uint8Array): Promise<Uint8Array>\n sealJson(value: unknown): Promise<Uint8Array>\n openJson<T>(sealed: Uint8Array): Promise<T>\n /** A keyed hash of `parts`, used as an IndexedDB key so ids never appear in plaintext. */\n blind(...parts: string[]): Promise<string>\n /** Forget the derived keys (sign-out, or the offline data was removed). */\n forget(): void\n}\n\nexport interface OfflineSealerOptions {\n /** Builds the error thrown when no identity key is unlocked. */\n locked: () => Error\n /**\n * The identity keypair to derive from; the sealer zeroes its secret key after use. Defaults to\n * the signed-in session's ({@link getUserEncryptionKeypair}).\n */\n keypair?: () => Promise<KeyPair | null>\n}\n\n/**\n * libsodium type-checks its inputs with `instanceof Uint8Array`; bytes that come from another realm\n * (an IndexedDB structured clone, a TextEncoder of another global) fail that check. Re-wrap those.\n */\nfunction bytes(value: Uint8Array): Uint8Array {\n return value instanceof Uint8Array ? value : Uint8Array.from(value)\n}\n\n/** A sealer for one offline store, namespaced so stores can't read each other's records. */\nexport function createOfflineSealer(\n namespace: string,\n { locked, keypair: getKeypair = getUserEncryptionKeypair }: OfflineSealerOptions\n): OfflineSealer {\n const ENC_LABEL = `${namespace}:enc`\n const INDEX_LABEL = `${namespace}:index`\n let cached: { publicKey: string; keys: Keys } | null = null\n\n async function keys(): Promise<Keys> {\n await sodium.ready\n const keypair = await getKeypair()\n if (!keypair) throw locked()\n const publicKey = sodium.to_hex(keypair.publicKey)\n if (cached?.publicKey === publicKey) {\n keypair.secretKey.fill(0)\n return cached.keys\n }\n const derived = {\n enc: sodium.crypto_generichash(32, ENC_LABEL, bytes(keypair.secretKey)),\n index: sodium.crypto_generichash(32, INDEX_LABEL, bytes(keypair.secretKey)),\n }\n keypair.secretKey.fill(0)\n cached = { publicKey, keys: derived }\n return derived\n }\n\n async function seal(plain: Uint8Array | string): Promise<Uint8Array> {\n const { enc } = await keys()\n const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)\n const box = sodium.crypto_secretbox_easy(\n typeof plain === 'string' ? plain : bytes(plain),\n nonce,\n enc\n )\n const out = new Uint8Array(nonce.length + box.length)\n out.set(nonce)\n out.set(box, nonce.length)\n return out\n }\n\n async function openBytes(sealed: Uint8Array): Promise<Uint8Array> {\n const { enc } = await keys()\n const nonceBytes = sodium.crypto_secretbox_NONCEBYTES\n const data = bytes(sealed)\n // Throws on a wrong key or tampered record; callers treat that record as missing.\n return sodium.crypto_secretbox_open_easy(\n data.subarray(nonceBytes),\n data.subarray(0, nonceBytes),\n enc\n )\n }\n\n return {\n sealBytes: (plain) => seal(plain),\n openBytes,\n sealJson: (value) => seal(JSON.stringify(value)),\n async openJson<T>(sealed: Uint8Array) {\n return JSON.parse(sodium.to_string(await openBytes(sealed))) as T\n },\n async blind(...parts) {\n const { index } = await keys()\n return sodium.to_hex(sodium.crypto_generichash(16, parts.join('\\u0000'), index))\n },\n forget() {\n cached?.keys.enc.fill(0)\n cached?.keys.index.fill(0)\n cached = null\n },\n }\n}\n","/**\n * Bearer Auth Middleware\n *\n * Injects Authorization header on every request using the provided TokenProvider.\n */\n\nimport type { Middleware } from 'openapi-fetch'\nimport type { BearerAuthMiddlewareConfig } from './types'\n\nexport function createBearerAuthMiddleware(config: BearerAuthMiddlewareConfig): Middleware {\n return {\n async onRequest({ request }) {\n const accessToken = config.tokenProvider.getAccessToken()\n if (accessToken) {\n request.headers.set('Authorization', `Bearer ${accessToken}`)\n }\n return request\n },\n }\n}\n","/**\n * The session gate: every authenticated request of a client runs under it, so a sign-out can stop\n * them all before the server revokes the token.\n *\n * A sign-out `close`s the gate: from then on no request starts (it fails at once with an\n * `AbortError`, without reaching the network) and no re-login runs; then it `abort`s what is in\n * flight. Only then does the server end the session, so nothing still running on the old token\n * comes back 401, and nothing a 401 would set off (a re-login, a workspace re-open, a retry) starts\n * a new server session behind the sign-out. Once the session is cleared the gate `reopen`s, for the\n * next sign-in.\n */\n\nimport type { Middleware } from 'openapi-fetch'\n\nexport interface SessionGate {\n /** Aborted when the session ends; a new one after `reopen`. */\n readonly signal: AbortSignal\n /** The session is ending: nothing new may start on it. */\n readonly closed: boolean\n /** Nothing new starts: requests fail at once with an `AbortError`, re-logins do not run. */\n close(): void\n /** Abort every request in flight on this session. */\n abort(): void\n /** The session is over: requests may start again (for the next sign-in). */\n reopen(): void\n}\n\n/** The error an aborted request fails with (`DOMException`'s `AbortError`). */\nfunction abortError(): Error {\n return new DOMException('The session ended.', 'AbortError')\n}\n\n/**\n * Whether `error` is a request (or work) that was aborted rather than one that failed: callers\n * treat it as nothing to report. Looks through `cause`, for an error wrapped by the SDK.\n */\nexport function isAbortError(error: unknown): boolean {\n for (let e = error, depth = 0; e && typeof e === 'object' && depth < 5; depth++) {\n if ((e as { name?: unknown }).name === 'AbortError') return true\n e = (e as { cause?: unknown }).cause\n }\n return false\n}\n\n/** A signal aborted when either is (`AbortSignal.any`, where the platform has it). */\nfunction eitherSignal(a: AbortSignal, b: AbortSignal | null | undefined): AbortSignal {\n if (!b) return a\n if (typeof AbortSignal.any === 'function') return AbortSignal.any([a, b])\n const controller = new AbortController()\n const abort = (signal: AbortSignal) => () => controller.abort(signal.reason)\n if (a.aborted || b.aborted) controller.abort((a.aborted ? a : b).reason)\n else {\n a.addEventListener('abort', abort(a), { once: true })\n b.addEventListener('abort', abort(b), { once: true })\n }\n return controller.signal\n}\n\nexport function createSessionGate(): SessionGate {\n let controller = new AbortController()\n let closed = false\n return {\n get signal() {\n return controller.signal\n },\n get closed() {\n return closed\n },\n close() {\n closed = true\n },\n abort() {\n controller.abort(abortError())\n },\n reopen() {\n if (controller.signal.aborted) controller = new AbortController()\n closed = false\n },\n }\n}\n\n/** The gate's signal on `init` (and the caller's own, if it has one); rejects once it is closed. */\nexport function gatedFetch(gate: SessionGate, fetch: typeof globalThis.fetch): typeof fetch {\n return (input, init) => {\n if (gate.closed) return Promise.reject(abortError())\n const own = init?.signal ?? (input instanceof Request ? input.signal : undefined)\n return fetch(input, { ...init, signal: eitherSignal(gate.signal, own) })\n }\n}\n\n/**\n * The first middleware of a client: each request carries the gate's signal (so a retry cloned\n * from it does too), and one asked for while the gate is closed is aborted before it is sent.\n */\nexport function createSessionGateMiddleware(gate: SessionGate): Middleware {\n return {\n onRequest({ request }) {\n const signal = gate.closed ? AbortSignal.abort(abortError()) : gate.signal\n return new Request(request, { signal: eitherSignal(signal, request.signal) })\n },\n }\n}\n","/**\n * The user's workspace keys on this client: what the workspace lists said (each workspace's key,\n * wrapped to the user, and which are public, with none), and depositing a workspace's key on the\n * server session without opening it (`/prime-key`).\n *\n * One per client, so every `Arbi` on the client (a host recreates its `Arbi` per session and per\n * opened workspace) and the client's own recovery share it: a list read once, by whoever read it,\n * serves every later open. A request refused with 409 `workspace_key_required` primes the\n * workspace it names and is sent again (see the auto re-login middleware).\n */\n\nimport type { CryptoProvider, SessionPersistence } from './relogin/types'\n\n/** A workspace as a workspace list has it (only what the keys need). */\nexport interface ListedWorkspaceKey {\n external_id: string\n wrapped_key?: string | null\n is_public?: boolean | null\n /** A member without an account key: a temporary grant whose key lives in the server session. */\n is_member?: boolean | null\n}\n\nexport interface WorkspaceKeys {\n /** Remember what a workspace list said. Returns the list. */\n remember<T extends ListedWorkspaceKey>(workspaces: T[]): T[]\n /**\n * The workspace's key, wrapped to the user: from what was remembered, else from a fresh list\n * (a workspace created or shared since), or a fresh list with `refresh` (a key that no longer\n * opens: access re-granted with a new key). `null` for a public workspace the user holds no key\n * for, or one they hold a temporary (session-scoped or fixed-expiry) grant to. Throws when the user cannot see the workspace.\n */\n wrappedKey(\n workspaceId: string,\n options?: { refresh?: boolean }\n ): Promise<{ wrappedKey: string | null; fromCache: boolean }>\n /**\n * Make a workspace usable for requests that name it, without opening it: its key, sealed to this\n * server session, is deposited with `/prime-key`. Once per server session (a re-login rotates\n * it); concurrent calls share one request; `force` deposits again (the server lost it).\n */\n prime(workspaceId: string, options?: { force?: boolean }): Promise<void>\n /** Forget these workspaces (deleted). */\n forget(workspaceIds: string[]): void\n /** Forget everything (another user, signed out). */\n clear(): void\n}\n\nexport interface WorkspaceKeysDeps {\n crypto: Pick<CryptoProvider, 'ensureReady' | 'sealKeyForSession'>\n /** The workspace key, unwrapped with the signing key. */\n unwrapWorkspaceKey(wrappedKey: string, signingPrivateKey: Uint8Array): Uint8Array\n persistence: SessionPersistence\n getAccessToken(): string | null\n /** The server session key in use (the session's), else the stored one is read. */\n getServerSessionKey(): Uint8Array | null\n listWorkspaces(accessToken: string): Promise<ListedWorkspaceKey[] | null>\n /** POST `/v1/workspace/{id}/prime-key`; throws when refused. */\n primeKey(accessToken: string, workspaceId: string, sealedKey: string): Promise<void>\n}\n\nexport function createWorkspaceKeys(deps: WorkspaceKeysDeps): WorkspaceKeys {\n const wrapped = new Map<string, string>()\n const keyless = new Set<string>()\n let listing: Promise<void> | null = null\n /** Workspaces primed on this server session, by the session key they were sealed to. */\n const primed = new Map<string, Promise<void>>()\n let primedFor: Uint8Array | null = null\n\n function remember<T extends ListedWorkspaceKey>(workspaces: T[]): T[] {\n for (const ws of workspaces) {\n if (ws.wrapped_key) {\n wrapped.set(ws.external_id, ws.wrapped_key)\n keyless.delete(ws.external_id)\n } else if (ws.is_public || ws.is_member) keyless.add(ws.external_id)\n }\n return workspaces\n }\n\n /** One list read at a time: concurrent misses share it. */\n function readList(): Promise<void> {\n listing ??= (async () => {\n try {\n const token = deps.getAccessToken()\n if (!token) throw new Error('Not signed in')\n const list = await deps.listWorkspaces(token)\n if (!list) throw new Error('Failed to fetch workspaces')\n remember(list)\n } finally {\n listing = null\n }\n })()\n return listing\n }\n\n async function wrappedKey(workspaceId: string, { refresh = false } = {}) {\n if (!refresh) {\n const cached = wrapped.get(workspaceId)\n if (cached) return { wrappedKey: cached, fromCache: true }\n if (keyless.has(workspaceId)) return { wrappedKey: null, fromCache: true }\n }\n wrapped.delete(workspaceId)\n keyless.delete(workspaceId)\n await readList()\n const fresh = wrapped.get(workspaceId)\n if (fresh) return { wrappedKey: fresh, fromCache: false }\n if (keyless.has(workspaceId)) return { wrappedKey: null, fromCache: false }\n throw new Error(`Workspace ${workspaceId} not found or has no encryption key`)\n }\n\n async function sealedFor(workspaceId: string, serverSessionKey: Uint8Array, refresh: boolean) {\n const stored = await deps.persistence.getSession()\n if (!stored?.signingPrivateKey) throw new Error('No stored identity to unlock the workspace')\n const { wrappedKey: key, fromCache } = await wrappedKey(workspaceId, { refresh })\n if (!key) throw new Error(`Workspace ${workspaceId} is public: it has no key to deposit`)\n try {\n await deps.crypto.ensureReady()\n return await deps.crypto.sealKeyForSession(\n deps.unwrapWorkspaceKey(key, stored.signingPrivateKey),\n serverSessionKey\n )\n } catch (error) {\n // A remembered key that no longer opens: access was re-granted with a new key.\n if (!fromCache) throw error\n return sealedFor(workspaceId, serverSessionKey, true)\n }\n }\n\n async function serverSessionKey(): Promise<Uint8Array> {\n const key =\n deps.getServerSessionKey() ?? (await deps.persistence.getSession())?.serverSessionKey\n if (!key) throw new Error('No server session to unlock the workspace for')\n return key\n }\n\n function prime(workspaceId: string, { force = false } = {}): Promise<void> {\n const sessionKey = deps.getServerSessionKey()\n if (sessionKey !== primedFor) {\n primed.clear()\n primedFor = sessionKey\n }\n const pending = primed.get(workspaceId)\n if (pending && !force) return pending\n const run = (async () => {\n const token = deps.getAccessToken()\n if (!token) throw new Error('Not signed in')\n const sealed = await sealedFor(workspaceId, await serverSessionKey(), false)\n await deps.primeKey(token, workspaceId, sealed)\n })()\n primed.set(workspaceId, run)\n run.catch(() => {\n if (primed.get(workspaceId) === run) primed.delete(workspaceId)\n })\n return run\n }\n\n return {\n remember,\n wrappedKey,\n prime,\n forget(workspaceIds) {\n for (const id of workspaceIds) {\n wrapped.delete(id)\n keyless.delete(id)\n primed.delete(id)\n }\n },\n clear() {\n wrapped.clear()\n keyless.clear()\n primed.clear()\n primedFor = null\n },\n }\n}\n\n/** The workspace a 409 `{detail: {code: \"workspace_key_required\", workspace_ext_id}}` names. */\nexport function workspaceKeyRequiredOf(body: unknown): string | null {\n const detail = (body as { detail?: unknown } | null | undefined)?.detail\n if (!detail || typeof detail !== 'object') return null\n const d = detail as { code?: unknown; workspace_ext_id?: unknown }\n return d.code === 'workspace_key_required' && typeof d.workspace_ext_id === 'string'\n ? d.workspace_ext_id\n : null\n}\n","/**\n * Workspace opens, one at a time.\n *\n * The server keeps ONE open (\"active\") workspace per session, and every `POST /workspace/{id}/open`\n * replaces it. Every request that does not name its workspace reads that one. Two opens in flight\n * at once can land in either order, so the server may end on a workspace the client already left\n * while the client believes the other is open: the next lists read would return the wrong\n * workspace's data. So every open on a client goes through this queue (the SDK's\n * `selectWorkspace`, the re-open after a lost workspace, the re-open after a re-login, the\n * open-all): the server applies them in the order they were asked for, and ends on the last.\n *\n * The queue also says when the active workspace may have changed: `generation` moves whenever an\n * open that may change it starts (or one fails, leaving it unknown), so a read can tell whether\n * its response may belong to another workspace than the one it was issued for.\n */\n\nexport interface WorkspaceOpens {\n /**\n * Run `open` alone: after every open queued before it, before any queued after it. `target` is\n * read when it starts: the workspace it leaves active, or `null` when that is not one known\n * workspace (an open-all).\n */\n run<T>(target: () => string | null, open: () => Promise<T>): Promise<T>\n /** An open is running or waiting. */\n readonly busy: boolean\n /** Moves whenever an open that may change the server's active workspace starts or fails. */\n readonly generation: number\n /** The workspace the last open left active on the server; `null` when unknown. */\n readonly active: string | null\n /** Resolves once no open is running or waiting. */\n idle(): Promise<void>\n /** The server session changed (a login, a re-login, a sign-out): nothing is known to be open. */\n reset(): void\n}\n\nexport function createWorkspaceOpens(): WorkspaceOpens {\n let tail: Promise<unknown> = Promise.resolve()\n let pending = 0\n let generation = 0\n let active: string | null = null\n\n return {\n run<T>(target: () => string | null, open: () => Promise<T>): Promise<T> {\n pending++\n const result = tail.then(async () => {\n const workspaceId = target()\n if (workspaceId === null || workspaceId !== active) {\n generation++\n active = null\n }\n try {\n const value = await open()\n active = workspaceId\n return value\n } catch (error) {\n // The server may or may not have applied it.\n generation++\n active = null\n throw error\n }\n })\n const done = () => {\n pending--\n }\n tail = result.then(done, done)\n return result\n },\n get busy() {\n return pending > 0\n },\n get generation() {\n return generation\n },\n get active() {\n return active\n },\n async idle() {\n // An open queued while waiting extends the tail: wait for that one too.\n for (let current = tail; ; current = tail) {\n await current\n if (current === tail && pending === 0) return\n }\n },\n reset() {\n generation++\n active = null\n },\n }\n}\n","/**\n * Auto Re-login Middleware\n *\n * Handles 401 and 400 responses by triggering re-login and retrying the request.\n * Framework-agnostic — the actual re-login logic is provided via ReloginHandler.\n *\n * Clones the request in onRequest (before the body stream is consumed)\n * so that POST/PUT requests with bodies can be retried after re-login.\n */\n\nimport type { Middleware } from 'openapi-fetch'\nimport type { AutoReloginMiddlewareConfig } from './types'\nimport { workspaceKeyRequiredOf } from '../workspace-keys'\n\nconst NO_ACTIVE_WORKSPACE = /no active workspace/i\n\n/** The workspace a 409 `workspace_key_required` names, or null. */\nasync function keyRequiredWorkspace(response: Response): Promise<string | null> {\n try {\n return workspaceKeyRequiredOf(await response.clone().json())\n } catch {\n return null\n }\n}\n\nasync function isNoActiveWorkspace(response: Response): Promise<boolean> {\n try {\n return NO_ACTIVE_WORKSPACE.test(await response.clone().text())\n } catch {\n return false\n }\n}\n\nfunction safeClone(request: Request): Request | null {\n try {\n return request.clone()\n } catch {\n return null\n }\n}\n\nexport function createAutoReloginMiddleware(config: AutoReloginMiddlewareConfig): Middleware {\n // Store a pre-consumption clone keyed by request identity.\n // WeakMap ensures entries are garbage-collected when the Request is.\n const cloneCache = new WeakMap<Request, Request>()\n\n return {\n async onRequest({ request }) {\n // Clone before body is consumed by fetch(), so we can retry later\n try {\n cloneCache.set(request, request.clone())\n } catch {\n // Cloning can fail for certain exotic request types; proceed without cache\n }\n },\n\n async onResponse({ response, request }) {\n // 409 `workspace_key_required`: the request named a workspace whose key this session does\n // not hold. Deposit it (without opening the workspace) and send the request again, once:\n // it never ran. The retry bypasses this middleware, so it cannot loop.\n if (response.status === 409 && config.primeWorkspaceHandler) {\n const workspaceId = await keyRequiredWorkspace(response)\n if (workspaceId) {\n if (!(await config.primeWorkspaceHandler(workspaceId))) return response\n const retry = cloneCache.get(request) ?? safeClone(request)\n if (retry) return (config.fetch ?? globalThis.fetch)(retry)\n config.onRetryCloneFailed?.()\n return response\n }\n }\n\n // 400 \"No active workspace - call /open first\": the server session lost the open workspace.\n // Re-open it (or re-login, which re-opens) and retry ONCE, whatever the method: the request\n // never ran, so a retry is safe. The retry bypasses this middleware, so it cannot loop.\n if (response.status === 400 && (await isNoActiveWorkspace(response))) {\n let token: string | null = null\n let recovered = (await config.reopenWorkspaceHandler?.()) ?? false\n if (!recovered) {\n token = await config.reloginHandler()\n recovered = token !== null\n }\n if (!recovered) return response\n const retry = cloneCache.get(request) ?? safeClone(request)\n if (retry) {\n if (token) retry.headers.set('Authorization', `Bearer ${token}`)\n return (config.fetch ?? globalThis.fetch)(retry)\n }\n config.onRetryCloneFailed?.()\n return response\n }\n\n // Handle 400 errors on protected endpoints - try instant re-login once\n if (response.status === 400) {\n const isSafeMethod = ['GET', 'HEAD', 'DELETE'].includes(request.method)\n\n if (isSafeMethod) {\n const newToken = await config.reloginHandler()\n if (newToken) {\n const retryRequest = cloneCache.get(request) ?? request.clone()\n retryRequest.headers.set('Authorization', `Bearer ${newToken}`)\n return (config.fetch ?? globalThis.fetch)(retryRequest)\n }\n }\n }\n\n if (response.status === 401) {\n const excludePatterns = config.reloginExcludePatterns ?? []\n const isExcluded = excludePatterns.some((pattern) => request.url.includes(pattern))\n\n // Retry ALL requests after re-login, not just safe methods\n if (!isExcluded) {\n const newToken = await config.reloginHandler()\n if (newToken) {\n const cached = cloneCache.get(request)\n if (cached) {\n cached.headers.set('Authorization', `Bearer ${newToken}`)\n return (config.fetch ?? globalThis.fetch)(cached)\n }\n // Fallback: try cloning directly (works for bodyless requests)\n try {\n const retryRequest = request.clone()\n retryRequest.headers.set('Authorization', `Bearer ${newToken}`)\n return (config.fetch ?? globalThis.fetch)(retryRequest)\n } catch {\n console.warn('[API] Could not retry request after re-login (body already consumed)')\n config.onRetryCloneFailed?.()\n }\n }\n }\n }\n\n return response\n },\n }\n}\n","/**\n * Concurrent identical GETs share one network call: a GET of a URL, with the same Authorization,\n * made while an identical one is in flight waits for it and gets a copy of its response. Not a\n * cache: the entry goes as soon as the request settles. Every other method goes straight through.\n *\n * A fetch wrapper under the client (not openapi-fetch middleware): middleware cannot hand a request\n * to another in-flight call, and the re-login and workspace-open requests bypass the chain.\n */\n\n/**\n * The Authorization of a call, so GETs with different bearer tokens are keyed separately. Reads\n * the Request first, then the init headers (raw fetch callers).\n */\nfunction authTokenOf(input: RequestInfo | URL, init?: RequestInit): string {\n if (input instanceof Request) {\n const fromRequest = input.headers.get('authorization')\n if (fromRequest) return fromRequest\n }\n if (init?.headers) {\n return new Headers(init.headers).get('authorization') ?? ''\n }\n return ''\n}\n\n/** `fetch` with concurrent identical GETs deduplicated (one in-flight map per wrapper). */\nexport function createDedupFetch(originalFetch: typeof fetch): typeof fetch {\n const inFlightRequests = new Map<string, Promise<Response>>()\n return function dedupFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n // openapi-fetch hands over a Request whose method lives on the Request itself (no `init`),\n // so read it from there first: defaulting to GET made every POST/PATCH/DELETE look like a\n // GET, registered it under the GET key, and let a concurrent GET of the same URL receive the\n // mutation's response (e.g. the created agent object where the agent list belongs).\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n\n if (method !== 'GET') {\n return originalFetch(input, init)\n }\n\n const url = input instanceof Request ? input.url : String(input)\n // Key on URL + Authorization token. Two GETs to the same URL with DIFFERENT\n // auth tokens are NOT identical back-end requests — one may be authorized\n // (200) and the other not (401). Keying on URL alone let a freshly-logged-in\n // request (good token) dedupe onto an in-flight request issued during\n // completeLogin's reset window (blank/dead token) and inherit its 401, which\n // then drove a spurious auto-relogin → logout on first login. Same token →\n // still collapsed (the common case: many components requesting /workspaces).\n const key = `GET:${url}\\0${authTokenOf(input, init)}`\n\n const existing = inFlightRequests.get(key)\n if (existing) {\n return existing.then((r) => r.clone())\n }\n\n const promise = originalFetch(input, init).finally(() => {\n inFlightRequests.delete(key)\n })\n\n inFlightRequests.set(key, promise)\n // EVERY consumer — the first caller included — gets a clone, so the shared\n // response's own body is never consumed. If the first caller received the\n // original, its .json() would mark the body used before concurrent\n // duplicates run their .clone(), which then throws \"Response body is\n // already used\" — silently killing every duplicate caller.\n return promise.then((r) => r.clone())\n }\n}\n","/**\n * Client-side circuit breaker for runaway settings writes.\n *\n * A stale cached bundle once stormed PATCH /v1/user/settings (~1200 requests\n * from one tab), saturating the tab's main thread. Every legitimate settings\n * write is a discrete user gesture — the worst real burst (rapid pin/unpin\n * clicking, flipping every experimental toggle) stays well under 30 writes a\n * minute — so a sustained rate past that is a bug, not a user. This wrapper\n * drops the excess so a future regression degrades into a few failed writes\n * instead of a frozen tab and a hammered server.\n *\n * A fetch wrapper under the client (not openapi-fetch middleware): the\n * auto-relogin middleware re-issues 401'd requests outside the middleware\n * chain, so the client's fetch is the one choke point every settings write\n * must pass.\n *\n * The rejection is a synthetic 429 WITH a JSON body: openapi-fetch parses a\n * non-ok response with an empty body as `{ error: undefined }`, which a caller\n * would treat as SUCCESS. 400/401 would engage the auto-relogin machinery and\n * 402 opens the quota dialog — 429 is the one status nothing else reacts to,\n * and mutations never retry (`createArbiQueryClient` in `@arbidocs/react`), so\n * callers see one ordinary failed write with the code below.\n */\n\nconst WINDOW_MS = 60_000\n// Cap on ACCEPTED writes per sliding window. Deliberately generous: humans\n// top out around half of this; don't lower it or bulk offline-resume and\n// toggle sprees risk false trips.\nconst MAX_WRITES_PER_WINDOW = 30\n\n/** The error code of a settings write the breaker dropped. */\nexport const SETTINGS_WRITE_BREAKER_CODE = 'CLIENT_SETTINGS_WRITE_BREAKER'\n\nfunction isSettingsWrite(input: RequestInfo | URL, init?: RequestInit): boolean {\n const method = (input instanceof Request ? input.method : (init?.method ?? 'GET')).toUpperCase()\n if (method !== 'PATCH') return false\n const url = input instanceof Request ? input.url : String(input)\n try {\n const base = typeof location !== 'undefined' ? location.origin : 'http://localhost'\n return new URL(url, base).pathname.endsWith('/v1/user/settings')\n } catch {\n return false\n }\n}\n\nfunction breakerResponse(): Response {\n return new Response(\n JSON.stringify({\n detail: {\n code: SETTINGS_WRITE_BREAKER_CODE,\n message:\n 'Too many settings updates from this tab — write dropped by the client circuit breaker.',\n },\n }),\n { status: 429, headers: { 'Content-Type': 'application/json' } }\n )\n}\n\n/** `fetch` with settings writes past the cap dropped (one window per wrapper). */\nexport function createSettingsWriteBreakerFetch(originalFetch: typeof fetch): typeof fetch {\n let acceptedAt: number[] = []\n let trippedThisEpisode = false\n return function settingsWriteBreakerFetch(\n input: RequestInfo | URL,\n init?: RequestInit\n ): Promise<Response> {\n if (!isSettingsWrite(input, init)) {\n return originalFetch(input, init)\n }\n\n const now = Date.now()\n acceptedAt = acceptedAt.filter((t) => now - t < WINDOW_MS)\n\n if (acceptedAt.length >= MAX_WRITES_PER_WINDOW) {\n // Log once per trip episode, not per dropped request — a storm rejects\n // hundreds of times a minute.\n if (!trippedThisEpisode) {\n trippedThisEpisode = true\n console.error(\n `[settings-write-breaker] over ${MAX_WRITES_PER_WINDOW} PATCH /v1/user/settings in ${WINDOW_MS / 1000}s — dropping further writes. This indicates a client-side write loop.`\n )\n }\n return Promise.resolve(breakerResponse())\n }\n\n trippedThisEpisode = false\n acceptedAt.push(now)\n return originalFetch(input, init)\n }\n}\n","/**\n * Re-login Handler Factory\n *\n * Framework-agnostic instant re-login using stored private key.\n * All app-specific dependencies (state management, crypto, storage,\n * API transport) are injected via provider interfaces.\n *\n * Zero external dependencies beyond TypeScript types.\n */\n\nimport type { ReloginDeps, ReloginFailure } from './types'\n\n/**\n * Cooldown period after a successful re-login.\n * Prevents a second login from overwriting the session key in the DB\n * before the first login's workspace-open call completes.\n *\n * The race: WebSocket auth failure triggers a delayed `instantReLogin()` (via dynamic import)\n * that arrives after the middleware's re-login has already completed, causing a second /login\n * that regenerates the server session key and invalidates in-flight workspace-open requests.\n */\nconst RELOGIN_COOLDOWN_MS = 5_000\n\n/**\n * Create a re-login handler with injected dependencies.\n *\n * Returns a function: `() => Promise<string | null>`\n * Resolves to the new access token, or null on failure.\n *\n * Includes two layers of protection:\n * 1. Debounce: concurrent calls share the same in-flight promise.\n * 2. Cooldown: calls within RELOGIN_COOLDOWN_MS of a success return the cached token.\n */\nexport function createReloginHandler(deps: ReloginDeps): () => Promise<string | null> {\n let reloginPromise: Promise<string | null> | null = null\n let lastSuccessToken: string | null = null\n let lastSuccessTime = 0\n\n return function instantReLogin(): Promise<string | null> {\n // Layer 1: debounce — concurrent calls share the same promise\n if (reloginPromise) {\n return reloginPromise\n }\n\n // Layer 2: cooldown — recent success returns cached token\n const elapsed = Date.now() - lastSuccessTime\n if (lastSuccessToken && elapsed < RELOGIN_COOLDOWN_MS) {\n return Promise.resolve(lastSuccessToken)\n }\n\n // Precondition check BEFORE the shared promise is created. During a login's\n // reset window (completeLogin briefly sets auth.user = null) any gated query\n // that 401s will call here with no email yet. If that transient \"abort\"\n // resolved INSIDE the shared promise, Layer-1 debounce would hand the same\n // null result to a concurrent/subsequent caller that DOES have an email —\n // poisoning a relogin that would otherwise succeed and triggering a spurious\n // logout. The cold-start `ensureReady()` (libsodium WASM) widens this window\n // on the very first login, which is exactly when users hit it. Resolving the\n // no-email case here (not in the shared promise) keeps it from sticking.\n const userEmail = deps.authState.getUserEmail()\n if (!userEmail) {\n console.warn('[API] Re-login aborted: no user email')\n deps.onReloginFailed?.('not-ready')\n return Promise.resolve(null)\n }\n\n const fail = (reason: ReloginFailure): null => {\n deps.onReloginFailed?.(reason)\n return null\n }\n\n reloginPromise = (async () => {\n try {\n await deps.crypto.ensureReady()\n\n const session = await deps.persistence.getSession()\n if (!session) {\n console.warn('[API] Re-login aborted: no session')\n return fail('not-ready')\n }\n\n // Derive encryption key from signing key (for workspace key decryption)\n // Ed25519 secret key is 64 bytes: [32-byte seed][32-byte public key]\n const ed25519PublicKey = session.signingPrivateKey.slice(32, 64)\n const encryptionKeyPair = deps.crypto.deriveEncryptionKeypair({\n publicKey: ed25519PublicKey,\n secretKey: session.signingPrivateKey,\n })\n\n // Create timestamp and signature for login\n const timestamp = Math.floor(Date.now() / 1000)\n const message = `${userEmail}|${timestamp}`\n const signature = deps.crypto.signMessage(message, session.signingPrivateKey)\n\n // An SSO session re-logs in with the provider's token, and ONLY an SSO session asks for one:\n // the provider's cache can hold a session from another deployment on the same tenant, and\n // sending that token to this deployment's login is refused (401) and logs the user out.\n let ssoToken: string | null = null\n if (deps.authState.isSsoMode()) {\n try {\n ssoToken = (await deps.sso?.getToken()) ?? null\n } catch (error) {\n console.error('[API] Failed to get SSO token:', error)\n }\n if (!ssoToken) {\n console.warn('[API] Re-login aborted: SSO account but no token available')\n return fail('refused')\n }\n }\n\n // Perform login via injected provider\n const loginResult = await deps.loginProvider.login({\n email: userEmail,\n signature,\n timestamp,\n ssoToken: ssoToken ?? undefined,\n })\n\n if (loginResult === 'unreachable') {\n console.warn('[API] Re-login failed: server unreachable')\n return fail('unreachable')\n }\n if (!loginResult) {\n console.warn('[API] Re-login failed')\n return fail('refused')\n }\n\n // Save new session key (so it survives page reload)\n await deps.persistence.saveSession({\n signingPrivateKey: session.signingPrivateKey,\n serverSessionKey: loginResult.sessionKey,\n userExtId: loginResult.userExtId,\n wrappedIdentityKey: loginResult.wrappedIdentityKey ?? null,\n })\n\n // Notify consumers (e.g. cache update) — must await so session key\n // is propagated to React Query before workspace re-open\n await deps.onReloginSuccess?.({\n email: userEmail,\n accessToken: loginResult.accessToken,\n userExtId: loginResult.userExtId,\n serverSessionKey: loginResult.sessionKey,\n })\n\n // Track the best token we have — starts as user-scoped, may upgrade to workspace-scoped\n const activeToken = loginResult.accessToken\n\n deps.authState.setAccessToken(activeToken)\n\n // Re-open currently selected workspace (keys are re-encrypted with new session key)\n const selectedWorkspaceId = deps.authState.getSelectedWorkspaceId()\n if (selectedWorkspaceId) {\n try {\n const wrappedKey = await deps.workspaceKeyRefreshProvider.getWrappedKey(\n loginResult.accessToken,\n selectedWorkspaceId\n )\n\n if (wrappedKey) {\n const workspaceKey = deps.crypto.sealedBoxDecrypt(\n wrappedKey,\n encryptionKeyPair.secretKey\n )\n\n const encryptedWorkspaceKey = await deps.crypto.sealKeyForSession(\n workspaceKey,\n loginResult.sessionKey\n )\n\n // Call /open to store key on session and set active workspace\n if (deps.workspaceOpenProvider) {\n await deps.workspaceOpenProvider.openWorkspace(\n loginResult.accessToken,\n selectedWorkspaceId,\n encryptedWorkspaceKey\n )\n }\n }\n } catch (error) {\n console.error('[API] Failed to re-open workspace after re-login:', error)\n }\n }\n\n console.info('[API] Re-login successful')\n lastSuccessToken = activeToken\n lastSuccessTime = Date.now()\n return activeToken\n } catch (error) {\n console.error('[API] Re-login error:', error)\n lastSuccessToken = null\n lastSuccessTime = 0\n return fail('refused')\n } finally {\n reloginPromise = null\n }\n })()\n\n return reloginPromise\n }\n}\n","/**\n * Workspace re-open (no re-login)\n *\n * The server keeps \"which workspace is open, and its key sealed for this session\" on the session.\n * When that state is gone while the access token is still valid (a server restart, a rotated\n * session, an expired workspace session), requests fail with 400 \"No active workspace - call\n * /open first\". Re-opening needs no new login: unwrap the workspace key with the stored signing\n * key, seal it for the stored server session key, POST /open.\n */\n\nimport type {\n AuthStateProvider,\n CryptoProvider,\n SessionPersistence,\n WorkspaceKeyRefreshProvider,\n WorkspaceOpenProvider,\n} from './types'\n\nexport interface ReopenDeps {\n crypto: Pick<\n CryptoProvider,\n 'ensureReady' | 'deriveEncryptionKeypair' | 'sealedBoxDecrypt' | 'sealKeyForSession'\n >\n persistence: SessionPersistence\n authState: Pick<AuthStateProvider, 'getSelectedWorkspaceId'>\n getAccessToken(): string | null\n workspaceKeyRefreshProvider: WorkspaceKeyRefreshProvider\n workspaceOpenProvider: WorkspaceOpenProvider\n}\n\n/**\n * Returns `reopenWorkspace()`: resolves true when the selected workspace is open again on the\n * server session, false when it cannot be (nothing selected, no stored keys, server refused).\n * Concurrent calls share one in-flight attempt.\n */\nexport function createWorkspaceReopener(deps: ReopenDeps): () => Promise<boolean> {\n let inFlight: Promise<boolean> | null = null\n\n return function reopenWorkspace(): Promise<boolean> {\n if (inFlight) return inFlight\n inFlight = (async () => {\n try {\n const workspaceId = deps.authState.getSelectedWorkspaceId()\n const accessToken = deps.getAccessToken()\n if (!workspaceId || !accessToken) return false\n\n const session = await deps.persistence.getSession()\n if (!session?.signingPrivateKey || !session.serverSessionKey) return false\n\n await deps.crypto.ensureReady()\n const wrappedKey = await deps.workspaceKeyRefreshProvider.getWrappedKey(\n accessToken,\n workspaceId\n )\n if (!wrappedKey) return false\n\n const encryptionKeyPair = deps.crypto.deriveEncryptionKeypair({\n publicKey: session.signingPrivateKey.slice(32, 64),\n secretKey: session.signingPrivateKey,\n })\n const workspaceKey = deps.crypto.sealedBoxDecrypt(wrappedKey, encryptionKeyPair.secretKey)\n const sealed = await deps.crypto.sealKeyForSession(workspaceKey, session.serverSessionKey)\n const opened = await deps.workspaceOpenProvider.openWorkspace(\n accessToken,\n workspaceId,\n sealed\n )\n return opened === true\n } catch (error) {\n console.error('[API] Failed to re-open workspace:', error)\n return false\n } finally {\n inFlight = null\n }\n })()\n return inFlight\n }\n}\n\nexport interface OpenAllDeps {\n crypto: Pick<CryptoProvider, 'ensureReady' | 'sealKeyForSession' | 'fromBase64'>\n persistence: SessionPersistence\n getAccessToken(): string | null\n /** The session's own X25519 key (the token's `sk` claim), which workspace keys are sealed to. */\n getSessionKey(accessToken: string): string | null\n /** The workspace key, unwrapped with the signing key. */\n unwrapWorkspaceKey(wrappedKey: string, signingPrivateKey: Uint8Array): Uint8Array\n listWorkspaces(\n accessToken: string\n ): Promise<Array<{ external_id: string; wrapped_key?: string | null }> | null>\n workspaceOpenProvider: WorkspaceOpenProvider\n /**\n * The workspace to open last, so the session's active workspace ends on it (each `/open` makes\n * its workspace the active one): the selected workspace.\n */\n lastWorkspace?: () => string | null\n}\n\n/**\n * Returns `openAllWorkspaces()`: seal every workspace key the user holds to this server session\n * (`/open` each, sequentially), so a session derived from it (an MCP session copies the browser\n * session's keys) can reach every workspace. Best-effort: a workspace that fails is logged and\n * skipped. Sequential on purpose: the server's per-session key store is a read-modify-write, so\n * parallel opens overwrite each other.\n */\nexport function createAllWorkspacesOpener(deps: OpenAllDeps): () => Promise<void> {\n return async function openAllWorkspaces(): Promise<void> {\n const accessToken = deps.getAccessToken()\n if (!accessToken) return\n await deps.crypto.ensureReady()\n const session = await deps.persistence.getSession()\n if (!session?.signingPrivateKey) return\n const sessionKey = deps.getSessionKey(accessToken)\n if (!sessionKey) return\n const sessionKeyBytes = deps.crypto.fromBase64(sessionKey)\n\n let workspaces: Array<{ external_id: string; wrapped_key?: string | null }> | null\n try {\n workspaces = await deps.listWorkspaces(accessToken)\n } catch {\n return\n }\n const last = deps.lastWorkspace?.() ?? null\n const ordered = [...(workspaces ?? [])].sort(\n (a, b) => Number(a.external_id === last) - Number(b.external_id === last)\n )\n for (const ws of ordered) {\n if (!ws.wrapped_key || !ws.external_id) continue\n try {\n const workspaceKey = deps.unwrapWorkspaceKey(ws.wrapped_key, session.signingPrivateKey)\n const sealed = await deps.crypto.sealKeyForSession(workspaceKey, sessionKeyBytes)\n await deps.workspaceOpenProvider.openWorkspace(accessToken, ws.external_id, sealed)\n } catch (error) {\n console.warn(`[API] Failed to open workspace ${ws.external_id}:`, error)\n }\n }\n }\n}\n","/**\n * The one reader of the access token's claims. Unverified decode: the server signs and checks the\n * token; a client reads it only to know which session it is on and when the token runs out, never\n * to authorize anything.\n */\n\n/** What a client reads from an ARBI access token. */\nexport interface SessionClaims {\n /** The `sk` claim: the session's X25519 public key (base64), which workspace keys are sealed to. */\n sessionKey: string | null\n /** The short id (first 12 characters of `sk`) the session is listed under in `GET /v1/user/sessions`. */\n sessionId: string | null\n /** The `exp` claim in milliseconds since the epoch, or null when the token has none. */\n expiresAt: number | null\n}\n\n/** A JWT's claims, or `null` for a missing, opaque or malformed token. */\nexport function readSessionClaims(token: string | null | undefined): SessionClaims | null {\n const payload = token?.split('.')[1]\n if (!payload) return null\n let claims: unknown\n try {\n const binary = atob(payload.replace(/-/g, '+').replace(/_/g, '/'))\n claims = JSON.parse(\n new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)))\n ) as unknown\n } catch {\n return null\n }\n if (typeof claims !== 'object' || claims === null) return null\n const { sk, exp } = claims as { sk?: unknown; exp?: unknown }\n const sessionKey = typeof sk === 'string' && sk ? sk : null\n return {\n sessionKey,\n sessionId: sessionKey ? sessionKey.slice(0, 12) : null,\n expiresAt: typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : null,\n }\n}\n","/**\n * Opening the account identity with a password (see ../crypto/identity.ts).\n */\n\nimport {\n base64Encode,\n encryptionKeypairFromSigningKey,\n generateUserKeypairs,\n unwrapIdentityKey,\n} from '../crypto'\nimport { getSession } from '../storage'\n\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n return a.length === b.length && a.every((byte, i) => byte === b[i])\n}\n\nfunction encryptionPublicKeyOf(identitySecretKey: Uint8Array): string {\n return base64Encode(encryptionKeypairFromSigningKey(identitySecretKey).publicKey)\n}\n\n/**\n * The identity a password login opened: unwrapped from the response with the password key that signed it (or\n * the password key itself for an account whose password key is its identity). Refuses an identity that is not\n * the account's, so a wrong wrap cannot become the session's key.\n */\nexport function identityFromLoginResponse(\n passwordPrivateKey: Uint8Array,\n response: { wrapped_identity_key?: string | null; user: { encryption_public_key: string } }\n): Uint8Array {\n const identity = unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey)\n if (encryptionPublicKeyOf(identity) !== response.user.encryption_public_key) {\n throw new Error('The account key does not match this account')\n }\n return identity\n}\n\n/**\n * Check a typed password against the signed-in session and return the identity it opens (step-up\n * confirmations, offline unlock). Uses the wrap saved at the last login; throws \"Incorrect password\".\n */\nexport async function unlockIdentityWithPassword(\n email: string,\n password: string,\n deploymentDomain: string\n): Promise<Uint8Array> {\n const session = await getSession()\n if (!session?.signingPrivateKey) throw new Error('No active session found')\n const { signingKeyPair } = await generateUserKeypairs(email, password, deploymentDomain)\n const identity = unwrapIdentityKey(session.wrappedIdentityKey, signingKeyPair.secretKey)\n if (!bytesEqual(identity, session.signingPrivateKey)) throw new Error('Incorrect password')\n return session.signingPrivateKey\n}\n","/**\n * Login flow\n *\n * Signs \"email|timestamp\" (password key, or the identity key itself) → posts to /v1/user/login → opens the\n * identity → saves session\n */\n\nimport type createFetchClient from 'openapi-fetch'\nimport type { components, paths } from '../schema'\nimport type { SessionManager, SessionUser } from '../session'\nimport type { SessionPersistence } from '../relogin/types'\nimport { generateLoginCredentials, generateLoginCredentialsFromKey, base64ToBytes } from '../crypto'\nimport { identityFromLoginResponse } from './identity'\nimport { saveSession } from '../storage'\n\nexport type LoginResponse = components['schemas']['LoginResponse']\n\nexport interface LoginParams {\n email: string\n password: string\n /** An SSO account signs in with its provider's token too (the session is then in SSO mode). */\n ssoToken?: string\n /** Profile fields to use instead of the login response's (a new SSO account's provider name). */\n profile?: Partial<Pick<SessionUser, 'given_name' | 'family_name' | 'picture'>>\n}\n\nexport interface LoginWithKeyParams {\n email: string\n signingPrivateKey: Uint8Array\n ssoToken?: string\n}\n\n/**\n * The host's part of every sign-in (password, key, SSO), around the client's own: `before` runs once\n * the server accepted the login and the identity opened, before anything is stored, so the host can\n * clear the previous user's state; `after` runs once the session is signed in.\n */\nexport interface SignInHooks {\n before?(next: { user: LoginResponse['user'] }): Promise<void> | void\n after?(signedIn: { response: LoginResponse; serverSessionKey: Uint8Array }): void\n}\n\n/** A refused auth request: its message, and the server's `detail` and status for the caller. */\nexport function authRequestError(\n what: string,\n error: unknown,\n status: number | undefined\n): Error & { detail?: unknown; status?: number } {\n const detail =\n typeof error === 'object' && error !== null && 'detail' in error\n ? (error as { detail?: unknown }).detail\n : undefined\n const text = typeof detail === 'string' ? detail : 'Unknown error'\n return Object.assign(new Error(`${what} failed: ${text}`), { detail, status })\n}\n\n/** The signed-in user's profile as the login response carries it. */\nexport interface LoginProfile {\n givenName: string\n familyName: string | null\n /** Avatar image (data URL or URL), when set. */\n picture: string | null\n email: string\n /** True when the account signs in through an SSO provider (the email is managed there). */\n isSso: boolean\n /** Verified tick: passed an ID check under this name, not expired. */\n isIdentityVerified?: boolean\n}\n\nexport interface LoginResult {\n /** The login response itself (workspaces, a pending share, the user). */\n response?: LoginResponse\n accessToken: string\n userExtId?: string\n /** Owner's ext_id for agent accounts; null/undefined for human users */\n parentExtId?: string | null\n /** The profile from the login response, so hosts need no second request for the name. */\n profile?: LoginProfile\n /** The account identity's secret key (the session key material, and the recovery key). */\n signingPrivateKey: Uint8Array\n serverSessionKey: Uint8Array\n}\n\ninterface LoginDeps {\n fetchClient: ReturnType<typeof createFetchClient<paths>>\n session: SessionManager\n deploymentDomain: string\n /** Where the keys are kept (the bundled IndexedDB store by default). */\n persistence?: Pick<SessionPersistence, 'saveSession'>\n signIn?: SignInHooks\n}\n\nexport async function login(params: LoginParams, deps: LoginDeps): Promise<LoginResult> {\n const credentials = await generateLoginCredentials(\n {\n email: params.email,\n sso_token: params.ssoToken,\n },\n params.password,\n deps.deploymentDomain\n )\n\n return performLogin(\n credentials.request,\n { password: credentials.passwordPrivateKey },\n deps,\n params.profile\n )\n}\n\nexport async function loginWithKey(\n params: LoginWithKeyParams,\n deps: LoginDeps\n): Promise<LoginResult> {\n const credentials = generateLoginCredentialsFromKey(\n {\n email: params.email,\n sso_token: params.ssoToken,\n },\n params.signingPrivateKey\n )\n\n return performLogin(credentials.request, { identity: credentials.signingPrivateKey }, deps)\n}\n\nasync function performLogin(\n request: { email: string; signature: string; timestamp: number; sso_token?: string | null },\n signer: { password: Uint8Array } | { identity: Uint8Array },\n deps: LoginDeps,\n profile?: LoginParams['profile']\n): Promise<LoginResult> {\n const response = await deps.fetchClient.POST('/v1/user/login', {\n body: request,\n })\n\n if (response.error || !response.data) {\n throw authRequestError('Login', response.error, response.response?.status)\n }\n\n const data = response.data\n const serverSessionKey = base64ToBytes(data.session_key)\n // Before anything is cleared: a wrap this password does not open must not sign anyone out.\n const signingPrivateKey =\n 'password' in signer ? identityFromLoginResponse(signer.password, data) : signer.identity\n\n // The host clears the previous user's state (this may be someone else) before it is replaced.\n await deps.signIn?.before?.({ user: data.user })\n\n // Save session to IndexedDB\n await (deps.persistence?.saveSession ?? saveSession)({\n signingPrivateKey,\n serverSessionKey,\n userExtId: data.user.external_id ?? undefined,\n wrappedIdentityKey: data.wrapped_identity_key ?? null,\n })\n\n // Sign the session in: token, user, SSO mode and server key at once\n // The address signed in with: a re-login signs `email|timestamp` with it.\n const email = request.email\n deps.session.signIn({\n accessToken: data.access_token,\n isSsoMode: !!request.sso_token,\n serverSessionKey,\n user: {\n ...data.user,\n email,\n given_name: profile?.given_name ?? data.user.given_name ?? email.split('@')[0],\n family_name: profile?.family_name ?? data.user.family_name,\n picture: profile?.picture ?? data.user.picture ?? null,\n parent_ext_id: data.user.parent_ext_id ?? null,\n is_sso: data.user.is_sso ?? false,\n is_identity_verified: data.user.is_identity_verified ?? false,\n },\n })\n deps.signIn?.after?.({ response: data, serverSessionKey })\n\n return {\n response: data,\n accessToken: data.access_token,\n userExtId: data.user.external_id ?? undefined,\n parentExtId: data.user.parent_ext_id ?? null,\n profile: {\n givenName: data.user.given_name,\n familyName: data.user.family_name ?? null,\n picture: data.user.picture ?? null,\n email: data.user.email ?? request.email,\n isSso: data.user.is_sso === true,\n isIdentityVerified: data.user.is_identity_verified === true,\n },\n signingPrivateKey,\n serverSessionKey,\n }\n}\n","/**\n * Registration flow\n *\n * Generates Ed25519 keypair → posts to /v1/user/register\n */\n\nimport type createFetchClient from 'openapi-fetch'\nimport type { paths } from '../schema'\nimport type { SessionManager } from '../session'\nimport { generateRegistrationCredentials } from '../crypto'\nimport { authRequestError } from './login'\n\nexport interface RegisterParams {\n email: string\n password: string\n verificationCode: string\n firstName?: string\n lastName?: string\n picture?: string\n}\n\nexport interface RegisterResult {\n signingPrivateKey: Uint8Array\n}\n\nexport async function register(\n params: RegisterParams,\n deps: {\n fetchClient: ReturnType<typeof createFetchClient<paths>>\n session: SessionManager\n deploymentDomain: string\n }\n): Promise<RegisterResult> {\n const credentials = await generateRegistrationCredentials(\n {\n email: params.email,\n verification_credential: params.verificationCode,\n given_name: params.firstName,\n family_name: params.lastName,\n picture: params.picture,\n },\n params.password,\n deps.deploymentDomain\n )\n\n const response = await deps.fetchClient.POST('/v1/user/register', {\n body: credentials.request,\n })\n\n if (response.error) {\n throw authRequestError('Registration', response.error, response.response?.status)\n }\n\n return { signingPrivateKey: credentials.signingPrivateKey }\n}\n","/**\n * Change password flow\n *\n * The password only wraps the account identity (see ../crypto/identity.ts). Changing it derives the new password\n * key, re-wraps the session's identity under it and posts both to /v1/user/change_password: one request, O(1).\n * Workspace keys, mailbox keys and direct messages stay encrypted to the unchanged identity, so nothing is\n * re-encrypted, nothing can be missed and the other party of a conversation is unaffected. The recovery key\n * (the identity secret key) is unchanged too.\n */\n\nimport type createFetchClient from 'openapi-fetch'\nimport type { paths } from '../schema'\nimport { generatePasswordChangeCredentials } from '../crypto'\nimport { getSession, updateWrappedIdentityKey } from '../storage'\n\nexport interface ChangePasswordParams {\n email: string\n newPassword: string\n /** The current password. Omit in recovery mode: the session's identity key signs instead. */\n currentPassword?: string\n /**\n * The account identity's secret key. Omitted: read from the browser session store, which is then\n * updated with the new wrap (hosts with their own key store pass it and keep `wrappedIdentityKey`).\n */\n identitySecretKey?: Uint8Array\n}\n\nexport interface ChangePasswordResult {\n /** The identity wrapped under the new password key (what a password login now returns). */\n wrappedIdentityKey: string\n}\n\n/** Pull a readable message out of whatever shape a failed call carried (`{ detail }`, `Error`). */\nexport function passwordChangeErrorMessage(err: unknown): string {\n if (err instanceof Error) return err.message\n if (err && typeof err === 'object') {\n const obj = err as Record<string, unknown>\n if (typeof obj.detail === 'string') return obj.detail\n if (typeof obj.message === 'string') return obj.message\n if (Array.isArray(obj.detail)) {\n const msgs = obj.detail\n .map((d) =>\n d && typeof (d as { msg?: unknown }).msg === 'string' ? (d as { msg: string }).msg : null\n )\n .filter((m): m is string => m !== null)\n if (msgs.length) return msgs.join('; ')\n }\n }\n return 'Failed to change password'\n}\n\n/**\n * Change (or, in recovery mode, set) the master password of the signed-in account.\n */\nexport async function changePassword(\n params: ChangePasswordParams,\n deps: { fetchClient: ReturnType<typeof createFetchClient<paths>>; deploymentDomain: string }\n): Promise<ChangePasswordResult> {\n const fromStore = !params.identitySecretKey\n const identitySecretKey = params.identitySecretKey ?? (await getSession())?.signingPrivateKey\n if (!identitySecretKey) throw new Error('Sign in to change your password')\n\n const { request } = await generatePasswordChangeCredentials(\n {\n email: params.email,\n identitySecretKey,\n newPassword: params.newPassword,\n currentPassword: params.currentPassword,\n },\n deps.deploymentDomain\n )\n const response = await deps.fetchClient.POST('/v1/user/change_password', { body: request })\n if (response.error || !response.data)\n throw response.error ?? new Error('Failed to change password')\n\n // The session keeps the identity; only the wrap that a password unlocks offline changes.\n if (fromStore) await updateWrappedIdentityKey(request.wrapped_identity_key)\n return { wrappedIdentityKey: request.wrapped_identity_key }\n}\n","/** Password-verified SSO disconnect. The identity stays fixed; only its password wrap and email change. */\nimport type createFetchClient from 'openapi-fetch'\nimport type { paths } from '../schema'\nimport { generateUserKeypairs, bytesToBase64, signMessage, wrapIdentityKey } from '../crypto'\nimport { updateWrappedIdentityKey } from '../storage'\nimport { unlockIdentityWithPassword } from './identity'\nimport { passwordChangeErrorMessage } from './change-password'\n\n// Narrow contracts for the new endpoints; reuse the app transport and its authentication middleware.\ntype SsoDisconnectPaths = {\n '/v1/user/sso-disconnect-code': {\n post: {\n requestBody: { content: { 'application/json': { new_email: string } } }\n responses: {\n 200: { content: { 'application/json': { detail: string } } }\n 400: { content: { 'application/json': { detail: string } } }\n }\n }\n }\n '/v1/user/disconnect-sso': {\n post: {\n requestBody: {\n content: {\n 'application/json': {\n new_email: string\n verification_code?: string\n timestamp: number\n signature: string\n new_login_key: string\n wrapped_identity_key: string\n }\n }\n }\n responses: {\n 200: { content: { 'application/json': { detail: string; email: string } } }\n 400: { content: { 'application/json': { detail: string } } }\n }\n }\n }\n}\n\nexport interface DisconnectSsoParams {\n email: string\n userExtId: string\n newEmail: string\n password: string\n code?: string\n}\n\ntype DisconnectSsoDeps = {\n fetchClient: ReturnType<typeof createFetchClient<paths>>\n deploymentDomain: string\n}\nconst endpointClient = (client: DisconnectSsoDeps['fetchClient']) =>\n client as unknown as ReturnType<typeof createFetchClient<SsoDisconnectPaths>>\n\n/** Verify a replacement email. Sending a code never changes the account or sign-in method. */\nexport async function requestSsoDisconnectCode(\n newEmail: string,\n deps: Pick<DisconnectSsoDeps, 'fetchClient'>\n): Promise<void> {\n const response = await endpointClient(deps.fetchClient).POST('/v1/user/sso-disconnect-code', {\n body: { new_email: newEmail.trim().toLowerCase() },\n })\n if (response.error) throw new Error(passwordChangeErrorMessage(response.error))\n}\n\n/** Confirm the master password, sign the exact change and preserve the same identity under the new email. */\nexport async function disconnectSso(\n params: DisconnectSsoParams,\n deps: DisconnectSsoDeps\n): Promise<{ email: string }> {\n const email = params.newEmail.trim().toLowerCase()\n const identity = await unlockIdentityWithPassword(\n params.email,\n params.password,\n deps.deploymentDomain\n )\n const current = await generateUserKeypairs(params.email, params.password, deps.deploymentDomain)\n const replacement = await generateUserKeypairs(email, params.password, deps.deploymentDomain)\n const timestamp = Math.floor(Date.now() / 1000)\n const newLoginKey = bytesToBase64(replacement.signingKeyPair.publicKey)\n const wrappedIdentityKey = wrapIdentityKey(identity, replacement.signingKeyPair.secretKey)\n const signature = signMessage(\n `disconnect-sso|${params.userExtId}|${email}|${timestamp}|${newLoginKey}|${wrappedIdentityKey}`,\n current.signingKeyPair.secretKey\n )\n const response = await endpointClient(deps.fetchClient).POST('/v1/user/disconnect-sso', {\n body: {\n new_email: email,\n verification_code: params.code || undefined,\n timestamp,\n signature,\n new_login_key: newLoginKey,\n wrapped_identity_key: wrappedIdentityKey,\n },\n })\n if (response.error) throw new Error(passwordChangeErrorMessage(response.error))\n await updateWrappedIdentityKey(wrappedIdentityKey)\n return { email }\n}\n","/**\n * createArbiClient() — SDK entry point\n *\n * Factory that wires together:\n * - SessionManager (in-memory state)\n * - Crypto providers (libsodium wrappers)\n * - Login / WorkspaceKeyRefresh providers (openapi-fetch transport)\n * - Relogin handler (zero-knowledge re-authentication)\n * - openapi-fetch client with 3 middleware layers\n * - High-level auth methods (register, login, logout, changePassword)\n *\n * Returns an ArbiClient object that SDK consumers interact with.\n */\n\nimport createFetchClient, { type Middleware } from 'openapi-fetch'\nimport { createMemorySessionPersistence } from './memory-persistence'\n\nimport {\n createHttpTransport,\n type HttpTransport,\n type HttpTransportOptions,\n} from './http-transport'\nimport type { paths } from './schema'\nimport {\n createSessionManager,\n createTokenProvider,\n createAuthStateProvider,\n type SessionManager,\n} from './session'\nimport {\n initSodium,\n signMessage,\n sealedBoxDecrypt,\n deriveEncryptionKeypairFromSigning,\n generateRandomSigningKeypair,\n sealKeyForSession,\n base64ToBytes,\n bytesToBase64,\n base64Encode,\n base64Decode,\n sealedBoxEncrypt,\n derivePublicKey,\n computeSharedSecret,\n encryptMessageWithSharedSecret,\n decryptMessageWithSharedSecret,\n encryptMessage,\n decryptMessage,\n generateUserKeypairs,\n unwrapWorkspaceKey,\n encryptionKeypairFromSigningKey,\n} from './crypto'\nimport { createBearerAuthMiddleware } from './middleware/bearer-auth'\nimport {\n createSessionGate,\n createSessionGateMiddleware,\n gatedFetch,\n isAbortError,\n} from './session-gate'\nimport { createWorkspaceKeys, type ListedWorkspaceKey, type WorkspaceKeys } from './workspace-keys'\nimport { createWorkspaceOpens, type WorkspaceOpens } from './workspace-opens'\nimport { createAutoReloginMiddleware } from './middleware/auto-relogin'\nimport { createDedupFetch } from './middleware/request-dedup'\nimport { createSettingsWriteBreakerFetch } from './middleware/settings-write-breaker'\nimport { createAllWorkspacesOpener, createReloginHandler, createWorkspaceReopener } from './relogin'\nimport type {\n CryptoProvider,\n LoginProvider,\n OnReloginSuccess,\n ReloginFailure,\n SessionPersistence,\n SsoTokenSource,\n WorkspaceKeyRefreshProvider,\n WorkspaceOpenProvider,\n} from './relogin/types'\nimport { readSessionClaims } from './auth/session-claims'\nimport { clearAllData, getSession, saveSession } from './storage'\nimport {\n register,\n login,\n loginWithKey,\n changePassword,\n unlockIdentityWithPassword,\n type SignInHooks,\n} from './auth'\nimport type {\n RegisterParams,\n RegisterResult,\n LoginParams,\n LoginWithKeyParams,\n LoginResult,\n ChangePasswordParams,\n ChangePasswordResult,\n} from './auth'\n\n// ============================================================================\n// API path prefix — single source of truth for route matching\n// ============================================================================\n\nexport const API_PREFIX = '/v1' as const\n\n// ============================================================================\n// Client options\n// ============================================================================\n\nexport interface ArbiClientOptions {\n /** Shared HTTP adapter, header timeout and metadata hooks; no workspace or retry policy. */\n transport?: HttpTransportOptions\n /**\n * Base URL for the ARBI API (e.g. \"https://api.mydeployment.com\"; `''` for the page's own\n * origin). A function is read on every request: a host whose configuration arrives after the\n * client is made (a runtime config file) passes a getter.\n */\n baseUrl: string | (() => string)\n /** Deployment domain used for deterministic key derivation (e.g. \"mydeployment.com\") */\n deploymentDomain: string | (() => string)\n /** URL patterns that should never trigger re-login */\n reloginExcludePatterns?: string[]\n /** Include credentials (cookies) in requests. Default: true */\n credentials?: RequestCredentials\n /**\n * The session state (token, user, selected workspace, SSO mode), read on every request. Default:\n * an in-memory one. A host app that keeps the session in its own store passes an adapter over it;\n * its `clear()` is called when the session ends (logout, or a re-login the server refused).\n */\n session?: SessionManager\n /**\n * Where the signing key and server session key are kept between page loads. Browsers default to\n * the bundled encrypted IndexedDB store; without IndexedDB the default is per-client memory.\n * Supply an adapter explicitly to persist Node sessions beyond this instance.\n */\n persistence?: SessionPersistence\n /**\n * The workspace a re-login re-opens, when the host's navigation keeps it rather than the session\n * (`session.selectedWorkspaceId`).\n */\n selectedWorkspace?: () => string | null\n /** The SSO provider's token for re-logins of SSO accounts (see `SsoTokenSource`). */\n sso?: SsoTokenSource | null\n /**\n * Extra openapi-fetch middleware, run after the bearer token is added and before the re-login\n * middleware sees the response (e.g. a host's handling of 402 Payment Required).\n */\n middleware?: Middleware[]\n /** The host's part of every sign-in (`SignInHooks`): clear the previous user, then follow up. */\n signIn?: SignInHooks\n /** Optional callback when re-login succeeds */\n onReloginSuccess?: OnReloginSuccess\n /** A request re-logged in but could not be re-sent (its body was already consumed). */\n onRetryCloneFailed?: () => void\n /**\n * Optional user email to seed the in-memory session at creation time.\n * Ensures the auto-relogin middleware can re-authenticate even when\n * the client is constructed from cached credentials (no login call).\n */\n userEmail?: string\n}\n\n// ============================================================================\n// ArbiClient interface\n// ============================================================================\n\nexport interface ArbiClient {\n /** Session-gated HTTP for raw streaming/multipart adapters. Optional for existing host adapters. */\n http?: HttpTransport\n /** Type-safe openapi-fetch client with middleware */\n fetch: ReturnType<typeof createFetchClient<paths>>\n\n /** In-memory session state */\n session: SessionManager\n\n /**\n * The user's workspace keys: the wrapped keys the workspace lists returned (shared by everything\n * on this client), and depositing a workspace's key on the session without opening it. A request\n * refused with 409 `workspace_key_required` primes the workspace it names and is sent again.\n */\n workspaceKeys: WorkspaceKeys\n\n /**\n * Every workspace `/open` on this client, one at a time and in the order asked (the server keeps\n * one active workspace per session, so concurrent opens could leave it on a workspace the client\n * left). The SDK's `selectWorkspace` and the re-opens below all go through it.\n */\n workspaceOpens: WorkspaceOpens\n\n /** High-level auth operations */\n auth: {\n register(params: RegisterParams): Promise<RegisterResult>\n login(params: LoginParams): Promise<LoginResult>\n loginWithKey(params: LoginWithKeyParams): Promise<LoginResult>\n /**\n * Sign out: the server session ends (every session of the user with `everywhere`), the session\n * state is cleared and, with `everywhere`, so are the keys kept on this device. A single sign-out\n * keeps them, so the user can unlock offline. Best-effort on the server: offline still signs out.\n */\n logout(options?: { everywhere?: boolean }): Promise<void>\n /**\n * Sign in on this device with no server (offline): the password must open the identity saved\n * at the last login here. Signed in without a token; the next request online re-logs in.\n * Throws `'no-session'` (nothing saved here) or `'bad-password'`.\n */\n unlock(params: { email: string; password: string }): Promise<void>\n /**\n * After a reload: put the stored server session key back in the session. `false` (and the\n * session cleared) when the session says signed in but this device holds no keys.\n */\n restore(): Promise<boolean>\n changePassword(params: ChangePasswordParams): Promise<ChangePasswordResult>\n /**\n * Silent re-login with the stored key (and the SSO token for an SSO account); re-opens the\n * selected workspace. Concurrent calls share one attempt and a success is reused for 5s. The\n * new token, or `null`. When the server refused it the session is over: `session.clear()` runs\n * and `onSessionExpired` listeners fire. A login still finishing or an unreachable server\n * leaves the session alone.\n */\n relogin(): Promise<string | null>\n /** Re-open the selected workspace on the server session, without a new login */\n reopenWorkspace(): Promise<boolean>\n /**\n * Seal every workspace key the user holds to this server session, so a session derived from it\n * (an MCP session) reaches every workspace. Best-effort.\n */\n openAllWorkspaces(): Promise<void>\n /** Subscribe to \"the session could not be recovered\" (see `relogin`). Returns an unsubscribe. */\n onSessionExpired(listener: () => void): () => void\n /**\n * Subscribe to \"the session is ending\" (`logout`): called once nothing new can start on it and\n * before what is in flight is aborted and the server revokes the token, so a host stops its\n * own work on it (cancels its queries, closes its socket). Returns an unsubscribe.\n */\n onSigningOut(listener: () => void): () => void\n /** A `logout` is under way: no request starts and no re-login runs until it is done. */\n isSigningOut(): boolean\n /**\n * The current session's signal: aborted when a `logout` begins, before the server revokes the\n * token. Hand it to work that must stop with the session (a socket, a stream).\n */\n sessionSignal(): AbortSignal\n }\n\n /** Crypto utilities */\n crypto: {\n initSodium: typeof initSodium\n generateUserKeypairs(email: string, password: string): ReturnType<typeof generateUserKeypairs>\n signMessage: typeof signMessage\n sealedBoxDecrypt: typeof sealedBoxDecrypt\n sealedBoxEncrypt: typeof sealedBoxEncrypt\n sealKeyForSession: typeof sealKeyForSession\n deriveEncryptionKeypairFromSigning: typeof deriveEncryptionKeypairFromSigning\n generateRandomSigningKeypair: typeof generateRandomSigningKeypair\n derivePublicKey: typeof derivePublicKey\n base64ToBytes: typeof base64ToBytes\n bytesToBase64: typeof bytesToBase64\n base64Encode: typeof base64Encode\n base64Decode: typeof base64Decode\n computeSharedSecret: typeof computeSharedSecret\n encryptMessage: typeof encryptMessage\n decryptMessage: typeof decryptMessage\n encryptMessageWithSharedSecret: typeof encryptMessageWithSharedSecret\n decryptMessageWithSharedSecret: typeof decryptMessageWithSharedSecret\n }\n\n /** The same session-key persistence used by login and session recovery. */\n storage: {\n getSession: typeof getSession\n saveSession: typeof saveSession\n }\n}\n\n// ============================================================================\n// Retry wrapper for transient connection errors (ECONNREFUSED, ECONNRESET, etc.)\n// ============================================================================\n\nconst RETRYABLE_CODES = new Set([\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'ETIMEDOUT',\n 'UND_ERR_CONNECT_TIMEOUT',\n])\nconst MAX_RETRIES = 3\nconst BASE_DELAY_MS = 200\n\nfunction isRetryableError(err: unknown): boolean {\n if (!(err instanceof Error) || isAbortError(err)) return false\n // Node/undici errors nest the cause\n const cause = (err as { cause?: { code?: string } }).cause\n if (cause?.code && RETRYABLE_CODES.has(cause.code)) return true\n // Fallback: check message for known patterns\n const msg = err.message || ''\n return RETRYABLE_CODES.has(msg) || msg.includes('ECONNREFUSED') || msg.includes('ECONNRESET')\n}\n\nfunction createRetryFetch(fetch: typeof globalThis.fetch): typeof globalThis.fetch {\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()\n const maxRetries = method === 'GET' || method === 'HEAD' ? MAX_RETRIES : 0\n const signal = init?.signal ?? (input instanceof Request ? input.signal : undefined)\n let lastError: unknown\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (signal?.aborted) throw signal.reason ?? new DOMException('Request aborted.', 'AbortError')\n try {\n const fetchInput = input instanceof Request ? input.clone() : input\n return await fetch(fetchInput, init)\n } catch (err) {\n lastError = err\n if (attempt < maxRetries && isRetryableError(err)) {\n await new Promise((r) => setTimeout(r, BASE_DELAY_MS * 2 ** attempt))\n continue\n }\n throw err\n }\n }\n throw lastError\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/** The deployment domain, read when it is used (a host may know it only after its config loaded). */\nconst HTTP_METHODS = ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE'] as const\n\n/** Every call of `fetchClient` goes to the base URL as of the call (openapi-fetch's per-request `baseUrl`). */\nfunction readBaseUrlPerRequest(\n fetchClient: ReturnType<typeof createFetchClient<paths>>,\n base: () => string\n): void {\n type Call = (url: unknown, init?: Record<string, unknown>) => unknown\n const methods = fetchClient as unknown as Record<string, Call> & {\n request: (method: unknown, url: unknown, init?: Record<string, unknown>) => unknown\n }\n for (const method of HTTP_METHODS) {\n const call = methods[method].bind(fetchClient)\n methods[method] = (url, init) => call(url, { ...init, baseUrl: base() })\n }\n const request = methods.request.bind(fetchClient)\n methods.request = (method, url, init) => request(method, url, { ...init, baseUrl: base() })\n}\n\nconst deploymentDomainOf = ({ deploymentDomain }: Pick<ArbiClientOptions, 'deploymentDomain'>) =>\n typeof deploymentDomain === 'function' ? deploymentDomain() : deploymentDomain\n\nexport function createArbiClient(options: ArbiClientOptions): ArbiClient {\n const { fetch, http, session, persistence, workspaceKeys, workspaceOpens, auth } =\n createTransport(options)\n const authDeps = {\n fetchClient: fetch,\n session,\n get deploymentDomain() {\n return deploymentDomainOf(options)\n },\n persistence,\n signIn: options.signIn,\n }\n\n return {\n fetch,\n http,\n workspaceKeys,\n workspaceOpens,\n session,\n\n auth: {\n register: (params) => register(params, authDeps),\n login: (params) => login(params, authDeps),\n loginWithKey: (params) => loginWithKey(params, authDeps),\n changePassword: (params) => changePassword(params, authDeps),\n ...auth,\n },\n\n crypto: {\n initSodium,\n generateUserKeypairs: (email, password) =>\n generateUserKeypairs(email, password, deploymentDomainOf(options)),\n signMessage,\n sealedBoxDecrypt,\n sealedBoxEncrypt,\n sealKeyForSession,\n deriveEncryptionKeypairFromSigning,\n generateRandomSigningKeypair,\n derivePublicKey,\n base64ToBytes,\n bytesToBase64,\n base64Encode,\n base64Decode,\n computeSharedSecret,\n encryptMessage,\n decryptMessage,\n encryptMessageWithSharedSecret,\n decryptMessageWithSharedSecret,\n },\n\n storage: {\n getSession: () => persistence.getSession(),\n saveSession: (data) => persistence.saveSession(data),\n },\n }\n}\n\n/** The session, the fetch client (bearer + host middleware + auto-re-login) and the recovery. */\nfunction createTransport(options: ArbiClientOptions): {\n fetch: ReturnType<typeof createFetchClient<paths>>\n http: HttpTransport\n session: SessionManager\n persistence: SessionPersistence\n workspaceKeys: WorkspaceKeys\n workspaceOpens: WorkspaceOpens\n auth: Pick<\n ArbiClient['auth'],\n | 'relogin'\n | 'reopenWorkspace'\n | 'openAllWorkspaces'\n | 'onSessionExpired'\n | 'onSigningOut'\n | 'isSigningOut'\n | 'sessionSignal'\n | 'logout'\n | 'restore'\n | 'unlock'\n >\n} {\n const {\n reloginExcludePatterns = [`${API_PREFIX}/user/login`, `${API_PREFIX}/user/logout`],\n credentials = 'include',\n sso = null,\n middleware = [],\n onReloginSuccess,\n onRetryCloneFailed,\n userEmail,\n } = options\n // Keep encrypted browser storage; Node/no-IndexedDB clients each own their memory adapter.\n const persistence: SessionPersistence =\n options.persistence ??\n (typeof indexedDB === 'undefined'\n ? createMemorySessionPersistence()\n : { getSession, saveSession, clearSession: clearAllData })\n const baseUrlOption = options.baseUrl\n /** The API base URL as of now. */\n const base = typeof baseUrlOption === 'function' ? baseUrlOption : () => baseUrlOption\n\n // 0. Create retry-aware fetch for resilience against transient connection errors. Every request\n // on the session runs under its gate, so a sign-out stops them before the token is revoked.\n const transport = createHttpTransport(options.transport)\n // Under every request of the client (re-sends, re-opens and the raw `http` included): concurrent\n // identical GETs go once, and a runaway loop of settings writes is cut off.\n const guardedFetch = createSettingsWriteBreakerFetch(createDedupFetch(transport.fetch))\n const retryFetch = createRetryFetch(guardedFetch)\n const gate = createSessionGate()\n const sessionFetch = gatedFetch(gate, retryFetch)\n const http: HttpTransport = {\n fetch: gatedFetch(gate, guardedFetch),\n customFetch: transport.customFetch,\n withFetch: (adapter) => gatedFetch(gate, transport.withFetch(adapter)),\n }\n\n // 1. The session state: the host's, or an in-memory one\n const session = options.session ?? createSessionManager()\n if (userEmail) session.setUser(userEmail)\n\n // 2. Create provider adapters\n const tokenProvider = createTokenProvider(session)\n const authState = createAuthStateProvider(session, options.selectedWorkspace)\n\n // 3. Create CryptoProvider\n const cryptoProvider: CryptoProvider = {\n ensureReady: initSodium,\n signMessage,\n deriveEncryptionKeypair: deriveEncryptionKeypairFromSigning,\n sealedBoxDecrypt,\n sealKeyForSession,\n fromBase64: base64ToBytes,\n }\n\n // 4. Create LoginProvider (raw fetch client for login — no middleware)\n const loginProvider: LoginProvider = {\n async login(payload) {\n const rawFetch = createFetchClient<paths>({\n baseUrl: base(),\n credentials,\n fetch: sessionFetch,\n })\n\n let response\n try {\n response = await rawFetch.POST('/v1/user/login', {\n body: {\n email: payload.email,\n signature: payload.signature,\n timestamp: payload.timestamp,\n sso_token: payload.ssoToken,\n },\n })\n } catch (error) {\n // An outage, not an expired session: the user must not be told to sign in again. (Or a\n // sign-out stopped it: nothing to report.)\n if (!isAbortError(error)) console.warn('[API] Login call unreachable:', error)\n return 'unreachable'\n }\n\n if (response.error || !response.data) {\n console.warn('[API] Login call failed:', response.error)\n return null\n }\n\n const data = response.data\n return {\n accessToken: data.access_token,\n sessionKey: base64ToBytes(data.session_key),\n userExtId: data.user.external_id ?? undefined,\n wrappedIdentityKey: data.wrapped_identity_key ?? null,\n }\n },\n }\n\n async function listWorkspaces(accessToken: string): Promise<ListedWorkspaceKey[] | null> {\n const response = await sessionFetch(`${base()}${API_PREFIX}/user/workspaces`, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n credentials,\n })\n return response.ok ? response.json() : null\n }\n\n // 5. The user's workspace keys: what the lists said, and depositing a key without opening.\n const workspaceKeys = createWorkspaceKeys({\n crypto: cryptoProvider,\n unwrapWorkspaceKey,\n persistence,\n getAccessToken: () => session.getState().accessToken,\n getServerSessionKey: () => session.getState().serverSessionKey,\n listWorkspaces,\n async primeKey(accessToken, workspaceId, sealedKey) {\n const response = await sessionFetch(\n `${base()}${API_PREFIX}/workspace/${workspaceId}/prime-key`,\n {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ workspace_key: sealedKey }),\n credentials,\n }\n )\n if (!response.ok) throw new Error(`Could not unlock the workspace (${response.status})`)\n },\n })\n // Another user's keys are not this one's: forget them when the session ends or changes hands.\n const workspaceOpens = createWorkspaceOpens()\n let keysUser = session.getState().signedIn ? session.getState().userExtId : null\n session.subscribe((state) => {\n const user = state.signedIn ? state.userExtId : null\n if (user !== keysUser) {\n workspaceKeys.clear()\n workspaceOpens.reset()\n }\n keysUser = user\n })\n\n const workspaceKeyRefreshProvider: WorkspaceKeyRefreshProvider = {\n async getWrappedKey(_accessToken, workspaceId) {\n return (await workspaceKeys.wrappedKey(workspaceId).catch(() => null))?.wrappedKey ?? null\n },\n }\n\n // 5b. Re-open provider: POST /open with the workspace key sealed for the session. Only the key\n // matters here, so the response leaves out the documents, conversations and tags.\n const rawWorkspaceOpenProvider: WorkspaceOpenProvider = {\n async openWorkspace(accessToken, workspaceId, encryptedWorkspaceKey) {\n const query = '?include_documents=false&include_conversations=false&include_tags=false'\n try {\n const response = await sessionFetch(\n `${base()}${API_PREFIX}/workspace/${workspaceId}/open${query}`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ workspace_key: encryptedWorkspaceKey }),\n credentials,\n }\n )\n return response.ok ? true : null\n } catch {\n return null\n }\n },\n }\n\n // Every open goes through the queue. A re-login's re-open runs only when no open is queued: the\n // queued ones (re-sent with the new token) leave the server on the latest workspace asked for,\n // and an open waiting behind one that is itself waiting for this re-login would never run.\n const workspaceOpenProvider: WorkspaceOpenProvider = {\n openWorkspace: (accessToken, workspaceId, encryptedWorkspaceKey) =>\n workspaceOpens.busy\n ? Promise.resolve(true)\n : workspaceOpens.run(\n () => workspaceId,\n () =>\n rawWorkspaceOpenProvider.openWorkspace(\n accessToken,\n workspaceId,\n encryptedWorkspaceKey\n )\n ),\n }\n\n // 6. The re-login (re-opens the selected workspace after the new login), the lighter workspace\n // re-opener (token still valid, server lost the open workspace) and the open-all.\n let lastFailure: ReloginFailure | null = null\n const expiredListeners = new Set<() => void>()\n const signingOutListeners = new Set<() => void>()\n const rawRelogin = createReloginHandler({\n crypto: cryptoProvider,\n persistence,\n authState,\n sso,\n loginProvider,\n workspaceKeyRefreshProvider,\n workspaceOpenProvider,\n // The new server session key goes into the session before the token: whatever re-renders on\n // the token reads the key that goes with it.\n async onReloginSuccess(data) {\n session.setServerSessionKey(data.serverSessionKey)\n await onReloginSuccess?.(data)\n },\n onReloginFailed: (reason) => {\n lastFailure = reason\n },\n })\n\n async function relogin(): Promise<string | null> {\n // A session being signed out is not recovered: a new login would outlive the sign-out.\n if (gate.closed) return null\n const tokenBefore = session.getState().accessToken\n const token = await rawRelogin()\n if (token) return token\n // A login that finished while this re-login failed (register then auto-login) put a fresh\n // session in place: retry with it rather than ending the session it just started.\n const tokenNow = session.getState().accessToken\n if (tokenNow && tokenNow !== tokenBefore) return tokenNow\n if (lastFailure === 'refused') {\n // Concurrent callers share one attempt: end the session once.\n lastFailure = null\n session.clear()\n for (const listener of [...expiredListeners]) listener()\n }\n return null\n }\n\n // The re-open reads the selected workspace when its turn comes, so it never re-opens one the\n // host has left meanwhile. Concurrent calls share one attempt.\n const reopenSelected = createWorkspaceReopener({\n crypto: cryptoProvider,\n persistence,\n authState,\n getAccessToken: () => session.getState().accessToken,\n workspaceKeyRefreshProvider,\n workspaceOpenProvider: rawWorkspaceOpenProvider,\n })\n let reopening: Promise<boolean> | null = null\n const reopenWorkspace = (): Promise<boolean> =>\n gate.closed\n ? Promise.resolve(false)\n : (reopening ??= workspaceOpens\n .run(() => authState.getSelectedWorkspaceId(), reopenSelected)\n .finally(() => {\n reopening = null\n }))\n\n const openEveryWorkspace = createAllWorkspacesOpener({\n crypto: cryptoProvider,\n persistence,\n getAccessToken: () => session.getState().accessToken,\n getSessionKey: (accessToken) => readSessionClaims(accessToken)?.sessionKey ?? null,\n unwrapWorkspaceKey,\n listWorkspaces: async (accessToken) => {\n const list = await listWorkspaces(accessToken)\n return list && workspaceKeys.remember(list)\n },\n workspaceOpenProvider: rawWorkspaceOpenProvider,\n lastWorkspace: () => authState.getSelectedWorkspaceId(),\n })\n // One queued open for all of them: nothing else opens in between, and the selected one is last.\n const openAllWorkspaces = () => workspaceOpens.run(() => null, openEveryWorkspace)\n\n // 7. Create openapi-fetch client with middleware\n const fetchClient = createFetchClient<paths>({\n baseUrl: base(),\n credentials,\n fetch: retryFetch,\n })\n if (typeof baseUrlOption === 'function') readBaseUrlPerRequest(fetchClient, base)\n\n // First, so the requests every later middleware sees (and retries) carry the session's signal.\n fetchClient.use(createSessionGateMiddleware(gate))\n fetchClient.use(createBearerAuthMiddleware({ tokenProvider }))\n // openapi-fetch runs onResponse in reverse order: the host's middleware sees a response after\n // the re-login middleware retried it.\n for (const m of middleware) fetchClient.use(m)\n fetchClient.use(\n createAutoReloginMiddleware({\n fetch: sessionFetch,\n reloginHandler: relogin,\n reloginExcludePatterns,\n reopenWorkspaceHandler: reopenWorkspace,\n primeWorkspaceHandler: (workspaceId) =>\n workspaceKeys.prime(workspaceId, { force: true }).then(\n () => true,\n (error: unknown) => {\n console.warn('[API] Could not unlock workspace', workspaceId, error)\n return false\n }\n ),\n onRetryCloneFailed,\n })\n )\n\n return {\n fetch: fetchClient,\n http,\n session,\n persistence,\n workspaceKeys,\n workspaceOpens,\n auth: {\n relogin,\n reopenWorkspace,\n openAllWorkspaces,\n onSigningOut(listener) {\n signingOutListeners.add(listener)\n return () => {\n signingOutListeners.delete(listener)\n }\n },\n isSigningOut: () => gate.closed,\n sessionSignal: () => gate.signal,\n async logout({ everywhere = false } = {}) {\n // The session's work stops BEFORE the server revokes its token: nothing new starts (no\n // request, no re-login, no workspace open), the host stops its own, and what is in flight\n // is aborted. Otherwise it comes back 401 on the revoked token, or a re-login on that 401\n // starts a new server session behind the sign-out.\n gate.close()\n for (const listener of [...signingOutListeners]) {\n try {\n listener()\n } catch (error) {\n console.warn('[API] A sign-out listener failed:', error)\n }\n }\n gate.abort()\n try {\n const accessToken = session.getState().accessToken\n if (accessToken) {\n // Outside the gate (it is closed): the one request of a session being signed out.\n const query = `?all_sessions=${everywhere}`\n await retryFetch(`${base()}${API_PREFIX}/user/logout${query}`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}` },\n credentials,\n }).catch((error: unknown) => console.warn('[API] Server logout failed:', error))\n }\n session.clear()\n if (everywhere) {\n if (persistence.clearSession) await persistence.clearSession()\n else if (typeof indexedDB !== 'undefined') await clearAllData()\n }\n } finally {\n gate.reopen()\n }\n },\n async unlock({ email, password }) {\n const saved = await persistence.getSession()\n if (!saved?.signingPrivateKey) throw new Error('no-session')\n let signingPrivateKey: Uint8Array\n try {\n signingPrivateKey = await unlockIdentityWithPassword(\n email,\n password,\n deploymentDomainOf(options)\n )\n } catch {\n throw new Error('bad-password')\n }\n // The encryption public key the login response would have carried, derived from the key.\n const { publicKey } = encryptionKeypairFromSigningKey(signingPrivateKey)\n session.signIn({\n accessToken: null,\n isSsoMode: false,\n serverSessionKey: saved.serverSessionKey ?? null,\n user: {\n email,\n given_name: email.split('@')[0],\n family_name: null,\n picture: null,\n external_id: saved.userExtId ?? '',\n parent_ext_id: null,\n encryption_public_key: bytesToBase64(publicKey),\n is_sso: false,\n is_identity_verified: false,\n temporary_access_only: false,\n },\n })\n },\n async restore() {\n if (!session.getState().signedIn) return false\n const keys = await persistence.getSession().catch(() => null)\n // A login that finished meanwhile has its own key: leave it.\n if (session.getState().serverSessionKey) return true\n if (keys?.signingPrivateKey && keys.serverSessionKey) {\n session.setServerSessionKey(keys.serverSessionKey)\n return true\n }\n session.clear()\n return false\n },\n onSessionExpired(listener) {\n expiredListeners.add(listener)\n return () => {\n expiredListeners.delete(listener)\n }\n },\n },\n }\n}\n","/**\n * WebSocket helpers — pure functions, no runtime dependencies.\n *\n * Consumers bring their own WebSocket implementation (browser native, Node 22+, ws package).\n * This module provides URL building, auth message creation, typed message parsing,\n * and type guards for the discriminated-union server messages.\n */\n\nimport type { components } from './schema'\nimport { API_PREFIX } from './client'\n\n// ==========================================\n// Type aliases from OpenAPI schema\n// ==========================================\n\nexport type WsAuthMessage = components['schemas']['AuthMessage']\nexport type WsAuthResultMessage = components['schemas']['AuthResultMessage']\nexport type WsTaskUpdateMessage = components['schemas']['TaskUpdateMessage']\nexport type WsBatchCompleteMessage = components['schemas']['BatchCompleteMessage']\nexport type WsConnectionClosedMessage = components['schemas']['ConnectionClosedMessage']\nexport type WsErrorMessage = components['schemas']['ErrorMessage']\nexport type WsPresenceUpdateMessage = components['schemas']['PresenceUpdateMessage']\nexport type WsNotificationResponse = components['schemas']['NotificationResponse']\nexport type WsResponseCompleteMessage = components['schemas']['ResponseCompleteMessage']\n\nexport type WsConversationMessagePostedMessage =\n components['schemas']['ConversationMessagePostedMessage']\nexport type WsChatMessageMessage = components['schemas']['ChatMessageMessage']\nexport type WsChatUpdatedMessage = components['schemas']['ChatUpdatedMessage']\nexport type WsChatReadMessage = components['schemas']['ChatReadMessage']\nexport type WsAgentDmStatusMessage = components['schemas']['AgentDmStatusMessage']\n\n/** Union of all server → client message types (discriminated on `type` field). */\nexport type WebSocketServerMessage =\n | WsTaskUpdateMessage\n | WsAuthResultMessage\n | WsConnectionClosedMessage\n | WsPresenceUpdateMessage\n | WsErrorMessage\n | WsNotificationResponse\n | WsBatchCompleteMessage\n | WsResponseCompleteMessage\n | WsConversationMessagePostedMessage\n | WsChatMessageMessage\n | WsChatUpdatedMessage\n | WsChatReadMessage\n | WsAgentDmStatusMessage\n\n/** Union of all client → server message types. */\nexport type WebSocketClientMessage = WsAuthMessage\n\n// ==========================================\n// Pure helper functions\n// ==========================================\n\n/**\n * Build a WebSocket URL from an HTTP(S) base URL.\n *\n * \"https://box-105.arbibox.com\" → \"wss://box-105.arbibox.com/v1/notifications/ws\"\n * \"http://localhost:8000\" → \"ws://localhost:8000/v1/notifications/ws\"\n */\nexport function buildWebSocketUrl(baseUrl: string): string {\n const wsScheme = baseUrl.startsWith('https') ? 'wss' : 'ws'\n const hostAndPath = baseUrl.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '')\n return `${wsScheme}://${hostAndPath}${API_PREFIX}/notifications/ws`\n}\n\n/**\n * Create the JSON auth message to send after WebSocket connection opens.\n * Returns the serialized JSON string ready to send.\n */\nexport function createAuthMessage(accessToken: string): string {\n const msg: WsAuthMessage = { type: 'auth', token: accessToken }\n return JSON.stringify(msg)\n}\n\n/**\n * Parse a raw WebSocket message string into a typed server message.\n * Returns `null` for unparseable data. Accepts any object with a string `type`\n * field — no hardcoded list of known types, so this stays valid as the schema evolves.\n */\nexport function parseServerMessage(data: string): WebSocketServerMessage | null {\n try {\n const parsed = JSON.parse(data)\n if (typeof parsed === 'object' && parsed !== null && typeof parsed.type === 'string') {\n return parsed as WebSocketServerMessage\n }\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Type guard to narrow a server message to a specific type by its `type` field value.\n *\n * Usage:\n * if (isMessageType(msg, 'task_update')) {\n * // msg is WsTaskUpdateMessage\n * }\n */\nexport function isMessageType<T extends WebSocketServerMessage>(\n msg: WebSocketServerMessage,\n type: T['type']\n): msg is T {\n return msg.type === type\n}\n","/**\n * One console logger for an ARBI frontend and its packages: errors always print; warnings, info\n * and debug lines print only when the host turns verbose logging on (in development, say:\n * `configureLogger({ verbose: import.meta.env.DEV })` at startup). The package never reads a\n * bundler's environment itself.\n */\n\nlet verbose = false\n\nexport interface LoggerOptions {\n /** Print `warn`, `info` and `debug` too. Off by default. */\n verbose: boolean\n}\n\nexport function configureLogger(options: LoggerOptions): void {\n verbose = options.verbose\n}\n\nexport const logger = {\n /** Always printed, production included. */\n error: (...args: unknown[]): void => {\n console.error(...args)\n },\n warn: (...args: unknown[]): void => {\n if (verbose) console.warn(...args)\n },\n info: (...args: unknown[]): void => {\n if (verbose) console.info(...args)\n },\n debug: (...args: unknown[]): void => {\n if (verbose) console.debug(...args)\n },\n}\n"]}
|