snapback2 0.0.1
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 +127 -0
- package/bin/snapback2.mjs +36 -0
- package/dist/api.d.ts +20 -0
- package/dist/assets.d.ts +34 -0
- package/dist/client-assets.d.ts +26 -0
- package/dist/client-offline.d.ts +94 -0
- package/dist/client-outbox.d.ts +58 -0
- package/dist/client-upload.d.ts +41 -0
- package/dist/client-wire.d.ts +41 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.mjs +5 -0
- package/dist/client.mjs.map +7 -0
- package/dist/compiler-core.mjs +60 -0
- package/dist/compiler-core.mjs.map +7 -0
- package/dist/compiler-lib.d.ts +71 -0
- package/dist/compiler.mjs +5 -0
- package/dist/compiler.mjs.map +7 -0
- package/dist/drain.d.ts +33 -0
- package/dist/expo/files.d.ts +3 -0
- package/dist/expo/index.d.ts +16 -0
- package/dist/expo/token-store.d.ts +7 -0
- package/dist/expo/witness.d.ts +28 -0
- package/dist/expo/witness.mjs +2 -0
- package/dist/expo/witness.mjs.map +7 -0
- package/dist/expo.d.ts +4 -0
- package/dist/expo.mjs +9 -0
- package/dist/expo.mjs.map +7 -0
- package/dist/guide/auth.md +89 -0
- package/dist/guide/effects.md +52 -0
- package/dist/guide/families.json +446 -0
- package/dist/guide/grammar.md +52 -0
- package/dist/guide/live-query.md +27 -0
- package/dist/guide/offline.md +75 -0
- package/dist/guide/personas.md +15 -0
- package/dist/guide/quarry.md +297 -0
- package/dist/guide/testing.md +57 -0
- package/dist/index.d.ts +362 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +7 -0
- package/dist/offline-protocol.d.ts +180 -0
- package/dist/offline-schema.d.ts +1 -0
- package/dist/offline.d.ts +177 -0
- package/dist/react-core.d.ts +91 -0
- package/dist/react-core.mjs +2 -0
- package/dist/react-core.mjs.map +7 -0
- package/dist/react-native/components.d.ts +23 -0
- package/dist/react-native/files.d.ts +43 -0
- package/dist/react-native/source.d.ts +16 -0
- package/dist/react-native.d.ts +4 -0
- package/dist/react-native.mjs +2 -0
- package/dist/react-native.mjs.map +7 -0
- package/dist/react.d.ts +19 -0
- package/dist/react.mjs +2 -0
- package/dist/react.mjs.map +7 -0
- package/dist/sqlite-test.mjs +1720 -0
- package/dist/sqlite-test.mjs.map +7 -0
- package/dist/sse.d.ts +44 -0
- package/dist/store/byte-cache.d.ts +162 -0
- package/dist/store/canonical.d.ts +2 -0
- package/dist/store/indexeddb.d.ts +23 -0
- package/dist/store/locks.d.ts +11 -0
- package/dist/store/outbox.d.ts +113 -0
- package/dist/store/overlay-retirement.d.ts +17 -0
- package/dist/store/projection.d.ts +11 -0
- package/dist/store/range-store.d.ts +388 -0
- package/dist/store/sqlite-driver.conformance.d.ts +7 -0
- package/dist/store/sqlite-driver.d.ts +16 -0
- package/dist/store/sqlite-expo.d.ts +3 -0
- package/dist/store/sqlite.d.ts +31 -0
- package/dist/templates/chat/expo/App.tsx +29 -0
- package/dist/templates/chat/expo/app.json +11 -0
- package/dist/templates/chat/expo/index.js +3 -0
- package/dist/templates/chat/expo/shared/log.js +92 -0
- package/dist/templates/chat/expo/shared/log.ts +130 -0
- package/dist/templates/chat/expo/shared/offline.js +8 -0
- package/dist/templates/chat/expo/shared/offline.ts +9 -0
- package/dist/templates/chat/expo/src/Chat.tsx +23 -0
- package/dist/templates/chat/expo/src/Composer.tsx +23 -0
- package/dist/templates/chat/expo/src/MediaView.tsx +29 -0
- package/dist/templates/chat/expo/src/Witness.tsx +131 -0
- package/dist/templates/chat/expo/src/screens/Inbox.tsx +9 -0
- package/dist/templates/chat/expo/src/screens/Search.tsx +10 -0
- package/dist/templates/chat/expo/src/screens/Thread.tsx +22 -0
- package/dist/templates/chat/expo/src/witness-state.ts +68 -0
- package/dist/templates/chat/expo/tsconfig.json +5 -0
- package/dist/templates/chat/react/index.html +5 -0
- package/dist/templates/chat/react/shared/log.js +92 -0
- package/dist/templates/chat/react/shared/log.ts +130 -0
- package/dist/templates/chat/react/shared/offline.js +8 -0
- package/dist/templates/chat/react/shared/offline.ts +9 -0
- package/dist/templates/chat/react/src/App.tsx +36 -0
- package/dist/templates/chat/react/src/Composer.tsx +45 -0
- package/dist/templates/chat/react/src/Inbox.tsx +24 -0
- package/dist/templates/chat/react/src/Search.tsx +26 -0
- package/dist/templates/chat/react/src/Thread.tsx +126 -0
- package/dist/templates/chat/react/src/env.d.ts +1 -0
- package/dist/templates/chat/react/src/main.tsx +20 -0
- package/dist/templates/chat/shared/log.js +92 -0
- package/dist/templates/chat/shared/log.ts +130 -0
- package/dist/templates/chat/shared/offline.js +8 -0
- package/dist/templates/chat/shared/offline.ts +9 -0
- package/dist/templates/chat/snapback/deliveries.q +33 -0
- package/dist/templates/chat/snapback/delivery.ts +30 -0
- package/dist/templates/chat/snapback/feeds.q +14 -0
- package/dist/templates/chat/snapback/follows.q +11 -0
- package/dist/templates/chat/snapback/groups.q +40 -0
- package/dist/templates/chat/snapback/messages.q +32 -0
- package/dist/templates/chat/snapback/notifications.q +7 -0
- package/dist/templates/chat/snapback/posts.q +4 -0
- package/dist/templates/chat/snapback/profiles.q +17 -0
- package/dist/templates/chat/snapback/schema.q +136 -0
- package/dist/templates/chat/snapback/seed.ts +45 -0
- package/dist/templates/chat/snapback/tests/chat.test.ts +759 -0
- package/dist/templates/react/index.html +5 -0
- package/dist/templates/react/src/App.tsx +5 -0
- package/dist/templates/react/src/main.tsx +18 -0
- package/dist/templates/todos/snapback/schema.q +11 -0
- package/dist/templates/todos/snapback/seed.ts +10 -0
- package/dist/templates/todos/snapback/tests/todos.test.ts +13 -0
- package/dist/templates/todos/snapback/todos.q +6 -0
- package/dist/test-runner.mjs +8541 -0
- package/dist/test-runner.mjs.map +7 -0
- package/dist/test.d.ts +28 -0
- package/dist/test.mjs +8541 -0
- package/dist/test.mjs.map +7 -0
- package/dist/token-store.d.ts +3 -0
- package/dist/twin-hydrate.d.ts +43 -0
- package/dist/twin.d.ts +70 -0
- package/dist/types.d.ts +410 -0
- package/dist/witness-test.mjs +2 -0
- package/dist/witness-test.mjs.map +7 -0
- package/package.json +117 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/expo.ts", "../src/react-native.tsx", "../src/react-native/components.tsx", "../src/react-native/source.ts", "../src/store/byte-cache.ts", "../src/react-native/files.ts", "../src/expo/index.ts", "../src/store/sqlite-expo.ts", "../src/store/sqlite-driver.ts", "../src/expo/token-store.ts", "../src/store/canonical.ts", "../src/store/overlay-retirement.ts", "../src/store/range-store.ts", "../src/store/locks.ts", "../src/store/projection.ts", "../src/store/sqlite.ts", "../src/expo/files.ts"],
|
|
4
|
+
"sourcesContent": ["// Explicit core forwarding preserves ESM star exports across the external module boundary.\n// E2: esbuild drops the indirect external star export through react-native.\n// Re-export every native component (and hook, such as useAssetFile) by name here\n// AND in react-native.tsx; the built-entry parity test protects this list.\nexport * from \"./react-core.js\";\nexport { AssetImage, AssetVideo, useAssetFile } from \"./react-native.js\";\nexport type { AssetImageProps, AssetVideoProps } from \"./react-native.js\";\nexport * from \"./expo/index.js\";\n", "export * from \"./react-core.js\";\nexport { AssetImage, AssetVideo } from \"./react-native/components.js\";\nexport { useAssetFile } from \"./react-native/source.js\";\nexport type { AssetImageProps, AssetVideoProps } from \"./react-native/components.js\";\n", "import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Image, PixelRatio, View, type ImageProps, type LayoutChangeEvent } from \"react-native\";\nimport { VideoView, useVideoPlayer, type VideoViewProps } from \"expo-video\";\nimport { useSnapbackClient, useSnapbackSnapshot } from \"../react-core.js\";\nimport { SnapbackRefusal } from \"../client.js\";\nimport type { ImageAsset, VideoAsset } from \"../types.js\";\nimport { useNativeSource } from \"./source.js\";\n\nexport type AssetImageProps = Omit<ImageProps, \"source\"> & {\n asset: ImageAsset; width?: number; height?: number;\n onRefusal?: (refusal: SnapbackRefusal) => void;\n onSourceChange?: (uri: string | undefined, settled: boolean) => void;\n};\nexport function AssetImage({ asset, width, height, style, onLayout, onRefusal, onSourceChange, ...props }: AssetImageProps): React.ReactElement {\n const [measured, setMeasured] = useState<number>();\n const requested = Math.max(1, Math.ceil((measured ?? width ?? asset.width) * PixelRatio.get()));\n const { uri, refusal, settled } = useNativeSource(asset, { width: requested });\n const callback = useRef(onRefusal);\n callback.current = onRefusal;\n React.useLayoutEffect(() => { onSourceChange?.(uri, settled); }, [uri, settled, onSourceChange]);\n useEffect(() => { if (refusal) callback.current?.(refusal); }, [refusal]);\n const layout = (event: LayoutChangeEvent) => {\n if (event.nativeEvent.layout.width > 0) setMeasured(event.nativeEvent.layout.width);\n onLayout?.(event);\n };\n return <Image {...props} onLayout={layout} source={uri ? { uri } : undefined}\n style={[{ width: width ?? asset.width, height: height ?? (width === undefined ? asset.height : undefined), aspectRatio: asset.width / asset.height }, style]} />;\n}\n\nexport type AssetVideoProps = Omit<VideoViewProps, \"player\"> & {\n autoPlay?: boolean;\n onPlaybackStart?: () => void;\n asset: VideoAsset; width?: number; height?: number;\n onRefusal?: (refusal: SnapbackRefusal) => void;\n onSourceChange?: (uri: string | undefined, settled: boolean) => void;\n};\nfunction Player({ uri, asset: _asset, play, onPlay, onRefusal, onSourceChange: _onSourceChange, autoPlay: _autoPlay, onPlaybackStart: _onPlaybackStart, ...props }: AssetVideoProps & { uri: string; play: boolean; onPlay(): void }) {\n const player = useVideoPlayer(uri);\n useEffect(() => {\n const errors = player.addListener(\"statusChange\", ({ status, error }) => {\n if (status === \"error\") onRefusal?.(new SnapbackRefusal({ code: \"E_ASSET_TYPE\", family: \"input\",\n site: \"AssetVideo\", message: error?.message ?? \"native video decoder refused the source\",\n rewrite: \"use a video source supported by the native player\", guide: \"assets/client\" }));\n });\n const subscription = player.addListener(\"playingChange\", ({ isPlaying }) => {\n if (isPlaying) onPlay();\n });\n if (play) player.play();\n return () => { subscription.remove(); errors.remove(); };\n }, [player, onPlay, play]);\n return <VideoView {...props} player={player} nativeControls={props.nativeControls ?? true} />;\n}\n\n// Native v1 refuses view-once clips before fetching: AVPlayer cannot open a\n// memory source, and these bytes must never be materialized as a file.\nexport function AssetVideo({ asset, width, height, style, onRefusal, onSourceChange, onPlaybackStart, autoPlay = false, ...props }: AssetVideoProps): React.ReactElement {\n const client = useSnapbackClient();\n const snapshot = useSnapbackSnapshot();\n const identity = useMemo(() => ({ client, id: asset.id, auth: snapshot.authGeneration }), [client, asset.id, snapshot.authGeneration]);\n const [policy, setPolicy] = useState<{ identity: typeof identity; once: boolean }>();\n const callback = useRef(onRefusal);\n callback.current = onRefusal;\n useEffect(() => {\n let active = true;\n void (async () => {\n await client.ready;\n const once = Boolean(await client.assetCache?.viewOnce(asset.id) || await client.assetCache?.viewed(asset.id));\n if (active) setPolicy({ identity, once });\n })().catch((error) => { if (active) callback.current?.(error); });\n return () => { active = false; };\n }, [identity]);\n const once = policy?.identity === identity ? policy.once : undefined;\n const refused = useMemo(() => once ? new SnapbackRefusal({ code: \"E_ASSET_TYPE\", family: \"input\", site: \"AssetVideo\",\n message: \"view-once video is not played on native in v1: the native player cannot open an in-memory source and a view-once clip never touches disk\",\n rewrite: \"send the clip as an ordinary attachment, or wait for the native view-once video ruling\", guide: \"assets/client\" }) : undefined, [once]);\n const { uri, refusal, settled } = useNativeSource(once === false ? asset : null, { enabled: once === false });\n React.useLayoutEffect(() => { onSourceChange?.(uri, settled); }, [uri, settled, onSourceChange]);\n useEffect(() => { if (refused ?? refusal) callback.current?.((refused ?? refusal)!); }, [refused, refusal]);\n const size = [{ width: width ?? asset.width, height: height ?? (width === undefined ? asset.height : undefined), aspectRatio: asset.width / asset.height }, style];\n if (uri) return <Player {...props} asset={asset} uri={uri} onRefusal={onRefusal} play={autoPlay} onPlay={onPlaybackStart ?? (() => {})} style={size} />;\n return <View testID={props.testID} style={size} />;\n}\n", "import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { useSnapbackClient, useSnapbackSnapshot } from \"../react-core.js\";\nimport { isSnapbackRefusal, SnapbackRefusal } from \"../client.js\";\nimport type { AssetRecord } from \"../types.js\";\nimport type { AssetBytes } from \"../store/byte-cache.js\";\nimport { nativeAssetFiles } from \"./files.js\";\n\nconst none = () => \"0\";\nconst noSubscription = () => () => {};\nconst fileRefusal = (error: unknown): SnapbackRefusal => isSnapbackRefusal(error) ? error : new SnapbackRefusal({\n code: \"E_OFFLINE_CARRIER\", family: \"offline\", message: String(error), site: \"useAssetFile\",\n rewrite: \"open a writable Expo cache directory and retry\", guide: \"offline\",\n});\nexport function bytesDataUri(value: AssetBytes): string {\n // No Buffer, Blob, or huge argument list on Hermes.\n const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n const output: string[] = [];\n for (let i = 0; i < value.bytes.length; i += 3) {\n const a = value.bytes[i], b = value.bytes[i + 1], c = value.bytes[i + 2];\n const n = (a << 16) | ((b ?? 0) << 8) | (c ?? 0);\n output.push(alphabet[n >>> 18], alphabet[(n >>> 12) & 63], b === undefined ? \"=\" : alphabet[(n >>> 6) & 63], c === undefined ? \"=\" : alphabet[n & 63]);\n }\n return `data:${value.type.replace(/[;,\\r\\n]/g, \"\")};base64,${output.join(\"\")}`;\n}\n\nfunction useFile(asset: AssetRecord | null | undefined, width?: number) {\n const client = useSnapbackClient();\n const snapshot = useSnapbackSnapshot();\n const files = nativeAssetFiles(client);\n const getRevision = useMemo(() => files && asset ? () => files.getAssetRevision(asset.id) : none, [files, asset?.id]);\n const revision = useSyncExternalStore(files?.subscribe ?? noSubscription, getRevision, none);\n const identity = useMemo(() => ({ client, id: asset?.id, width, auth: snapshot.authGeneration, files, revision }),\n [client, asset?.id, width, snapshot.authGeneration, files, revision]);\n const [result, setResult] = useState<{ identity: typeof identity; uri?: string; error?: unknown }>();\n useEffect(() => {\n let active = true;\n if (!asset || !files || !client.assetCache) {\n setResult({ identity });\n return;\n }\n void files.get(client.assetCache, asset.id, width ?? null).then(\n (uri) => { if (active) setResult({ identity, uri }); },\n (error) => { if (active) setResult({ identity, error }); },\n );\n return () => { active = false; };\n }, [identity]);\n return { files, revision, custody: files?.getCustody() ?? 0, checked: result?.identity === identity,\n uri: result?.identity === identity ? result.uri : undefined, error: result?.identity === identity ? result.error : undefined };\n}\n\n/** Cached ordinary media only. View-once is held by its viewing component, never a file. */\nexport function useAssetFile(asset: AssetRecord | null | undefined, options: { width?: number } = {}): string | undefined {\n return useFile(asset, options.width).uri;\n}\n\nexport function useNativeSource(asset: AssetRecord | null | undefined, options: { width?: number; enabled?: boolean } = {}) {\n const client = useSnapbackClient();\n const snapshot = useSnapbackSnapshot();\n const file = useFile(asset, options.width);\n const failure = useMemo(() => file.error === undefined ? undefined : fileRefusal(file.error), [file.error]);\n const viewing = useRef({}).current;\n // Layout selects a derivative; it never starts another viewing session.\n const identity = useMemo(() => ({ client, id: asset?.id, auth: snapshot.authGeneration, custody: file.custody }),\n [client, asset?.id, snapshot.authGeneration, file.custody]);\n const [memory, setMemory] = useState<{ identity: typeof identity; revision?: string; uri?: string; refusal?: SnapbackRefusal }>();\n const attempted = useRef<{ identity: typeof identity; width?: number } | undefined>(undefined);\n const current = useRef<typeof identity | undefined>(identity);\n current.current = identity;\n useEffect(() => {\n current.current = identity;\n return () => { current.current = undefined; };\n }, [identity]);\n useEffect(() => {\n if (!asset || options.enabled === false || !file.checked || failure || file.uri || (attempted.current?.identity === identity && (attempted.current.width === options.width || memory?.identity !== identity)) || (file.files && !file.files.available())) return;\n attempted.current = { identity, width: options.width };\n const active = () => current.current === identity && client.snapshot.authGeneration === identity.auth\n && (file.files?.getCustody() ?? 0) === identity.custody;\n void (async () => {\n await client.ready;\n if (!active()) return;\n // A new viewing instance cannot borrow another instance's allowance.\n if (await client.assetCache?.viewed(asset.id)) {\n if (active() && memory?.identity !== identity) setMemory({ identity, revision: file.files?.getAssetRevision(asset.id) ?? \"0\" });\n return;\n }\n if (!active()) return;\n const url = await client.assetUrl(asset, { width: options.width });\n if (!url || !active()) return;\n const value = await client.assetBytes(url, { viewing });\n if (!active()) return;\n if (client.assetCache && !await client.assetCache.canServe(asset.id, viewing)) return;\n if (active()) setMemory({ identity, revision: file.files?.getAssetRevision(asset.id) ?? \"0\", uri: bytesDataUri(value) });\n })().catch((error) => {\n if (current.current !== identity) return;\n const refusal = fileRefusal(error);\n setMemory({ identity, revision: file.files?.getAssetRevision(asset!.id) ?? \"0\", refusal });\n });\n }, [identity, memory, file.checked, file.uri, options.width, options.enabled, failure]);\n useEffect(() => {\n if (!asset || !file.files || memory?.identity !== identity || !memory.uri || memory.revision === file.revision) return;\n let active = true;\n const custody = file.custody;\n void client.assetCache?.canServe(asset.id, viewing).then((held) => {\n if (active && current.current === identity && file.files?.getCustody() === custody)\n setMemory({ ...memory, revision: file.revision, uri: held ? memory.uri : undefined });\n }).catch(() => {\n if (active && current.current === identity) setMemory({ ...memory, revision: file.revision, uri: undefined });\n });\n return () => { active = false; };\n }, [memory, identity, file.revision]);\n // Fetch completion is fenced by the client's authority and by identity at render.\n return { settled: file.checked && (Boolean(file.uri) || memory?.identity === identity), uri: file.uri ?? (memory?.identity === identity && memory.revision === file.revision ? memory.uri : undefined), refusal: failure ?? (memory?.identity === identity ? memory.refusal : undefined) };\n}\n", "// @ref LLP 1006#9b-bytes-on-the-device-author-ruling-2026-09-04 \u2014 bytes are cached under the owning row's lease, or not at all.\n// @ref LLP 1012#9-asset-bytes-on-the-device \u2014 the ByteCache sits beside the range store and joins its swap; view-once is excluded at view time.\n\nimport type { RangeStore, RowRef, StoredRow } from \"./range-store.js\";\n\n/** One cached rendition: what a component fetched at the width it asked for. */\nexport interface ByteCacheEntry {\n assetId: string;\n width: number | null;\n size: number;\n type: string;\n /** Logical last-read stamp on the range store's clock; the LRU orders by it. */\n lastRead: number;\n}\n\n/** A view-once row that was viewed, with the asset ids it carried at that moment. */\nexport interface ViewedRecord { at: number; assets: string[] }\n\nexport interface ByteCachePut { assetId: string; width: number | null; bytes: Uint8Array; type: string }\nexport interface ByteSwapRequest { put?: ByteCachePut[]; touch?: string[]; ceiling?: number }\n\n/** What a carrier persists beside the state in the same swap: payloads to write and keys to drop. */\nexport interface ByteDelta { put: Array<{ key: string; bytes: Uint8Array }>; remove: string[] }\n\nexport interface ByteCacheStatus { entries: ByteCacheEntry[]; totalBytes: number; viewed: RowRef[] }\nexport interface AssetBytes { bytes: Uint8Array; type: string }\n/** An opaque identity held by one mounted viewing instance, never shared by asset id. */\nexport interface AssetFetchOptions { signal?: AbortSignal; viewing?: object }\nexport type ByteCacheOutcome = \"cached\" | \"viewed\" | \"unleased\" | \"refused\";\nexport type ViewOncePredicate = (table: string, row: Record<string, unknown>) => boolean;\n\n/** The byte surface the swap engine exposes beside `RangeStore`; only the carriers implement it. */\nexport interface ByteCarrier {\n readBytes(assetId: string, width: number | null): Promise<{ bytes: Uint8Array; type: string } | undefined>;\n bytes(): Promise<ByteCacheStatus>;\n rowsReferencing(assetId: string): Promise<StoredRow[]>;\n viewedAsset(assetId: string): Promise<boolean>;\n viewedRows(): Promise<RowRef[]>;\n /** LRU read stamps, coalesced: stamped in memory now, persisted by the next swap. */\n touchBytes(keys: string[]): Promise<void>;\n commit(swap: { bytes?: ByteSwapRequest; viewed?: RowRef[] }): Promise<void>;\n}\n\n/** The client-facing byte cache: `client.assetCache` when the client has an offline store. */\nexport interface AssetCache {\n /** Session custody changes revoke mounted object URLs. */\n subscribeCustody?(listener: () => void): () => void;\n getCustody?(): number;\n getBytes(assetId: string, width: number | null, viewing?: object): Promise<AssetBytes | undefined>;\n putBytes(assetId: string, width: number | null, value: AssetBytes, viewing?: object): Promise<ByteCacheOutcome>;\n canServe(assetId: string, viewing?: object): Promise<boolean>;\n /** The held bytes for an asset at a width, or nothing: never fetched, evicted with its row, viewed, or sealed. */\n get(assetId: string, width: number | null, viewing?: object): Promise<Blob | undefined>;\n /** True once a view-once row carrying this asset was viewed on this partition. */\n viewed(assetId: string): Promise<boolean>;\n /** True while a held row carrying this asset is view-once (`offline.viewOnce`) and not yet viewed. */\n viewOnce(assetId: string): Promise<boolean>;\n /** Marks the held view-once rows carrying this asset viewed: what a player calls when playback starts. */\n markViewed(assetId: string): Promise<boolean>;\n status(): Promise<ByteCacheStatus>;\n}\n\nexport const ASSET_ID = /^s2id-[0-9a-f]{32}-[0-9a-f]{16}$/;\nconst SESSION_VIEW_LIMIT = 8;\n\nexport function byteKey(assetId: string, width: number | null): string {\n return width === null ? assetId : `${assetId}.w${width}`;\n}\n\nfunction rowKey(ref: RowRef): string {\n return `${ref.table}\\u0000${ref.id}`;\n}\n\nfunction positive(value: unknown): boolean {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0;\n}\n\n/** The closed asset record shape (LLP 1006 \u00A71): exactly id, width, height, and duration for video. */\nexport function assetRecordId(value: unknown): string | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n const keys = Object.keys(record).sort().join(\",\");\n if (keys !== \"height,id,width\" && keys !== \"duration,height,id,width\") return undefined;\n if (typeof record.id !== \"string\" || !ASSET_ID.test(record.id)) return undefined;\n if (!positive(record.width) || !positive(record.height)) return undefined;\n if (\"duration\" in record && !positive(record.duration)) return undefined;\n return record.id;\n}\n\nexport function assetIdsIn(value: unknown, output = new Set<string>()): Set<string> {\n const id = assetRecordId(value);\n if (id !== undefined) output.add(id);\n else if (Array.isArray(value)) for (const item of value) assetIdsIn(item, output);\n else if (value && typeof value === \"object\") {\n for (const item of Object.values(value as Record<string, unknown>)) assetIdsIn(item, output);\n }\n return output;\n}\n\n/** Assets a held delivery references: through pooled rows and through inline answer data. */\nexport function leasedAssets(rows: Iterable<StoredRow>, answers: Iterable<{ data?: unknown }>): Set<string> {\n const leased = new Set<string>();\n for (const row of rows) assetIdsIn(row.row, leased);\n for (const answer of answers) if (answer.data !== undefined) assetIdsIn(answer.data, leased);\n return leased;\n}\n\nexport interface ByteSwapState {\n clock: number;\n rows: Record<string, StoredRow>;\n assets: Record<string, ByteCacheEntry>;\n viewed: Record<string, ViewedRecord>;\n}\n\n/**\n * View-once is tracked per row, never per asset id: an asset is refused only while\n * every held row carrying it was viewed. A row that is not viewed keeps its lease,\n * so one shared id never poisons an ordinary row's bytes.\n */\nexport function viewedOnlyAssets(state: Pick<ByteSwapState, \"rows\" | \"viewed\">): Set<string> {\n const viewed = new Set<string>();\n for (const record of Object.values(state.viewed)) for (const id of record.assets) viewed.add(id);\n if (viewed.size === 0) return viewed;\n for (const [key, row] of Object.entries(state.rows)) {\n if (state.viewed[key]) continue;\n for (const id of assetIdsIn(row.row)) viewed.delete(id);\n }\n return viewed;\n}\n\nfunction checkedPut(put: ByteCachePut): void {\n if (!put || typeof put !== \"object\" || typeof put.assetId !== \"string\" || !ASSET_ID.test(put.assetId)) {\n throw new TypeError(\"byte cache put must name an engine-minted asset id\");\n }\n if (put.width !== null && !positive(put.width)) throw new TypeError(\"byte cache put width must be null or a positive integer\");\n if (!(put.bytes instanceof Uint8Array)) throw new TypeError(\"byte cache put bytes must be a Uint8Array\");\n if (typeof put.type !== \"string\") throw new TypeError(\"byte cache put type must be a string\");\n}\n\n/**\n * The byte half of one swap, run after the row rules settled `state.rows`: viewed\n * marks, the lease purge, read touches, puts, then the ceiling. Returns what the\n * carrier must write and drop in the same transaction.\n */\nexport function applyByteSwap(\n state: ByteSwapState,\n swap: { bytes?: ByteSwapRequest; viewed?: RowRef[] },\n leased: Set<string>,\n): ByteDelta {\n const delta: ByteDelta = { put: [], remove: [] };\n for (const ref of swap.viewed ?? []) {\n if (!ref || typeof ref.table !== \"string\" || typeof ref.id !== \"string\") throw new TypeError(\"viewed rows must be row references\");\n const key = rowKey(ref);\n const assets = new Set(state.viewed[key]?.assets ?? []);\n assetIdsIn(state.rows[key]?.row, assets);\n state.viewed[key] = { at: Date.now(), assets: [...assets] };\n }\n const viewedAssets = viewedOnlyAssets(state);\n for (const [key, entry] of Object.entries(state.assets)) {\n if (leased.has(entry.assetId) && !viewedAssets.has(entry.assetId)) continue;\n delete state.assets[key];\n delta.remove.push(key);\n }\n for (const key of swap.bytes?.touch ?? []) {\n const entry = state.assets[key];\n if (entry) entry.lastRead = ++state.clock;\n }\n const ceiling = swap.bytes?.ceiling ?? Number.POSITIVE_INFINITY;\n if (!(ceiling > 0)) throw new TypeError(\"byte cache ceiling must be positive\");\n for (const put of swap.bytes?.put ?? []) {\n checkedPut(put);\n if (!leased.has(put.assetId) || viewedAssets.has(put.assetId)) continue;\n const size = put.bytes.byteLength;\n if (size === 0 || size > ceiling) continue;\n const key = byteKey(put.assetId, put.width);\n state.assets[key] = { assetId: put.assetId, width: put.width, size, type: put.type, lastRead: ++state.clock };\n delta.put.push({ key, bytes: put.bytes });\n }\n let total = Object.values(state.assets).reduce((sum, entry) => sum + entry.size, 0);\n while (total > ceiling) {\n const [key, victim] = Object.entries(state.assets)\n .reduce((least, item) => item[1].lastRead < least[1].lastRead ? item : least);\n delete state.assets[key];\n delta.remove.push(key);\n total -= victim.size;\n }\n delta.put = delta.put.filter((item) => state.assets[item.key] !== undefined);\n delta.remove = [...new Set(delta.remove)].filter((key) => state.assets[key] === undefined);\n return delta;\n}\n\nfunction isByteCarrier(store: RangeStore): store is RangeStore & ByteCarrier {\n const candidate = store as Partial<ByteCarrier>;\n return typeof candidate.readBytes === \"function\"\n && typeof candidate.bytes === \"function\"\n && typeof candidate.rowsReferencing === \"function\"\n && typeof candidate.viewedAsset === \"function\"\n && typeof candidate.viewedRows === \"function\"\n && typeof candidate.touchBytes === \"function\";\n}\n\nfunction checkedAssetId(assetId: string): string {\n if (typeof assetId !== \"string\" || !ASSET_ID.test(assetId)) throw new TypeError(\"asset id must be engine-minted\");\n return assetId;\n}\n\n/**\n * Bytes a component fetched, kept under the owning row's lease in the same\n * partition as the rows. A store without a byte carrier caches nothing.\n */\nexport class ByteCache implements AssetCache {\n /**\n * View-once bytes stay renderable inside the instance that viewed them, keyed by\n * the partition that viewed them; nothing here is durable. The runtime forgets it\n * on seal, wipe, partition change, and close, and `get` serves it only under the\n * custody the carrier path applies: this partition, unsealed, the row still held.\n */\n private readonly session = new Map<string, { viewing: object; value: AssetBytes }>();\n private partition?: string;\n private custody = 0;\n private readonly custodyListeners = new Set<() => void>();\n readonly getCustody = () => this.custody;\n readonly subscribeCustody = (listener: () => void) => {\n this.custodyListeners.add(listener);\n return () => { this.custodyListeners.delete(listener); };\n };\n private admissions: Promise<unknown> = Promise.resolve();\n\n constructor(\n readonly store: RangeStore,\n private readonly options: { maxAssetBytes: number; viewOnce?: ViewOncePredicate },\n ) {}\n\n /** The partition the runtime opened; a change drops every session blob. */\n bind(partition: string | undefined): void {\n if (this.partition !== partition) this.forget();\n this.partition = partition;\n }\n\n /** Drops the session blobs: seal, close, and wipe call this. */\n forget(): void {\n this.custody++;\n this.session.clear();\n for (const listener of this.custodyListeners) listener();\n }\n\n async get(assetId: string, width: number | null, viewing?: object): Promise<Blob | undefined> {\n const held = await this.getBytes(assetId, width, viewing);\n return held ? new Blob([held.bytes as BlobPart], { type: held.type }) : undefined;\n }\n\n // @ref LLP 1013#2-decisions \u2014 native paths exchange bytes, never RN Blobs.\n async getBytes(assetId: string, width: number | null, viewing?: object): Promise<AssetBytes | undefined> {\n const custody = this.custody;\n checkedAssetId(assetId);\n const store = this.carrier();\n if (!store) return undefined;\n // `viewedAsset` is false on a sealed partition, so the session is never consulted past a seal.\n if (await store.viewedAsset(assetId)) {\n const held = await this.sessionBytes(assetId, width, viewing);\n return custody === this.custody ? held : undefined;\n }\n if (await this.viewOnce(assetId)) return undefined;\n const held = await store.readBytes(assetId, width);\n if (!held) return undefined;\n // The touch is the LRU stamp, coalesced into the next swap; a closing partition may refuse it.\n await store.touchBytes([byteKey(assetId, width)]).catch(() => undefined);\n return await this.canServe(assetId, viewing) && custody === this.custody ? held : undefined;\n }\n\n /** Completion fence for both a cached source and an uncached ordinary source. */\n async canServe(assetId: string, viewing?: object): Promise<boolean> {\n const custody = this.custody;\n const store = this.carrier();\n if (!store) return false;\n const rows = await store.rowsReferencing(assetId);\n if (rows.length === 0) return false;\n const viewed = await store.viewedAsset(assetId);\n const once = rows.every((row) => this.options.viewOnce?.(row.table, row.row) === true);\n const owns = (!viewed && !once) || [...this.session.entries()].some(([key, entry]) =>\n entry.viewing === viewing && key.startsWith(this.sessionKey(assetId)));\n return custody === this.custody && owns;\n }\n\n async viewed(assetId: string): Promise<boolean> {\n checkedAssetId(assetId);\n const store = this.carrier();\n return store ? store.viewedAsset(assetId) : false;\n }\n\n async viewOnce(assetId: string): Promise<boolean> {\n checkedAssetId(assetId);\n const store = this.carrier();\n if (!store) return false;\n const once = await this.viewOnceRows(assetId);\n if (once.length === 0) return false;\n const viewed = new Set((await store.viewedRows()).map(rowKey));\n return once.some((ref) => !viewed.has(rowKey(ref)));\n }\n\n async markViewed(assetId: string): Promise<boolean> {\n checkedAssetId(assetId);\n const store = this.carrier();\n if (!store) return false;\n const once = await this.viewOnceRows(assetId);\n if (once.length === 0) return false;\n await store.commit({ viewed: once });\n return true;\n }\n\n /** After a network fetch: cache under the row's lease, or mark the view-once rows viewed and cache nothing. */\n async put(assetId: string, width: number | null, blob: Blob, viewing?: object): Promise<ByteCacheOutcome> {\n const custody = this.custody;\n const bytes = new Uint8Array(await blob.arrayBuffer());\n if (custody !== this.custody) return \"refused\";\n return this.putBytes(assetId, width, { bytes, type: blob.type }, viewing);\n }\n\n putBytes(assetId: string, width: number | null, value: AssetBytes, viewing?: object): Promise<ByteCacheOutcome> {\n const custody = this.custody;\n // Two concurrent consumers may fetch; only one can acquire the viewing allowance.\n const result = this.admissions.then(() => custody === this.custody\n ? this.admit(assetId, width, value, viewing) : \"refused\" as const);\n this.admissions = result.catch(() => undefined);\n return result;\n }\n\n private async admit(assetId: string, width: number | null, value: AssetBytes, viewing?: object): Promise<ByteCacheOutcome> {\n const custody = this.custody;\n checkedAssetId(assetId);\n checkedPut({ assetId, width, ...value });\n const store = this.carrier();\n if (!store) return \"unleased\";\n if (await store.viewedAsset(assetId)) return \"refused\";\n const rows = await store.rowsReferencing(assetId);\n if (rows.length === 0 || custody !== this.custody) return \"unleased\";\n const once = rows\n .filter((row) => this.options.viewOnce?.(row.table, row.row) === true)\n .map(({ table, id }) => ({ table, id }));\n // Per row: the view-once rows are marked viewed; an ordinary row sharing the id still leases the bytes.\n if (once.length > 0 && !viewing) return \"refused\";\n if (once.length === rows.length) {\n try {\n await store.commit({ viewed: once });\n } catch {\n return \"refused\";\n }\n if (custody !== this.custody || (await store.rowsReferencing(assetId)).length === 0\n || !await store.viewedAsset(assetId) || custody !== this.custody) return \"unleased\";\n if (this.session.size >= SESSION_VIEW_LIMIT) this.session.delete(this.session.keys().next().value!);\n if (viewing) this.session.set(this.sessionKey(assetId, width), { viewing, value: { bytes: value.bytes.slice(), type: value.type } });\n return \"viewed\";\n }\n try {\n await store.commit({\n ...(once.length === 0 ? {} : { viewed: once }),\n bytes: { put: [{ assetId, width, ...value }], ceiling: this.options.maxAssetBytes },\n });\n } catch {\n return \"refused\";\n }\n const status = await store.bytes();\n return custody === this.custody && status.entries.some((entry) => entry.assetId === assetId && entry.width === width) ? \"cached\" : \"refused\";\n }\n\n async status(): Promise<ByteCacheStatus> {\n const store = this.carrier();\n return store ? store.bytes() : { entries: [], totalBytes: 0, viewed: [] };\n }\n\n /** Nothing is served, marked, or cached without an open partition and a byte carrier. */\n private carrier(): (RangeStore & ByteCarrier) | undefined {\n return this.partition !== undefined && isByteCarrier(this.store) ? this.store : undefined;\n }\n\n private sessionKey(assetId: string, width?: number | null): string {\n return `${this.partition}\\u0000${assetId}\\u0000${width === undefined ? \"\" : width}`;\n }\n\n /** The session blob, only while the row that was viewed is still held on this partition. */\n private async sessionBytes(assetId: string, width: number | null, viewing?: object): Promise<AssetBytes | undefined> {\n const store = this.carrier();\n if (!store) return undefined;\n const key = this.sessionKey(assetId, width);\n const blob = this.session.get(key);\n if (!viewing || blob?.viewing !== viewing) return undefined;\n if ((await store.rowsReferencing(assetId)).length > 0) return blob.value;\n this.session.delete(key);\n return undefined;\n }\n\n private async viewOnceRows(assetId: string): Promise<RowRef[]> {\n const store = this.carrier();\n if (!store) return [];\n const rows = await store.rowsReferencing(assetId);\n return rows\n .filter((row) => this.options.viewOnce?.(row.table, row.row) === true)\n .map(({ table, id }) => ({ table, id }));\n }\n}\n", "// @ref LLP 1013#2-decisions \u2014 native files are derivatives; permission is always the cache's.\nimport type { AssetCache, ByteCache, ByteDelta } from \"../store/byte-cache.js\";\nimport { ASSET_ID, assetIdsIn, byteKey } from \"../store/byte-cache.js\";\nimport type { PersistedRangeState, RangeStore, RangeStoreBackend } from \"../store/range-store.js\";\nimport type { SnapbackClient } from \"../types.js\";\n\nexport interface NativeFileSystem {\n readonly root: string;\n list(directory: string): Promise<string[]>;\n exists?(uri: string): Promise<boolean>;\n write(uri: string, bytes: Uint8Array): Promise<void>;\n remove(uri: string): Promise<void>;\n}\nconst FILES = Symbol.for(\"snapback2.native.assetFiles\");\ntype FileStore = RangeStore & { [FILES]?: NativeAssetFiles };\n\nexport function attachAssetFiles(store: RangeStore, files: NativeAssetFiles): void {\n Object.defineProperty(store, FILES, { value: files });\n}\nexport function nativeAssetFiles(client: SnapbackClient): NativeAssetFiles | undefined {\n return ((client.assetCache as ByteCache | undefined)?.store as FileStore | undefined)?.[FILES];\n}\n\n/** Encoded even for adversarial principal strings; no partition can escape its directory. */\nexport function partitionDirectory(root: string, partition: string): string {\n return `${root.replace(/\\/$/, \"\")}/${encodeURIComponent(partition).replace(/\\./g, \"%2E\")}/`;\n}\n\nexport class NativeAssetFiles {\n private partition?: string;\n private state?: PersistedRangeState;\n private revision = 0;\n private custody = 0;\n private readonly assetRevisions = new Map<string, number>();\n private readonly listeners = new Set<() => void>();\n private readonly materialized = new Set<string>();\n // Serialize file writes and removals; a late write cannot resurrect an evicted file.\n private tail: Promise<unknown> = Promise.resolve();\n constructor(readonly fs: NativeFileSystem) {}\n getRevision = (): number => this.revision;\n getAssetRevision = (id: string): string => `${this.custody}:${this.assetRevisions.get(id) ?? 0}`;\n getCustody = (): number => this.custody;\n available = (): boolean => this.partition !== undefined && !this.state?.sealed;\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => { this.listeners.delete(listener); };\n };\n private changed(custody = false): void {\n this.revision++;\n if (custody) this.custody++;\n for (const listener of this.listeners) {\n try { listener(); } catch { /* Observers cannot undo a committed carrier swap. */ }\n }\n }\n private enqueue<T>(body: () => Promise<T>): Promise<T> {\n const result = this.tail.then(body);\n this.tail = result.catch(() => undefined);\n return result;\n }\n private remove(uri: string): Promise<void> {\n this.materialized.delete(uri);\n // A failed derivative delete must not turn an already committed SQLite swap\n // into a failed swap. It remains garbage, refused below and swept next open.\n return this.fs.remove(uri).catch(() => undefined);\n }\n private path(key: string, partition = this.partition): string | undefined {\n return partition === undefined ? undefined : partitionDirectory(this.fs.root, partition) + key;\n }\n private eligible(assetId: string, width: number | null): boolean {\n return this.partition !== undefined && !this.state?.sealed && this.state?.assets[byteKey(assetId, width)] !== undefined;\n }\n\n async get(cache: AssetCache, assetId: string, width: number | null): Promise<string | undefined> {\n if (!ASSET_ID.test(assetId)) return undefined;\n if (width !== null && (!Number.isSafeInteger(width) || width <= 0)) throw new TypeError(\"asset width must be a positive integer\");\n const revision = this.getAssetRevision(assetId);\n const uri = this.path(byteKey(assetId, width));\n if (!uri) return undefined;\n // The carrier read checks seal, lease, viewed set, payload existence and length.\n const once = await cache.viewOnce(assetId) || await cache.viewed(assetId);\n const held = once ? undefined : await cache.getBytes(assetId, width);\n return this.enqueue(async () => {\n // Recheck after acquiring the queue: viewed custody can move while a\n // preceding materialization holds it, even without a byte delta.\n if (!held || revision !== this.getAssetRevision(assetId) || !this.eligible(assetId, width)\n || await cache.viewOnce(assetId) || await cache.viewed(assetId)) {\n await this.remove(uri);\n return undefined;\n }\n if (!this.materialized.has(uri) || !await this.fs.exists?.(uri)) await this.fs.write(uri, held.bytes);\n if (revision !== this.getAssetRevision(assetId) || !this.eligible(assetId, width)\n || await cache.viewOnce(assetId) || await cache.viewed(assetId)) {\n await this.remove(uri);\n return undefined;\n }\n this.materialized.add(uri);\n return uri;\n });\n }\n\n /** Only backend success is a commit notification; never call this from beforeCommit. */\n async opened(partition: string, state: PersistedRangeState | undefined): Promise<void> {\n this.materialized.clear();\n this.partition = partition;\n this.state = state;\n this.changed(true);\n const directory = partitionDirectory(this.fs.root, partition);\n await this.enqueue(async () => {\n for (const name of await this.fs.list(directory)) {\n if (!state?.assets[name]) await this.remove(directory + name);\n }\n });\n }\n async replaced(state: PersistedRangeState, bytes: ByteDelta): Promise<void> {\n const sealed = this.state?.sealed !== state.sealed;\n const before = assetLeases(this.state), after = assetLeases(state);\n const changed = new Set([...before.keys(), ...after.keys()].filter((id) => before.get(id) !== after.get(id)));\n for (const key of [...bytes.remove, ...bytes.put.map((put) => put.key)]) changed.add(key.split(\".w\")[0]);\n for (const id of changed) this.assetRevisions.set(id, (this.assetRevisions.get(id) ?? 0) + 1);\n this.state = state;\n this.changed(sealed);\n const partition = this.partition;\n // A queued get rechecks the carrier, whose swap is awaiting this notification.\n // Publish custody now; cleanup follows asynchronously, never holding that swap.\n void this.enqueue(async () => {\n for (const key of [...bytes.remove, ...bytes.put.map((put) => put.key)]) {\n const uri = this.path(key, partition);\n if (uri) await this.remove(uri);\n }\n }).catch(() => undefined);\n }\n async wiped(partition: string): Promise<void> {\n if (this.partition === partition) this.closed();\n await this.enqueue(() => this.remove(partitionDirectory(this.fs.root, partition)));\n }\n closed(): void {\n this.materialized.clear();\n this.partition = undefined;\n this.state = undefined;\n this.changed(true);\n }\n}\n\n/** A message/grant/watermark swap that leaves a clip's lease unchanged keeps its player. */\nfunction assetLeases(state: PersistedRangeState | undefined): Map<string, string> {\n const refs = new Map<string, string[]>();\n for (const [key, row] of Object.entries(state?.rows ?? {})) {\n for (const id of assetIdsIn(row.row)) {\n const leases = refs.get(id) ?? [];\n leases.push(JSON.stringify([key, row.row, Boolean(state?.viewed[key])]));\n refs.set(id, leases);\n }\n }\n return new Map([...refs].map(([id, leases]) => [id, leases.sort().join(\"\\n\")]));\n}\n\nexport function fileBackend(backend: RangeStoreBackend, files: NativeAssetFiles): RangeStoreBackend {\n return {\n carrier: backend.carrier,\n async open(partition) {\n const state = await backend.open(partition);\n // Sweep errors leave unusable derivatives, never a substituted memory carrier.\n try { await files.opened(partition, state); }\n catch (error) { files.closed(); await backend.close(); throw error; }\n return state;\n },\n async replace(state, bytes) {\n await backend.replace(state, bytes);\n await files.replaced(state, bytes);\n },\n readBytes: backend.readBytes ? (key) => backend.readBytes!(key) : undefined,\n async wipe(partition) {\n await backend.wipe(partition); // Wiping the open partition also closes SQLite.\n await files.wiped(partition);\n },\n async close() {\n files.closed();\n await backend.close();\n },\n };\n}\n", "import { fetch as expoFetch } from \"expo/fetch\";\nimport { createClient } from \"../client.js\";\nimport type { CreateClientOptions, OfflineClientOptions, SnapbackClient } from \"../types.js\";\nimport { expoSqliteDriver } from \"../store/sqlite-expo.js\";\nimport { sqliteRangeStore, type SqliteRangeStoreOptions } from \"../store/sqlite.js\";\nimport { expoSecureTokenStore } from \"./token-store.js\";\nimport { PersistentRangeStore, type RangeStoreFactory } from \"../store/range-store.js\";\nimport { SqliteBackend } from \"../store/sqlite.js\";\nimport { NativeAssetFiles, attachAssetFiles, fileBackend } from \"../react-native/files.js\";\nimport { expoAssetFileSystem } from \"./files.js\";\n\nexport { expoSecureTokenStore } from \"./token-store.js\";\nexport { expoSqliteDriver } from \"../store/sqlite-expo.js\";\nexport { sqliteRangeStore, inProcessLocks } from \"../store/sqlite.js\";\nexport type { SqliteDriver, SqliteExecutor, SqliteParams, SqliteRangeStoreOptions } from \"../store/sqlite.js\";\n\nexport function expoSqliteStore(name = \"snapback2.db\", options: SqliteRangeStoreOptions = {}) {\n const factory = (() => {\n const files = new NativeAssetFiles(expoAssetFileSystem());\n const store = new PersistentRangeStore(fileBackend(new SqliteBackend(() => expoSqliteDriver(name), options), files));\n attachAssetFiles(store, files);\n return store;\n }) as RangeStoreFactory;\n Object.defineProperty(factory, \"carrier\", { value: \"SQLite\" });\n return factory;\n}\n\nexport type CreateExpoClientOptions = CreateClientOptions extends infer Options\n ? Options extends CreateClientOptions\n ? Omit<Options, \"offline\"> & {\n /** Restore a persisted transport cut before the first request or carrier resume. */\n startOffline?: boolean;\n offline?: Omit<OfflineClientOptions, \"store\"> & { store?: OfflineClientOptions[\"store\"] };\n }\n : never\n : never;\n\n// @ref LLP 1013#5-the-entries \u2014 streaming Expo fetch and native custody are\n// defaults; createClient itself checks the one-authority rule before opening.\nexport function createExpoClient(options: CreateExpoClientOptions): SnapbackClient {\n return createClient({\n ...options,\n fetch: options.fetch ?? expoFetch,\n offline: { ...options.offline, store: options.offline?.store ?? expoSqliteStore() },\n ...(options.as !== undefined ? {} : { tokenStore: options.tokenStore ?? expoSecureTokenStore() }),\n } as CreateClientOptions);\n}\n", "import { defaultDatabaseDirectory, openDatabaseAsync, type SQLiteDatabase } from \"expo-sqlite\";\nimport { driverQueue, type SqliteDriver, type SqliteExecutor } from \"./sqlite-driver.js\";\n\nfunction executor(database: SQLiteDatabase): SqliteExecutor {\n return {\n async run(sql, params = []) { await database.runAsync(sql, params); },\n async get<T>(sql: string, params = []) { return await database.getFirstAsync<T>(sql, params) ?? undefined; },\n async all<T>(sql: string, params = []) { return database.getAllAsync<T>(sql, params); },\n };\n}\n\nconst DATABASE_NAME = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;\n\n/** Requires Expo SDK 54's initialized runtime (including structuredClone). */\nexport function expoSqliteDriver(name = \"snapback2.db\"): SqliteDriver {\n // The identity is the lock key for one writer per database (LLP 1013 \u00A72 decision 4):\n // a name is an unambiguous basename in Expo's default directory, never a path, so two\n // spellings of one file cannot earn two locks (expo-sqlite joins directory and name\n // without collapsing dot segments before native open).\n if (!DATABASE_NAME.test(name)) {\n throw new TypeError(`expoSqliteDriver: the database name must be a plain file name (letters, digits, ., _, -), not a path: ${JSON.stringify(name)}`);\n }\n let database: Promise<SQLiteDatabase> | undefined;\n const db = () => database ??= openDatabaseAsync(name, { useNewConnection: true });\n const queue = driverQueue();\n return {\n identity: `expo-sqlite:${defaultDatabaseDirectory.replace(/\\/*$/, \"\")}/${name}`,\n run: (sql, params) => queue(async () => executor(await db()).run(sql, params)),\n get: (sql, params) => queue(async () => executor(await db()).get(sql, params)),\n all: (sql, params) => queue(async () => executor(await db()).all(sql, params)),\n exec: (sql) => queue(async () => (await db()).execAsync(sql)),\n // @ref LLP 1013#3-the-sqlite-carrier \u2014 Expo owns BEGIN/COMMIT on a separate\n // connection. Every statement uses that connection, never the outer handle.\n // Its COMMIT failure rolls back and closes that connection; the outer handle stays usable.\n transaction: <T>(body: (tx: SqliteExecutor) => Promise<T>) => queue(async () => {\n let result!: T;\n await (await db()).withExclusiveTransactionAsync(async (transaction) => {\n result = await body(executor(transaction));\n });\n return result;\n }),\n close: () => queue(async () => {\n const pending = database;\n database = undefined;\n if (pending) await (await pending).closeAsync();\n }),\n };\n}\n", "export type SqliteParams = Array<string | number | null | Uint8Array>;\n\nexport interface SqliteExecutor {\n run(sql: string, params?: SqliteParams): Promise<void>;\n get<T>(sql: string, params?: SqliteParams): Promise<T | undefined>;\n all<T>(sql: string, params?: SqliteParams): Promise<T[]>;\n}\n\nexport interface SqliteDriver extends SqliteExecutor {\n /** Stable identity of the database, shared by every connection/factory opening it. */\n readonly identity: string;\n exec(sql: string): Promise<void>;\n /** All statements in body must use tx. Commit only after its promise resolves. */\n transaction<T>(body: (tx: SqliteExecutor) => Promise<T>): Promise<T>;\n close(): Promise<void>;\n}\n\n/** Outer operations wait for an async transaction; its executor bypasses the queue. */\nexport function driverQueue(): <T>(body: () => Promise<T>) => Promise<T> {\n let tail = Promise.resolve();\n return (body) => {\n const result = tail.then(body);\n tail = result.then(() => undefined, () => undefined);\n return result;\n };\n}\n", "import * as SecureStore from \"expo-secure-store\";\nimport type { AuthTokenStore } from \"../types.js\";\n\nexport interface SecureStoreAdapter {\n getItemAsync(key: string): Promise<string | null>;\n setItemAsync(key: string, value: string): Promise<void>;\n deleteItemAsync(key: string): Promise<void>;\n}\n\n// @ref LLP 1013#4-locks-the-token-store-and-the-partition \u2014 SecureStore keys\n// use its legal alphabet; token deletion also deletes the cached principal.\nexport function expoSecureTokenStore(name = \"default\", adapter: SecureStoreAdapter = SecureStore): AuthTokenStore {\n if (!/^[A-Za-z0-9._-]+$/.test(name)) throw new TypeError(\"expoSecureTokenStore name must contain only A-Z, a-z, 0-9, '.', '_', or '-'\");\n const keys = { token: `snapback2.${name}.token`, principal: `snapback2.${name}.principal` };\n const cache: Partial<Record<keyof typeof keys, string | null>> = {};\n let tail = Promise.resolve();\n function ordered<T>(body: () => Promise<T>): Promise<T> {\n const result = tail.then(body);\n tail = result.then(() => undefined, () => undefined);\n return result;\n }\n const load = (kind: keyof typeof keys) => ordered(async () => {\n if (cache[kind] === undefined) cache[kind] = await adapter.getItemAsync(keys[kind]);\n return cache[kind]!;\n });\n const save = (kind: keyof typeof keys, value: string | null) => ordered(async () => {\n if (value !== null && new TextEncoder().encode(value).byteLength > 2048) {\n throw new TypeError(\"expoSecureTokenStore values must fit in 2 KB\");\n }\n if (value === null && kind === \"token\") {\n delete cache.token;\n delete cache.principal;\n const results = await Promise.allSettled(Object.values(keys).map((key) => adapter.deleteItemAsync(key)));\n const failure = results.find((result) => result.status === \"rejected\");\n if (failure?.status === \"rejected\") throw failure.reason;\n cache.token = cache.principal = null;\n } else {\n delete cache[kind];\n if (value === null) await adapter.deleteItemAsync(keys[kind]);\n else await adapter.setItemAsync(keys[kind], value);\n cache[kind] = value;\n }\n });\n return { load: () => load(\"token\"), save: (value) => save(\"token\", value),\n loadPrincipal: () => load(\"principal\"), savePrincipal: (value) => save(\"principal\", value) };\n}\n", "/** The store's answer and cursor-chain keys share one shape-preserving encoding. */\nexport function canonical(value: unknown): string {\n if (value === undefined) return \"undefined\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n return `{${Object.keys(value as object).sort().map((key) =>\n `${JSON.stringify(key)}:${canonical((value as Record<string, unknown>)[key])}`).join(\",\")}}`;\n}\n", "// @ref LLP 1012#7-writes-offline \u2014 cursor identity is not order. Only held,\n// post-commit next links prove progress; explicit negatives settle deletions.\nimport type { StoredAnswer, WatermarkRecord } from \"./range-store.js\";\nimport { canonical } from \"./canonical.js\";\n\nexport interface OverlayWatermark extends Pick<WatermarkRecord, \"op\" | \"args\" | \"watermark\"> {\n cursorArg: string;\n /** Last proven progress, and positions already consumed, survive a remount/reopen. */\n progress?: string;\n consumed?: string[];\n}\n\nfunction object(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** Each page keeps the name used when it was filed, including a pre-manifest c. */\nexport function pagePosition(page: Pick<StoredAnswer, \"op\" | \"args\" | \"cursorArg\">, mark: OverlayWatermark): string | null | undefined {\n if (page.op !== mark.op || !object(page.args) || !object(mark.args)) return undefined;\n const cursor = page.cursorArg ?? mark.cursorArg;\n const base = { ...mark.args };\n const args = { ...page.args };\n // Before the manifest, a caller can already pass { after: null } while the\n // recorded name is c. Only the now-known cursor substitutes for that missing\n // field; other nullable/string arguments remain part of the query identity.\n delete base[Object.hasOwn(base, mark.cursorArg) ? mark.cursorArg : cursor];\n delete args[cursor];\n if (canonical(base) !== canonical(args)) return undefined;\n const position = page.args[cursor];\n return position === null || typeof position === \"string\" ? position : undefined;\n}\n\n/**\n * An ordered path starting at the commit snapshot, never inferred from a newer\n * seq or a different opaque string. A cycle, ambiguity, or missing link ends\n * the proven prefix. The caller supplies only non-empty, intact held pages.\n */\nexport function cursorChain(pages: StoredAnswer[], mark: OverlayWatermark, committedSeq: number): string[] {\n const links = new Map<string | null, string | null>();\n for (const page of pages) {\n if ((page.nextSeq ?? page.seq) < committedSeq || typeof page.next !== \"string\") continue;\n const position = pagePosition(page, mark);\n if (position === undefined) continue;\n // Conflicting links quarantine only this position, including off-path ones.\n links.set(position, links.has(position) && links.get(position) !== page.next ? null : page.next);\n }\n const seen = new Set<string | null>([mark.watermark]);\n const chain: string[] = [];\n let position = mark.watermark;\n while (links.has(position)) {\n const next = links.get(position);\n if (next == null || seen.has(next)) break;\n seen.add(next);\n chain.push(next);\n position = next;\n }\n return chain;\n}\n\n/** A re-mark can consume progress only once and only beyond the last proven mark. */\nexport function advanceOverlay(mark: OverlayWatermark, tail: WatermarkRecord | undefined, chain: string[]): boolean {\n if (!tail || pagePosition({ ...tail, args: object(tail.args)\n ? { ...tail.args, [tail.cursorArg ?? mark.cursorArg]: tail.watermark } : tail.args }, mark) === undefined) return false;\n if (typeof tail.watermark !== \"string\" || (mark.consumed ?? []).includes(tail.watermark)) return false;\n const at = chain.indexOf(tail.watermark);\n if (mark.progress !== undefined && !chain.includes(mark.progress)) {\n // A page can grow or be evicted. Re-anchor at the nearest surviving consumed\n // position (or the snapshot root), without forgetting what already counted.\n mark.progress = [...(mark.consumed ?? [])].reverse().find((position) => chain.includes(position));\n }\n const previous = mark.progress === undefined ? -1 : chain.indexOf(mark.progress);\n if (at < 0 || at <= previous) return false;\n mark.progress = tail.watermark;\n mark.consumed = [...new Set([...(mark.consumed ?? []), ...chain.slice(0, at + 1)])];\n return true;\n}\n", "// @ref LLP 1012#4-the-range-store \u2014 every carrier persists the same per-principal answer/range model.\n// @ref LLP 1012#5-retention-revocation-and-the-fence \u2014 eviction is decided once over a complete swap.\n// @ref LLP 1012#9-asset-bytes-on-the-device \u2014 asset bytes leave in the same commit as the row whose lease held them.\n\nimport {\n applyByteSwap,\n assetIdsIn,\n byteKey,\n leasedAssets,\n viewedOnlyAssets,\n type ByteCacheEntry,\n type ByteCacheStatus,\n type ByteDelta,\n type ByteSwapRequest,\n type ViewedRecord,\n} from \"./byte-cache.js\";\n\nimport { advanceOverlay, cursorChain, pagePosition, type OverlayWatermark } from \"./overlay-retirement.js\";\nimport { canonical } from \"./canonical.js\";\n\nexport type PrincipalPartition = string;\nexport type RetentionPolicy = \"until-revoked\" | \"delivered-history\";\n\nexport interface RowRef { table: string; id: string }\nexport interface StoredRow extends RowRef { row: Record<string, unknown> }\n\nexport interface ReceiptRange {\n site: string;\n table: string;\n index: string;\n prefix: unknown[];\n order: \"Asc\" | \"Desc\";\n take: number;\n after: unknown;\n before: unknown;\n gt: unknown;\n gte: unknown;\n lt: unknown;\n lte: unknown;\n rowIds: string[];\n stop: \"Limit\" | \"Exhausted\";\n absence: boolean;\n haloId?: string;\n ruleHash: string;\n /**\n * Members this page was recorded with that a later swap evicted (LLP 1012 \u00A75):\n * the page's answer is `partial/evicted` from then on, and the twin's\n * drained-prefix rule (\u00A76) no longer counts the page as a link in a complete chain.\n */\n evictedIds?: string[];\n}\n\nexport interface Receipt {\n ranges: ReceiptRange[];\n absences: Array<[table: string, index: string, key: unknown[]]>;\n verdicts: unknown[];\n}\n\nexport interface HeldAnswer<Result = unknown> {\n op: string;\n args: unknown;\n state: \"complete\" | \"capped\" | \"partial\" | \"denied\";\n data?: Result;\n next?: string | null;\n seq: number;\n validator?: string;\n receipt?: Receipt;\n deliveredAt: number;\n retained?: boolean;\n caughtUp?: boolean;\n watermark?: string | null;\n reason?: string;\n rule?: string;\n}\n\nexport interface StoredAnswer extends Omit<HeldAnswer, \"data\"> {\n data?: unknown;\n refs: RowRef[];\n order: number;\n fingerprint?: string;\n /** Cursor argument used when this page was filed, before or after manifest load. */\n cursorArg?: string;\n /** Seq of the delivery that recorded `next`; conditional refreshes cannot renew a link. */\n nextSeq?: number;\n}\n\nexport interface WatermarkRecord {\n op: string;\n args: unknown;\n /** The argument the manifest types as this query's cursor; `c` before the manifest loads. */\n cursorArg?: string;\n watermark: string | null;\n validator?: string;\n generation?: string;\n schemaHash?: string;\n authEpoch?: number;\n updatedAt: number;\n /**\n * Durable position among this partition's drained queries: assigned by the store\n * when the query first records a watermark, kept across every later mark. The\n * lowest order is the log a settlement and a resume name (LLP 1012 \u00A77).\n */\n order?: number;\n}\n\n/** The generation and authority every held envelope of a partition was delivered under. */\nexport interface CoverageFacts {\n generation: string;\n schemaHash: string;\n authEpoch: number;\n}\n\n/** One certified operation as `GET /api/program` serves it: the IR the twin runs and its certificate. */\nexport interface HeldOperation {\n kind: \"query\" | \"mutation\";\n planHash: string;\n ir: unknown;\n certificate: unknown;\n}\n\n// @ref LLP 1012#8-the-delivery-envelope-the-validator-and-resume \u2014 the program\n// custody the evaluator ticket names: the certified IR, certificates, and the\n// schema of one generation, held in the partition so a cold start with the\n// network cut still evaluates and prices from the certificate.\nexport interface HeldProgram {\n generation: string;\n schemaHash: string;\n schema: OfflineSchema & Record<string, unknown>;\n programs: Record<string, HeldOperation>;\n}\n\nexport interface Coverage {\n rows: StoredRow[];\n ranges: ReceiptRange[];\n absences: Receipt[\"absences\"];\n verdicts: unknown[];\n watermarks: WatermarkRecord[];\n /**\n * View-once rows already viewed on this partition: absent from `rows`, listed under\n * `absences` as a `byId` point, and named here so a replay never renders them (LLP 1012 \u00A79).\n */\n viewed?: RowRef[];\n /** Rows a swap evicted (LLP 1012 \u00A75): the twin reports a read of one as `evicted`, not `never-held`. */\n evicted?: RowRef[];\n /** The generation and auth epoch the held coverage was delivered under; absent when nothing is held. */\n facts?: CoverageFacts;\n /**\n * The facts a later delivery arrived under when its generation or schema differ\n * from `facts`: the held answers predate the program the server now runs, so the\n * twin serves nothing from them \u2014 every read is `hydrating` \u2014 until the reset\n * path drops this coverage and rebuilds it under the live generation (LLP 1012 \u00A78).\n */\n superseded?: CoverageFacts;\n /** The newest delivery's time: what an answer the twin computes reports as `stale.since`. */\n deliveredAt?: number;\n}\n\nexport type OutboxState = \"queued\" | \"committed\" | \"rejected\" | \"expired\";\n/** What the twin read when the intent was queued: the replay envelope's `trace` (LLP 1012 \u00A77). */\nexport interface OutboxTrace {\n points: Array<{ table: string; index: string; key: unknown[]; digest: string | null }>;\n verdicts: Array<{ ruleHash: string; inputsDigest: string; result: boolean }>;\n}\n// @ref LLP 1012#7-writes-offline \u2014 one durable intent: its pinned id slice, its\n// bytes, and its terminal response, so a retry is the same envelope.\nexport interface OutboxEntry {\n intent: string;\n grant: string;\n offset: number;\n count: number;\n ids: string[];\n op: string;\n args: unknown;\n issuedSeq: number;\n state: OutboxState;\n response?: unknown;\n predicted?: boolean;\n /** Prediction and its trace were skipped; the program will check this write on the server. */\n reason?: \"fence\";\n /** Engine-owned aggregate targets the prediction's overlay omits by design (the server writes them); absent when none. */\n omitted?: string[];\n trace?: OutboxTrace;\n createdAt: number;\n updatedAt: number;\n /** Durable FIFO position; assigned by the store when absent. */\n order?: number;\n}\n\n/** A principal-bound replay grant plus the client's own consumption cursor. */\nexport interface OutboxGrant {\n id: string;\n from: string;\n count: number;\n mintedAt: number;\n expiresAt: number;\n used: number;\n}\n\nexport interface OutboxStore {\n all(): Promise<OutboxEntry[]>;\n get(intent: string): Promise<OutboxEntry | undefined>;\n put(entry: OutboxEntry): Promise<void>;\n remove(intent: string): Promise<void>;\n /** The grant new intents consume from, if one is held. */\n grant(): Promise<OutboxGrant | undefined>;\n /** Every held grant, including those older queued intents still name. */\n grants(): Promise<OutboxGrant[]>;\n /** Each op's persisted write bound (`maxNewIds`); an enqueue refuses without one. */\n bounds(): Promise<Record<string, number>>;\n /** The prediction overlay by intent: the rows a queued intent's local run wrote, `removed` for a delete. */\n overlay(): Promise<Record<string, OverlayRow[]>>;\n /** The certified programs held for this partition, keyed by generation. */\n programs(): Promise<Record<string, HeldProgram>>;\n}\n\n/** A predicted row: the write's final image, or a `removed` marker for a row the intent deletes. */\nexport interface OverlayRow extends StoredRow { removed?: true }\n\nexport interface StoreDelivery {\n cursorArg?: string;\n op: string;\n args: unknown;\n state: HeldAnswer[\"state\"];\n data?: unknown;\n next?: string | null;\n seq: number;\n validator?: string;\n receipt?: Receipt;\n rows?: StoredRow[];\n deliveredAt?: number;\n reason?: string;\n rule?: string;\n}\n\nexport interface StoreTombstone extends RowRef { seq: number }\nexport interface StoreRefresh {\n op: string;\n args: unknown;\n seq: number;\n validator: string;\n deliveredAt?: number;\n}\n\nexport interface OfflineSchema {\n tables?: Record<string, {\n columns?: Record<string, unknown>;\n indexes?: Record<string, { columns?: string[] }>;\n retain?: RetentionPolicy;\n }>;\n}\n\nexport interface StoreSwap {\n deliveries?: StoreDelivery[];\n refreshes?: StoreRefresh[];\n tombstones?: StoreTombstone[];\n retention?: Record<string, RetentionPolicy>;\n schema?: OfflineSchema;\n watermark?: WatermarkRecord;\n resetCoverage?: boolean;\n /** One validated resume response, including unchanged; never a query re-delivery. */\n resumeSeq?: number;\n dropAnswers?: string[];\n outbox?: { put?: OutboxEntry[]; remove?: string[] };\n /**\n * Byte-cache puts and read touches; they land in the same swap as the rows: one\n * readwrite transaction on IndexedDB, an ordered payload write + state rename with\n * a sweep on open for the Node file carrier.\n */\n bytes?: ByteSwapRequest;\n /** View-once rows viewed now: excluded from every later answer, their bytes never cached. */\n viewed?: RowRef[];\n /** `current` names the grant new intents consume; `null` clears it. */\n grants?: { put?: OutboxGrant[]; current?: string | null; remove?: string[] };\n /** Predicted rows keyed by intent; visible to the twin's local evaluation, never to `answer()` (LLP 1012 \u00A77). */\n overlay?: { put?: Record<string, OverlayRow[]>; remove?: string[] };\n /** The certified programs, replaced whole (one generation is held at a time); custody like the outbox. */\n programs?: Record<string, HeldProgram>;\n /** The facts the swap's envelopes were delivered under; cleared by `resetCoverage`. */\n facts?: CoverageFacts;\n /** A rotation: the facts a refused delivery arrived under; held coverage is superseded until rebuild completion clears it with `null`. */\n superseded?: CoverageFacts | null;\n /**\n * The program's write bounds, replaced whole: what `/api/program` certified each op may\n * mint. Custody like the outbox \u2014 a coverage reset never touches it (LLP 1012 \u00A77).\n */\n bounds?: Record<string, number>;\n}\n\nexport interface RangeStore {\n open(partition: PrincipalPartition): Promise<void>;\n unseal(): Promise<void>;\n seal(): Promise<void>;\n wipe(partition: PrincipalPartition): Promise<void>;\n answer<Result = unknown>(op: string, args: unknown): Promise<HeldAnswer<Result> | undefined>;\n commit(swap: StoreSwap): Promise<void>;\n coverage(): Promise<Coverage>;\n readonly outbox: OutboxStore;\n close?(): Promise<void> | void;\n}\n\nexport interface RangeStoreFactory {\n (): RangeStore;\n readonly carrier?: string;\n}\n\nexport class OfflineStoreFailure extends Error {\n constructor(readonly code: \"E_OFFLINE_CARRIER\" | \"E_OFFLINE_LOCK\", message: string, readonly rewrite?: string) {\n super(message);\n this.name = \"OfflineStoreFailure\";\n }\n}\n\nexport interface PersistedRangeState {\n version: 1;\n sealed: boolean;\n clock: number;\n rows: Record<string, StoredRow>;\n answers: Record<string, StoredAnswer>;\n watermarks: Record<string, WatermarkRecord>;\n outbox: Record<string, OutboxEntry>;\n grants: Record<string, OutboxGrant>;\n currentGrant?: string;\n overlay: Record<string, OverlayRow[]>;\n /** Per committed intent, successful resumes or proven tail advances without its rows. */\n overlayMisses: Record<string, number>;\n /** The commit-time tail snapshot; null after reset until the next drain establishes a new head. */\n overlayWatermarks: Record<string, OverlayWatermark | null>;\n /** Only primary absences and tombstones, scoped to each prediction's ids. */\n overlayNegatives: Record<string, Record<string, { seq: number; source: \"absence\" | \"tombstone\" }>>;\n bounds: Record<string, number>;\n programs: Record<string, HeldProgram>;\n facts?: CoverageFacts;\n superseded?: CoverageFacts;\n negative: Record<string, number>;\n rowSeq: Record<string, number>;\n /** The byte-cache index; payloads live beside the state in the carrier, keyed by `byteKey`. */\n assets: Record<string, ByteCacheEntry>;\n viewed: Record<string, ViewedRecord>;\n}\n\nexport interface RangeStoreBackend {\n readonly carrier: string;\n open(partition: PrincipalPartition): Promise<PersistedRangeState | undefined>;\n /** One carrier transaction: the state, plus the byte payloads to write and the keys to drop. */\n replace(state: PersistedRangeState, bytes: ByteDelta): Promise<void>;\n readBytes?(key: string): Promise<Uint8Array | undefined>;\n wipe(partition: PrincipalPartition): Promise<void>;\n close(): Promise<void> | void;\n}\n\nconst NO_BYTES: ByteDelta = { put: [], remove: [] };\n\nexport function emptyState(): PersistedRangeState {\n return {\n version: 1, sealed: false, clock: 0, rows: {}, answers: {}, watermarks: {}, outbox: {},\n grants: {}, overlay: {}, overlayMisses: {}, overlayWatermarks: {}, overlayNegatives: {}, bounds: {}, programs: {}, negative: {}, rowSeq: {}, assets: {}, viewed: {},\n };\n}\n\nfunction clone<T>(value: T): T {\n return structuredClone(value);\n}\n\nexport function canonicalAnswerKey(op: string, args: unknown): string {\n return `${op}\\u0000${canonical(args === undefined ? args : jsonState(args))}`;\n}\n\nfunction rowKey(ref: RowRef): string {\n return `${ref.table}\\u0000${ref.id}`;\n}\n\nfunction viewedRef(key: string): RowRef {\n const at = key.indexOf(String.fromCharCode(0));\n return { table: key.slice(0, at), id: key.slice(at + 1) };\n}\n\nfunction recordEviction(evictions: Map<string, StoreTombstone>, eviction: StoreTombstone): void {\n const key = rowKey(eviction);\n if ((evictions.get(key)?.seq ?? -1) <= eviction.seq) evictions.set(key, eviction);\n}\n\nexport function rowReference(table: string, id: string): { $row: RowRef } {\n return { $row: { table, id } };\n}\n\nfunction asRowRef(value: unknown): RowRef | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n const marker = (value as { $row?: unknown }).$row;\n return marker !== null && typeof marker === \"object\" && !Array.isArray(marker)\n && Object.keys(marker).sort().join(\",\") === \"id,table\"\n && typeof (marker as RowRef).table === \"string\" && typeof (marker as RowRef).id === \"string\"\n ? { table: (marker as RowRef).table, id: (marker as RowRef).id }\n : undefined;\n}\n\nfunction collectRefs(value: unknown, refs = new Map<string, RowRef>()): RowRef[] {\n const ref = asRowRef(value);\n if (ref) refs.set(rowKey(ref), ref);\n else if (Array.isArray(value)) for (const item of value) collectRefs(item, refs);\n else if (value && typeof value === \"object\") {\n for (const item of Object.values(value as Record<string, unknown>)) collectRefs(item, refs);\n }\n return [...refs.values()];\n}\n\nfunction expand(value: unknown, rows: Record<string, StoredRow>, viewed?: Record<string, unknown>): unknown {\n const ref = asRowRef(value);\n if (ref) return viewed?.[rowKey(ref)] ? null : rows[rowKey(ref)]?.row ?? null;\n if (Array.isArray(value)) return value.map((item) => expand(item, rows, viewed));\n if (!value || typeof value !== \"object\") return value;\n return Object.fromEntries(Object.entries(value as Record<string, unknown>)\n .map(([key, item]) => [key, expand(item, rows, viewed)]));\n}\n\nfunction hiddenRefs(before: unknown, after: unknown, output = new Map<string, RowRef>()): RowRef[] {\n if (after === null || after === undefined) {\n for (const ref of collectRefs(before)) output.set(rowKey(ref), ref);\n return [...output.values()];\n }\n const ref = asRowRef(before);\n if (ref && after === null) output.set(rowKey(ref), ref);\n else if (Array.isArray(before) && Array.isArray(after)) {\n for (let index = 0; index < before.length; index += 1) {\n hiddenRefs(before[index], index < after.length ? after[index] : undefined, output);\n }\n } else if (before && after && typeof before === \"object\" && typeof after === \"object\"\n && !Array.isArray(before) && !Array.isArray(after)) {\n for (const key of Object.keys(before as object)) {\n hiddenRefs(\n (before as Record<string, unknown>)[key],\n Object.prototype.hasOwnProperty.call(after, key) ? (after as Record<string, unknown>)[key] : undefined,\n output,\n );\n }\n }\n return [...output.values()];\n}\n\nfunction restoreRetained(before: unknown, after: unknown, retained: Set<string>): unknown {\n const ref = asRowRef(before);\n if (ref && (after === null || after === undefined) && retained.has(rowKey(ref))) return before;\n if (Array.isArray(before) && Array.isArray(after)) {\n const result = after.map((item, index) => index < before.length\n ? restoreRetained(before[index], item, retained) : item);\n for (let index = after.length; index < before.length; index += 1) {\n if (collectRefs(before[index]).some((item) => retained.has(rowKey(item)))) result.push(clone(before[index]));\n }\n return result;\n }\n if (before && after && typeof before === \"object\" && typeof after === \"object\"\n && !Array.isArray(before) && !Array.isArray(after)) {\n const result = clone(after as Record<string, unknown>);\n for (const key of Object.keys(before as object)) {\n const old = (before as Record<string, unknown>)[key];\n if (Object.prototype.hasOwnProperty.call(result, key)) result[key] = restoreRetained(old, result[key], retained);\n else if (collectRefs(old).some((item) => retained.has(rowKey(item)))) result[key] = clone(old);\n }\n return result;\n }\n if ((after === null || after === undefined)\n && collectRefs(before).some((item) => retained.has(rowKey(item)))) return clone(before);\n return after;\n}\n\nfunction sameRange(left: ReceiptRange, right: ReceiptRange): boolean {\n return left.site === right.site && left.table === right.table && left.index === right.index\n && canonical(left.prefix) === canonical(right.prefix)\n && left.order === right.order\n && canonical(left.after) === canonical(right.after)\n && canonical(left.before) === canonical(right.before)\n && canonical(left.gt) === canonical(right.gt)\n && canonical(left.gte) === canonical(right.gte)\n && canonical(left.lt) === canonical(right.lt)\n && canonical(left.lte) === canonical(right.lte)\n && left.ruleHash === right.ruleHash;\n}\n\nfunction compareValue(left: unknown, right: unknown): number {\n if (left === right) return 0;\n if (typeof left === \"number\" && typeof right === \"number\") return left < right ? -1 : 1;\n if (typeof left === \"string\" && typeof right === \"string\") return left < right ? -1 : 1;\n if (typeof left === \"boolean\" && typeof right === \"boolean\") return left ? 1 : -1;\n const a = canonical(left);\n const b = canonical(right);\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\nfunction compareKey(left: unknown[], right: unknown[]): number {\n for (let index = 0; index < Math.min(left.length, right.length); index += 1) {\n const order = compareValue(left[index], right[index]);\n if (order !== 0) return order;\n }\n return left.length - right.length;\n}\n\nfunction indexKey(schema: OfflineSchema | undefined, range: ReceiptRange, row: StoredRow | undefined): unknown[] | undefined {\n const columns = schema?.tables?.[range.table]?.indexes?.[range.index]?.columns;\n if (!row || !Array.isArray(columns) || !columns.every((item) => typeof item === \"string\")) return undefined;\n const key = columns.map((column) => row.row[column]);\n return key.some((item) => item === undefined) ? undefined : key;\n}\n\nfunction cursorKey(value: unknown, width: number): unknown[] | undefined {\n if (value === null || value === undefined) return undefined;\n if (Array.isArray(value)) return value.length === width ? value : undefined;\n return width === 1 ? [value] : undefined;\n}\n\nfunction insidePrefixBounds(key: unknown[], range: ReceiptRange): boolean {\n if (key.length < range.prefix.length\n || compareKey(key.slice(0, range.prefix.length), range.prefix) !== 0) return false;\n const suffix = key.slice(range.prefix.length);\n const after = cursorKey(range.after, suffix.length);\n const before = cursorKey(range.before, suffix.length);\n if (after && (range.order === \"Asc\" ? compareKey(suffix, after) <= 0 : compareKey(suffix, after) >= 0)) return false;\n if (before && (range.order === \"Asc\" ? compareKey(suffix, before) >= 0 : compareKey(suffix, before) <= 0)) return false;\n const first = suffix[0];\n if (range.gt !== null && range.gt !== undefined && compareValue(first, range.gt) <= 0) return false;\n if (range.gte !== null && range.gte !== undefined && compareValue(first, range.gte) < 0) return false;\n if (range.lt !== null && range.lt !== undefined && compareValue(first, range.lt) >= 0) return false;\n if (range.lte !== null && range.lte !== undefined && compareValue(first, range.lte) > 0) return false;\n return true;\n}\n\nfunction inFreshExtent(\n id: string,\n held: ReceiptRange,\n fresh: ReceiptRange,\n rows: Record<string, StoredRow>,\n schema: OfflineSchema | undefined,\n): boolean {\n const key = indexKey(schema, held, rows[rowKey({ table: held.table, id })]);\n if (!key) return fresh.stop === \"Exhausted\";\n if (!insidePrefixBounds(key, fresh)) return false;\n if (fresh.stop === \"Exhausted\") return true;\n const presentKeys = fresh.rowIds\n .map((rowId) => indexKey(schema, fresh, rows[rowKey({ table: fresh.table, id: rowId })]))\n .filter(Array.isArray) as unknown[][];\n if (presentKeys.length === 0) return false;\n const first = presentKeys.reduce((a, b) => compareKey(a, b) <= 0 ? a : b);\n const last = presentKeys.reduce((a, b) => compareKey(a, b) >= 0 ? a : b);\n return compareKey(key, first) >= 0 && compareKey(key, last) <= 0;\n}\n\n/** One JSON form for warm state and every carrier: omit undefined fields, preserve null. */\nexport function jsonState<T>(value: T): T {\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nfunction normalizeState(value: PersistedRangeState | undefined): PersistedRangeState {\n if (!value) return emptyState();\n value = jsonState(value);\n if (value.version !== 1 || typeof value.rows !== \"object\" || typeof value.answers !== \"object\") {\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store contains an unsupported format\");\n }\n return {\n ...value,\n watermarks: value.watermarks ?? {},\n outbox: value.outbox ?? {},\n grants: value.grants ?? {},\n overlay: value.overlay ?? {},\n overlayMisses: value.overlayMisses ?? {},\n overlayWatermarks: value.overlayWatermarks ?? {},\n overlayNegatives: value.overlayNegatives ?? {},\n bounds: value.bounds ?? {},\n programs: value.programs ?? {},\n negative: value.negative ?? {},\n rowSeq: value.rowSeq ?? {},\n assets: value.assets ?? {},\n viewed: value.viewed ?? {},\n };\n}\n\n/**\n * The log a settlement's tail request and a resume's `log` both name: the drained\n * query whose watermark was recorded first in this partition \u2014 the first-mounted\n * drain, since a drain records its watermark when it first catches up \u2014 by the\n * store's durable `order`, so the choice survives restarts and re-marks and never\n * follows whichever page moved last (LLP 1012 \u00A77, \u00A78).\n */\nexport function tailWatermark(watermarks: WatermarkRecord[]): WatermarkRecord | undefined {\n return [...watermarks].sort((a, b) =>\n (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER)\n || a.updatedAt - b.updatedAt\n || canonicalAnswerKey(a.op, a.args).localeCompare(canonicalAnswerKey(b.op, b.args)))[0];\n}\n\n/** Two post-commit resumes or proven tail advances retire a stranded prediction. */\nconst OVERLAY_PATIENCE = 2;\n\nfunction outboxOrder(entries: Record<string, OutboxEntry>): OutboxEntry[] {\n return Object.values(entries).sort((a, b) =>\n (a.order ?? a.createdAt) - (b.order ?? b.createdAt) || a.createdAt - b.createdAt || (a.intent < b.intent ? -1 : 1));\n}\n\n/** Shared swap engine; carrier subclasses only provide the atomic replace. */\nexport class PersistentRangeStore implements RangeStore {\n private state = emptyState();\n private partition?: PrincipalPartition;\n private tail: Promise<void> = Promise.resolve();\n\n readonly outbox: OutboxStore = {\n all: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(outboxOrder(this.state.outbox));\n }),\n get: async (intent) => this.read(() => {\n this.ensureUnsealed();\n return this.state.outbox[intent] && clone(this.state.outbox[intent]);\n }),\n put: async (entry) => this.commit({ outbox: { put: [entry] } }),\n remove: async (intent) => this.commit({ outbox: { remove: [intent] } }),\n grant: async () => this.read(() => {\n this.ensureUnsealed();\n const current = this.state.currentGrant === undefined ? undefined : this.state.grants[this.state.currentGrant];\n return current && clone(current);\n }),\n grants: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(Object.values(this.state.grants));\n }),\n bounds: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(this.state.bounds);\n }),\n overlay: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(this.state.overlay);\n }),\n programs: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(this.state.programs);\n }),\n };\n\n constructor(private readonly backend: RangeStoreBackend) {}\n\n async open(partition: PrincipalPartition): Promise<void> {\n if (typeof partition !== \"string\" || partition.length === 0) {\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store partition must be a principal id\");\n }\n await this.enqueue(async () => {\n if (this.partition === partition) return;\n if (this.partition !== undefined && this.partition !== partition) await this.backend.close();\n this.partition = partition;\n this.state = normalizeState(await this.backend.open(partition));\n });\n }\n\n async unseal(): Promise<void> {\n await this.enqueue(async () => {\n this.ensureOpen();\n if (!this.state.sealed) return;\n const next = { ...clone(this.state), sealed: false };\n await this.backend.replace(next, NO_BYTES);\n this.state = next;\n });\n }\n\n async seal(): Promise<void> {\n await this.enqueue(async () => {\n this.ensureOpen();\n const next = { ...clone(this.state), sealed: true };\n await this.backend.replace(next, NO_BYTES);\n this.state = next;\n });\n }\n\n async wipe(partition: PrincipalPartition): Promise<void> {\n await this.enqueue(async () => {\n await this.backend.wipe(partition);\n if (this.partition === partition) {\n this.partition = undefined;\n this.state = emptyState();\n }\n });\n }\n\n async answer<Result = unknown>(op: string, args: unknown): Promise<HeldAnswer<Result> | undefined> {\n return this.read(() => {\n if (this.state.sealed) return undefined;\n const key = canonicalAnswerKey(op, args);\n const stored = this.state.answers[key];\n if (!stored) return undefined;\n const watermark = this.state.watermarks[key];\n const { refs: _refs, order: _order, fingerprint: _fingerprint, cursorArg: _cursorArg, data, ...answer } = clone(stored);\n return {\n ...answer,\n // A viewed view-once row reads as absent: the view was its one delivery (LLP 1012 \u00A79).\n ...(data === undefined ? {} : { data: expand(data, this.state.rows, this.state.viewed) as Result }),\n ...(watermark === undefined ? {} : { caughtUp: true, watermark: watermark.watermark }),\n };\n });\n }\n\n async coverage(): Promise<Coverage> {\n return this.read(() => {\n if (this.state.sealed) return { rows: [], ranges: [], absences: [], verdicts: [], watermarks: [], viewed: [], evicted: [] };\n const ranges = new Map<string, ReceiptRange>();\n const absences = new Map<string, Receipt[\"absences\"][number]>();\n const verdicts = new Map<string, unknown>();\n for (const answer of Object.values(this.state.answers)) {\n for (const range of answer.receipt?.ranges ?? []) {\n ranges.set(`${range.site}\\u0000${canonical(range.prefix)}\\u0000${canonical([\n range.order, range.after, range.before, range.gt, range.gte, range.lt, range.lte,\n ])}`, clone(range));\n }\n for (const absence of answer.receipt?.absences ?? []) absences.set(canonical(absence), clone(absence));\n for (const verdict of answer.receipt?.verdicts ?? []) verdicts.set(canonical(verdict), clone(verdict));\n }\n // A viewed view-once row is absent to the twin: not a row, and a byId absence (LLP 1012 \u00A79).\n const viewed = Object.keys(this.state.viewed).map(viewedRef);\n for (const ref of viewed) {\n const absence: Receipt[\"absences\"][number] = [ref.table, \"byId\", [ref.id]];\n absences.set(canonical(absence), absence);\n }\n let deliveredAt: number | undefined;\n for (const answer of Object.values(this.state.answers)) {\n if (deliveredAt === undefined || answer.deliveredAt > deliveredAt) deliveredAt = answer.deliveredAt;\n }\n return {\n rows: clone(Object.entries(this.state.rows).filter(([key]) => !this.state.viewed[key]).map(([, row]) => row)),\n ranges: [...ranges.values()],\n absences: [...absences.values()],\n verdicts: [...verdicts.values()],\n watermarks: clone(Object.values(this.state.watermarks)),\n viewed,\n evicted: Object.keys(this.state.negative).map(viewedRef),\n ...(this.state.facts === undefined ? {} : { facts: clone(this.state.facts) }),\n ...(this.state.superseded === undefined ? {} : { superseded: clone(this.state.superseded) }),\n ...(deliveredAt === undefined ? {} : { deliveredAt }),\n };\n });\n }\n\n async commit(swap: StoreSwap): Promise<void> {\n await this.enqueue(async () => {\n this.ensureOpen();\n // Byte payloads are not cloned: they can be megabytes and the swap never mutates them.\n const { bytes, ...rest } = swap;\n const delta: ByteDelta = { put: [], remove: [] };\n // Normalize before deriving answer keys/fingerprints, then normalize the state we publish.\n const next = normalizeState(this.applySwap(clone(this.state), { ...jsonState(rest), ...(bytes === undefined ? {} : { bytes }) }, delta));\n await this.backend.replace(next, delta);\n this.state = next;\n });\n }\n\n /** The cached rendition for an asset at a width; nothing when unheld, sealed, or the payload is gone. */\n async readBytes(assetId: string, width: number | null): Promise<{ bytes: Uint8Array; type: string } | undefined> {\n return this.read(async () => {\n if (this.state.sealed) return undefined;\n const key = byteKey(assetId, width);\n const entry = this.state.assets[key];\n if (!entry) return undefined;\n const bytes = await this.backend.readBytes?.(key);\n return bytes && bytes.byteLength === entry.size ? { bytes, type: entry.type } : undefined;\n });\n }\n\n async bytes(): Promise<ByteCacheStatus> {\n return this.read(() => {\n if (this.state.sealed) return { entries: [], totalBytes: 0, viewed: [] };\n const entries = clone(Object.values(this.state.assets));\n return {\n entries,\n totalBytes: entries.reduce((sum, entry) => sum + entry.size, 0),\n viewed: Object.keys(this.state.viewed).map(viewedRef),\n };\n });\n }\n\n /** Held rows whose values carry this asset record: the lease under which its bytes may be cached. */\n async rowsReferencing(assetId: string): Promise<StoredRow[]> {\n return this.read(() => this.state.sealed\n ? []\n : clone(Object.values(this.state.rows).filter((row) => assetIdsIn(row.row).has(assetId))));\n }\n\n /** True while every held row carrying this asset is a viewed view-once row (per row, LLP 1012 \u00A79). */\n async viewedAsset(assetId: string): Promise<boolean> {\n return this.read(() => !this.state.sealed && viewedOnlyAssets(this.state).has(assetId));\n }\n\n /** The viewed view-once rows; a live frame nulls them exactly as a held answer does. */\n async viewedRows(): Promise<RowRef[]> {\n return this.read(() => this.state.sealed ? [] : Object.keys(this.state.viewed).map(viewedRef));\n }\n\n /**\n * LRU read stamps, coalesced per swap: a read stamps the entry in memory and the next\n * swap's `replace` persists it, so a read never rewrites the carrier (LLP 1012 \u00A79).\n */\n async touchBytes(keys: string[]): Promise<void> {\n await this.enqueue(async () => {\n if (this.partition === undefined || this.state.sealed) return;\n for (const key of keys) {\n const entry = this.state.assets[key];\n if (entry) entry.lastRead = ++this.state.clock;\n }\n });\n }\n\n async close(): Promise<void> {\n await this.enqueue(async () => {\n this.partition = undefined;\n this.state = emptyState();\n await this.backend.close();\n });\n }\n\n private applySwap(state: PersistedRangeState, swap: StoreSwap, bytes: ByteDelta): PersistedRangeState {\n if (state.sealed) throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store is sealed\");\n if (swap.resetCoverage) {\n state.rows = {};\n // Sequence guards belong to this generation's coverage, just like rows.\n // A query-only successor can deliver the same row at the same data seq.\n state.rowSeq = {};\n state.negative = {};\n state.answers = {};\n state.watermarks = {};\n // These describe coverage, unlike the overlay and its replay entry.\n state.overlayWatermarks = Object.fromEntries(Object.keys(state.overlay).map((intent) => [intent, null]));\n state.overlayMisses = {};\n delete state.facts;\n }\n if (swap.superseded === null) delete state.superseded;\n if (swap.resumeSeq !== undefined && (!Number.isSafeInteger(swap.resumeSeq) || swap.resumeSeq < 0)) {\n throw new TypeError(\"store resume seq must be a non-negative safe integer\");\n }\n if (swap.facts) state.facts = clone(swap.facts);\n if (swap.superseded) state.superseded = clone(swap.superseded);\n const explicitEvictions = new Map<string, StoreTombstone>();\n // Keep provenance distinct from hidden-row and extent evictions. These facts\n // join each matching overlay below, even while its response is still queued.\n const authoritativeNegatives = new Map<string, { seq: number; source: \"absence\" | \"tombstone\" }>();\n const recordNegative = (ref: StoreTombstone, source: \"absence\" | \"tombstone\") => {\n const key = rowKey(ref);\n if ((authoritativeNegatives.get(key)?.seq ?? -1) <= ref.seq) {\n authoritativeNegatives.set(key, { seq: ref.seq, source });\n }\n recordEviction(explicitEvictions, ref);\n };\n const recordAbsences = (answer: Pick<StoredAnswer, \"receipt\" | \"seq\">) => {\n for (const [table, index, key] of answer.receipt?.absences ?? []) {\n if (index !== \"byId\" || key.length !== 1) {\n throw new TypeError(\"store receipts may evict only a primary byId absence\");\n }\n if (typeof key[0] === \"string\") recordNegative({ table, id: key[0], seq: answer.seq }, \"absence\");\n }\n };\n for (const key of swap.dropAnswers ?? []) delete state.answers[key];\n for (const refresh of swap.refreshes ?? []) {\n const answer = state.answers[canonicalAnswerKey(refresh.op, refresh.args)];\n if (!answer || refresh.seq < answer.seq) continue;\n if (answer.validator !== undefined && answer.validator !== refresh.validator) {\n throw new TypeError(`conditional validator changed for ${refresh.op}`);\n }\n if (refresh.seq === answer.seq) continue;\n answer.nextSeq ??= answer.seq;\n answer.seq = refresh.seq;\n answer.validator = refresh.validator;\n answer.deliveredAt = refresh.deliveredAt ?? Date.now();\n answer.order = ++state.clock;\n recordAbsences(answer);\n }\n const before = clone(state.answers);\n const freshRanges: Array<{ range: ReceiptRange; seq: number }> = [];\n for (const ref of swap.tombstones ?? []) {\n recordNegative(ref, \"tombstone\");\n }\n for (const delivery of swap.deliveries ?? []) {\n if (!Number.isSafeInteger(delivery.seq) || delivery.seq < 0) {\n throw new TypeError(\"store delivery seq must be a non-negative safe integer\");\n }\n const key = canonicalAnswerKey(delivery.op, delivery.args);\n const old = before[key];\n const fingerprint = canonical({\n op: delivery.op, args: delivery.args, state: delivery.state, data: delivery.data,\n next: delivery.next, seq: delivery.seq, validator: delivery.validator,\n receipt: delivery.receipt, rows: delivery.rows, reason: delivery.reason, rule: delivery.rule,\n });\n if (old && delivery.seq < old.seq) continue;\n if (old && delivery.seq === old.seq) {\n if (old.fingerprint === fingerprint) continue;\n throw new TypeError(`conflicting deliveries for ${delivery.op} at seq ${delivery.seq}`);\n }\n for (const row of delivery.rows ?? []) {\n if (!row.table || !row.id || !row.row || typeof row.row !== \"object\") {\n throw new TypeError(\"store delivery row is malformed\");\n }\n const storageKey = rowKey(row);\n if ((state.negative[storageKey] ?? -1) >= delivery.seq) {\n recordEviction(explicitEvictions, { table: row.table, id: row.id, seq: state.negative[storageKey]! });\n continue;\n }\n if (state.rowSeq[storageKey] === delivery.seq\n && canonical(state.rows[storageKey]) !== canonical(row)) {\n throw new TypeError(`conflicting row ${row.table}/${row.id} at seq ${delivery.seq}`);\n }\n if ((state.rowSeq[storageKey] ?? -1) > delivery.seq) continue;\n state.rows[storageKey] = clone(row);\n state.rowSeq[storageKey] = delivery.seq;\n }\n let data = clone(delivery.data);\n let answerState = delivery.state;\n let retained = false;\n const hidden = delivery.state === \"denied\" && old\n ? old.refs\n : old ? hiddenRefs(old.data, data) : [];\n const retainedRefs = new Set<string>();\n for (const ref of hidden) {\n if ((swap.retention?.[ref.table] ?? \"until-revoked\") === \"delivered-history\") {\n retainedRefs.add(rowKey(ref));\n retained = true;\n } else recordEviction(explicitEvictions, { ...ref, seq: delivery.seq });\n }\n if (delivery.state === \"denied\" && old && retainedRefs.size > 0) {\n data = clone(old.data);\n answerState = old.state;\n } else if (old && retainedRefs.size > 0) {\n data = restoreRetained(old.data, data, retainedRefs);\n }\n const refs = collectRefs(data);\n for (const range of delivery.receipt?.ranges ?? []) {\n for (const id of [...range.rowIds, ...(range.haloId ? [range.haloId] : [])]) {\n if (!refs.some((ref) => ref.table === range.table && ref.id === id)) refs.push({ table: range.table, id });\n }\n }\n // The pool is the answer's closure: halo and rule-input bodies (the\n // membership a message's read rule probed) are delivered content the\n // twin evaluates over, so an answer keeps every row it was delivered with.\n for (const pooled of delivery.rows ?? []) {\n if (!refs.some((ref) => ref.table === pooled.table && ref.id === pooled.id)) refs.push({ table: pooled.table, id: pooled.id });\n }\n const stored: StoredAnswer = {\n op: delivery.op,\n ...(delivery.cursorArg === undefined ? {} : { cursorArg: delivery.cursorArg }),\n args: clone(delivery.args),\n state: answerState,\n ...(data === undefined ? {} : { data }),\n ...(delivery.next === undefined ? {} : { next: delivery.next }),\n nextSeq: delivery.seq,\n seq: delivery.seq,\n ...(delivery.validator === undefined ? {} : { validator: delivery.validator }),\n ...(delivery.receipt === undefined ? {} : { receipt: clone(delivery.receipt) }),\n deliveredAt: delivery.deliveredAt ?? Date.now(),\n ...(retained ? { retained: true } : {}),\n ...(delivery.reason === undefined ? {} : { reason: delivery.reason }),\n ...(delivery.rule === undefined ? {} : { rule: delivery.rule }),\n refs,\n order: ++state.clock,\n fingerprint,\n };\n state.answers[key] = stored;\n freshRanges.push(...(delivery.receipt?.ranges ?? []).map((range) => ({ range, seq: delivery.seq })));\n recordAbsences(stored);\n }\n\n const heldRanges = Object.values(before).flatMap((answer) => answer.receipt?.ranges ?? []);\n for (const held of heldRanges) {\n const matching = freshRanges.filter(({ range: fresh }) => sameRange(held, fresh));\n if (matching.length === 0) continue;\n const present = new Set(matching.flatMap(({ range: fresh }) => [\n ...fresh.rowIds,\n ...(fresh.haloId ? [fresh.haloId] : []),\n ]));\n for (const id of held.rowIds) {\n if (present.has(id)) continue;\n const seq = matching\n .filter(({ range: fresh }) => inFreshExtent(id, held, fresh, state.rows, swap.schema))\n .reduce((latest, item) => Math.max(latest, item.seq), -1);\n if (seq >= 0) recordEviction(explicitEvictions, { table: held.table, id, seq });\n }\n }\n\n const appliedEvictions = new Set<string>();\n for (const [key, eviction] of explicitEvictions) {\n if ((state.negative[key] ?? -1) > eviction.seq) continue;\n if ((state.rowSeq[key] ?? -1) > eviction.seq) continue;\n state.negative[key] = eviction.seq;\n appliedEvictions.add(key);\n delete state.rows[key];\n delete state.rowSeq[key];\n for (const answer of Object.values(state.answers)) {\n for (const range of answer.receipt?.ranges ?? []) {\n if (range.table !== eviction.table) continue;\n const id = eviction.id;\n if (range.rowIds.includes(id)) {\n range.rowIds = range.rowIds.filter((rowId) => rowId !== id);\n // The page remembers what it lost: an interior eviction leaves a hole\n // the twin must not paper over with \"complete\" (LLP 1012 \u00A76).\n range.evictedIds = [...(range.evictedIds ?? []), id];\n }\n if (range.haloId === id) delete range.haloId;\n }\n if (!answer.refs.some((ref) => rowKey(ref) === key)) continue;\n answer.refs = answer.refs.filter((ref) => rowKey(ref) !== key);\n if (!answer.retained && answer.state !== \"denied\") {\n answer.state = \"partial\";\n answer.reason = \"evicted\";\n delete answer.next;\n }\n }\n }\n\n for (const answer of Object.values(state.answers)) {\n if (!answer.receipt) continue;\n answer.receipt.absences = answer.receipt.absences.filter(([table, index, key]) => {\n const id = index === \"byId\" && key.length === 1 ? key[0] : undefined;\n const storageKey = typeof id === \"string\" ? rowKey({ table, id }) : undefined;\n return storageKey === undefined || (state.rowSeq[storageKey] ?? -1) < 0 || appliedEvictions.has(storageKey);\n });\n }\n\n const referenced = new Set(Object.values(state.answers).flatMap((answer) => answer.refs.map(rowKey)));\n // Every pooled row joins its answer's refs above, so nothing arrives unused;\n // a row leaves here when no answer references it any more \u2014 its answer was\n // dropped, or replaced by a delivery whose closure no longer pools it.\n for (const key of Object.keys(state.rows)) if (!referenced.has(key)) {\n delete state.rows[key];\n delete state.rowSeq[key];\n }\n\n // Bytes join the swap by row lease: whatever left `state.rows` above takes its bytes with it.\n const byteDelta = applyByteSwap(state, swap, leasedAssets(Object.values(state.rows), Object.values(state.answers)));\n bytes.put.push(...byteDelta.put);\n bytes.remove.push(...byteDelta.remove);\n\n const previousTail = tailWatermark(Object.values(state.watermarks));\n if (swap.watermark) {\n const key = canonicalAnswerKey(swap.watermark.op, swap.watermark.args);\n // The order is the store's: first recorded, kept across re-marks (LLP 1012 \u00A77's tail chooser).\n const order = state.watermarks[key]?.order ?? ++state.clock;\n state.watermarks[key] = { ...clone(swap.watermark), order };\n }\n const tail = tailWatermark(Object.values(state.watermarks));\n // The outbox, its grants, its write bounds, and the prediction overlay are\n // custody of unsent work: a coverage reset above never touches them.\n for (const intent of swap.outbox?.remove ?? []) {\n delete state.outbox[intent];\n delete state.overlayMisses[intent];\n delete state.overlay[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n }\n const committedNow = new Set<string>();\n for (const entry of swap.outbox?.put ?? []) {\n if (typeof entry.intent !== \"string\" || entry.intent.length === 0) throw new TypeError(\"outbox entry needs an intent\");\n const previous = state.outbox[entry.intent];\n if (entry.state === \"committed\" && previous?.state !== \"committed\") committedNow.add(entry.intent);\n const order = previous?.order ?? entry.order ?? ++state.clock;\n state.outbox[entry.intent] = { ...clone(entry), order };\n }\n if (swap.bounds) state.bounds = clone(swap.bounds);\n if (swap.programs) state.programs = clone(swap.programs);\n for (const id of swap.grants?.remove ?? []) {\n delete state.grants[id];\n if (state.currentGrant === id) delete state.currentGrant;\n }\n for (const grant of swap.grants?.put ?? []) state.grants[grant.id] = clone(grant);\n if (swap.grants?.current === null) delete state.currentGrant;\n else if (typeof swap.grants?.current === \"string\") {\n if (!state.grants[swap.grants.current]) throw new TypeError(\"current grant must be a held grant\");\n state.currentGrant = swap.grants.current;\n }\n for (const intent of swap.overlay?.remove ?? []) {\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n }\n for (const [intent, rows] of Object.entries(swap.overlay?.put ?? {})) {\n state.overlay[intent] = clone(rows);\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n }\n // @ref LLP 1012#7-writes-offline \u2014 retire on authoritative row/negative\n // evidence, a non-empty page reached by a post-commit next-cursor chain,\n // or two misses (proven forward marks or successful resumes, once per swap).\n // A reset rebases the snapshot at the new drain's current head; opaque cursor names\n // and positions from the former coverage cannot order the new log.\n const answers = Object.keys(state.overlay).some((intent) => state.outbox[intent]?.state === \"committed\")\n ? Object.values(state.answers) : [];\n const pages = answers.filter((answer) => {\n const nonempty = Array.isArray(answer.data) ? answer.data.length > 0 : collectRefs(answer.data).length > 0;\n return (answer.state === \"complete\" || answer.state === \"capped\") && answer.receipt !== undefined\n && !answer.receipt.ranges.some((range) => (range.evictedIds?.length ?? 0) > 0)\n && nonempty && answer.refs.length > 0 && answer.refs.every((ref) => state.rows[rowKey(ref)] !== undefined);\n });\n const chains = new Map<string, { chain: string[]; reached: Set<string | null | undefined> }>();\n for (const intent of Object.keys(state.overlay)) {\n const entry = state.outbox[intent];\n if (entry === undefined || entry.state === \"rejected\" || entry.state === \"expired\") {\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n if (entry) delete entry.predicted;\n continue;\n }\n for (const row of state.overlay[intent]!) {\n const key = rowKey(row);\n const evidence = authoritativeNegatives.get(key);\n if (evidence !== undefined && evidence.seq >= (state.overlayNegatives[intent]?.[key]?.seq ?? -1)) {\n (state.overlayNegatives[intent] ??= {})[key] = evidence;\n }\n }\n if (entry.state !== \"committed\") continue;\n if (state.overlayWatermarks[intent] == null && tail !== undefined) {\n const snapshot = committedNow.has(intent) && state.overlayWatermarks[intent] !== null ? previousTail ?? tail : tail;\n state.overlayWatermarks[intent] = {\n op: snapshot.op, args: clone(snapshot.args), cursorArg: snapshot.cursorArg ?? \"c\",\n watermark: snapshot.watermark,\n };\n }\n const committedSeq = (entry.response as { seq?: unknown } | undefined)?.seq;\n if (!Number.isSafeInteger(committedSeq)) {\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n delete entry.predicted;\n continue;\n }\n const overlay = state.overlay[intent]!;\n const seq = Number(committedSeq);\n // A deletion is confirmed by absence, never by a still-present row.\n const predicted = new Set(overlay.filter((row) => !row.removed).map(rowKey));\n const committedWatermark = state.overlayWatermarks[intent] ?? undefined;\n const chainKey = committedWatermark ? canonical({ op: committedWatermark.op, args: committedWatermark.args,\n cursorArg: committedWatermark.cursorArg, watermark: committedWatermark.watermark, seq }) : \"\";\n if (!chains.has(chainKey)) {\n const chain = committedWatermark ? cursorChain(pages, committedWatermark, seq) : [];\n chains.set(chainKey, { chain, reached: new Set(chain) });\n }\n const { chain, reached } = chains.get(chainKey)!;\n const negative = overlay.some((row) => {\n const evidence = state.overlayNegatives[intent]?.[rowKey(row)];\n return evidence !== undefined && evidence.seq >= seq && (state.rowSeq[rowKey(row)] ?? -1) <= evidence.seq;\n });\n // The closure's pooled halo/rule-input row is authoritative arrival too.\n const arrived = negative || answers.some((answer) => answer.seq >= seq && !answer.retained && answer.state !== \"denied\"\n && answer.refs.some((ref) => predicted.has(rowKey(ref)) && state.rows[rowKey(ref)] !== undefined))\n || (predicted.size > 0 && committedWatermark !== undefined && pages.some((page) => page.seq >= seq\n && reached.has(pagePosition(page, committedWatermark))));\n const advanced = committedWatermark !== undefined && swap.watermark !== undefined\n && tail !== undefined && canonicalAnswerKey(tail.op, tail.args) === canonicalAnswerKey(swap.watermark.op, swap.watermark.args)\n && advanceOverlay(committedWatermark, tail, chain);\n const moved = advanced || (swap.resumeSeq !== undefined && swap.resumeSeq > seq);\n const misses = arrived ? 0 : (state.overlayMisses[intent] ?? 0)\n + (moved && !committedNow.has(intent) ? 1 : 0);\n if (!arrived && misses < OVERLAY_PATIENCE) {\n if (misses > 0) state.overlayMisses[intent] = misses;\n continue;\n }\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n delete entry.predicted;\n }\n return state;\n }\n\n private ensureOpen(): void {\n if (this.partition === undefined) {\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", `${this.backend.carrier} range store is not open`);\n }\n }\n\n private ensureUnsealed(): void {\n if (this.state.sealed) throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store is sealed\");\n }\n\n private enqueue<T>(action: () => Promise<T>): Promise<T> {\n const run = this.tail.then(action);\n this.tail = run.then(() => undefined, () => undefined);\n return run;\n }\n\n private async read<T>(action: () => T): Promise<T> {\n await this.tail;\n this.ensureOpen();\n return action();\n }\n}\n", "import { OfflineStoreFailure } from \"./range-store.js\";\n\nexport interface StoreLocks {\n request<T>(name: string, options: { ifAvailable: true }, callback: (lock: { readonly name?: string } | null) => T | Promise<T>): Promise<T>;\n}\n\n// @ref LLP 1013#4-locks-the-token-store-and-the-partition \u2014 a global symbol\n// keeps the one-writer table shared even across separately emitted bundles.\n// Deliberate pre-publication rename from snapback2.offline.locks for the new scoped value shape.\nconst key = Symbol.for(\"snapback2.offline.storeLocks\");\ntype LockScope = string | object;\nconst scopes = ((globalThis as Record<PropertyKey, unknown>)[key] ??= new Map()) as Map<LockScope, Map<string, object>>;\n\nexport function inProcessLocks(scope: LockScope = \"default\"): StoreLocks {\n return {\n async request(name, _options, callback) {\n const held = scopes.get(scope) ?? new Map<string, object>();\n if (held.has(name)) return callback(null);\n scopes.set(scope, held);\n const lock = { name };\n held.set(name, lock);\n try { return await callback(lock); }\n finally {\n if (held.get(name) === lock) held.delete(name);\n if (held.size === 0) scopes.delete(scope);\n }\n },\n };\n}\n\nexport async function acquireStoreLock(locks: StoreLocks, partition: string): Promise<() => Promise<void>> {\n let accept!: () => void;\n let refuse!: (error: unknown) => void;\n let release!: () => void;\n const acquired = new Promise<void>((resolve, reject) => { accept = resolve; refuse = reject; });\n const released = new Promise<void>((resolve) => { release = resolve; });\n const request = locks.request(`snapback2:${partition}`, { ifAvailable: true }, async (lock) => {\n if (!lock) {\n refuse(new OfflineStoreFailure(\"E_OFFLINE_LOCK\", \"this account is open in another client; close it and try again\"));\n return;\n }\n accept();\n await released;\n });\n void request.catch(refuse);\n await acquired;\n return async () => { release(); await request; };\n}\n", "import { emptyState, jsonState, type PersistedRangeState } from \"./range-store.js\";\n\nexport type StateEntry = { key: string; value: unknown };\nexport type StateProjection = Record<\"rows\" | \"answers\" | \"outbox\" | \"meta\", StateEntry[]>;\n\n// @ref LLP 1013#3-the-sqlite-carrier \u2014 one projection for both database carriers;\n// the rest carries future metadata fields without a second list to keep in sync.\nexport function projectState(state: PersistedRangeState): StateProjection {\n // State has the JSON wire form on every carrier: omit undefined object fields,\n // preserve null, and turn undefined array slots into null. Bytes travel separately.\n const { rows = {}, answers = {}, outbox = {}, ...meta } = jsonState(state);\n const entries = (value: object) => Object.entries(value).map(([key, value]) => ({ key, value }));\n return { rows: entries(rows), answers: entries(answers), outbox: entries(outbox), meta: [{ key: \"state\", value: meta }] };\n}\n\nexport function unprojectState(projected: StateProjection): PersistedRangeState | undefined {\n const meta = projected.meta.find(({ key }) => key === \"state\");\n if (!meta && !projected.rows.length && !projected.answers.length && !projected.outbox.length) return undefined;\n const record = (entries: StateEntry[]) => Object.fromEntries(entries.map(({ key, value }) => [key, value]));\n return {\n ...emptyState(),\n ...meta?.value as Omit<PersistedRangeState, \"rows\" | \"answers\" | \"outbox\">,\n rows: record(projected.rows) as PersistedRangeState[\"rows\"],\n answers: record(projected.answers) as PersistedRangeState[\"answers\"],\n outbox: record(projected.outbox) as PersistedRangeState[\"outbox\"],\n };\n}\n\n/** Split only the first separator: a row id may itself contain NUL. */\nexport function encodeStateKey(key: string, tuple: boolean): string {\n const at = tuple ? key.indexOf(\"\\u0000\") : -1;\n return JSON.stringify(at < 0 ? [key] : [key.slice(0, at), key.slice(at + 1)]);\n}\n\nexport function decodeStateKey(key: string): string {\n const parts: unknown = JSON.parse(key);\n if (!Array.isArray(parts) || parts.length < 1 || parts.length > 2 || parts.some((part) => typeof part !== \"string\")) {\n throw new Error(\"invalid sqlite state key\");\n }\n return parts.join(\"\\u0000\");\n}\n", "import {\n OfflineStoreFailure, PersistentRangeStore,\n type PersistedRangeState, type RangeStoreBackend, type RangeStoreFactory,\n} from \"./range-store.js\";\nimport type { ByteDelta } from \"./byte-cache.js\";\nimport { acquireStoreLock, inProcessLocks, type StoreLocks } from \"./locks.js\";\nimport { decodeStateKey, encodeStateKey, projectState, unprojectState, type StateEntry } from \"./projection.js\";\nimport type { SqliteDriver } from \"./sqlite-driver.js\";\n\nexport type { SqliteDriver, SqliteExecutor, SqliteParams } from \"./sqlite-driver.js\";\nexport { inProcessLocks } from \"./locks.js\";\n\nexport interface SqliteRangeStoreOptions {\n locks?: StoreLocks;\n /** Witness barrier, after all DML and inside the transaction, before COMMIT. */\n beforeCommit?: (state: PersistedRangeState, bytes: ByteDelta) => void | Promise<void>;\n}\n\nconst STATE_TABLES = [\"state\", \"rows\", \"answers\", \"outbox\"] as const;\nconst TABLES = [...STATE_TABLES, \"bytes\"] as const;\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS state (partition TEXT NOT NULL PRIMARY KEY, value TEXT NOT NULL);\nCREATE TABLE IF NOT EXISTS rows (partition TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY (partition, key));\nCREATE TABLE IF NOT EXISTS answers (partition TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY (partition, key));\nCREATE TABLE IF NOT EXISTS outbox (partition TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY (partition, key));\nCREATE TABLE IF NOT EXISTS bytes (partition TEXT NOT NULL, key TEXT NOT NULL, value BLOB NOT NULL, PRIMARY KEY (partition, key));\n`;\ntype DriverSource = SqliteDriver | (() => SqliteDriver | Promise<SqliteDriver>);\n\n/** Public backend seam: byte deltas share replace's transaction; wipe deletes all five tables. */\nexport class SqliteBackend implements RangeStoreBackend {\n readonly carrier = \"SQLite\";\n private driver?: SqliteDriver;\n private partition?: string;\n private release?: () => Promise<void>;\n private locks?: StoreLocks;\n\n constructor(private readonly source: DriverSource, private readonly options: SqliteRangeStoreOptions = {}) {}\n\n private async guard<T>(body: () => Promise<T>): Promise<T> {\n try { return await body(); }\n catch (error) {\n if (error instanceof OfflineStoreFailure) throw error;\n const message = error instanceof Error ? error.message : String(error);\n const busy = /SQLITE_BUSY|SQLITE_LOCKED|database (?:is )?(?:busy|locked)/i.test(message);\n const rewrite = busy ? \"another writer holds the store; close it or wait\" : \"open a writable database with expo-sqlite ^16\";\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", `SQLite carrier: ${message}; ${rewrite}`, rewrite);\n }\n }\n\n async open(partition: string): Promise<PersistedRangeState | undefined> {\n await this.close();\n return this.guard(async () => {\n const driver = typeof this.source === \"function\" ? await this.source() : this.source;\n try {\n const identity = driver.identity;\n if (typeof identity !== \"string\" || !identity.trim()) {\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"driver has no database identity\",\n \"supply a stable database identity on the SQLite driver\");\n }\n this.locks = this.options.locks ?? inProcessLocks(identity);\n this.release = await acquireStoreLock(this.locks, partition);\n }\n catch (error) {\n // A factory may open eagerly; a refused client owns that fresh connection.\n // A caller-supplied driver may belong to the client holding the lock.\n if (typeof this.source === \"function\") await driver.close().catch(() => undefined);\n throw error;\n }\n try {\n this.driver = driver;\n this.partition = partition;\n const mode = await this.driver.get<{ journal_mode: string }>(\"PRAGMA journal_mode=WAL\");\n if (mode?.journal_mode.toLowerCase() !== \"wal\") throw new Error(`journal_mode is ${mode?.journal_mode ?? \"missing\"}, expected wal`);\n await this.driver.exec(SCHEMA);\n return await this.driver.transaction(async (tx) => {\n const meta = await tx.get<{ value: string }>(\"SELECT value FROM state WHERE partition = ?\", [partition]);\n const read = async (table: \"rows\" | \"answers\" | \"outbox\"): Promise<StateEntry[]> =>\n (await tx.all<{ key: string; value: string }>(`SELECT key, value FROM ${table} WHERE partition = ?`, [partition]))\n .map(({ key, value }) => ({ key: decodeStateKey(key), value: JSON.parse(value) }));\n return unprojectState({ rows: await read(\"rows\"), answers: await read(\"answers\"), outbox: await read(\"outbox\"),\n meta: meta ? [{ key: \"state\", value: JSON.parse(meta.value) }] : [] });\n });\n } catch (error) {\n await this.close().catch(() => undefined);\n throw error;\n }\n });\n }\n\n // @ref LLP 1013#3-the-sqlite-carrier \u2014 state rewrite plus byte delta in one\n // transaction; the byte table is never rewritten wholesale and has no MIME column.\n async replace(state: PersistedRangeState, bytes: ByteDelta): Promise<void> {\n return this.guard(async () => {\n if (!this.driver || this.partition === undefined) throw new Error(\"not open\");\n const partition = this.partition;\n const projected = projectState(state);\n await this.driver.transaction(async (tx) => {\n for (const table of STATE_TABLES) await tx.run(`DELETE FROM ${table} WHERE partition = ?`, [partition]);\n await tx.run(\"INSERT INTO state (partition, value) VALUES (?, ?)\", [partition, JSON.stringify(projected.meta[0].value)]);\n for (const table of [\"rows\", \"answers\", \"outbox\"] as const) {\n for (const { key, value } of projected[table]) {\n await tx.run(`INSERT INTO ${table} (partition, key, value) VALUES (?, ?, ?)`,\n [partition, encodeStateKey(key, table !== \"outbox\"), JSON.stringify(value)]);\n }\n }\n for (const item of bytes.put) {\n await tx.run(\"INSERT OR REPLACE INTO bytes (partition, key, value) VALUES (?, ?, ?)\",\n [partition, encodeStateKey(item.key, false), item.bytes]);\n }\n for (const key of bytes.remove) await tx.run(\"DELETE FROM bytes WHERE partition = ? AND key = ?\", [partition, encodeStateKey(key, false)]);\n await this.options.beforeCommit?.(state, bytes);\n });\n });\n }\n\n async readBytes(key: string): Promise<Uint8Array | undefined> {\n return this.guard(async () => {\n if (!this.driver || this.partition === undefined) return undefined;\n const row = await this.driver.get<{ value: Uint8Array }>(\"SELECT value FROM bytes WHERE partition = ? AND key = ?\",\n [this.partition, encodeStateKey(key, false)]);\n return row?.value;\n });\n }\n\n async wipe(partition: string): Promise<void> {\n if (!this.driver) {\n await this.open(partition);\n return this.wipe(partition);\n }\n if (this.partition !== partition) {\n const release = await acquireStoreLock(this.locks!, partition);\n try {\n await this.guard(() => this.driver!.transaction(async (tx) => {\n for (const table of TABLES) await tx.run(`DELETE FROM ${table} WHERE partition = ?`, [partition]);\n }));\n } finally { await release(); }\n return;\n }\n await this.guard(async () => {\n await this.driver!.transaction(async (tx) => {\n for (const table of TABLES) await tx.run(`DELETE FROM ${table} WHERE partition = ?`, [partition]);\n });\n });\n await this.close();\n }\n\n async close(): Promise<void> {\n const driver = this.driver;\n const release = this.release;\n this.driver = undefined;\n this.partition = undefined;\n this.release = undefined;\n try { if (driver) await this.guard(() => driver.close()); }\n finally { await release?.(); }\n }\n}\n\n/** Pass a driver factory when this factory will construct multiple clients. */\nexport function sqliteRangeStore(driver: DriverSource, options: SqliteRangeStoreOptions = {}): RangeStoreFactory {\n const factory = (() => new PersistentRangeStore(new SqliteBackend(driver, options))) as RangeStoreFactory;\n Object.defineProperty(factory, \"carrier\", { value: \"SQLite\" });\n return factory;\n}\n", "import { Directory, File, Paths } from \"expo-file-system\";\nimport type { NativeFileSystem } from \"../react-native/files.js\";\n\n/** SDK 54 File.write accepts Uint8Array directly; no Blob or base64 file ingress. */\nexport function expoAssetFileSystem(): NativeFileSystem {\n return {\n root: new Directory(Paths.cache, \"snapback2\").uri,\n async exists(uri) { return new File(uri).exists; },\n async list(uri) {\n const directory = new Directory(uri);\n return directory.exists ? directory.list().map((entry) => entry.name) : [];\n },\n async write(uri, bytes) {\n const file = new File(uri);\n file.parentDirectory.create({ idempotent: true, intermediates: true });\n file.write(bytes);\n },\n async remove(uri) {\n const entry = uri.endsWith(\"/\") ? new Directory(uri) : new File(uri);\n if (entry.exists) entry.delete();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["react_native_exports", "__export", "AssetImage", "AssetVideo", "useAssetFile", "__reExport", "react_core_star", "React", "useEffect", "useMemo", "useRef", "useState", "Image", "PixelRatio", "View", "VideoView", "useVideoPlayer", "useSnapbackClient", "useSnapbackSnapshot", "SnapbackRefusal", "useEffect", "useMemo", "useRef", "useState", "useSyncExternalStore", "useSnapbackClient", "useSnapbackSnapshot", "isSnapbackRefusal", "SnapbackRefusal", "ASSET_ID", "byteKey", "assetId", "width", "rowKey", "ref", "positive", "value", "assetRecordId", "record", "keys", "ASSET_ID", "assetIdsIn", "output", "id", "item", "leasedAssets", "rows", "answers", "leased", "row", "answer", "viewedOnlyAssets", "state", "viewed", "key", "checkedPut", "put", "applyByteSwap", "swap", "delta", "assets", "viewedAssets", "entry", "ceiling", "size", "total", "sum", "victim", "least", "FILES", "attachAssetFiles", "store", "files", "nativeAssetFiles", "client", "partitionDirectory", "root", "partition", "NativeAssetFiles", "fs", "id", "listener", "custody", "body", "result", "uri", "key", "assetId", "width", "byteKey", "cache", "ASSET_ID", "revision", "held", "state", "directory", "name", "bytes", "sealed", "before", "assetLeases", "after", "changed", "put", "refs", "row", "assetIdsIn", "leases", "fileBackend", "backend", "error", "none", "noSubscription", "fileRefusal", "error", "isSnapbackRefusal", "SnapbackRefusal", "bytesDataUri", "value", "alphabet", "output", "i", "a", "b", "c", "n", "useFile", "asset", "width", "client", "useSnapbackClient", "snapshot", "useSnapbackSnapshot", "files", "nativeAssetFiles", "getRevision", "useMemo", "revision", "useSyncExternalStore", "identity", "result", "setResult", "useState", "useEffect", "active", "uri", "useAssetFile", "options", "useNativeSource", "file", "failure", "viewing", "useRef", "memory", "setMemory", "attempted", "current", "url", "refusal", "custody", "held", "AssetImage", "asset", "width", "height", "style", "onLayout", "onRefusal", "onSourceChange", "props", "measured", "setMeasured", "useState", "requested", "PixelRatio", "uri", "refusal", "settled", "useNativeSource", "callback", "useRef", "React", "useEffect", "Image", "event", "Player", "_asset", "play", "onPlay", "_onSourceChange", "_autoPlay", "_onPlaybackStart", "player", "useVideoPlayer", "errors", "status", "error", "SnapbackRefusal", "subscription", "isPlaying", "VideoView", "AssetVideo", "onPlaybackStart", "autoPlay", "client", "useSnapbackClient", "snapshot", "useSnapbackSnapshot", "identity", "useMemo", "policy", "setPolicy", "active", "once", "refused", "size", "View", "expoFetch", "createClient", "defaultDatabaseDirectory", "openDatabaseAsync", "driverQueue", "tail", "body", "result", "executor", "database", "sql", "params", "DATABASE_NAME", "expoSqliteDriver", "name", "db", "openDatabaseAsync", "queue", "driverQueue", "defaultDatabaseDirectory", "body", "result", "transaction", "pending", "SecureStore", "expoSecureTokenStore", "name", "adapter", "keys", "cache", "tail", "ordered", "body", "result", "load", "kind", "save", "value", "failure", "key", "canonical", "value", "key", "object", "value", "pagePosition", "page", "mark", "cursor", "base", "args", "canonical", "position", "cursorChain", "pages", "committedSeq", "links", "seen", "chain", "next", "advanceOverlay", "tail", "at", "previous", "OfflineStoreFailure", "code", "message", "rewrite", "NO_BYTES", "emptyState", "clone", "value", "canonicalAnswerKey", "op", "args", "canonical", "jsonState", "rowKey", "ref", "viewedRef", "key", "at", "recordEviction", "evictions", "eviction", "asRowRef", "value", "marker", "collectRefs", "refs", "ref", "rowKey", "item", "expand", "rows", "viewed", "key", "hiddenRefs", "before", "after", "output", "index", "restoreRetained", "retained", "result", "clone", "old", "sameRange", "left", "right", "canonical", "compareValue", "a", "b", "compareKey", "order", "indexKey", "schema", "range", "row", "columns", "column", "cursorKey", "width", "insidePrefixBounds", "suffix", "first", "inFreshExtent", "id", "held", "fresh", "presentKeys", "rowId", "last", "jsonState", "normalizeState", "emptyState", "OfflineStoreFailure", "tailWatermark", "watermarks", "canonicalAnswerKey", "OVERLAY_PATIENCE", "outboxOrder", "entries", "PersistentRangeStore", "backend", "intent", "entry", "current", "partition", "next", "NO_BYTES", "op", "args", "stored", "watermark", "_refs", "_order", "_fingerprint", "_cursorArg", "data", "answer", "ranges", "absences", "verdicts", "absence", "verdict", "viewedRef", "deliveredAt", "swap", "bytes", "rest", "delta", "assetId", "byteKey", "sum", "assetIdsIn", "viewedOnlyAssets", "keys", "state", "explicitEvictions", "authoritativeNegatives", "recordNegative", "source", "recordEviction", "recordAbsences", "table", "refresh", "freshRanges", "delivery", "fingerprint", "storageKey", "answerState", "hidden", "retainedRefs", "pooled", "heldRanges", "matching", "present", "seq", "latest", "appliedEvictions", "eviction", "referenced", "byteDelta", "applyByteSwap", "leasedAssets", "previousTail", "tail", "committedNow", "previous", "grant", "answers", "pages", "nonempty", "chains", "evidence", "snapshot", "committedSeq", "overlay", "predicted", "committedWatermark", "chainKey", "chain", "cursorChain", "reached", "arrived", "page", "pagePosition", "moved", "advanceOverlay", "misses", "action", "run", "key", "scopes", "inProcessLocks", "scope", "name", "_options", "callback", "held", "lock", "acquireStoreLock", "locks", "partition", "accept", "refuse", "release", "acquired", "resolve", "reject", "released", "request", "OfflineStoreFailure", "projectState", "state", "rows", "answers", "outbox", "meta", "jsonState", "entries", "value", "key", "unprojectState", "projected", "record", "emptyState", "encodeStateKey", "tuple", "at", "decodeStateKey", "parts", "part", "STATE_TABLES", "TABLES", "SCHEMA", "SqliteBackend", "source", "options", "body", "error", "OfflineStoreFailure", "message", "rewrite", "partition", "driver", "identity", "inProcessLocks", "acquireStoreLock", "mode", "tx", "meta", "read", "table", "key", "value", "decodeStateKey", "unprojectState", "state", "bytes", "projected", "projectState", "encodeStateKey", "item", "release", "sqliteRangeStore", "factory", "PersistentRangeStore", "Directory", "File", "Paths", "expoAssetFileSystem", "uri", "directory", "entry", "bytes", "file", "expoSqliteStore", "name", "options", "factory", "files", "NativeAssetFiles", "expoAssetFileSystem", "store", "PersistentRangeStore", "fileBackend", "SqliteBackend", "expoSqliteDriver", "attachAssetFiles", "createExpoClient", "createClient", "expoFetch", "expoSecureTokenStore"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Auth and mutation reads
|
|
2
|
+
|
|
3
|
+
Authentication is always enabled. In `snapback/schema.q`:
|
|
4
|
+
|
|
5
|
+
```q
|
|
6
|
+
use identity
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
This enables password and guest flows; select just one with `use identity
|
|
10
|
+
password` or `use identity guests`. Clients use `client.auth.signup`, `login`,
|
|
11
|
+
`guest`, `logout`, and `me`. For relaunches, pass `tokenStore` and await
|
|
12
|
+
`client.ready`; browser persistence is explicit through
|
|
13
|
+
`browserTokenStore(storage, backendSpecificKey)`. Dev personas (`--as alice`)
|
|
14
|
+
cannot be combined with tokens or bearer-session transitions. Production
|
|
15
|
+
refuses personas. Logout and expiry fence that session, including live queries
|
|
16
|
+
and channels, without signing out other sessions for the same principal.
|
|
17
|
+
|
|
18
|
+
Keep authority separate from product profiles. Use nominal `principal` for
|
|
19
|
+
creator, membership, and author fields, and derive the acting value from
|
|
20
|
+
`viewer`. A profile reference is for product data; it is not a principal.
|
|
21
|
+
Never copy login email from the protected identity store into a public row.
|
|
22
|
+
For example, the chat template's `snapback/schema.q` contains:
|
|
23
|
+
|
|
24
|
+
```q
|
|
25
|
+
table profiles:
|
|
26
|
+
principal: principal
|
|
27
|
+
displayName: text 1..50
|
|
28
|
+
handle: text 3..20 format handle
|
|
29
|
+
avatarUrl: text <=2048 format url ?
|
|
30
|
+
bio: text <=200
|
|
31
|
+
location: text <=50
|
|
32
|
+
link: text <=2048 format url ?
|
|
33
|
+
unique byPrincipal: principal
|
|
34
|
+
unique byHandle: handle
|
|
35
|
+
immutable principal
|
|
36
|
+
public 'profiles are public'
|
|
37
|
+
insert <- .principal = viewer
|
|
38
|
+
update <- .principal = viewer
|
|
39
|
+
delete <- deny
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## A write permission does not grant a read
|
|
43
|
+
|
|
44
|
+
Every program lookup obeys the caller's table `read` rule, including lookups
|
|
45
|
+
inside mutations. An unreadable point lookup returns absence just like a
|
|
46
|
+
missing row; `! else CODE` rejects both with the same code. Program `exists`
|
|
47
|
+
also checks readable rows. An admin update/delete rule does not elevate these
|
|
48
|
+
reads. Do not treat absence as proof that no row exists, or add a duplicate
|
|
49
|
+
roster to work around a read policy.
|
|
50
|
+
|
|
51
|
+
For group administration, start with `snapback2 init --template chat`. Its
|
|
52
|
+
membership roster is readable to current members of that same conversation:
|
|
53
|
+
|
|
54
|
+
```q
|
|
55
|
+
read <- exists memberships[.conversationId, viewer]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
An owner-only rule (`read <- .principal = viewer`) would hide another person's
|
|
59
|
+
seat from an admin. Choose the roster's read audience intentionally; if only
|
|
60
|
+
admins should see other seats, admit self reads plus the current scoped admin
|
|
61
|
+
membership. Never make private roster rows public merely to unblock a write.
|
|
62
|
+
Table write rules independently enforce admin authority, immutable scope and
|
|
63
|
+
principal, and the member-to-admin transition. The template's promotion is:
|
|
64
|
+
|
|
65
|
+
```q
|
|
66
|
+
mutation memberPromote(conversationId: conversations, membershipId: memberships):
|
|
67
|
+
require exists memberships[conversationId, viewer, 'admin'] else ADMIN_REQUIRED
|
|
68
|
+
membership = memberships[membershipId] ! else MEMBERSHIP_REQUIRED
|
|
69
|
+
require membership.conversationId = conversationId else MEMBERSHIP_SCOPE_REQUIRED
|
|
70
|
+
require membership.role = 'member' else MEMBER_REQUIRED
|
|
71
|
+
update memberships[membership] { role: 'admin' }
|
|
72
|
+
return null
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`groupCreate` atomically inserts the conversation and creator-admin seat. The
|
|
76
|
+
conversation's `after insert` constraint requires that seat; `created` admits
|
|
77
|
+
only the creator's bootstrap in that transaction. `memberAdd`, `memberRemove`,
|
|
78
|
+
and `memberLeave` complete the pattern. Intrinsic membership ids prevent a
|
|
79
|
+
remove/re-add from retargeting an old request. There is no last-admin invariant.
|
|
80
|
+
|
|
81
|
+
## Diagnose an unexpected absence
|
|
82
|
+
|
|
83
|
+
Use a query containing the same lookup, then run
|
|
84
|
+
`snapback2 why <query> '<args-json>' --as alice --json`. `why` refuses mutations
|
|
85
|
+
with `E_OP_KIND` before execution. Its local, owner-protected
|
|
86
|
+
`rowVerdicts` and `diagnostics` explain denied read sites and point here.
|
|
87
|
+
Compare the intended viewer's result with a member/admin persona. A genuinely
|
|
88
|
+
missing row has no denied-row diagnostic. These details are development
|
|
89
|
+
inspection; ordinary query/mutation responses do not gain a hidden-row hint.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Effects
|
|
2
|
+
|
|
3
|
+
Effects are outside the data transaction. A mutation durably emits an outbox
|
|
4
|
+
row; the optional Ibex 2 runner performs I/O and may invoke a named Quarry
|
|
5
|
+
`then` mutation. The TypeScript module exports effects only:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { effect } from "snapback2";
|
|
9
|
+
import { recordNotified } from "./notifications";
|
|
10
|
+
import { notifications } from "./schema";
|
|
11
|
+
|
|
12
|
+
const baseHeaders = { accept: "application/json" };
|
|
13
|
+
const requestDefaults = {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { ...baseHeaders, "content-type": "application/json" },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const notify = effect({
|
|
19
|
+
grants: ["https://api.example.com"],
|
|
20
|
+
run: async (payload: { to: string; body: string }, { fetch, meta }) => {
|
|
21
|
+
function identity(value: string) { return value; }
|
|
22
|
+
const formatter = { format(value: string) { return identity(value); } };
|
|
23
|
+
const body = [payload.body].map(function keep(value) { return formatter.format(value); })[0];
|
|
24
|
+
try {
|
|
25
|
+
const response = await fetch("https://api.example.com/send", {
|
|
26
|
+
method: requestDefaults.method,
|
|
27
|
+
headers: { ...requestDefaults.headers, "idempotency-key": meta.id },
|
|
28
|
+
body: JSON.stringify({ ...payload, body }),
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) throw new Error(`provider ${response.status}`);
|
|
31
|
+
return { providerId: (await response.json()).id as string };
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
then: recordNotified,
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Quarry declares the effect's module and emits the payload:
|
|
41
|
+
|
|
42
|
+
```q
|
|
43
|
+
effect notify from delivery
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```q
|
|
47
|
+
emit notify { to: recipient.principal, body }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The default development binary has no engine. `snapback2 test` records the
|
|
51
|
+
derived effects check as `blocked: no engine in this build`; it never claims
|
|
52
|
+
the queued row was sent. Use `snapback2 trace <seq>` to see the outbox row.
|