@tinycloud/replica 0.2.4-beta.2 → 0.3.0-beta.4
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/README.md +29 -0
- package/dist/browser.d.ts +6 -0
- package/dist/browser.js +7 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +20 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +20 -2
- package/dist/index.js.map +1 -1
- package/dist/kv-storage-testing.d.ts +83 -0
- package/dist/kv-storage-testing.js +1145 -0
- package/dist/kv-storage-testing.js.map +1 -0
- package/dist/kv-storage.d.ts +155 -0
- package/dist/kv-storage.js +2587 -0
- package/dist/kv-storage.js.map +1 -0
- package/dist/kv-storage.worker.618d3a20b6f3f54ed78b68f1dc244dddc3daba46e91e9ae2b577685cc9339315.js +18891 -0
- package/dist/kv-storage.worker.d.ts +2 -0
- package/dist/kv-storage.worker.js +18891 -0
- package/dist/kv-storage.worker.js.map +1 -0
- package/dist/profile-gate.cjs +560 -0
- package/dist/profile-gate.cjs.map +1 -0
- package/dist/profile-gate.d.cts +89 -0
- package/dist/profile-gate.d.ts +89 -0
- package/dist/profile-gate.js +517 -0
- package/dist/profile-gate.js.map +1 -0
- package/dist/replica.worker.js +444 -171
- package/dist/replica.worker.js.map +1 -1
- package/dist/sqlite.cjs +926 -239
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.d.cts +77 -8
- package/dist/sqlite.d.ts +77 -8
- package/dist/sqlite.js +914 -229
- package/dist/sqlite.js.map +1 -1
- package/dist/{types-f3-kYLQZ.d.cts → types-CQ61VnsP.d.cts} +1 -1
- package/dist/{types-f3-kYLQZ.d.ts → types-CQ61VnsP.d.ts} +1 -1
- package/package.json +20 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../bootstrap/src/index.ts","../../bootstrap/src/generated/capabilities.ts","../../bootstrap/src/capabilities.ts","../../sdk-services/src/kv/replication/constants.ts","../../sdk-services/src/kv/replication/identity.ts","../../sdk-services/src/kv/replication/prefix.ts","../../sdk-services/src/kv/replication/scope.ts","../../sdk-services/src/errors.ts","../../sdk-services/src/types.ts","../../sdk-services/src/kv/replication/outcome.ts","../../sdk-services/src/kv/replication/pendingWrites.ts","../../sdk-services/src/kv/replication/localResponse.ts","../../sdk-services/src/kv/replication/listLocal.ts","../../sdk-services/src/kv/replication/events.ts","../../sdk-services/src/kv/replication/grantPolicyConstants.ts","../../sdk-services/src/kv/replication/grantPolicy.ts","../../sdk-services/src/kv/replication/controller.ts","../../sdk-services/src/kv/replication/memoryPendingStore.ts","../src/errors.ts","../../sdk-services/src/kv/replication/prefix.ts","../src/scope.ts","../src/browser/idb.ts","../src/kv-storage/gateKeys.ts","../../sdk-services/src/kv/replication/grantPolicyConstants.ts","../../sdk-services/src/kv/replication/contractConstants.ts","../src/did.ts","../src/kv-storage/sealed.ts","../src/kv-storage/schema.ts","../src/kv-storage/ledger.ts","../src/kv-storage/gateTx.ts","../src/kv-storage/lifecycle.ts","../src/kv-storage/codec.ts","../src/kv-storage/pending.ts","../src/kv-storage/client.ts"],"sourcesContent":["import { getAddress, isAddress } from \"viem\";\nimport { KV, SQL, CAPABILITIES, SPACE, ENCRYPTION } from \"./capabilities.js\";\n\nexport * from \"./capabilities.js\";\n\nexport type ManifestDefaults = boolean | \"admin\" | \"all\";\n\nexport interface PermissionEntry {\n service: string;\n space?: string;\n path: string;\n actions: string[];\n skipPrefix?: boolean;\n expiry?: string;\n description?: string;\n}\n\nexport interface Manifest {\n manifest_version?: 1;\n app_id: string;\n name: string;\n description?: string;\n did?: string;\n icon?: string;\n appVersion?: string;\n expiry?: string;\n space?: string;\n prefix?: string;\n defaults?: ManifestDefaults | string;\n includePublicSpace?: boolean;\n knowledge?: true | string;\n permissions?: PermissionEntry[];\n}\n\nexport interface ResourceCapability {\n service: string;\n space: string;\n path: string;\n actions: string[];\n expiryMs?: number;\n description?: string;\n}\n\nexport interface ManifestRegistryRecord {\n key: string;\n app_id: string;\n manifests: Manifest[];\n}\n\nexport interface ComposedManifestRequest {\n manifests: Manifest[];\n resources: ResourceCapability[];\n delegationTargets: [];\n registryRecords: ManifestRegistryRecord[];\n expiryMs: number;\n includePublicSpace: boolean;\n}\n\nexport interface ComposeManifestOptions {\n includeAccountRegistryPermissions?: boolean;\n}\n\nexport const DEFAULT_MANIFEST_SPACE = \"applications\";\nexport const ACCOUNT_REGISTRY_SPACE = \"account\";\nexport const ACCOUNT_REGISTRY_PATH = \"applications/\";\nexport const SECRETS_SPACE = \"secrets\";\nexport const BOOTSTRAP_DEFAULT_SPACE = \"default\";\nexport const BOOTSTRAP_PUBLIC_SPACE = \"public\";\nexport const AGENTS_SPACE = \"agents\";\nexport const BOOTSTRAP_ENCRYPTION_NETWORK_NAME = \"default\";\nexport const BOOTSTRAP_ENCRYPTION_NETWORK_RESOURCE_TEMPLATE =\n `urn:tinycloud:encryption:{ownerDid}:${BOOTSTRAP_ENCRYPTION_NETWORK_NAME}` as const;\n\nconst DEFAULT_EXPIRY_MS = 30 * 24 * 60 * 60 * 1000;\nconst VAULT_PERMISSION_SERVICE = \"tinycloud.vault\";\nconst ENCRYPTION_PERMISSION_SERVICE = \"tinycloud.encryption\";\nconst ENCRYPTION_MANIFEST_SPACE = \"encryption\";\nconst NETWORK_CREATE_ACTION = ENCRYPTION.NETWORK_CREATE;\n\nexport const BOOTSTRAP_SPACE_NAMES = [\n BOOTSTRAP_DEFAULT_SPACE,\n DEFAULT_MANIFEST_SPACE,\n ACCOUNT_REGISTRY_SPACE,\n SECRETS_SPACE,\n BOOTSTRAP_PUBLIC_SPACE,\n AGENTS_SPACE,\n] as const;\n\nexport type BootstrapSpaceName = (typeof BOOTSTRAP_SPACE_NAMES)[number];\n\nexport const TINYCLOUD_DEFAULT_SPACE_MANIFEST: Manifest = {\n app_id: \"xyz.tinycloud.default\",\n name: \"TinyCloud Default Space\",\n space: BOOTSTRAP_DEFAULT_SPACE,\n prefix: \"\",\n defaults: false,\n includePublicSpace: false,\n permissions: [\n {\n service: \"tinycloud.kv\",\n space: BOOTSTRAP_DEFAULT_SPACE,\n // Empty path = whole service on this space. Do NOT use \"/\": the recap\n // encoder joins it as `<space>/<service>//`, which the node's byte-prefix\n // resource matching can never extend (real paths start `<service>/x…`).\n path: \"\",\n actions: [\"get\", \"put\", \"del\", \"list\", \"metadata\"],\n },\n {\n service: \"tinycloud.sql\",\n space: BOOTSTRAP_DEFAULT_SPACE,\n path: \"\",\n actions: [\"read\", \"write\"],\n },\n ],\n};\n\nexport const TINYCLOUD_APPLICATIONS_SPACE_MANIFEST: Manifest = {\n app_id: \"xyz.tinycloud.applications\",\n name: \"TinyCloud Applications Space\",\n space: DEFAULT_MANIFEST_SPACE,\n prefix: \"\",\n defaults: false,\n includePublicSpace: false,\n permissions: [\n {\n service: \"tinycloud.kv\",\n space: DEFAULT_MANIFEST_SPACE,\n // Empty path = whole service on this space. Do NOT use \"/\": the recap\n // encoder joins it as `<space>/<service>//`, which the node's byte-prefix\n // resource matching can never extend (real paths start `<service>/x…`).\n path: \"\",\n actions: [\"get\", \"put\", \"del\", \"list\", \"metadata\"],\n },\n {\n service: \"tinycloud.sql\",\n space: DEFAULT_MANIFEST_SPACE,\n path: \"\",\n actions: [\"read\", \"write\"],\n },\n ],\n};\n\nexport const TINYCLOUD_ACCOUNT_SPACE_MANIFEST: Manifest = {\n app_id: \"xyz.tinycloud.account\",\n name: \"TinyCloud Account Registry\",\n space: ACCOUNT_REGISTRY_SPACE,\n prefix: \"\",\n defaults: false,\n includePublicSpace: false,\n permissions: [\n {\n service: \"tinycloud.kv\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"applications/\",\n actions: [\"get\", \"put\", \"list\"],\n },\n {\n service: \"tinycloud.kv\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"spaces/\",\n actions: [\"get\", \"put\", \"list\"],\n },\n {\n service: \"tinycloud.sql\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"account\",\n actions: [\"read\", \"write\", \"schema\"],\n },\n ],\n};\n\nexport const TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST: Manifest = {\n app_id: \"xyz.tinycloud.secrets\",\n name: \"TinyCloud Secrets\",\n space: SECRETS_SPACE,\n prefix: \"\",\n defaults: false,\n includePublicSpace: false,\n permissions: [\n {\n service: \"tinycloud.vault\",\n space: SECRETS_SPACE,\n path: \"secrets/\",\n actions: [\"read\"],\n skipPrefix: true,\n },\n {\n service: \"tinycloud.kv\",\n space: SECRETS_SPACE,\n path: \"variables\",\n actions: [\"list\", \"metadata\"],\n skipPrefix: true,\n },\n {\n service: \"tinycloud.kv\",\n space: SECRETS_SPACE,\n path: \"variables/\",\n actions: [\"get\", \"put\", \"del\", \"list\", \"metadata\"],\n skipPrefix: true,\n },\n {\n service: \"tinycloud.sql\",\n space: SECRETS_SPACE,\n path: \"default\",\n actions: [\"read\", \"write\", \"schema\"],\n skipPrefix: true,\n },\n {\n service: \"tinycloud.capabilities\",\n space: SECRETS_SPACE,\n path: \"\",\n actions: [\"read\"],\n skipPrefix: true,\n },\n ],\n};\n\nexport const TINYCLOUD_PUBLIC_SPACE_MANIFEST: Manifest = {\n app_id: \"xyz.tinycloud.public\",\n name: \"TinyCloud Public Space\",\n space: BOOTSTRAP_PUBLIC_SPACE,\n prefix: \"\",\n defaults: false,\n includePublicSpace: false,\n permissions: [\n {\n service: \"tinycloud.kv\",\n space: BOOTSTRAP_PUBLIC_SPACE,\n path: \"\",\n actions: [\"get\", \"list\", \"metadata\"],\n },\n ],\n};\n\nexport const TINYCLOUD_AGENTS_SPACE_MANIFEST: Manifest = {\n app_id: \"xyz.tinycloud.agents\",\n name: \"TinyCloud Agents Space\",\n space: AGENTS_SPACE,\n prefix: \"\",\n defaults: false,\n includePublicSpace: false,\n permissions: [\n {\n service: \"tinycloud.kv\",\n space: AGENTS_SPACE,\n path: \"\",\n actions: [\"get\", \"put\", \"del\", \"list\", \"metadata\"],\n },\n ],\n};\n\nexport const BOOTSTRAP_SPACE_MANIFESTS: Readonly<Record<BootstrapSpaceName, Manifest>> = {\n [BOOTSTRAP_DEFAULT_SPACE]: TINYCLOUD_DEFAULT_SPACE_MANIFEST,\n [DEFAULT_MANIFEST_SPACE]: TINYCLOUD_APPLICATIONS_SPACE_MANIFEST,\n [ACCOUNT_REGISTRY_SPACE]: TINYCLOUD_ACCOUNT_SPACE_MANIFEST,\n [SECRETS_SPACE]: TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,\n [BOOTSTRAP_PUBLIC_SPACE]: TINYCLOUD_PUBLIC_SPACE_MANIFEST,\n [AGENTS_SPACE]: TINYCLOUD_AGENTS_SPACE_MANIFEST,\n};\n\nexport const BOOTSTRAP_PERSISTED_APPLICATION_MANIFESTS = [\n TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,\n] as const;\n\nexport const ACCOUNT_INDEX_SCHEMA = [\n `CREATE TABLE IF NOT EXISTS applications (\n app_id TEXT PRIMARY KEY,\n name TEXT,\n description TEXT,\n updated_at TEXT,\n manifest_json TEXT NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS application_state (\n app_id TEXT PRIMARY KEY,\n manifest_hash TEXT NOT NULL,\n indexed_at TEXT NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS spaces (\n space_id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n owner_did TEXT NOT NULL,\n type TEXT NOT NULL,\n permissions_json TEXT NOT NULL,\n status TEXT NOT NULL,\n registered_at TEXT,\n updated_at TEXT NOT NULL,\n expires_at TEXT\n )`,\n `CREATE TABLE IF NOT EXISTS delegations (\n cid TEXT PRIMARY KEY,\n direction TEXT NOT NULL,\n space_id TEXT NOT NULL,\n space_name TEXT,\n counterparty_did TEXT NOT NULL,\n delegate_did TEXT NOT NULL,\n delegator_did TEXT,\n path TEXT NOT NULL,\n actions_json TEXT NOT NULL,\n expiry TEXT NOT NULL,\n status TEXT NOT NULL,\n created_at TEXT,\n updated_at TEXT NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS sync_state (\n source TEXT PRIMARY KEY,\n synced_at TEXT NOT NULL,\n count INTEGER NOT NULL\n )`,\n \"CREATE INDEX IF NOT EXISTS idx_delegations_direction ON delegations(direction)\",\n \"CREATE INDEX IF NOT EXISTS idx_delegations_space ON delegations(space_id)\",\n \"CREATE INDEX IF NOT EXISTS idx_delegations_counterparty ON delegations(counterparty_did)\",\n \"CREATE INDEX IF NOT EXISTS idx_spaces_owner ON spaces(owner_did)\",\n \"CREATE INDEX IF NOT EXISTS idx_spaces_type ON spaces(type)\",\n] as const;\n\nexport const SECRET_RECORDS_SCHEMA = [\n `CREATE TABLE IF NOT EXISTS secret_records (\n scope TEXT NOT NULL,\n name TEXT NOT NULL,\n provider_id TEXT,\n custom_note TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n last_tested TEXT,\n test_status TEXT,\n test_message TEXT,\n PRIMARY KEY(scope, name)\n )`,\n] as const;\n\nexport interface BootstrapSpaceDescriptor {\n name: BootstrapSpaceName;\n manifest: Manifest;\n persistedAsApplication: boolean;\n}\n\nexport interface BootstrapManifest {\n spaces: readonly BootstrapSpaceDescriptor[];\n applications: readonly Manifest[];\n accountIndexSchema: readonly string[];\n secretRecordsSchema: readonly string[];\n encryptionNetwork: {\n name: typeof BOOTSTRAP_ENCRYPTION_NETWORK_NAME;\n };\n}\n\nexport const BOOTSTRAP_MANIFEST: BootstrapManifest = {\n spaces: BOOTSTRAP_SPACE_NAMES.map((name) => ({\n name,\n manifest: BOOTSTRAP_SPACE_MANIFESTS[name],\n persistedAsApplication: name === SECRETS_SPACE,\n })),\n applications: BOOTSTRAP_PERSISTED_APPLICATION_MANIFESTS,\n accountIndexSchema: ACCOUNT_INDEX_SCHEMA,\n secretRecordsSchema: SECRET_RECORDS_SCHEMA,\n encryptionNetwork: {\n name: BOOTSTRAP_ENCRYPTION_NETWORK_NAME,\n },\n};\n\nexport type BootstrapAllowlistKind = \"session\" | \"space/host\";\n\nexport interface BootstrapRawAbilityAllowlistEntry {\n service: \"tinycloud.encryption\";\n resource: typeof BOOTSTRAP_ENCRYPTION_NETWORK_RESOURCE_TEMPLATE;\n actions: readonly [typeof NETWORK_CREATE_ACTION];\n}\n\nexport interface BootstrapAllowlistEntry {\n kind: BootstrapAllowlistKind;\n space: BootstrapSpaceName;\n service: \"tinycloud.session\" | \"tinycloud.space\";\n actions: readonly string[];\n resources?: readonly ResourceCapability[];\n rawAbilities?: readonly BootstrapRawAbilityAllowlistEntry[];\n}\n\nfunction assertAddress(address: string): string {\n if (!isAddress(address, { strict: false })) {\n throw new Error(`Invalid EVM address: ${address}`);\n }\n return getAddress(address);\n}\n\nfunction assertChainId(chainId: number): void {\n if (!Number.isSafeInteger(chainId) || chainId <= 0) {\n throw new Error(`Invalid EIP-155 chain ID: ${chainId}`);\n }\n}\n\nexport function pkhDid(address: string, chainId: number = 1): string {\n assertChainId(chainId);\n return `did:pkh:eip155:${chainId}:${assertAddress(address)}`;\n}\n\nexport function makePkhSpaceId(\n address: string,\n chainId: number,\n name: string,\n): string {\n assertChainId(chainId);\n if (!name) {\n throw new Error(\"Space name cannot be empty\");\n }\n return `tinycloud:pkh:eip155:${chainId}:${assertAddress(address)}:${name}`;\n}\n\nfunction cloneManifest(manifest: Manifest): Manifest {\n return {\n ...manifest,\n permissions: manifest.permissions?.map((permission) => ({\n ...permission,\n actions: [...permission.actions],\n })),\n };\n}\n\nfunction actionUrn(service: string, action: string): string {\n return action.includes(\"/\") ? action : `${service}/${action}`;\n}\n\nfunction applyPrefix(prefix: string, path: string, skipPrefix?: boolean): string {\n if (skipPrefix === true || prefix === \"\" || path === \"\") {\n return path;\n }\n if (path === \"/\") {\n return `${prefix}/`;\n }\n const trimmedPrefix = prefix.endsWith(\"/\") ? prefix.slice(0, -1) : prefix;\n const trimmedPath = path.startsWith(\"/\") ? path.slice(1) : path;\n return `${trimmedPrefix}/${trimmedPath}`;\n}\n\nfunction expandVaultPermission(entry: PermissionEntry): PermissionEntry[] {\n return entry.actions.map((action) => {\n const normalized = action.startsWith(\"tinycloud.vault/\")\n ? action.slice(\"tinycloud.vault/\".length)\n : action.startsWith(\"tinycloud.kv/\")\n ? action.slice(\"tinycloud.kv/\".length)\n : action;\n const mapped =\n normalized === \"read\" || normalized === \"get\"\n ? KV.GET\n : normalized === \"write\" || normalized === \"put\"\n ? KV.PUT\n : normalized === \"delete\" || normalized === \"del\"\n ? KV.DEL\n : normalized === \"list\"\n ? KV.LIST\n : normalized === \"metadata\"\n ? KV.METADATA\n : undefined;\n if (mapped === undefined) {\n throw new Error(`unknown vault action ${JSON.stringify(action)}`);\n }\n const normalizedPath = entry.path.startsWith(\"/\")\n ? entry.path.slice(1)\n : entry.path;\n return {\n ...entry,\n service: \"tinycloud.kv\",\n path: `vault/${normalizedPath}`,\n actions: [mapped],\n skipPrefix: true,\n };\n });\n}\n\nfunction expandPermissionEntry(\n entry: PermissionEntry,\n prefix: string,\n inheritedSpace: string,\n): ResourceCapability[] {\n if (entry.service === VAULT_PERMISSION_SERVICE) {\n return expandVaultPermission(entry).flatMap((expanded) =>\n expandPermissionEntry(expanded, prefix, inheritedSpace),\n );\n }\n const skipPrefix =\n entry.skipPrefix === true || entry.service === ENCRYPTION_PERMISSION_SERVICE;\n return [\n {\n service: entry.service,\n space:\n entry.service === ENCRYPTION_PERMISSION_SERVICE\n ? ENCRYPTION_MANIFEST_SPACE\n : entry.space ?? inheritedSpace,\n path: applyPrefix(prefix, entry.path, skipPrefix),\n actions: entry.actions.map((action) => actionUrn(entry.service, action)),\n ...(entry.description !== undefined ? { description: entry.description } : {}),\n },\n ];\n}\n\nfunction dedupeResources(resources: readonly ResourceCapability[]): ResourceCapability[] {\n const byKey = new Map<string, ResourceCapability>();\n for (const resource of resources) {\n const key = `${resource.service}\\u0000${resource.space}\\u0000${resource.path}`;\n const existing = byKey.get(key);\n if (!existing) {\n byKey.set(key, { ...resource, actions: [...resource.actions] });\n continue;\n }\n for (const action of resource.actions) {\n if (!existing.actions.includes(action)) {\n existing.actions.push(action);\n }\n }\n }\n return [...byKey.values()];\n}\n\nfunction withCapabilitiesReadForSpaces(\n resources: readonly ResourceCapability[],\n): ResourceCapability[] {\n const spaces = new Set(\n resources\n .filter((resource) => resource.service !== ENCRYPTION_PERMISSION_SERVICE)\n .map((resource) => resource.space),\n );\n return dedupeResources([\n ...resources,\n ...[...spaces].map((space) => ({\n service: \"tinycloud.capabilities\",\n space,\n path: \"\",\n actions: [CAPABILITIES.READ],\n })),\n ]);\n}\n\nexport function composeManifestRequest(\n inputs: readonly Manifest[],\n options: ComposeManifestOptions = {},\n): ComposedManifestRequest {\n if (!Array.isArray(inputs) || inputs.length === 0) {\n throw new Error(\"composeManifestRequest requires at least one manifest\");\n }\n\n const includeAccountRegistryPermissions =\n options.includeAccountRegistryPermissions ?? true;\n const manifests = inputs.map(cloneManifest);\n const resources = manifests.flatMap((manifest) => {\n const prefix = manifest.prefix ?? manifest.app_id;\n const space = manifest.space ?? DEFAULT_MANIFEST_SPACE;\n const explicit = manifest.permissions ?? [];\n return explicit.flatMap((entry) => expandPermissionEntry(entry, prefix, space));\n });\n\n if (includeAccountRegistryPermissions) {\n resources.push(\n ...ACCOUNT_MANIFEST_PERMISSIONS.map((resource) => ({\n ...resource,\n actions: [...resource.actions],\n })),\n );\n }\n\n const manifestsByAppId = new Map<string, Manifest[]>();\n for (const manifest of manifests) {\n const current = manifestsByAppId.get(manifest.app_id) ?? [];\n current.push(cloneManifest(manifest));\n manifestsByAppId.set(manifest.app_id, current);\n }\n\n return {\n manifests,\n resources: withCapabilitiesReadForSpaces(resources),\n delegationTargets: [],\n registryRecords: includeAccountRegistryPermissions\n ? [...manifestsByAppId.entries()].map(([app_id, appManifests]) => ({\n key: `${ACCOUNT_REGISTRY_PATH}${app_id}`,\n app_id,\n manifests: appManifests,\n }))\n : [],\n expiryMs: DEFAULT_EXPIRY_MS,\n includePublicSpace: manifests.some(\n (manifest) => manifest.includePublicSpace ?? true,\n ),\n };\n}\n\nexport function composeBootstrapSpaceManifest(\n space: BootstrapSpaceName,\n): ComposedManifestRequest {\n return composeManifestRequest([BOOTSTRAP_SPACE_MANIFESTS[space]], {\n includeAccountRegistryPermissions: false,\n });\n}\n\n/**\n * The canonical account authority granted to ordinary sign-in sessions.\n *\n * Keep the completion marker as its own exact key: the registry prefixes do\n * not cover it. Consumers must clone entries and actions before composing a\n * request or converting this value to mutable WASM abilities.\n */\nexport const ACCOUNT_MANIFEST_PERMISSIONS: readonly ResourceCapability[] = Object.freeze([\n {\n service: \"tinycloud.kv\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: ACCOUNT_REGISTRY_PATH,\n actions: [KV.GET, KV.PUT, KV.LIST],\n },\n {\n service: \"tinycloud.kv\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"spaces/\",\n actions: [KV.GET, KV.PUT, KV.LIST],\n },\n {\n service: \"tinycloud.kv\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"system/bootstrap/complete\",\n actions: [KV.GET, KV.PUT],\n },\n {\n service: \"tinycloud.delegation\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"\",\n actions: [\"tinycloud.delegation/list\"],\n },\n {\n service: \"tinycloud.sql\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"account\",\n actions: [SQL.READ, SQL.WRITE, SQL.SCHEMA],\n },\n {\n service: \"tinycloud.capabilities\",\n space: ACCOUNT_REGISTRY_SPACE,\n path: \"\",\n actions: [CAPABILITIES.READ],\n },\n]);\n\nexport const BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST =\n composeBootstrapSpaceManifest(BOOTSTRAP_DEFAULT_SPACE);\n\nconst BOOTSTRAP_WIDENED_DEFAULT_SESSION_REQUEST: ComposedManifestRequest = {\n ...BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST,\n resources: [\n ...BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST.resources,\n ...ACCOUNT_MANIFEST_PERMISSIONS.map((resource) => ({\n ...resource,\n actions: [...resource.actions],\n })),\n ],\n};\n\nexport const BOOTSTRAP_SESSION_REQUESTS: Readonly<\n Record<BootstrapSpaceName, ComposedManifestRequest>\n> = Object.freeze(\n Object.fromEntries(\n BOOTSTRAP_SPACE_NAMES.map((space) => [\n space,\n space === BOOTSTRAP_DEFAULT_SPACE\n ? BOOTSTRAP_WIDENED_DEFAULT_SESSION_REQUEST\n : composeBootstrapSpaceManifest(space),\n ]),\n ) as Record<BootstrapSpaceName, ComposedManifestRequest>,\n);\n\nconst ACCOUNT_SESSION_RAW_ALLOWLIST: readonly BootstrapRawAbilityAllowlistEntry[] =\n Object.freeze([\n {\n service: \"tinycloud.encryption\",\n resource: BOOTSTRAP_ENCRYPTION_NETWORK_RESOURCE_TEMPLATE,\n actions: [NETWORK_CREATE_ACTION],\n },\n ]);\n\nexport const BOOTSTRAP_ALLOWLIST: readonly BootstrapAllowlistEntry[] =\n Object.freeze(\n BOOTSTRAP_SPACE_NAMES.flatMap((space) => [\n {\n kind: \"session\" as const,\n service: \"tinycloud.session\" as const,\n space,\n actions: [\"siwe\"],\n resources: BOOTSTRAP_SESSION_REQUESTS[space].resources,\n ...(space === ACCOUNT_REGISTRY_SPACE\n ? { rawAbilities: ACCOUNT_SESSION_RAW_ALLOWLIST }\n : {}),\n },\n {\n kind: \"space/host\" as const,\n service: \"tinycloud.space\" as const,\n space,\n actions: [SPACE.HOST],\n },\n ]),\n );\n\nexport type BootstrapStepKind =\n | \"session\"\n | \"host\"\n | \"activate\"\n | \"account-index-schema\"\n | \"seed-spaces\"\n | \"seed-applications\"\n | \"encryption-network-create\"\n | \"secret-records-schema\";\n\nexport interface BootstrapStepBase {\n id: string;\n kind: BootstrapStepKind;\n}\n\nexport interface BootstrapSpaceStep extends BootstrapStepBase {\n kind: \"session\" | \"host\" | \"activate\";\n space: BootstrapSpaceName;\n spaceId: string;\n request?: ComposedManifestRequest;\n rawAbilities?: Record<string, string[]>;\n includeEncryptionNetworkCreate?: boolean;\n}\n\nexport interface BootstrapSchemaStep extends BootstrapStepBase {\n kind: \"account-index-schema\" | \"secret-records-schema\";\n space: typeof ACCOUNT_REGISTRY_SPACE | typeof SECRETS_SPACE;\n spaceId: string;\n database: string;\n schema: readonly string[];\n}\n\nexport interface BootstrapSeedSpacesStep extends BootstrapStepBase {\n kind: \"seed-spaces\";\n spaces: readonly {\n name: BootstrapSpaceName;\n spaceId: string;\n }[];\n}\n\nexport interface BootstrapSeedApplicationsStep extends BootstrapStepBase {\n kind: \"seed-applications\";\n manifests: readonly Manifest[];\n}\n\nexport interface BootstrapEncryptionNetworkStep extends BootstrapStepBase {\n kind: \"encryption-network-create\";\n networkId: string;\n}\n\nexport type BootstrapStep =\n | BootstrapSpaceStep\n | BootstrapSchemaStep\n | BootstrapSeedSpacesStep\n | BootstrapSeedApplicationsStep\n | BootstrapEncryptionNetworkStep;\n\nexport function bootstrapSpaceId(\n address: string,\n chainId: number,\n space: BootstrapSpaceName,\n): string {\n return makePkhSpaceId(address, chainId, space);\n}\n\nexport function bootstrapEncryptionNetworkId(\n address: string,\n chainId: number,\n): string {\n return `urn:tinycloud:encryption:${pkhDid(address, chainId)}:${BOOTSTRAP_ENCRYPTION_NETWORK_NAME}`;\n}\n\nexport function bootstrapSteps(\n address: string,\n chainId: number,\n): BootstrapStep[] {\n const spaces = BOOTSTRAP_SPACE_NAMES.map((name) => ({\n name,\n spaceId: bootstrapSpaceId(address, chainId, name),\n }));\n const account = spaces.find((space) => space.name === ACCOUNT_REGISTRY_SPACE)!;\n const secrets = spaces.find((space) => space.name === SECRETS_SPACE)!;\n const networkId = bootstrapEncryptionNetworkId(address, chainId);\n\n return [\n ...spaces.map((space) => ({\n id: `session:${space.name}`,\n kind: \"session\" as const,\n space: space.name,\n spaceId: space.spaceId,\n request: BOOTSTRAP_SESSION_REQUESTS[space.name],\n includeEncryptionNetworkCreate: space.name === ACCOUNT_REGISTRY_SPACE,\n ...(space.name === ACCOUNT_REGISTRY_SPACE\n ? { rawAbilities: { [networkId]: [NETWORK_CREATE_ACTION] } }\n : {}),\n })),\n ...spaces.map((space) => ({\n id: `host:${space.name}`,\n kind: \"host\" as const,\n space: space.name,\n spaceId: space.spaceId,\n })),\n ...spaces.map((space) => ({\n id: `activate:${space.name}`,\n kind: \"activate\" as const,\n space: space.name,\n spaceId: space.spaceId,\n })),\n {\n id: \"account:index-schema\",\n kind: \"account-index-schema\",\n space: ACCOUNT_REGISTRY_SPACE,\n spaceId: account.spaceId,\n database: \"account\",\n schema: ACCOUNT_INDEX_SCHEMA,\n },\n {\n id: \"account:seed-spaces\",\n kind: \"seed-spaces\",\n spaces,\n },\n {\n id: \"account:seed-applications\",\n kind: \"seed-applications\",\n manifests: BOOTSTRAP_PERSISTED_APPLICATION_MANIFESTS,\n },\n {\n id: \"encryption:network-create\",\n kind: \"encryption-network-create\",\n networkId,\n },\n {\n id: \"secrets:secret-records-schema\",\n kind: \"secret-records-schema\",\n space: SECRETS_SPACE,\n spaceId: secrets.spaceId,\n database: \"default\",\n schema: SECRET_RECORDS_SCHEMA,\n },\n ];\n}\n","// @generated by scripts/gen-capabilities.mjs — DO NOT EDIT.\n// Source: capabilities.json (registry version 1, sha256 78866ee7b73c964a9698e71d1411f049d1655d5c832fb168191ef63943efe26a).\n//\n// Canonical single source of truth for TinyCloud capability action URNs (TC-112).\n// Regenerate with: node scripts/gen-capabilities.mjs\n\nexport const REGISTRY_VERSION = 1 as const;\nexport const REGISTRY_SOURCE_SHA256 = \"78866ee7b73c964a9698e71d1411f049d1655d5c832fb168191ef63943efe26a\" as const;\n\n/** GitHub repository the registry lives in (TC-121; js-sdk sync anchor). */\nexport const REGISTRY_SOURCE_REPO = \"TinyCloudLabs/tinycloud-node\" as const;\n/**\n * Git commit the artifact was generated from. Authoritative when generated\n * in CI (GITHUB_SHA); approximate when generated locally, where it names\n * the parent of the commit that will contain this artifact.\n */\nexport const REGISTRY_SOURCE_GIT_SHA = \"a11ea8f1911be8bc4768122444fd831c933e2150\" as const;\n\nexport type CapabilityStatus = \"active\" | \"deprecated-alias\" | \"reserved\";\n\nexport interface CapabilityEntry {\n urn: string;\n service: string;\n status: CapabilityStatus;\n aliasOf?: string;\n implies?: readonly string[];\n}\n\nexport const CAPABILITIES: readonly CapabilityEntry[] = [\n { urn: \"tinycloud.kv/get\", service: \"tinycloud.kv\", status: \"active\" },\n { urn: \"tinycloud.kv/list\", service: \"tinycloud.kv\", status: \"active\" },\n { urn: \"tinycloud.kv/metadata\", service: \"tinycloud.kv\", status: \"active\" },\n { urn: \"tinycloud.kv/put\", service: \"tinycloud.kv\", status: \"active\" },\n { urn: \"tinycloud.kv/del\", service: \"tinycloud.kv\", status: \"active\" },\n { urn: \"tinycloud.kv/delete\", service: \"tinycloud.kv\", status: \"deprecated-alias\", aliasOf: \"tinycloud.kv/del\" },\n { urn: \"tinycloud.kv/sync\", service: \"tinycloud.kv\", status: \"active\" },\n { urn: \"tinycloud.kv/retain\", service: \"tinycloud.kv\", status: \"active\" },\n { urn: \"tinycloud.sql/read\", service: \"tinycloud.sql\", status: \"active\" },\n { urn: \"tinycloud.sql/select\", service: \"tinycloud.sql\", status: \"deprecated-alias\", aliasOf: \"tinycloud.sql/read\" },\n { urn: \"tinycloud.sql/write\", service: \"tinycloud.sql\", status: \"active\" },\n { urn: \"tinycloud.sql/schema\", service: \"tinycloud.sql\", status: \"active\" },\n { urn: \"tinycloud.sql/admin\", service: \"tinycloud.sql\", status: \"active\", implies: [\"tinycloud.sql/schema\"] },\n { urn: \"tinycloud.sql/*\", service: \"tinycloud.sql\", status: \"active\", implies: [\"tinycloud.sql/read\", \"tinycloud.sql/write\", \"tinycloud.sql/schema\", \"tinycloud.sql/admin\"] },\n { urn: \"tinycloud.duckdb/read\", service: \"tinycloud.duckdb\", status: \"active\" },\n { urn: \"tinycloud.duckdb/write\", service: \"tinycloud.duckdb\", status: \"active\" },\n { urn: \"tinycloud.duckdb/admin\", service: \"tinycloud.duckdb\", status: \"active\" },\n { urn: \"tinycloud.duckdb/import\", service: \"tinycloud.duckdb\", status: \"active\" },\n { urn: \"tinycloud.duckdb/export\", service: \"tinycloud.duckdb\", status: \"active\" },\n { urn: \"tinycloud.duckdb/select\", service: \"tinycloud.duckdb\", status: \"deprecated-alias\", aliasOf: \"tinycloud.duckdb/read\" },\n { urn: \"tinycloud.duckdb/*\", service: \"tinycloud.duckdb\", status: \"active\", implies: [\"tinycloud.duckdb/read\", \"tinycloud.duckdb/write\", \"tinycloud.duckdb/admin\", \"tinycloud.duckdb/import\", \"tinycloud.duckdb/export\"] },\n { urn: \"tinycloud.capabilities/read\", service: \"tinycloud.capabilities\", status: \"active\" },\n { urn: \"tinycloud.delegation/status\", service: \"tinycloud.delegation\", status: \"active\" },\n { urn: \"tinycloud.delegation/list\", service: \"tinycloud.delegation\", status: \"active\" },\n { urn: \"tinycloud.hooks/subscribe\", service: \"tinycloud.hooks\", status: \"active\" },\n { urn: \"tinycloud.hooks/register\", service: \"tinycloud.hooks\", status: \"active\" },\n { urn: \"tinycloud.hooks/list\", service: \"tinycloud.hooks\", status: \"active\" },\n { urn: \"tinycloud.hooks/unregister\", service: \"tinycloud.hooks\", status: \"active\" },\n { urn: \"tinycloud.encryption/decrypt\", service: \"tinycloud.encryption\", status: \"active\" },\n { urn: \"tinycloud.encryption/network.create\", service: \"tinycloud.encryption\", status: \"active\" },\n { urn: \"tinycloud.encryption/network.revoke\", service: \"tinycloud.encryption\", status: \"active\" },\n { urn: \"tinycloud.space/host\", service: \"tinycloud.space\", status: \"active\" },\n { urn: \"tinycloud.space/create\", service: \"tinycloud.space\", status: \"active\" },\n { urn: \"tinycloud.space/list\", service: \"tinycloud.space\", status: \"active\" },\n { urn: \"tinycloud.space/info\", service: \"tinycloud.space\", status: \"active\" },\n { urn: \"tinycloud.vfs/get\", service: \"tinycloud.vfs\", status: \"reserved\" },\n { urn: \"tinycloud.vfs/list\", service: \"tinycloud.vfs\", status: \"reserved\" },\n { urn: \"tinycloud.vfs/metadata\", service: \"tinycloud.vfs\", status: \"reserved\" },\n { urn: \"tinycloud.vfs/put\", service: \"tinycloud.vfs\", status: \"reserved\" },\n { urn: \"tinycloud.vfs/delete\", service: \"tinycloud.vfs\", status: \"reserved\" },\n] as const;\n\n/// Every action URN accepted at the policy boundary for a service\n/// (active, deprecated-alias, and reserved), sorted.\nexport const ACCEPTED_ACTIONS: Readonly<Record<string, readonly string[]>> = {\n \"tinycloud.capabilities\": [\"tinycloud.capabilities/read\"],\n \"tinycloud.delegation\": [\"tinycloud.delegation/list\", \"tinycloud.delegation/status\"],\n \"tinycloud.duckdb\": [\"tinycloud.duckdb/*\", \"tinycloud.duckdb/admin\", \"tinycloud.duckdb/export\", \"tinycloud.duckdb/import\", \"tinycloud.duckdb/read\", \"tinycloud.duckdb/select\", \"tinycloud.duckdb/write\"],\n \"tinycloud.encryption\": [\"tinycloud.encryption/decrypt\", \"tinycloud.encryption/network.create\", \"tinycloud.encryption/network.revoke\"],\n \"tinycloud.hooks\": [\"tinycloud.hooks/list\", \"tinycloud.hooks/register\", \"tinycloud.hooks/subscribe\", \"tinycloud.hooks/unregister\"],\n \"tinycloud.kv\": [\"tinycloud.kv/del\", \"tinycloud.kv/delete\", \"tinycloud.kv/get\", \"tinycloud.kv/list\", \"tinycloud.kv/metadata\", \"tinycloud.kv/put\", \"tinycloud.kv/retain\", \"tinycloud.kv/sync\"],\n \"tinycloud.space\": [\"tinycloud.space/create\", \"tinycloud.space/host\", \"tinycloud.space/info\", \"tinycloud.space/list\"],\n \"tinycloud.sql\": [\"tinycloud.sql/*\", \"tinycloud.sql/admin\", \"tinycloud.sql/read\", \"tinycloud.sql/schema\", \"tinycloud.sql/select\", \"tinycloud.sql/write\"],\n \"tinycloud.vfs\": [\"tinycloud.vfs/delete\", \"tinycloud.vfs/get\", \"tinycloud.vfs/list\", \"tinycloud.vfs/metadata\", \"tinycloud.vfs/put\"],\n};\n\n/// aliasUrn -> canonical URN.\nexport const ALIASES: Readonly<Record<string, string>> = {\n \"tinycloud.duckdb/select\": \"tinycloud.duckdb/read\",\n \"tinycloud.kv/delete\": \"tinycloud.kv/del\",\n \"tinycloud.sql/select\": \"tinycloud.sql/read\",\n};\n\n/// urn -> directly implied URNs.\nexport const IMPLICATIONS: Readonly<Record<string, readonly string[]>> = {\n \"tinycloud.duckdb/*\": [\"tinycloud.duckdb/admin\", \"tinycloud.duckdb/export\", \"tinycloud.duckdb/import\", \"tinycloud.duckdb/read\", \"tinycloud.duckdb/write\"],\n \"tinycloud.sql/*\": [\"tinycloud.sql/admin\", \"tinycloud.sql/read\", \"tinycloud.sql/schema\", \"tinycloud.sql/write\"],\n \"tinycloud.sql/admin\": [\"tinycloud.sql/schema\"],\n};\n\n/// Resolve a deprecated alias to its canonical URN (single hop).\nexport function resolveAlias(action: string): string {\n return ALIASES[action] ?? action;\n}\n\n/// URNs directly implied by holding `action`.\nexport function impliedActions(action: string): readonly string[] {\n return IMPLICATIONS[action] ?? [];\n}\n","/**\n * Canonical TinyCloud capability URN registry (js-sdk side).\n *\n * TC-112 single source of truth: the registry is defined in tinycloud-node\n * (`capabilities.json` + codegen) and vendored here VERBATIM as\n * `./generated/capabilities.ts` — the ONE copy in this repo. A CI job\n * (`.github/workflows/capabilities-sync.yml`) fetches the generated file from\n * tinycloud-node at the rev pinned in `packages/sdk-rs/Cargo.toml` and fails on\n * any diff against the vendored copy, so this module can never silently drift\n * from the enforcer.\n *\n * Everything below is DERIVED from the vendored registry by mechanical string\n * transform — there is no second hand-maintained action list. The bootstrap\n * manifests, the node-sdk default abilities, the SQL/DuckDB service action\n * tables, and the web-sdk permission-modal labels all consume the constants\n * declared here.\n *\n * The only hand-authored URNs are the four request-kind artifacts\n * (`sql/execute`, `sql/export`, `duckdb/describe`, `duckdb/execute`): the node\n * routes these by request-body kind gated by read/write/admin — they are NOT\n * grantable capabilities and are intentionally absent from the vendored\n * registry. The SDK keeps them as exported constants because the service\n * clients send them as the invocation ability today (wire alignment tracked in\n * TC-114). They are excluded from `CAPABILITY_REGISTRY`.\n */\n\nimport {\n CAPABILITIES as GENERATED_CAPABILITIES,\n type CapabilityEntry,\n type CapabilityStatus,\n} from \"./generated/capabilities.js\";\n\nexport type { CapabilityStatus };\n\n/**\n * A single registry entry. Alias of the vendored `CapabilityEntry` so the\n * public type name stays stable while the shape tracks the node registry\n * (long-form `service`, optional `aliasOf`/`implies`).\n */\nexport type CapabilityRegistryEntry = CapabilityEntry;\n\n// ---------------------------------------------------------------------------\n// Derivation\n//\n// Each registry URN is `tinycloud.<service>/<action>`. The per-service constant\n// objects below are built by stripping the `tinycloud.<service>/` prefix and\n// upper-casing the action into a key (`.` -> `_`, `*` -> `ALL`). This is a pure\n// string transform over the vendored registry — no action is named twice.\n// ---------------------------------------------------------------------------\n\nfunction actionKey(action: string): string {\n if (action === \"*\") return \"ALL\";\n return action.toUpperCase().replace(/[^A-Z0-9]/g, \"_\");\n}\n\nfunction serviceOf(urn: string): string {\n // \"tinycloud.sql/read\" -> \"sql\"\n return urn.slice(\"tinycloud.\".length, urn.indexOf(\"/\"));\n}\n\nfunction actionOf(urn: string): string {\n return urn.slice(urn.indexOf(\"/\") + 1);\n}\n\nfunction deriveServiceConstants(service: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const entry of GENERATED_CAPABILITIES) {\n if (serviceOf(entry.urn) !== service) continue;\n out[actionKey(actionOf(entry.urn))] = entry.urn;\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Per-service constants (long-form `tinycloud.<service>/<action>` URNs).\n// ---------------------------------------------------------------------------\n\nexport const KV = deriveServiceConstants(\"kv\") as {\n GET: \"tinycloud.kv/get\";\n LIST: \"tinycloud.kv/list\";\n METADATA: \"tinycloud.kv/metadata\";\n PUT: \"tinycloud.kv/put\";\n DEL: \"tinycloud.kv/del\";\n DELETE: \"tinycloud.kv/delete\";\n SYNC: \"tinycloud.kv/sync\";\n RETAIN: \"tinycloud.kv/retain\";\n};\n\n// `execute`/`export` are request-kind artifacts, not registry capabilities —\n// hand-authored (see module header, TC-114).\nexport const SQL = {\n ...deriveServiceConstants(\"sql\"),\n EXECUTE: \"tinycloud.sql/execute\",\n EXPORT: \"tinycloud.sql/export\",\n} as {\n READ: \"tinycloud.sql/read\";\n SELECT: \"tinycloud.sql/select\";\n WRITE: \"tinycloud.sql/write\";\n SCHEMA: \"tinycloud.sql/schema\";\n ADMIN: \"tinycloud.sql/admin\";\n ALL: \"tinycloud.sql/*\";\n EXECUTE: \"tinycloud.sql/execute\";\n EXPORT: \"tinycloud.sql/export\";\n};\n\n// `describe`/`execute` are request-kind artifacts, not registry capabilities —\n// hand-authored (see module header, TC-114).\nexport const DUCKDB = {\n ...deriveServiceConstants(\"duckdb\"),\n DESCRIBE: \"tinycloud.duckdb/describe\",\n EXECUTE: \"tinycloud.duckdb/execute\",\n} as {\n READ: \"tinycloud.duckdb/read\";\n WRITE: \"tinycloud.duckdb/write\";\n ADMIN: \"tinycloud.duckdb/admin\";\n IMPORT: \"tinycloud.duckdb/import\";\n EXPORT: \"tinycloud.duckdb/export\";\n SELECT: \"tinycloud.duckdb/select\";\n ALL: \"tinycloud.duckdb/*\";\n DESCRIBE: \"tinycloud.duckdb/describe\";\n EXECUTE: \"tinycloud.duckdb/execute\";\n};\n\nexport const CAPABILITIES = deriveServiceConstants(\"capabilities\") as {\n READ: \"tinycloud.capabilities/read\";\n};\n\nexport const HOOKS = deriveServiceConstants(\"hooks\") as {\n SUBSCRIBE: \"tinycloud.hooks/subscribe\";\n REGISTER: \"tinycloud.hooks/register\";\n LIST: \"tinycloud.hooks/list\";\n UNREGISTER: \"tinycloud.hooks/unregister\";\n};\n\nexport const ENCRYPTION = deriveServiceConstants(\"encryption\") as {\n DECRYPT: \"tinycloud.encryption/decrypt\";\n NETWORK_CREATE: \"tinycloud.encryption/network.create\";\n NETWORK_REVOKE: \"tinycloud.encryption/network.revoke\";\n};\n\nexport const SPACE = deriveServiceConstants(\"space\") as {\n HOST: \"tinycloud.space/host\";\n CREATE: \"tinycloud.space/create\";\n LIST: \"tinycloud.space/list\";\n INFO: \"tinycloud.space/info\";\n};\n\n/**\n * The full registry with per-URN status/alias/implication metadata. Re-exported\n * verbatim from the vendored node artifact — used by the canonical-set test and\n * the CI cross-check. The four request-kind artifacts are intentionally NOT\n * present here (see module header).\n */\nexport const CAPABILITY_REGISTRY: readonly CapabilityRegistryEntry[] =\n GENERATED_CAPABILITIES;\n","export const CLEAR_PENDING_WARNING =\n \"Clearing pending writes surrenders read-your-writes protection for the cleared keys. If a write whose record was cleared had an unknown outcome or never finished, it may commit now or later; this device can serve an older value until the next sync after that commit, as it would for a write from another device.\";\n","import type { ReplicationIdentity } from \"./types\";\n\nconst SPACE_ID = /^(tinycloud:pkh:eip155:\\d+:)([^:]+)(:.+)$/;\nconst PRINCIPAL_DID = /^(did:pkh:eip155:\\d+:)([^:]+)$/;\n\n/**\n * Pure canonicalization: lower-cases only EIP-155 address segments and preserves all other\n * space/principal bytes. Rejects non-HTTP(S) hosts, credentials, query/fragment, and non-full\n * TinyCloud space ids or non-pkh principals.\n */\nexport function canonicalReplicationIdentity(\n raw: ReplicationIdentity,\n): ReplicationIdentity {\n if (\n !raw ||\n typeof raw.host !== \"string\" ||\n typeof raw.space !== \"string\" ||\n typeof raw.principal !== \"string\"\n ) {\n throw new TypeError(\n \"Replication identity host, space, and principal must be strings\",\n );\n }\n const authority = /^https?:\\/\\/([^/?#]*)/i.exec(raw.host)?.[1];\n let url: URL;\n try {\n url = new URL(raw.host);\n } catch {\n throw new TypeError(\n \"Replication identity host must be an absolute HTTP(S) URL\",\n );\n }\n if (\n !authority ||\n authority.includes(\"@\") ||\n raw.host.includes(\"?\") ||\n raw.host.includes(\"#\") ||\n url.username ||\n url.password\n ) {\n throw new TypeError(\n \"Replication identity host must be HTTP(S) without credentials, query, or fragment\",\n );\n }\n const space = SPACE_ID.exec(raw.space);\n const principal = PRINCIPAL_DID.exec(raw.principal);\n if (!space || !principal) {\n throw new TypeError(\n \"Replication identity requires a full TinyCloud space id and a pkh principal DID\",\n );\n }\n return {\n host: `${url.origin}${url.pathname.replace(/\\/+$/, \"\")}`,\n space: `${space[1]}${space[2]!.toLowerCase()}${space[3]}`,\n principal: `${principal[1]}${principal[2]!.toLowerCase()}`,\n };\n}\n\n/** Stable in-memory key; durable adapters hash its UTF-8 bytes with their platform crypto. */\nexport function replicationIdentityKey(id: ReplicationIdentity): string {\n const canonical = canonicalReplicationIdentity(id);\n return `tc-replication/v1\\n${canonical.host}\\n${canonical.space}\\n${canonical.principal}`;\n}\n","/** Shared prefix boundary and configuration rules; no runtime dependencies. */\nexport function kvPrefixCovers(prefix: string, key: string): boolean {\n return prefix === \"/\" || key.startsWith(prefix);\n}\n\n/** Replication scopes are `/` or non-empty, slash-terminated folder paths. */\nexport function assertFolderPrefix(prefix: unknown): asserts prefix is string {\n const validFolder = typeof prefix === \"string\" &&\n prefix.length > 0 &&\n !prefix.startsWith(\"/\") &&\n !prefix.includes(\"//\") &&\n prefix.endsWith(\"/\");\n if (prefix !== \"/\" && !validFolder) {\n const folderHint = typeof prefix === \"string\"\n ? prefix.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")\n : \"\";\n const suggestion = folderHint.length > 0 && !folderHint.includes(\"//\")\n ? ` Use ${JSON.stringify(`${folderHint}/`)}.`\n : ' Use \"/\" or a slash-terminated folder path such as \"notes/\".';\n throw new TypeError(`Replication prefix must be \"/\" or a non-empty slash-terminated folder path without empty segments.${suggestion}`);\n }\n}\n","export { kvPrefixCovers } from \"./prefix\";\n\n/** LIST returns its exact path plus descendants below its slash-terminated path. */\nexport function listRangeCovers(path: string, key: string): boolean {\n return path === \"\" || key === path || key.startsWith(path.endsWith(\"/\") ? path : `${path}/`);\n}\n\n/** Whether replicating this space/prefix can copy encrypted secret material to disk. */\nexport function requiresSecretsOptIn(space: string, prefix: string): boolean {\n if (prefix === \"/\") return true;\n if (space === \"secrets\" || space.endsWith(\":secrets\")) return true;\n return prefix.split(\"/\", 1)[0] === \"vault\";\n}\n","/**\n * SDK Services - Error Utilities\n *\n * Utilities for creating and handling service errors.\n */\n\nimport { responseErrorMeta } from \"./responseErrors\";\nimport { CAPABILITY_REGISTRY } from \"@tinycloud/bootstrap\";\nimport { parseNetworkId } from \"./encryption/networkId\";\n\nimport {\n type ServiceError,\n ErrorCodes,\n err,\n serviceError,\n type PermissionHint,\n} from \"./types\";\n\n/** Validate one structured node permission hint without accepting raw errors. */\nexport function parsePermissionHint(value: unknown): PermissionHint | undefined {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const candidate = value as Record<string, unknown>;\n const keys = Object.keys(candidate).sort();\n if (keys.some((key) => ![\"actions\", \"path\", \"service\", \"space\"].includes(key))) return undefined;\n if (candidate.service !== \"tinycloud.kv\" && candidate.service !== \"tinycloud.encryption\") return undefined;\n if (typeof candidate.path !== \"string\" || candidate.path.length === 0 || candidate.path.includes(\"*\")) return undefined;\n if (candidate.service === \"tinycloud.kv\" &&\n (typeof candidate.space !== \"string\" || candidate.space.length === 0 || !candidate.path.startsWith(\"vault/\") || candidate.path.endsWith(\"/\"))) {\n return undefined;\n }\n if (candidate.service === \"tinycloud.encryption\" &&\n (candidate.space !== undefined || !candidate.path.startsWith(\"urn:tinycloud:encryption:\") || candidate.path.endsWith(\":\"))) {\n return undefined;\n }\n if (!Array.isArray(candidate.actions) || candidate.actions.length !== 1 ||\n typeof candidate.actions[0] !== \"string\" || candidate.actions[0].includes(\"*\")) return undefined;\n const expectedAction = candidate.service === \"tinycloud.kv\"\n ? \"tinycloud.kv/get\"\n : \"tinycloud.encryption/decrypt\";\n if (candidate.actions[0] !== expectedAction) return undefined;\n const space = typeof candidate.space === \"string\" ? candidate.space : undefined;\n return {\n service: candidate.service,\n ...(space === undefined ? {} : { space }),\n path: candidate.path,\n actions: [candidate.actions[0]],\n };\n}\n\n/** Extract only a validated structured hint from an SDK-owned error body. */\nexport function parsePermissionHintFromErrorText(text: string): PermissionHint | undefined {\n try {\n const parsed: unknown = JSON.parse(text);\n if (typeof parsed !== \"object\" || parsed === null) return undefined;\n const root = parsed as Record<string, unknown>;\n const nested = root.error;\n const nestedRecord = typeof nested === \"object\" && nested !== null\n ? nested as Record<string, unknown>\n : undefined;\n return parsePermissionHint(root.permissionHint) ??\n parsePermissionHint(nestedRecord?.permissionHint);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Create a service error for authentication required.\n */\nexport function authRequiredError(service: string): ServiceError {\n return {\n code: ErrorCodes.AUTH_REQUIRED,\n message: \"Authentication required. Please sign in first.\",\n service,\n };\n}\n\n/**\n * Create a service error for expired authentication.\n */\nexport function authExpiredError(service: string): ServiceError {\n return {\n code: ErrorCodes.AUTH_EXPIRED,\n message: \"Session has expired. Please sign in again.\",\n service,\n };\n}\n\n/**\n * Create a service error for network issues.\n */\nexport function networkError(\n service: string,\n message: string,\n cause?: Error\n): ServiceError {\n return {\n code: ErrorCodes.NETWORK_ERROR,\n message,\n service,\n cause,\n };\n}\n\n/**\n * Classify a node retry signal (tinycloud-node #347, TC-1054). The node's\n * bodies are plain text led by a stable token:\n * - `503 sql_busy: <stage>: ...` and `503 unavailable_retryable: ...` are\n * `NODE_BUSY`: nothing was applied; retry after `meta.retryAfterMs`.\n * - `503 request_timeout: ...` is `REQUEST_TIMEOUT`: the deadline passed before\n * any write began, so nothing was applied.\n * - `500 outcome_unknown: ...` is `OUTCOME_UNKNOWN`: a write may have been\n * applied; read back before retrying a non-idempotent operation.\n *\n * `meta.retryable` is the safe-to-retry verdict and `meta.retryAfterMs` the\n * node's `Retry-After` (the node sends whole seconds; anything else is\n * ignored). The SDK never retries on its own. Returns `undefined` for any\n * other response, including the bodyless 503/500 of nodes before 1.21, which\n * callers keep classifying as they always did.\n */\nexport function nodeRetryError(\n service: string,\n message: string,\n response: { status: number; statusText: string; headers: { get(name: string): string | null } },\n errorText: string\n): ServiceError | undefined {\n const body = errorText.trim();\n const [, token, stage] = /^([a-z_]+)(?::\\s*([a-z_]+):)?/.exec(body) ?? [];\n let code: string;\n if (response.status === 503 && (token === \"sql_busy\" || token === \"unavailable_retryable\")) {\n code = ErrorCodes.NODE_BUSY;\n } else if (response.status === 503 && token === \"request_timeout\") {\n code = ErrorCodes.REQUEST_TIMEOUT;\n } else if (response.status === 500 && token === \"outcome_unknown\") {\n code = ErrorCodes.OUTCOME_UNKNOWN;\n } else {\n return undefined;\n }\n const retryable = code !== ErrorCodes.OUTCOME_UNKNOWN;\n const retryAfter = response.headers.get(\"retry-after\")?.trim();\n return serviceError(code, message, service, {\n meta: {\n ...responseErrorMeta(response.status, response.statusText, errorText),\n retryable,\n ...(token === \"sql_busy\" && stage ? { stage } : {}),\n ...(retryable && retryAfter && /^\\d{1,9}$/.test(retryAfter) ? { retryAfterMs: Number(retryAfter) * 1000 } : {}),\n },\n });\n}\n\n/**\n * Abort reason for a service request that exceeded its configured timeout.\n *\n * Named `TimeoutError` (like the reason of the platform's\n * `AbortSignal.timeout()`), so it maps to `ErrorCodes.TIMEOUT` and never to\n * `ErrorCodes.ABORTED`, which is reserved for caller and sign-out aborts.\n */\nexport class RequestTimeoutError extends Error {\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms.`);\n this.name = \"TimeoutError\";\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Whether an error is a {@link RequestTimeoutError}. Also matches by shape so\n * that a copy of the class from another bundle (ESM/CJS entrypoint) is\n * recognized.\n */\nexport function isRequestTimeoutError(error: unknown): error is RequestTimeoutError {\n return (\n error instanceof RequestTimeoutError ||\n (error instanceof Error &&\n error.name === \"TimeoutError\" &&\n typeof (error as { timeoutMs?: unknown }).timeoutMs === \"number\")\n );\n}\n\n/**\n * Create a service error for timeouts.\n *\n * @param timeoutMs - The configured timeout that elapsed, when known\n * @param cause - The underlying timeout error, when known\n */\nexport function timeoutError(\n service: string,\n timeoutMs?: number,\n cause?: Error\n): ServiceError {\n if (timeoutMs === undefined) {\n return {\n code: ErrorCodes.TIMEOUT,\n message: \"Request timed out.\",\n service,\n ...(cause === undefined ? {} : { cause }),\n };\n }\n return {\n code: ErrorCodes.TIMEOUT,\n message: `Request timed out after ${timeoutMs}ms.`,\n service,\n ...(cause === undefined ? {} : { cause }),\n meta: { timeoutMs },\n };\n}\n\n/**\n * Create a service error for aborted requests.\n */\nexport function abortedError(service: string): ServiceError {\n return {\n code: ErrorCodes.ABORTED,\n message: \"Request was aborted.\",\n service,\n };\n}\n\n/**\n * Create a service error for not found resources.\n */\nexport function notFoundError(\n service: string,\n resource: string\n): ServiceError {\n return {\n code: ErrorCodes.NOT_FOUND,\n message: `Resource not found: ${resource}`,\n service,\n };\n}\n\n/**\n * Create a service error for permission denied.\n */\nexport function permissionDeniedError(\n service: string,\n action: string\n): ServiceError {\n return {\n code: ErrorCodes.PERMISSION_DENIED,\n message: `Permission denied for action: ${action}`,\n service,\n };\n}\n\n/**\n * Parse the server's \"Unauthorized Action: {resource} / {ability}\" pattern.\n */\nexport function parseAuthError(responseText: string): { resource?: string; action?: string } {\n const match = responseText.match(/^Unauthorized Action:\\s*(.+?)\\s*\\/\\s*(tinycloud\\.\\S+)$/m);\n if (match) {\n return { resource: match[1].trim(), action: match[2].trim() };\n }\n return {};\n}\n\n/**\n * Create a service error for unauthorized action (missing capability).\n */\nexport function authUnauthorizedError(\n service: string,\n message: string,\n meta?: Record<string, unknown>\n): ServiceError {\n return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });\n}\n\n/**\n * Authorization verdict read from an error's structure, never its message:\n * - `\"unauthenticated\"`: HTTP 401 — the session is missing or stale.\n * - `\"forbidden\"`: HTTP 403, or `AUTH_UNAUTHORIZED` without a status — the\n * session is valid but lacks the capability.\n * - `\"other\"`: a non-authorization HTTP error status (4xx/5xx).\n */\nexport type AuthorizationVerdict = \"unauthenticated\" | \"forbidden\" | \"other\";\n\nconst grantableActions = new Set(\n CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith(\"/*\"))\n);\n\nconst capabilityServices = new Set(\n CAPABILITY_REGISTRY.map(({ service }) => service.slice(\"tinycloud.\".length))\n);\n\n/**\n * Parse a canonical TinyCloud resource, keeping nested space names intact.\n * The first registered service segment is authoritative: a later matching\n * segment in the path cannot turn a different service into grant advice.\n */\nexport function parseCapabilityResource(\n resource: string,\n service: string\n): { space: string; path: string } | undefined {\n if (\n resource.length === 0 ||\n resource.length > 1024 ||\n !capabilityServices.has(service) ||\n /[\\s\\p{C}*#]/u.test(resource) ||\n resource.includes(\"://\")\n ) return undefined;\n\n const segments = resource.split(\"/\");\n if (!/^tinycloud:[A-Za-z0-9][A-Za-z0-9:._-]*$/.test(segments[0])) return undefined;\n const serviceIndex = segments.findIndex((segment, index) =>\n index > 0 && capabilityServices.has(segment)\n );\n if (serviceIndex < 1 || segments[serviceIndex] !== service) return undefined;\n if (segments.slice(1, serviceIndex).some((segment) =>\n segment.length === 0 || segment === \".\" || segment === \"..\"\n )) return undefined;\n const pathSegments = segments.slice(serviceIndex + 1);\n if (pathSegments.some((segment) => segment === \".\" || segment === \"..\")) return undefined;\n if (service !== \"kv\" && (pathSegments.length === 0 || pathSegments[pathSegments.length - 1] === \"\")) return undefined;\n\n return {\n space: segments.slice(0, serviceIndex).join(\"/\"),\n path: pathSegments.join(\"/\"),\n };\n}\n\n/** A capability resource is a canonical TinyCloud resource or encryption network, never a URL or expression. */\nfunction safeCapabilityResource(value: unknown, service: string, action: string): value is string {\n if (typeof value !== \"string\" || value.length === 0 || value.length > 1024) return false;\n if (service === \"encryption\" && value.startsWith(\"urn:tinycloud:encryption:\")) {\n if (\n !/^[A-Za-z0-9_][A-Za-z0-9_.:/-]*$/.test(value) ||\n value.includes(\"//\") ||\n value.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")\n ) return false;\n try {\n parseNetworkId(value);\n return true;\n } catch {\n return false;\n }\n }\n const parsed = parseCapabilityResource(value, service);\n return parsed !== undefined &&\n (!parsed.path.endsWith(\"/\") || (service === \"kv\" && action === \"tinycloud.kv/list\")) &&\n (parsed.path !== \"\" || (service === \"kv\" && action === \"tinycloud.kv/list\"));\n}\n\n/**\n * Return a grantable missing capability only when typed authorization evidence\n * and both safe, service-matched capability fields are present. Status alone,\n * message text, wildcard actions and unrecognized actions cannot grant scope.\n */\nexport function validatedCapabilityOf(\n error: unknown\n): { resource: string; requiredAction: string } | undefined {\n const verdict = authorizationVerdictOf(error);\n if (verdict !== \"unauthenticated\" && verdict !== \"forbidden\") return undefined;\n\n const seen = new Set<unknown>();\n let node: unknown = error;\n for (\n let depth = 0;\n depth < MAX_CAUSE_DEPTH && typeof node === \"object\" && node !== null && !seen.has(node);\n depth += 1\n ) {\n seen.add(node);\n const record = node as Record<string, unknown>;\n const status = errorStatusOf(record);\n const meta = record.meta;\n if (\n (status === 401 || status === 403 || (status === undefined && record.code === ErrorCodes.AUTH_UNAUTHORIZED)) &&\n typeof meta === \"object\" && meta !== null && !Array.isArray(meta)\n ) {\n const metadata = meta as Record<string, unknown>;\n const { resource, requiredAction } = metadata;\n if (typeof requiredAction === \"string\" && grantableActions.has(requiredAction)) {\n const actionService = requiredAction.slice(\"tinycloud.\".length, requiredAction.indexOf(\"/\"));\n const explicitService = record.service === undefined ? metadata.service : record.service;\n if (\n safeCapabilityResource(resource, actionService, requiredAction) &&\n (explicitService === undefined ||\n explicitService === actionService ||\n explicitService === `tinycloud.${actionService}`)\n ) {\n return { resource, requiredAction };\n }\n }\n }\n node = record.cause;\n }\n return undefined;\n}\n\nconst MAX_CAUSE_DEPTH = 8;\n\n/** The first 4xx/5xx among `status`, `statusCode`, `meta.status`. Success and\n * informational statuses (e.g. a 200 `Response` kept as `cause`) are not\n * failures, so they are skipped rather than ending the search. */\nfunction errorStatusOf(node: Record<string, unknown>): number | undefined {\n const meta = node.meta;\n const candidates = [\n node.status,\n node.statusCode,\n typeof meta === \"object\" && meta !== null\n ? (meta as Record<string, unknown>).status\n : undefined,\n ];\n for (const candidate of candidates) {\n if (\n typeof candidate === \"number\" &&\n Number.isInteger(candidate) &&\n candidate >= 400 &&\n candidate <= 599\n ) {\n return candidate;\n }\n }\n return undefined;\n}\n\n/**\n * Classify an error from its typed HTTP error status (`status`, `statusCode`,\n * or `meta.status`, 4xx/5xx only) and `AUTH_UNAUTHORIZED` code, following the\n * `cause` chain outer-first (at most {@link MAX_CAUSE_DEPTH} links, cycles\n * stop the walk) so wrappers that rethrow with `cause` keep the verdict. The\n * outermost error status decides, so an outer 5xx keeps its retry budget even\n * over an inner 401. Returns `undefined` for untyped errors; only then may\n * callers fall back to message heuristics.\n */\nexport function authorizationVerdictOf(\n error: unknown,\n): AuthorizationVerdict | undefined {\n const seen = new Set<unknown>();\n let sawUnauthorizedCode = false;\n let node: unknown = error;\n for (\n let depth = 0;\n depth < MAX_CAUSE_DEPTH && typeof node === \"object\" && node !== null && !seen.has(node);\n depth += 1\n ) {\n seen.add(node);\n const record = node as Record<string, unknown>;\n const status = errorStatusOf(record);\n if (status === 401) return \"unauthenticated\";\n if (status === 403) return \"forbidden\";\n if (status !== undefined) return \"other\";\n if (record.code === ErrorCodes.AUTH_UNAUTHORIZED) sawUnauthorizedCode = true;\n node = record.cause;\n }\n return sawUnauthorizedCode ? \"forbidden\" : undefined;\n}\n\n/**\n * Create a service error for storage quota exceeded (402 Payment Required).\n */\nexport function storageQuotaExceededError(\n service: string,\n message: string,\n meta?: Record<string, unknown>\n): ServiceError {\n return {\n code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,\n message,\n service,\n meta,\n };\n}\n\n/**\n * Create a service error for storage limit reached (413 Payload Too Large).\n */\nexport function storageLimitReachedError(\n service: string,\n message: string,\n meta?: Record<string, unknown>\n): ServiceError {\n return {\n code: ErrorCodes.STORAGE_LIMIT_REACHED,\n message,\n service,\n meta,\n };\n}\n\n/** Shown when a write is rejected because the owner's storage is full. */\nexport const STORAGE_FULL_MESSAGE =\n \"TinyCloud storage is full, so this change was not saved. Reading still works. Free up space or upgrade your plan to save again.\";\n\n/** Shown when a write is larger than the storage the owner has left. */\nexport const STORAGE_WRITE_TOO_LARGE_MESSAGE =\n \"This change is larger than the TinyCloud storage you have left, so it was not saved. Reading still works. Free up space or upgrade your plan to save it.\";\n\n/**\n * Parse the byte counts from a node storage rejection\n * (\"... Used: 155744 bytes, Limit: 0 bytes\"). The limit is the share of the\n * owner's account-wide budget left for this space, so it is 0 when the\n * owner's other spaces already use the whole budget.\n */\nexport function parseStorageQuotaBytes(\n responseText: string\n): { usedBytes: number; limitBytes: number } | undefined {\n const match = responseText.match(/Used:\\s*(\\d+)\\s*bytes,\\s*Limit:\\s*(\\d+)\\s*bytes/i);\n if (!match) return undefined;\n return {\n usedBytes: parseInt(match[1], 10),\n limitBytes: parseInt(match[2], 10),\n };\n}\n\n/**\n * Account-wide storage totals the node attaches to a storage rejection when\n * billing supplied them. `limitBytes` is the plan budget shared by all the\n * owner's spaces, so this is the number to show the user, not the space's.\n */\nexport interface StorageAccountUsage {\n usedBytes: number;\n limitBytes: number;\n /** Plan tier id, e.g. `free` or `paid`. */\n plan?: string;\n}\n\n/** What a node storage rejection says about the space and the account. */\nexport interface StorageRejectionDetails {\n usedBytes?: number;\n limitBytes?: number;\n account?: StorageAccountUsage;\n}\n\nconst STORAGE_REJECTION_BODY_ERRORS: Record<string, true> = {\n storage_quota_exceeded: true,\n storage_limit_reached: true,\n};\n\nfunction isByteCount(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction byteCountsOf(value: unknown): { usedBytes: number; limitBytes: number } | undefined {\n if (typeof value !== \"object\" || value === null) return undefined;\n const { usedBytes, limitBytes } = value as Record<string, unknown>;\n return isByteCount(usedBytes) && isByteCount(limitBytes) ? { usedBytes, limitBytes } : undefined;\n}\n\n/**\n * Parse a node storage rejection. The node sends a JSON body\n * (`{error, message, space: {usedBytes, limitBytes}, account?: {usedBytes,\n * limitBytes, plan}}`); older nodes send only the plain-text message. Returns\n * undefined when the body is neither, e.g. a proxy's own 413 page.\n */\nexport function parseStorageRejection(responseText: string): StorageRejectionDetails | undefined {\n let body: unknown;\n try {\n body = JSON.parse(responseText);\n } catch {\n return parseStorageQuotaBytes(responseText);\n }\n if (typeof body !== \"object\" || body === null) return undefined;\n const record = body as Record<string, unknown>;\n const message = typeof record.message === \"string\" ? record.message : \"\";\n const space = byteCountsOf(record.space) ?? parseStorageQuotaBytes(message);\n const isStorageBody = typeof record.error === \"string\" && STORAGE_REJECTION_BODY_ERRORS[record.error] === true;\n if (!space && !isStorageBody) {\n return undefined;\n }\n const details: StorageRejectionDetails = { ...space };\n const account = byteCountsOf(record.account);\n if (account) {\n const plan = (record.account as Record<string, unknown>).plan;\n details.account = typeof plan === \"string\" && plan !== \"\" ? { ...account, plan } : account;\n }\n return details;\n}\n\n/**\n * Build the error for a write the node rejected for storage: 402 when storage\n * is already full, 413 when this write is larger than what is left. KV, SQL\n * and DuckDB all report it with the same codes and message so an app can\n * detect \"storage full\" in one place with {@link isStorageFullError}.\n * `meta.usedBytes`/`meta.limitBytes` describe the space; `meta.account`\n * carries the account totals when the node sent them.\n */\nexport function storageRejectionError(\n service: string,\n status: 402 | 413,\n meta: Record<string, unknown>,\n responseText: string\n): ServiceError {\n const quotaMeta = { ...meta, ...parseStorageRejection(responseText) };\n return status === 402\n ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta)\n : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);\n}\n\n/**\n * True when a write failed for storage: the owner's TinyCloud storage is full\n * (`STORAGE_QUOTA_EXCEEDED`), or this write is larger than what is left\n * (`STORAGE_LIMIT_REACHED`). Reads keep working in both cases, so apps should\n * stay usable read-only and point the user at freeing up space or upgrading.\n */\nexport function isStorageFullError(error: { code?: string } | null | undefined): boolean {\n return (\n error?.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED ||\n error?.code === ErrorCodes.STORAGE_LIMIT_REACHED\n );\n}\n\n/**\n * Wrap an unknown error in a ServiceError.\n */\nexport function wrapError(\n service: string,\n error: unknown,\n defaultCode: string = ErrorCodes.NETWORK_ERROR\n): ServiceError {\n if (error instanceof Error) {\n // A configured request timeout elapsed (see BaseService.createRequestSignal)\n if (isRequestTimeoutError(error)) {\n return timeoutError(service, error.timeoutMs, error);\n }\n\n // Check for abort errors\n if (error.name === \"AbortError\") {\n return abortedError(service);\n }\n\n // Check for timeout errors (varies by platform)\n if (\n error.name === \"TimeoutError\" ||\n error.message.toLowerCase().includes(\"timeout\")\n ) {\n return timeoutError(service);\n }\n\n return {\n code: defaultCode,\n message: error.message,\n service,\n cause: error,\n };\n }\n\n return {\n code: defaultCode,\n message: String(error),\n service,\n };\n}\n\n/**\n * Create an error Result from a ServiceError.\n */\nexport function errorResult(error: ServiceError) {\n return err(error);\n}\n","/**\n * SDK Services - Core Types\n *\n * These types define the service architecture for TinyCloud SDK.\n * Services use dependency injection via IServiceContext for platform independence.\n */\n\n// =============================================================================\n// Result Type Pattern\n// =============================================================================\n\n/**\n * Result type for service operations.\n * Services return Result instead of throwing, making error handling explicit.\n *\n * @template T - The success data type\n * @template E - The error type (defaults to ServiceError)\n *\n * @example\n * ```typescript\n * const result = await kv.get('key');\n * if (result.ok) {\n * console.log(result.data);\n * } else {\n * console.error(result.error.code);\n * }\n * ```\n */\nexport type Result<T, E = ServiceError> =\n | { ok: true; data: T }\n | { ok: false; error: E };\n\n/**\n * Service error with structured information.\n */\nexport interface ServiceError {\n /** Error code for programmatic handling (e.g., 'KV_NOT_FOUND', 'AUTH_EXPIRED') */\n code: string;\n /** Human-readable error message */\n message: string;\n /** Service that produced the error (e.g., 'kv', 'sql') */\n service: string;\n /** Original error if this wraps another error */\n cause?: Error;\n /** Additional metadata about the error */\n meta?: Record<string, unknown>;\n}\n\n/**\n * A node-supplied permission hint after strict SDK validation. This is\n * deliberately narrower than a general capability: no wildcards, caveats,\n * descriptions, or transport metadata can cross the service boundary.\n */\nexport interface PermissionHint {\n readonly service: \"tinycloud.kv\" | \"tinycloud.encryption\";\n readonly space?: string;\n readonly path: string;\n readonly actions: readonly string[];\n}\n\n/**\n * Storage quota information returned with quota-related errors.\n * @deprecated Read `usedBytes`, `limitBytes` and `account` from the error's\n * `meta`, or use `StorageFullEvent` from `tc.on(\"storage.full\", handler)`.\n */\nexport interface StorageQuotaInfo {\n usedBytes: number;\n limitBytes: number;\n service: string;\n}\n\n/**\n * Standard error codes used across services.\n */\nexport const ErrorCodes = {\n // Common errors\n NOT_FOUND: \"NOT_FOUND\",\n AUTH_EXPIRED: \"AUTH_EXPIRED\",\n AUTH_REQUIRED: \"AUTH_REQUIRED\",\n AUTH_UNAUTHORIZED: \"AUTH_UNAUTHORIZED\",\n /** HTTP 401: the delegation the invocation cites was revoked. */\n AUTH_DELEGATION_REVOKED: \"AUTH_DELEGATION_REVOKED\",\n /** HTTP 401: a delegation the cited one rests on was revoked. */\n AUTH_DELEGATION_ANCESTOR_REVOKED: \"AUTH_DELEGATION_ANCESTOR_REVOKED\",\n NETWORK_ERROR: \"NETWORK_ERROR\",\n TIMEOUT: \"TIMEOUT\",\n ABORTED: \"ABORTED\",\n INVALID_INPUT: \"INVALID_INPUT\",\n PERMISSION_DENIED: \"PERMISSION_DENIED\",\n\n // Node retry signals (tinycloud-node #347). `meta.retryable` says whether a\n // retry is safe; `meta.retryAfterMs` carries the node's Retry-After.\n /** HTTP 503 `sql_busy:<stage>` / `unavailable_retryable`: nothing was applied; retry after `meta.retryAfterMs`. */\n NODE_BUSY: \"NODE_BUSY\",\n /** HTTP 503 `request_timeout`: the node's deadline passed before any write began; nothing was applied. */\n REQUEST_TIMEOUT: \"REQUEST_TIMEOUT\",\n /** HTTP 500 `outcome_unknown`: a write may have been applied; read back before retrying a non-idempotent operation. */\n OUTCOME_UNKNOWN: \"OUTCOME_UNKNOWN\",\n\n // KV-specific errors\n KV_NOT_FOUND: \"KV_NOT_FOUND\",\n KV_WRITE_FAILED: \"KV_WRITE_FAILED\",\n KV_PRECONDITION_FAILED: \"KV_PRECONDITION_FAILED\",\n KV_CONFLICT: \"KV_CONFLICT\",\n KV_RESPONSE_TOO_LARGE: \"KV_RESPONSE_TOO_LARGE\",\n /** HTTP 410 from the change feed: discard sync state and restart without a cursor; `meta.reason` says why. */\n KV_SYNC_RESET_REQUIRED: \"KV_SYNC_RESET_REQUIRED\",\n /** HTTP 403 from the change feed: the retention grant was refused; `meta.reason` says why. */\n KV_RETENTION_GRANT_REFUSED: \"KV_RETENTION_GRANT_REFUSED\",\n\n // SQL-specific errors\n SQL_ERROR: \"SQL_ERROR\",\n SQL_PERMISSION_DENIED: \"SQL_PERMISSION_DENIED\",\n SQL_DATABASE_NOT_FOUND: \"SQL_DATABASE_NOT_FOUND\",\n SQL_RESPONSE_TOO_LARGE: \"SQL_RESPONSE_TOO_LARGE\",\n SQL_QUOTA_EXCEEDED: \"SQL_QUOTA_EXCEEDED\",\n SQL_INVALID_STATEMENT: \"SQL_INVALID_STATEMENT\",\n SQL_SCHEMA_ERROR: \"SQL_SCHEMA_ERROR\",\n SQL_READONLY_VIOLATION: \"SQL_READONLY_VIOLATION\",\n\n // Storage quota errors\n STORAGE_QUOTA_EXCEEDED: \"STORAGE_QUOTA_EXCEEDED\",\n STORAGE_LIMIT_REACHED: \"STORAGE_LIMIT_REACHED\",\n /** The node answered the usage read without usage numbers (it predates the read). */\n STORAGE_STATUS_UNAVAILABLE: \"STORAGE_STATUS_UNAVAILABLE\",\n\n // DuckDB-specific errors\n DUCKDB_ERROR: \"DUCKDB_ERROR\",\n DUCKDB_PERMISSION_DENIED: \"DUCKDB_PERMISSION_DENIED\",\n DUCKDB_DATABASE_NOT_FOUND: \"DUCKDB_DATABASE_NOT_FOUND\",\n DUCKDB_RESPONSE_TOO_LARGE: \"DUCKDB_RESPONSE_TOO_LARGE\",\n DUCKDB_QUOTA_EXCEEDED: \"DUCKDB_QUOTA_EXCEEDED\",\n DUCKDB_INVALID_STATEMENT: \"DUCKDB_INVALID_STATEMENT\",\n DUCKDB_SCHEMA_ERROR: \"DUCKDB_SCHEMA_ERROR\",\n DUCKDB_READONLY_VIOLATION: \"DUCKDB_READONLY_VIOLATION\",\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\n// =============================================================================\n// Service Session\n// =============================================================================\n\n/**\n * Session data required for authenticated service operations.\n * Both TinyCloudSession and web-sdk Session can be cast to this interface.\n */\nexport interface ServiceSession {\n /** The delegation header containing the UCAN */\n delegationHeader: { Authorization: string };\n /** The delegation CID */\n delegationCid: string;\n /** The space ID for this session */\n spaceId: string;\n /** The verification method DID */\n verificationMethod: string;\n /** The session key JWK (required for invoke) */\n jwk: object;\n}\n\n// =============================================================================\n// Platform Dependencies (Injected)\n// =============================================================================\n\n/**\n * Headers type - compatible with both browser and Node.js.\n */\nexport type ServiceHeaders = Record<string, string> | [string, string][];\n\n/**\n * A single fact object to include in the UCAN invocation.\n * Facts are key-value objects that the server reads from the UCAN facts field.\n */\nexport interface InvocationFact {\n [key: string]: unknown;\n}\n\n/**\n * Facts to include in the UCAN invocation.\n * This is an array of fact objects per the UCAN spec.\n * Used to pass additional parameters that the server reads from the UCAN facts field.\n */\nexport type InvocationFacts = InvocationFact[];\n\n/**\n * Invoke function signature - platform-specific implementation injected via DI.\n * Both node-sdk-wasm and web-sdk-wasm export this with identical signature.\n *\n * @param session - The service session with delegation data\n * @param service - Service name (e.g., \"kv\")\n * @param path - Resource path or key\n * @param action - Action to perform (e.g., \"tinycloud.kv/get\")\n * @param facts - Optional facts to include in the UCAN (e.g., for capabilities/read params)\n * @returns Headers to include in the request\n */\nexport type InvokeFunction = (\n session: ServiceSession,\n service: string,\n path: string,\n action: string,\n facts?: InvocationFacts,\n) => ServiceHeaders;\n\n/**\n * Multi-resource invocation entry.\n */\nexport interface InvokeAnyEntry {\n /**\n * Legacy space-scoped resource. Optional when `resource` is provided.\n */\n spaceId?: string;\n service: string;\n path: string;\n action: string;\n /** Optional raw resource URI. When set, WASM signs this URI directly. */\n resource?: string;\n /** Capability caveats that must remain on this invocation attenuation. */\n caveats?: Record<string, unknown>[];\n}\n\n/**\n * Invoke function for minting a single authorization header that covers\n * multiple capabilities across one effective invoker.\n */\nexport type InvokeAnyFunction = (\n session: ServiceSession,\n entries: InvokeAnyEntry[],\n facts?: InvocationFacts,\n) => ServiceHeaders;\n\n/**\n * Fetch request options - compatible with standard fetch API.\n */\nexport interface FetchRequestInit {\n method?: string;\n headers?: ServiceHeaders;\n body?: Blob | FormData | string;\n signal?: AbortSignal;\n redirect?: \"error\";\n}\n\n/**\n * Fetch response interface - compatible with standard Response.\n */\nexport interface FetchResponse {\n ok: boolean;\n status: number;\n statusText: string;\n body?: unknown;\n headers: {\n get(name: string): string | null;\n };\n json(): Promise<unknown>;\n text(): Promise<string>;\n arrayBuffer(): Promise<ArrayBuffer>;\n blob(): Promise<Blob>;\n}\n\n/**\n * Fetch function signature - allows for custom fetch implementations.\n * Compatible with both browser fetch and Node.js fetch.\n */\nexport type FetchFunction = (\n url: string,\n init?: FetchRequestInit,\n) => Promise<FetchResponse>;\n\n// =============================================================================\n// Retry Policy\n// =============================================================================\n\n/**\n * Configuration for automatic retry of failed requests.\n */\nexport interface RetryPolicy {\n /** Maximum number of attempts (including initial) */\n maxAttempts: number;\n /** Backoff strategy between retries */\n backoff: \"none\" | \"linear\" | \"exponential\";\n /** Base delay in milliseconds for backoff calculation */\n baseDelayMs: number;\n /** Maximum delay in milliseconds between retries */\n maxDelayMs: number;\n /** Error codes that should trigger a retry */\n retryableErrors: string[];\n}\n\n/**\n * Default retry policy.\n */\nexport const defaultRetryPolicy: RetryPolicy = {\n maxAttempts: 3,\n backoff: \"exponential\",\n baseDelayMs: 1000,\n maxDelayMs: 10000,\n retryableErrors: [ErrorCodes.NETWORK_ERROR, ErrorCodes.TIMEOUT],\n};\n\n// =============================================================================\n// Service Context\n// =============================================================================\n\n/**\n * Event handler function type.\n */\nexport type EventHandler = (data: unknown) => void;\n\n/**\n * SDK telemetry event handler.\n */\nexport type TelemetryEventHandler = (event: string, data: unknown) => void;\n\n/**\n * Default-off telemetry configuration.\n */\nexport type TelemetryConfig =\n | boolean\n | {\n enabled?: boolean;\n onEvent?: TelemetryEventHandler;\n };\n\n/**\n * Service interface - base contract for all services.\n */\nexport interface IService {\n /** Initialize service with context */\n initialize(context: IServiceContext): void;\n\n /** Called when session changes (sign-in, sign-out, refresh) */\n onSessionChange(session: ServiceSession | null): void;\n\n /** Called when SDK signs out - should abort pending operations */\n onSignOut(): void;\n\n /** Service-specific configuration */\n readonly config: Record<string, unknown>;\n}\n\n/**\n * Context provided to services for accessing platform dependencies.\n * The SDK creates this context and passes it to services during initialization.\n */\nexport interface IServiceContext {\n // Session management\n /** Current active session, or null if not authenticated */\n readonly session: ServiceSession | null;\n /** Whether there is an active authenticated session */\n readonly isAuthenticated: boolean;\n\n // Platform dependencies (injected by SDK)\n /** Platform-specific invoke function from WASM binding */\n readonly invoke: InvokeFunction;\n /** Optional multi-resource invoke function */\n readonly invokeAny?: InvokeAnyFunction;\n /** Fetch function (defaults to globalThis.fetch) */\n readonly fetch: FetchFunction;\n /** Available TinyCloud host URLs */\n readonly hosts: string[];\n\n // Cross-service access\n /** Get another registered service by name */\n getService<T extends IService>(name: string): T | undefined;\n\n // Telemetry/Events\n /** Emit a telemetry event */\n emit(event: string, data: unknown): void;\n /** Subscribe to events */\n on(event: string, handler: EventHandler): () => void;\n\n // Lifecycle\n /** Abort signal that fires when SDK signs out. */\n readonly abortSignal: AbortSignal;\n /** Additional abort signal for a scoped operation, when active. */\n readonly operationAbortSignal?: AbortSignal;\n /** Install an additional signal for the duration of a scoped operation. */\n setOperationAbortSignal?(signal: AbortSignal | undefined): void;\n // Retry policy\n /** Retry policy for failed requests */\n readonly retryPolicy: RetryPolicy;\n}\n\n// =============================================================================\n// Telemetry Events\n// =============================================================================\n\n/**\n * Event emitted before a service request.\n */\nexport interface ServiceRequestEvent {\n service: string;\n action: string;\n span?: string;\n key?: string;\n timestamp: number;\n}\n\n/**\n * Event emitted after a service response.\n */\nexport interface ServiceResponseEvent {\n service: string;\n action: string;\n span?: string;\n ok: boolean;\n duration: number;\n durationMs?: number;\n status?: number;\n}\n\n/**\n * Event emitted on service error.\n */\nexport interface ServiceErrorEvent {\n service: string;\n span?: string;\n error: ServiceError;\n}\n\n/**\n * Event emitted on retry attempt.\n */\nexport interface ServiceRetryEvent {\n service: string;\n attempt: number;\n maxAttempts: number;\n error: ServiceError;\n}\n\n/**\n * Generic named span event for aggregating operation timings.\n */\nexport interface TelemetrySpanEvent {\n span: string;\n ok: boolean;\n durationMs: number;\n service?: string;\n action?: string;\n status?: number;\n error?: ServiceError;\n}\n\n/**\n * Telemetry event names.\n */\nexport const TelemetryEvents = {\n SPAN: \"telemetry.span\",\n SERVICE_REQUEST: \"service.request\",\n SERVICE_RESPONSE: \"service.response\",\n SERVICE_ERROR: \"service.error\",\n SERVICE_RETRY: \"service.retry\",\n SESSION_CHANGED: \"session.changed\",\n SESSION_EXPIRED: \"session.expired\",\n REPLICATION_READ: \"replication.read\",\n REPLICATION_WRITE: \"replication.write\",\n REPLICATION_SYNC: \"replication.sync\",\n REPLICATION_STATE: \"replication.state\",\n REPLICATION_DIVERGENCE: \"replication.divergence\",\n REPLICATION_GRANT: \"replication.grant\",\n REPLICATION_LIFECYCLE: \"replication.lifecycle\",\n /** Emitted once, on the first write rejected because storage is full. */\n STORAGE_FULL: \"storage.full\",\n} as const;\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Create a success result.\n */\nexport function ok<T>(data: T): Result<T> {\n return { ok: true, data };\n}\n\n/**\n * Create an error result.\n */\nexport function err<E = ServiceError>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Create a ServiceError.\n */\nexport function serviceError(\n code: string,\n message: string,\n service: string,\n options?: { cause?: Error; meta?: Record<string, unknown> },\n): ServiceError {\n return {\n code,\n message,\n service,\n cause: options?.cause,\n meta: options?.meta,\n };\n}\n","import { ErrorCodes, type Result } from \"../../types\";\n\nconst DEFINITIVE_FAILURES = new Set<string>([\n ErrorCodes.AUTH_REQUIRED, ErrorCodes.INVALID_INPUT, ErrorCodes.AUTH_UNAUTHORIZED,\n ErrorCodes.KV_PRECONDITION_FAILED, ErrorCodes.STORAGE_QUOTA_EXCEEDED, ErrorCodes.STORAGE_LIMIT_REACHED,\n]);\n\nexport function classifyWriteOutcome<T>(\n op: \"put\" | \"delete\" | \"batchPut\",\n result: Result<T>,\n options: { conditional?: boolean } = {},\n): \"committed\" | \"failed\" | \"ambiguous\" {\n if (result.ok) return \"committed\";\n const { code, meta } = result.error;\n if (op === \"delete\" && code === ErrorCodes.KV_NOT_FOUND) {\n return options.conditional === true ? \"failed\" : \"committed\";\n }\n if (meta?.requestMayHaveDispatched === false) return \"failed\";\n if (DEFINITIVE_FAILURES.has(code)) return \"failed\";\n if (meta?.outcome === \"batch-unconfirmed\") return \"ambiguous\";\n const status = typeof meta?.status === \"number\" ? meta.status : undefined;\n if (status !== undefined && status >= 400 && status < 500) return \"failed\";\n return \"ambiguous\";\n}\n","import { kvPrefixCovers } from \"./scope\";\nimport type { PendingWriteRecord, PendingWriteState } from \"./types\";\n\nexport function emptyPendingState(identity: PendingWriteState[\"identity\"]): PendingWriteState {\n return { v: 2, identity: { ...identity }, committedEpoch: 0, seq: 0, records: [] };\n}\n\nexport function begin(s: PendingWriteState, opId: string, keys: readonly { key: string; op: \"put\" | \"delete\" }[], at: string): PendingWriteRecord[] {\n const records = keys.map(({ key, op }) => ({ opId, seq: ++s.seq, key, op, state: \"in_flight\" as const, epoch: null, at, settledAt: null }));\n s.records.push(...records);\n return records;\n}\n\nexport function settle(s: PendingWriteState, opId: string, outcome: \"committed\" | \"failed\" | \"ambiguous\", at: string, code?: string): void {\n if (outcome === \"failed\") { s.records = s.records.filter((r) => r.opId !== opId); return; }\n const own = s.records.filter((r) => r.opId === opId && r.state === \"in_flight\");\n if (outcome === \"committed\" && own.length > 0) {\n const epoch = ++s.committedEpoch;\n for (const r of own) { r.state = \"committed\"; r.epoch = epoch; r.settledAt = at; }\n return;\n }\n for (const r of own) { r.state = \"ambiguous\"; r.settledAt = at; if (code) r.code = code; }\n}\n\nexport function afterSync(s: PendingWriteState, prefix: string, syncStartEpoch: number): number {\n const before = s.records.length;\n s.records = s.records.filter((r) => !(r.state === \"committed\" && r.epoch !== null && r.epoch <= syncStartEpoch && kvPrefixCovers(prefix, r.key)));\n return before - s.records.length;\n}\n\nexport function clearPrefix(s: PendingWriteState, prefix: string): number {\n const before = s.records.length;\n s.records = s.records.filter((r) => !kvPrefixCovers(prefix, r.key));\n return before - s.records.length;\n}\n\nexport function clearPending(s: PendingWriteState, now: number): number {\n const before = s.records.length;\n s.records = s.records.filter((r) => r.state === \"committed\" || (r.state === \"in_flight\" && now - Date.parse(r.at) <= 10 * 60_000));\n return before - s.records.length;\n}\n\nexport function pinnedKeys(s: PendingWriteState, prefix: string, now: number, cap = 100) {\n return s.records.filter((r) => kvPrefixCovers(prefix, r.key) && (r.state === \"in_flight\" || r.state === \"ambiguous\"))\n .sort((a, b) => a.seq - b.seq).slice(0, cap).map((r) => ({ key: r.key, state: r.state as \"in_flight\" | \"ambiguous\", op: r.op, since: r.at, ...(r.code ? { code: r.code } : {}), likelyOrphaned: r.state === \"in_flight\" && now - Date.parse(r.at) > 10 * 60_000 }));\n}\n","import { err, ErrorCodes, ok, serviceError } from \"../../types\";\nimport type { KVResponse } from \"../types\";\nimport type { LocalGetResult } from \"./types\";\n\nexport type LocalGetResponse<T> = { ok: true; data: KVResponse<T> } | { ok: false; error: { code: string; message: string; service: string; meta?: Record<string, unknown> } };\n\nexport function parseLocalValue<T>(bytes: Uint8Array, contentType: string | undefined, raw: boolean | undefined, binary: boolean | undefined): T {\n if (binary) return bytes as T;\n const text = new TextDecoder().decode(bytes);\n if (raw) return text as T;\n if (contentType?.includes(\"application/json\")) return JSON.parse(text) as T;\n if (contentType?.startsWith(\"text/\")) return text as T;\n if (!text) return undefined as T;\n try { return JSON.parse(text) as T; } catch { return text as T; }\n}\n\nexport function localGet<T>(result: LocalGetResult, key: string, options: { raw?: boolean; binary?: boolean; maxResponseBytes?: number }): LocalGetResponse<T> {\n if (result.status === \"present\") {\n if (options.maxResponseBytes !== undefined && result.value.byteLength > options.maxResponseBytes) {\n return err(serviceError(ErrorCodes.KV_RESPONSE_TOO_LARGE, `KV value at key ${JSON.stringify(key)} exceeds the requested response limit`, \"kv\", { meta: { status: 413 } }));\n }\n const contentType = Object.entries(result.metadata).find(([name]) => name.toLowerCase() === \"content-type\")?.[1];\n const headers = new Headers({ etag: result.etag, \"content-length\": String(result.value.byteLength), \"cache-control\": \"private, no-cache\", ...result.metadata, \"x-tinycloud-source\": \"replica\" });\n return ok({\n data: parseLocalValue<T>(result.value, contentType, options.raw, options.binary),\n headers: {\n etag: result.etag,\n contentType,\n contentLength: result.value.byteLength,\n get: (name: string) => headers.get(name),\n },\n });\n }\n if (result.status === \"absent\" || result.status === \"deleted\") return err(serviceError(ErrorCodes.KV_NOT_FOUND, `Key not found: ${key}`, \"kv\"));\n return err(serviceError(ErrorCodes.NETWORK_ERROR, \"Local value is not available\", \"kv\"));\n}\n","import { err, ErrorCodes, serviceError } from \"../../types\";\nimport { kvPrefixCovers } from \"./scope\";\nimport type { KVListPage, LocalListResult, LocalReadMeta } from \"./types\";\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder(\"utf-8\", { fatal: true });\nexport function utf8Compare(a: string, b: string): number {\n const x = encoder.encode(a), y = encoder.encode(b);\n for (let i = 0; i < Math.min(x.length, y.length); i++) if (x[i] !== y[i]) return x[i]! - y[i]!;\n return x.length - y.length;\n}\nexport function encodeTcr1(space: string, path: string, last: string): string {\n const bytes = encoder.encode(JSON.stringify({ v: 1, space, path, last }));\n let binary = \"\";\n for (let offset = 0; offset < bytes.length; offset += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000));\n }\n const payload = btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n return `tcr1.${payload}`;\n}\nexport function decodeTcr1(cursor: string): { v: 1; space: string; path: string; last: string } | null {\n try {\n const encoded = cursor.slice(5).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(encoded + \"=\".repeat((4 - encoded.length % 4) % 4));\n const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n const x = JSON.parse(decoder.decode(bytes));\n return x?.v === 1 && typeof x.space === \"string\" && typeof x.path === \"string\" && typeof x.last === \"string\" ? x : null;\n } catch { return null; }\n}\nexport function cursorRestart() {\n return err(serviceError(ErrorCodes.INVALID_INPUT, \"Local list cursor cannot be served; restart without the cursor\", \"kv\", { meta: { replication: \"cursor_restart\" } }));\n}\nexport function localList(handle: { list(o: { prefix: string; after?: string; limit?: number }): Promise<LocalListResult> }, space: string, path: string, limit: number | undefined, cursor: string | undefined, validateMeta: (meta: LocalReadMeta) => void): Promise<KVListPage> {\n const after = cursor ? decodeTcr1(cursor)?.last : undefined;\n const exact = path !== \"\" && !path.endsWith(\"/\") && (after === undefined || utf8Compare(path, after) > 0)\n ? awaitExact(handle, path, after, validateMeta) : Promise.resolve(false);\n return exact.then(async (hasExact) => {\n const child = path === \"\" ? \"\" : path.endsWith(\"/\") ? path : `${path}/`;\n const want = limit === undefined ? undefined : limit + 1 - (hasExact ? 1 : 0);\n const children = await handle.list({ prefix: child, after, limit: want });\n validateMeta(children.meta);\n let keys = (hasExact ? [path] : []).concat(children.keys);\n const truncated = limit !== undefined && keys.length > limit;\n if (truncated) keys = keys.slice(0, limit);\n return { keys, truncated: truncated, ...(truncated ? { nextCursor: encodeTcr1(space, path, keys[keys.length - 1]!) } : {}) };\n });\n}\n\nasync function awaitExact(handle: { list(o: { prefix: string; after?: string; limit?: number }): Promise<LocalListResult> }, path: string, after: string | undefined, validateMeta: (meta: LocalReadMeta) => void): Promise<boolean> {\n if (after !== undefined && utf8Compare(path, after) <= 0) return false;\n const result = await handle.list({ prefix: path, limit: 1 });\n validateMeta(result.meta);\n return result.keys[0] === path;\n}\n\nexport function listPathCovered(prefixes: readonly string[], path: string): string | undefined {\n return prefixes.find((prefix) => kvPrefixCovers(prefix, path));\n}\n","import type { ReplicationEvent, ReplicationScheduler } from \"./types\";\n\nexport type ReplicationEventInput = ReplicationEvent extends infer Event\n ? Event extends { at: string }\n ? Omit<Event, \"at\">\n : never\n : never;\n\nexport function emitEvent(emit: (event: ReplicationEvent) => void, scheduler: ReplicationScheduler, event: ReplicationEventInput): void {\n try { emit({ ...event, at: new Date(scheduler.now()).toISOString() } as ReplicationEvent); } catch { /* Observability never changes KV behavior. */ }\n}\n","/** Grant lifetime constants without browser storage identifiers. */\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Default device-grant lifetime from install (24 h). All durations are milliseconds. */\nexport const DEFAULT_GRANT_TTL_MS = DAY_MS;\n/** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */\nexport const MAX_GRANT_TTL_MS = 7 * DAY_MS;\n/** Consent deadline = consent anchor + this window (7 d). */\nexport const CONSENT_WINDOW_MS = 7 * DAY_MS;\n/** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */\nexport const RENEW_BELOW_FRACTION = 0.25;\n","/**\n * Grant lifetime policy (TC-858 plan §6, CONTRACT.md §3). Pure functions over epoch\n * milliseconds. Types and constants come from the shared contract; this file only implements them.\n *\n * Every function fails closed: a non-finite input yields a value that refuses the mint, renewal or\n * read, never a permissive one.\n */\nimport { CONSENT_WINDOW_MS, MAX_GRANT_TTL_MS, RENEW_BELOW_FRACTION } from \"./grantPolicyConstants\";\nexport { MAX_GRANT_TTL_MS } from \"./grantPolicyConstants\";\nimport type {\n ConsentDeadlineMs,\n EffectiveGrantExpiry,\n MintRemainingMs,\n NeedsSilentRenewal,\n ReplicaConsentAnchor,\n} from \"./grantPolicyTypes\";\n\n/** An instant that has already passed: nothing is minted, renewed or served against it. */\nconst EXPIRED = Number.NEGATIVE_INFINITY;\n\n/**\n * Caller contract: clamp the anchor with {@link clampConsentAnchor} first. A non-finite anchor\n * yields an already-passed deadline.\n */\nexport const consentDeadlineMs: ConsentDeadlineMs = (anchor) =>\n Number.isFinite(anchor.at) ? anchor.at + CONSENT_WINDOW_MS : EXPIRED;\n\n/**\n * Returns the anchor the deadline may be computed from. A non-finite anchor or clock yields\n * `null` (no anchor, so no mint). An anchor dated after `now` is pulled back to `now`, so a\n * future-dated anchor cannot extend the 7 d window.\n */\nexport const clampConsentAnchor = (\n anchor: ReplicaConsentAnchor | null,\n now: number,\n): ReplicaConsentAnchor | null => {\n if (anchor === null || !Number.isFinite(anchor.at) || !Number.isFinite(now)) return null;\n return anchor.at > now ? { at: now, source: anchor.source } : anchor;\n};\n\nexport const effectiveGrantExpiry: EffectiveGrantExpiry = ({\n signedExpiresAt,\n installedAt,\n grantTtlMs,\n consentDeadline,\n}) => {\n const signedValid = signedExpiresAt === null || Number.isFinite(signedExpiresAt);\n if (!signedValid || !Number.isFinite(installedAt) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) {\n return EXPIRED;\n }\n const ttl = Math.min(grantTtlMs, MAX_GRANT_TTL_MS);\n const localBound = Math.min(installedAt + ttl, consentDeadline);\n return signedExpiresAt === null ? localBound : Math.min(signedExpiresAt, localBound);\n};\n\nexport const mintRemainingMs: MintRemainingMs = ({ now, grantTtlMs, consentDeadline }) => {\n if (!Number.isFinite(now) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) return 0;\n return Math.min(Math.min(grantTtlMs, MAX_GRANT_TTL_MS), consentDeadline - now);\n};\n\nexport const needsSilentRenewal: NeedsSilentRenewal = ({ now, installedAt, effectiveExpiresAt, consentDeadline }) => {\n if (\n !Number.isFinite(now) ||\n !Number.isFinite(installedAt) ||\n !Number.isFinite(effectiveExpiresAt) ||\n !Number.isFinite(consentDeadline)\n ) {\n return false;\n }\n if (!(now < consentDeadline)) return false;\n const remaining = effectiveExpiresAt - now;\n const lifetime = effectiveExpiresAt - installedAt;\n return remaining < lifetime * RENEW_BELOW_FRACTION;\n};\n","import { wrapError } from \"../../errors\";\nimport { ErrorCodes, err, ok, serviceError, type Result } from \"../../types\";\nimport type { KVGetOptions, KVListOptions, KVResponse } from \"../types\";\nimport { kvPrefixCovers, listRangeCovers, requiresSecretsOptIn } from \"./scope\";\nimport { classifyWriteOutcome } from \"./outcome\";\nimport { afterSync, begin, clearPending as clearPendingRecords, clearPrefix, emptyPendingState, pinnedKeys, settle } from \"./pendingWrites\";\nimport { localGet, type LocalGetResponse } from \"./localResponse\";\nimport { cursorRestart, decodeTcr1, listPathCovered, localList } from \"./listLocal\";\nimport { emitEvent, type ReplicationEventInput } from \"./events\";\nimport type { KVListPage, KVReplicaHandle, KVReplicationController, LocalGetResult, LocalReadMeta, LocalReplicaStatus, ReplicaInspectedStatus, ReplicaGrantInfo, PendingWriteState, ReplicaDevice, ReplicaPeerCommit, ReplicationEvent, ReplicationReason, ReplicaStatusEntry, KVReplicationDeps, LocalSyncResult } from \"./types\";\nimport type { ReplicaDeliveryDecision, ReplicaSessionStamp } from \"./lifecycle\";\nimport { DEFAULT_GRANT_TTL_MS, RENEW_BELOW_FRACTION } from \"./grantPolicyConstants\";\nimport { clampConsentAnchor, consentDeadlineMs, mintRemainingMs, needsSilentRenewal } from \"./grantPolicy\";\nimport type { ReplicaConsentAnchor } from \"./grantPolicyTypes\";\n\nconst CLOSE_TIMEOUT_MS = 3_000;\nconst STATUS_REFRESH_TIMEOUT_MS = CLOSE_TIMEOUT_MS;\ntype SyncAbortCause = \"timeout\" | \"caller\" | \"close\" | \"purge\";\ninterface SyncContext { abortCause?: SyncAbortCause }\ninterface StatusInspection { abort: AbortController; settled: Promise<void> }\ninterface InspectedStatusResult { missing: boolean; local?: LocalReplicaStatus | ReplicaInspectedStatus; errorCode?: string }\ninterface ReplicaDerivationPlan { path: \"session\" | \"runtime\"; parentCid: string; expiresAt: number }\ninterface Opened {\n handle?: KVReplicaHandle;\n opening?: Promise<KVReplicaHandle>;\n sync?: Promise<LocalSyncResult>;\n syncContext?: SyncContext;\n abort?: AbortController;\n mintAbort?: AbortController;\n timer?: () => void;\n renewalTimer?: () => void;\n renewing?: Promise<void>;\n lastError?: string;\n reason?: ReplicationReason;\n strategy?: \"session\" | \"minted\" | \"installed\";\n retryAt?: number;\n failures?: number;\n unsupported?: boolean;\n authorityRevoked?: boolean;\n reportedExpired?: boolean;\n reportedCappedCid?: string;\n reportedRenewalUnqualifiedCid?: string;\n}\nconst nowDate = (now: number) => new Date(now).toISOString();\nconst errorCode = (e: unknown): string => typeof e === \"object\" && e !== null && \"code\" in e && typeof e.code === \"string\" ? e.code : \"REPLICA_UNAVAILABLE\";\nfunction raceSignal<T>(job: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) return Promise.reject(signal.reason ?? Object.assign(new Error(\"KV request was aborted\"), { code: ErrorCodes.ABORTED }));\n let remove = () => {};\n const aborted = new Promise<never>((_, reject) => {\n const onAbort = () => reject(signal.reason ?? Object.assign(new Error(\"KV request was aborted\"), { code: ErrorCodes.ABORTED }));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n remove = () => signal.removeEventListener(\"abort\", onAbort);\n });\n return Promise.race([job, aborted]).finally(remove);\n}\n\nexport function createKVReplication(deps: KVReplicationDeps): KVReplicationController {\n const { options, mode, storage, identity, session, authority, pending, scheduler } = deps;\n const emit = (event: ReplicationEventInput): void => emitEvent(deps.emit, scheduler, event);\n const replicas = new Map<string, Opened>();\n const statusInspections = new Set<StatusInspection>();\n let isClosed = false;\n let purgeStarted = false;\n let purgeInProgress = false;\n let previous = deps.previous;\n let pinnedStateReported = false;\n const inProcessProof = new Set<string>();\n let anchorUnavailable = false;\n let consentAnchor: ReplicaConsentAnchor | null = null;\n try {\n consentAnchor = clampConsentAnchor(authority.consentAnchor?.() ?? null, scheduler.now());\n if (consentAnchor?.source === \"first_install\") consentAnchor = null;\n } catch {\n anchorUnavailable = true;\n }\n const grantPolicy = { grantTtlMs: options.grantTtlMs ?? DEFAULT_GRANT_TTL_MS, consentAnchor };\n const quota = options.maxBytes === undefined && options.minFreeBytes === undefined\n ? undefined : { maxBytes: options.maxBytes, minFreeBytes: options.minFreeBytes };\n const policyDeadline = consentAnchor === null ? null : consentDeadlineMs(consentAnchor);\n let scheduledConsentDeadline: number | null = null;\n let cancelConsentTimer: (() => void) | undefined;\n function durableDeadline(): number | null {\n if (storage.kind !== \"indexeddb\" || !deps.stamp) return null;\n try {\n const deadline = storage.lifecycle?.consentDeadline(deps.stamp);\n return typeof deadline === \"number\" && Number.isFinite(deadline) ? deadline : null;\n } catch {\n return null;\n }\n }\n function mintDeadline(): number | null {\n if (policyDeadline === null) return null;\n if (storage.kind !== \"indexeddb\") return policyDeadline;\n const durable = durableDeadline();\n return durable === null ? null : Math.min(policyDeadline, durable);\n }\n function scheduleConsentDeadline(): void {\n const deadline = durableDeadline();\n if (deadline === null || consentDenyStarted || isClosed) return;\n const now = scheduler.now();\n if (!Number.isFinite(now)) return;\n if (scheduledConsentDeadline === deadline && cancelConsentTimer) return;\n scheduledConsentDeadline = deadline;\n cancelConsentTimer?.();\n cancelConsentTimer = scheduler.setTimeout(() => {\n cancelConsentTimer = undefined;\n checkDelivery();\n }, Math.max(0, deadline - now));\n }\n const reportedDeadline = new Set<string>();\n let consentDenyStarted = false;\n function checkDelivery(): ReplicaDeliveryDecision {\n const gate = storage.lifecycle;\n if (!gate) return storage.kind === \"indexeddb\" || anchorUnavailable || deps.stamp !== undefined\n ? { status: \"gated\", gate: \"gate_unavailable\" }\n : { status: \"allow\" };\n if (!deps.stamp) return { status: \"gated\", gate: \"not_established\" };\n if (consentDenyStarted) return { status: \"gated\", gate: \"stamp_stale\" };\n try {\n const decision = gate.checkDelivery(deps.stamp);\n if (decision.status === \"consent_expired\") startConsentDenial();\n if (decision.status !== \"allow\") return decision;\n if (storage.kind === \"indexeddb\") {\n const deadline = durableDeadline();\n if (deadline === null) return { status: \"gated\", gate: \"gate_unavailable\" };\n const now = scheduler.now();\n if (!Number.isFinite(now)) return { status: \"gated\", gate: \"gate_unavailable\" };\n if (now >= deadline) {\n startConsentDenial();\n return { status: \"consent_expired\", code: \"CONSENT_EXPIRED\" };\n }\n }\n return anchorUnavailable ? { status: \"gated\", gate: \"gate_unavailable\" } : decision;\n } catch {\n return { status: \"gated\", gate: \"gate_unavailable\" };\n }\n }\n function markConsentExpired(): boolean {\n if (consentDenyStarted || isClosed || purgeStarted) return false;\n cancelConsentTimer?.();\n cancelConsentTimer = undefined;\n consentDenyStarted = true;\n for (const state of replicas.values()) {\n state.renewalTimer?.();\n state.renewalTimer = undefined;\n state.mintAbort?.abort();\n const id = state.handle?.replicaId;\n if (id && !reportedDeadline.has(id)) {\n reportedDeadline.add(id);\n emit({ type: \"replication.grant\", replicaId: id, action: \"consent_deadline_reached\", code: \"CONSENT_EXPIRED\" });\n }\n }\n return true;\n }\n function observeConsentExpired(stamp: ReplicaSessionStamp): void {\n if (!deps.stamp || stamp.incarnation !== deps.stamp.incarnation || stamp.lifecycleEpoch !== deps.stamp.lifecycleEpoch) return;\n if (markConsentExpired()) emit({ type: \"replication.lifecycle\", action: \"denied\", reason: \"consent_expired\" });\n }\n function startConsentDenial(): void {\n const gate = storage.lifecycle;\n if (!gate || !markConsentExpired()) return;\n void gate.deny({ reason: \"consent_expired\", principal: identity.principal }).then(\n (outcome) => emit({ type: \"replication.lifecycle\", action: outcome.status === \"denied\" ? \"denied\" : outcome.status === \"stale\" ? \"deny_stale\" : outcome.status === \"deleted\" ? \"database_deleted\" : outcome.status === \"marker\" ? \"marker_set\" : \"unguarded\", reason: \"consent_expired\" }),\n () => emit({ type: \"replication.lifecycle\", action: \"deny_failed\", reason: \"consent_expired\" }),\n );\n }\n function deliveryError(decision: Exclude<ReplicaDeliveryDecision, { status: \"allow\" }>): Error {\n return Object.assign(new Error(decision.status === \"consent_expired\" ? \"Replica consent expired\" : \"Replica session is gated\"), {\n code: decision.status === \"consent_expired\" ? decision.code : \"REPLICA_GATED\",\n ...(decision.status === \"gated\" ? { gate: decision.gate } : {}),\n });\n }\n function deliveryReason(code: string): ReplicationReason {\n return code === \"CONSENT_EXPIRED\" || code === \"GRANT_EXPIRED\" ? \"grant_expired\" : code === \"REPLICA_GATED\" ? \"replica_gated\" : \"replica_error\";\n }\n function reportGrantExpiry(prefix: string): void {\n const state = replicas.get(prefix);\n if (!state) return;\n state.reason = \"grant_expired\";\n state.lastError = \"GRANT_EXPIRED\";\n const replicaId = state.handle?.replicaId;\n if (!replicaId || state.reportedExpired) return;\n state.reportedExpired = true;\n emit({ type: \"replication.grant\", replicaId, action: \"expired\", code: \"GRANT_EXPIRED\" });\n }\n function reportGrantCap(state: Opened, handle: KVReplicaHandle, grant: ReplicaGrantInfo | null | undefined): void {\n if (\n !grant?.unconstrained || !handle.replicaId ||\n typeof grant.effectiveExpiresAt !== \"number\" || !Number.isFinite(grant.effectiveExpiresAt) ||\n !(grant.expiresAt === null || grant.effectiveExpiresAt < grant.expiresAt)\n ) return;\n const capKey = `${grant.cid}:${grant.effectiveExpiresAt}`;\n if (state.reportedCappedCid === capKey) return;\n state.reportedCappedCid = capKey;\n emit({ type: \"replication.grant\", replicaId: handle.replicaId, action: \"capped\", effectiveExpiresAt: nowDate(grant.effectiveExpiresAt) });\n }\n const configuredPrefix = (path: string) => options.prefixes.find((prefix) => kvPrefixCovers(prefix, path));\n function recordRevocation(prefix: string, error: unknown): void {\n if (errorCode(error) !== \"GRANT_REVOKED\") return;\n const state = replicas.get(prefix) ?? {};\n state.authorityRevoked = true;\n state.reason = \"grant_revoked\";\n state.lastError = \"GRANT_REVOKED\";\n replicas.set(prefix, state);\n }\n function markRootUnsupported(prefix: string): void {\n const state = replicas.get(prefix) ?? {};\n const firstRefusal = state.lastError !== \"REPLICATION_ROOT_UNSUPPORTED\";\n state.reason = \"replica_unavailable\";\n state.lastError = \"REPLICATION_ROOT_UNSUPPORTED\";\n replicas.set(prefix, state);\n if (firstRefusal) {\n emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"unavailable\", code: \"REPLICATION_ROOT_UNSUPPORTED\" });\n }\n }\n function unsupportedRoot(prefix: string): Error {\n markRootUnsupported(prefix);\n return Object.assign(new Error(\"This node doesn't support whole-space sync yet.\"), { code: \"REPLICATION_ROOT_UNSUPPORTED\" });\n }\n\n\n function canReuseInstalled(grant: ReplicaGrantInfo | null | undefined, sessionOnly: boolean): boolean {\n if (!grant?.unconstrained) return false;\n if (!deps.stamp) return true;\n if (!sessionOnly && consentAnchor === null) return false;\n const now = scheduler.now();\n const deadline = storage.kind === \"indexeddb\" ? durableDeadline() : policyDeadline ?? grant.consentDeadline;\n return grant.state === \"active\" &&\n typeof grant.installedAt === \"number\" && Number.isFinite(grant.installedAt) &&\n typeof grant.effectiveExpiresAt === \"number\" && Number.isFinite(grant.effectiveExpiresAt) &&\n typeof grant.consentDeadline === \"number\" && Number.isFinite(grant.consentDeadline) &&\n typeof deadline === \"number\" && Number.isFinite(deadline) &&\n Number.isFinite(now) && now >= grant.installedAt &&\n (grant.expiresAt === null || typeof grant.expiresAt === \"number\" && Number.isFinite(grant.expiresAt) && now < grant.expiresAt) &&\n now < Math.min(grant.effectiveExpiresAt, grant.consentDeadline, deadline);\n }\n function sessionRefusal(prefix: string): string | undefined {\n try {\n if (authority.sessionOnly !== true) return undefined;\n // A signed get+sync grant for the configured prefix covers its contained get key/list path.\n const grant = authority.sessionGrant(prefix);\n return \"refused\" in grant ? grant.refused : undefined;\n } catch {\n return \"NOT_COVERED\";\n }\n }\n\n\n async function open(prefix: string): Promise<KVReplicaHandle> {\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") throw deliveryError(delivery);\n if (isClosed || purgeStarted) throw Object.assign(new Error(\"Replication controller is closed\"), { code: \"REPLICA_CLOSED\" });\n let state = replicas.get(prefix);\n if (state?.handle) return state.handle;\n if (state?.opening) return state.opening;\n state ??= {};\n replicas.set(prefix, state);\n if (state.unsupported) throw Object.assign(new Error(\"Replication runtime is unsupported\"), { code: \"RUNTIME_UNSUPPORTED\" });\n if (state.retryAt !== undefined && scheduler.now() < state.retryAt) throw Object.assign(new Error(\"Replica open is backing off\"), { code: state.lastError ?? \"REPLICA_UNAVAILABLE\" });\n if (requiresSecretsOptIn(session.space, prefix) && !options.allowSecrets) {\n const firstRefusal = state.lastError !== \"SECRETS_OPT_IN_REQUIRED\";\n state.reason = \"replica_unavailable\";\n state.lastError = \"SECRETS_OPT_IN_REQUIRED\";\n if (firstRefusal) emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"unavailable\", code: \"SECRETS_OPT_IN_REQUIRED\" });\n throw Object.assign(new Error(\"Replication requires allowSecrets for this space or prefix\"), { code: \"SECRETS_OPT_IN_REQUIRED\" });\n }\n state.opening = (async () => {\n if (previous) { await previous; previous = undefined; }\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") throw deliveryError(delivery);\n const sessionOnly = authority.sessionOnly === true;\n const sessionGrant = authority.sessionGrant(prefix);\n const delegated = \"refused\" in sessionGrant ? undefined : sessionGrant;\n const plan = sessionOnly ? undefined : authority.plan(prefix);\n let refusalCode: string | undefined;\n if (\"refused\" in sessionGrant) refusalCode = sessionGrant.refused;\n if (plan && \"refused\" in plan) refusalCode ??= plan.refused;\n if (deps.stamp && consentAnchor === null && !sessionOnly) refusalCode = \"REPLICA_GATED\";\n let device: ReplicaDevice | undefined;\n if (delegated) { device = delegated.device; state!.strategy = \"session\"; }\n const spec = {\n identity, space: session.space, prefix, allowSecrets: options.allowSecrets, grantPolicy,\n ...(quota ? { quota } : {}),\n ...(deps.stamp ? { stamp: deps.stamp } : {}),\n ...(device ? { device } : {}),\n ...(deps.fetch ? { fetch: deps.fetch } : {}),\n onPeerCommit: (info: ReplicaPeerCommit) => {\n if (isClosed || purgeStarted || state!.handle === undefined) return;\n emit({\n type: \"replication.sync\", space: session.space, replica: prefix,\n trigger: \"peer\", origin: \"peer\", outcome: \"ok\", durationMs: 0, lagMs: null,\n ...(info.changes === undefined ? {} : { changes: info.changes }),\n ...(info.coverage === undefined ? {} : { coverage: info.coverage }),\n });\n },\n };\n if (prefix === \"/\" && deps.nodeFeatures !== undefined && !deps.nodeFeatures.includes(\"kv-sync-root\")) {\n throw unsupportedRoot(prefix);\n }\n const handle = await storage.open(spec);\n state!.handle = handle;\n const afterOpen = checkDelivery();\n if (afterOpen.status !== \"allow\") throw deliveryError(afterOpen);\n emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"opened\" });\n const runtimePlan = !sessionOnly && plan && !(\"refused\" in plan) ? plan : undefined;\n let installed = runtimePlan || delegated ? await handle.grant() : undefined;\n if (installed && !canReuseInstalled(installed, sessionOnly)) {\n if (installed.unconstrained) refusalCode = consentAnchor === null && !sessionOnly ? \"REPLICA_GATED\" : \"GRANT_EXPIRED\";\n installed = undefined;\n }\n let mintedExpiryMs: number | undefined;\n if (delegated && consentAnchor !== null) {\n const beforeInstall = checkDelivery();\n if (beforeInstall.status !== \"allow\") throw deliveryError(beforeInstall);\n installed = await handle.installGrant(delegated.ucan);\n } else if (runtimePlan) {\n if (!installed || !installed.unconstrained || installed.parentCid !== runtimePlan.parentCid || (installed.expiresAt !== null && runtimePlan.expiresAt > installed.expiresAt + 300_000)) {\n const deadline = mintDeadline();\n const expiryMs = mintRemainingMs({ now: scheduler.now(), grantTtlMs: grantPolicy.grantTtlMs, consentDeadline: deadline ?? Number.NaN });\n if (expiryMs > 0) {\n try {\n const mintAbort = new AbortController();\n state!.mintAbort = mintAbort;\n const minted = await authority.mint(handle.deviceDid, prefix, mintAbort.signal, { expiryMs });\n const beforeInstall = checkDelivery();\n if (beforeInstall.status !== \"allow\") throw deliveryError(beforeInstall);\n installed = await handle.installGrant(minted.ucan);\n state!.strategy = \"minted\";\n mintedExpiryMs = expiryMs;\n } catch (error) {\n if (errorCode(error) === \"CONSENT_EXPIRED\" || errorCode(error) === \"REPLICA_GATED\" || !installed?.unconstrained) throw error;\n } finally { state!.mintAbort = undefined; }\n }\n }\n if (installed?.unconstrained) { state!.strategy ??= \"installed\"; state!.reason = undefined; }\n } else if ((delegated || sessionOnly) && installed?.unconstrained) {\n state!.strategy = \"installed\";\n }\n const beforeGrantEvent = checkDelivery();\n if (beforeGrantEvent.status !== \"allow\") throw deliveryError(beforeGrantEvent);\n reportGrantCap(state!, handle, installed);\n if (mintedExpiryMs !== undefined) state!.reportedExpired = false;\n if (mintedExpiryMs !== undefined && handle.replicaId) emit({ type: \"replication.grant\", replicaId: handle.replicaId, action: \"minted\", expiryMs: mintedExpiryMs });\n if (!installed?.unconstrained) {\n state!.reason = \"grant_missing\";\n state!.lastError = refusalCode ?? \"SESSION_LACKS_SYNC\";\n emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"grant_missing\", code: state!.lastError });\n } else emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"grant_installed\", strategy: state!.strategy });\n if (isClosed || purgeStarted) {\n await handle.close();\n throw Object.assign(new Error(\"Replication controller is closed\"), { code: \"REPLICA_CLOSED\" });\n }\n if (installed?.unconstrained) await maybeRenew(prefix, handle, installed, runtimePlan);\n if (mode === \"background\" && state!.reason !== \"grant_missing\") {\n void syncPrefix(prefix, \"start\").catch(() => undefined);\n schedule(prefix);\n }\n return handle;\n })();\n try { return await state.opening; } catch (error) {\n const code = errorCode(error);\n if (code === \"CONSENT_EXPIRED\") startConsentDenial();\n recordRevocation(prefix, error);\n if (code === \"REPLICA_GATED\" || code === \"CONSENT_EXPIRED\") state.reason = deliveryReason(code);\n else if (code !== \"GRANT_REVOKED\") state.reason = \"replica_unavailable\";\n state.lastError = code;\n state.failures = (state.failures ?? 0) + 1;\n if (code === \"RUNTIME_UNSUPPORTED\") state.unsupported = true;\n else if (code !== \"REPLICA_CLOSED\" && code !== \"REPLICATION_ROOT_UNSUPPORTED\" && code !== \"REPLICA_GATED\" && code !== \"CONSENT_EXPIRED\") state.retryAt = scheduler.now() + Math.min(300_000, 5_000 * 2 ** Math.min(state.failures - 1, 6));\n state.handle?.close().catch(() => undefined);\n state.handle = undefined;\n throw error;\n } finally { state.opening = undefined; }\n }\n\n function scheduleRenewal(prefix: string, handle: KVReplicaHandle, grant: ReplicaGrantInfo, plan: ReplicaDerivationPlan): void {\n const state = replicas.get(prefix);\n state?.renewalTimer?.();\n if (state) state.renewalTimer = undefined;\n if (!state || isClosed || purgeStarted || plan.path !== \"session\" || !authority.canRenew) return;\n const { installedAt, effectiveExpiresAt } = grant;\n const deadline = mintDeadline();\n if (\n typeof installedAt !== \"number\" || !Number.isFinite(installedAt) ||\n typeof effectiveExpiresAt !== \"number\" || !Number.isFinite(effectiveExpiresAt) ||\n !(effectiveExpiresAt > installedAt) || deadline === null\n ) return;\n const threshold = installedAt + (effectiveExpiresAt - installedAt) * (1 - RENEW_BELOW_FRACTION);\n const now = scheduler.now();\n if (!Number.isFinite(now) || !(threshold < deadline) || now > threshold) return;\n state.renewalTimer = scheduler.setTimeout(() => {\n state.renewalTimer = undefined;\n void maybeRenew(prefix, handle).catch(() => undefined);\n }, Math.max(0, Math.floor(threshold) + 1 - now));\n }\n\n async function maybeRenew(prefix: string, handle: KVReplicaHandle, knownGrant?: ReplicaGrantInfo, knownPlan?: ReplicaDerivationPlan): Promise<void> {\n const state = replicas.get(prefix);\n if (!state || state.handle !== handle || isClosed || purgeStarted || !authority.canRenew) return;\n if (state.renewing) return state.renewing;\n const decision = checkDelivery();\n if (decision.status !== \"allow\") return;\n const grant = knownGrant ?? await handle.grant();\n if (!grant?.unconstrained) return;\n const { installedAt, effectiveExpiresAt } = grant;\n const deadline = mintDeadline();\n if (\n typeof installedAt !== \"number\" || !Number.isFinite(installedAt) ||\n typeof effectiveExpiresAt !== \"number\" || !Number.isFinite(effectiveExpiresAt) ||\n deadline === null\n ) return;\n const now = scheduler.now();\n if (!needsSilentRenewal({ now, installedAt, effectiveExpiresAt, consentDeadline: deadline })) {\n if (knownPlan) scheduleRenewal(prefix, handle, grant, knownPlan);\n return;\n }\n let plan: ReplicaDerivationPlan | undefined = knownPlan;\n try {\n if (!plan) {\n const selected = authority.plan(prefix);\n if (\"refused\" in selected) {\n if (handle.replicaId) emit({ type: \"replication.grant\", replicaId: handle.replicaId, action: \"renewal_refused\", code: selected.refused });\n return;\n }\n plan = selected;\n }\n } catch {\n if (handle.replicaId) emit({ type: \"replication.grant\", replicaId: handle.replicaId, action: \"renewal_deferred\" });\n return;\n }\n if (plan?.path !== \"session\") {\n if (handle.replicaId && state.reportedRenewalUnqualifiedCid !== grant.cid) {\n state.reportedRenewalUnqualifiedCid = grant.cid;\n emit({ type: \"replication.grant\", replicaId: handle.replicaId, action: \"renewal_deferred\" });\n }\n return;\n }\n const expiryMs = mintRemainingMs({ now, grantTtlMs: grantPolicy.grantTtlMs, consentDeadline: deadline });\n if (!(expiryMs > 0)) return;\n state.renewalTimer?.();\n state.renewalTimer = undefined;\n const mintAbort = new AbortController();\n state.mintAbort = mintAbort;\n const job = Promise.resolve().then(async () => {\n const minted = await authority.mint(handle.deviceDid, prefix, mintAbort.signal, { expiryMs, renewalOnly: true });\n const beforeInstall = checkDelivery();\n if (beforeInstall.status !== \"allow\") throw deliveryError(beforeInstall);\n const installed = await handle.installGrant(minted.ucan);\n const beforeEvent = checkDelivery();\n if (beforeEvent.status !== \"allow\") throw deliveryError(beforeEvent);\n reportGrantCap(state, handle, installed);\n state.reportedExpired = false;\n if (state.reason === \"grant_expired\") state.reason = undefined;\n if (state.lastError === \"GRANT_EXPIRED\") state.lastError = undefined;\n if (handle.replicaId) emit({ type: \"replication.grant\", replicaId: handle.replicaId, action: \"renewed\", expiryMs });\n if (typeof installed.effectiveExpiresAt === \"number\" && installed.effectiveExpiresAt > effectiveExpiresAt) {\n scheduleRenewal(prefix, handle, installed, plan);\n }\n });\n state.renewing = job;\n try {\n await job;\n } catch (error) {\n const code = errorCode(error);\n if (code === \"CONSENT_EXPIRED\" || code === \"REPLICA_GATED\") throw error;\n if (!isClosed && handle.replicaId) {\n const refused = typeof error === \"object\" && error !== null && \"refused\" in error && typeof error.refused === \"string\" ? error.refused : null;\n emit({ type: \"replication.grant\", replicaId: handle.replicaId, action: refused ? \"renewal_refused\" : \"renewal_deferred\", code: refused ?? code });\n }\n } finally {\n state.renewing = undefined;\n if (state.mintAbort === mintAbort) state.mintAbort = undefined;\n }\n }\n\n function schedule(prefix: string): void {\n const state = replicas.get(prefix);\n if (!state || mode !== \"background\" || isClosed || purgeStarted) return;\n state.timer = scheduler.setTimeout(() => {\n state.timer = undefined;\n void syncPrefix(prefix, \"interval\").catch(() => undefined).finally(() => schedule(prefix));\n }, options.syncIntervalMs);\n }\n\n async function syncPrefix(prefix: string, trigger: \"start\" | \"interval\" | \"stale_read\" | \"manual\", signal?: AbortSignal, context?: SyncContext): Promise<LocalSyncResult> {\n if (prefix === \"/\" && deps.nodeFeatures !== undefined && !deps.nodeFeatures.includes(\"kv-sync-root\")) {\n throw unsupportedRoot(prefix);\n }\n const initialRefusal = sessionRefusal(prefix);\n if (initialRefusal) throw Object.assign(new Error(\"Current session does not cover replica sync\"), { code: initialRefusal });\n const handle = await open(prefix);\n const state = replicas.get(prefix)!;\n if (state.sync) return state.sync;\n const abort = new AbortController();\n const syncContext = context ?? {};\n state.syncContext = syncContext;\n state.abort = abort;\n const abortFromCaller = () => {\n syncContext.abortCause ??= \"caller\";\n abort.abort(signal?.reason);\n };\n signal?.addEventListener(\"abort\", abortFromCaller, { once: true });\n const started = scheduler.now();\n let job!: Promise<LocalSyncResult>;\n job = (async () => {\n try {\n const syncStartEpoch = (await pending.read()).committedEpoch;\n const beforeSync = checkDelivery();\n if (beforeSync.status !== \"allow\") throw deliveryError(beforeSync);\n await maybeRenew(prefix, handle);\n const afterRenewal = checkDelivery();\n if (afterRenewal.status !== \"allow\") throw deliveryError(afterRenewal);\n const refusal = sessionRefusal(prefix);\n if (refusal) throw Object.assign(new Error(\"Current session does not cover replica sync\"), { code: refusal });\n const result = await handle.sync({ signal: abort.signal, syncStartEpoch });\n const afterSyncDelivery = checkDelivery();\n if (afterSyncDelivery.status !== \"allow\") throw deliveryError(afterSyncDelivery);\n if (result.status === \"busy\") {\n emit({ type: \"replication.sync\", space: session.space, replica: prefix, trigger, outcome: \"busy\", durationMs: scheduler.now() - started, lagMs: null });\n return result;\n }\n inProcessProof.add(prefix);\n const snapshot = await pending.read();\n const beforePending = checkDelivery();\n if (beforePending.status !== \"allow\") throw deliveryError(beforePending);\n const clearedCandidates = snapshot.records.some((r) => r.state === \"committed\" && r.epoch !== null && r.epoch <= syncStartEpoch && kvPrefixCovers(prefix, r.key));\n const cleared = clearedCandidates ? await pending.update((s) => afterSync(s, prefix, syncStartEpoch)) : 0;\n const beforeResult = checkDelivery();\n if (beforeResult.status !== \"allow\") throw deliveryError(beforeResult);\n emit({ type: \"replication.sync\", space: session.space, replica: prefix, trigger, outcome: \"ok\", durationMs: scheduler.now() - started, lagMs: null, pendingCleared: cleared, pages: result.pages, changes: result.changes, deleted: result.deleted, fetched: result.fetched, contentMissing: result.contentMissing, coverage: result.coverage });\n return result;\n } catch (error) {\n const code = errorCode(error); state.lastError = code; recordRevocation(prefix, error);\n if (code === \"CONSENT_EXPIRED\") startConsentDenial();\n emit({ type: \"replication.sync\", space: session.space, replica: prefix, trigger, outcome: abort.signal.aborted ? \"aborted\" : \"error\", class: code === \"CONSENT_EXPIRED\" || code === \"REPLICA_GATED\" ? \"lifecycle\" : code === \"NETWORK_ERROR\" || code === \"TIMEOUT\" ? \"offline\" : \"node\", code, durationMs: scheduler.now() - started, lagMs: null });\n throw error;\n } finally { signal?.removeEventListener(\"abort\", abortFromCaller); state.abort = undefined; }\n })();\n state.sync = job;\n try { return await job; } finally {\n if (state.sync === job) {\n state.sync = undefined;\n state.syncContext = undefined;\n }\n }\n }\n type DrainedSync = { settled: false } | { settled: true; result: LocalSyncResult } | { settled: true; error: unknown };\n async function drainForegroundSync(prefix: string, sync: Promise<LocalSyncResult>): Promise<DrainedSync> {\n let cancel = () => {};\n const settled: Promise<DrainedSync> = sync.then(\n (result) => ({ settled: true, result }),\n (error: unknown) => ({ settled: true, error }),\n );\n const timeout = new Promise<DrainedSync>((resolve) => {\n cancel = scheduler.setTimeout(() => resolve({ settled: false }), CLOSE_TIMEOUT_MS);\n });\n try {\n const drained = await Promise.race([settled, timeout]);\n if (!drained.settled) emit({ type: \"replication.sync\", space: session.space, replica: prefix, trigger: \"stale_read\", outcome: \"aborted\", code: \"DRAIN_TIMEOUT\", durationMs: CLOSE_TIMEOUT_MS, lagMs: null });\n return drained;\n } finally { cancel(); }\n }\n function validateReadMeta(meta: LocalReadMeta): void {\n if (meta.coverage !== \"complete\") throw Object.assign(new Error(\"Replica coverage changed before the local read\"), { code: \"COVERAGE_INCOMPLETE\" });\n if (meta.authority !== \"valid\") {\n const code = meta.authority === \"expired\" ? \"GRANT_EXPIRED\" : meta.authority === \"revoked\" ? \"GRANT_REVOKED\" : \"GRANT_NOT_YET_VALID\";\n throw Object.assign(new Error(\"Replica authority changed before the local read\"), { code });\n }\n }\n function reasonForReadMetaCode(code: string): ReplicationReason {\n if (code === \"COVERAGE_INCOMPLETE\") return \"coverage_incomplete\";\n if (code === \"GRANT_EXPIRED\") return \"grant_expired\";\n if (code === \"GRANT_REVOKED\") return \"grant_revoked\";\n if (code === \"GRANT_NOT_YET_VALID\") return \"grant_not_yet_valid\";\n return \"replica_error\";\n }\n async function statusAfterDrain(handle: KVReplicaHandle, signal: AbortSignal): Promise<LocalReplicaStatus> {\n let cancel = () => {};\n const timeout = new Promise<never>((_resolve, reject) => {\n cancel = scheduler.setTimeout(\n () => reject(Object.assign(new Error(\"Replica status refresh timed out\"), { code: \"STATUS_TIMEOUT\" })),\n STATUS_REFRESH_TIMEOUT_MS,\n );\n });\n try {\n return await raceSignal(Promise.race([handle.status(), timeout]), signal);\n } finally { cancel(); }\n }\n function staleSyncOutcome(outcome: { result: LocalSyncResult } | { error: unknown }, timedOut: boolean, currentStatus: LocalReplicaStatus): { status: LocalReplicaStatus; syncError?: string; syncedBeforeRead: boolean; failure?: \"busy\" | \"error\" } {\n if (\"error\" in outcome) {\n const code = errorCode(outcome.error);\n if (code === \"NETWORK_ERROR\" || (timedOut && (code === \"ABORTED\" || code === \"TIMEOUT\"))) return { status: currentStatus, syncedBeforeRead: false, syncError: code === \"NETWORK_ERROR\" ? code : \"TIMEOUT\" };\n return { status: currentStatus, syncedBeforeRead: false, syncError: code, failure: \"error\" };\n }\n if (outcome.result.status === \"busy\") return { status: currentStatus, syncedBeforeRead: false, failure: \"busy\" };\n return { status: currentStatus, syncedBeforeRead: true };\n }\n async function freshness(prefix: string, handle: KVReplicaHandle, signal: AbortSignal): Promise<{ status: LocalReplicaStatus; syncError?: string; syncedBeforeRead: boolean; failure?: \"busy\" | \"error\" }> {\n let currentStatus = await handle.status();\n const syncedAt = currentStatus.lastSyncAt === null ? null : Date.parse(currentStatus.lastSyncAt);\n const stale = syncedAt === null || !Number.isFinite(syncedAt) || scheduler.now() - syncedAt > options.maxStalenessMs;\n let snapshot;\n try { snapshot = await pending.read(); } catch (error) { return { status: currentStatus, syncedBeforeRead: false, syncError: errorCode(error), failure: \"error\" }; }\n const behind = currentStatus.syncedThroughEpoch < snapshot.committedEpoch;\n const unproven = !pending.durable && !inProcessProof.has(prefix);\n if ((stale || behind || unproven) && !signal.aborted) {\n const syncController = mode === \"foreground\" ? new AbortController() : undefined;\n const syncState = replicas.get(prefix);\n const ownsSync = !syncState?.sync;\n const syncContext = syncState?.syncContext ?? {};\n const abortFromCaller = () => {\n if (ownsSync) syncContext.abortCause ??= \"caller\";\n syncController?.abort(signal.reason);\n };\n if (syncController) signal.addEventListener(\"abort\", abortFromCaller, { once: true });\n let cancelTimeout = () => {};\n const timeout = new Promise<{ timeout: true }>((resolve) => {\n cancelTimeout = scheduler.setTimeout(() => resolve({ timeout: true }), options.staleSyncTimeoutMs);\n });\n let cancelAbort = () => {};\n const callerAbort = new Promise<{ callerAborted: true }>((resolve) => {\n if (signal.aborted) resolve({ callerAborted: true });\n else {\n const listener = () => resolve({ callerAborted: true });\n signal.addEventListener(\"abort\", listener, { once: true });\n cancelAbort = () => signal.removeEventListener(\"abort\", listener);\n }\n });\n const sync = syncPrefix(prefix, \"stale_read\", syncController?.signal, syncContext);\n const outcome = await Promise.race([\n sync.then((result) => ({ result }), (error: unknown) => ({ error })),\n timeout,\n callerAbort,\n ]);\n cancelTimeout();\n cancelAbort();\n signal.removeEventListener(\"abort\", abortFromCaller);\n if (\"callerAborted\" in outcome) {\n if (syncController && ownsSync) {\n syncContext.abortCause ??= \"caller\";\n syncController.abort(signal.reason);\n await drainForegroundSync(prefix, sync);\n }\n return { status: currentStatus, syncedBeforeRead: false, syncError: cancellationCode(signal) };\n }\n if (\"timeout\" in outcome) {\n if (ownsSync) {\n syncContext.abortCause ??= \"timeout\";\n syncController?.abort(Object.assign(new Error(\"Stale-read sync timed out\"), { code: \"TIMEOUT\" }));\n }\n const drained = syncController ? await drainForegroundSync(prefix, sync) : undefined;\n if (signal.aborted) return { status: currentStatus, syncedBeforeRead: false, syncError: cancellationCode(signal) };\n if (drained && !drained.settled) return { status: currentStatus, syncedBeforeRead: false, syncError: \"DRAIN_TIMEOUT\", failure: \"error\" };\n try { currentStatus = await statusAfterDrain(handle, signal); }\n catch (error) {\n if (signal.aborted) return { status: currentStatus, syncedBeforeRead: false, syncError: cancellationCode(signal), failure: \"error\" };\n return { status: currentStatus, syncedBeforeRead: false, syncError: errorCode(error), failure: \"error\" };\n }\n const timeoutAbort = syncContext.abortCause === \"timeout\";\n return staleSyncOutcome(\n drained?.settled ? (\"result\" in drained ? { result: drained.result } : { error: drained.error }) : { error: Object.assign(new Error(\"Stale-read sync timed out\"), { code: \"TIMEOUT\" }) },\n timeoutAbort || !syncController,\n currentStatus,\n );\n }\n if (\"error\" in outcome) return staleSyncOutcome({ error: outcome.error }, false, currentStatus);\n if (outcome.result.status === \"busy\") return { status: currentStatus, syncedBeforeRead: false, failure: \"busy\" };\n currentStatus = await handle.status();\n return { status: currentStatus, syncedBeforeRead: true };\n }\n return { status: currentStatus, syncedBeforeRead: false };\n }\n\n function readEvent(op: \"get\" | \"list\", path: string, prefix: string | null, source: \"replica\" | \"network\" | \"none\", reason: ReplicationReason, outcome: \"found\" | \"not_found\" | \"error\", started: number, extra: Partial<Extract<ReplicationEvent, { type: \"replication.read\" }>> = {}): void {\n if (prefix !== null && reason === \"grant_expired\" && extra.code !== \"CONSENT_EXPIRED\") reportGrantExpiry(prefix);\n emit({ type: \"replication.read\", op, space: session.space, key: path, replica: prefix, source, reason, outcome, latencyMs: scheduler.now() - started, stalenessMs: null, coverage: null, authority: null, ...extra });\n }\n async function networkRead<T>(\n network: () => Promise<Result<T>>, op: \"get\" | \"list\", path: string, prefix: string | null,\n reason: ReplicationReason, started: number,\n extra: Partial<Extract<ReplicationEvent, { type: \"replication.read\" }>> = {},\n ): Promise<Result<T>> {\n let outcome: \"found\" | \"not_found\" | \"error\" = \"error\";\n try {\n const result = await network();\n outcome = result.ok ? \"found\" : op === \"get\" && (reason === \"pending_write\" || reason === \"not_covered\") && result.error.code === ErrorCodes.KV_NOT_FOUND ? \"not_found\" : \"error\";\n return result;\n } finally {\n readEvent(op, path, prefix, \"network\", reason, outcome, started, extra);\n }\n }\n async function verifyGet<T>(\n r: { space: string; path: string; signal: AbortSignal; network: () => Promise<Result<KVResponse<T>>> },\n local: Result<KVResponse<T>>,\n reason: ReplicationReason,\n started: number,\n extra: Partial<Extract<ReplicationEvent, { type: \"replication.read\" }>>,\n ): Promise<Result<KVResponse<T>>> {\n const prefix = configuredPrefix(r.path) ?? null;\n const localFound = local.ok;\n const localNotFound = !local.ok && local.error.code === ErrorCodes.KV_NOT_FOUND;\n const outcome = localFound ? \"found\" : localNotFound ? \"not_found\" : \"error\";\n try {\n const network = await raceSignal(r.network(), r.signal);\n if (r.signal.aborted) {\n readEvent(\"get\", r.path, prefix, \"none\", \"aborted\", \"error\", started, { ...extra, verify: \"aborted\" });\n return abortedResult(r.signal);\n }\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") {\n readEvent(\"get\", r.path, prefix, \"network\", delivery.status === \"consent_expired\" ? \"grant_expired\" : \"replica_gated\", network.ok ? \"found\" : \"error\", started, { code: delivery.status === \"consent_expired\" ? delivery.code : \"REPLICA_GATED\" });\n return network;\n }\n const refusal = prefix === null ? undefined : sessionRefusal(prefix);\n if (refusal) {\n readEvent(\"get\", r.path, prefix, \"network\", \"grant_missing\", network.ok ? \"found\" : \"error\", started, { code: refusal });\n return network;\n }\n if (!network.ok && network.error.code !== ErrorCodes.KV_NOT_FOUND) {\n readEvent(\"get\", r.path, prefix, \"replica\", reason, outcome, started, { ...extra, code: network.error.code, verify: \"error\" });\n return local;\n }\n const networkFound = network.ok;\n const networkNotFound = !network.ok && network.error.code === ErrorCodes.KV_NOT_FOUND;\n const localEtag = local.ok ? local.data.headers.etag ?? null : null;\n const networkEtag = network.ok ? network.data.headers.etag ?? null : null;\n const matches = localFound && networkFound ? localEtag === networkEtag : localNotFound && networkNotFound;\n const verify = matches ? \"match\" : \"diverged\";\n if (!matches) {\n emit({\n type: \"replication.divergence\",\n op: \"get\",\n space: r.space,\n key: r.path,\n replica: prefix ?? \"\",\n kind: localFound && networkFound ? \"value\" : localNotFound ? \"missing_local\" : \"extra_local\",\n localEtag,\n networkEtag,\n stalenessMs: typeof extra.stalenessMs === \"number\" ? extra.stalenessMs : null,\n });\n }\n readEvent(\"get\", r.path, prefix, \"replica\", reason, outcome, started, { ...extra, verify });\n return local;\n } catch (error) {\n if (r.signal.aborted) {\n readEvent(\"get\", r.path, prefix, \"none\", \"aborted\", \"error\", started, { ...extra, verify: \"aborted\" });\n return abortedResult(r.signal);\n }\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") {\n readEvent(\"get\", r.path, prefix, \"network\", delivery.status === \"consent_expired\" ? \"grant_expired\" : \"replica_gated\", \"error\", started, { code: delivery.status === \"consent_expired\" ? delivery.code : \"REPLICA_GATED\" });\n return err(wrapError(\"kv\", error));\n }\n const refusal = prefix === null ? undefined : sessionRefusal(prefix);\n if (refusal) {\n readEvent(\"get\", r.path, prefix, \"network\", \"grant_missing\", \"error\", started, { code: refusal });\n return err(wrapError(\"kv\", error));\n }\n readEvent(\"get\", r.path, prefix, \"replica\", reason, outcome, started, { ...extra, code: errorCode(error), verify: \"error\" });\n return local;\n }\n }\n async function verifyList(\n r: { space: string; listPath: string; signal: AbortSignal; network: () => Promise<Result<KVListPage>> },\n local: KVListPage,\n started: number,\n extra: Partial<Extract<ReplicationEvent, { type: \"replication.read\" }>>,\n ): Promise<Result<KVListPage>> {\n const prefix = listPathCovered(options.prefixes, r.listPath) ?? null;\n try {\n const network = await raceSignal(r.network(), r.signal);\n if (r.signal.aborted) {\n readEvent(\"list\", r.listPath, prefix, \"none\", \"aborted\", \"error\", started, { ...extra, verify: \"aborted\" });\n return abortedResult(r.signal);\n }\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") {\n readEvent(\"list\", r.listPath, prefix, \"network\", delivery.status === \"consent_expired\" ? \"grant_expired\" : \"replica_gated\", network.ok ? \"found\" : \"error\", started, { code: delivery.status === \"consent_expired\" ? delivery.code : \"REPLICA_GATED\" });\n return network;\n }\n const refusal = prefix === null ? undefined : sessionRefusal(prefix);\n if (refusal) {\n readEvent(\"list\", r.listPath, prefix, \"network\", \"grant_missing\", network.ok ? \"found\" : \"error\", started, { code: refusal });\n return network;\n }\n if (!network.ok) {\n readEvent(\"list\", r.listPath, prefix, \"replica\", \"hit\", \"found\", started, { ...extra, code: network.error.code, verify: \"error\" });\n return ok(local);\n }\n const localSet = new Set(local.keys);\n const networkSet = new Set(network.data.keys);\n const localOnly = local.keys.filter((key) => !networkSet.has(key));\n const networkOnly = network.data.keys.filter((key) => !localSet.has(key));\n const sameKeys = localOnly.length === 0 && networkOnly.length === 0;\n const sameOrder = sameKeys && local.keys.every((key, index) => key === network.data.keys[index]);\n const verify = sameOrder ? \"match\" : \"diverged\";\n if (!sameKeys || !sameOrder) {\n emit({\n type: \"replication.divergence\",\n op: \"list\",\n space: r.space,\n key: r.listPath,\n replica: prefix ?? \"\",\n kind: sameKeys ? \"order\" : \"keys\",\n ...(!sameKeys ? { localOnly, networkOnly } : {}),\n stalenessMs: typeof extra.stalenessMs === \"number\" ? extra.stalenessMs : null,\n });\n }\n readEvent(\"list\", r.listPath, prefix, \"replica\", \"hit\", \"found\", started, { ...extra, verify });\n return ok(local);\n } catch (error) {\n if (r.signal.aborted) {\n readEvent(\"list\", r.listPath, prefix, \"none\", \"aborted\", \"error\", started, { ...extra, verify: \"aborted\" });\n return abortedResult(r.signal);\n }\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") {\n readEvent(\"list\", r.listPath, prefix, \"network\", delivery.status === \"consent_expired\" ? \"grant_expired\" : \"replica_gated\", \"error\", started, { code: delivery.status === \"consent_expired\" ? delivery.code : \"REPLICA_GATED\" });\n return err(wrapError(\"kv\", error));\n }\n const refusal = prefix === null ? undefined : sessionRefusal(prefix);\n if (refusal) {\n readEvent(\"list\", r.listPath, prefix, \"network\", \"grant_missing\", \"error\", started, { code: refusal });\n return err(wrapError(\"kv\", error));\n }\n readEvent(\"list\", r.listPath, prefix, \"replica\", \"hit\", \"found\", started, { ...extra, code: errorCode(error), verify: \"error\" });\n return ok(local);\n }\n }\n async function reportExistingPins(): Promise<void> {\n if (pinnedStateReported) return;\n pinnedStateReported = true;\n try {\n const records = await pending.read();\n const pins = pinnedKeys(records, \"\", scheduler.now());\n if (pins.length > 0) emit({ type: \"replication.state\", space: session.space, state: \"pinned\", count: pins.length, keys: pins.map((pin) => pin.key) });\n } catch { emit({ type: \"replication.state\", space: session.space, state: \"pending_store_error\", code: \"STORAGE_ERROR\" }); }\n }\n\n async function get<T>(r: { space: string; key: string; path: string; options: KVGetOptions | undefined; signal: AbortSignal; network: () => Promise<Result<KVResponse<T>>> }): Promise<Result<KVResponse<T>>> {\n const started = scheduler.now();\n const prefix = configuredPrefix(r.path);\n if (r.options?.source === \"network\") {\n let outcome: \"found\" | \"not_found\" | \"error\" = \"error\";\n try {\n const value = await r.network();\n outcome = value.ok ? \"found\" : value.error.code === ErrorCodes.KV_NOT_FOUND ? \"not_found\" : \"error\";\n return value;\n } finally {\n observeNetworkRequested({ op: \"get\", space: r.space, path: r.path, reason: \"NETWORK_REQUESTED\", outcome, latencyMs: scheduler.now() - started });\n }\n }\n let networkRejected = false;\n const fallback = async (\n replica: string, reason: ReplicationReason,\n extra: Partial<Extract<ReplicationEvent, { type: \"replication.read\" }>> = {},\n ) => {\n try { return await networkRead(r.network, \"get\", r.path, replica, reason, started, extra); }\n catch (error) { networkRejected = true; throw error; }\n };\n if (prefix === undefined) return networkRead(r.network, \"get\", r.path, null, \"not_covered\", started);\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") {\n return fallback(prefix, delivery.status === \"consent_expired\" ? \"grant_expired\" : \"replica_gated\",\n { code: delivery.status === \"consent_expired\" ? delivery.code : \"REPLICA_GATED\" });\n }\n const refusal = sessionRefusal(prefix);\n if (refusal) return fallback(prefix, \"grant_missing\", { code: refusal });\n try { await raceSignal(reportExistingPins(), r.signal); } catch { if (r.signal.aborted) return abortedResult(r.signal); }\n let handle: KVReplicaHandle;\n try { handle = await raceSignal(open(prefix), r.signal); }\n catch (error) {\n if (r.signal.aborted) return abortedResult(r.signal);\n if (errorCode(error) === \"CONSENT_EXPIRED\") startConsentDenial();\n const code = errorCode(error);\n return fallback(prefix, code === \"RUNTIME_UNSUPPORTED\" ? \"runtime_unsupported\" : code === \"CONSENT_EXPIRED\" || code === \"REPLICA_GATED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"replica_unavailable\", { code });\n }\n if (replicas.get(prefix)?.reason === \"grant_missing\") {\n const code = replicas.get(prefix)?.lastError;\n return fallback(prefix, code === \"GRANT_EXPIRED\" ? \"grant_expired\" : code === \"REPLICA_GATED\" ? \"replica_gated\" : \"grant_missing\", { code });\n }\n\n let fresh: Awaited<ReturnType<typeof freshness>>;\n try { fresh = await freshness(prefix, handle, r.signal); }\n catch (error) {\n recordRevocation(prefix, error);\n if (errorCode(error) === \"CONSENT_EXPIRED\") startConsentDenial();\n if (r.signal.aborted) return abortedResult(r.signal);\n const code = errorCode(error);\n return fallback(prefix, code === \"CONSENT_EXPIRED\" || code === \"REPLICA_GATED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"replica_error\", { code });\n }\n if (r.signal.aborted) return abortedResult(r.signal);\n if (fresh.failure) {\n const code = fresh.failure === \"busy\" ? \"REPLICA_BUSY\" : fresh.syncError;\n return fallback(prefix, code === \"GRANT_REVOKED\" ? \"grant_revoked\" : code === \"REPLICA_GATED\" || code === \"CONSENT_EXPIRED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"stale\",\n { code, syncedBeforeRead: fresh.syncedBeforeRead });\n }\n let pendingState: PendingWriteState;\n try { pendingState = await raceSignal(pending.read(), r.signal); }\n catch (error) {\n if (r.signal.aborted) return abortedResult(r.signal);\n const code = errorCode(error);\n return fallback(prefix, code === \"REPLICA_GATED\" || code === \"CONSENT_EXPIRED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"replica_unavailable\", { code });\n }\n const record = pendingState.records.find((x) => x.key === r.path);\n if (record) return fallback(prefix, \"pending_write\", { pendingState: record.state, syncedBeforeRead: fresh.syncedBeforeRead });\n if (!pending.durable && !inProcessProof.has(prefix)) return fallback(prefix, \"REPLICA_UNPROVEN_SINCE_START\");\n if (fresh.status.syncedThroughEpoch < pendingState.committedEpoch) return fallback(prefix, \"REPLICA_BEHIND_OWN_WRITES\");\n if (fresh.status.authority.state !== \"valid\") return fallback(prefix, fresh.status.authority.state === \"expired\" ? \"grant_expired\" : fresh.status.authority.state === \"revoked\" ? \"grant_revoked\" : \"grant_not_yet_valid\");\n if (fresh.status.coverage !== \"complete\") return fallback(prefix, \"coverage_incomplete\");\n try {\n const local = await raceSignal(handle.get(r.path), r.signal);\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") throw deliveryError(delivery);\n const refusal = sessionRefusal(prefix);\n if (refusal) return await fallback(prefix, \"grant_missing\", { code: refusal });\n try { validateReadMeta(local.meta); }\n catch (error) {\n const code = errorCode(error);\n recordRevocation(prefix, error);\n return await fallback(prefix, reasonForReadMetaCode(code), { code });\n }\n if (local.status === \"coverage_incomplete\" || local.status === \"not_covered\" || local.status === \"content_missing\") return await fallback(prefix, local.status === \"content_missing\" ? \"content_missing\" : local.status === \"coverage_incomplete\" ? \"coverage_incomplete\" : \"not_covered\");\n if (local.status === \"present\" && r.options?.maxResponseBytes !== undefined && local.value.byteLength > r.options.maxResponseBytes) {\n return await fallback(prefix, \"unsupported_option\");\n }\n const result = localGet<T>(local as LocalGetResult, r.path, r.options ?? {});\n const reason = local.status === \"present\" ? \"hit\" : local.status;\n const syncedAt = fresh.status.lastSyncAt === null ? null : Date.parse(fresh.status.lastSyncAt);\n const event = {\n syncedBeforeRead: fresh.syncedBeforeRead,\n coverage: local.meta.coverage,\n authority: local.meta.authority,\n stalenessMs: syncedAt === null ? null : scheduler.now() - syncedAt,\n ...(fresh.syncError ? { syncError: fresh.syncError } : {}),\n };\n if (options.verify) return await verifyGet(r, result as Result<KVResponse<T>>, reason, started, event);\n readEvent(\"get\", r.path, prefix, \"replica\", reason, result.ok ? \"found\" : result.error.code === ErrorCodes.KV_NOT_FOUND ? \"not_found\" : \"error\", started, event);\n return result as LocalGetResponse<T>;\n } catch (error) {\n if (networkRejected) throw error;\n recordRevocation(prefix, error);\n if (errorCode(error) === \"CONSENT_EXPIRED\") startConsentDenial();\n if (r.signal.aborted) return abortedResult(r.signal);\n return fallback(prefix, deliveryReason(errorCode(error)), { code: errorCode(error) });\n }\n }\n\n async function list(r: { space: string; listPath: string; options: KVListOptions | undefined; signal: AbortSignal; network: () => Promise<Result<KVListPage>> }): Promise<Result<KVListPage>> {\n const started = scheduler.now();\n if (r.options?.source === \"network\") {\n let outcome: \"found\" | \"not_found\" | \"error\" = \"error\";\n try {\n const result = await r.network();\n outcome = result.ok ? \"found\" : \"error\";\n return result;\n } finally {\n observeNetworkRequested({ op: \"list\", space: r.space, path: r.listPath, reason: \"NETWORK_REQUESTED\", outcome, latencyMs: scheduler.now() - started });\n }\n }\n const cursor = r.options?.cursor;\n const decoded = cursor?.startsWith(\"tcr1.\") ? decodeTcr1(cursor) : null;\n if (cursor && cursor.startsWith(\"tcr1.\") && !decoded) { readEvent(\"list\", r.listPath, null, \"none\", \"cursor_restart\", \"error\", started); return cursorRestart(); }\n if (cursor && !cursor.startsWith(\"tcr1.\")) return networkRead(r.network, \"list\", r.listPath, null, \"network_cursor\", started);\n const prefix = listPathCovered(options.prefixes, r.listPath);\n let networkRejected = false;\n const fallback = async (\n replica: string, reason: ReplicationReason,\n extra: Partial<Extract<ReplicationEvent, { type: \"replication.read\" }>> = {},\n ) => {\n try { return await networkRead(r.network, \"list\", r.listPath, replica, reason, started, extra); }\n catch (error) { networkRejected = true; throw error; }\n };\n if (prefix !== undefined && !r.options?.raw) {\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") {\n if (decoded) { readEvent(\"list\", r.listPath, prefix, \"none\", \"cursor_restart\", \"error\", started); return cursorRestart(); }\n return fallback(prefix, delivery.status === \"consent_expired\" ? \"grant_expired\" : \"replica_gated\",\n { code: delivery.status === \"consent_expired\" ? delivery.code : \"REPLICA_GATED\" });\n }\n }\n if (prefix !== undefined && !r.options?.raw) {\n const refusal = sessionRefusal(prefix);\n if (refusal) {\n if (decoded) { readEvent(\"list\", r.listPath, prefix, \"none\", \"cursor_restart\", \"error\", started); return cursorRestart(); }\n return fallback(prefix, \"grant_missing\", { code: refusal });\n }\n }\n try { await raceSignal(reportExistingPins(), r.signal); } catch { if (r.signal.aborted) return abortedResult(r.signal); }\n const restart = () => { readEvent(\"list\", r.listPath, prefix ?? null, \"none\", \"cursor_restart\", \"error\", started); return cursorRestart(); };\n if (cursor && decoded && (decoded.space !== r.space || decoded.path !== r.listPath)) return restart();\n if (prefix === undefined || r.options?.raw) { if (cursor && decoded) return restart(); return networkRead(r.network, \"list\", r.listPath, prefix ?? null, prefix !== undefined ? \"unsupported_option\" : \"not_covered\", started); }\n let handle: KVReplicaHandle;\n try { handle = await raceSignal(open(prefix), r.signal); }\n catch (error) {\n if (r.signal.aborted) return abortedResult(r.signal);\n if (errorCode(error) === \"CONSENT_EXPIRED\") startConsentDenial();\n if (cursor && decoded) return restart();\n const code = errorCode(error);\n return fallback(prefix, code === \"RUNTIME_UNSUPPORTED\" ? \"runtime_unsupported\" : code === \"CONSENT_EXPIRED\" || code === \"REPLICA_GATED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"replica_unavailable\", { code });\n }\n if (replicas.get(prefix)?.reason === \"grant_missing\") {\n if (cursor && decoded) return restart();\n const code = replicas.get(prefix)?.lastError;\n return fallback(prefix, code === \"GRANT_EXPIRED\" ? \"grant_expired\" : code === \"REPLICA_GATED\" ? \"replica_gated\" : \"grant_missing\", { code });\n }\n let fresh: Awaited<ReturnType<typeof freshness>>;\n try { fresh = await freshness(prefix, handle, r.signal); }\n catch (error) {\n recordRevocation(prefix, error);\n if (errorCode(error) === \"CONSENT_EXPIRED\") startConsentDenial();\n if (r.signal.aborted) return abortedResult(r.signal);\n if (cursor && decoded) return restart();\n const code = errorCode(error);\n return fallback(prefix, code === \"CONSENT_EXPIRED\" || code === \"REPLICA_GATED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"replica_error\", { code });\n }\n if (r.signal.aborted) return abortedResult(r.signal);\n let state: PendingWriteState;\n try { state = await raceSignal(pending.read(), r.signal); }\n catch (error) {\n if (r.signal.aborted) return abortedResult(r.signal);\n if (cursor && decoded) return restart();\n const code = errorCode(error);\n return fallback(prefix, code === \"REPLICA_GATED\" || code === \"CONSENT_EXPIRED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"replica_unavailable\", { code });\n }\n const pendingRange = state.records.find((record) => listRangeCovers(r.listPath, record.key));\n const behind = fresh.status.syncedThroughEpoch < state.committedEpoch;\n if (cursor && decoded && (fresh.failure || pendingRange || behind || fresh.status.coverage !== \"complete\" || fresh.status.authority.state !== \"valid\" || (!pending.durable && !inProcessProof.has(prefix)))) return restart();\n if (behind) return fallback(prefix, \"REPLICA_BEHIND_OWN_WRITES\");\n if (fresh.failure) {\n const code = fresh.failure === \"busy\" ? \"REPLICA_BUSY\" : fresh.syncError;\n return fallback(prefix, code === \"GRANT_REVOKED\" ? \"grant_revoked\" : code === \"REPLICA_GATED\" || code === \"CONSENT_EXPIRED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : \"stale\", { code });\n }\n if (pendingRange) return fallback(prefix, \"pending_write\", { pendingState: pendingRange.state });\n if (!pending.durable && !inProcessProof.has(prefix)) return fallback(prefix, \"REPLICA_UNPROVEN_SINCE_START\");\n if (fresh.status.coverage !== \"complete\" || fresh.status.authority.state !== \"valid\") return fallback(prefix, fresh.status.coverage !== \"complete\" ? \"coverage_incomplete\" : fresh.status.authority.state === \"expired\" ? \"grant_expired\" : fresh.status.authority.state === \"revoked\" ? \"grant_revoked\" : \"grant_not_yet_valid\");\n try {\n const signalHandle = { list: (o: { prefix: string; after?: string; limit?: number }) => raceSignal(handle.list(o), r.signal) };\n const page = await raceSignal(localList(signalHandle, r.space, r.listPath, r.options?.limit, cursor, validateReadMeta), r.signal);\n const latest = await raceSignal(pending.read(), r.signal);\n const laterPending = latest.records.find((record) => listRangeCovers(r.listPath, record.key));\n if (cursor && decoded && (laterPending || fresh.status.syncedThroughEpoch < latest.committedEpoch)) return restart();\n if (fresh.status.syncedThroughEpoch < latest.committedEpoch) return await fallback(prefix, \"REPLICA_BEHIND_OWN_WRITES\");\n if (laterPending) return await fallback(prefix, \"pending_write\", { pendingState: laterPending.state });\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") throw deliveryError(delivery);\n const refusal = sessionRefusal(prefix);\n if (refusal) {\n if (decoded) return restart();\n return await fallback(prefix, \"grant_missing\", { code: refusal });\n }\n const event = {\n count: page.keys.length,\n syncedBeforeRead: fresh.syncedBeforeRead,\n stalenessMs: fresh.status.lastSyncAt === null ? null : scheduler.now() - Date.parse(fresh.status.lastSyncAt),\n ...(fresh.syncError ? { syncError: fresh.syncError } : {}),\n };\n if (options.verify && !cursor) return await verifyList(r, page, started, event);\n readEvent(\"list\", r.listPath, prefix, \"replica\", \"hit\", \"found\", started, event);\n return ok(page);\n } catch (error) {\n if (networkRejected) throw error;\n if (r.signal.aborted) return abortedResult(r.signal);\n const code = errorCode(error);\n if (code === \"CONSENT_EXPIRED\") startConsentDenial();\n recordRevocation(prefix, error);\n if (cursor && decoded) return restart();\n const reason = code === \"CONSENT_EXPIRED\" || code === \"REPLICA_GATED\" || code === \"GRANT_EXPIRED\" ? deliveryReason(code) : reasonForReadMetaCode(code);\n return fallback(prefix, reason, { code });\n }\n }\n\n async function write<T>(r: { op: \"put\" | \"delete\" | \"batchPut\"; space: string; entries: ReadonlyArray<{ path: string; body?: Blob | string }>; signal: AbortSignal; conditional?: boolean; network: () => Promise<Result<T>> }): Promise<Result<T>> {\n const covered = r.entries.flatMap((entry) => {\n const prefix = configuredPrefix(entry.path);\n return prefix !== undefined ? [{ key: entry.path, op: r.op === \"delete\" ? \"delete\" as const : \"put\" as const }] : [];\n });\n if (covered.length === 0) return r.network();\n if (checkDelivery().status !== \"allow\") return r.network();\n await reportExistingPins();\n if (checkDelivery().status !== \"allow\") return r.network();\n const opId = globalThis.crypto?.randomUUID?.() ?? `${scheduler.now()}-${Math.random()}`;\n try { await pending.update((s) => begin(s, opId, covered, nowDate(scheduler.now()))); }\n catch (error) {\n if (errorCode(error) === \"REPLICA_GATED\" || errorCode(error) === \"CONSENT_EXPIRED\" || checkDelivery().status !== \"allow\") return r.network();\n return err(serviceError(ErrorCodes.KV_WRITE_FAILED, \"Unable to persist pending KV write; request was not dispatched\", \"kv\", { cause: error instanceof Error ? error : undefined, meta: { replication: \"pending_store_unavailable\", requestDispatched: false } }));\n }\n const started = scheduler.now();\n let result: Result<T>;\n try { result = await r.network(); }\n catch (error) {\n const wrapped = wrapError(\"kv\", error);\n result = err({\n ...wrapped,\n meta: { ...wrapped.meta, requestMayHaveDispatched: true },\n });\n }\n const outcome = classifyWriteOutcome(r.op, result, { conditional: r.conditional === true });\n let settleError: unknown;\n try { await pending.update((s) => settle(s, opId, outcome, nowDate(scheduler.now()), result.ok ? undefined : result.error.code)); } catch (error) { settleError = error; }\n emit({ type: \"replication.write\", space: r.space, op: r.op, keys: covered.map((x) => x.key), outcome, ...(!result.ok ? { code: result.error.code } : {}), latencyMs: scheduler.now() - started });\n const state = await pending.read().catch(() => undefined);\n const pins = state ? pinnedKeys(state, \"\", scheduler.now()) : [];\n if (outcome === \"ambiguous\") emit({ type: \"replication.state\", space: r.space, state: \"pinned\", count: pins.length, keys: pins.map((p) => p.key) });\n if (settleError) emit({ type: \"replication.state\", space: r.space, state: \"pending_store_error\", code: \"STORAGE_ERROR\" });\n return result;\n }\n\n function observeNetworkRequested(r: { op: \"get\" | \"list\"; space: string; path: string; reason: \"NETWORK_REQUESTED\"; outcome: \"found\" | \"not_found\" | \"error\"; latencyMs: number }): void {\n emit({ type: \"replication.read\", op: r.op, space: r.space, key: r.path, replica: null, source: \"network\", reason: \"NETWORK_REQUESTED\", outcome: r.outcome, latencyMs: r.latencyMs, stalenessMs: null, coverage: null, authority: null });\n }\n\n async function inspectPersistedStatus(prefix: string): Promise<InspectedStatusResult> {\n if (!storage.inspectStatus || isClosed || purgeInProgress) return { missing: false };\n const sessionGrant = authority.sessionGrant(prefix);\n const device = \"refused\" in sessionGrant ? undefined : sessionGrant.device;\n const spec = { identity, space: session.space, prefix, allowSecrets: options.allowSecrets, ...(device ? { device } : {}), ...(deps.fetch ? { fetch: deps.fetch } : {}) };\n const abort = new AbortController();\n const job = Promise.resolve().then(() => storage.inspectStatus!(spec, { signal: abort.signal }));\n const settled = job.then(() => undefined, () => undefined);\n const inspection = { abort, settled };\n statusInspections.add(inspection);\n void settled.then(() => statusInspections.delete(inspection));\n let cancel = () => {};\n const timeout = new Promise<{ timedOut: true }>((resolve) => {\n cancel = scheduler.setTimeout(() => {\n abort.abort(Object.assign(new Error(\"Replica status inspection timed out\"), { code: \"STATUS_TIMEOUT\" }));\n resolve({ timedOut: true });\n }, STATUS_REFRESH_TIMEOUT_MS);\n });\n try {\n const result = await Promise.race([job.then((local) => ({ local })), timeout]);\n if (\"timedOut\" in result) return { missing: false, errorCode: \"STATUS_TIMEOUT\" };\n return { missing: result.local === undefined, ...(result.local ? { local: result.local } : {}) };\n } catch (error) {\n return { missing: false, errorCode: errorCode(error) };\n } finally { cancel(); }\n }\n\n function cancelStatusInspections(): Promise<void> {\n const active = [...statusInspections];\n for (const inspection of active) inspection.abort.abort(Object.assign(new Error(\"Replica status inspection cancelled\"), { code: \"ABORTED\" }));\n return Promise.all(active.map((inspection) => inspection.settled)).then(() => undefined);\n }\n\n function gatedStatus(decision: Exclude<ReplicaDeliveryDecision, { status: \"allow\" }>): ReplicaStatusEntry[] {\n return options.prefixes.map((prefix) => ({\n prefix,\n state: \"gated\",\n reason: \"replica_gated\",\n gate: decision.status === \"gated\" ? decision.gate : \"stamp_stale\",\n errorCode: decision.status === \"consent_expired\" ? decision.code : \"REPLICA_GATED\",\n pending: { inFlight: 0, committed: 0, ambiguous: 0 },\n pinned: [],\n lagMs: null,\n redacted: true,\n }));\n }\n\n async function status(): Promise<ReplicaStatusEntry[]> {\n const beforeStatus = checkDelivery();\n if (beforeStatus.status !== \"allow\") return gatedStatus(beforeStatus);\n let persistedSnapshot: PendingWriteState | null | undefined;\n try {\n persistedSnapshot = pending.readExisting ? await pending.readExisting() : await pending.read();\n } catch (error) {\n const delivery = checkDelivery();\n if (delivery.status !== \"allow\") return gatedStatus(delivery);\n throw error;\n }\n const afterPending = checkDelivery();\n if (afterPending.status !== \"allow\") return gatedStatus(afterPending);\n const snapshot = persistedSnapshot ?? emptyPendingState(identity);\n const entries = await Promise.all(options.prefixes.map(async (prefix): Promise<ReplicaStatusEntry | undefined> => {\n if (prefix === \"/\" && deps.nodeFeatures !== undefined && !deps.nodeFeatures.includes(\"kv-sync-root\")) {\n markRootUnsupported(prefix);\n }\n const records = snapshot.records.filter((r) => kvPrefixCovers(prefix, r.key));\n const opened = replicas.get(prefix);\n let local: LocalReplicaStatus | ReplicaInspectedStatus | undefined;\n if (opened?.handle) {\n try { local = await opened.handle.status(); }\n catch { /* A generation-fenced or unavailable handle has no live status. */ }\n }\n let inspected: InspectedStatusResult = { missing: false };\n if (!local && !opened?.opening && !opened?.authorityRevoked) inspected = await inspectPersistedStatus(prefix);\n local ??= inspected.local;\n if (inspected.missing && !opened?.reason && !opened?.authorityRevoked && !opened?.opening && !isClosed) return undefined;\n const full = local && !(\"redacted\" in local) ? local : undefined;\n const revoked = opened?.authorityRevoked === true || full?.authority.state === \"revoked\";\n const rootUnsupported = opened?.lastError === \"REPLICATION_ROOT_UNSUPPORTED\";\n const state = isClosed ? \"closed\" as const : revoked ? \"revoked\" as const : rootUnsupported || opened?.reason === \"grant_expired\" ? \"unavailable\" as const : opened?.reason === \"grant_missing\" ? \"grant_missing\" as const : full?.coverage === \"complete\" && full.authority.state === \"valid\" ? \"ready\" as const : opened?.reason || inspected.errorCode ? \"unavailable\" as const : \"idle\" as const;\n return {\n prefix,\n state,\n ...(opened?.reason ? { reason: opened.reason } : inspected.errorCode ? { reason: \"replica_unavailable\" as const } : {}),\n ...(inspected.errorCode ?? opened?.lastError ? { errorCode: inspected.errorCode ?? opened?.lastError } : {}),\n ...(local ?? {}),\n ...(revoked ? { authority: { state: \"revoked\" as const, expiresAt: full?.authority.expiresAt ?? null } } : {}),\n pending: {\n inFlight: records.filter((r) => r.state === \"in_flight\").length,\n committed: records.filter((r) => r.state === \"committed\").length,\n ambiguous: records.filter((r) => r.state === \"ambiguous\").length,\n },\n pinned: pinnedKeys(snapshot, prefix, scheduler.now()),\n lagMs: full?.lastSyncAt ? scheduler.now() - Date.parse(full.lastSyncAt) : null,\n };\n }));\n const beforeReturn = checkDelivery();\n if (beforeReturn.status !== \"allow\") return gatedStatus(beforeReturn);\n return entries.filter((entry): entry is ReplicaStatusEntry => entry !== undefined);\n }\n\n async function sync(o?: { prefix?: string; signal?: AbortSignal }): Promise<void> {\n const prefixes = o?.prefix !== undefined ? options.prefixes.filter((p) => p === o.prefix) : options.prefixes;\n await Promise.all(prefixes.map((prefix) => syncPrefix(prefix, \"manual\", o?.signal).then(() => undefined)));\n }\n\n async function clearPending(): Promise<number> {\n const count = await pending.update((s) => clearPendingRecords(s, scheduler.now()));\n emit({ type: \"replication.state\", space: session.space, state: \"pending_cleared\", count });\n return count;\n }\n\n function purge(o?: { timeoutMs?: number }): Promise<{ purged: string[]; failed: Array<{ prefix: string; code: string }> }> {\n purgeStarted = true;\n purgeInProgress = true;\n cancelConsentTimer?.();\n cancelConsentTimer = undefined;\n const hasStatusInspections = statusInspections.size > 0;\n const statusDrain = cancelStatusInspections();\n for (const state of replicas.values()) {\n state.timer?.();\n state.timer = undefined;\n state.renewalTimer?.();\n state.renewalTimer = undefined;\n state.syncContext && (state.syncContext.abortCause ??= \"purge\");\n state.abort?.abort();\n state.mintAbort?.abort();\n }\n return Promise.resolve().then(async () => {\n const report = { purged: [] as string[], failed: [] as Array<{ prefix: string; code: string }> };\n const timeoutMs = o?.timeoutMs ?? 5_000;\n const withTimeout = async <T>(job: Promise<T>): Promise<T> => {\n let cancel = () => {};\n const timeout = new Promise<never>((_, reject) => {\n cancel = scheduler.setTimeout(() => reject(Object.assign(new Error(\"Replication cleanup timed out\"), { code: \"TIMEOUT\" })), timeoutMs);\n });\n try { return await Promise.race([job, timeout]); }\n finally { cancel(); }\n };\n const drain = Promise.all([\n ...[...replicas.values()].flatMap((state) => [\n state.opening?.catch(() => undefined),\n state.sync?.catch(() => undefined),\n state.renewing?.catch(() => undefined),\n state.handle?.close().catch(() => undefined),\n ]),\n ...(hasStatusInspections ? [statusDrain] : []),\n ]);\n let drainCode: string | undefined;\n try { await withTimeout(drain); } catch (error) { drainCode = errorCode(error); }\n const jobs = options.prefixes.map(async (prefix) => {\n try {\n if (drainCode) throw Object.assign(new Error(\"Replica cleanup did not settle before purge\"), { code: drainCode });\n const grant = authority.sessionGrant(prefix);\n const sessionDeviceDid = replicas.get(prefix)?.handle?.deviceDid ?? (\"refused\" in grant ? undefined : grant.device.did);\n await withTimeout(storage.purge({ identity, space: session.space, prefix, ...(sessionDeviceDid ? { sessionDeviceDid } : {}) }));\n await pending.update((s) => clearPrefix(s, prefix));\n replicas.delete(prefix);\n inProcessProof.delete(prefix);\n report.purged.push(prefix);\n emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"purged\" });\n } catch (error) {\n const code = errorCode(error);\n report.failed.push({ prefix, code });\n emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"purge_failed\", code });\n }\n });\n await Promise.all(jobs);\n return report;\n }).finally(() => { purgeInProgress = false; });\n }\n\n async function close(): Promise<void> {\n if (isClosed) return;\n isClosed = true;\n cancelConsentTimer?.();\n cancelConsentTimer = undefined;\n const hasStatusInspections = statusInspections.size > 0;\n const statusDrain = cancelStatusInspections();\n for (const [prefix, state] of replicas) {\n state.timer?.();\n state.timer = undefined;\n state.renewalTimer?.();\n state.renewalTimer = undefined;\n state.mintAbort?.abort();\n state.syncContext && (state.syncContext.abortCause ??= \"close\");\n state.abort?.abort();\n emit({ type: \"replication.state\", space: session.space, replica: prefix, state: \"closed\" });\n }\n const drain = Promise.all([\n ...[...replicas.values()].map(async (state) => {\n await state.opening?.catch(() => undefined);\n await state.renewing?.catch(() => undefined);\n await state.sync?.catch(() => undefined);\n await state.handle?.close().catch(() => undefined);\n }),\n ...(hasStatusInspections ? [statusDrain] : []),\n ]);\n let cancel = () => {};\n let drained = false;\n void drain.then(\n () => { drained = true; cancel(); },\n () => { drained = true; cancel(); },\n );\n const timeout = new Promise<void>((resolve) => {\n queueMicrotask(() => {\n if (!drained) cancel = scheduler.setTimeout(resolve, CLOSE_TIMEOUT_MS);\n });\n });\n\n try { await Promise.race([drain, timeout]); }\n finally { cancel(); }\n }\n\n scheduleConsentDeadline();\n return { get, list, write, observeNetworkRequested, observeConsentExpired, status, sync, purge, clearPending, close };\n}\n\nfunction cancellationCode(signal: AbortSignal): string {\n return wrapError(\"kv\", signal.reason).code === ErrorCodes.TIMEOUT ||\n (typeof signal.reason === \"object\" && signal.reason !== null && \"code\" in signal.reason && signal.reason.code === ErrorCodes.TIMEOUT)\n ? ErrorCodes.TIMEOUT\n : ErrorCodes.ABORTED;\n}\n\nfunction abortedResult(signal: AbortSignal): Result<never> {\n const code = cancellationCode(signal);\n return err(serviceError(code, code === ErrorCodes.TIMEOUT ? \"KV request timed out\" : \"KV request was aborted\", \"kv\"));\n}\n","import { canonicalReplicationIdentity, replicationIdentityKey } from \"./identity\";\nimport { emptyPendingState } from \"./pendingWrites\";\nimport type { PendingWriteState, PendingWriteStore, ReplicationIdentity } from \"./types\";\n\nexport function createMemoryPendingStore(identity: ReplicationIdentity): PendingWriteStore {\n const canonical = canonicalReplicationIdentity(identity);\n const key = replicationIdentityKey(canonical);\n let state = emptyPendingState(canonical);\n let tail: Promise<void> = Promise.resolve();\n return {\n identity: canonical,\n durable: false,\n async read(): Promise<PendingWriteState> { return structuredClone(state); },\n async update<T>(mutate: (s: PendingWriteState) => T): Promise<T> {\n let resolve!: (value: T) => void;\n let reject!: (reason: unknown) => void;\n const result = new Promise<T>((res, rej) => { resolve = res; reject = rej; });\n const operation = tail.then(() => {\n try {\n if (replicationIdentityKey(state.identity) !== key) throw Object.assign(new Error(\"Pending-store identity mismatch\"), { code: \"STORAGE_ERROR\" });\n const next = structuredClone(state);\n const value = mutate(next);\n state = next;\n resolve(value);\n } catch (error) { reject(error); }\n });\n tail = operation.then(() => undefined, () => undefined);\n return result;\n },\n };\n}\n","/**\n * Typed replica errors. Every failure a caller can act on has its own code;\n * hosts (CLI, worker) map codes to their own exit codes or UI states.\n */\nexport const ReplicaErrorCode = {\n /** Another process holds the sync lease. */\n BUSY: \"REPLICA_BUSY\",\n /** No replica with this name exists. */\n NOT_FOUND: \"REPLICA_NOT_FOUND\",\n /** The replica exists but its stored configuration differs from the request. */\n CONFIG_MISMATCH: \"REPLICA_CONFIG_MISMATCH\",\n /** The runtime has no supported durable store (e.g. Node < 22.13). */\n RUNTIME_UNSUPPORTED: \"RUNTIME_UNSUPPORTED\",\n /** A required open() argument is missing or malformed (e.g. `principal`). */\n INVALID_ARGUMENT: \"REPLICA_INVALID_ARGUMENT\",\n /** The local store failed (I/O, corruption, schema). */\n STORAGE_ERROR: \"STORAGE_ERROR\",\n /** The local disk is full. */\n STORAGE_FULL: \"STORAGE_FULL\",\n /** The key is outside the replica's prefix. */\n NOT_COVERED: \"NOT_COVERED\",\n /** Syncing the secrets space or the vault namespace needs an explicit opt-in. */\n SECRETS_OPT_IN_REQUIRED: \"SECRETS_OPT_IN_REQUIRED\",\n /** No grant is installed, or none covers the requested scope. */\n GRANT_MISSING: \"GRANT_MISSING\",\n /** The grant bytes are not a verifiable UCAN, or its signature is wrong. */\n GRANT_INVALID: \"GRANT_INVALID\",\n /** SIWE/CACAO and other non-UCAN grants cannot be used for a replica. */\n GRANT_FORMAT_UNSUPPORTED: \"GRANT_FORMAT_UNSUPPORTED\",\n /** The grant was issued to a different device. */\n GRANT_AUDIENCE_MISMATCH: \"GRANT_AUDIENCE_MISMATCH\",\n /** The grant lacks `tinycloud.kv/sync` or `tinycloud.kv/get` on the prefix. */\n GRANT_NOT_COVERING: \"GRANT_NOT_COVERING\",\n GRANT_NOT_YET_VALID: \"GRANT_NOT_YET_VALID\",\n GRANT_EXPIRED: \"GRANT_EXPIRED\",\n /** The configured node does not advertise whole-space KV sync support. */\n REPLICATION_ROOT_UNSUPPORTED: \"REPLICATION_ROOT_UNSUPPORTED\",\n GRANT_REVOKED: \"GRANT_REVOKED\",\n /** The node refused the invocation for a reason other than revocation. */\n GRANT_UNAUTHORIZED: \"GRANT_UNAUTHORIZED\",\n /** The node refused the retention grant. */\n RETENTION_GRANT_REFUSED: \"RETENTION_GRANT_REFUSED\",\n /** The node could not be reached. */\n NETWORK_ERROR: \"NETWORK_ERROR\",\n /** The node answered with an unexpected status. */\n NODE_ERROR: \"NODE_ERROR\",\n /** The node's answer violates the wire contract. */\n PROTOCOL_ERROR: \"PROTOCOL_ERROR\",\n /** The node asked for a fresh bootstrap (410). Handled inside sync. */\n RESET_REQUIRED: \"RESET_REQUIRED\",\n /** The feed now comes from a different node than the one pinned. */\n SOURCE_CHANGED: \"SOURCE_CHANGED\",\n /** The feed delivered a key outside the replica's prefix. */\n SCOPE_VIOLATION: \"SCOPE_VIOLATION\",\n /** Fetched bytes do not hash to the ETag the node attested for them. */\n CONTENT_MISMATCH: \"CONTENT_MISMATCH\",\n /** A stored blob no longer hashes to its name. */\n INTEGRITY_ERROR: \"INTEGRITY_ERROR\",\n /** The replica handle was closed; in-flight calls settle with this code. */\n CLOSED: \"REPLICA_CLOSED\",\n /** The lifecycle gate refused the operation (shared contract `REPLICA_GATED`); `detail.gate` says why. */\n GATED: \"REPLICA_GATED\",\n /** Quota admission refused a page (`maxBytes` or the free-space floor); nothing committed. */\n STORAGE_BUDGET: \"STORAGE_BUDGET\",\n /** The consent deadline passed: the grant is not served until the user consents again. */\n CONSENT_EXPIRED: \"CONSENT_EXPIRED\",\n} as const;\n\nexport type ReplicaErrorCode = (typeof ReplicaErrorCode)[keyof typeof ReplicaErrorCode];\n\n/**\n * The package ships separate entry bundles (`.`, `./sqlite`), each with its own\n * copy of this class, so identity is a registered symbol, not `instanceof`.\n */\nconst REPLICA_ERROR = Symbol.for(\"tinycloud.replica.error\");\n\nexport class ReplicaError extends Error {\n readonly [REPLICA_ERROR] = true;\n readonly code: ReplicaErrorCode;\n readonly detail?: Record<string, unknown>;\n\n constructor(code: ReplicaErrorCode, message: string, detail?: Record<string, unknown>, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"ReplicaError\";\n this.code = code;\n if (detail !== undefined) this.detail = detail;\n }\n}\n\nexport function isReplicaError(error: unknown, code?: ReplicaErrorCode): error is ReplicaError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as { [REPLICA_ERROR]?: unknown })[REPLICA_ERROR] === true &&\n (code === undefined || (error as ReplicaError).code === code)\n );\n}\n\n/**\n * A lifecycle-gate refusal in the shared contract's shape:\n * `Error & { code: \"REPLICA_GATED\"; gate }`, with `gate` also in `detail`\n * so it survives the worker boundary.\n */\nexport function gatedError(gate: string, message: string): ReplicaError & { gate: string } {\n return Object.assign(new ReplicaError(ReplicaErrorCode.GATED, message, { gate }), { gate });\n}\n","/** Shared prefix boundary and configuration rules; no runtime dependencies. */\nexport function kvPrefixCovers(prefix: string, key: string): boolean {\n return prefix === \"/\" || key.startsWith(prefix);\n}\n\n/** Replication scopes are `/` or non-empty, slash-terminated folder paths. */\nexport function assertFolderPrefix(prefix: unknown): asserts prefix is string {\n const validFolder = typeof prefix === \"string\" &&\n prefix.length > 0 &&\n !prefix.startsWith(\"/\") &&\n !prefix.includes(\"//\") &&\n prefix.endsWith(\"/\");\n if (prefix !== \"/\" && !validFolder) {\n const folderHint = typeof prefix === \"string\"\n ? prefix.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")\n : \"\";\n const suggestion = folderHint.length > 0 && !folderHint.includes(\"//\")\n ? ` Use ${JSON.stringify(`${folderHint}/`)}.`\n : ' Use \"/\" or a slash-terminated folder path such as \"notes/\".';\n throw new TypeError(`Replication prefix must be \"/\" or a non-empty slash-terminated folder path without empty segments.${suggestion}`);\n }\n}\n","import { ReplicaError, ReplicaErrorCode } from \"./errors.js\";\nimport type { AuthorityState, AuthorityWindow, GrantRecord, LocalReadPolicy } from \"./types.js\";\nimport { assertFolderPrefix as assertPureFolderPrefix } from \"@tinycloud/sdk-services/kv/replication/prefix\";\n\n/** Replication prefixes are the whole space (`/`) or a slash-terminated folder. */\nexport function assertFolderPrefix(prefix: unknown): asserts prefix is string {\n try {\n assertPureFolderPrefix(prefix);\n } catch {\n const folderHint = typeof prefix === \"string\"\n ? prefix.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")\n : \"\";\n const suggestion = prefix === \"\" ? 'use \"/\" for the whole space' :\n folderHint.length > 0 && !folderHint.includes(\"//\")\n ? `use ${JSON.stringify(`${folderHint}/`)}`\n : 'use \"/\" for the whole space or a folder path such as \"notes/\"';\n throw new ReplicaError(\n ReplicaErrorCode.INVALID_ARGUMENT,\n `Replication prefix ${JSON.stringify(prefix)} must be \"/\" or a non-empty folder path ending in / without empty segments; ${suggestion}. Run \\`tc replica reset --replica <name> --purge\\` and recreate it with the folder prefix.`,\n );\n }\n}\n\n/** Prefix coverage shared with the KV replication feed. */\nexport function kvPrefixCovers(prefix: string, key: string): boolean {\n return prefix === \"/\" || key.startsWith(prefix);\n}\n/** Capability containment: exact grants cover exact keys; slash grants cover descendants. */\nexport function authorityPathCovers(grantPath: string, requestedPath: string): boolean {\n if (grantPath === \"/\") return true;\n if (grantPath.endsWith(\"/\")) return requestedPath.startsWith(grantPath);\n return requestedPath === grantPath;\n}\n\n/**\n * Syncing the owner's secrets space, or any prefix overlapping the vault\n * namespace (including bare `vault`), copies encrypted secret material to\n * disk and needs an explicit opt-in (TC-733).\n */\nexport function requiresSecretsOptIn(space: string, prefix: string): boolean {\n if (prefix === \"/\") return true;\n if (space === \"secrets\" || space.endsWith(\":secrets\")) return true;\n const firstSegment = prefix.split(\"/\", 1)[0];\n return firstSegment === \"vault\";\n}\n\n/** Browser read-through replicas never retain secrets or vault data, even with legacy opt-in. */\nexport function assertBrowserReadThroughScope(space: string, prefix: string, allowSecrets: boolean): void {\n if (allowSecrets || requiresSecretsOptIn(space, prefix) || prefix.split(\"/\", 1)[0] === \"secrets\") {\n throw new ReplicaError(\n ReplicaErrorCode.INVALID_ARGUMENT,\n \"Browser read-through replicas require allowSecrets=false and exclude the whole space, secrets and vault prefixes.\",\n );\n }\n}\n\n/** `\"blake3-<hex>\"` (quoted or not) → the 64-hex hash, or undefined. */\nexport function hashFromEtag(etag: string): string | undefined {\n const match = /^\"?blake3-([0-9a-f]{64})\"?$/.exec(etag);\n return match?.[1];\n}\n\nconst RFC3339 = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/;\n\n/** An RFC 3339 instant that parses: the only form an authority bound may take. */\nexport function isInstant(value: string): boolean {\n return RFC3339.test(value) && Number.isFinite(Date.parse(value));\n}\n\nexport type EffectiveAuthority = {\n state: AuthorityState;\n notBefore: string | null;\n expiresAt: string | null;\n retainUntil: string | null;\n /** The retention grant was revoked: after expiry, reads are revoked rather than expired. */\n retentionRevoked: boolean;\n};\n\nfunction minIso(a: string | null, bSeconds: number | null): string | null {\n if (bSeconds === null) return a;\n const b = new Date(bSeconds * 1000).toISOString();\n if (a === null) return b;\n return Date.parse(a) <= Date.parse(b) ? a : b;\n}\n\nfunction maxIso(a: string | null, bSeconds: number | null): string | null {\n if (bSeconds === null) return a;\n const b = new Date(bSeconds * 1000).toISOString();\n if (a === null) return b;\n return Date.parse(a) >= Date.parse(b) ? a : b;\n}\n\n/**\n * The window local reads are enforced against: the node-attested window from\n * the last successful sync, bounded by the installed leaf grant (an upper\n * bound only — a multi-parent ancestor can end the chain earlier, which only\n * the node can see).\n */\nexport function effectiveAuthority(input: {\n window: AuthorityWindow | null;\n grant: GrantRecord | null;\n revoked: string | null;\n retentionRevoked?: string | null;\n policy: LocalReadPolicy;\n now: number;\n}): EffectiveAuthority {\n const notBefore = maxIso(input.window?.notBefore ?? null, input.grant?.notBefore ?? null);\n const expiresAt = minIso(input.window?.expiresAt ?? null, input.grant?.expiresAt ?? null);\n const retainUntil = input.policy === \"retainAfterExpiry\" ? input.window?.retainUntil ?? null : null;\n let state: AuthorityState = \"valid\";\n if (input.revoked !== null) state = \"revoked\";\n else if (notBefore !== null && input.now < Date.parse(notBefore)) state = \"not-yet-valid\";\n else if (expiresAt !== null && input.now >= Date.parse(expiresAt)) state = \"expired\";\n return { state, notBefore, expiresAt, retainUntil, retentionRevoked: (input.retentionRevoked ?? null) !== null };\n}\n\n/**\n * Throws unless local reads are allowed now. Returns the reported authority\n * state: `valid`, or `expired` while a node-attested retention holds.\n */\nexport function assertReadable(authority: EffectiveAuthority, now: number): AuthorityState {\n switch (authority.state) {\n case \"valid\":\n return \"valid\";\n case \"revoked\":\n throw new ReplicaError(ReplicaErrorCode.GRANT_REVOKED, \"The replica's grant was revoked; local reads are blocked.\");\n case \"not-yet-valid\":\n throw new ReplicaError(\n ReplicaErrorCode.GRANT_NOT_YET_VALID,\n `The replica's grant is not valid before ${authority.notBefore}.`,\n );\n case \"expired\":\n if (authority.retentionRevoked) {\n throw new ReplicaError(\n ReplicaErrorCode.GRANT_REVOKED,\n `The replica's grant expired at ${authority.expiresAt} and its retention grant was revoked; local reads are blocked.`,\n );\n }\n if (authority.retainUntil !== null && now < Date.parse(authority.retainUntil)) return \"expired\";\n throw new ReplicaError(\n ReplicaErrorCode.GRANT_EXPIRED,\n authority.retainUntil === null\n ? `The replica's grant expired at ${authority.expiresAt}; local reads are blocked.`\n : `The replica's retention ended at ${authority.retainUntil}; local reads are blocked.`,\n );\n }\n}\n","/**\n * IndexedDB plumbing for the browser replica store: request promises and a\n * transaction-completer. A transaction's promise resolves on `oncomplete`\n * (never on request success — the SignatureCache mistake the design calls\n * out) and rejects on `onabort`/`onerror`.\n */\nimport { ReplicaError, ReplicaErrorCode } from \"../errors.js\";\n\nexport function requestAsPromise<T>(request: IDBRequest<T>): Promise<T> {\n const { promise, resolve, reject } = Promise.withResolvers<T>();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new DOMException(\"IndexedDB request failed\", \"UnknownError\"));\n return promise;\n}\n\n/**\n * Resolves when the transaction commits; rejects when it aborts or errors.\n * Listeners, not `on*` handlers, so several owners of one transaction (the\n * store and the lifecycle gate's `run`) can each await it.\n */\nexport function transactionDone(tx: IDBTransaction): Promise<void> {\n const { promise, resolve, reject } = Promise.withResolvers<void>();\n tx.addEventListener(\"complete\", () => resolve(), { once: true });\n tx.addEventListener(\"abort\", () => reject(tx.error ?? new DOMException(\"Transaction aborted\", \"AbortError\")), { once: true });\n tx.addEventListener(\"error\", () => reject(tx.error ?? new DOMException(\"Transaction failed\", \"UnknownError\")), { once: true });\n return promise;\n}\n\nexport function openDatabase(name: string, upgrade: (db: IDBDatabase) => void): Promise<IDBDatabase> {\n if (typeof indexedDB === \"undefined\") {\n return Promise.reject(\n new ReplicaError(\n ReplicaErrorCode.RUNTIME_UNSUPPORTED,\n \"IndexedDB is unavailable (private browsing or a non-browser runtime); the replica cannot persist.\",\n ),\n );\n }\n const { promise, resolve, reject } = Promise.withResolvers<IDBDatabase>();\n const request = indexedDB.open(name, 1);\n request.onupgradeneeded = () => upgrade(request.result);\n request.onsuccess = () => {\n const db = request.result;\n // A newer copy in another tab asks us to close; refuse silently so the\n // caller's transactions still work, then surface the version error to\n // the next opener instead of dropping writes mid-sync.\n db.onversionchange = () => db.close();\n resolve(db);\n };\n request.onerror = () => reject(request.error ?? new DOMException(`Opening ${name} failed`, \"UnknownError\"));\n request.onblocked = () =>\n reject(\n new ReplicaError(\n ReplicaErrorCode.BUSY,\n `Opening ${name} is blocked by another connection; close the replica in its other tab.`,\n ),\n );\n return promise;\n}\n\nconst byteEncoder = new TextEncoder();\n\n/** UTF-8 byte order for keys — the order SQLite, the node and `batchGet` share. */\nexport function compareKeyBytes(a: string, b: string): number {\n const x = byteEncoder.encode(a);\n const y = byteEncoder.encode(b);\n for (let index = 0; index < Math.min(x.length, y.length); index += 1) {\n if (x[index] !== y[index]) return x[index]! - y[index]!;\n }\n return x.length - y.length;\n}\n\ntype NamedError = { name: string };\n\nfunction hasName(error: unknown): error is NamedError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n typeof (error as Record<string, unknown>).name === \"string\"\n );\n}\n\n/** Map an IndexedDB failure to a replica error. Quota exceeded is STORAGE_FULL. */\nexport function idbError(error: unknown, action: string): ReplicaError {\n if (error instanceof ReplicaError) return error;\n const message = error instanceof Error ? error.message : String(error);\n if (hasName(error) && error.name === \"QuotaExceededError\") {\n return new ReplicaError(ReplicaErrorCode.STORAGE_FULL, `${action}: the browser's storage quota is exceeded.`, undefined, {\n cause: error,\n });\n }\n return new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, `${action}: ${message}`, undefined, { cause: error });\n}\n","import type { ReplicaAccountGate } from \"@tinycloud/sdk-services/kv/replication\";\n\n/** Browser-only gate fields; node profiles keep the shared salt-based gate layout. */\nexport interface BrowserGate extends ReplicaAccountGate {\n keyId: string;\n accountKeyId: string;\n consentDeadline: number | null;\n}\n\nexport interface GateHmacRecord {\n v: 1;\n incarnation: string;\n keyId: string;\n hmac: CryptoKey;\n}\n\nexport interface AccountKeyRecord {\n v: 1;\n incarnation: string;\n lifecycleEpoch: number;\n principalHash: string;\n keyId: string;\n aesGcm: CryptoKey;\n hmac: CryptoKey;\n}\n\nexport const GATE_HMAC_KEY = \"gateHmac\";\nexport const ACCOUNT_KEY = \"accountKey\";\n\nconst HEX = \"0123456789abcdef\";\nconst ENCODER = new TextEncoder();\n\nfunction hex(bytes: Uint8Array): string {\n let value = \"\";\n for (const byte of bytes) value += HEX.charAt(byte >>> 4) + HEX.charAt(byte & 15);\n return value;\n}\n\nfunction keyId(): string {\n return hex(crypto.getRandomValues(new Uint8Array(16)));\n}\n\nexport async function newGateHmac(incarnation: string): Promise<GateHmacRecord> {\n const hmac = await crypto.subtle.generateKey({ name: \"HMAC\", hash: \"SHA-256\", length: 256 }, false, [\"sign\", \"verify\"]);\n return { v: 1, incarnation, keyId: keyId(), hmac };\n}\n\nexport async function newAccountKey(incarnation: string, lifecycleEpoch: number, principalHash: string): Promise<AccountKeyRecord> {\n const [aesGcm, hmac] = await Promise.all([\n crypto.subtle.generateKey({ name: \"AES-GCM\", length: 256 }, false, [\"encrypt\", \"decrypt\"]),\n crypto.subtle.generateKey({ name: \"HMAC\", hash: \"SHA-256\", length: 256 }, false, [\"sign\", \"verify\"]),\n ]);\n return { v: 1, incarnation, lifecycleEpoch, principalHash, keyId: keyId(), aesGcm, hmac };\n}\n\n/** Domain separation prevents one identifier class from revealing another's HMAC. */\nexport async function gateHash(key: CryptoKey, domain: \"principal\" | \"identity\" | \"partition\" | \"lookup\", material: string): Promise<string> {\n const bytes = ENCODER.encode(`${domain}\\0${material}`);\n return hex(new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, bytes)));\n}\n\nfunction isHmac(key: unknown): key is CryptoKey {\n if (!(key instanceof CryptoKey) || key.extractable || key.algorithm.name !== \"HMAC\") return false;\n const algorithm = key.algorithm;\n return \"hash\" in algorithm && algorithm.hash !== null && typeof algorithm.hash === \"object\" &&\n \"name\" in algorithm.hash && algorithm.hash.name === \"SHA-256\" &&\n key.usages.length === 2 && key.usages.includes(\"sign\") && key.usages.includes(\"verify\");\n}\n\nfunction isAesGcm(key: unknown): key is CryptoKey {\n if (!(key instanceof CryptoKey) || key.extractable || key.algorithm.name !== \"AES-GCM\") return false;\n return \"length\" in key.algorithm && key.algorithm.length === 256 &&\n key.usages.length === 2 && key.usages.includes(\"encrypt\") && key.usages.includes(\"decrypt\");\n}\n\nexport function validGateHmac(record: GateHmacRecord | undefined, gate: BrowserGate): record is GateHmacRecord {\n return record?.v === 1 && record.incarnation === gate.incarnation && record.keyId === gate.keyId &&\n /^[0-9a-f]{32}$/.test(record.keyId) && isHmac(record.hmac);\n}\n\nexport function validAccountKey(record: AccountKeyRecord | undefined, gate: BrowserGate): record is AccountKeyRecord {\n return record?.v === 1 && record.incarnation === gate.incarnation && record.lifecycleEpoch === gate.lifecycleEpoch &&\n record.principalHash === gate.principalHash && record.keyId === gate.accountKeyId &&\n /^[0-9a-f]{32}$/.test(record.keyId) && isAesGcm(record.aesGcm) && isHmac(record.hmac);\n}\n","/** Grant lifetime constants without browser storage identifiers. */\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Default device-grant lifetime from install (24 h). All durations are milliseconds. */\nexport const DEFAULT_GRANT_TTL_MS = DAY_MS;\n/** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */\nexport const MAX_GRANT_TTL_MS = 7 * DAY_MS;\n/** Consent deadline = consent anchor + this window (7 d). */\nexport const CONSENT_WINDOW_MS = 7 * DAY_MS;\n/** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */\nexport const RENEW_BELOW_FRACTION = 0.25;\n","/**\n * Frozen constants of the shared replica contract (TC-858 Phase 2, see CONTRACT.md).\n *\n * Exported via `@tinycloud/sdk-services/kv/replication/contractConstants`, never from the\n * package root. Runtime grant policy imports the numeric-only `grantPolicyConstants` subpath\n * instead, so the default web bundle does not carry browser storage identifiers.\n */\nexport {\n DEFAULT_GRANT_TTL_MS,\n MAX_GRANT_TTL_MS,\n CONSENT_WINDOW_MS,\n RENEW_BELOW_FRACTION,\n} from \"./grantPolicyConstants\";\n\n/** Error codes the contract adds or gives new meaning. Values equal keys. */\nexport const ReplicaContractCode = {\n /**\n * The lifecycle gate refused the operation: the handle's session stamp or principal no longer\n * matches the gate, a purge intent covers the partition, or the logout marker is set. The error\n * carries `gate: ReplicaGateReason`. Read-through answers from the network; nothing is erased.\n */\n REPLICA_GATED: \"REPLICA_GATED\",\n /**\n * Reserved for handles whose partition was erased (purge or revocation) after they opened. The\n * gate check runs first, so a handle that is both gated and erased reports REPLICA_GATED.\n */\n RESET_REQUIRED: \"RESET_REQUIRED\",\n /** A page was refused by quota admission (`maxBytes` or the free-space floor). Nothing committed. */\n STORAGE_BUDGET: \"STORAGE_BUDGET\",\n /** The platform store refused the write (IndexedDB `QuotaExceededError`, ENOSPC). Nothing committed. */\n STORAGE_FULL: \"STORAGE_FULL\",\n /** The consent deadline has passed: no grant may be minted, renewed or served until re-consent. */\n CONSENT_EXPIRED: \"CONSENT_EXPIRED\",\n /** The installed grant's effective expiry (not necessarily its signed `exp`) has passed. */\n GRANT_EXPIRED: \"GRANT_EXPIRED\",\n} as const;\nexport type ReplicaContractCode = (typeof ReplicaContractCode)[keyof typeof ReplicaContractCode];\n\n/** Browser free-space floor in bytes (64 MiB, `navigator.storage.estimate()`); not applied on node/CLI. */\nexport const DEFAULT_MIN_FREE_BYTES = 64 * 1024 * 1024;\n\n/** The single per-origin IndexedDB database of the browser `KVReplicaStorage` adapter. */\nexport const REPLICA_KV_DATABASE = \"tinycloud-replica-kv\";\n/** Origin database schema: v2 destructively replaces v1 plaintext replica-owned stores. */\nexport const REPLICA_KV_SCHEMA_VERSION = 2;\n\n/**\n * Object-store names in {@link REPLICA_KV_DATABASE}. Every store uses out-of-line keys (no\n * `keyPath`, no autoIncrement) so the schema upgrade can create control stores without knowing\n * their record shapes. Data stores are owned by the adapter (S1); control stores by the lifecycle\n * gate (S3) and quota ledger (S5).\n */\nexport const REPLICA_KV_STORES = {\n /** Data: partition meta (opaque fences, sealed config/grants), private gate-HMAC partition id. */\n meta: \"meta\",\n /** Data: sealed KV entries, key `[privatePartitionId, accountHmac(path)]`. */\n entries: \"entries\",\n /** Data: AES-GCM content blobs, key `[privatePartitionId, accountHmac(hash)]`. */\n blobs: \"blobs\",\n /** Data: AES-sealed pending state, key private gate-HMAC `identityKeyHash`. */\n pending: \"pending\",\n /** Data: sealed owner device, private nonextractable key records and opaque install anchors. */\n device: \"device\",\n /** Control: the account gate, singleton key `\"account\"`, value `ReplicaAccountGate`. */\n gate: \"gate\",\n /** Control: partition index keyed by private `partitionId`; nonunique `byLookupId` index. */\n partitions: \"partitions\",\n /** Control: purge intents, key `ReplicaPurgeIntent.id`, value `ReplicaPurgeIntent`. */\n purgeIntents: \"purgeIntents\",\n /** Control: quota ledger, keys owned by the ledger (S5). */\n quota: \"quota\",\n} as const;\n\n/** Synchronous, cross-tab `localStorage` marker set when the deny transaction and fallback delete both failed. */\nexport const REPLICA_LOGOUT_MARKER = \"tinycloud-replica:logout-pending\";\n\n/** Origin-wide deny floor outside the deletable replica database; JSON `{ epoch, deniedAt }`. */\nexport const REPLICA_DENY_TOMBSTONE = \"tinycloud-replica:deny-tombstone\";\n\n/** BroadcastChannel name used for lifecycle nudges and peer-commit notifications. */\nexport const REPLICA_KV_CHANNEL = \"tinycloud-replica-kv\";\n\n/** Web Lock name prefix for pending-write read-modify-write; suffix is the private gate-HMAC identity id. */\nexport const REPLICA_PENDING_LOCK_PREFIX = \"tinycloud-replica-kv:pending:\";\n\n/** Node/CLI gate file name. CLI places it at `<profile>/replica-gate.json`. */\nexport const REPLICA_GATE_FILE = \"replica-gate.json\";\n","/**\n * `did:key` verification method fragment → the principal DID.\n */\nexport function principalOf(did: string): string {\n return did.split(\"#\", 1)[0]!;\n}\n\nconst METHOD = /^[a-z0-9]+$/u;\n// DID method-specific-id: idchars ([A-Za-z0-9._-]) or %XX escapes, with `:`\n// separators allowed; the final segment must be non-empty.\nconst IDCHAR = /^[A-Za-z0-9._-]$/u;\n\n/**\n * Whether `value` is a well-formed DID the replica accepts as a `principal`\n * partition label: `did:` + a lowercase method name + a non-empty\n * method-specific-id whose segments (separated by `:`) consist of idchars or\n * valid `%XX` percent-escapes, and whose last segment is not empty. Shape\n * only — `principal` is an app-asserted label, never a credential.\n */\nexport function isPrincipalDid(value: string): boolean {\n if (typeof value !== \"string\" || !value.startsWith(\"did:\")) return false;\n const rest = value.slice(4);\n const methodEnd = rest.indexOf(\":\");\n if (methodEnd <= 0) return false;\n if (!METHOD.test(rest.slice(0, methodEnd))) return false;\n const msid = rest.slice(methodEnd + 1);\n if (msid.length === 0) return false;\n const segments = msid.split(\":\");\n const last = segments[segments.length - 1]!;\n if (last.length === 0) return false;\n for (const segment of segments) {\n for (let i = 0; i < segment.length; i += 1) {\n const c = segment[i]!;\n if (c === \"%\") {\n // A percent-escape needs exactly two hex digits.\n if (i + 2 >= segment.length || !/^[0-9a-fA-F]{2}$/u.test(segment.slice(i + 1, i + 3))) return false;\n i += 2;\n } else if (!IDCHAR.test(c)) {\n return false;\n }\n }\n }\n return true;\n}\n","import { bytesToHex } from \"@noble/hashes/utils\";\n\nimport { ReplicaError, ReplicaErrorCode } from \"../errors.js\";\n\n/** v1 AES-256-GCM record: 96-bit fresh random IV per write, 128-bit tag; the account gate owns the nonextractable CryptoKey. */\nexport type SealedRecord = { v: 1; iv: Uint8Array; bytes: Uint8Array };\n\nconst encoder = new TextEncoder();\nconst NONCE_LENGTH = 12;\nconst TAG_LENGTH = 16;\n\n/** AAD binds format version, store, partition and row id; the caller supplies an unambiguous context. */\nfunction aad(context: string): Uint8Array {\n return encoder.encode(`tinycloud-replica-kv:v1\\u0000${context}`);\n}\n\nexport async function seal(key: CryptoKey, plaintext: Uint8Array, context: string): Promise<SealedRecord> {\n const iv = crypto.getRandomValues(new Uint8Array(NONCE_LENGTH));\n const bytes = new Uint8Array(await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv, additionalData: aad(context) }, key, plaintext,\n ));\n return { v: 1, iv, bytes };\n}\n\nexport async function openSealed(key: CryptoKey, record: unknown, context: string): Promise<Uint8Array> {\n if (record === null || typeof record !== \"object\" || !(\"v\" in record) || record.v !== 1\n || !(\"iv\" in record) || !(record.iv instanceof Uint8Array) || record.iv.length !== NONCE_LENGTH\n || !(\"bytes\" in record) || !(record.bytes instanceof Uint8Array) || record.bytes.length < TAG_LENGTH) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica record is unsealed or has an unknown ciphertext version.\");\n }\n try {\n return new Uint8Array(await crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv: record.iv, additionalData: aad(context) }, key, record.bytes,\n ));\n } catch (cause) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica record failed authentication.\", undefined, { cause });\n }\n}\n\n/** A private, deterministic primary key. The gate's public salt never enters this derivation. */\nexport async function opaqueId(key: CryptoKey, store: string, partition: string, value: string): Promise<string> {\n const input = encoder.encode(JSON.stringify([\"tinycloud-replica-kv\", 1, store, partition, value]));\n return bytesToHex(new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, input)));\n}\n\n/** Count the canonical UTF-8 encoding without allocating an encoded copy of a stored value. */\nfunction utf8Length(value: string): number {\n let bytes = 0;\n for (let i = 0; i < value.length; i += 1) {\n const code = value.charCodeAt(i);\n if (code < 0x80) bytes += 1;\n else if (code < 0x800) bytes += 2;\n else if (code >= 0xd800 && code <= 0xdbff && i + 1 < value.length\n && value.charCodeAt(i + 1) >= 0xdc00 && value.charCodeAt(i + 1) <= 0xdfff) {\n bytes += 4;\n i += 1;\n } else bytes += 3;\n }\n return bytes;\n}\n\ntype MeasuredRow = Partial<SealedRecord> & {\n pid?: string;\n hashId?: string;\n size?: number;\n revision?: number;\n generation?: number;\n coverageCode?: number;\n syncedThroughEpoch?: number;\n keys?: number;\n contentMissing?: number;\n tombstones?: number;\n contentBytes?: number;\n purged?: boolean;\n};\n\n/** Canonical application-encoded bytes for the final persisted row, not IDB engine allocation. */\nexport function measureSealedRow(key: IDBValidKey, row: MeasuredRow): number {\n if (row.purged === true\n ? row.v !== undefined || row.iv !== undefined || row.bytes !== undefined\n : row.v !== 1 || !(row.iv instanceof Uint8Array) || !(row.bytes instanceof Uint8Array)) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has an invalid sealed envelope.\");\n }\n const primaryKey = JSON.stringify(key);\n if (typeof primaryKey !== \"string\") {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has an invalid primary key.\");\n }\n let total = 2 + 4 + utf8Length(primaryKey);\n let hasSize = false;\n for (const name in row) {\n if (!Object.hasOwn(row, name)) continue;\n const value: unknown = Reflect.get(row, name);\n total += 1 + name.length; // All persisted field names below are ASCII.\n switch (name) {\n case \"pid\":\n case \"hashId\":\n if (typeof value !== \"string\") throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has an invalid identifier.\");\n total += 4 + utf8Length(value);\n break;\n case \"v\":\n if (value !== 1) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has an unknown version.\");\n total += 1;\n break;\n case \"coverageCode\":\n if (value !== 0 && value !== 1 && value !== 2) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has invalid coverage.\");\n total += 1;\n break;\n case \"purged\":\n if (typeof value !== \"boolean\") throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has invalid purge state.\");\n total += 1;\n break;\n case \"revision\":\n case \"generation\":\n case \"syncedThroughEpoch\":\n case \"keys\":\n case \"contentMissing\":\n case \"tombstones\":\n case \"contentBytes\":\n case \"size\":\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has an invalid numeric field.\");\n }\n if (name === \"size\") hasSize = true;\n total += 8;\n break;\n case \"iv\":\n case \"bytes\":\n if (!(value instanceof Uint8Array)) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has invalid ciphertext.\");\n total += 4 + value.byteLength;\n break;\n default:\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica row has an unknown persisted field.\");\n }\n }\n if (!hasSize) total += 1 + \"size\".length + 8;\n return total;\n}\n","/**\n * The origin database of `@tinycloud/replica/kv-storage` (TC-858 Phase 2\n * plan §3): ONE IndexedDB database per origin, `tinycloud-replica-kv`, so\n * that a page commit, its quota accounting and its lifecycle-gate check, or\n * an erase and its purge-intent update, each run as a single transaction.\n *\n * Stores (names and keys frozen in the shared contract; every store keys\n * out-of-line):\n * meta — one sealed state row per partition, key partitionId\n * entries — key [pid, opaque key HMAC]; index byHash on [pid, opaque hash HMAC]\n * blobs — key [pid, opaque hash HMAC]; index bySize on [pid, ciphertext row size]\n * pending — one sealed PendingWriteState per identity, key private identity HMAC\n * device — sealed owner device and grant install timestamps; gate crypto keys\n * gate, partitions, purgeIntents — lifecycle control stores; partition lookup index byLookupId\n * quota — origin-wide measured ciphertext byte ledger\n *\n * The RC1 `openReplica` databases (`tinycloud-replica/<id>`) are separate\n * and untouched.\n */\nimport { replicationIdentityKey, type ReplicaPartitionEraser, type ReplicationIdentity } from \"@tinycloud/sdk-services/kv/replication\";\nimport { REPLICA_KV_DATABASE, REPLICA_KV_STORES } from \"@tinycloud/sdk-services/kv/replication/contractConstants\";\n\nimport { principalOf } from \"../did.js\";\nimport { ReplicaError, ReplicaErrorCode } from \"../errors.js\";\nimport { requestAsPromise } from \"../browser/idb.js\";\nimport type { ReplicaStoreLayout } from \"../browser/store.js\";\nimport { gateHash } from \"./gateKeys.js\";\nimport { measureSealedRow } from \"./sealed.js\";\n\nexport const KV_DATABASE = REPLICA_KV_DATABASE;\nexport const KV_DATABASE_VERSION = 2;\nexport const KV_STORE = REPLICA_KV_STORES;\n\n/**\n * `device` store keys `firstInstall:<identityKeyHash>` → `{ at }` (ms): the\n * `first_install` consent anchor of an identity whose session has neither\n * SIWE nor delegation `iat`/`nbf`. Written set-if-absent by the install\n * transaction; survives partition reset, purge and reinstall; only the\n * lifecycle gate's `deny` deletes the range.\n */\nexport const FIRST_INSTALL_KEY_PREFIX = \"firstInstall:\";\n/** CID install timestamps live outside partitions, so purge/reinstall cannot refresh a CID. */\nexport const GRANT_INSTALL_KEY_PREFIX = \"grantInstall:\";\n\n\n/** The scope a partition erase (and the identity-scoped pending erase) needs. */\nexport const ERASE_STORES: readonly string[] = [KV_STORE.meta, KV_STORE.entries, KV_STORE.blobs, KV_STORE.pending];\n\nconst READ_SCOPE: readonly string[] = [KV_STORE.gate, KV_STORE.purgeIntents];\nconst WRITE_SCOPE: readonly string[] = [KV_STORE.gate, KV_STORE.partitions, KV_STORE.purgeIntents, KV_STORE.quota, KV_STORE.device];\n\nfunction createStores(db: IDBDatabase): void {\n db.createObjectStore(KV_STORE.meta);\n const entries = db.createObjectStore(KV_STORE.entries);\n entries.createIndex(\"byHash\", [\"pid\", \"hash\"], { unique: false });\n const blobs = db.createObjectStore(KV_STORE.blobs);\n blobs.createIndex(\"bySize\", [\"pid\", \"size\"], { unique: false });\n const partitions = db.createObjectStore(KV_STORE.partitions);\n partitions.createIndex(\"byLookupId\", \"lookupId\", { unique: false });\n for (const name of [KV_STORE.pending, KV_STORE.device, KV_STORE.gate, KV_STORE.purgeIntents, KV_STORE.quota]) {\n db.createObjectStore(name);\n }\n}\n\n/**\n * Private gate-HMAC identity id (`pending` key, `firstInstall:` suffix and\n * pending Web Lock suffix). Never derive account identifiers from the public\n * gate salt; precompute them before opening a transaction.\n */\nexport function identityKeyHashOf(identity: ReplicationIdentity, gateHmac: CryptoKey): Promise<string> {\n return gateHash(gateHmac, \"identity\", replicationIdentityKey(identity));\n}\n\n/**\n * Open the origin database. With `create: false` a missing database stays\n * missing — the upgrade that would create it is aborted — and the result\n * is null; inspection and purge use this so they never create storage.\n * Every connection closes itself on `versionchange`, so a\n * `deleteDatabase` from any tab is never blocked by an idle connection.\n */\nexport function openKvDatabase(options: { create: boolean }): Promise<IDBDatabase | null> {\n if (typeof indexedDB === \"undefined\") {\n return Promise.reject(\n new ReplicaError(\n ReplicaErrorCode.RUNTIME_UNSUPPORTED,\n \"IndexedDB is unavailable (private browsing or a non-browser runtime); the replica cannot persist.\",\n ),\n );\n }\n const { promise, resolve, reject } = Promise.withResolvers<IDBDatabase | null>();\n const request = options.create ? indexedDB.open(KV_DATABASE, KV_DATABASE_VERSION) : indexedDB.open(KV_DATABASE);\n let refused = false;\n request.onupgradeneeded = (event) => {\n if (!options.create && event.oldVersion === 0) {\n refused = true;\n request.transaction?.abort();\n return;\n }\n if (event.oldVersion > 0) {\n // v1 stored plaintext values and recognizable IndexedDB keys. No data or\n // account gate from that format can be retained in the ciphertext layout.\n for (const name of Array.from(request.result.objectStoreNames)) request.result.deleteObjectStore(name);\n }\n createStores(request.result);\n };\n request.onsuccess = () => {\n const db = request.result;\n if (db.version !== KV_DATABASE_VERSION) {\n db.close();\n resolve(null);\n return;\n }\n db.onversionchange = () => db.close();\n resolve(db);\n };\n request.onerror = (event) => {\n if (refused) {\n // The aborted upgrade rolls the creation back; this is \"missing\", not a failure.\n event.preventDefault();\n resolve(null);\n return;\n }\n reject(request.error ?? new DOMException(`Opening ${KV_DATABASE} failed`, \"UnknownError\"));\n };\n request.onblocked = () =>\n reject(new ReplicaError(ReplicaErrorCode.BUSY, `Opening ${KV_DATABASE} is blocked by an older connection in another tab.`));\n return promise;\n}\n\n/**\n * Partition id (and opaque `replicaId`): gate-HMAC over the canonical\n * identity, folder prefix and device principal. Dropping the DID fragment\n * makes two names of one key share a partition. Derive before any transaction.\n */\nexport function partitionIdOf(input: { identity: ReplicationIdentity; prefix: string; deviceDid: string }, gateHmac: CryptoKey): Promise<string> {\n return gateHash(gateHmac, \"partition\", `${replicationIdentityKey(input.identity)}\\n${input.prefix}\\n${principalOf(input.deviceDid)}`);\n}\n\n/** The partition-scoped key layout `IndexedDbReplicaStore` runs over. */\nexport function kvLayout(partitionId: string): ReplicaStoreLayout {\n return {\n partitionId,\n readScope: READ_SCOPE,\n writeScope: WRITE_SCOPE,\n metaKey: partitionId,\n outOfLineKeys: true,\n entryKey: (key) => [partitionId, key],\n blobKey: (hash) => [partitionId, hash],\n blobHashOf: (key) => (Array.isArray(key) && key[0] === partitionId && typeof key[1] === \"string\" ? key[1] : undefined),\n // Arrays sort after every string and number, so [pid, []] bounds every [pid, <string|number>].\n range: IDBKeyRange.bound([partitionId], [partitionId, []]),\n tag: { pid: partitionId },\n blobSizeIndex: \"bySize\",\n };\n}\n\n/** Delete ciphertext rows by opaque partition range without needing the account's shredded key. */\nfunction eraseSealedRows(tx: IDBTransaction, name: string, partitionId: string): Promise<number> {\n const { promise, resolve, reject } = Promise.withResolvers<number>();\n const range = IDBKeyRange.bound([partitionId], [partitionId, []]);\n const request = tx.objectStore(name).openCursor(range);\n let removed = 0;\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor === null) return resolve(removed);\n try {\n const row: unknown = cursor.value;\n if (row === null || typeof row !== \"object\" || !(\"pid\" in row) || row.pid !== partitionId ||\n !(\"size\" in row) || typeof row.size !== \"number\") {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The encrypted replica row has an invalid partition or byte measure.\");\n }\n const measured = measureSealedRow(cursor.primaryKey, row as Parameters<typeof measureSealedRow>[1]);\n if (row.size !== measured || !Number.isSafeInteger(removed + measured)) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The encrypted replica row has an invalid byte measure.\");\n }\n removed += measured;\n cursor.delete();\n cursor.continue();\n } catch (error) {\n reject(error);\n }\n };\n request.onerror = () => reject(request.error);\n return promise;\n}\n\n/**\n * The lifecycle erase seam. Entries/blobs are deleted and encrypted metadata\n * becomes a contentless generation tombstone: stale handles reject RESET_REQUIRED\n * without requiring an account key after deny. `bytes` is the exact net measured\n * row release, including metadata replacement, for idempotent quota accounting.\n */\nexport const kvPartitionEraser: ReplicaPartitionEraser<IDBTransaction> = {\n async erasePartition(tx, partitionId) {\n const meta = tx.objectStore(KV_STORE.meta);\n const old: unknown = await requestAsPromise(meta.get(partitionId));\n if (old !== undefined && (old === null || typeof old !== \"object\" ||\n !(\"pid\" in old) || old.pid !== partitionId ||\n !(\"revision\" in old) || typeof old.revision !== \"number\" || !Number.isSafeInteger(old.revision) || old.revision < 0 ||\n !(\"generation\" in old) || typeof old.generation !== \"number\" || !Number.isSafeInteger(old.generation) || old.generation < 0 ||\n !(\"size\" in old) || typeof old.size !== \"number\" || old.size !== measureSealedRow(partitionId, old as Parameters<typeof measureSealedRow>[1]))) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The encrypted replica metadata is invalid.\");\n }\n const [entries, blobs] = await Promise.all([\n eraseSealedRows(tx, KV_STORE.entries, partitionId),\n eraseSealedRows(tx, KV_STORE.blobs, partitionId),\n ]);\n if (old === undefined) return { bytes: entries + blobs };\n const current = old as { pid: string; revision: number; generation: number; size: number; purged?: boolean };\n if (current.purged === true) {\n if (entries !== 0 || blobs !== 0) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"An erased replica still owns ciphertext rows.\");\n return { bytes: 0 };\n }\n const tombstone = {\n pid: partitionId, revision: current.revision + 1, generation: current.generation + 1,\n coverageCode: 0 as const, syncedThroughEpoch: 0, keys: 0,\n contentMissing: 0, tombstones: 0, contentBytes: 0, purged: true as const, size: 0,\n };\n tombstone.size = measureSealedRow(partitionId, tombstone);\n const bytes = current.size + entries + blobs - tombstone.size;\n if (!Number.isSafeInteger(bytes) || bytes < 0) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The erased replica has an invalid byte delta.\");\n meta.put(tombstone, partitionId);\n return { bytes };\n },\n async eraseIdentityPending(tx, identityKeyHash) {\n tx.objectStore(KV_STORE.pending).delete(identityKeyHash);\n },\n};\n","import type { ReplicaQuotaLedger, ReplicaQuotaSpec } from \"@tinycloud/sdk-services/kv/replication\";\nimport { DEFAULT_MIN_FREE_BYTES } from \"@tinycloud/sdk-services/kv/replication/contractConstants\";\n\nimport { requestAsPromise } from \"../browser/idb.js\";\nimport { ReplicaError, ReplicaErrorCode } from \"../errors.js\";\nimport { KV_STORE } from \"./schema.js\";\n\ntype Usage = { bytes: number };\nconst TOTAL = \"total\";\n\n/** A reserved origin-wide bucket for sealed owner-device and install-stamp rows. */\nexport const DEVICE_QUOTA_PARTITION_ID = \"device\";\n\nexport interface ReplicaBrowserQuotaLedger extends ReplicaQuotaLedger<IDBTransaction> {\n /** Admit the combined signed origin delta once, before any sealed row is written. */\n admitRows(tx: IDBTransaction, rows: {\n partitionId: string;\n partitionDeltaBytes: number;\n deviceDeltaBytes: number;\n freeBytes: number | null;\n }): Promise<void>;\n /** Commit that same delta, split between the partition and retained device rows. */\n accountRows(tx: IDBTransaction, rows: {\n partitionId: string;\n partitionDeltaBytes: number;\n deviceDeltaBytes: number;\n }): Promise<void>;\n}\n\nfunction partitionKey(partitionId: string): string {\n return `partition:${partitionId}`;\n}\n\nfunction measured(row: Usage | undefined): number {\n const bytes = row?.bytes ?? 0;\n if (!Number.isSafeInteger(bytes) || bytes < 0) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica quota ledger has invalid byte accounting.\");\n }\n return bytes;\n}\n\nfunction checkedDelta(delta: number): number {\n if (!Number.isSafeInteger(delta)) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica quota delta is not a safe integer.\");\n }\n return delta;\n}\n\n/** Origin-wide quota, serialized by every readwrite transaction's shared `quota` store. */\nexport function ledgerFor(quota?: ReplicaQuotaSpec): ReplicaBrowserQuotaLedger {\n const maxBytes = quota?.maxBytes;\n const minFreeBytes = quota?.minFreeBytes ?? DEFAULT_MIN_FREE_BYTES;\n\n async function admit(tx: IDBTransaction, delta: number, freeBytes: number | null): Promise<void> {\n if (delta <= 0) return;\n const total = measured(await requestAsPromise<Usage | undefined>(tx.objectStore(KV_STORE.quota).get(TOTAL)));\n if (maxBytes !== undefined && total + delta > maxBytes) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_BUDGET, \"The replica page exceeds the origin's byte budget.\");\n }\n if (freeBytes !== null && freeBytes - delta < minFreeBytes) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_BUDGET, \"The replica page would cross the browser's free-space floor.\");\n }\n }\n\n const ledger: ReplicaBrowserQuotaLedger = {\n async freeBytes() {\n if (typeof navigator === \"undefined\" || navigator.storage?.estimate === undefined) return null;\n const { quota: capacity, usage } = await navigator.storage.estimate();\n return typeof capacity === \"number\" && typeof usage === \"number\"\n && Number.isFinite(capacity) && Number.isFinite(usage)\n ? Math.max(0, capacity - usage)\n : null;\n },\n async admitPage(tx, page) {\n await admit(tx, checkedDelta(page.deltaBytes), page.freeBytes);\n },\n async admitRows(tx, { partitionDeltaBytes, deviceDeltaBytes, freeBytes }) {\n const delta = checkedDelta(checkedDelta(partitionDeltaBytes) + checkedDelta(deviceDeltaBytes));\n await admit(tx, delta, freeBytes);\n },\n async accountCommit(tx, { partitionId, deltaBytes }) {\n await ledger.accountRows(tx, { partitionId, partitionDeltaBytes: deltaBytes, deviceDeltaBytes: 0 });\n },\n async accountRows(tx, { partitionId, partitionDeltaBytes, deviceDeltaBytes }) {\n const partitionDelta = checkedDelta(partitionDeltaBytes);\n const deviceDelta = checkedDelta(deviceDeltaBytes);\n if (partitionDelta === 0 && deviceDelta === 0) return;\n if (partitionDelta !== 0 && partitionId === DEVICE_QUOTA_PARTITION_ID) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The device quota bucket cannot contain partition rows.\");\n }\n const combined = checkedDelta(partitionDelta + deviceDelta);\n const store = tx.objectStore(KV_STORE.quota);\n const totalRequest = combined === 0 ? undefined : requestAsPromise<Usage | undefined>(store.get(TOTAL));\n const partitionRequest = partitionDelta === 0 ? undefined : requestAsPromise<Usage | undefined>(store.get(partitionKey(partitionId)));\n const deviceRequest = deviceDelta === 0 ? undefined : requestAsPromise<Usage | undefined>(store.get(partitionKey(DEVICE_QUOTA_PARTITION_ID)));\n const total = totalRequest === undefined ? 0 : measured(await totalRequest) + combined;\n const partition = partitionRequest === undefined ? 0 : measured(await partitionRequest) + partitionDelta;\n const device = deviceRequest === undefined ? 0 : measured(await deviceRequest) + deviceDelta;\n if ((totalRequest !== undefined && (!Number.isSafeInteger(total) || total < 0))\n || (partitionRequest !== undefined && (!Number.isSafeInteger(partition) || partition < 0))\n || (deviceRequest !== undefined && (!Number.isSafeInteger(device) || device < 0))) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica quota ledger would become negative or imprecise.\");\n }\n if (totalRequest !== undefined) store.put({ bytes: total } satisfies Usage, TOTAL);\n if (partitionRequest !== undefined) {\n if (partition === 0) store.delete(partitionKey(partitionId));\n else store.put({ bytes: partition } satisfies Usage, partitionKey(partitionId));\n }\n if (deviceRequest !== undefined) {\n if (device === 0) store.delete(partitionKey(DEVICE_QUOTA_PARTITION_ID));\n else store.put({ bytes: device } satisfies Usage, partitionKey(DEVICE_QUOTA_PARTITION_ID));\n }\n },\n async accountErase(tx, { partitionId, bytes }) {\n const removed = checkedDelta(bytes);\n if (removed < 0) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica erase has negative bytes.\");\n const store = tx.objectStore(KV_STORE.quota);\n const partition = await requestAsPromise<Usage | undefined>(store.get(partitionKey(partitionId)));\n if (partition === undefined) return; // A completed erase has no partition entry to subtract again.\n const remaining = measured(partition) - removed;\n if (remaining < 0) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica erase exceeds its accounted bytes.\");\n const total = measured(await requestAsPromise<Usage | undefined>(store.get(TOTAL))) - removed;\n if (total < 0) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica erase exceeds origin usage.\");\n store.put({ bytes: total } satisfies Usage, TOTAL);\n if (remaining === 0) store.delete(partitionKey(partitionId));\n else store.put({ bytes: remaining } satisfies Usage, partitionKey(partitionId));\n },\n };\n return ledger;\n}\n","/**\n * The browser `ReplicaGateTx` over the origin database's control stores\n * (`gate`, `partitions`, `purgeIntents`, `quota`). Every data transaction goes\n * through `run`, which reads the gate record as its FIRST request and refuses\n * — aborting, so nothing commits — unless the incarnation, the lifecycle epoch\n * and the principal hash all match, and no purge intent covers the partition\n * or identity. `run` resolves only after `oncomplete`.\n *\n * Erase transactions are exempt from `run`: they call `indexPartition`,\n * `unindexPartition` and `clearIntent` on their own transaction.\n */\nimport type {\n ReplicaBrowserGateAccess,\n ReplicaBrowserGateSnapshot,\n ReplicaBrowserGateTx,\n ReplicaGateReason,\n ReplicaGateScope,\n ReplicaPartitionIndexEntry,\n ReplicaDenyOutcome,\n} from \"@tinycloud/sdk-services/kv/replication\";\nimport { ReplicaError, ReplicaErrorCode, gatedError } from \"../errors.js\";\nimport { requestAsPromise, transactionDone } from \"../browser/idb.js\";\nimport { ACCOUNT_KEY, GATE_HMAC_KEY, validAccountKey, validGateHmac, type AccountKeyRecord, type BrowserGate, type GateHmacRecord } from \"./gateKeys.js\";\nimport { KV_STORE } from \"./schema.js\";\n\nconst ACCOUNT = \"account\";\nconst CONTROL = [KV_STORE.gate, KV_STORE.partitions, KV_STORE.purgeIntents, KV_STORE.quota, KV_STORE.device];\n\n/**\n * Opens the origin database. `create` false yields `null` when it does not\n * exist; `create` true creates it (the first `run` may precede any schema).\n */\nexport type KvDatabaseOpener = (create: boolean) => Promise<IDBDatabase | null>;\n\nfunction refusal(reason: ReplicaGateReason): Error {\n return gatedError(reason, `The replica gate refused: ${reason}.`);\n}\n\nexport async function withDatabase<T>(open: KvDatabaseOpener, create: boolean, use: (db: IDBDatabase) => Promise<T>): Promise<T | null> {\n const db = await open(create);\n if (db === null) return null;\n try {\n return await use(db);\n } finally {\n db.close();\n }\n}\n\n/** Browser IDs and key ids are precomputed before opening a data transaction. */\nexport type BrowserGateAccess = ReplicaBrowserGateAccess;\nexport type BrowserGateSnapshot = ReplicaBrowserGateSnapshot;\n\nexport interface BrowserReplicaGateTx extends ReplicaBrowserGateTx<IDBTransaction> {\n snapshot(): Promise<BrowserGateSnapshot | null>;\n readAccountKey(access: BrowserGateAccess): Promise<AccountKeyRecord>;\n}\n\nexport function createIndexedDbGateTx(\n open: KvDatabaseOpener,\n options: { now?: () => number; onConsentExpired: () => Promise<ReplicaDenyOutcome> },\n): BrowserReplicaGateTx {\n if (typeof options?.onConsentExpired !== \"function\") throw refusal(\"gate_unavailable\");\n const now = options.now ?? Date.now;\n function checkedNow(): number {\n const at = now();\n if (!Number.isSafeInteger(at) || at < 0) throw refusal(\"gate_unavailable\");\n return at;\n }\n\n let expiryFlight: Promise<ReplicaDenyOutcome> | undefined;\n\n async function snapshot(): Promise<BrowserGateSnapshot | null> {\n return withDatabase(open, false, async (db) => {\n const tx = db.transaction([KV_STORE.gate, KV_STORE.device]);\n const gate = await requestAsPromise<BrowserGate | undefined>(tx.objectStore(KV_STORE.gate).get(ACCOUNT));\n if (gate === undefined || gate.principalHash === null) return null;\n if (typeof gate.consentDeadline !== \"number\" || !Number.isSafeInteger(gate.consentDeadline) || gate.consentDeadline < 0) throw refusal(\"gate_unavailable\");\n const hash = await requestAsPromise<GateHmacRecord | undefined>(tx.objectStore(KV_STORE.device).get(GATE_HMAC_KEY));\n if (!validGateHmac(hash, gate)) throw refusal(\"gate_unavailable\");\n return { incarnation: gate.incarnation, salt: gate.salt, lifecycleEpoch: gate.lifecycleEpoch, keyId: hash.keyId, accountKeyId: gate.accountKeyId, gateHmac: hash.hmac };\n });\n }\n\n async function expire(access: Pick<BrowserGateAccess, \"stamp\" | \"incarnation\">): Promise<void> {\n let flight: Promise<ReplicaDenyOutcome> | undefined;\n try {\n flight = expiryFlight ?? options.onConsentExpired();\n expiryFlight = flight;\n const outcome = await flight;\n if (outcome.status !== \"denied\" && outcome.status !== \"deleted\" && outcome.status !== \"stale\") throw refusal(\"gate_unavailable\");\n // `stale` can also mean the main clock has not reached the deadline. Verify that\n // the old incarnation/epoch was actually removed before reporting expiry.\n const gate = await withDatabase(open, false, (db) =>\n requestAsPromise<BrowserGate | undefined>(db.transaction(KV_STORE.gate).objectStore(KV_STORE.gate).get(ACCOUNT)),\n );\n if (gate !== null && (gate === undefined ||\n (gate.incarnation === access.incarnation && (gate.lifecycleEpoch <= access.stamp.lifecycleEpoch || gate.principalHash !== null)))) {\n throw refusal(\"gate_unavailable\");\n }\n } catch {\n throw refusal(\"gate_unavailable\");\n } finally {\n if (flight !== undefined && expiryFlight === flight) expiryFlight = undefined;\n }\n }\n\n async function runChecked<T>(scope: ReplicaGateScope, access: BrowserGateAccess, fn: (tx: IDBTransaction, account: AccountKeyRecord) => Promise<T>): Promise<T> {\n if (access === null || typeof access !== \"object\" || access.stamp === null || typeof access.stamp !== \"object\") {\n throw refusal(\"not_established\");\n }\n if (!(\"principalHash\" in access) || typeof access.principalHash !== \"string\" ||\n !(\"keyId\" in access) || typeof access.keyId !== \"string\" ||\n !(\"accountKeyId\" in access) || typeof access.accountKeyId !== \"string\") throw refusal(\"gate_unavailable\");\n try {\n const result = await withDatabase(open, false, async (db) => {\n const tx = db.transaction([...scope.stores, ...CONTROL], scope.mode, { durability: \"strict\" });\n const done = transactionDone(tx);\n try {\n // The first request is always the gate. No WebCrypto work occurs inside this transaction.\n const gate = await requestAsPromise<BrowserGate | undefined>(tx.objectStore(KV_STORE.gate).get(ACCOUNT));\n if (gate === undefined) throw refusal(\"not_established\");\n if (gate.incarnation !== access.incarnation || gate.incarnation !== access.stamp.incarnation ||\n gate.lifecycleEpoch !== access.stamp.lifecycleEpoch || gate.principalHash === null) throw refusal(\"stamp_stale\");\n if (gate.keyId !== access.keyId || gate.accountKeyId !== access.accountKeyId) throw refusal(\"stamp_stale\");\n if (gate.principalHash !== access.principalHash) throw refusal(\"principal_mismatch\");\n if (typeof gate.consentDeadline !== \"number\" || !Number.isSafeInteger(gate.consentDeadline) || gate.consentDeadline < 0) throw refusal(\"gate_unavailable\");\n\n const device = tx.objectStore(KV_STORE.device);\n const hash = await requestAsPromise<GateHmacRecord | undefined>(device.get(GATE_HMAC_KEY));\n const account = await requestAsPromise<AccountKeyRecord | undefined>(device.get(ACCOUNT_KEY));\n if (!validGateHmac(hash, gate) || !validAccountKey(account, gate)) throw refusal(\"gate_unavailable\");\n const intents = tx.objectStore(KV_STORE.purgeIntents);\n if (access.partitionId !== undefined && (await requestAsPromise(intents.count(access.partitionId))) > 0) throw refusal(\"purge_pending\");\n if (access.identityKeyHash !== undefined && (await requestAsPromise(intents.count(`pending:${access.identityKeyHash}`))) > 0) throw refusal(\"purge_pending\");\n if (checkedNow() >= gate.consentDeadline) throw new ReplicaError(ReplicaErrorCode.CONSENT_EXPIRED, \"The account consent has expired.\");\n const value = await fn(tx, account);\n await done;\n return { value };\n } catch (error) {\n try {\n tx.abort();\n } catch {\n // Already settled.\n }\n await done.catch(() => undefined);\n throw error;\n }\n });\n if (result === null) throw refusal(\"gate_unavailable\");\n return result.value;\n } catch (error) {\n if (error !== null && typeof error === \"object\" && \"code\" in error && error.code === ReplicaErrorCode.CONSENT_EXPIRED) {\n await expire(access);\n }\n throw error;\n }\n }\n\n return {\n snapshot,\n run: (scope, access, fn) => runChecked(scope, access, (tx) => fn(tx)),\n readAccountKey: (access) => runChecked({ stores: [KV_STORE.device], mode: \"readonly\" }, access, async (_tx, account) => account),\n\n async indexPartition(tx: IDBTransaction, entry: ReplicaPartitionIndexEntry): Promise<void> {\n tx.objectStore(KV_STORE.partitions).put(entry, entry.partitionId);\n },\n\n async unindexPartition(tx: IDBTransaction, partitionId: string): Promise<void> {\n tx.objectStore(KV_STORE.partitions).delete(partitionId);\n },\n\n async clearIntent(tx: IDBTransaction, id: string): Promise<void> {\n tx.objectStore(KV_STORE.purgeIntents).delete(id);\n },\n };\n}\n","/**\n * The browser `ReplicaLifecycleGate` (CONTRACT.md lifecycle): sign-in stamping, deny with purge\n * intents, ordered erase and startup recovery over the origin database's control stores\n * (`gate`, `partitions`, `purgeIntents`, `device`).\n *\n * Main thread only: `deliverable` and the logout marker/tombstone live in `localStorage`, which\n * workers don't have. Gate-mutating paths (establish, deny, recovery delete) take the Web Lock\n * `GATE_LOCK`; without it no mutation proceeds. Every transaction commits whole or aborts.\n */\nimport type {\n ReplicaConsentAnchor,\n ReplicaDeliveryDecision,\n ReplicaDenyInput,\n ReplicaDenyOutcome,\n ReplicaEraseReport,\n ReplicaLifecycleGate,\n ReplicaPartitionEraser,\n ReplicaPartitionIndexEntry,\n ReplicaPurgeIntent,\n ReplicaQuotaLedger,\n ReplicaSessionStamp,\n} from \"@tinycloud/sdk-services/kv/replication\";\nimport { CONSENT_WINDOW_MS, REPLICA_DENY_TOMBSTONE, REPLICA_LOGOUT_MARKER } from \"@tinycloud/sdk-services/kv/replication/contractConstants\";\n\nimport { ReplicaError, ReplicaErrorCode, gatedError } from \"../errors.js\";\nimport { requestAsPromise, transactionDone } from \"../browser/idb.js\";\nimport { ACCOUNT_KEY, GATE_HMAC_KEY, gateHash, newAccountKey, newGateHmac, validAccountKey, validGateHmac, type AccountKeyRecord, type BrowserGate, type GateHmacRecord } from \"./gateKeys.js\";\nimport { createIndexedDbGateTx, withDatabase } from \"./gateTx.js\";\nimport { ERASE_STORES, FIRST_INSTALL_KEY_PREFIX, KV_DATABASE, KV_STORE, kvPartitionEraser, openKvDatabase } from \"./schema.js\";\n\ntype Gate = BrowserGate;\ntype Tx = IDBTransaction;\ntype Stamp = { incarnation: string; lifecycleEpoch: number; consentDeadline: number; principal: string };\ntype DeleteOutcome = { status: \"deleted\" } | { status: \"failed\"; code: string };\ntype Tombstone = { epoch: number; deniedAt: number };\n\nconst ACCOUNT = \"account\";\nconst DEVICE_KEY = \"device\";\nconst GRANT_INSTALL_KEY_PREFIX = \"grantInstall:\";\nconst GATE_LOCK = \"tinycloud-replica-kv:gate\";\nconst DELETE_BLOCKED = \"DELETE_BLOCKED\";\n\n\nexport type DenyFaultPoint = \"deny_tx\" | \"delete_database\";\n\n/**\n * Test seam. `@tinycloud/replica/kv-storage/testing` plans a failure here; production leaves it\n * empty. `once` (default true) removes the plan after its first use.\n */\nexport const denyFaults: Partial<Record<DenyFaultPoint, { once: boolean }>> = {};\n\nfunction takeFault(point: DenyFaultPoint): boolean {\n const fault = denyFaults[point];\n if (fault === undefined) return false;\n if (fault.once) delete denyFaults[point];\n return true;\n}\n\nfunction billedDeviceBytes(row: unknown): number {\n if (row === undefined || (typeof row === \"number\" && Number.isSafeInteger(row) && row >= 0)) return 0;\n if (row !== null && typeof row === \"object\" && \"size\" in row &&\n typeof row.size === \"number\" && Number.isSafeInteger(row.size) && row.size >= 0) {\n return row.size;\n }\n throw gatedError(\"gate_unavailable\", \"A device quota row has no valid encoded size.\");\n}\n\nfunction openKvStore(create: boolean): Promise<IDBDatabase | null> {\n return openKvDatabase({ create });\n}\n\n/** Test-only presence probe. Never returns, clones or exports CryptoKey material. */\nexport async function inspectReplicaKeyPresence(): Promise<{ gateHmac: boolean; accountKey: boolean }> {\n const db = await openKvStore(false);\n if (db === null) return { gateHmac: false, accountKey: false };\n try {\n const device = db.transaction(KV_STORE.device).objectStore(KV_STORE.device);\n const gateHmac = (await requestAsPromise<number>(device.count(GATE_HMAC_KEY))) === 1;\n const accountKey = (await requestAsPromise<number>(device.count(ACCOUNT_KEY))) === 1;\n return { gateHmac, accountKey };\n } finally {\n db.close();\n }\n}\n\ninterface LegacyGateFloor {\n epoch: number;\n deniedAt: number | null;\n}\n\n/** Versionless, readonly v1 probe; no data row is read and a missing DB is never created. */\nasync function readLegacyGateFloor(): Promise<LegacyGateFloor | null> {\n const { promise, resolve, reject } = Promise.withResolvers<LegacyGateFloor | null>();\n const request = indexedDB.open(KV_DATABASE);\n let absent = false;\n request.onupgradeneeded = () => {\n absent = true;\n request.transaction?.abort();\n };\n request.onsuccess = async () => {\n const db = request.result;\n try {\n if (db.version !== 1) return resolve(null);\n if (!db.objectStoreNames.contains(KV_STORE.gate)) return resolve({ epoch: 0, deniedAt: null });\n const value = await requestAsPromise<unknown>(db.transaction(KV_STORE.gate).objectStore(KV_STORE.gate).get(ACCOUNT));\n if (value === undefined) return resolve({ epoch: 0, deniedAt: null });\n if (value === null || typeof value !== \"object\" || !(\"lifecycleEpoch\" in value) || !(\"deniedAt\" in value) ||\n typeof value.lifecycleEpoch !== \"number\" || !Number.isSafeInteger(value.lifecycleEpoch) || value.lifecycleEpoch < 0 ||\n (value.deniedAt !== null && (typeof value.deniedAt !== \"number\" || !Number.isSafeInteger(value.deniedAt) || value.deniedAt < 0)) ||\n (value.lifecycleEpoch === 0) !== (value.deniedAt === null)) {\n throw gatedError(\"gate_unavailable\", \"The legacy gate deny floor is invalid.\");\n }\n resolve({ epoch: value.lifecycleEpoch, deniedAt: value.deniedAt });\n } catch (error) {\n reject(error);\n } finally {\n db.close();\n }\n };\n request.onerror = (event) => {\n if (absent) {\n event.preventDefault();\n resolve(null);\n } else {\n reject(gatedError(\"gate_unavailable\", \"The legacy gate deny floor cannot be read.\"));\n }\n };\n request.onblocked = () => reject(gatedError(\"gate_unavailable\", \"The legacy gate read is blocked.\"));\n return promise;\n}\n\n/** Preserve a legacy denial outside the store before v2 versionchange can destroy its gate. */\nfunction preserveLegacyFloor(legacy: LegacyGateFloor | null, tombstone: Tombstone | null): { tombstone: Tombstone | null; advanced: boolean } {\n if (legacy?.deniedAt === null || legacy === null) return { tombstone, advanced: false };\n const floor = {\n epoch: Math.max(legacy.epoch, tombstone?.epoch ?? 0),\n deniedAt: Math.max(legacy.deniedAt, tombstone?.deniedAt ?? 0),\n };\n if (tombstone !== null && tombstone.epoch >= floor.epoch && tombstone.deniedAt >= floor.deniedAt) {\n return { tombstone, advanced: false };\n }\n writeTombstone(floor);\n return { tombstone: floor, advanced: true };\n}\n\nfunction codeOf(error: unknown): string {\n if (error !== null && typeof error === \"object\" && \"code\" in error && error.code === \"REPLICA_GATED\" && \"gate\" in error && typeof error.gate === \"string\") return error.gate;\n return error !== null && typeof error === \"object\" && \"code\" in error && typeof error.code === \"string\" ? error.code : \"STORAGE_ERROR\";\n}\n\n/** Fail closed: no readable `localStorage` means no proof the logout completed. */\nfunction logoutMarkerSet(): boolean {\n try {\n return localStorage.getItem(REPLICA_LOGOUT_MARKER) !== null;\n } catch {\n return true;\n }\n}\n\n/** Missing is valid only before the first deny. Corruption or denied storage is not. */\nfunction readTombstone(): Tombstone | null {\n try {\n const stored = localStorage.getItem(REPLICA_DENY_TOMBSTONE);\n if (stored === null) return null;\n const value: unknown = JSON.parse(stored);\n if (\n value === null || typeof value !== \"object\" ||\n !(\"epoch\" in value) || typeof value.epoch !== \"number\" || !Number.isSafeInteger(value.epoch) || value.epoch < 1 ||\n !(\"deniedAt\" in value) || typeof value.deniedAt !== \"number\" || !Number.isSafeInteger(value.deniedAt) || value.deniedAt < 0 ||\n Object.keys(value).length !== 2\n ) throw new Error(\"Invalid deny tombstone.\");\n return value as Tombstone;\n } catch {\n throw gatedError(\"gate_unavailable\", \"The origin deny tombstone cannot be read.\");\n }\n}\n\nfunction writeTombstone(value: Tombstone): void {\n try {\n const serialized = JSON.stringify(value);\n localStorage.setItem(REPLICA_DENY_TOMBSTONE, serialized);\n if (localStorage.getItem(REPLICA_DENY_TOMBSTONE) !== serialized) throw new Error(\"The deny tombstone was not persisted.\");\n } catch {\n throw gatedError(\"gate_unavailable\", \"The origin deny tombstone cannot be written.\");\n }\n}\n\n/** A readable but read-only origin must not establish a session it could not later deny. */\nfunction assertTombstoneWritable(): void {\n try {\n const stored = localStorage.getItem(REPLICA_DENY_TOMBSTONE);\n if (stored === null) {\n const probe = `${REPLICA_DENY_TOMBSTONE}:probe`;\n localStorage.setItem(probe, \"1\");\n if (localStorage.getItem(probe) !== \"1\") throw new Error(\"The deny tombstone probe was not persisted.\");\n localStorage.removeItem(probe);\n } else {\n localStorage.setItem(REPLICA_DENY_TOMBSTONE, stored);\n if (localStorage.getItem(REPLICA_DENY_TOMBSTONE) !== stored) throw new Error(\"The deny tombstone was not persisted.\");\n }\n } catch {\n throw gatedError(\"gate_unavailable\", \"The origin deny tombstone cannot be written.\");\n }\n}\n\nfunction denyFloor(gate: Gate | undefined, tombstone: Tombstone | null): { epoch: number; deniedAt: number | null } {\n if (gate !== undefined && tombstone === null && (gate.lifecycleEpoch > 0 || gate.deniedAt !== null)) {\n throw gatedError(\"gate_unavailable\", \"A denied gate has no origin deny tombstone.\");\n }\n if (gate !== undefined && tombstone !== null && gate.lifecycleEpoch < tombstone.epoch) {\n throw gatedError(\"gate_unavailable\", \"The gate is behind the origin deny tombstone.\");\n }\n return {\n epoch: Math.max(gate?.lifecycleEpoch ?? 0, tombstone?.epoch ?? 0),\n deniedAt: gate?.deniedAt === null || gate?.deniedAt === undefined\n ? tombstone?.deniedAt ?? null\n : Math.max(gate.deniedAt, tombstone?.deniedAt ?? 0),\n };\n}\n\n\nfunction exclusive<T>(name: string, section: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n if (typeof navigator === \"undefined\" || typeof navigator.locks?.request !== \"function\") {\n return Promise.reject(gatedError(\"gate_unavailable\", \"The origin Web Lock is unavailable.\"));\n }\n return signal === undefined\n ? navigator.locks.request(name, section)\n : navigator.locks.request(name, { signal }, section);\n}\n\nfunction deleteKvDatabase(): Promise<DeleteOutcome> {\n const { promise, resolve } = Promise.withResolvers<DeleteOutcome>();\n if (takeFault(\"delete_database\")) {\n resolve({ status: \"failed\", code: \"STORAGE_ERROR\" });\n return promise;\n }\n const request = indexedDB.deleteDatabase(KV_DATABASE);\n request.onsuccess = () => resolve({ status: \"deleted\" });\n request.onerror = () => resolve({ status: \"failed\", code: \"STORAGE_ERROR\" });\n // The request stays queued and may still complete later; the marker covers that until a retry\n // confirms the delete.\n request.onblocked = () => resolve({ status: \"failed\", code: DELETE_BLOCKED });\n return promise;\n}\n\nfunction setLogoutMarker(): boolean {\n try {\n const marker = String(Date.now());\n localStorage.setItem(REPLICA_LOGOUT_MARKER, marker);\n return localStorage.getItem(REPLICA_LOGOUT_MARKER) === marker;\n } catch {\n return false;\n }\n}\n\n/**\n * Runs `use` in one transaction. `use` may only await requests on `tx`. A throw aborts the\n * transaction so nothing partial commits, then rethrows. Resolves only after `oncomplete`.\n */\nasync function transact<T>(db: IDBDatabase, stores: string[], mode: IDBTransactionMode, use: (tx: Tx) => Promise<T>): Promise<T> {\n const tx = db.transaction(stores, mode, { durability: \"strict\" });\n const done = transactionDone(tx);\n let value: T;\n try {\n value = await use(tx);\n } catch (error) {\n try {\n tx.abort();\n } catch {\n // Already finished.\n }\n await done.catch(() => undefined);\n throw error;\n }\n await done;\n return value;\n}\n\nexport interface BrowserReplicaLifecycle extends ReplicaLifecycleGate {\n consentDeadline(stamp: ReplicaSessionStamp): number | null;\n subscribeConsentExpired(listener: (stamp: ReplicaSessionStamp) => void): () => void;\n expireConsent(): Promise<ReplicaDenyOutcome>;\n}\n\nexport function createIndexedDbLifecycle(options: {\n eraser?: ReplicaPartitionEraser<Tx>;\n ledger?: Pick<ReplicaQuotaLedger<Tx>, \"accountErase\">;\n now?: () => number;\n onConsentExpired?: (stamp: ReplicaSessionStamp) => void;\n} = {}): BrowserReplicaLifecycle {\n const eraser = options.eraser ?? kvPartitionEraser;\n const ledger = options.ledger;\n const now = options.now ?? Date.now;\n function checkedNow(): number {\n const at = now();\n if (!Number.isSafeInteger(at) || at < 0) throw gatedError(\"gate_unavailable\", \"The replica clock is unavailable.\");\n return at;\n }\n\n function deadlineOf(gate: Gate): number {\n const deadline = gate.consentDeadline;\n if (typeof deadline !== \"number\" || !Number.isSafeInteger(deadline) || deadline < 0) {\n throw gatedError(\"gate_unavailable\", \"The account gate has no valid consent deadline.\");\n }\n return deadline;\n }\n\n const gateTx = createIndexedDbGateTx(openKvStore, { now, onConsentExpired: expireConsent });\n let view: Stamp | undefined;\n let expiryTimer: Parameters<typeof clearTimeout>[0];\n const expiryObservers = new Set<(stamp: ReplicaSessionStamp) => void>();\n\n function adopt(gate: Gate, principal: string): ReplicaSessionStamp {\n const stamp = { incarnation: gate.incarnation, lifecycleEpoch: gate.lifecycleEpoch };\n view = { ...stamp, consentDeadline: deadlineOf(gate), principal: principal.toLowerCase() };\n clearTimeout(expiryTimer);\n armExpiryTimer();\n return stamp;\n }\n\n function armExpiryTimer(): void {\n if (view === undefined) return;\n const delay = Math.max(0, Math.min(view.consentDeadline - checkedNow(), 2_147_483_647));\n expiryTimer = setTimeout(() => {\n expiryTimer = undefined;\n if (view === undefined) return;\n try {\n if (checkedNow() < view.consentDeadline) armExpiryTimer();\n else void expireConsent();\n } catch {\n view = undefined;\n }\n }, delay);\n }\n\n async function readGate(): Promise<Gate | undefined> {\n const found = await withDatabase(openKvStore, false, (db) =>\n requestAsPromise<Gate | undefined>(db.transaction(KV_STORE.gate).objectStore(KV_STORE.gate).get(ACCOUNT)),\n );\n return found ?? undefined;\n }\n\n async function activeKeys(gate: Gate): Promise<{ hash: GateHmacRecord; account: AccountKeyRecord }> {\n const records = await withDatabase(openKvStore, false, async (db) => {\n const device = db.transaction(KV_STORE.device).objectStore(KV_STORE.device);\n const hash = await requestAsPromise<GateHmacRecord | undefined>(device.get(GATE_HMAC_KEY));\n const account = await requestAsPromise<AccountKeyRecord | undefined>(device.get(ACCOUNT_KEY));\n return { hash, account };\n });\n if (records === null || !validGateHmac(records.hash, gate) || !validAccountKey(records.account, gate)) {\n throw gatedError(\"gate_unavailable\", \"The account gate encryption keys are missing or mismatched.\");\n }\n return { hash: records.hash, account: records.account };\n }\n\n async function readIntents(): Promise<ReplicaPurgeIntent[]> {\n const found = await withDatabase(openKvStore, false, (db) =>\n requestAsPromise<ReplicaPurgeIntent[]>(db.transaction(KV_STORE.purgeIntents).objectStore(KV_STORE.purgeIntents).getAll()),\n );\n return found ?? [];\n }\n\n async function writeGate(gate: Gate, previous: Gate | undefined, keys: { hash: GateHmacRecord; account: AccountKeyRecord }): Promise<void> {\n const db = await openKvStore(true);\n if (db === null) throw gatedError(\"gate_unavailable\", \"The origin database could not be created.\");\n try {\n await transact(db, [KV_STORE.gate, KV_STORE.device], \"readwrite\", async (tx) => {\n const current = await requestAsPromise<Gate | undefined>(tx.objectStore(KV_STORE.gate).get(ACCOUNT));\n if (current?.incarnation !== previous?.incarnation || current?.lifecycleEpoch !== previous?.lifecycleEpoch || current?.principalHash !== previous?.principalHash) {\n throw gatedError(\"stamp_stale\", \"The origin gate changed during establishment.\");\n }\n const device = tx.objectStore(KV_STORE.device);\n device.put(keys.hash, GATE_HMAC_KEY);\n device.put(keys.account, ACCOUNT_KEY);\n tx.objectStore(KV_STORE.gate).put(gate, ACCOUNT);\n });\n } finally {\n db.close();\n }\n }\n\n async function establishSessionStamp(principal: string, o: { consentAnchor: ReplicaConsentAnchor }): Promise<ReplicaSessionStamp> {\n return exclusive(GATE_LOCK, async () => {\n const tombstone = readTombstone();\n if (logoutMarkerSet()) throw gatedError(\"logout_pending\", \"A logout is still pending on this origin.\");\n const anchor = o.consentAnchor;\n if (anchor === undefined ||\n (anchor.source !== \"siwe\" && anchor.source !== \"delegation_iat\" && anchor.source !== \"delegation_nbf\") ||\n !Number.isSafeInteger(anchor.at) || anchor.at < 0) {\n throw gatedError(\"not_established\", \"A verified finite consent anchor is required.\");\n }\n const issuedAt = Math.min(anchor.at, checkedNow());\n if ((await readIntents()).length > 0) throw gatedError(\"purge_pending\", \"A purge is still pending on this origin.\");\n const current = await readGate();\n const legacy = current === undefined ? await readLegacyGateFloor() : null;\n const preserved = preserveLegacyFloor(legacy, tombstone);\n const floor = denyFloor(current, preserved.tombstone);\n if (preserved.advanced) throw gatedError(\"stamp_stale\", \"The legacy deny floor was preserved; a new consent proof is required.\");\n if (floor.deniedAt !== null && issuedAt <= floor.deniedAt) {\n throw gatedError(\"stamp_stale\", \"This sign-in predates the last sign-out.\");\n }\n assertTombstoneWritable();\n if (current === undefined || current.principalHash === null) {\n const incarnation = crypto.randomUUID();\n const hash = await newGateHmac(incarnation);\n const principalHash = await gateHash(hash.hmac, \"principal\", principal.toLowerCase());\n const account = await newAccountKey(incarnation, floor.epoch, principalHash);\n const created: Gate = {\n incarnation,\n salt: crypto.randomUUID(),\n principalHash,\n lifecycleEpoch: floor.epoch,\n deniedAt: floor.deniedAt,\n keyId: hash.keyId,\n accountKeyId: account.keyId,\n consentDeadline: issuedAt + CONSENT_WINDOW_MS,\n };\n if (!Number.isSafeInteger(created.consentDeadline)) throw gatedError(\"not_established\", \"The consent deadline is invalid.\");\n await writeGate(created, current, { hash, account });\n return adopt(created, principal);\n }\n const keys = await activeKeys(current);\n const principalHash = await gateHash(keys.hash.hmac, \"principal\", principal.toLowerCase());\n if (current.principalHash !== principalHash) throw gatedError(\"principal_mismatch\", \"The origin is bound to another account.\");\n if (checkedNow() >= deadlineOf(current)) {\n await expireConsentLocked();\n throw new ReplicaError(ReplicaErrorCode.CONSENT_EXPIRED, \"The account consent has expired.\");\n }\n return adopt(current, principal);\n });\n }\n\n async function restoreSessionStamp(principal: string, persisted: ReplicaSessionStamp | undefined): Promise<ReplicaSessionStamp> {\n const gate = await readGate();\n denyFloor(gate, readTombstone());\n if (gate === undefined || persisted === undefined) throw gatedError(\"not_established\", \"No session stamp is established for this origin.\");\n if (\n typeof persisted !== \"object\" || persisted === null || Array.isArray(persisted) ||\n Object.keys(persisted).length !== 2 ||\n !Object.prototype.hasOwnProperty.call(persisted, \"incarnation\") ||\n !Object.prototype.hasOwnProperty.call(persisted, \"lifecycleEpoch\") ||\n typeof persisted.incarnation !== \"string\" || persisted.incarnation.length === 0 ||\n !Number.isSafeInteger(persisted.lifecycleEpoch) || persisted.lifecycleEpoch < 0\n ) {\n throw gatedError(\"stamp_stale\", \"The persisted replica stamp is malformed.\");\n }\n if (persisted.incarnation !== gate.incarnation || persisted.lifecycleEpoch !== gate.lifecycleEpoch) {\n throw gatedError(\"stamp_stale\", \"The persisted session stamp is stale.\");\n }\n if (gate.principalHash === null) throw gatedError(\"principal_mismatch\", \"The origin has no active account.\");\n const keys = await activeKeys(gate);\n const hash = await gateHash(keys.hash.hmac, \"principal\", principal.toLowerCase());\n if (hash !== gate.principalHash) throw gatedError(\"principal_mismatch\", \"The origin is bound to another account.\");\n if (logoutMarkerSet()) throw gatedError(\"logout_pending\", \"A logout is still pending on this origin.\");\n if ((await readIntents()).length > 0) throw gatedError(\"purge_pending\", \"A purge is still pending on this origin.\");\n assertTombstoneWritable();\n if (checkedNow() >= deadlineOf(gate)) {\n await expireConsent();\n throw new ReplicaError(ReplicaErrorCode.CONSENT_EXPIRED, \"The account consent has expired.\");\n }\n return adopt(gate, principal);\n }\n\n async function activationAllowed(next: string): Promise<boolean> {\n try {\n if (logoutMarkerSet()) return false;\n const gate = await readGate();\n denyFloor(gate, readTombstone());\n if (gate === undefined || gate.principalHash === null) return false;\n if (checkedNow() >= deadlineOf(gate)) {\n await expireConsent();\n return false;\n }\n const keys = await activeKeys(gate);\n const hash = await gateHash(keys.hash.hmac, \"principal\", next.toLowerCase());\n if (hash !== gate.principalHash) return false;\n return (await readIntents()).every((intent) => intent.principalHash === hash);\n } catch {\n return false;\n }\n }\n\n function checkDelivery(stamp: ReplicaSessionStamp): ReplicaDeliveryDecision {\n if (stamp === undefined) return { status: \"gated\", gate: \"not_established\" };\n if (view === undefined) return { status: \"gated\", gate: \"stamp_stale\" };\n if (view.incarnation !== stamp.incarnation || view.lifecycleEpoch !== stamp.lifecycleEpoch) {\n return { status: \"gated\", gate: \"stamp_stale\" };\n }\n try {\n const tombstone = readTombstone();\n if (logoutMarkerSet()) return { status: \"gated\", gate: \"logout_pending\" };\n if (tombstone === null && stamp.lifecycleEpoch !== 0) return { status: \"gated\", gate: \"gate_unavailable\" };\n if (tombstone !== null && stamp.lifecycleEpoch < tombstone.epoch) return { status: \"gated\", gate: \"stamp_stale\" };\n if (checkedNow() >= view.consentDeadline) return { status: \"consent_expired\", code: \"CONSENT_EXPIRED\" };\n return { status: \"allow\" };\n } catch {\n return { status: \"gated\", gate: \"gate_unavailable\" };\n }\n }\n\n function consentDeadline(stamp: ReplicaSessionStamp): number | null {\n return view !== undefined && checkDelivery(stamp).status === \"allow\"\n ? view.consentDeadline\n : null;\n }\n\n function deliverable(stamp: ReplicaSessionStamp): boolean {\n return checkDelivery(stamp).status === \"allow\";\n }\n\n /**\n * One transaction: moves the gate to the already persisted origin deny floor, records intents\n * for the caller, and removes its device, first-install and durable grant-install anchors.\n */\n async function commitDeny(plan: { gate: Gate; callerHash: string; tombstone: Tombstone }): Promise<ReplicaDenyOutcome> {\n if (takeFault(\"deny_tx\")) throw new Error(\"injected deny_tx failure\");\n const db = await openKvStore(false);\n if (db === null) return { status: \"stale\" };\n try {\n return await transact<ReplicaDenyOutcome>(\n db,\n [KV_STORE.gate, KV_STORE.partitions, KV_STORE.purgeIntents, KV_STORE.device, KV_STORE.pending, KV_STORE.quota],\n \"readwrite\",\n async (tx) => {\n const current = await requestAsPromise<Gate | undefined>(tx.objectStore(KV_STORE.gate).get(ACCOUNT));\n if (\n current === undefined ||\n current.incarnation !== plan.gate.incarnation ||\n current.principalHash !== plan.callerHash ||\n current.lifecycleEpoch !== plan.gate.lifecycleEpoch ||\n current.keyId !== plan.gate.keyId ||\n current.accountKeyId !== plan.gate.accountKeyId\n ) {\n return { status: \"stale\" };\n }\n const now = plan.tombstone.deniedAt;\n const partitions = await requestAsPromise<ReplicaPartitionIndexEntry[]>(tx.objectStore(KV_STORE.partitions).getAll());\n const pendingKeys = await requestAsPromise<IDBValidKey[]>(tx.objectStore(KV_STORE.pending).getAllKeys());\n\n const intents: ReplicaPurgeIntent[] = [];\n const identities = new Set<string>();\n for (const entry of partitions) {\n if (entry.principalHash !== plan.callerHash) continue;\n intents.push({ id: entry.partitionId, kind: \"partition\", partitionId: entry.partitionId, principalHash: plan.callerHash, recordedAt: now });\n identities.add(entry.identityKeyHash);\n }\n // Activation never admits another principal while old purge intents remain.\n // Pending values may be sealed; only the opaque keys are needed for erase.\n for (const key of pendingKeys) {\n if (typeof key === \"string\") identities.add(key);\n }\n for (const identityKeyHash of identities) {\n intents.push({ id: `pending:${identityKeyHash}`, kind: \"pending\", identityKeyHash, principalHash: plan.callerHash, recordedAt: now });\n }\n\n const purge = tx.objectStore(KV_STORE.purgeIntents);\n for (const intent of intents) purge.put(intent, intent.id);\n const device = tx.objectStore(KV_STORE.device);\n let deviceBytes = billedDeviceBytes(await requestAsPromise<unknown>(device.get(DEVICE_KEY)));\n device.delete(DEVICE_KEY);\n device.delete(ACCOUNT_KEY);\n device.delete(GATE_HMAC_KEY);\n for (const prefix of [FIRST_INSTALL_KEY_PREFIX, GRANT_INSTALL_KEY_PREFIX]) {\n const keys = await requestAsPromise<IDBValidKey[]>(device.getAllKeys(IDBKeyRange.bound(prefix, `${prefix}\\uffff`)));\n for (const key of keys) {\n deviceBytes += billedDeviceBytes(await requestAsPromise<unknown>(device.get(key)));\n if (!Number.isSafeInteger(deviceBytes)) throw gatedError(\"gate_unavailable\", \"Device quota bytes overflow.\");\n device.delete(key);\n }\n }\n await ledger?.accountErase(tx, { partitionId: \"device\", bytes: deviceBytes });\n\n const next: Gate = {\n ...current,\n principalHash: null,\n consentDeadline: null,\n lifecycleEpoch: plan.tombstone.epoch,\n deniedAt: plan.tombstone.deniedAt,\n };\n tx.objectStore(KV_STORE.gate).put(next, ACCOUNT);\n return { status: \"denied\", lifecycleEpoch: next.lifecycleEpoch, intents: intents.length };\n },\n );\n } finally {\n db.close();\n }\n }\n\n /** Commit failed: delete the whole origin database. Blocked or failed delete: set the marker. */\n async function wipe(): Promise<Extract<ReplicaDenyOutcome, { status: \"deleted\" | \"marker\" | \"unguarded\" }>> {\n const deleted = await deleteKvDatabase();\n if (deleted.status === \"deleted\") return { status: \"deleted\" };\n return setLogoutMarker() ? { status: \"marker\", code: deleted.code } : { status: \"unguarded\", code: deleted.code };\n }\n\n async function advanceDeny(gate: Gate, floor: { epoch: number; deniedAt: number | null }): Promise<ReplicaDenyOutcome> {\n const callerHash = gate.principalHash;\n if (callerHash === null) return { status: \"stale\" };\n const tombstone = { epoch: floor.epoch + 1, deniedAt: Math.max(checkedNow(), (floor.deniedAt ?? -1) + 1) };\n if (!Number.isSafeInteger(tombstone.epoch) || !Number.isSafeInteger(tombstone.deniedAt)) {\n throw gatedError(\"gate_unavailable\", \"The origin deny tombstone cannot advance.\");\n }\n writeTombstone(tombstone);\n try {\n return await commitDeny({ gate, callerHash, tombstone });\n } catch {\n return wipe();\n }\n }\n\n async function denyLocked(input: ReplicaDenyInput): Promise<ReplicaDenyOutcome> {\n const gate = await readGate();\n const floor = denyFloor(gate, readTombstone());\n if (gate === undefined || gate.principalHash === null) return { status: \"stale\" };\n const keys = await activeKeys(gate);\n const callerHash = await gateHash(keys.hash.hmac, \"principal\", input.principal.toLowerCase());\n if (callerHash !== gate.principalHash) return { status: \"stale\" };\n if (input.reason === \"account_switch\" && input.next === undefined) {\n throw new Error(\"account_switch requires the next principal\");\n }\n return advanceDeny(gate, floor);\n }\n\n async function expireConsentLocked(): Promise<ReplicaDenyOutcome> {\n const gate = await readGate();\n const floor = denyFloor(gate, readTombstone());\n if (gate === undefined || gate.principalHash === null) return { status: \"stale\" };\n if (checkedNow() < deadlineOf(gate)) return { status: \"stale\" };\n const stamp = { incarnation: gate.incarnation, lifecycleEpoch: gate.lifecycleEpoch };\n view = undefined;\n clearTimeout(expiryTimer);\n const result = await advanceDeny(gate, floor);\n if (result.status === \"denied\" || result.status === \"deleted\") {\n try {\n options.onConsentExpired?.(stamp);\n } catch {\n // An observer cannot undo a committed denial or relabel it as an unguarded gate.\n }\n for (const observer of expiryObservers) {\n try {\n observer(stamp);\n } catch {\n // Other subscribers still observe this committed denial.\n }\n }\n }\n return result;\n }\n\n async function expireConsent(): Promise<ReplicaDenyOutcome> {\n try {\n return await exclusive(GATE_LOCK, expireConsentLocked);\n } catch (error) {\n return { status: \"unguarded\", code: codeOf(error) };\n }\n }\n\n async function deny(input: ReplicaDenyInput): Promise<ReplicaDenyOutcome> {\n // Disable this tab before the first await, but never clear a successor's view\n // when a delayed sign-out from a previous account arrives.\n if (view?.principal === input.principal.toLowerCase()) {\n view = undefined;\n clearTimeout(expiryTimer);\n }\n try {\n return await exclusive(GATE_LOCK, () => denyLocked(input));\n } catch (error) {\n return { status: \"unguarded\", code: codeOf(error) };\n }\n }\n\n /** One exempt transaction per intent. A thrown error aborts it, so nothing partial commits. */\n async function eraseIntent(intent: ReplicaPurgeIntent): Promise<void> {\n const db = await openKvStore(false);\n if (db === null) return;\n try {\n await transact(db, [...ERASE_STORES, KV_STORE.partitions, KV_STORE.purgeIntents, KV_STORE.quota], \"readwrite\", async (tx) => {\n if (intent.kind === \"partition\") {\n const { bytes } = await eraser.erasePartition(tx, intent.partitionId);\n await gateTx.unindexPartition(tx, intent.partitionId);\n await ledger?.accountErase(tx, { partitionId: intent.partitionId, bytes });\n } else {\n await eraser.eraseIdentityPending(tx, intent.identityKeyHash);\n }\n await gateTx.clearIntent(tx, intent.id);\n });\n } finally {\n db.close();\n }\n }\n\n async function erasePendingLocked({ signal }: { signal: AbortSignal }): Promise<ReplicaEraseReport> {\n const erased: string[] = [];\n const failed: Array<{ id: string; code: string }> = [];\n for (const intent of await readIntents()) {\n if (signal.aborted) break;\n try {\n await eraseIntent(intent);\n erased.push(intent.id);\n } catch (error) {\n failed.push({ id: intent.id, code: codeOf(error) });\n }\n }\n return { erased, failed, remaining: (await readIntents()).length };\n }\n\n function erasePending(o: { signal: AbortSignal }): Promise<ReplicaEraseReport> {\n return exclusive(GATE_LOCK, () => erasePendingLocked(o));\n }\n\n async function recover({ signal }: { signal: AbortSignal }): Promise<ReplicaEraseReport> {\n try {\n return await exclusive(GATE_LOCK, async () => {\n const failed: Array<{ id: string; code: string }> = [];\n if (logoutMarkerSet()) {\n // A marker without a durable deny floor cannot authorize destruction of the last gate.\n if (readTombstone() === null) throw gatedError(\"gate_unavailable\", \"The pending logout has no deny tombstone.\");\n const deleted = await deleteKvDatabase();\n if (deleted.status === \"deleted\") {\n try {\n localStorage.removeItem(REPLICA_LOGOUT_MARKER);\n if (localStorage.getItem(REPLICA_LOGOUT_MARKER) !== null) throw new Error(\"The logout marker was not cleared.\");\n } catch {\n failed.push({ id: \"marker\", code: \"STORAGE_ERROR\" });\n }\n } else {\n failed.push({ id: \"database\", code: deleted.code });\n }\n }\n if (failed.length > 0) return { erased: [], failed, remaining: 1 };\n // A crash between persisting the tombstone and committing the denial leaves\n // an older gate behind. The external floor already authorizes a full wipe.\n const gate = await readGate();\n const tombstone = readTombstone();\n if (gate !== undefined && tombstone !== null && gate.lifecycleEpoch < tombstone.epoch) {\n const wiped = await wipe();\n if (wiped.status !== \"deleted\") {\n return { erased: [], failed: [{ id: \"database\", code: wiped.code }], remaining: 1 };\n }\n }\n const legacy = await readLegacyGateFloor();\n if (legacy !== null) {\n const tombstone = readTombstone();\n preserveLegacyFloor(legacy, tombstone);\n assertTombstoneWritable();\n const db = await openKvStore(true);\n if (db === null) throw gatedError(\"gate_unavailable\", \"The legacy origin could not be migrated.\");\n db.close();\n }\n const expiry = await expireConsentLocked();\n if (expiry.status === \"marker\" || expiry.status === \"unguarded\") {\n return { erased: [], failed: [{ id: \"expiry\", code: expiry.code }], remaining: 1 };\n }\n const pass = await erasePendingLocked({ signal });\n return { erased: pass.erased, failed: [...failed, ...pass.failed], remaining: pass.remaining, consentExpired: expiry.status === \"denied\" || expiry.status === \"deleted\" };\n }, signal);\n } catch (error) {\n // Outcome unknown: report one outstanding intent so `purgePending` stays set.\n return { erased: [], failed: [{ id: \"recover\", code: codeOf(error) }], remaining: 1 };\n }\n }\n\n function subscribeConsentExpired(listener: (stamp: ReplicaSessionStamp) => void): () => void {\n expiryObservers.add(listener);\n return () => { expiryObservers.delete(listener); };\n }\n\n return {\n kind: \"indexeddb\",\n recover,\n expireConsent,\n checkDelivery,\n consentDeadline,\n subscribeConsentExpired,\n establishSessionStamp,\n restoreSessionStamp,\n activationAllowed,\n deliverable,\n deny,\n erasePending,\n pendingPurge: readIntents,\n };\n}\n","import { bytesToHex, hexToBytes } from \"@noble/hashes/utils\";\n\nimport { ReplicaError, ReplicaErrorCode } from \"../errors.js\";\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder(\"utf-8\", { fatal: true });\nconst HASH_BYTES = 64;\n\n/** Typed arrays and user objects occupy different wire variants, even when a user key resembles a marker. */\nfunction encodeValue(value: unknown): unknown {\n if (value === undefined) return [\"undefined\"];\n if (value instanceof Uint8Array) return [\"bytes\", bytesToHex(value)];\n if (Array.isArray(value)) return [\"array\", value.map(encodeValue)];\n if (value !== null && typeof value === \"object\") {\n return [\"object\", Object.entries(value).map(([key, item]) => [key, encodeValue(item)])];\n }\n if (typeof value === \"number\" && !Number.isFinite(value)) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"A replica record contains a non-finite number.\");\n }\n if (value === null || typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") return value;\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"A replica record contains an unsupported value.\");\n}\n\nfunction decodeValue(value: unknown): unknown {\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value))) return value;\n if (!Array.isArray(value) || typeof value[0] !== \"string\") throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica record has an invalid payload variant.\");\n if (value[0] === \"undefined\" && value.length === 1) return undefined;\n if (value[0] === \"bytes\" && value.length === 2 && typeof value[1] === \"string\" && /^(?:[0-9a-f]{2})*$/.test(value[1])) return hexToBytes(value[1]);\n if (value[0] === \"array\" && value.length === 2 && Array.isArray(value[1])) return value[1].map(decodeValue);\n if (value[0] === \"object\" && value.length === 2 && Array.isArray(value[1])) {\n const seen = new Set<string>();\n const fields: Array<[string, unknown]> = [];\n for (const pair of value[1]) {\n if (!Array.isArray(pair) || pair.length !== 2 || typeof pair[0] !== \"string\" || seen.has(pair[0])) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica record has an invalid object field.\");\n }\n seen.add(pair[0]);\n fields.push([pair[0], decodeValue(pair[1])]);\n }\n return Object.fromEntries(fields);\n }\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica record has an invalid payload variant.\");\n}\n\nexport function encodeJson(value: unknown): Uint8Array {\n return encoder.encode(JSON.stringify([\"tinycloud-replica-kv\", 1, encodeValue(value)]));\n}\n\nexport function decodeJson<T>(bytes: Uint8Array): T {\n try {\n const value: unknown = JSON.parse(decoder.decode(bytes));\n if (!Array.isArray(value) || value.length !== 3 || value[0] !== \"tinycloud-replica-kv\" || value[1] !== 1) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica record has an unknown payload version.\");\n }\n return decodeValue(value[2]) as T;\n } catch (cause) {\n if (cause instanceof ReplicaError) throw cause;\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica record payload is corrupt.\", undefined, { cause });\n }\n}\n\n/** Binds the original content hash inside authenticated plaintext, not just to its opaque IDB key. */\nexport function encodeBlob(hash: string, bytes: Uint8Array): Uint8Array {\n if (!/^[0-9a-f]{64}$/.test(hash)) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"Invalid content hash in the replica record.\");\n const content = new Uint8Array(HASH_BYTES + bytes.length);\n content.set(encoder.encode(hash));\n content.set(bytes, HASH_BYTES);\n return content;\n}\n\nexport function decodeBlob(content: Uint8Array): { hash: string; bytes: Uint8Array } {\n if (content.length < HASH_BYTES) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica content record is truncated.\");\n const hash = decoder.decode(content.subarray(0, HASH_BYTES));\n if (!/^[0-9a-f]{64}$/.test(hash)) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"Invalid content hash in the replica record.\");\n return { hash, bytes: content.subarray(HASH_BYTES) };\n}\n","/**\n * Identity-scoped pending writes: private gate-HMAC row names and Web Locks,\n * account-key sealed content, and gated compare-and-swap transactions.\n * A missing key or moved gate never falls back to an unlocked/plaintext store.\n */\nimport {\n canonicalReplicationIdentity,\n replicationIdentityKey,\n type PendingWriteState,\n type PendingWriteStore,\n type ReplicaBrowserGateAccess,\n type ReplicaSessionStamp,\n type ReplicationIdentity,\n} from \"@tinycloud/sdk-services/kv/replication\";\nimport { REPLICA_PENDING_LOCK_PREFIX } from \"@tinycloud/sdk-services/kv/replication/contractConstants\";\n\nimport { ReplicaError, ReplicaErrorCode, gatedError } from \"../errors.js\";\nimport { requestAsPromise } from \"../browser/idb.js\";\nimport { decodeJson, encodeJson } from \"./codec.js\";\nimport { gateHash } from \"./gateKeys.js\";\nimport type { BrowserReplicaGateTx } from \"./gateTx.js\";\nimport { KV_STORE } from \"./schema.js\";\nimport { measureSealedRow, openSealed, seal, type SealedRecord } from \"./sealed.js\";\n\ntype SealedPending = SealedRecord & { size: number };\n\ntype Locks = Pick<LockManager, \"request\">;\n\nfunction corrupt(message: string): ReplicaError {\n return new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, message);\n}\n\nexport class IndexedDbPendingWriteStore implements PendingWriteStore {\n readonly durable = true;\n readonly identity: ReplicationIdentity;\n readonly #identityKey: string;\n readonly #gateTx: BrowserReplicaGateTx | undefined;\n readonly #stamp: ReplicaSessionStamp | undefined;\n readonly #locks: Locks | undefined;\n\n constructor(identity: ReplicationIdentity, options: { gateTx?: BrowserReplicaGateTx; stamp?: ReplicaSessionStamp; locks?: Locks } = {}) {\n this.identity = canonicalReplicationIdentity(identity);\n this.#identityKey = replicationIdentityKey(this.identity);\n this.#gateTx = options.gateTx;\n this.#stamp = options.stamp;\n this.#locks = options.locks ?? (typeof navigator === \"undefined\" ? undefined : navigator.locks);\n }\n\n #empty(): PendingWriteState {\n return { v: 2, identity: this.identity, committedEpoch: 0, seq: 0, records: [] };\n }\n\n /** Validate a stored record: the v2 shape, and this store's identity (never another's). */\n #parse(value: unknown): PendingWriteState {\n if (\n value === null ||\n typeof value !== \"object\" ||\n !(\"v\" in value) ||\n value.v !== 2 ||\n !(\"identity\" in value) ||\n !(\"committedEpoch\" in value) ||\n typeof value.committedEpoch !== \"number\" ||\n !(\"seq\" in value) ||\n typeof value.seq !== \"number\" ||\n !(\"records\" in value) ||\n !Array.isArray(value.records)\n ) {\n throw corrupt(\"The pending-write state is corrupt.\");\n }\n let storedKey: string | undefined;\n try {\n storedKey = replicationIdentityKey(value.identity as ReplicationIdentity);\n } catch {\n storedKey = undefined;\n }\n if (storedKey !== this.#identityKey) throw corrupt(\"The pending-write state belongs to a different identity.\");\n return value as PendingWriteState;\n }\n\n async #access(): Promise<{ gateTx: BrowserReplicaGateTx; access: ReplicaBrowserGateAccess; id: string }> {\n const gateTx = this.#gateTx;\n if (gateTx === undefined) throw gatedError(\"gate_unavailable\", \"No lifecycle gate is wired into the pending-write store.\");\n const stamp = this.#stamp;\n if (stamp === undefined) throw gatedError(\"not_established\", \"The pending-write store has no session stamp.\");\n const snapshot = await gateTx.snapshot();\n if (snapshot === null) throw gatedError(\"not_established\", \"No replica gate exists on this origin yet.\");\n const identityKeyHash = await gateHash(snapshot.gateHmac, \"identity\", this.#identityKey);\n const principalHash = await gateHash(snapshot.gateHmac, \"principal\", this.identity.principal.toLowerCase());\n return {\n gateTx,\n id: identityKeyHash,\n access: {\n stamp, incarnation: snapshot.incarnation, keyId: snapshot.keyId,\n accountKeyId: snapshot.accountKeyId, principalHash, identityKeyHash,\n },\n };\n }\n\n async #stored(): Promise<PendingWriteState | undefined> {\n const gated = await this.#access();\n const { gateTx, access, id } = gated;\n const row = await gateTx.run({ stores: [KV_STORE.pending], mode: \"readonly\" }, access, (tx) =>\n requestAsPromise<SealedPending | undefined>(tx.objectStore(KV_STORE.pending).get(id)));\n if (row === undefined) return undefined;\n const account = await gateTx.readAccountKey(access);\n return this.#parse(decodeJson(await openSealed(account.aesGcm, row, `pending\\0${id}`)));\n }\n\n async read(): Promise<PendingWriteState> {\n return (await this.#stored()) ?? this.#empty();\n }\n\n async readExisting(): Promise<PendingWriteState | undefined> {\n return this.#stored();\n }\n\n async update<T>(mutate: (state: PendingWriteState) => T): Promise<T> {\n const gated = await this.#access();\n const { gateTx, access, id } = gated;\n if (this.#locks === undefined) throw gatedError(\"gate_unavailable\", \"Web Locks are required for pending-write mutations.\");\n const section = async (): Promise<T> => {\n const old = await gateTx.run({ stores: [KV_STORE.pending], mode: \"readonly\" }, access, (tx) =>\n requestAsPromise<SealedPending | undefined>(tx.objectStore(KV_STORE.pending).get(id)));\n const account = await gateTx.readAccountKey(access);\n const state = old === undefined ? this.#empty() : this.#parse(decodeJson(await openSealed(account.aesGcm, old, `pending\\0${id}`)));\n const result = mutate(state);\n const sealed = await seal(account.aesGcm, encodeJson(state), `pending\\0${id}`);\n const row = { ...sealed, size: 0 };\n row.size = measureSealedRow(id, row);\n await gateTx.run({ stores: [KV_STORE.pending], mode: \"readwrite\" }, access, async (tx) => {\n const pending = tx.objectStore(KV_STORE.pending);\n const current = await requestAsPromise<SealedPending | undefined>(pending.get(id));\n if ((old === undefined) !== (current === undefined) ||\n (old !== undefined && current !== undefined &&\n (old.iv.length !== current.iv.length || old.iv.some((byte, index) => byte !== current.iv[index])))) {\n throw new ReplicaError(ReplicaErrorCode.BUSY, \"The pending-write state changed during its sealed mutation.\");\n }\n pending.put(row, id);\n });\n return result;\n };\n return this.#locks.request(`${REPLICA_PENDING_LOCK_PREFIX}${id}`, section) as Promise<T>;\n }\n}\n","/**\n * `indexedDbReplicaStorage()`: the browser `ReplicaGatedStorage` (TC-858 Phase 2\n * plan §3, CONTRACT.md §1). Main-thread half: a thin RPC client over one\n * dedicated worker per storage instance, which owns the engine, the network\n * and the device key. Pending writes, `inspectStatus` and `purge` run here\n * directly against the origin database: none needs WASM or the network, so\n * none spawns the worker.\n *\n * Gate (CONTRACT.md §2): with no lifecycle gate there is no ungated mode —\n * `open`, pending writes, `purge` and `inspectStatus` refuse REPLICA_GATED\n * `gate_unavailable`. Every replica-served value is delivered only when the\n * worker's reply carries exactly the handle's stamp and `deliverable(stamp)`.\n */\nimport type {\n KVReplicaSpec,\n LocalGetResult,\n LocalListResult,\n LocalReplicaStatus,\n LocalSyncResult,\n PendingWriteStore,\n PurgeTarget,\n ReplicaDenyOutcome,\n ReplicaBrowserGateSnapshot,\n ReplicaGatedHandle,\n ReplicaGatedSpec,\n ReplicaGatedStorage,\n ReplicaGrantInfo,\n ReplicaLifecycleGate,\n ReplicaQuotaLedger,\n ReplicaInspectedStatus,\n ReplicaPartitionIndexEntry,\n ReplicaSessionStamp,\n ReplicationIdentity,\n} from \"@tinycloud/sdk-services/kv/replication\";\nimport { canonicalReplicationIdentity, replicationIdentityKey } from \"@tinycloud/sdk-services/kv/replication\";\n\nimport { ReplicaError, ReplicaErrorCode, gatedError as gated } from \"../errors.js\";\nimport { assertFolderPrefix } from \"../scope.js\";\nimport { idbError, requestAsPromise, transactionDone } from \"../browser/idb.js\";\nimport { gateHash, GATE_HMAC_KEY, type BrowserGate, type GateHmacRecord, validGateHmac } from \"./gateKeys.js\";\nimport { ledgerFor } from \"./ledger.js\";\nimport { createIndexedDbGateTx, type BrowserReplicaGateTx } from \"./gateTx.js\";\nimport { createIndexedDbLifecycle } from \"./lifecycle.js\";\nimport { IndexedDbPendingWriteStore } from \"./pending.js\";\nimport type { KvConsentExpiryAck, KvEvent, KvOpenSpec, KvReply, KvRequest, KvResults, KvWireError } from \"./protocol.js\";\nimport type { SealedMeta } from \"./secureStore.js\";\nimport { ERASE_STORES, KV_STORE, kvPartitionEraser, openKvDatabase, partitionIdOf } from \"./schema.js\";\n\nexport type IndexedDbReplicaStorageOptions = {\n /**\n * Spawn this worker instead of the content-hashed default\n * (custom bundler layouts). A factory runs on first `open`.\n */\n worker?: Worker | URL | string | (() => Worker);\n /** The lifecycle gate (`storage.lifecycle`): consulted before every open, sync and delivery. */\n lifecycle?: ReplicaLifecycleGate;\n /**\n * The main-thread transaction guard (`createIndexedDbGateTx`): the pending\n * store runs every read and update through it, and `purge`/`inspectStatus`\n * derive private gate-HMAC ids from its `snapshot()`.\n */\n gateTx?: BrowserReplicaGateTx;\n /** Releases quota for partitions `purge()` erases, in the erase transaction. */\n ledger?: Pick<ReplicaQuotaLedger<IDBTransaction>, \"accountErase\">;\n};\n\nfunction replyError(err: KvWireError): ReplicaError {\n const error = new ReplicaError(err.code as ReplicaErrorCode, err.message, err.detail);\n // Contract shape for gate refusals: `Error & { code: \"REPLICA_GATED\"; gate }`.\n if (err.code === ReplicaErrorCode.GATED && typeof err.detail?.gate === \"string\")\n (error as ReplicaError & { gate: string }).gate = err.detail.gate;\n return error;\n}\n\nfunction sameStamp(a: ReplicaSessionStamp | undefined, b: ReplicaSessionStamp): boolean {\n return a !== undefined && a.incarnation === b.incarnation && a.lifecycleEpoch === b.lifecycleEpoch;\n}\n\nfunction spawn(source: IndexedDbReplicaStorageOptions[\"worker\"]): Worker {\n if (source !== undefined) {\n if (typeof Worker !== \"undefined\" && source instanceof Worker) return source;\n if (source instanceof URL || typeof source === \"string\") return new Worker(source, { type: \"module\" });\n if (typeof source === \"function\") return source();\n }\n // The package build replaces this literal with the worker's SHA-256 filename;\n // leave the new URL shape intact for bundlers' static asset resolution.\n return new Worker(new URL(\"./kv-storage.worker.js\", import.meta.url), { type: \"module\" });\n}\n\ntype Reply<T> = { result: T; stamp: ReplicaSessionStamp | undefined };\ntype Pending = { resolve(reply: Reply<unknown>): void; reject(error: Error): void };\n\n/** One live worker. A dead one (crashed or killed) fails its calls and is replaced on the next use. */\nclass WorkerConnection {\n readonly ready: Promise<void>;\n dead = false;\n readonly #worker: Worker;\n readonly #pending = new Map<number, Pending>();\n readonly #onEvent: (event: KvEvent) => void;\n #nextId = 1;\n #readyResolve: () => void;\n #readyReject: (error: Error) => void;\n\n constructor(worker: Worker, onEvent: (event: KvEvent) => void) {\n this.#worker = worker;\n this.#onEvent = onEvent;\n const ready = Promise.withResolvers<void>();\n this.ready = ready.promise;\n ready.promise.catch(() => undefined);\n this.#readyResolve = ready.resolve;\n this.#readyReject = ready.reject;\n worker.onmessage = (message: MessageEvent<KvReply | { event: KvEvent }>) => this.#receive(message.data);\n worker.onerror = (event) => this.kill(new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, event.message || \"The replica worker failed.\"));\n }\n\n #receive(data: KvReply | { event: KvEvent }): void {\n if (\"event\" in data) {\n if (data.event.event === \"ready\") this.#readyResolve();\n else this.#onEvent(data.event);\n return;\n }\n const pending = this.#pending.get(data.id);\n if (pending === undefined) return;\n this.#pending.delete(data.id);\n if (data.ok) pending.resolve({ result: data.result, stamp: data.stamp });\n else pending.reject(replyError(data.err));\n }\n\n /** Post `request`; `onId` learns the request id before the reply (cancel needs it). */\n async call<Op extends KvRequest[\"op\"]>(request: Extract<KvRequest, { op: Op }>, onId?: (id: number) => void): Promise<Reply<KvResults[Op]>> {\n await this.ready;\n if (this.dead) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica worker stopped.\");\n const id = this.#nextId++;\n const { promise, resolve, reject } = Promise.withResolvers<Reply<unknown>>();\n this.#pending.set(id, { resolve, reject });\n onId?.(id);\n this.#worker.postMessage({ id, ...request });\n return promise as Promise<Reply<KvResults[Op]>>;\n }\n\n /** Fire-and-forget control message: cancel or the durable expiry result. */\n notify(request: KvRequest | KvConsentExpiryAck): void {\n if (this.dead) return;\n this.#worker.postMessage({ id: this.#nextId++, ...request });\n }\n\n kill(error: Error): void {\n if (this.dead) return;\n this.dead = true;\n this.#worker.terminate();\n this.#readyReject(error);\n for (const pending of this.#pending.values()) pending.reject(error);\n this.#pending.clear();\n }\n}\n\nclass IndexedDbReplicaHandle implements ReplicaGatedHandle {\n readonly spec: ReplicaGatedSpec;\n readonly deviceDid: string;\n readonly replicaId: string;\n readonly #storage: IndexedDbReplicaStorage;\n readonly #lifecycle: ReplicaLifecycleGate;\n readonly #stamp: ReplicaSessionStamp;\n readonly #wire: KvOpenSpec;\n #connection: WorkerConnection;\n #remote: number;\n #closed = false;\n readonly #syncs = new Set<Promise<unknown>>();\n\n constructor(\n storage: IndexedDbReplicaStorage,\n gate: { lifecycle: ReplicaLifecycleGate; stamp: ReplicaSessionStamp },\n spec: ReplicaGatedSpec,\n wire: KvOpenSpec,\n connection: WorkerConnection,\n opened: KvResults[\"open\"],\n ) {\n this.#storage = storage;\n this.#lifecycle = gate.lifecycle;\n this.#stamp = gate.stamp;\n this.spec = spec;\n this.#wire = wire;\n this.#connection = connection;\n this.#remote = opened.handle;\n this.deviceDid = opened.deviceDid;\n this.replicaId = opened.partitionId;\n }\n\n acceptsPeerCommit(connection: WorkerConnection | undefined, handle: number): boolean {\n return !this.#closed && this.#connection === connection && this.#remote === handle && this.#lifecycle.deliverable(this.#stamp);\n }\n\n /** Before every request that reaches the worker (and every delivery): the gate must still honour the stamp. */\n #assertDeliverable(): void {\n if (!this.#lifecycle.deliverable(this.#stamp)) throw gated(\"stamp_stale\", \"The replica session ended.\");\n }\n\n /** The live worker-side handle; after a worker restart the spec is reopened on the new worker. */\n async #live(): Promise<{ connection: WorkerConnection; handle: number }> {\n if (this.#closed) throw new ReplicaError(ReplicaErrorCode.CLOSED, \"The replica handle is closed.\");\n this.#assertDeliverable();\n if (this.#connection.dead) {\n const connection = this.#storage.connection();\n const reply = await connection.call({ op: \"open\", spec: this.#wire });\n if (this.#closed) {\n await connection.call({ op: \"close\", handle: reply.result.handle }).catch(() => undefined);\n throw new ReplicaError(ReplicaErrorCode.CLOSED, \"The replica handle is closed.\");\n }\n const opened = this.#deliver(reply);\n this.#connection = connection;\n this.#remote = opened.handle;\n }\n return { connection: this.#connection, handle: this.#remote };\n }\n\n /** Delivery check (CONTRACT §2): drop a reply that ran under another (or no) stamp, or that the gate no longer honours. */\n #deliver<T>(reply: Reply<T>): T {\n if (this.#closed) throw new ReplicaError(ReplicaErrorCode.CLOSED, \"The replica handle is closed.\");\n if (!sameStamp(reply.stamp, this.#stamp)) throw gated(\"stamp_stale\", \"The replica reply ran under another session; it was not delivered.\");\n this.#assertDeliverable();\n return reply.result;\n }\n\n async get(key: string): Promise<LocalGetResult> {\n const { connection, handle } = await this.#live();\n const result = this.#deliver(await connection.call({ op: \"get\", handle, key }));\n return result.status === \"present\" ? { ...result, value: new Uint8Array(result.value) } : result;\n }\n\n async list(options: { prefix: string; after?: string; limit?: number }): Promise<LocalListResult> {\n const { connection, handle } = await this.#live();\n return this.#deliver(await connection.call({ op: \"list\", handle, ...options }));\n }\n\n async grant(): Promise<ReplicaGrantInfo | null> {\n const { connection, handle } = await this.#live();\n return this.#deliver(await connection.call({ op: \"grant\", handle }));\n }\n\n async installGrant(ucan: string): Promise<ReplicaGrantInfo> {\n const { connection, handle } = await this.#live();\n return this.#deliver(await connection.call({ op: \"installGrant\", handle, ucan }));\n }\n\n sync(options: { signal: AbortSignal; syncStartEpoch: number }): Promise<LocalSyncResult> {\n // Track the entire operation, including a worker restart before the RPC is sent.\n const running = this.#sync(options);\n const settled = running.then(() => undefined, () => undefined);\n this.#syncs.add(settled);\n void settled.then(() => this.#syncs.delete(settled));\n return running;\n }\n\n async #sync(options: { signal: AbortSignal; syncStartEpoch: number }): Promise<LocalSyncResult> {\n options.signal.throwIfAborted();\n const { connection, handle } = await this.#live();\n if (this.#closed) throw new ReplicaError(ReplicaErrorCode.CLOSED, \"The replica handle is closed.\");\n let requestId: number | undefined;\n const cancel = (): void => {\n if (requestId !== undefined) connection.notify({ op: \"cancel\", target: requestId });\n };\n options.signal.addEventListener(\"abort\", cancel, { once: true });\n try {\n const running = connection.call({ op: \"sync\", handle, syncStartEpoch: options.syncStartEpoch }, (id) => {\n requestId = id;\n if (options.signal.aborted) cancel();\n });\n return this.#deliver(await running);\n } finally {\n options.signal.removeEventListener(\"abort\", cancel);\n }\n }\n\n async status(): Promise<LocalReplicaStatus> {\n const { connection, handle } = await this.#live();\n const status = this.#deliver(await connection.call({ op: \"status\", handle }));\n return { ...status, persisted: await this.#storage.persisted(), purgePending: await purgePendingFor(this.#lifecycle, this.replicaId, null) };\n }\n\n async close(): Promise<void> {\n if (this.#closed) return;\n this.#closed = true;\n this.#storage.forget(this);\n // The worker aborts this handle's syncs and replies once they settle.\n if (!this.#connection.dead) await this.#connection.call({ op: \"close\", handle: this.#remote }).catch(() => undefined);\n await Promise.allSettled([...this.#syncs]);\n }\n}\n\n/** True while a purge intent covers the partition, or the identity's pending record. */\nasync function purgePendingFor(lifecycle: ReplicaLifecycleGate, partitionId: string | null, identityKeyHash: string | null): Promise<boolean> {\n return (await lifecycle.pendingPurge()).some((intent) =>\n intent.kind === \"partition\" ? intent.partitionId === partitionId : intent.identityKeyHash === identityKeyHash,\n );\n}\n\n\nclass IndexedDbReplicaStorage implements ReplicaGatedStorage {\n readonly kind = \"indexeddb\" as const;\n readonly lifecycle: ReplicaLifecycleGate;\n readonly #options: IndexedDbReplicaStorageOptions;\n readonly #handles = new Set<IndexedDbReplicaHandle>();\n #connection: WorkerConnection | undefined;\n #persisted: Promise<boolean | null> | undefined;\n #recovery: Promise<void> | undefined;\n\n constructor(options: IndexedDbReplicaStorageOptions & { lifecycle: ReplicaLifecycleGate }) {\n this.#options = { ...options, ledger: options.ledger ?? ledgerFor() };\n this.lifecycle = options.lifecycle;\n }\n\n /** A nonspawning probe lets the published testing helper terminate only an existing worker. */\n connection(): WorkerConnection;\n connection(peek: true): WorkerConnection | undefined;\n connection(peek?: true): WorkerConnection | undefined {\n if (peek) return this.#connection;\n if (this.#connection === undefined || this.#connection.dead) {\n const connection = new WorkerConnection(spawn(this.#options.worker), (event) => this.#event(event, connection));\n this.#connection = connection;\n }\n return this.#connection;\n }\n\n #event(event: KvEvent, connection: WorkerConnection): void {\n if (event.event === \"consentExpiry\") {\n const lifecycle = this.lifecycle as (ReplicaLifecycleGate & { expireConsent?: () => Promise<ReplicaDenyOutcome> }) | undefined;\n void Promise.resolve().then(() => {\n if (typeof lifecycle?.expireConsent !== \"function\") throw gated(\"gate_unavailable\", \"The lifecycle cannot expire account consent.\");\n return lifecycle.expireConsent();\n }).then(\n (outcome) => connection.notify({ op: \"consentExpiryAck\", requestId: event.requestId, ok: true, outcome }),\n () => connection.notify({ op: \"consentExpiryAck\", requestId: event.requestId, ok: false, message: \"Consent expiry failed.\" }),\n );\n return;\n }\n if (event.event !== \"peerCommit\") return;\n for (const handle of this.#handles) {\n if (!handle.acceptsPeerCommit(connection, event.handle)) continue;\n try {\n handle.spec.onPeerCommit?.(event.info);\n } catch {\n // onPeerCommit must not throw; if it does, the bridge stays up.\n }\n }\n }\n\n forget(handle: IndexedDbReplicaHandle): void {\n this.#handles.delete(handle);\n }\n\n /** `navigator.storage.persist()`, asked once per storage instance. */\n persisted(): Promise<boolean | null> {\n this.#persisted ??=\n typeof navigator !== \"undefined\" && typeof navigator.storage?.persist === \"function\"\n ? navigator.storage.persist().catch(() => null)\n : Promise.resolve(null);\n return this.#persisted;\n }\n\n #gateTx(): BrowserReplicaGateTx {\n const gateTx = this.#options.gateTx;\n if (gateTx === undefined) throw gated(\"gate_unavailable\", \"No lifecycle gate is wired into the replica storage.\");\n return gateTx;\n }\n\n async #recoverBeforeOpen(lifecycle: ReplicaLifecycleGate): Promise<void> {\n this.#recovery ??= (async () => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 3_000);\n const timedOut = new Promise<never>((_resolve, reject) =>\n controller.signal.addEventListener(\"abort\", () =>\n reject(gated(\"gate_unavailable\", \"Replica startup recovery timed out; local reads remain unavailable.\")), { once: true }));\n try {\n const report = await Promise.race([lifecycle.recover({ signal: controller.signal }), timedOut]);\n if (report.failed.length > 0 || report.remaining > 0) {\n throw gated(\"purge_pending\", \"Replica startup recovery did not finish; local reads remain unavailable.\");\n }\n } finally {\n clearTimeout(timer);\n }\n })().catch((error: unknown) => {\n this.#recovery = undefined;\n throw error;\n });\n return this.#recovery;\n }\n\n async open(spec: ReplicaGatedSpec): Promise<ReplicaGatedHandle> {\n assertFolderPrefix(spec.prefix);\n const identity = canonicalReplicationIdentity(spec.identity);\n const lifecycle = this.lifecycle;\n const stamp = spec.stamp;\n if (stamp === undefined) throw gated(\"not_established\", \"The session has no replica stamp.\");\n await this.#recoverBeforeOpen(lifecycle);\n if (!lifecycle.deliverable(stamp)) throw gated(\"stamp_stale\", \"The replica session ended.\");\n void this.persisted();\n const wire: KvOpenSpec = {\n identity,\n space: spec.space,\n prefix: spec.prefix,\n allowSecrets: spec.allowSecrets,\n stamp: { incarnation: stamp.incarnation, lifecycleEpoch: stamp.lifecycleEpoch },\n ...(spec.device === undefined ? {} : { device: { did: spec.device.did, jwk: spec.device.jwk } }),\n grantPolicy: structuredClone(spec.grantPolicy),\n ...(spec.quota === undefined ? {} : { quota: { ...spec.quota } }),\n };\n const connection = this.connection();\n const reply = await connection.call({ op: \"open\", spec: wire });\n if (!sameStamp(reply.stamp, stamp) || !lifecycle.deliverable(stamp)) {\n await connection.call({ op: \"close\", handle: reply.result.handle }).catch(() => undefined);\n throw gated(\"stamp_stale\", \"The replica session ended while the replica opened.\");\n }\n const handle = new IndexedDbReplicaHandle(this, { lifecycle, stamp }, spec, wire, connection, reply.result);\n this.#handles.add(handle);\n return handle;\n }\n\n /** The private lookup index names the stored owner partition without decrypting its device. */\n async #partitions(\n db: IDBDatabase,\n snapshot: ReplicaBrowserGateSnapshot,\n identity: ReplicationIdentity,\n prefix: string,\n sessionDeviceDid: string | undefined,\n ): Promise<string[]> {\n const lookupId = await gateHash(snapshot.gateHmac, \"lookup\", `${replicationIdentityKey(identity)}\\n${prefix}`);\n const indexed = await requestAsPromise<ReplicaPartitionIndexEntry[]>(\n db.transaction(KV_STORE.partitions).objectStore(KV_STORE.partitions).index(\"byLookupId\").getAll(lookupId));\n const owners = indexed.filter((item) => item.lookupId === lookupId && item.ownerDevice === true);\n if (owners.length > 1) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica has multiple owner partitions.\");\n const sessionId = sessionDeviceDid === undefined ? undefined :\n await partitionIdOf({ identity, prefix, deviceDid: sessionDeviceDid }, snapshot.gateHmac);\n return [...new Set([owners[0]?.partitionId, sessionId].filter((id): id is string => id !== undefined))];\n }\n\n async inspectStatus(spec: KVReplicaSpec, { signal }: { signal: AbortSignal }): Promise<ReplicaInspectedStatus | undefined> {\n signal.throwIfAborted();\n const controller = new AbortController();\n const onAbort = () => controller.abort(signal.reason);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n const timer = setTimeout(() => controller.abort(new DOMException(\"Replica status inspection timed out.\", \"TimeoutError\")), 3_000);\n const aborted = new Promise<never>((_resolve, reject) => {\n controller.signal.addEventListener(\"abort\", () => reject(controller.signal.reason), { once: true });\n });\n try {\n if (signal.aborted) onAbort();\n return await Promise.race([this.#inspectRedacted(spec, controller.signal), aborted]);\n } finally {\n clearTimeout(timer);\n signal.removeEventListener(\"abort\", onAbort);\n }\n }\n\n async #inspectRedacted(spec: KVReplicaSpec, signal: AbortSignal): Promise<ReplicaInspectedStatus | undefined> {\n signal.throwIfAborted();\n const identity = canonicalReplicationIdentity(spec.identity);\n const snapshot = await this.#gateTx().snapshot();\n if (snapshot === null) return undefined;\n const identityKey = replicationIdentityKey(identity);\n const lookupId = await gateHash(snapshot.gateHmac, \"lookup\", `${identityKey}\\n${spec.prefix}`);\n const principalHash = await gateHash(snapshot.gateHmac, \"principal\", identity.principal.toLowerCase());\n const identityKeyHash = await gateHash(snapshot.gateHmac, \"identity\", identityKey);\n const injectedId = spec.device === undefined ? undefined :\n await partitionIdOf({ identity, prefix: spec.prefix, deviceDid: spec.device.did }, snapshot.gateHmac);\n signal.throwIfAborted();\n const db = await openKvDatabase({ create: false });\n if (db === null) return undefined;\n try {\n const tx = db.transaction([KV_STORE.gate, KV_STORE.device, KV_STORE.partitions, KV_STORE.meta, KV_STORE.purgeIntents], \"readonly\");\n const gate = await requestAsPromise<BrowserGate | undefined>(tx.objectStore(KV_STORE.gate).get(\"account\"));\n if (gate === undefined || gate.incarnation !== snapshot.incarnation || gate.lifecycleEpoch !== snapshot.lifecycleEpoch ||\n gate.keyId !== snapshot.keyId || gate.accountKeyId !== snapshot.accountKeyId || gate.principalHash !== principalHash) return undefined;\n const hmac = await requestAsPromise<GateHmacRecord | undefined>(tx.objectStore(KV_STORE.device).get(GATE_HMAC_KEY));\n if (!validGateHmac(hmac, gate)) return undefined;\n signal.throwIfAborted();\n let partitionId = injectedId;\n if (partitionId === undefined) {\n const matches = await requestAsPromise<ReplicaPartitionIndexEntry[]>(\n tx.objectStore(KV_STORE.partitions).index(\"byLookupId\").getAll(lookupId, 64));\n const owners = matches.filter((item) => item.ownerDevice === true && item.lookupId === lookupId);\n if (owners.length > 1) throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The replica has multiple owner partitions.\");\n if (matches.length === 64) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The bounded replica owner lookup is inconclusive.\");\n }\n partitionId = owners[0]?.partitionId;\n }\n if (partitionId === undefined) return undefined;\n const row = await requestAsPromise<SealedMeta | undefined>(tx.objectStore(KV_STORE.meta).get(partitionId));\n if (row === undefined || row.purged) return undefined;\n if (row.pid !== partitionId || ![0, 1, 2].includes(row.coverageCode) ||\n ![row.syncedThroughEpoch, row.keys, row.contentMissing, row.tombstones, row.contentBytes]\n .every((value) => Number.isSafeInteger(value) && value >= 0)) {\n throw new ReplicaError(ReplicaErrorCode.STORAGE_ERROR, \"The redacted replica status controls are invalid.\");\n }\n const intents = tx.objectStore(KV_STORE.purgeIntents);\n const [partitionIntent, identityIntent] = await Promise.all([\n requestAsPromise<number>(intents.count(partitionId)),\n requestAsPromise<number>(intents.count(`pending:${identityKeyHash}`)),\n ]);\n signal.throwIfAborted();\n const persisted = typeof navigator.storage?.persisted === \"function\"\n ? await navigator.storage.persisted().catch(() => null)\n : null;\n signal.throwIfAborted();\n return {\n redacted: true, coverage: row.coverageCode === 0 ? \"empty\" : row.coverageCode === 1 ? \"bootstrapping\" : \"complete\",\n syncedThroughEpoch: row.syncedThroughEpoch,\n counts: { keys: row.keys, contentMissing: row.contentMissing, tombstones: row.tombstones },\n bytes: row.contentBytes, persisted, purgePending: partitionIntent > 0 || identityIntent > 0,\n };\n } finally {\n db.close();\n }\n }\n\n #assertPurgeGate(gate: BrowserGate | undefined, snapshot: ReplicaBrowserGateSnapshot, principalHash: string): void {\n if (gate === undefined || gate.principalHash === null || gate.incarnation !== snapshot.incarnation ||\n gate.lifecycleEpoch !== snapshot.lifecycleEpoch || gate.keyId !== snapshot.keyId ||\n gate.accountKeyId !== snapshot.accountKeyId) {\n throw gated(\"stamp_stale\", \"The replica gate moved before purge.\");\n }\n if (gate.principalHash !== principalHash) throw gated(\"principal_mismatch\", \"Purge belongs to another account.\");\n }\n\n /**\n * Erase the identity's replica of `target.prefix` under the stored device\n * and the session device (deduplicated by principal), each in its own\n * exempt erase transaction that also unindexes the partition and releases\n * its quota. Never opens, mints or syncs, and never creates the database.\n * Handles opened earlier fail RESET_REQUIRED on their next call. With no\n * gate on the origin it rejects REPLICA_GATED `not_established` rather than\n * reporting an erase it could not address.\n */\n async purge(target: PurgeTarget): Promise<void> {\n const gateTx = this.#gateTx();\n const identity = canonicalReplicationIdentity(target.identity);\n const snapshot = await gateTx.snapshot();\n if (snapshot === null) throw gated(\"not_established\", \"No replica gate exists on this origin; there is nothing purge can address.\");\n const principalHash = await gateHash(snapshot.gateHmac, \"principal\", identity.principal.toLowerCase());\n let db: IDBDatabase | null;\n try {\n db = await openKvDatabase({ create: false });\n } catch (error) {\n throw idbError(error, \"Opening the replica database\");\n }\n if (db === null) throw gated(\"gate_unavailable\", \"The replica database disappeared before purge.\");\n try {\n this.#assertPurgeGate(await requestAsPromise<BrowserGate | undefined>(\n db.transaction(KV_STORE.gate).objectStore(KV_STORE.gate).get(\"account\")), snapshot, principalHash);\n const partitions = await this.#partitions(db, snapshot, identity, target.prefix, target.sessionDeviceDid);\n let firstError: unknown;\n for (const partitionId of partitions) {\n try {\n const tx = db.transaction([...ERASE_STORES, KV_STORE.gate, KV_STORE.partitions, KV_STORE.quota], \"readwrite\", { durability: \"strict\" });\n const done = transactionDone(tx);\n try {\n this.#assertPurgeGate(await requestAsPromise<BrowserGate | undefined>(\n tx.objectStore(KV_STORE.gate).get(\"account\")), snapshot, principalHash);\n const { bytes } = await kvPartitionEraser.erasePartition(tx, partitionId);\n await gateTx.unindexPartition(tx, partitionId);\n await this.#options.ledger?.accountErase(tx, { partitionId, bytes });\n await done;\n } catch (error) {\n try {\n tx.abort();\n } catch {\n // already finished\n }\n await done.catch(() => undefined);\n throw error;\n }\n } catch (error) {\n // Every device is attempted; the first failure throws after the rest ran.\n firstError ??= idbError(error, \"Purging the replica\");\n }\n }\n if (firstError !== undefined) throw firstError;\n } finally {\n db.close();\n }\n }\n\n pendingWrites(identity: ReplicationIdentity, options: { stamp?: ReplicaSessionStamp } = {}): PendingWriteStore {\n return new IndexedDbPendingWriteStore(identity, {\n ...(this.#options.gateTx === undefined ? {} : { gateTx: this.#options.gateTx }),\n ...(options.stamp === undefined ? {} : { stamp: options.stamp }),\n });\n }\n}\n\n/**\n * The IndexedDB `ReplicaGatedStorage`: one origin database\n * (`tinycloud-replica-kv`) and one dedicated worker per storage instance.\n * Pass it as `replication.storage`; the worker is spawned lazily on the\n * first `open`, so an app with replication off never starts it.\n */\nexport function indexedDbReplicaStorage(options: IndexedDbReplicaStorageOptions = {}): ReplicaGatedStorage {\n const ledger = options.ledger ?? ledgerFor();\n const lifecycle = options.lifecycle ?? createIndexedDbLifecycle({ ledger });\n const gateTx = options.gateTx ?? createIndexedDbGateTx((create) => openKvDatabase({ create }), {\n onConsentExpired: () => {\n if (!(\"expireConsent\" in lifecycle) || typeof lifecycle.expireConsent !== \"function\") {\n throw gated(\"gate_unavailable\", \"The lifecycle cannot expire account consent.\");\n }\n return lifecycle.expireConsent();\n },\n });\n return new IndexedDbReplicaStorage({ ...options, ledger, gateTx, lifecycle });\n}\n"],"mappings":"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","names":["CAPABILITIES","CAPABILITIES","assertFolderPrefix","HOUR_MS","DAY_MS","MAX_GRANT_TTL_MS","DAY_MS","CONSENT_WINDOW_MS","encoder","measured","ACCOUNT","ACCOUNT","principalHash","CONSENT_WINDOW_MS","now","tombstone","bytesToHex","encoder","decoder","bytesToHex","encoder","decoder","assertFolderPrefix"]}
|