@bitcobblers/wod-wiki-storage 0.39.2142 → 0.40.2144

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api.ts"],"names":["keys","key"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * ApiStorage — fetch-based IStorage backend speaking the pinned /v1 wire\n * protocol (implemented by wod-wiki-api). Reads overlay a per-tx write buffer\n * on top of server reads (buffered put replaces a row, buffered delete removes\n * it, matched by encoded key); writes buffer only and flush as ONE\n * POST /v1/tx on fn success. A thrown fn discards the buffer (no request).\n *\n * Signature extension over IStorage: query/delete args also accept plain\n * RangeDTO literals so non-IDB runtimes (Bun, node, tests) can drive this\n * client without an IDBKeyRange global. Transactional range deletes expand\n * matching primary keys into scalar delete ops on the existing /tx wire.\n */\n\nimport type {\n IReadWriteStore,\n IReadOnlyStore,\n IStorage,\n IStorageTransaction,\n StoreName,\n StoreType,\n} from './contract';\nimport { STORE_DEFS, type StoreDef } from './schema';\nimport { stampUserOwned } from './membership';\nimport { parseDomainQueryResult, type DomainQuery, type DomainQueryResult } from './domain';\nimport {\n encodeKey,\n isRange,\n keyFromValue,\n rangeFromIDB,\n type KeyDTO,\n type RangeDTO,\n type TxOp,\n} from './wire';\nimport {\n bufferedGet,\n bufferSlot,\n bufferToOps,\n isDirty,\n overlayRows,\n type BufferEntry,\n} from './overlay';\nimport { rowsEqual } from './validation';\n\n/** Query/delete argument: IndexedDB key forms plus the wire RangeDTO. */\ntype QueryArg = IDBValidKey | IDBKeyRange | RangeDTO;\n\ninterface Http { baseUrl: string; fetchImpl: typeof fetch }\n\n// ── HTTP layer (module functions; one shared client instance passes `Http`) ──\n\nasync function request(\n http: Http,\n method: string,\n path: string,\n init?: { body?: unknown; params?: URLSearchParams },\n): Promise<Response> {\n const qs = init?.params?.toString();\n const res = await http.fetchImpl(`${http.baseUrl}/v1${path}${qs ? `?${qs}` : ''}`, {\n method,\n headers: init?.body !== undefined ? { 'content-type': 'application/json' } : undefined,\n body: init?.body !== undefined ? JSON.stringify(init.body) : undefined,\n });\n if (!res.ok) throw new Error(`ApiStorage: ${method} /v1${path} → ${res.status}`);\n return res;\n}\n\nasync function remoteGet<T>(http: Http, store: StoreName, key: KeyDTO): Promise<T | undefined> {\n const res = await http.fetchImpl(`${http.baseUrl}/v1/${store}/get?key=${encodeKey(key)}`);\n if (res.status === 404) return undefined;\n if (!res.ok) throw new Error(`ApiStorage: GET /v1/${store}/get → ${res.status}`);\n return (await res.json()) as T;\n}\n\nasync function remoteList<T>(\n http: Http,\n store: StoreName,\n path: string,\n range: RangeDTO | undefined,\n count?: number,\n): Promise<T[]> {\n const params = new URLSearchParams();\n if (range) params.set('range', JSON.stringify(range));\n if (count !== undefined) params.set('count', String(count));\n const res = await request(http, 'GET', `/${store}/${path}`, { params });\n return (await res.json()) as T[];\n}\n\nasync function remoteCount(http: Http, store: StoreName, range: RangeDTO | undefined, indexName?: string): Promise<number> {\n const params = new URLSearchParams();\n if (range) params.set('range', JSON.stringify(range));\n if (indexName !== undefined) params.set('index', indexName);\n const res = await request(http, 'GET', `/${store}/count`, { params });\n return ((await res.json()) as { count: number }).count;\n}\n\n/** DELETE /v1/:store?key= — key or range as JSON; URLSearchParams owns the percent-encoding (encodeKey would double-encode). */\nasync function remoteDelete(http: Http, store: StoreName, keyOrRange: KeyDTO | RangeDTO): Promise<void> {\n await request(http, 'DELETE', `/${store}`, { params: new URLSearchParams({ key: JSON.stringify(keyOrRange) }) });\n}\n\nexport class ApiStorage implements IStorage {\n private readonly http: Http;\n private readonly defs: Record<StoreName, StoreDef>;\n /** Injected identity: user-owned rows are stamped with this on write. */\n private readonly getUserId?: () => string;\n\n constructor(\n baseUrl: string = '/api',\n fetchImpl: typeof fetch = globalThis.fetch.bind(globalThis),\n options: { getUserId?: () => string } = {},\n ) {\n this.http = { baseUrl, fetchImpl };\n this.getUserId = options.getUserId;\n // Keys are StoreName by construction (STORE_DEFS[].name is typed so).\n this.defs = Object.fromEntries(STORE_DEFS.map((d) => [d.name, d])) as Record<StoreName, StoreDef>;\n }\n\n def(store: StoreName): StoreDef {\n const def = this.defs[store];\n if (!def) throw new Error(`ApiStorage: unknown store '${store}'`);\n return def;\n }\n\n private makeView<K extends StoreName>(\n store: K,\n buffer?: Map<string, BufferEntry>,\n cleared?: Set<StoreName>,\n checks?: Map<string, Extract<TxOp, {op: 'check'}>>,\n mutable = false,\n ): IReadWriteStore<StoreType<K>> {\n return new ApiStore<StoreType<K>>(this.http, this.def(store), store, buffer, cleared, this.getUserId, checks, mutable);\n }\n\n readonly<K extends StoreName>(store: K): IReadOnlyStore<StoreType<K>> {\n return this.makeView(store);\n }\n\n readwrite<K extends StoreName>(store: K): IReadWriteStore<StoreType<K>> {\n return this.makeView(store, undefined, undefined, undefined, true);\n }\n async queryDomain(query: DomainQuery): Promise<DomainQueryResult | undefined> {\n const res = await this.http.fetchImpl(`${this.http.baseUrl}/v1/query`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(query),\n });\n if (res.status === 409) {\n const error: unknown = await res.json();\n if (typeof error === 'object' && error !== null && 'code' in error\n && error.code === 'domain_projection_unavailable') return undefined;\n }\n if (!res.ok) throw new Error(`ApiStorage: POST /v1/query → ${res.status}`);\n return parseDomainQueryResult(await res.json(), query.plan);\n }\n\n async transaction<K extends StoreName, R>(\n stores: K[],\n mode: 'readonly' | 'readwrite',\n fn: (tx: IStorageTransaction) => Promise<R>,\n ): Promise<R> {\n const buffer = new Map<string, BufferEntry>();\n const cleared = new Set<StoreName>();\n const checks = new Map<string, Extract<TxOp, {op: 'check'}>>();\n const scoped = new Set<StoreName>(stores);\n const view = <S extends StoreName>(store: S, mutable: boolean) => {\n if (!scoped.has(store)) throw new Error('store outside transaction scope');\n if (mutable && mode !== 'readwrite') throw new Error('read-only transaction');\n return this.makeView(store, buffer, cleared, checks, mutable);\n };\n const tx: IStorageTransaction = {\n readonly: <S extends StoreName>(store: S) => view(store, false),\n readwrite: <S extends StoreName>(store: S) => view(store, true),\n };\n const result = await fn(tx);\n await this.flush(buffer, cleared, checks);\n return result;\n }\n\n /** Sends buffered ops as one server-side SQL transaction. */\n private async flush(buffer: Map<string, BufferEntry>, cleared: Set<StoreName>, checks: Map<string, Extract<TxOp, {op: 'check'}>>): Promise<void> {\n const ops = bufferToOps(STORE_DEFS.map(d => d.name), buffer, cleared);\n if (ops.length > 0) await request(this.http, 'POST', '/tx', { body: { ops: [...checks.values(), ...ops] } });\n }\n\n async wipe(): Promise<void> {\n await request(this.http, 'POST', '/wipe');\n }\n\n async close(): Promise<void> {\n // stateless HTTP client — nothing to release\n }\n}\n\n/**\n * Store view. Outside a transaction (`buffer` undefined) every write posts\n * immediately; inside one, writes land in the shared buffer and reads overlay\n * it on server responses in op order, matching rows by encoded primary key.\n */\nclass ApiStore<T> implements IReadWriteStore<T> {\n constructor(\n private readonly http: Http,\n private readonly def: StoreDef,\n private readonly store: StoreName,\n private readonly buffer?: Map<string, BufferEntry>,\n private readonly cleared?: Set<StoreName>,\n private readonly getUserId?: () => string,\n private readonly checks?: Map<string, Extract<TxOp, {op: 'check'}>>,\n private readonly mutable = false,\n ) {}\n\n /** True when this tx has buffered writes for this store. */\n private dirty(): boolean {\n return isDirty(this.store, this.buffer, this.cleared);\n }\n\n async get(key: IDBValidKey | RangeDTO): Promise<T | undefined> {\n const range = isRange(key) ? key : undefined;\n let k: KeyDTO;\n if (range) {\n if (range.only === undefined) {\n throw new Error('ApiStorage.get: needs a plain key or {only}; bounded ranges match no single row');\n }\n k = range.only;\n } else {\n // IDBValidKey ⊃ KeyDTO (Date/ArrayBuffer keys are outside the wire subset).\n k = key as KeyDTO;\n }\n const state = bufferedGet<T>(this.store, k, this.buffer);\n if (state) return state.hit ? state.value : undefined;\n if (this.cleared?.has(this.store)) return undefined;\n const value = await remoteGet<T>(this.http, this.store, k);\n const slot = bufferSlot(this.store, k);\n if (!this.checks?.has(slot)) this.checks?.set(slot, { op: 'check', store: this.store, key: k, value: structuredClone(value ?? null) });\n return value;\n }\n\n async getMany(keys: IDBValidKey[]): Promise<(T | undefined)[]> {\n return Promise.all(keys.map(key => this.get(key)));\n }\n\n async getAllFromIndexMany(indexName: string, keys: IDBValidKey[]): Promise<T[][]> {\n return Promise.all(keys.map(key => this.getAllFromIndex(indexName, key)));\n }\n\n async getAll(query?: QueryArg, count?: number): Promise<T[]> {\n const range = rangeFromIDB(query);\n return this.overlay(await this.serverRows('all', range, this.dirty() ? undefined : count), count, range);\n }\n\n async getAllFromIndex(indexName: string, query?: QueryArg, count?: number): Promise<T[]> {\n const range = rangeFromIDB(query);\n return this.overlay(await this.serverRows(`index/${encodeURIComponent(indexName)}`, range, this.dirty() ? undefined : count), count, range, indexName);\n }\n\n async count(query?: QueryArg): Promise<number> {\n const range = rangeFromIDB(query);\n if (!this.dirty()) return remoteCount(this.http, this.store, range);\n return this.overlay(await this.serverRows('all', range), undefined, range).length;\n }\n\n async countFromIndex(indexName: string, query?: QueryArg): Promise<number> {\n const range = rangeFromIDB(query);\n if (!this.dirty()) return remoteCount(this.http, this.store, range, indexName);\n return this.overlay(await this.serverRows(`index/${encodeURIComponent(indexName)}`, range), undefined, range, indexName).length;\n }\n\n /** Server rows for a list path, or none when this tx cleared the store. */\n private async serverRows(path: string, range: RangeDTO | undefined, count?: number): Promise<T[]> {\n if (this.cleared?.has(this.store)) return [];\n const rows = await remoteList<T>(this.http, this.store, path, range, count);\n for (const row of rows) {\n const key = keyFromValue(this.def, row), slot = bufferSlot(this.store, key);\n if (!this.checks?.has(slot)) this.checks?.set(slot, { op: 'check', store: this.store, key, value: structuredClone(row) });\n }\n return rows;\n }\n\n /** Applies buffered puts and deletes before range filtering, ordering and paging. */\n private overlay(rows: T[], count?: number, range?: RangeDTO, indexName?: string): T[] {\n return overlayRows<T>(this.def, this.store, this.buffer, this.cleared, rows, count, range, indexName);\n }\n\n async put(value: T, _key?: IDBValidKey): Promise<IDBValidKey> {\n if (!this.mutable) throw new Error('read-only store');\n const userId = this.getUserId?.();\n const stored = userId ? (stampUserOwned(this.store, value, userId) as T) : value;\n const key = keyFromValue(this.def, stored);\n if (this.store === 'block_revisions') {\n const previous = this.buffer?.get(bufferSlot(this.store, key));\n if (previous?.kind === 'put' && !rowsEqual(previous.value, stored)) throw new Error('immutable block revision collision');\n }\n if (this.buffer) {\n this.buffer.set(bufferSlot(this.store, key), { kind: 'put', value: stored });\n return key;\n }\n await request(this.http, 'POST', '/tx', { body: { ops: [{ op: 'put', store: this.store, value: stored }] } });\n return key;\n }\n\n async putMany(values: T[], _keys?: IDBValidKey[]): Promise<IDBValidKey[]> {\n if (!this.mutable) throw new Error('read-only store');\n if (this.buffer) {\n const keys: IDBValidKey[] = [];\n for (const value of values) keys.push(await this.put(value));\n return keys;\n }\n const stored = values.map(value => this.getUserId ? stampUserOwned(this.store, value, this.getUserId()) : value);\n const keys = stored.map(value => keyFromValue(this.def, value));\n await request(this.http, 'POST', '/tx', { body: { ops: stored.map(value => ({ op: 'put', store: this.store, value })) } });\n return keys;\n }\n\n async delete(key: IDBValidKey | IDBKeyRange | RangeDTO): Promise<void> {\n if (!this.mutable) throw new Error('read-only store');\n if (this.store === 'block_revisions') throw new Error('block history requires explicit wipe');\n const range = isRange(key) ? key : undefined;\n if (range) {\n if (this.buffer) {\n const rows = await this.getAll(range);\n for (const row of rows) {\n const key = keyFromValue(this.def, row);\n this.buffer.set(bufferSlot(this.store, key), { kind: 'delete', key });\n }\n return;\n }\n await remoteDelete(this.http, this.store, range);\n return;\n }\n // IDBValidKey ⊃ KeyDTO (exotic keys pass through lossy).\n const k = key as KeyDTO;\n if (this.buffer) {\n this.buffer.set(bufferSlot(this.store, k), { kind: 'delete', key: k });\n return;\n }\n await remoteDelete(this.http, this.store, k);\n }\n\n async clear(): Promise<void> {\n if (!this.mutable) throw new Error('read-only store');\n if (this.store === 'block_revisions') throw new Error('block history requires explicit wipe');\n if (this.buffer) {\n this.cleared?.add(this.store);\n const prefix = `${this.store}\\u0000`;\n for (const slot of [...this.buffer.keys()]) {\n if (slot.startsWith(prefix)) this.buffer.delete(slot);\n }\n return;\n }\n await request(this.http, 'POST', '/tx', { body: { ops: [{ op: 'clear', store: this.store }] } });\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/api.ts"],"names":["keys","key"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * ApiStorage — fetch-based IStorage backend speaking the pinned /v1 wire\n * protocol (implemented by wod-wiki-api). Reads overlay a per-tx write buffer\n * on top of server reads (buffered put replaces a row, buffered delete removes\n * it, matched by encoded key); writes buffer only and flush as ONE\n * POST /v1/tx on fn success. A thrown fn discards the buffer (no request).\n *\n * Signature extension over IStorage: query/delete args also accept plain\n * RangeDTO literals so non-IDB runtimes (Bun, node, tests) can drive this\n * client without an IDBKeyRange global. Transactional range deletes expand\n * matching primary keys into scalar delete ops on the existing /tx wire.\n */\n\nimport type {\n IReadWriteStore,\n IReadOnlyStore,\n IStorage,\n IStorageTransaction,\n StoreName,\n StoreType,\n} from './contract';\nimport { STORE_DEFS, type StoreDef } from './schema';\nimport { stampUserOwned } from './membership';\nimport { parseDomainQueryResult, type DomainQuery, type DomainQueryResult } from './domain';\nimport {\n encodeKey,\n isRange,\n keyFromValue,\n rangeFromIDB,\n type KeyDTO,\n type RangeDTO,\n type TxOp,\n} from './wire';\nimport {\n bufferedGet,\n bufferSlot,\n bufferToOps,\n isDirty,\n overlayRows,\n type BufferEntry,\n} from './overlay';\nimport { rowsEqual } from './validation';\n\n/** Query/delete argument: IndexedDB key forms plus the wire RangeDTO. */\ntype QueryArg = IDBValidKey | IDBKeyRange | RangeDTO;\n\ninterface Http { baseUrl: string; fetchImpl: typeof fetch }\n\n// ── HTTP layer (module functions; one shared client instance passes `Http`) ──\n\nasync function request(\n http: Http,\n method: string,\n path: string,\n init?: { body?: unknown; params?: URLSearchParams },\n): Promise<Response> {\n const qs = init?.params?.toString();\n const res = await http.fetchImpl(`${http.baseUrl}/v1${path}${qs ? `?${qs}` : ''}`, {\n method,\n headers: init?.body !== undefined ? { 'content-type': 'application/json' } : undefined,\n body: init?.body !== undefined ? JSON.stringify(init.body) : undefined,\n });\n if (!res.ok) throw new Error(`ApiStorage: ${method} /v1${path} → ${res.status}`);\n return res;\n}\n\nasync function remoteGet<T>(http: Http, store: StoreName, key: KeyDTO): Promise<T | undefined> {\n const res = await http.fetchImpl(`${http.baseUrl}/v1/${store}/get?key=${encodeKey(key)}`);\n if (res.status === 404) return undefined;\n if (!res.ok) throw new Error(`ApiStorage: GET /v1/${store}/get → ${res.status}`);\n return (await res.json()) as T;\n}\n\nasync function remoteList<T>(\n http: Http,\n store: StoreName,\n path: string,\n range: RangeDTO | undefined,\n count?: number,\n): Promise<T[]> {\n const params = new URLSearchParams();\n if (range) params.set('range', JSON.stringify(range));\n if (count !== undefined) params.set('count', String(count));\n const res = await request(http, 'GET', `/${store}/${path}`, { params });\n return (await res.json()) as T[];\n}\n\nasync function remoteCount(http: Http, store: StoreName, range: RangeDTO | undefined, indexName?: string): Promise<number> {\n const params = new URLSearchParams();\n if (range) params.set('range', JSON.stringify(range));\n if (indexName !== undefined) params.set('index', indexName);\n const res = await request(http, 'GET', `/${store}/count`, { params });\n return ((await res.json()) as { count: number }).count;\n}\n\n/** DELETE /v1/:store?key= — key or range as JSON; URLSearchParams owns the percent-encoding (encodeKey would double-encode). */\nasync function remoteDelete(http: Http, store: StoreName, keyOrRange: KeyDTO | RangeDTO): Promise<void> {\n await request(http, 'DELETE', `/${store}`, { params: new URLSearchParams({ key: JSON.stringify(keyOrRange) }) });\n}\n\nexport class ApiStorage implements IStorage {\n private readonly http: Http;\n private readonly defs: Record<StoreName, StoreDef>;\n /** Injected identity: user-owned rows are stamped with this on write. */\n private readonly getUserId?: () => string;\n\n constructor(\n baseUrl: string = '/api',\n fetchImpl: typeof fetch = globalThis.fetch.bind(globalThis),\n options: { getUserId?: () => string } = {},\n ) {\n this.http = { baseUrl, fetchImpl };\n this.getUserId = options.getUserId;\n // Keys are StoreName by construction (STORE_DEFS[].name is typed so).\n this.defs = Object.fromEntries(STORE_DEFS.map((d) => [d.name, d])) as Record<StoreName, StoreDef>;\n }\n\n def(store: StoreName): StoreDef {\n const def = this.defs[store];\n if (!def) throw new Error(`ApiStorage: unknown store '${store}'`);\n return def;\n }\n\n private makeView<K extends StoreName>(\n store: K,\n buffer?: Map<string, BufferEntry>,\n cleared?: Set<StoreName>,\n checks?: Map<string, Extract<TxOp, {op: 'check'}>>,\n mutable = false,\n ): IReadWriteStore<StoreType<K>> {\n return new ApiStore<StoreType<K>>(this.http, this.def(store), store, buffer, cleared, this.getUserId, checks, mutable);\n }\n\n readonly<K extends StoreName>(store: K): IReadOnlyStore<StoreType<K>> {\n return this.makeView(store);\n }\n\n readwrite<K extends StoreName>(store: K): IReadWriteStore<StoreType<K>> {\n return this.makeView(store, undefined, undefined, undefined, true);\n }\n async queryDomain(query: DomainQuery): Promise<DomainQueryResult | undefined> {\n const res = await this.http.fetchImpl(`${this.http.baseUrl}/v1/query`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(query),\n });\n if (res.status === 409) {\n const error: unknown = await res.json();\n if (typeof error === 'object' && error !== null && 'code' in error\n && error.code === 'domain_projection_unavailable') return undefined;\n }\n if (!res.ok) throw new Error(`ApiStorage: POST /v1/query → ${res.status}`);\n return parseDomainQueryResult(await res.json(), query.plan);\n }\n\n async transaction<K extends StoreName, R>(\n stores: K[],\n mode: 'readonly' | 'readwrite',\n fn: (tx: IStorageTransaction) => Promise<R>,\n ): Promise<R> {\n const buffer = new Map<string, BufferEntry>();\n const cleared = new Set<StoreName>();\n const checks = new Map<string, Extract<TxOp, {op: 'check'}>>();\n const scoped = new Set<StoreName>(stores);\n const view = <S extends StoreName>(store: S, mutable: boolean) => {\n if (!scoped.has(store)) throw new Error('store outside transaction scope');\n if (mutable && mode !== 'readwrite') throw new Error('read-only transaction');\n return this.makeView(store, buffer, cleared, checks, mutable);\n };\n const tx: IStorageTransaction = {\n readonly: <S extends StoreName>(store: S) => view(store, false),\n readwrite: <S extends StoreName>(store: S) => view(store, true),\n };\n const result = await fn(tx);\n await this.flush(buffer, cleared, checks);\n return result;\n }\n\n /** Sends buffered ops as one server-side SQL transaction. */\n private async flush(buffer: Map<string, BufferEntry>, cleared: Set<StoreName>, checks: Map<string, Extract<TxOp, {op: 'check'}>>): Promise<void> {\n const ops = bufferToOps(STORE_DEFS.map(d => d.name), buffer, cleared);\n if (ops.length > 0) await request(this.http, 'POST', '/tx', { body: { ops: [...checks.values(), ...ops] } });\n }\n\n async wipe(): Promise<void> {\n await request(this.http, 'POST', '/wipe');\n }\n\n async close(): Promise<void> {\n // stateless HTTP client — nothing to release\n }\n}\n\n/**\n * Store view. Outside a transaction (`buffer` undefined) every write posts\n * immediately; inside one, writes land in the shared buffer and reads overlay\n * it on server responses in op order, matching rows by encoded primary key.\n */\nclass ApiStore<T> implements IReadWriteStore<T> {\n constructor(\n private readonly http: Http,\n private readonly def: StoreDef,\n private readonly store: StoreName,\n private readonly buffer?: Map<string, BufferEntry>,\n private readonly cleared?: Set<StoreName>,\n private readonly getUserId?: () => string,\n private readonly checks?: Map<string, Extract<TxOp, {op: 'check'}>>,\n private readonly mutable = false,\n ) {}\n\n /** True when this tx has buffered writes for this store. */\n private dirty(): boolean {\n return isDirty(this.store, this.buffer, this.cleared);\n }\n\n async get(key: IDBValidKey | RangeDTO): Promise<T | undefined> {\n const range = isRange(key) ? key : undefined;\n let k: KeyDTO;\n if (range) {\n if (range.only === undefined) {\n throw new Error('ApiStorage.get: needs a plain key or {only}; bounded ranges match no single row');\n }\n k = range.only;\n } else {\n // IDBValidKey ⊃ KeyDTO (Date/ArrayBuffer keys are outside the wire subset).\n k = key as KeyDTO;\n }\n const state = bufferedGet<T>(this.store, k, this.buffer);\n if (state) return state.hit ? state.value : undefined;\n if (this.cleared?.has(this.store)) return undefined;\n const value = await remoteGet<T>(this.http, this.store, k);\n const slot = bufferSlot(this.store, k);\n if (!this.checks?.has(slot)) this.checks?.set(slot, { op: 'check', store: this.store, key: k, value: structuredClone(value ?? null) });\n return value;\n }\n\n async getMany(keys: IDBValidKey[]): Promise<(T | undefined)[]> {\n return Promise.all(keys.map(key => this.get(key)));\n }\n\n async getAllFromIndexMany(indexName: string, keys: IDBValidKey[]): Promise<T[][]> {\n return Promise.all(keys.map(key => this.getAllFromIndex(indexName, key)));\n }\n\n async getAll(query?: QueryArg, count?: number): Promise<T[]> {\n const range = rangeFromIDB(query);\n return this.overlay(await this.serverRows('all', range, this.dirty() ? undefined : count), count, range);\n }\n\n async getAllFromIndex(indexName: string, query?: QueryArg, count?: number): Promise<T[]> {\n const range = rangeFromIDB(query);\n return this.overlay(await this.serverRows(`index/${encodeURIComponent(indexName)}`, range, this.dirty() ? undefined : count), count, range, indexName);\n }\n\n async count(query?: QueryArg): Promise<number> {\n const range = rangeFromIDB(query);\n if (!this.dirty()) return remoteCount(this.http, this.store, range);\n return this.overlay(await this.serverRows('all', range), undefined, range).length;\n }\n\n async countFromIndex(indexName: string, query?: QueryArg): Promise<number> {\n const range = rangeFromIDB(query);\n if (!this.dirty()) return remoteCount(this.http, this.store, range, indexName);\n return this.overlay(await this.serverRows(`index/${encodeURIComponent(indexName)}`, range), undefined, range, indexName).length;\n }\n\n /** Server rows for a list path, or none when this tx cleared the store. */\n private async serverRows(path: string, range: RangeDTO | undefined, count?: number): Promise<T[]> {\n if (this.cleared?.has(this.store)) return [];\n const rows = await remoteList<T>(this.http, this.store, path, range, count);\n for (const row of rows) {\n const key = keyFromValue(this.def, row), slot = bufferSlot(this.store, key);\n if (!this.checks?.has(slot)) this.checks?.set(slot, { op: 'check', store: this.store, key, value: structuredClone(row) });\n }\n return rows;\n }\n\n /** Applies buffered puts and deletes before range filtering, ordering and paging. */\n private overlay(rows: T[], count?: number, range?: RangeDTO, indexName?: string): T[] {\n return overlayRows<T>(this.def, this.store, this.buffer, this.cleared, rows, count, range, indexName);\n }\n\n async put(value: T, _key?: IDBValidKey): Promise<IDBValidKey> {\n if (!this.mutable) throw new Error('read-only store');\n const userId = this.getUserId?.();\n const stored = userId ? (stampUserOwned(this.store, value, userId) as T) : value;\n const key = keyFromValue(this.def, stored);\n if (this.store === 'block_revisions') {\n const previous = this.buffer?.get(bufferSlot(this.store, key));\n if (previous?.kind === 'put' && !rowsEqual(previous.value, stored)) throw new Error('immutable block revision collision');\n }\n if (this.buffer) {\n this.buffer.set(bufferSlot(this.store, key), { kind: 'put', value: stored });\n return key;\n }\n await request(this.http, 'POST', '/tx', { body: { ops: [{ op: 'put', store: this.store, value: stored }] } });\n return key;\n }\n\n async putMany(values: T[], _keys?: IDBValidKey[]): Promise<IDBValidKey[]> {\n if (!this.mutable) throw new Error('read-only store');\n if (this.buffer) {\n const keys: IDBValidKey[] = [];\n for (const value of values) keys.push(await this.put(value));\n return keys;\n }\n const stored = values.map(value => this.getUserId ? stampUserOwned(this.store, value, this.getUserId()) : value);\n const keys = stored.map(value => keyFromValue(this.def, value));\n await request(this.http, 'POST', '/tx', { body: { ops: stored.map(value => ({ op: 'put', store: this.store, value })) } });\n return keys;\n }\n\n async delete(key: IDBValidKey | IDBKeyRange | RangeDTO): Promise<void> {\n if (!this.mutable) throw new Error('read-only store');\n if (this.store === 'block_revisions') throw new Error('block history requires explicit wipe');\n const range = isRange(key) ? key : undefined;\n if (range) {\n if (this.buffer) {\n const rows = await this.getAll(range);\n for (const row of rows) {\n const key = keyFromValue(this.def, row);\n this.buffer.set(bufferSlot(this.store, key), { kind: 'delete', key });\n }\n return;\n }\n await remoteDelete(this.http, this.store, range);\n return;\n }\n // IDBValidKey ⊃ KeyDTO (exotic keys pass through lossy).\n const k = key as KeyDTO;\n if (this.buffer) {\n this.buffer.set(bufferSlot(this.store, k), { kind: 'delete', key: k });\n return;\n }\n await remoteDelete(this.http, this.store, k);\n }\n\n async clear(): Promise<void> {\n if (!this.mutable) throw new Error('read-only store');\n if (this.store === 'block_revisions') throw new Error('block history requires explicit wipe');\n if (this.buffer) {\n this.cleared?.add(this.store);\n const prefix = `${this.store}\\u0000`;\n for (const slot of [...this.buffer.keys()]) {\n if (slot.startsWith(prefix)) this.buffer.delete(slot);\n }\n return;\n }\n await request(this.http, 'POST', '/tx', { body: { ops: [{ op: 'clear', store: this.store }] } });\n }\n}\n"]}
@@ -0,0 +1,49 @@
1
+ import { S as StoreName } from './wire-DGYxXt3I.js';
2
+
3
+ /**
4
+ * Shared user-scope sync policy (versioned-databases-backups-review §3.4).
5
+ *
6
+ * ONE ownership classification governs outbox journals, bootstrap
7
+ * snapshots, the schema32 outbox cutover and cross-schema conversions. Rows
8
+ * are classified by actual provenance — `seedOrigin` on notes, `isStatic`
9
+ * plus owner note on projections, `registrySource` on bundled definitions,
10
+ * `seed:` prefixes on meta checkpoints — never from `userId` or the ABSENCE
11
+ * of a marker: uncertain rows are KEPT until their derivation and
12
+ * reconstruction are proven.
13
+ *
14
+ * Excluded rows are exactly the ones the seed bundle re-derives: seed
15
+ * notes, their static projections, bundled definitions and import
16
+ * checkpoints. Everything else — sessions, events, attachments, revision
17
+ * history, tags/pages/links, field-catalog data, non-seed meta — is user
18
+ * data and always retained. Immutable block_revisions are kept
19
+ * unconditionally until dependency closure is proven: sessions pin
20
+ * revisions a re-import may not reproduce.
21
+ */
22
+
23
+ /** Durable seed-deletion intent: written atomically with the delete by
24
+ * StorageService.deleteNote, honored by seed re-import (applySeedChunk) and
25
+ * carried in every user-scope snapshot so fresh devices suppress too. */
26
+ declare const USER_DELETED_SEED_PREFIX = "user-deleted-seed:";
27
+ /** Key constants shared by the writer (StorageService), the suppression
28
+ * reader (seed runtime) and the policy passes — a durable contract. */
29
+ declare function userDeletedSeedKey(noteId: string): string;
30
+ /** Inverse helper for readers; undefined for anything else. */
31
+ declare function userDeletedSeedNoteId(key: unknown): string | undefined;
32
+ /** The one meta key family a user-scope snapshot excludes: import
33
+ * checkpoints/claims (`seed:*`) are concurrency state re-derived from the
34
+ * bundle. `user-deleted-seed:*` tombstones and every other key stay in. */
35
+ declare function isSeedMetaKey(key: unknown): boolean;
36
+ /** Prior rows the policy needs: a projection's provenance is its owner
37
+ * note's, so every policy pass collects seed note ids first. */
38
+ interface UserScopeContext {
39
+ seedNoteIds: ReadonlySet<string>;
40
+ }
41
+ declare function collectUserScopeContext(notes: readonly unknown[]): UserScopeContext;
42
+ /**
43
+ * True when the row is user data a user-scope snapshot must retain.
44
+ * Store-level default is true (keep uncertain rows); only provably
45
+ * seed-rebuildable rows return false.
46
+ */
47
+ declare function isUserOwnedRow(store: StoreName, row: unknown, ctx: UserScopeContext): boolean;
48
+
49
+ export { type UserScopeContext as U, USER_DELETED_SEED_PREFIX as a, isUserOwnedRow as b, collectUserScopeContext as c, userDeletedSeedNoteId as d, isSeedMetaKey as i, userDeletedSeedKey as u };
@@ -0,0 +1,49 @@
1
+ import { S as StoreName } from './wire-DGYxXt3I.cjs';
2
+
3
+ /**
4
+ * Shared user-scope sync policy (versioned-databases-backups-review §3.4).
5
+ *
6
+ * ONE ownership classification governs outbox journals, bootstrap
7
+ * snapshots, the schema32 outbox cutover and cross-schema conversions. Rows
8
+ * are classified by actual provenance — `seedOrigin` on notes, `isStatic`
9
+ * plus owner note on projections, `registrySource` on bundled definitions,
10
+ * `seed:` prefixes on meta checkpoints — never from `userId` or the ABSENCE
11
+ * of a marker: uncertain rows are KEPT until their derivation and
12
+ * reconstruction are proven.
13
+ *
14
+ * Excluded rows are exactly the ones the seed bundle re-derives: seed
15
+ * notes, their static projections, bundled definitions and import
16
+ * checkpoints. Everything else — sessions, events, attachments, revision
17
+ * history, tags/pages/links, field-catalog data, non-seed meta — is user
18
+ * data and always retained. Immutable block_revisions are kept
19
+ * unconditionally until dependency closure is proven: sessions pin
20
+ * revisions a re-import may not reproduce.
21
+ */
22
+
23
+ /** Durable seed-deletion intent: written atomically with the delete by
24
+ * StorageService.deleteNote, honored by seed re-import (applySeedChunk) and
25
+ * carried in every user-scope snapshot so fresh devices suppress too. */
26
+ declare const USER_DELETED_SEED_PREFIX = "user-deleted-seed:";
27
+ /** Key constants shared by the writer (StorageService), the suppression
28
+ * reader (seed runtime) and the policy passes — a durable contract. */
29
+ declare function userDeletedSeedKey(noteId: string): string;
30
+ /** Inverse helper for readers; undefined for anything else. */
31
+ declare function userDeletedSeedNoteId(key: unknown): string | undefined;
32
+ /** The one meta key family a user-scope snapshot excludes: import
33
+ * checkpoints/claims (`seed:*`) are concurrency state re-derived from the
34
+ * bundle. `user-deleted-seed:*` tombstones and every other key stay in. */
35
+ declare function isSeedMetaKey(key: unknown): boolean;
36
+ /** Prior rows the policy needs: a projection's provenance is its owner
37
+ * note's, so every policy pass collects seed note ids first. */
38
+ interface UserScopeContext {
39
+ seedNoteIds: ReadonlySet<string>;
40
+ }
41
+ declare function collectUserScopeContext(notes: readonly unknown[]): UserScopeContext;
42
+ /**
43
+ * True when the row is user data a user-scope snapshot must retain.
44
+ * Store-level default is true (keep uncertain rows); only provably
45
+ * seed-rebuildable rows return false.
46
+ */
47
+ declare function isUserOwnedRow(store: StoreName, row: unknown, ctx: UserScopeContext): boolean;
48
+
49
+ export { type UserScopeContext as U, USER_DELETED_SEED_PREFIX as a, isUserOwnedRow as b, collectUserScopeContext as c, userDeletedSeedNoteId as d, isSeedMetaKey as i, userDeletedSeedKey as u };
@@ -124,7 +124,7 @@ function decodeRowJson(text2, binaryField) {
124
124
  }
125
125
 
126
126
  // src/schema.ts
127
- var DB_VERSION = 31;
127
+ var DB_VERSION = 32;
128
128
  var COLUMN_TYPES = {
129
129
  notes: { date: "number", createdAt: "number" },
130
130
  page: { createdAt: "number" },
@@ -2083,7 +2083,6 @@ var BrowserTursoStorage = class extends SqlStorage {
2083
2083
  // src/sql/sync.ts
2084
2084
  var SYNC_OPS_TABLE = "_wodwiki_sync_ops";
2085
2085
  var SYNC_STATE_TABLE = "_wodwiki_sync_state";
2086
- var SYNC_ARCHIVE_TABLE = "_wodwiki_sync_ops_archive";
2087
2086
  var BINARY_FIELD2 = { attachments: "data" };
2088
2087
  var STORE_NAMES = Object.fromEntries(STORE_DEFS.map((d) => [d.name, true]));
2089
2088
  var STATE_KEY = "meta";
@@ -2118,6 +2117,12 @@ function validateMutation(raw) {
2118
2117
  if (mutation.value === null || typeof mutation.value !== "object" || Array.isArray(mutation.value)) {
2119
2118
  throw new StorageError(400, "sync put value must be an object row", "bad_sync_mutation");
2120
2119
  }
2120
+ const def = STORE_DEFS.find((def2) => def2.name === store);
2121
+ const valueKey = keyFromValue(def, mutation.value);
2122
+ assertKey(valueKey, "sync row key");
2123
+ if (!rowsEqual(mutation.key, valueKey)) {
2124
+ throw new StorageError(400, "sync put key differs from row key", "bad_sync_key");
2125
+ }
2121
2126
  return { op: "put", store, key: mutation.key, value: mutation.value };
2122
2127
  }
2123
2128
  throw new StorageError(400, `sync mutation has unknown op ${String(mutation.op)}`, "bad_sync_mutation");
@@ -2261,10 +2266,9 @@ async function applySyncBatch(db, entries, opts = {}) {
2261
2266
  });
2262
2267
  });
2263
2268
  }
2264
- const nextSchema = opts.toSchemaVersion ?? state.schema;
2265
2269
  statements.push({
2266
2270
  sql: `UPDATE "${SYNC_STATE_TABLE}" SET "value" = ? WHERE "key" = ?`,
2267
- params: [JSON.stringify({ schema: nextSchema, rev }), STATE_KEY]
2271
+ params: [JSON.stringify({ schema: state.schema, rev }), STATE_KEY]
2268
2272
  });
2269
2273
  await runStatements(tx, statements);
2270
2274
  return committed;
@@ -2302,34 +2306,6 @@ async function fetchSyncOps(db, afterRev, limit) {
2302
2306
  return { opId, rev, idx, at: atMs, mutation: decodeMutation(row.data) };
2303
2307
  });
2304
2308
  }
2305
- async function replaceSyncLog(db, entries, toSchemaVersion) {
2306
- if (entries.length === 0) throw new StorageError(400, "replacement log must contain the converted snapshot", "bad_sync_entry");
2307
- for (const entry of entries) validateEntry(entry);
2308
- await db.transaction(async (tx) => {
2309
- await readSyncState(tx);
2310
- await tx.exec(
2311
- `CREATE TABLE IF NOT EXISTS "${SYNC_ARCHIVE_TABLE}" ("op_id" TEXT PRIMARY KEY, "rev" INTEGER NOT NULL, "idx" INTEGER NOT NULL, "at" INTEGER NOT NULL, "data" TEXT NOT NULL)`
2312
- );
2313
- await tx.exec(`INSERT INTO "${SYNC_ARCHIVE_TABLE}" ("op_id", "rev", "idx", "at", "data") SELECT "op_id", "rev", "idx", "at", "data" FROM "${SYNC_OPS_TABLE}"`);
2314
- await tx.exec(`DELETE FROM "${SYNC_OPS_TABLE}"`);
2315
- const statements = [];
2316
- let rev = 0;
2317
- for (const entry of entries) {
2318
- rev += 1;
2319
- entry.ops.forEach((mutation, idx) => {
2320
- statements.push({
2321
- sql: `INSERT INTO "${SYNC_OPS_TABLE}" ("op_id", "rev", "idx", "at", "data") VALUES (?, ?, ?, ?, ?) ON CONFLICT ("op_id") DO NOTHING`,
2322
- params: [`${entry.id}:${idx}`, rev, idx, entry.at, encodeMutation(mutation)]
2323
- });
2324
- });
2325
- }
2326
- statements.push({
2327
- sql: `UPDATE "${SYNC_STATE_TABLE}" SET "value" = ? WHERE "key" = ?`,
2328
- params: [JSON.stringify({ schema: toSchemaVersion, rev }), STATE_KEY]
2329
- });
2330
- await runStatements(tx, statements);
2331
- });
2332
- }
2333
2309
  async function readRawSyncOps(db) {
2334
2310
  const rows = await db.query(`SELECT "rev", "idx", "data" FROM "${SYNC_OPS_TABLE}" ORDER BY "rev", "idx"`);
2335
2311
  return rows.map((row) => {
@@ -2348,14 +2324,20 @@ async function readRawSyncOps(db) {
2348
2324
  throw new StorageError(400, "sync op data must be an object", "bad_sync_row");
2349
2325
  }
2350
2326
  const mutation = parsed;
2351
- if (typeof mutation.op !== "string" || typeof mutation.store !== "string") {
2352
- throw new StorageError(400, "sync op must carry string op/store", "bad_sync_row");
2327
+ if (mutation.op === "wipe") return { op: "wipe" };
2328
+ if (typeof mutation.store !== "string") {
2329
+ throw new StorageError(400, "sync op must carry a string store", "bad_sync_row");
2330
+ }
2331
+ if (mutation.op === "clear") return { op: "clear", store: mutation.store };
2332
+ if (mutation.op === "delete") return { op: "delete", store: mutation.store, key: mutation.key };
2333
+ if (mutation.op !== "put" || mutation.value === null || typeof mutation.value !== "object" || Array.isArray(mutation.value)) {
2334
+ throw new StorageError(400, "sync op has an unknown operation or invalid row", "bad_sync_row");
2353
2335
  }
2354
2336
  return {
2355
- op: mutation.op,
2337
+ op: "put",
2356
2338
  store: mutation.store,
2357
2339
  key: mutation.key,
2358
- value: mutation.value === void 0 || mutation.value === null ? void 0 : decodeRowJson(JSON.stringify(mutation.value), BINARY_FIELD2[mutation.store])
2340
+ value: decodeRowJson(JSON.stringify(mutation.value), BINARY_FIELD2[mutation.store])
2359
2341
  };
2360
2342
  });
2361
2343
  }
@@ -2365,21 +2347,243 @@ async function readLegacyRows(db, table) {
2365
2347
  return rows.map((row) => decodeRowJson(String(row.data), BINARY_FIELD2[table]));
2366
2348
  }
2367
2349
 
2350
+ // src/sql/backup.ts
2351
+ function bytesToHex(bytes) {
2352
+ let hex = "";
2353
+ for (const byte of bytes) hex += byte.toString(16).padStart(2, "0");
2354
+ return hex;
2355
+ }
2356
+ function toCanonicalCell(value) {
2357
+ if (value === null) return { z: null };
2358
+ if (typeof value === "string") return { s: value };
2359
+ if (typeof value === "number") return { n: value };
2360
+ if (typeof value === "bigint") return { i: value.toString() };
2361
+ if (value instanceof Uint8Array) return { b: bytesToHex(value) };
2362
+ if (value instanceof ArrayBuffer) return { b: bytesToHex(new Uint8Array(value)) };
2363
+ throw new StorageError(500, `fingerprint cannot encode cell of type ${typeof value}`, "bad_fingerprint_cell");
2364
+ }
2365
+ function quoteIdent(name) {
2366
+ return `"${name.replace(/"/g, '""')}"`;
2367
+ }
2368
+ async function sha256(text2) {
2369
+ const subtle = globalThis.crypto?.subtle;
2370
+ if (!subtle) throw new StorageError(500, "Web Crypto unavailable \u2014 cannot fingerprint the database", "no_webcrypto");
2371
+ const bytes = new Uint8Array(await subtle.digest("SHA-256", new TextEncoder().encode(text2)));
2372
+ return [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
2373
+ }
2374
+ async function readStateMarker(conn) {
2375
+ const tables = await conn.query(
2376
+ `SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?`,
2377
+ [SYNC_STATE_TABLE]
2378
+ );
2379
+ if (tables.length === 0) return void 0;
2380
+ const rows = await conn.query(`SELECT "value" FROM ${quoteIdent(SYNC_STATE_TABLE)} WHERE "key" = 'meta'`);
2381
+ const raw = rows[0]?.value;
2382
+ if (typeof raw !== "string") {
2383
+ throw new StorageError(400, "sync target is not initialized", "sync_not_initialized");
2384
+ }
2385
+ let parsed;
2386
+ try {
2387
+ parsed = JSON.parse(raw);
2388
+ } catch {
2389
+ throw new StorageError(400, "malformed sync state row", "bad_sync_state");
2390
+ }
2391
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
2392
+ throw new StorageError(400, "malformed sync state row", "bad_sync_state");
2393
+ }
2394
+ if (!("schema" in parsed) || !("rev" in parsed)) {
2395
+ throw new StorageError(400, "sync state row is missing schema/rev", "bad_sync_state");
2396
+ }
2397
+ const { schema, rev } = parsed;
2398
+ if (typeof schema !== "number" || !Number.isSafeInteger(schema) || schema < 0 || typeof rev !== "number" || !Number.isSafeInteger(rev) || rev < 0) {
2399
+ throw new StorageError(400, "sync state schema/rev must be non-negative safe integers", "bad_sync_state");
2400
+ }
2401
+ return { schema, rev };
2402
+ }
2403
+ async function databaseFingerprint(db) {
2404
+ return db.transaction(async (tx) => {
2405
+ const tableRows = await tx.query(
2406
+ `SELECT name, sql FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\' AND name NOT LIKE 'libsql\\_%' ESCAPE '\\'`
2407
+ );
2408
+ const tables = tableRows.map((row) => ({ name: String(row.name), createSql: typeof row.sql === "string" ? row.sql : "" })).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
2409
+ const sections = ["wod-wiki-db-fingerprint-v2"];
2410
+ let totalRows = 0;
2411
+ for (const table of tables) {
2412
+ const rows = await tx.query(`SELECT * FROM ${quoteIdent(table.name)}`);
2413
+ totalRows += rows.length;
2414
+ const encoded = rows.map((row) => JSON.stringify(Object.values(row).map(toCanonicalCell)));
2415
+ encoded.sort();
2416
+ sections.push(`table ${table.name}`, `schema ${table.createSql}`, `rows ${rows.length}`, ...encoded);
2417
+ }
2418
+ const sync = await readStateMarker(tx);
2419
+ return { tables: tables.length, rows: totalRows, digest: await sha256(sections.join("\n")), sync };
2420
+ });
2421
+ }
2422
+ async function assertDatabaseCopyMatches(source, copy, before) {
2423
+ const after = await databaseFingerprint(source);
2424
+ if (after.digest !== before.digest) {
2425
+ throw new StorageError(
2426
+ 409,
2427
+ "source database changed during the copy \u2014 a writer is still active; retire all writers and retry",
2428
+ "source_moved"
2429
+ );
2430
+ }
2431
+ const copied = await databaseFingerprint(copy);
2432
+ if (copied.digest !== before.digest) {
2433
+ throw new StorageError(
2434
+ 409,
2435
+ `copy is incomplete or divergent (copy: ${copied.tables} tables / ${copied.rows} rows, source: ${before.tables} tables / ${before.rows} rows)`,
2436
+ "copy_mismatch"
2437
+ );
2438
+ }
2439
+ return after;
2440
+ }
2441
+ async function finalizeMigrationTarget(db, toSchema, expectRev) {
2442
+ if (!Number.isSafeInteger(toSchema) || toSchema < 1) {
2443
+ throw new StorageError(400, "finalize requires a positive schema version", "bad_sync_state");
2444
+ }
2445
+ await db.transaction(async (tx) => {
2446
+ const marker = await readStateMarker(tx);
2447
+ if (!marker || marker.schema !== 0 || marker.rev !== expectRev) {
2448
+ throw new StorageError(
2449
+ 409,
2450
+ `migration target is not in constructing state (expected schema 0 at rev ${expectRev}, found ${marker ? `schema ${marker.schema} at rev ${marker.rev}` : "no state row"})`,
2451
+ "migration_not_constructing"
2452
+ );
2453
+ }
2454
+ await tx.exec(
2455
+ `UPDATE ${quoteIdent(SYNC_STATE_TABLE)} SET "value" = ? WHERE "key" = 'meta'`,
2456
+ [JSON.stringify({ schema: toSchema, rev: expectRev })]
2457
+ );
2458
+ });
2459
+ }
2460
+ function pinKey(noteId, blockId, version) {
2461
+ return `${String(noteId)}\0${String(blockId)}\0${String(version)}`;
2462
+ }
2463
+ function assertPolicySnapshot(ops) {
2464
+ const revisions = /* @__PURE__ */ new Set();
2465
+ for (const mutation of ops) {
2466
+ if (mutation.op !== "put") {
2467
+ throw new StorageError(
2468
+ 400,
2469
+ `policy snapshot contains a non-put operation (${mutation.op}) \u2014 refusing`,
2470
+ "policy_violation"
2471
+ );
2472
+ }
2473
+ if (mutation.store !== "block_revisions") continue;
2474
+ const row = mutation.value;
2475
+ if (typeof row !== "object" || row === null || !("noteId" in row) || !("blockId" in row) || !("version" in row)) {
2476
+ throw new StorageError(400, "block_revisions row is missing noteId/blockId/version", "policy_violation");
2477
+ }
2478
+ revisions.add(pinKey(row.noteId, row.blockId, row.version));
2479
+ }
2480
+ const check = (noteId, blockId, version, what) => {
2481
+ if (!revisions.has(pinKey(noteId, blockId, version))) {
2482
+ throw new StorageError(
2483
+ 400,
2484
+ `${what} pins [${String(noteId)}, ${String(blockId)}, ${String(version)}] but the snapshot has no such immutable revision`,
2485
+ "policy_violation"
2486
+ );
2487
+ }
2488
+ };
2489
+ for (const mutation of ops) {
2490
+ if (mutation.op !== "put") continue;
2491
+ if (mutation.store === "sessions") {
2492
+ const row = mutation.value;
2493
+ if (typeof row !== "object" || row === null || !("noteId" in row) || !("blockId" in row) || !("blockVersion" in row)) {
2494
+ throw new StorageError(400, "session row is missing noteId/blockId/blockVersion", "policy_violation");
2495
+ }
2496
+ check(row.noteId, row.blockId, row.blockVersion, "a session");
2497
+ } else if (mutation.store === "notes") {
2498
+ const row = mutation.value;
2499
+ if (typeof row !== "object" || row === null || !("id" in row) || !("blocks" in row)) {
2500
+ throw new StorageError(400, "note row is missing id/blocks", "policy_violation");
2501
+ }
2502
+ if (typeof row.blocks !== "object" || row.blocks === null) continue;
2503
+ for (const block of Object.values(row.blocks)) {
2504
+ if (typeof block !== "object" || block === null || !("id" in block) || !("version" in block)) {
2505
+ throw new StorageError(400, "note block entry is missing id/version", "policy_violation");
2506
+ }
2507
+ check(row.id, block.id, block.version, "a note block");
2508
+ }
2509
+ }
2510
+ }
2511
+ }
2512
+ function logKey(store, key) {
2513
+ return `${store}\0${JSON.stringify(key) ?? String(key)}`;
2514
+ }
2515
+ function assertLogPinClosure(ops) {
2516
+ const live = /* @__PURE__ */ new Map();
2517
+ for (const { mutation } of ops) {
2518
+ if (mutation.op === "put") {
2519
+ live.set(logKey(mutation.store, mutation.key), { store: mutation.store, value: mutation.value });
2520
+ } else if (mutation.op === "delete") {
2521
+ live.delete(logKey(mutation.store, mutation.key));
2522
+ } else if (mutation.op === "clear") {
2523
+ for (const key of live.keys()) {
2524
+ if (key.startsWith(`${mutation.store}\0`)) live.delete(key);
2525
+ }
2526
+ } else {
2527
+ live.clear();
2528
+ }
2529
+ }
2530
+ const revisions = /* @__PURE__ */ new Set();
2531
+ for (const row of live.values()) {
2532
+ if (row.store !== "block_revisions") continue;
2533
+ if (!("noteId" in row.value) || !("blockId" in row.value) || !("version" in row.value)) {
2534
+ throw new StorageError(400, "block_revisions row is missing noteId/blockId/version", "policy_violation");
2535
+ }
2536
+ revisions.add(pinKey(row.value.noteId, row.value.blockId, row.value.version));
2537
+ }
2538
+ const check = (noteId, blockId, version, what) => {
2539
+ if (!revisions.has(pinKey(noteId, blockId, version))) {
2540
+ throw new StorageError(
2541
+ 400,
2542
+ `${what} pins [${String(noteId)}, ${String(blockId)}, ${String(version)}] but the target has no live immutable revision for it`,
2543
+ "policy_violation"
2544
+ );
2545
+ }
2546
+ };
2547
+ for (const row of live.values()) {
2548
+ if (row.store === "sessions") {
2549
+ if (!("noteId" in row.value) || !("blockId" in row.value) || !("blockVersion" in row.value)) {
2550
+ throw new StorageError(400, "session row is missing noteId/blockId/blockVersion", "policy_violation");
2551
+ }
2552
+ check(row.value.noteId, row.value.blockId, row.value.blockVersion, "a live session");
2553
+ } else if (row.store === "notes") {
2554
+ if (!("id" in row.value) || !("blocks" in row.value)) {
2555
+ throw new StorageError(400, "note row is missing id/blocks", "policy_violation");
2556
+ }
2557
+ if (typeof row.value.blocks !== "object" || row.value.blocks === null) continue;
2558
+ for (const block of Object.values(row.value.blocks)) {
2559
+ if (typeof block !== "object" || block === null || !("id" in block) || !("version" in block)) {
2560
+ throw new StorageError(400, "note block entry is missing id/version", "policy_violation");
2561
+ }
2562
+ check(row.value.id, block.id, block.version, "a live note block");
2563
+ }
2564
+ }
2565
+ }
2566
+ }
2567
+
2368
2568
  exports.BrowserTursoStorage = BrowserTursoStorage;
2369
2569
  exports.MAX_BODY = MAX_BODY;
2370
2570
  exports.SCHEMA_TABLE = SCHEMA_TABLE;
2371
- exports.SYNC_ARCHIVE_TABLE = SYNC_ARCHIVE_TABLE;
2372
2571
  exports.SYNC_OPS_TABLE = SYNC_OPS_TABLE;
2373
2572
  exports.SYNC_STATE_TABLE = SYNC_STATE_TABLE;
2374
2573
  exports.SqlStorage = SqlStorage;
2375
2574
  exports.StorageError = StorageError;
2376
2575
  exports.applySyncBatch = applySyncBatch;
2576
+ exports.assertDatabaseCopyMatches = assertDatabaseCopyMatches;
2577
+ exports.assertLogPinClosure = assertLogPinClosure;
2578
+ exports.assertPolicySnapshot = assertPolicySnapshot;
2377
2579
  exports.clearRows = clearRows;
2378
2580
  exports.countRows = countRows;
2581
+ exports.databaseFingerprint = databaseFingerprint;
2379
2582
  exports.decodeRowJson = decodeRowJson;
2380
2583
  exports.deleteRows = deleteRows;
2381
2584
  exports.encodeRowJson = encodeRowJson;
2382
2585
  exports.fetchSyncOps = fetchSyncOps;
2586
+ exports.finalizeMigrationTarget = finalizeMigrationTarget;
2383
2587
  exports.getRow = getRow;
2384
2588
  exports.getRows = getRows;
2385
2589
  exports.handleDomainQuery = handleDomainQuery;
@@ -2396,7 +2600,6 @@ exports.readLegacyRows = readLegacyRows;
2396
2600
  exports.readRawSyncOps = readRawSyncOps;
2397
2601
  exports.rebuildProjections = rebuildProjections;
2398
2602
  exports.refreshDomain = refreshDomain;
2399
- exports.replaceSyncLog = replaceSyncLog;
2400
2603
  exports.storeDefinition = storeDefinition;
2401
2604
  exports.validateTursoUrl = validateTursoUrl;
2402
2605
  exports.verifyReadiness = verifyReadiness;