@statewalker/cellb 0.5.1 → 0.6.0

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.
@@ -21,16 +21,38 @@ export function installLtxVfs(sqlite3, channel, opts = {}) {
21
21
  const ctl = new Int32Array(channel.sab, 0, 2);
22
22
  const payload = new Uint8Array(channel.sab, 8);
23
23
  const stats = { reads: 0, cacheHits: 0, storeReads: 0, commits: 0, blockedMs: 0 };
24
+ /**
25
+ * Each request's number: the store tags its answer with it (state word = seq << 2 | state),
26
+ * so the late answer to a request this worker gave up on is not taken for the next one's.
27
+ */
28
+ let seq = 0;
24
29
  /** A request answered synchronously: blocks this worker until the store notifies. */
25
30
  const call = (msg) => {
31
+ seq = (seq % 0x1fffffff) + 1;
26
32
  Atomics.store(ctl, 0, 0);
27
33
  const t = performance.now();
28
- channel.post(msg);
34
+ // `until` (wall clock, which both threads share): a commit the store could only finish
35
+ // near it is not kept, since this worker may already have given up on it.
36
+ channel.post({ ...msg, seq, until: Date.now() + 30_000 });
29
37
  // A store that never answers (a worker that failed to load) must not freeze this worker.
30
- if (Atomics.wait(ctl, 0, 0, 30_000) === "timed-out")
31
- throw new Error(`ltx store: no answer to ${String(msg.op)} in 30 s`);
38
+ const deadline = t + 30_000;
39
+ let word = 0;
40
+ for (;;) {
41
+ const left = deadline - performance.now();
42
+ if (left > 0)
43
+ Atomics.wait(ctl, 0, 0, left);
44
+ word = Atomics.load(ctl, 0);
45
+ // Out of time: unless this request's answer is there now, it is abandoned (the store
46
+ // does not keep a commit past `until`, nor serve a request once a newer one came).
47
+ if (performance.now() >= deadline && word >>> 2 !== seq)
48
+ throw new Error(`ltx store: no answer to ${String(msg.op)} in 30 s`);
49
+ if (word >>> 2 === seq)
50
+ break;
51
+ // An answer to an earlier request (given up on): not this one's; wait on.
52
+ Atomics.compareExchange(ctl, 0, word, 0);
53
+ }
32
54
  stats.blockedMs += performance.now() - t;
33
- if (ctl[0] === 2)
55
+ if ((word & 3) === 2)
34
56
  throw new Error(new TextDecoder().decode(payload.slice(0, ctl[1])));
35
57
  return payload.slice(0, ctl[1]);
36
58
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ltx-vfs.js","sourceRoot":"","sources":["../../src/adapters/ltx-vfs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A synchronous SQLite VFS (SQLite WASM, in a worker) over an ASYNCHRONOUS page store in another\n * thread: the database is a cell's LTX files on a FilesApi (src/ltx/ltx-pages.ts, served by\n * ltxPageServer). Reads block on a SharedArrayBuffer (Atomics.wait) while the store reads the\n * page by range; pages are cached here (LRU). Writes stay in this worker until the commit\n * (xSync of the main file), which sends the transaction's pages to the store: one LTX file.\n * The rollback journal lives in memory (journal_mode=MEMORY): only the main file is a file.\n *\n * Needs cross-origin isolation (SharedArrayBuffer). One writer per database.\n */\nconst SQLITE_OK = 0;\nconst SQLITE_IOERR = 10;\nconst SQLITE_IOERR_SHORT_READ = 522;\nconst SQLITE_OPEN_MAIN_DB = 0x100;\n\nexport interface LtxVfsChannel {\n /** Shared control words [state, length] + payload (≥ one page). */\n sab: SharedArrayBuffer;\n /** Posts a request to the store (it answers into `sab`, then notifies). */\n post(msg: unknown): void;\n}\n\nexport interface LtxVfsStats {\n reads: number;\n cacheHits: number;\n storeReads: number;\n commits: number;\n blockedMs: number;\n}\n\nexport function installLtxVfs(\n sqlite3: any,\n channel: LtxVfsChannel,\n opts: { name?: string; cachePages?: number; readAhead?: number } = {},\n): { name: string; stats: LtxVfsStats } {\n const { capi, wasm } = sqlite3;\n const name = opts.name ?? \"ltx\";\n const cacheMax = opts.cachePages ?? 2048;\n // A miss fetches this many consecutive pages at once (SQLite scans walk pages in order).\n const readAhead = Math.max(1, opts.readAhead ?? 16);\n const ctl = new Int32Array(channel.sab, 0, 2);\n const payload = new Uint8Array(channel.sab, 8);\n const stats: LtxVfsStats = { reads: 0, cacheHits: 0, storeReads: 0, commits: 0, blockedMs: 0 };\n\n /** A request answered synchronously: blocks this worker until the store notifies. */\n const call = (msg: Record<string, unknown>): Uint8Array => {\n Atomics.store(ctl, 0, 0);\n const t = performance.now();\n channel.post(msg);\n // A store that never answers (a worker that failed to load) must not freeze this worker.\n if (Atomics.wait(ctl, 0, 0, 30_000) === \"timed-out\")\n throw new Error(`ltx store: no answer to ${String(msg.op)} in 30 s`);\n stats.blockedMs += performance.now() - t;\n if (ctl[0] === 2) throw new Error(new TextDecoder().decode(payload.slice(0, ctl[1])));\n return payload.slice(0, ctl[1]);\n };\n /** One open database (a cell): its size, its page cache, the current transaction's pages. */\n interface Db {\n cell: string;\n pageSize: number;\n pageCount: number;\n cache: Map<number, Uint8Array>; // LRU: insertion order\n dirty: Map<number, Uint8Array>;\n }\n const dbs = new Map<string, Db>();\n const dbOf = (cell: string): Db => {\n let d = dbs.get(cell);\n if (!d) {\n const meta = JSON.parse(new TextDecoder().decode(call({ op: \"meta\", cell }))) as {\n pageSize: number;\n pageCount: number;\n };\n d = {\n cell,\n pageSize: meta.pageSize || 4096,\n pageCount: meta.pageCount,\n cache: new Map(),\n dirty: new Map(),\n };\n dbs.set(cell, d);\n }\n return d;\n };\n const page = (d: Db, pgno: number): Uint8Array => {\n const w = d.dirty.get(pgno);\n if (w) return w;\n stats.reads++;\n const c = d.cache.get(pgno);\n if (c) {\n stats.cacheHits++;\n d.cache.delete(pgno);\n d.cache.set(pgno, c);\n return c;\n }\n stats.storeReads++;\n if (pgno > d.pageCount) return new Uint8Array(d.pageSize);\n const count = Math.min(\n readAhead,\n d.pageCount - pgno + 1,\n Math.floor((channel.sab.byteLength - 8) / d.pageSize),\n );\n const run = call({ op: \"readRun\", cell: d.cell, pgno, count });\n for (let i = 0; i * d.pageSize < run.length; i++) {\n const q = pgno + i;\n if (d.dirty.has(q)) continue;\n d.cache.set(q, run.subarray(i * d.pageSize, (i + 1) * d.pageSize));\n if (d.cache.size > cacheMax) d.cache.delete(d.cache.keys().next().value as number);\n }\n return d.cache.get(pgno) ?? new Uint8Array(d.pageSize);\n };\n\n // Journal and other non-main files: plain memory.\n const memFiles = new Map<string, Uint8Array>();\n const open = new Map<number, { main: boolean; path: string; db?: Db }>();\n\n const io = new capi.sqlite3_io_methods();\n io.$iVersion = 1;\n const vfs = new capi.sqlite3_vfs();\n vfs.$iVersion = 1;\n vfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;\n vfs.$mxPathname = 512;\n\n sqlite3.vfs.installVfs({\n io: {\n struct: io,\n methods: {\n xClose(pFile: number) {\n const d = open.get(pFile)?.db;\n if (d) dbs.delete(d.cell); // its cache goes with it\n open.delete(pFile);\n return SQLITE_OK;\n },\n xRead(pFile: number, pDest: number, n: number, off: bigint) {\n const f = open.get(pFile);\n const at = Number(off);\n const heap = wasm.heap8u();\n if (!f?.main) {\n const b = memFiles.get(f?.path ?? \"\") ?? new Uint8Array();\n const got = b.subarray(at, at + n);\n heap.set(got, pDest);\n if (got.length < n) {\n heap.fill(0, pDest + got.length, pDest + n);\n return SQLITE_IOERR_SHORT_READ;\n }\n return SQLITE_OK;\n }\n try {\n const d = f.db as Db;\n const { pageSize } = d;\n const size = d.pageCount * pageSize;\n let o = 0;\n while (o < n && at + o < size) {\n const pos = at + o;\n const pgno = Math.floor(pos / pageSize) + 1;\n const inPage = pos % pageSize;\n const take = Math.min(pageSize - inPage, n - o);\n heap.set(page(d, pgno).subarray(inPage, inPage + take), pDest + o);\n o += take;\n }\n if (o < n) {\n heap.fill(0, pDest + o, pDest + n);\n return SQLITE_IOERR_SHORT_READ;\n }\n return SQLITE_OK;\n } catch (err) {\n // SQLite only sees SQLITE_IOERR (and rolls the transaction back): say why.\n console.error(`cellb ltx-vfs: ${(err as Error)?.message ?? err}`);\n return SQLITE_IOERR;\n }\n },\n xWrite(pFile: number, pSrc: number, n: number, off: bigint) {\n const f = open.get(pFile);\n const at = Number(off);\n const src = wasm.heap8u().subarray(pSrc, pSrc + n);\n if (!f?.main) {\n const cur = memFiles.get(f?.path ?? \"\") ?? new Uint8Array();\n const next = cur.length >= at + n ? cur : new Uint8Array(at + n);\n if (next !== cur) next.set(cur);\n next.set(src, at);\n memFiles.set(f?.path ?? \"\", next);\n return SQLITE_OK;\n }\n const d = f.db as Db;\n if (d.pageCount === 0 && at === 0 && n >= 18) {\n const ps = (src[16] << 8) | src[17];\n d.pageSize = ps === 1 ? 65536 : ps;\n }\n const { pageSize } = d;\n for (let o = 0; o < n; ) {\n const pos = at + o;\n const pgno = Math.floor(pos / pageSize) + 1;\n const inPage = pos % pageSize;\n const take = Math.min(pageSize - inPage, n - o);\n let p = d.dirty.get(pgno);\n if (!p) {\n p = take === pageSize ? new Uint8Array(pageSize) : page(d, pgno).slice();\n d.dirty.set(pgno, p);\n }\n p.set(src.subarray(o, o + take), inPage);\n o += take;\n if (pgno > d.pageCount) d.pageCount = pgno;\n }\n return SQLITE_OK;\n },\n xTruncate(pFile: number, size: bigint) {\n const f = open.get(pFile);\n if (!f?.main) {\n memFiles.set(\n f?.path ?? \"\",\n (memFiles.get(f?.path ?? \"\") ?? new Uint8Array()).slice(0, Number(size)),\n );\n return SQLITE_OK;\n }\n const d = f.db as Db;\n d.pageCount = Math.ceil(Number(size) / d.pageSize);\n for (const k of [...d.dirty.keys()]) if (k > d.pageCount) d.dirty.delete(k);\n return SQLITE_OK;\n },\n xSync(pFile: number) {\n const d = open.get(pFile)?.db;\n if (!d || !d.dirty.size) return SQLITE_OK;\n // The commit: this transaction's pages become one LTX file in the store.\n try {\n const pages = [...d.dirty].sort((a, b) => a[0] - b[0]);\n call({\n op: \"commit\",\n cell: d.cell,\n pageSize: d.pageSize,\n pageCount: d.pageCount,\n pages,\n });\n stats.commits++;\n for (const [pgno, p] of pages) d.cache.set(pgno, p);\n d.dirty.clear();\n return SQLITE_OK;\n } catch (err) {\n // SQLite only sees SQLITE_IOERR (and rolls the transaction back): say why.\n console.error(`cellb ltx-vfs: ${(err as Error)?.message ?? err}`);\n return SQLITE_IOERR;\n }\n },\n xFileSize(pFile: number, pOut: number) {\n const f = open.get(pFile);\n const size = f?.db\n ? f.db.pageCount * f.db.pageSize\n : (memFiles.get(f?.path ?? \"\")?.length ?? 0);\n wasm.poke64(pOut, BigInt(size));\n return SQLITE_OK;\n },\n xLock: () => SQLITE_OK,\n xUnlock: () => SQLITE_OK,\n xCheckReservedLock(_p: number, pOut: number) {\n wasm.poke32(pOut, 0);\n return SQLITE_OK;\n },\n xFileControl: () => 12, // SQLITE_NOTFOUND\n xSectorSize: () => 4096,\n xDeviceCharacteristics: () => 0,\n },\n },\n vfs: {\n struct: vfs,\n name,\n methods: {\n xOpen(_pVfs: number, zName: number, pFile: number, flags: number, pOutFlags: number) {\n const path = zName ? wasm.cstrToJs(zName) : `tmp-${pFile}`;\n const main = !!(flags & SQLITE_OPEN_MAIN_DB);\n try {\n open.set(pFile, { main, path, db: main ? dbOf(path) : undefined });\n } catch (err) {\n // SQLite only sees SQLITE_IOERR (and rolls the transaction back): say why.\n console.error(`cellb ltx-vfs: ${(err as Error)?.message ?? err}`);\n return SQLITE_IOERR;\n }\n const f = new capi.sqlite3_file(pFile);\n f.$pMethods = io.pointer;\n f.dispose();\n if (pOutFlags) wasm.poke32(pOutFlags, flags);\n return SQLITE_OK;\n },\n xDelete(_p: number, zName: number) {\n memFiles.delete(wasm.cstrToJs(zName));\n return SQLITE_OK;\n },\n xAccess(_p: number, zName: number, _flags: number, pOut: number) {\n wasm.poke32(pOut, memFiles.has(wasm.cstrToJs(zName)) ? 1 : 0);\n return SQLITE_OK;\n },\n xFullPathname(_p: number, zName: number, nOut: number, pOut: number) {\n wasm.cstrncpy(pOut, zName, nOut);\n return SQLITE_OK;\n },\n xRandomness(_p: number, n: number, pOut: number) {\n crypto.getRandomValues(wasm.heap8u().subarray(pOut, pOut + n));\n return n;\n },\n xSleep: () => SQLITE_OK,\n xCurrentTime(_p: number, pOut: number) {\n wasm.poke64f(pOut, 2440587.5 + Date.now() / 86400000);\n return SQLITE_OK;\n },\n xCurrentTimeInt64(_p: number, pOut: number) {\n wasm.poke64(pOut, BigInt(Math.floor(2440587.5 * 86400000 + Date.now())));\n return SQLITE_OK;\n },\n xGetLastError: () => 0,\n },\n },\n });\n return { name, stats };\n}\n"]}
1
+ {"version":3,"file":"ltx-vfs.js","sourceRoot":"","sources":["../../src/adapters/ltx-vfs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A synchronous SQLite VFS (SQLite WASM, in a worker) over an ASYNCHRONOUS page store in another\n * thread: the database is a cell's LTX files on a FilesApi (src/ltx/ltx-pages.ts, served by\n * ltxPageServer). Reads block on a SharedArrayBuffer (Atomics.wait) while the store reads the\n * page by range; pages are cached here (LRU). Writes stay in this worker until the commit\n * (xSync of the main file), which sends the transaction's pages to the store: one LTX file.\n * The rollback journal lives in memory (journal_mode=MEMORY): only the main file is a file.\n *\n * Needs cross-origin isolation (SharedArrayBuffer). One writer per database.\n */\nconst SQLITE_OK = 0;\nconst SQLITE_IOERR = 10;\nconst SQLITE_IOERR_SHORT_READ = 522;\nconst SQLITE_OPEN_MAIN_DB = 0x100;\n\nexport interface LtxVfsChannel {\n /** Shared control words [state, length] + payload (≥ one page). */\n sab: SharedArrayBuffer;\n /** Posts a request to the store (it answers into `sab`, then notifies). */\n post(msg: unknown): void;\n}\n\nexport interface LtxVfsStats {\n reads: number;\n cacheHits: number;\n storeReads: number;\n commits: number;\n blockedMs: number;\n}\n\nexport function installLtxVfs(\n sqlite3: any,\n channel: LtxVfsChannel,\n opts: { name?: string; cachePages?: number; readAhead?: number } = {},\n): { name: string; stats: LtxVfsStats } {\n const { capi, wasm } = sqlite3;\n const name = opts.name ?? \"ltx\";\n const cacheMax = opts.cachePages ?? 2048;\n // A miss fetches this many consecutive pages at once (SQLite scans walk pages in order).\n const readAhead = Math.max(1, opts.readAhead ?? 16);\n const ctl = new Int32Array(channel.sab, 0, 2);\n const payload = new Uint8Array(channel.sab, 8);\n const stats: LtxVfsStats = { reads: 0, cacheHits: 0, storeReads: 0, commits: 0, blockedMs: 0 };\n\n /**\n * Each request's number: the store tags its answer with it (state word = seq << 2 | state),\n * so the late answer to a request this worker gave up on is not taken for the next one's.\n */\n let seq = 0;\n /** A request answered synchronously: blocks this worker until the store notifies. */\n const call = (msg: Record<string, unknown>): Uint8Array => {\n seq = (seq % 0x1fffffff) + 1;\n Atomics.store(ctl, 0, 0);\n const t = performance.now();\n // `until` (wall clock, which both threads share): a commit the store could only finish\n // near it is not kept, since this worker may already have given up on it.\n channel.post({ ...msg, seq, until: Date.now() + 30_000 });\n // A store that never answers (a worker that failed to load) must not freeze this worker.\n const deadline = t + 30_000;\n let word = 0;\n for (;;) {\n const left = deadline - performance.now();\n if (left > 0) Atomics.wait(ctl, 0, 0, left);\n word = Atomics.load(ctl, 0);\n // Out of time: unless this request's answer is there now, it is abandoned (the store\n // does not keep a commit past `until`, nor serve a request once a newer one came).\n if (performance.now() >= deadline && word >>> 2 !== seq)\n throw new Error(`ltx store: no answer to ${String(msg.op)} in 30 s`);\n if (word >>> 2 === seq) break;\n // An answer to an earlier request (given up on): not this one's; wait on.\n Atomics.compareExchange(ctl, 0, word, 0);\n }\n stats.blockedMs += performance.now() - t;\n if ((word & 3) === 2) throw new Error(new TextDecoder().decode(payload.slice(0, ctl[1])));\n return payload.slice(0, ctl[1]);\n };\n /** One open database (a cell): its size, its page cache, the current transaction's pages. */\n interface Db {\n cell: string;\n pageSize: number;\n pageCount: number;\n cache: Map<number, Uint8Array>; // LRU: insertion order\n dirty: Map<number, Uint8Array>;\n }\n const dbs = new Map<string, Db>();\n const dbOf = (cell: string): Db => {\n let d = dbs.get(cell);\n if (!d) {\n const meta = JSON.parse(new TextDecoder().decode(call({ op: \"meta\", cell }))) as {\n pageSize: number;\n pageCount: number;\n };\n d = {\n cell,\n pageSize: meta.pageSize || 4096,\n pageCount: meta.pageCount,\n cache: new Map(),\n dirty: new Map(),\n };\n dbs.set(cell, d);\n }\n return d;\n };\n const page = (d: Db, pgno: number): Uint8Array => {\n const w = d.dirty.get(pgno);\n if (w) return w;\n stats.reads++;\n const c = d.cache.get(pgno);\n if (c) {\n stats.cacheHits++;\n d.cache.delete(pgno);\n d.cache.set(pgno, c);\n return c;\n }\n stats.storeReads++;\n if (pgno > d.pageCount) return new Uint8Array(d.pageSize);\n const count = Math.min(\n readAhead,\n d.pageCount - pgno + 1,\n Math.floor((channel.sab.byteLength - 8) / d.pageSize),\n );\n const run = call({ op: \"readRun\", cell: d.cell, pgno, count });\n for (let i = 0; i * d.pageSize < run.length; i++) {\n const q = pgno + i;\n if (d.dirty.has(q)) continue;\n d.cache.set(q, run.subarray(i * d.pageSize, (i + 1) * d.pageSize));\n if (d.cache.size > cacheMax) d.cache.delete(d.cache.keys().next().value as number);\n }\n return d.cache.get(pgno) ?? new Uint8Array(d.pageSize);\n };\n\n // Journal and other non-main files: plain memory.\n const memFiles = new Map<string, Uint8Array>();\n const open = new Map<number, { main: boolean; path: string; db?: Db }>();\n\n const io = new capi.sqlite3_io_methods();\n io.$iVersion = 1;\n const vfs = new capi.sqlite3_vfs();\n vfs.$iVersion = 1;\n vfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;\n vfs.$mxPathname = 512;\n\n sqlite3.vfs.installVfs({\n io: {\n struct: io,\n methods: {\n xClose(pFile: number) {\n const d = open.get(pFile)?.db;\n if (d) dbs.delete(d.cell); // its cache goes with it\n open.delete(pFile);\n return SQLITE_OK;\n },\n xRead(pFile: number, pDest: number, n: number, off: bigint) {\n const f = open.get(pFile);\n const at = Number(off);\n const heap = wasm.heap8u();\n if (!f?.main) {\n const b = memFiles.get(f?.path ?? \"\") ?? new Uint8Array();\n const got = b.subarray(at, at + n);\n heap.set(got, pDest);\n if (got.length < n) {\n heap.fill(0, pDest + got.length, pDest + n);\n return SQLITE_IOERR_SHORT_READ;\n }\n return SQLITE_OK;\n }\n try {\n const d = f.db as Db;\n const { pageSize } = d;\n const size = d.pageCount * pageSize;\n let o = 0;\n while (o < n && at + o < size) {\n const pos = at + o;\n const pgno = Math.floor(pos / pageSize) + 1;\n const inPage = pos % pageSize;\n const take = Math.min(pageSize - inPage, n - o);\n heap.set(page(d, pgno).subarray(inPage, inPage + take), pDest + o);\n o += take;\n }\n if (o < n) {\n heap.fill(0, pDest + o, pDest + n);\n return SQLITE_IOERR_SHORT_READ;\n }\n return SQLITE_OK;\n } catch (err) {\n // SQLite only sees SQLITE_IOERR (and rolls the transaction back): say why.\n console.error(`cellb ltx-vfs: ${(err as Error)?.message ?? err}`);\n return SQLITE_IOERR;\n }\n },\n xWrite(pFile: number, pSrc: number, n: number, off: bigint) {\n const f = open.get(pFile);\n const at = Number(off);\n const src = wasm.heap8u().subarray(pSrc, pSrc + n);\n if (!f?.main) {\n const cur = memFiles.get(f?.path ?? \"\") ?? new Uint8Array();\n const next = cur.length >= at + n ? cur : new Uint8Array(at + n);\n if (next !== cur) next.set(cur);\n next.set(src, at);\n memFiles.set(f?.path ?? \"\", next);\n return SQLITE_OK;\n }\n const d = f.db as Db;\n if (d.pageCount === 0 && at === 0 && n >= 18) {\n const ps = (src[16] << 8) | src[17];\n d.pageSize = ps === 1 ? 65536 : ps;\n }\n const { pageSize } = d;\n for (let o = 0; o < n; ) {\n const pos = at + o;\n const pgno = Math.floor(pos / pageSize) + 1;\n const inPage = pos % pageSize;\n const take = Math.min(pageSize - inPage, n - o);\n let p = d.dirty.get(pgno);\n if (!p) {\n p = take === pageSize ? new Uint8Array(pageSize) : page(d, pgno).slice();\n d.dirty.set(pgno, p);\n }\n p.set(src.subarray(o, o + take), inPage);\n o += take;\n if (pgno > d.pageCount) d.pageCount = pgno;\n }\n return SQLITE_OK;\n },\n xTruncate(pFile: number, size: bigint) {\n const f = open.get(pFile);\n if (!f?.main) {\n memFiles.set(\n f?.path ?? \"\",\n (memFiles.get(f?.path ?? \"\") ?? new Uint8Array()).slice(0, Number(size)),\n );\n return SQLITE_OK;\n }\n const d = f.db as Db;\n d.pageCount = Math.ceil(Number(size) / d.pageSize);\n for (const k of [...d.dirty.keys()]) if (k > d.pageCount) d.dirty.delete(k);\n return SQLITE_OK;\n },\n xSync(pFile: number) {\n const d = open.get(pFile)?.db;\n if (!d || !d.dirty.size) return SQLITE_OK;\n // The commit: this transaction's pages become one LTX file in the store.\n try {\n const pages = [...d.dirty].sort((a, b) => a[0] - b[0]);\n call({\n op: \"commit\",\n cell: d.cell,\n pageSize: d.pageSize,\n pageCount: d.pageCount,\n pages,\n });\n stats.commits++;\n for (const [pgno, p] of pages) d.cache.set(pgno, p);\n d.dirty.clear();\n return SQLITE_OK;\n } catch (err) {\n // SQLite only sees SQLITE_IOERR (and rolls the transaction back): say why.\n console.error(`cellb ltx-vfs: ${(err as Error)?.message ?? err}`);\n return SQLITE_IOERR;\n }\n },\n xFileSize(pFile: number, pOut: number) {\n const f = open.get(pFile);\n const size = f?.db\n ? f.db.pageCount * f.db.pageSize\n : (memFiles.get(f?.path ?? \"\")?.length ?? 0);\n wasm.poke64(pOut, BigInt(size));\n return SQLITE_OK;\n },\n xLock: () => SQLITE_OK,\n xUnlock: () => SQLITE_OK,\n xCheckReservedLock(_p: number, pOut: number) {\n wasm.poke32(pOut, 0);\n return SQLITE_OK;\n },\n xFileControl: () => 12, // SQLITE_NOTFOUND\n xSectorSize: () => 4096,\n xDeviceCharacteristics: () => 0,\n },\n },\n vfs: {\n struct: vfs,\n name,\n methods: {\n xOpen(_pVfs: number, zName: number, pFile: number, flags: number, pOutFlags: number) {\n const path = zName ? wasm.cstrToJs(zName) : `tmp-${pFile}`;\n const main = !!(flags & SQLITE_OPEN_MAIN_DB);\n try {\n open.set(pFile, { main, path, db: main ? dbOf(path) : undefined });\n } catch (err) {\n // SQLite only sees SQLITE_IOERR (and rolls the transaction back): say why.\n console.error(`cellb ltx-vfs: ${(err as Error)?.message ?? err}`);\n return SQLITE_IOERR;\n }\n const f = new capi.sqlite3_file(pFile);\n f.$pMethods = io.pointer;\n f.dispose();\n if (pOutFlags) wasm.poke32(pOutFlags, flags);\n return SQLITE_OK;\n },\n xDelete(_p: number, zName: number) {\n memFiles.delete(wasm.cstrToJs(zName));\n return SQLITE_OK;\n },\n xAccess(_p: number, zName: number, _flags: number, pOut: number) {\n wasm.poke32(pOut, memFiles.has(wasm.cstrToJs(zName)) ? 1 : 0);\n return SQLITE_OK;\n },\n xFullPathname(_p: number, zName: number, nOut: number, pOut: number) {\n wasm.cstrncpy(pOut, zName, nOut);\n return SQLITE_OK;\n },\n xRandomness(_p: number, n: number, pOut: number) {\n crypto.getRandomValues(wasm.heap8u().subarray(pOut, pOut + n));\n return n;\n },\n xSleep: () => SQLITE_OK,\n xCurrentTime(_p: number, pOut: number) {\n wasm.poke64f(pOut, 2440587.5 + Date.now() / 86400000);\n return SQLITE_OK;\n },\n xCurrentTimeInt64(_p: number, pOut: number) {\n wasm.poke64(pOut, BigInt(Math.floor(2440587.5 * 86400000 + Date.now())));\n return SQLITE_OK;\n },\n xGetLastError: () => 0,\n },\n },\n });\n return { name, stats };\n}\n"]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * `node:sqlite`, loaded without Node's "SQLite is an experimental feature" warning. cellb is
3
+ * the one choosing the module, not its user, so the warning would only be noise on every start
4
+ * (`loadProject`, `nodeSqliteOpener`). Only that warning is held back; any other passes.
5
+ *
6
+ * Loaded with `require`: bundlers (vite/vitest) strip the "node:" prefix of the experimental
7
+ * builtin and then fail to resolve "sqlite".
8
+ */
9
+ export declare function requireNodeSqlite(): typeof import("node:sqlite");
@@ -0,0 +1,28 @@
1
+ import { createRequire } from "node:module";
2
+ const require = createRequire(import.meta.url);
3
+ /**
4
+ * `node:sqlite`, loaded without Node's "SQLite is an experimental feature" warning. cellb is
5
+ * the one choosing the module, not its user, so the warning would only be noise on every start
6
+ * (`loadProject`, `nodeSqliteOpener`). Only that warning is held back; any other passes.
7
+ *
8
+ * Loaded with `require`: bundlers (vite/vitest) strip the "node:" prefix of the experimental
9
+ * builtin and then fail to resolve "sqlite".
10
+ */
11
+ export function requireNodeSqlite() {
12
+ const emitWarning = process.emitWarning;
13
+ process.emitWarning = function (warning, ...rest) {
14
+ const type = typeof rest[0] === "string" ? rest[0] : rest[0]?.type;
15
+ const text = typeof warning === "string" ? warning : warning?.message;
16
+ const name = typeof warning === "string" ? type : (warning?.name ?? type);
17
+ if (name === "ExperimentalWarning" && /\bSQLite\b/.test(String(text)))
18
+ return;
19
+ return emitWarning.call(process, warning, ...rest);
20
+ };
21
+ try {
22
+ return require("node:sqlite");
23
+ }
24
+ finally {
25
+ process.emitWarning = emitWarning;
26
+ }
27
+ }
28
+ //# sourceMappingURL=node-sqlite-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-sqlite-module.js","sourceRoot":"","sources":["../../src/adapters/node-sqlite-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACxC,OAAO,CAAC,WAAW,GAAG,UAAyB,OAAuB,EAAE,GAAG,IAAe;QACxF,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,CAAuB,EAAE,IAAI,CAAC;QAC1F,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC;QACtE,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC;QAC1E,IAAI,IAAI,KAAK,qBAAqB,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO;QAC9E,OAAQ,WAAyC,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACpF,CAA+B,CAAC;IAChC,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,aAAa,CAAiC,CAAC;IAChE,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;IACpC,CAAC;AACH,CAAC","sourcesContent":["import { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\n\n/**\n * `node:sqlite`, loaded without Node's \"SQLite is an experimental feature\" warning. cellb is\n * the one choosing the module, not its user, so the warning would only be noise on every start\n * (`loadProject`, `nodeSqliteOpener`). Only that warning is held back; any other passes.\n *\n * Loaded with `require`: bundlers (vite/vitest) strip the \"node:\" prefix of the experimental\n * builtin and then fail to resolve \"sqlite\".\n */\nexport function requireNodeSqlite(): typeof import(\"node:sqlite\") {\n const emitWarning = process.emitWarning;\n process.emitWarning = function (this: unknown, warning: string | Error, ...rest: unknown[]) {\n const type = typeof rest[0] === \"string\" ? rest[0] : (rest[0] as { type?: string })?.type;\n const text = typeof warning === \"string\" ? warning : warning?.message;\n const name = typeof warning === \"string\" ? type : (warning?.name ?? type);\n if (name === \"ExperimentalWarning\" && /\\bSQLite\\b/.test(String(text))) return;\n return (emitWarning as (...a: unknown[]) => void).call(process, warning, ...rest);\n } as typeof process.emitWarning;\n try {\n return require(\"node:sqlite\") as typeof import(\"node:sqlite\");\n } finally {\n process.emitWarning = emitWarning;\n }\n}\n"]}
@@ -2,10 +2,9 @@ import { closeSync, fstatSync, mkdtempSync, openSync, readFileSync, readSync, rm
2
2
  import { createRequire } from "node:module";
3
3
  import { tmpdir } from "node:os";
4
4
  import { dirname, join } from "node:path";
5
- // Loaded via require: bundlers (vite/vitest) strip the "node:" prefix of the
6
- // still-experimental node:sqlite builtin and fail to resolve "sqlite".
7
- const { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
8
5
  import { splitSqlStatements } from "../core/sql-split.js";
6
+ import { requireNodeSqlite } from "./node-sqlite-module.js";
7
+ const { DatabaseSync } = requireNodeSqlite();
9
8
  const requireCjs = createRequire(import.meta.url);
10
9
  const KNOWN_EXTENSIONS = {
11
10
  sqlite_vec: () => requireCjs("sqlite-vec").getLoadablePath(),
@@ -1 +1 @@
1
- {"version":3,"file":"node-sqlite.js","sourceRoot":"","sources":["../../src/adapters/node-sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,6EAA6E;AAC7E,uEAAuE;AACvE,MAAM,EAAE,YAAY,EAAE,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CACrD,aAAa,CACkB,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG1D,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,gBAAgB,GAAiC;IACrD,UAAU,EAAE,GAAG,EAAE,CAAE,UAAU,CAAC,YAAY,CAAmC,CAAC,eAAe,EAAE;CAChG,CAAC;AAEF,kEAAkE;AAClE,MAAM,OAAO,gBAAgB;IAC3B,GAAG,CAAgB;IACnB,KAAK,CAAS;IACL,UAAU,CAAU;IACpB,YAAY,CAAU;IAC/B,YAAY,IAAI,GAAG,UAAU,EAAE,IAAI,GAAmD,EAAE;QACtF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,KAAK,UAAU,CAAC;QAC9D,oFAAoF;QACpF,IAAI,CAAC,GAAG,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE;YAChC,cAAc,EAAE,IAAI;YACpB,gCAAgC,EAAE,IAAI;SACvC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,+CAA+C;QACpF,0EAA0E;QAC1E,0EAA0E;QAC1E,0EAA0E;QAC1E,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QAC/F,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED,0FAA0F;IAC1F,4FAA4F;IAC5F,wFAAwF;IACxF,4FAA4F;IAC5F,uFAAuF;IACvF,qEAAqE;IACrE,UAAU,GAAG,CAAC,CAAC;IACf,SAAS;QACP,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QAC3E,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACtB,CAAC;IACD,oFAAoF;IACpF,cAAc;QAGZ,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO,SAAS,CAAC;QACzC,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,KAAK,MAAM,CAAC;QACpC,IAAI,EAAU,CAAC;QACf,IAAI,CAAC;YACH,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;YAChC,IAAI,IAAI,GAAG,EAAE;gBAAE,OAAO,SAAS,CAAC;YAChC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC/E,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1E,MAAM,SAAS,GAAG,EAAE,GAAG,QAAQ,CAAC;YAChC,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;YAC9C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;YAC5C,IAAI,SAAS,GAAG,CAAC,CAAC;YAClB,IAAI,WAAW,GAAG,MAAM,CAAC;YACzB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACtC,OAAO,MAAM,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;gBAClC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;gBAC1C,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,KAAK;oBAAE,MAAM,CAAC,eAAe;gBAC/F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACvE,MAAM,IAAI,SAAS,CAAC;gBACpB,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBACrC,IAAI,MAAM,EAAE,CAAC;oBACX,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO;wBAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBAC9C,OAAO,CAAC,KAAK,EAAE,CAAC;oBAChB,SAAS,GAAG,MAAM,CAAC;oBACnB,WAAW,GAAG,MAAM,CAAC;gBACvB,CAAC;YACH,CAAC;YACD,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC;YAC9B,IAAI,CAAC,SAAS;gBACZ,OAAO;oBACL,QAAQ;oBACR,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAChE,KAAK;iBACN,CAAC;YACJ,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;gBAAE,IAAI,CAAC,GAAG,SAAS;oBAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACtE,iEAAiE;YACjE,IAAI,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;gBAClC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;gBACjD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YACtB,CAAC;YACD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QACxC,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,EAAE,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,GAAW,EAAE,MAAiB;QACjC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACzE,wFAAwF;QACxF,IAAI,IAAI,GAAc,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;QACpE,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC/B,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC;QAC9B,CAAC;QACD,OAAO,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IAC3C,CAAC;IACD,IAAI,CAAC,GAAW,EAAE,MAAiB;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAU,CAAC;QAC3C,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;YAC5B,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,IAAI,GAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAA4B,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;QAC7F,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;IAC/C,CAAC;IACD,aAAa;QACX,OAAQ,IAAI,CAAC,GAA6C,CAAC,aAAa,CAAC;IAC3E,CAAC;IACD,YAAY;QACV,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAa,CAAC;QACpE,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAa,CAAC;QACnE,OAAO,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,yFAAyF;IACzF,QAAQ,CAAyD;IACjE,4FAA4F;IACnF,wBAAwB,GAAG,KAAK,CAAC;IAC1C,YAAY;QACV,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,GACX,IAAI,CAAC,GACN,CAAC,aAAa,EAAE,CAAC;IACpB,CAAC;IACD,WAAW;QACT,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,UAAU,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,CAAC,CAAC,KAAK,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IACD,cAAc;QACZ,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;IAC5B,CAAC;IACD,cAAc,CAAC,SAAqB;QAClC,IAAI,CAAC,SAAS,CAAC,UAAU;YAAE,OAAO;QAClC,MAAM,wBAAwB,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,GAAyE,CAAC,cAAc,CAC5F,SAAS,EACT;YACE,UAAU,EAAE,GAAG,EAAE,CAAC,wBAAwB;SAC3C,CACF,CAAC;IACJ,CAAC;IAED,2FAA2F;IAC3F,aAAa,CAAC,IAAY;QACxB,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,SAAS;QACP,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACnD,wFAAwF;QACxF,iFAAiF;QACjF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAAE,EAAE,YAAY,IAAI,EAAE,CAAC,CAAC;QACvF,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;YACjD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,sBAAsB;QAC7C,CAAC;QACD,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,4FAA4F;IAC5F,KAAK;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QACzE,IAAI,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1D,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,oGAAoG;IACpG,OAAO,CAAC,KAAiB;QACvB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACjB,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU;YAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAC3E,KAAK,MAAM,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChG,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,gCAAgC,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,IAAI,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QAChG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,wBAAwB;IAC5C,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,IAAI,CAAC,YAAY,WAAW;QAAE,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IACvD,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC;AACD,2CAA2C;AAC3C,SAAS,UAAU,CAAC,CAAU;IAC5B,IAAI,CAAC,YAAY,UAAU;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;IAC9F,OAAO,CAAC,CAAC;AACX,CAAC;AAED,sEAAsE;AACtE;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAY,EACZ,IAAI,GAAmD,EAAE;IAEzD,OAAO,CAAC,OAAO,EAAE,EAAE,CACjB,IAAI,gBAAgB,CAClB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,EACtE,IAAI,CACL,CAAC;AACN,CAAC","sourcesContent":["import {\n closeSync,\n fstatSync,\n mkdtempSync,\n openSync,\n readFileSync,\n readSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { DatabaseSync as DatabaseSyncT } from \"node:sqlite\";\n\n// Loaded via require: bundlers (vite/vitest) strip the \"node:\" prefix of the\n// still-experimental node:sqlite builtin and fail to resolve \"sqlite\".\nconst { DatabaseSync } = createRequire(import.meta.url)(\n \"node:sqlite\",\n) as typeof import(\"node:sqlite\");\n\nimport { splitSqlStatements } from \"../core/sql-split.js\";\nimport type { OpenCellSql, SqlResult, SyncSqlDriver } from \"../ports.js\";\n\nconst requireCjs = createRequire(import.meta.url);\nconst KNOWN_EXTENSIONS: Record<string, () => string> = {\n sqlite_vec: () => (requireCjs(\"sqlite-vec\") as { getLoadablePath(): string }).getLoadablePath(),\n};\n\n/** Server-side SyncSqlDriver over node:sqlite (Node >= 22.13). */\nexport class NodeSqliteDriver implements SyncSqlDriver {\n #db: DatabaseSyncT;\n #path: string;\n readonly #exclusive: boolean;\n readonly #pageCapture: boolean;\n constructor(path = \":memory:\", opts: { exclusive?: boolean; pageCapture?: boolean } = {}) {\n this.#path = path;\n this.#exclusive = !!opts.exclusive;\n this.#pageCapture = !!opts.pageCapture && path !== \":memory:\";\n // As celld and workerd: a double-quoted name that is no column is a string literal.\n this.#db = new DatabaseSync(path, {\n allowExtension: true,\n enableDoubleQuotedStringLiterals: true,\n });\n this.#db.enableLoadExtension(false); // only loadExtension() below may load, by name\n // EXCLUSIVE locking: the first write takes an OS lock on the file that is\n // kept until close (or process death) — a second process can neither read\n // nor write the cell. Storage-level fencing on one host, no lease needed.\n if (opts.exclusive) this.#db.exec(\"PRAGMA locking_mode = EXCLUSIVE; PRAGMA busy_timeout = 0;\");\n this.#walSetup();\n }\n\n // ---- page capture through the WAL (what the WASM driver does with its xWrite hook) ----\n // In WAL mode every commit appends its changed pages to `<db>-wal` as frames (24-byte frame\n // header + page; a commit frame carries the database size in pages). Reading the frames\n // appended since the last read gives exactly the committed transaction's pages, O(changed),\n // instead of reading the whole file. Automatic checkpoints are off; take() checkpoints\n // (TRUNCATE) itself once the WAL grows, and restarts from its start.\n #walOffset = 0;\n #walSetup(): void {\n if (!this.#pageCapture) return;\n this.#db.exec(\"PRAGMA journal_mode = WAL; PRAGMA wal_autocheckpoint = 0;\");\n this.#db.exec(\"PRAGMA wal_checkpoint(TRUNCATE)\");\n this.#walOffset = 0;\n }\n /** The pages of the transactions committed since the previous call (WAL frames). */\n takeDirtyPages():\n | { pageSize: number; pageCount: number; pages: Map<number, Uint8Array> }\n | undefined {\n if (!this.#pageCapture) return undefined;\n const walPath = `${this.#path}-wal`;\n let fd: number;\n try {\n fd = openSync(walPath, \"r\");\n } catch {\n return undefined;\n }\n try {\n const size = fstatSync(fd).size;\n if (size < 32) return undefined;\n const header = Buffer.alloc(32);\n readSync(fd, header, 0, 32, 0);\n const pageSize = header.readUInt32BE(8) === 1 ? 65536 : header.readUInt32BE(8);\n const [salt1, salt2] = [header.readUInt32BE(16), header.readUInt32BE(20)];\n const frameSize = 24 + pageSize;\n let offset = Math.max(32, this.#walOffset);\n const pending = new Map<number, Uint8Array>();\n const pages = new Map<number, Uint8Array>();\n let pageCount = 0;\n let committedTo = offset;\n const frame = Buffer.alloc(frameSize);\n while (offset + frameSize <= size) {\n readSync(fd, frame, 0, frameSize, offset);\n if (frame.readUInt32BE(8) !== salt1 || frame.readUInt32BE(12) !== salt2) break; // stale frames\n pending.set(frame.readUInt32BE(0), new Uint8Array(frame.subarray(24)));\n offset += frameSize;\n const commit = frame.readUInt32BE(4);\n if (commit) {\n for (const [p, d] of pending) pages.set(p, d);\n pending.clear();\n pageCount = commit;\n committedTo = offset;\n }\n }\n this.#walOffset = committedTo;\n if (!pageCount)\n return {\n pageSize,\n pageCount: Number(this.exec(\"PRAGMA page_count\", []).rows[0][0]),\n pages,\n };\n for (const p of [...pages.keys()]) if (p > pageCount) pages.delete(p);\n // keep the WAL bounded: fold it into the database and start over\n if (committedTo > 4 * 1024 * 1024) {\n this.#db.exec(\"PRAGMA wal_checkpoint(TRUNCATE)\");\n this.#walOffset = 0;\n }\n return { pageSize, pageCount, pages };\n } finally {\n closeSync(fd);\n }\n }\n exec(sql: string, params: unknown[]): SqlResult {\n const statements = params.length === 0 ? splitSqlStatements(sql) : [sql];\n // Several statements: the result of the last one, with the rows written by all of them.\n let last: SqlResult = { columnNames: [], rows: [], rowsWritten: 0 };\n let written = 0;\n for (const text of statements) {\n last = this.#one(text, params);\n written += last.rowsWritten;\n }\n return { ...last, rowsWritten: written };\n }\n #one(sql: string, params: unknown[]): SqlResult {\n const stmt = this.#db.prepare(sql);\n const columnNames = stmt.columns().map((c) => c.name);\n const args = params.map(toSqlite) as any[];\n if (columnNames.length === 0) {\n const r = stmt.run(...args);\n return { columnNames, rows: [], rowsWritten: Number(r.changes) };\n }\n stmt.setReturnArrays(true);\n const rows = (stmt.all(...args) as unknown as unknown[][]).map((row) => row.map(fromSqlite));\n return { columnNames, rows, rowsWritten: 0 };\n }\n inTransaction(): boolean {\n return (this.#db as unknown as { isTransaction: boolean }).isTransaction;\n }\n databaseSize(): number {\n const [pc] = this.exec(\"PRAGMA page_count\", []).rows[0] as [number];\n const [ps] = this.exec(\"PRAGMA page_size\", []).rows[0] as [number];\n return Number(pc) * Number(ps);\n }\n close(): void {\n this.#db.close();\n }\n\n // ---- change capture (session extension) for transaction logs -------------------------\n #session: { changeset(): Uint8Array; close(): void } | undefined;\n /** node:sqlite exposes no ROWID session option: PK-less tables are logged as statements. */\n readonly captureCoversRowidTables = false;\n captureStart(): void {\n this.#session?.close();\n this.#session = (\n this.#db as unknown as { createSession(): { changeset(): Uint8Array; close(): void } }\n ).createSession();\n }\n captureTake(): Uint8Array {\n const s = this.#session;\n this.#session = undefined;\n if (!s) return new Uint8Array();\n try {\n return s.changeset();\n } finally {\n s.close();\n }\n }\n captureDiscard(): void {\n this.#session?.close();\n this.#session = undefined;\n }\n applyChangeset(changeset: Uint8Array): void {\n if (!changeset.byteLength) return;\n const SQLITE_CHANGESET_REPLACE = 1;\n (this.#db as unknown as { applyChangeset(c: Uint8Array, o: unknown): boolean }).applyChangeset(\n changeset,\n {\n onConflict: () => SQLITE_CHANGESET_REPLACE,\n },\n );\n }\n\n /** Known extensions only: \"sqlite_vec\" → the sqlite-vec npm package's loadable library. */\n loadExtension(name: string): void {\n const path = KNOWN_EXTENSIONS[name]?.();\n if (!path) throw new Error(`Unknown SQLite extension \"${name}\"`);\n this.#db.enableLoadExtension(true);\n try {\n this.#db.loadExtension(path);\n } finally {\n this.#db.enableLoadExtension(false);\n }\n }\n\n /**\n * The database file as SQLite wrote it (page for page), for page-level logs; an in-memory\n * database falls back to image(). Valid between transactions (rollback journal mode).\n */\n pageImage(): Uint8Array {\n if (this.#path === \":memory:\") return this.image();\n // A database restored from celld's files is in WAL mode (litestream needs it): its last\n // commits are in the -wal file until a checkpoint moves them into the main file.\n const mode = String(this.#db.prepare(\"PRAGMA journal_mode\").get()?.journal_mode ?? \"\");\n if (mode.toLowerCase() === \"wal\") {\n this.#db.exec(\"PRAGMA wal_checkpoint(TRUNCATE)\");\n this.#walOffset = 0; // the WAL starts over\n }\n return new Uint8Array(readFileSync(this.#path));\n }\n\n /** `VACUUM INTO` a temp file: a consistent, compact image (no open transaction allowed). */\n image(): Uint8Array {\n const tmp = join(mkdtempSync(join(tmpdir(), \"cell-snap-\")), \"db.sqlite\");\n try {\n this.#db.exec(`VACUUM INTO '${tmp.replace(/'/g, \"''\")}'`);\n return new Uint8Array(readFileSync(tmp));\n } finally {\n rmSync(dirname(tmp), { recursive: true, force: true });\n }\n }\n\n /** Replaces the database file with `image` and reopens it (an in-memory DB becomes file-backed). */\n restore(image: Uint8Array): void {\n this.#db.close();\n if (this.#path === \":memory:\")\n this.#path = join(mkdtempSync(join(tmpdir(), \"cell-mem-\")), \"db.sqlite\");\n for (const suffix of [\"-wal\", \"-shm\", \"-journal\"]) rmSync(this.#path + suffix, { force: true });\n writeFileSync(this.#path, image);\n this.#db = new DatabaseSync(this.#path, { enableDoubleQuotedStringLiterals: true });\n if (this.#exclusive) this.#db.exec(\"PRAGMA locking_mode = EXCLUSIVE; PRAGMA busy_timeout = 0;\");\n this.#walSetup(); // a new file: a new WAL\n }\n}\n\nfunction toSqlite(v: unknown): unknown {\n if (v instanceof ArrayBuffer) return new Uint8Array(v);\n if (typeof v === \"boolean\") return v ? 1 : 0;\n return v === undefined ? null : v;\n}\n/** Workers return BLOBs as ArrayBuffer. */\nfunction fromSqlite(v: unknown): unknown {\n if (v instanceof Uint8Array) return v.buffer.slice(v.byteOffset, v.byteOffset + v.byteLength);\n return v;\n}\n\n/** One file per cell in `dir`, or in-memory when `dir` is omitted. */\n/**\n * `pageCapture` (file-backed only): WAL mode, and each commit's changed pages read from the WAL\n * (takeDirtyPages) — LTX logs then cost O(changed pages) on Node as with SQLite WASM.\n */\nexport function nodeSqliteOpener(\n dir?: string,\n opts: { exclusive?: boolean; pageCapture?: boolean } = {},\n): OpenCellSql {\n return (cellKey) =>\n new NodeSqliteDriver(\n dir ? `${dir}/${cellKey.replace(/[^\\w.-]/g, \"_\")}.sqlite` : \":memory:\",\n opts,\n );\n}\n"]}
1
+ {"version":3,"file":"node-sqlite.js","sourceRoot":"","sources":["../../src/adapters/node-sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n closeSync,\n fstatSync,\n mkdtempSync,\n openSync,\n readFileSync,\n readSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { DatabaseSync as DatabaseSyncT } from \"node:sqlite\";\n\nimport { splitSqlStatements } from \"../core/sql-split.js\";\nimport type { OpenCellSql, SqlResult, SyncSqlDriver } from \"../ports.js\";\nimport { requireNodeSqlite } from \"./node-sqlite-module.js\";\n\nconst { DatabaseSync } = requireNodeSqlite();\n\nconst requireCjs = createRequire(import.meta.url);\nconst KNOWN_EXTENSIONS: Record<string, () => string> = {\n sqlite_vec: () => (requireCjs(\"sqlite-vec\") as { getLoadablePath(): string }).getLoadablePath(),\n};\n\n/** Server-side SyncSqlDriver over node:sqlite (Node >= 22.13). */\nexport class NodeSqliteDriver implements SyncSqlDriver {\n #db: DatabaseSyncT;\n #path: string;\n readonly #exclusive: boolean;\n readonly #pageCapture: boolean;\n constructor(path = \":memory:\", opts: { exclusive?: boolean; pageCapture?: boolean } = {}) {\n this.#path = path;\n this.#exclusive = !!opts.exclusive;\n this.#pageCapture = !!opts.pageCapture && path !== \":memory:\";\n // As celld and workerd: a double-quoted name that is no column is a string literal.\n this.#db = new DatabaseSync(path, {\n allowExtension: true,\n enableDoubleQuotedStringLiterals: true,\n });\n this.#db.enableLoadExtension(false); // only loadExtension() below may load, by name\n // EXCLUSIVE locking: the first write takes an OS lock on the file that is\n // kept until close (or process death) — a second process can neither read\n // nor write the cell. Storage-level fencing on one host, no lease needed.\n if (opts.exclusive) this.#db.exec(\"PRAGMA locking_mode = EXCLUSIVE; PRAGMA busy_timeout = 0;\");\n this.#walSetup();\n }\n\n // ---- page capture through the WAL (what the WASM driver does with its xWrite hook) ----\n // In WAL mode every commit appends its changed pages to `<db>-wal` as frames (24-byte frame\n // header + page; a commit frame carries the database size in pages). Reading the frames\n // appended since the last read gives exactly the committed transaction's pages, O(changed),\n // instead of reading the whole file. Automatic checkpoints are off; take() checkpoints\n // (TRUNCATE) itself once the WAL grows, and restarts from its start.\n #walOffset = 0;\n #walSetup(): void {\n if (!this.#pageCapture) return;\n this.#db.exec(\"PRAGMA journal_mode = WAL; PRAGMA wal_autocheckpoint = 0;\");\n this.#db.exec(\"PRAGMA wal_checkpoint(TRUNCATE)\");\n this.#walOffset = 0;\n }\n /** The pages of the transactions committed since the previous call (WAL frames). */\n takeDirtyPages():\n | { pageSize: number; pageCount: number; pages: Map<number, Uint8Array> }\n | undefined {\n if (!this.#pageCapture) return undefined;\n const walPath = `${this.#path}-wal`;\n let fd: number;\n try {\n fd = openSync(walPath, \"r\");\n } catch {\n return undefined;\n }\n try {\n const size = fstatSync(fd).size;\n if (size < 32) return undefined;\n const header = Buffer.alloc(32);\n readSync(fd, header, 0, 32, 0);\n const pageSize = header.readUInt32BE(8) === 1 ? 65536 : header.readUInt32BE(8);\n const [salt1, salt2] = [header.readUInt32BE(16), header.readUInt32BE(20)];\n const frameSize = 24 + pageSize;\n let offset = Math.max(32, this.#walOffset);\n const pending = new Map<number, Uint8Array>();\n const pages = new Map<number, Uint8Array>();\n let pageCount = 0;\n let committedTo = offset;\n const frame = Buffer.alloc(frameSize);\n while (offset + frameSize <= size) {\n readSync(fd, frame, 0, frameSize, offset);\n if (frame.readUInt32BE(8) !== salt1 || frame.readUInt32BE(12) !== salt2) break; // stale frames\n pending.set(frame.readUInt32BE(0), new Uint8Array(frame.subarray(24)));\n offset += frameSize;\n const commit = frame.readUInt32BE(4);\n if (commit) {\n for (const [p, d] of pending) pages.set(p, d);\n pending.clear();\n pageCount = commit;\n committedTo = offset;\n }\n }\n this.#walOffset = committedTo;\n if (!pageCount)\n return {\n pageSize,\n pageCount: Number(this.exec(\"PRAGMA page_count\", []).rows[0][0]),\n pages,\n };\n for (const p of [...pages.keys()]) if (p > pageCount) pages.delete(p);\n // keep the WAL bounded: fold it into the database and start over\n if (committedTo > 4 * 1024 * 1024) {\n this.#db.exec(\"PRAGMA wal_checkpoint(TRUNCATE)\");\n this.#walOffset = 0;\n }\n return { pageSize, pageCount, pages };\n } finally {\n closeSync(fd);\n }\n }\n exec(sql: string, params: unknown[]): SqlResult {\n const statements = params.length === 0 ? splitSqlStatements(sql) : [sql];\n // Several statements: the result of the last one, with the rows written by all of them.\n let last: SqlResult = { columnNames: [], rows: [], rowsWritten: 0 };\n let written = 0;\n for (const text of statements) {\n last = this.#one(text, params);\n written += last.rowsWritten;\n }\n return { ...last, rowsWritten: written };\n }\n #one(sql: string, params: unknown[]): SqlResult {\n const stmt = this.#db.prepare(sql);\n const columnNames = stmt.columns().map((c) => c.name);\n const args = params.map(toSqlite) as any[];\n if (columnNames.length === 0) {\n const r = stmt.run(...args);\n return { columnNames, rows: [], rowsWritten: Number(r.changes) };\n }\n stmt.setReturnArrays(true);\n const rows = (stmt.all(...args) as unknown as unknown[][]).map((row) => row.map(fromSqlite));\n return { columnNames, rows, rowsWritten: 0 };\n }\n inTransaction(): boolean {\n return (this.#db as unknown as { isTransaction: boolean }).isTransaction;\n }\n databaseSize(): number {\n const [pc] = this.exec(\"PRAGMA page_count\", []).rows[0] as [number];\n const [ps] = this.exec(\"PRAGMA page_size\", []).rows[0] as [number];\n return Number(pc) * Number(ps);\n }\n close(): void {\n this.#db.close();\n }\n\n // ---- change capture (session extension) for transaction logs -------------------------\n #session: { changeset(): Uint8Array; close(): void } | undefined;\n /** node:sqlite exposes no ROWID session option: PK-less tables are logged as statements. */\n readonly captureCoversRowidTables = false;\n captureStart(): void {\n this.#session?.close();\n this.#session = (\n this.#db as unknown as { createSession(): { changeset(): Uint8Array; close(): void } }\n ).createSession();\n }\n captureTake(): Uint8Array {\n const s = this.#session;\n this.#session = undefined;\n if (!s) return new Uint8Array();\n try {\n return s.changeset();\n } finally {\n s.close();\n }\n }\n captureDiscard(): void {\n this.#session?.close();\n this.#session = undefined;\n }\n applyChangeset(changeset: Uint8Array): void {\n if (!changeset.byteLength) return;\n const SQLITE_CHANGESET_REPLACE = 1;\n (this.#db as unknown as { applyChangeset(c: Uint8Array, o: unknown): boolean }).applyChangeset(\n changeset,\n {\n onConflict: () => SQLITE_CHANGESET_REPLACE,\n },\n );\n }\n\n /** Known extensions only: \"sqlite_vec\" → the sqlite-vec npm package's loadable library. */\n loadExtension(name: string): void {\n const path = KNOWN_EXTENSIONS[name]?.();\n if (!path) throw new Error(`Unknown SQLite extension \"${name}\"`);\n this.#db.enableLoadExtension(true);\n try {\n this.#db.loadExtension(path);\n } finally {\n this.#db.enableLoadExtension(false);\n }\n }\n\n /**\n * The database file as SQLite wrote it (page for page), for page-level logs; an in-memory\n * database falls back to image(). Valid between transactions (rollback journal mode).\n */\n pageImage(): Uint8Array {\n if (this.#path === \":memory:\") return this.image();\n // A database restored from celld's files is in WAL mode (litestream needs it): its last\n // commits are in the -wal file until a checkpoint moves them into the main file.\n const mode = String(this.#db.prepare(\"PRAGMA journal_mode\").get()?.journal_mode ?? \"\");\n if (mode.toLowerCase() === \"wal\") {\n this.#db.exec(\"PRAGMA wal_checkpoint(TRUNCATE)\");\n this.#walOffset = 0; // the WAL starts over\n }\n return new Uint8Array(readFileSync(this.#path));\n }\n\n /** `VACUUM INTO` a temp file: a consistent, compact image (no open transaction allowed). */\n image(): Uint8Array {\n const tmp = join(mkdtempSync(join(tmpdir(), \"cell-snap-\")), \"db.sqlite\");\n try {\n this.#db.exec(`VACUUM INTO '${tmp.replace(/'/g, \"''\")}'`);\n return new Uint8Array(readFileSync(tmp));\n } finally {\n rmSync(dirname(tmp), { recursive: true, force: true });\n }\n }\n\n /** Replaces the database file with `image` and reopens it (an in-memory DB becomes file-backed). */\n restore(image: Uint8Array): void {\n this.#db.close();\n if (this.#path === \":memory:\")\n this.#path = join(mkdtempSync(join(tmpdir(), \"cell-mem-\")), \"db.sqlite\");\n for (const suffix of [\"-wal\", \"-shm\", \"-journal\"]) rmSync(this.#path + suffix, { force: true });\n writeFileSync(this.#path, image);\n this.#db = new DatabaseSync(this.#path, { enableDoubleQuotedStringLiterals: true });\n if (this.#exclusive) this.#db.exec(\"PRAGMA locking_mode = EXCLUSIVE; PRAGMA busy_timeout = 0;\");\n this.#walSetup(); // a new file: a new WAL\n }\n}\n\nfunction toSqlite(v: unknown): unknown {\n if (v instanceof ArrayBuffer) return new Uint8Array(v);\n if (typeof v === \"boolean\") return v ? 1 : 0;\n return v === undefined ? null : v;\n}\n/** Workers return BLOBs as ArrayBuffer. */\nfunction fromSqlite(v: unknown): unknown {\n if (v instanceof Uint8Array) return v.buffer.slice(v.byteOffset, v.byteOffset + v.byteLength);\n return v;\n}\n\n/** One file per cell in `dir`, or in-memory when `dir` is omitted. */\n/**\n * `pageCapture` (file-backed only): WAL mode, and each commit's changed pages read from the WAL\n * (takeDirtyPages) — LTX logs then cost O(changed pages) on Node as with SQLite WASM.\n */\nexport function nodeSqliteOpener(\n dir?: string,\n opts: { exclusive?: boolean; pageCapture?: boolean } = {},\n): OpenCellSql {\n return (cellKey) =>\n new NodeSqliteDriver(\n dir ? `${dir}/${cellKey.replace(/[^\\w.-]/g, \"_\")}.sqlite` : \":memory:\",\n opts,\n );\n}\n"]}
package/dist/browser.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  export { sahpoolOpener } from "./adapters/wasm-sqlite.js";
2
2
  export { idbObjectStore } from "./bucket/idb-object-store.js";
3
+ export { type FilesRpcOptions, rpcFilesClient, serveFilesApi } from "./ltx/files-rpc.js";
4
+ export { filesApiPort, type ServeLtxStoreOptions, serveLtxStore } from "./ltx/ltx-host.js";
5
+ export type { LtxStoreFiles } from "./ltx/ltx-page-server.js";
3
6
  export { type BrowserBucket, type BrowserProjectOptions, browserProjectRuntime, } from "./project/browser-host.js";
4
7
  export { type BrowserLoadProjectOptions, loadProject } from "./project/browser-load.js";
5
8
  export { type ProjectShards, serveProjectShard, startProjectShards, } from "./project/browser-shards.js";
package/dist/browser.js CHANGED
@@ -1,5 +1,7 @@
1
1
  export { sahpoolOpener } from "./adapters/wasm-sqlite.js";
2
2
  export { idbObjectStore } from "./bucket/idb-object-store.js";
3
+ export { rpcFilesClient, serveFilesApi } from "./ltx/files-rpc.js";
4
+ export { filesApiPort, serveLtxStore } from "./ltx/ltx-host.js";
3
5
  export { browserProjectRuntime, } from "./project/browser-host.js";
4
6
  export { loadProject } from "./project/browser-load.js";
5
7
  export { serveProjectShard, startProjectShards, } from "./project/browser-shards.js";
@@ -1 +1 @@
1
- {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAGL,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAkC,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,EAEL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EAIjB,UAAU,GACX,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["export { sahpoolOpener } from \"./adapters/wasm-sqlite.js\";\nexport { idbObjectStore } from \"./bucket/idb-object-store.js\";\nexport {\n type BrowserBucket,\n type BrowserProjectOptions,\n browserProjectRuntime,\n} from \"./project/browser-host.js\";\nexport { type BrowserLoadProjectOptions, loadProject } from \"./project/browser-load.js\";\nexport {\n type ProjectShards,\n serveProjectShard,\n startProjectShards,\n} from \"./project/browser-shards.js\";\nexport {\n installProjectRouter,\n joinProjectShards,\n type ProjectTabs,\n type ProjectTabsOptions,\n type ServiceWorkerScope,\n shardOwner,\n} from \"./project/browser-tabs.js\";\nexport type {\n LoadedProject,\n LoadProjectOptions,\n ProjectSource,\n} from \"./project/built-project.js\";\nexport { serviceWorkerConnector } from \"./ws/sw-connector.js\";\n"]}
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAwB,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACzF,OAAO,EAAE,YAAY,EAA6B,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE3F,OAAO,EAGL,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAkC,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,EAEL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EAIjB,UAAU,GACX,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["export { sahpoolOpener } from \"./adapters/wasm-sqlite.js\";\nexport { idbObjectStore } from \"./bucket/idb-object-store.js\";\nexport { type FilesRpcOptions, rpcFilesClient, serveFilesApi } from \"./ltx/files-rpc.js\";\nexport { filesApiPort, type ServeLtxStoreOptions, serveLtxStore } from \"./ltx/ltx-host.js\";\nexport type { LtxStoreFiles } from \"./ltx/ltx-page-server.js\";\nexport {\n type BrowserBucket,\n type BrowserProjectOptions,\n browserProjectRuntime,\n} from \"./project/browser-host.js\";\nexport { type BrowserLoadProjectOptions, loadProject } from \"./project/browser-load.js\";\nexport {\n type ProjectShards,\n serveProjectShard,\n startProjectShards,\n} from \"./project/browser-shards.js\";\nexport {\n installProjectRouter,\n joinProjectShards,\n type ProjectTabs,\n type ProjectTabsOptions,\n type ServiceWorkerScope,\n shardOwner,\n} from \"./project/browser-tabs.js\";\nexport type {\n LoadedProject,\n LoadProjectOptions,\n ProjectSource,\n} from \"./project/built-project.js\";\nexport { serviceWorkerConnector } from \"./ws/sw-connector.js\";\n"]}
@@ -1,6 +1,6 @@
1
- import { createRequire } from "node:module";
1
+ import { requireNodeSqlite } from "../adapters/node-sqlite-module.js";
2
2
  import { PreconditionFailedError } from "./object-store.js";
3
- const { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
3
+ const { DatabaseSync } = requireNodeSqlite();
4
4
  /**
5
5
  * celld dev's local bucket: `<project>/.celld/dev/objects.sqlite3` (objects(key, body, etag
6
6
  * INTEGER, modified_ms, attributes) + store_sequence). Reading and writing it lets a
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite-object-store.js","sourceRoot":"","sources":["../../src/bucket/sqlite-object-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,EAAE,YAAY,EAAE,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CACrD,aAAa,CACkB,CAAC;AAElC;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,EAAE,CAAC,IAAI,CAAC;;4DAEkD,CAAC,CAAC;IAC5D,EAAE,CAAC,IAAI,CAAC;qFAC2E,CAAC,CAAC;IACrF,EAAE,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;IACrF,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACtC,OAAO;QACL,KAAK,CAAC,GAAG,CAAC,GAAG;YACX,MAAM,CAAC,GAAG,EAAE;iBACT,OAAO,CAAC,uEAAuE,CAAC;iBAChF,GAAG,CAAC,GAAG,CAEG,CAAC;YACd,OAAO,CAAC;gBACN,CAAC,CAAC;oBACE,IAAI,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC5B,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;oBACpB,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;oBACjC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;iBACpC;gBACH,CAAC,CAAC,SAAS,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK;YAC9B,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,GAAG,CAAC,GAAG,CAE3D,CAAC;gBACd,IAAI,IAAI,EAAE,WAAW,KAAK,GAAG,IAAI,GAAG;oBAAE,MAAM,IAAI,uBAAuB,CAAC,GAAG,CAAC,CAAC;gBAC7E,IAAI,IAAI,EAAE,OAAO,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO;oBACnE,MAAM,IAAI,uBAAuB,CAAC,GAAG,CAAC,CAAC;gBACzC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE;qBACrB,OAAO,CAAC,0DAA0D,CAAC;qBACnE,GAAG,EAEL,CAAC;gBACF,EAAE,CAAC,OAAO,CAAC,6DAA6D,CAAC,CAAC,GAAG,CAC3E,SAAS,GAAG,CAAC,CACd,CAAC;gBACF,EAAE,CAAC,OAAO,CACR,kGAAkG,CACnG,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC7D,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAClB,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACpB,MAAM,CAAC,CAAC;YACV,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAM;YACf,OACE,EAAE;iBACC,OAAO,CAAC,iEAAiE,CAAC;iBAC1E,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,QAAQ,CAGjC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,GAAG;YACd,EAAE,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3D,CAAC;QACD,KAAK;YACH,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC;AAUD,MAAM,OAAO,GAA4B;IACvC,CAAC,aAAa,EAAE,cAAc,CAAC;IAC/B,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;IACvC,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;IAC7C,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;IACvC,CAAC,cAAc,EAAE,eAAe,CAAC;CAClC,CAAC;AACF,SAAS,YAAY,CAAC,KAAwB;IAC5C,MAAM,GAAG,GAA2D,EAAE,CAAC;IACvE,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,IAAI,EAAE,CAAC;QAC/D,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AACD,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,IAA4D,CAAC;IACjE,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC3D,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACpC,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;YACtC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QACnC,CAAC;QACD,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC;YAAG,KAAiC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { createRequire } from \"node:module\";\nimport type { ObjectAttributes, ObjectStore } from \"./object-store.js\";\nimport { PreconditionFailedError } from \"./object-store.js\";\n\nconst { DatabaseSync } = createRequire(import.meta.url)(\n \"node:sqlite\",\n) as typeof import(\"node:sqlite\");\n\n/**\n * celld dev's local bucket: `<project>/.celld/dev/objects.sqlite3` (objects(key, body, etag\n * INTEGER, modified_ms, attributes) + store_sequence). Reading and writing it lets a\n * cellb node and `celld dev` share one bucket, so cells move between them.\n * Conditional writes are real (one SQLite transaction).\n */\nexport function sqliteObjectStore(file: string): ObjectStore & { close(): void } {\n const db = new DatabaseSync(file);\n db.exec(`CREATE TABLE IF NOT EXISTS objects (\n key TEXT PRIMARY KEY, body BLOB NOT NULL, etag INTEGER NOT NULL,\n modified_ms INTEGER NOT NULL, attributes TEXT NOT NULL)`);\n db.exec(`CREATE TABLE IF NOT EXISTS store_sequence (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1), next_etag INTEGER NOT NULL)`);\n db.exec(\"INSERT OR IGNORE INTO store_sequence (singleton, next_etag) VALUES (1, 1)\");\n db.exec(\"PRAGMA busy_timeout = 5000\");\n return {\n async get(key) {\n const r = db\n .prepare(\"SELECT body, etag, modified_ms, attributes FROM objects WHERE key = ?\")\n .get(key) as\n | { body: Uint8Array; etag: number; modified_ms: number; attributes: string }\n | undefined;\n return r\n ? {\n body: new Uint8Array(r.body),\n etag: String(r.etag),\n modifiedMs: Number(r.modified_ms),\n attrs: fromAttributes(r.attributes),\n }\n : undefined;\n },\n async put(key, body, cond, attrs) {\n db.exec(\"BEGIN IMMEDIATE\");\n try {\n const cur = db.prepare(\"SELECT etag FROM objects WHERE key = ?\").get(key) as\n | { etag: number }\n | undefined;\n if (cond?.ifNoneMatch === \"*\" && cur) throw new PreconditionFailedError(key);\n if (cond?.ifMatch !== undefined && String(cur?.etag) !== cond.ifMatch)\n throw new PreconditionFailedError(key);\n const { next_etag } = db\n .prepare(\"SELECT next_etag FROM store_sequence WHERE singleton = 1\")\n .get() as {\n next_etag: number;\n };\n db.prepare(\"UPDATE store_sequence SET next_etag = ? WHERE singleton = 1\").run(\n next_etag + 1,\n );\n db.prepare(\n \"INSERT OR REPLACE INTO objects (key, body, etag, modified_ms, attributes) VALUES (?, ?, ?, ?, ?)\",\n ).run(key, body, next_etag, Date.now(), toAttributes(attrs));\n db.exec(\"COMMIT\");\n return String(next_etag);\n } catch (e) {\n db.exec(\"ROLLBACK\");\n throw e;\n }\n },\n async list(prefix) {\n return (\n db\n .prepare(\"SELECT key FROM objects WHERE key >= ? AND key < ? ORDER BY key\")\n .all(prefix, `${prefix}\\uffff`) as {\n key: string;\n }[]\n ).map((r) => r.key);\n },\n async delete(key) {\n db.prepare(\"DELETE FROM objects WHERE key = ?\").run(key);\n },\n close() {\n db.close();\n },\n };\n}\n\n// celld dev's `attributes` column: a JSON array of {kind, name, value} — \"metadata\" entries\n// (user metadata, name = key) and one entry per content header (\"content-type\", …).\ntype HeaderField =\n | \"contentType\"\n | \"contentLanguage\"\n | \"contentDisposition\"\n | \"contentEncoding\"\n | \"cacheControl\";\nconst HEADERS: [HeaderField, string][] = [\n [\"contentType\", \"content-type\"],\n [\"contentLanguage\", \"content-language\"],\n [\"contentDisposition\", \"content-disposition\"],\n [\"contentEncoding\", \"content-encoding\"],\n [\"cacheControl\", \"cache-control\"],\n];\nfunction toAttributes(attrs?: ObjectAttributes): string {\n const out: { kind: string; name: string | null; value: string }[] = [];\n for (const [name, value] of Object.entries(attrs?.metadata ?? {}))\n out.push({ kind: \"metadata\", name, value });\n for (const [field, kind] of HEADERS) {\n const v = attrs?.[field];\n if (typeof v === \"string\") out.push({ kind, name: null, value: v });\n }\n return JSON.stringify(out);\n}\nfunction fromAttributes(raw: string): ObjectAttributes | undefined {\n let list: { kind: string; name: string | null; value: string }[];\n try {\n list = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!Array.isArray(list) || !list.length) return undefined;\n const attrs: ObjectAttributes = {};\n for (const e of list) {\n if (e.kind === \"metadata\" && e.name) {\n attrs.metadata = attrs.metadata ?? {};\n attrs.metadata[e.name] = e.value;\n }\n const h = HEADERS.find(([, kind]) => kind === e.kind);\n if (h) (attrs as Record<string, unknown>)[h[0]] = e.value;\n }\n return attrs;\n}\n"]}
1
+ {"version":3,"file":"sqlite-object-store.js","sourceRoot":"","sources":["../../src/bucket/sqlite-object-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { requireNodeSqlite } from \"../adapters/node-sqlite-module.js\";\nimport type { ObjectAttributes, ObjectStore } from \"./object-store.js\";\nimport { PreconditionFailedError } from \"./object-store.js\";\n\nconst { DatabaseSync } = requireNodeSqlite();\n\n/**\n * celld dev's local bucket: `<project>/.celld/dev/objects.sqlite3` (objects(key, body, etag\n * INTEGER, modified_ms, attributes) + store_sequence). Reading and writing it lets a\n * cellb node and `celld dev` share one bucket, so cells move between them.\n * Conditional writes are real (one SQLite transaction).\n */\nexport function sqliteObjectStore(file: string): ObjectStore & { close(): void } {\n const db = new DatabaseSync(file);\n db.exec(`CREATE TABLE IF NOT EXISTS objects (\n key TEXT PRIMARY KEY, body BLOB NOT NULL, etag INTEGER NOT NULL,\n modified_ms INTEGER NOT NULL, attributes TEXT NOT NULL)`);\n db.exec(`CREATE TABLE IF NOT EXISTS store_sequence (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1), next_etag INTEGER NOT NULL)`);\n db.exec(\"INSERT OR IGNORE INTO store_sequence (singleton, next_etag) VALUES (1, 1)\");\n db.exec(\"PRAGMA busy_timeout = 5000\");\n return {\n async get(key) {\n const r = db\n .prepare(\"SELECT body, etag, modified_ms, attributes FROM objects WHERE key = ?\")\n .get(key) as\n | { body: Uint8Array; etag: number; modified_ms: number; attributes: string }\n | undefined;\n return r\n ? {\n body: new Uint8Array(r.body),\n etag: String(r.etag),\n modifiedMs: Number(r.modified_ms),\n attrs: fromAttributes(r.attributes),\n }\n : undefined;\n },\n async put(key, body, cond, attrs) {\n db.exec(\"BEGIN IMMEDIATE\");\n try {\n const cur = db.prepare(\"SELECT etag FROM objects WHERE key = ?\").get(key) as\n | { etag: number }\n | undefined;\n if (cond?.ifNoneMatch === \"*\" && cur) throw new PreconditionFailedError(key);\n if (cond?.ifMatch !== undefined && String(cur?.etag) !== cond.ifMatch)\n throw new PreconditionFailedError(key);\n const { next_etag } = db\n .prepare(\"SELECT next_etag FROM store_sequence WHERE singleton = 1\")\n .get() as {\n next_etag: number;\n };\n db.prepare(\"UPDATE store_sequence SET next_etag = ? WHERE singleton = 1\").run(\n next_etag + 1,\n );\n db.prepare(\n \"INSERT OR REPLACE INTO objects (key, body, etag, modified_ms, attributes) VALUES (?, ?, ?, ?, ?)\",\n ).run(key, body, next_etag, Date.now(), toAttributes(attrs));\n db.exec(\"COMMIT\");\n return String(next_etag);\n } catch (e) {\n db.exec(\"ROLLBACK\");\n throw e;\n }\n },\n async list(prefix) {\n return (\n db\n .prepare(\"SELECT key FROM objects WHERE key >= ? AND key < ? ORDER BY key\")\n .all(prefix, `${prefix}\\uffff`) as {\n key: string;\n }[]\n ).map((r) => r.key);\n },\n async delete(key) {\n db.prepare(\"DELETE FROM objects WHERE key = ?\").run(key);\n },\n close() {\n db.close();\n },\n };\n}\n\n// celld dev's `attributes` column: a JSON array of {kind, name, value} — \"metadata\" entries\n// (user metadata, name = key) and one entry per content header (\"content-type\", …).\ntype HeaderField =\n | \"contentType\"\n | \"contentLanguage\"\n | \"contentDisposition\"\n | \"contentEncoding\"\n | \"cacheControl\";\nconst HEADERS: [HeaderField, string][] = [\n [\"contentType\", \"content-type\"],\n [\"contentLanguage\", \"content-language\"],\n [\"contentDisposition\", \"content-disposition\"],\n [\"contentEncoding\", \"content-encoding\"],\n [\"cacheControl\", \"cache-control\"],\n];\nfunction toAttributes(attrs?: ObjectAttributes): string {\n const out: { kind: string; name: string | null; value: string }[] = [];\n for (const [name, value] of Object.entries(attrs?.metadata ?? {}))\n out.push({ kind: \"metadata\", name, value });\n for (const [field, kind] of HEADERS) {\n const v = attrs?.[field];\n if (typeof v === \"string\") out.push({ kind, name: null, value: v });\n }\n return JSON.stringify(out);\n}\nfunction fromAttributes(raw: string): ObjectAttributes | undefined {\n let list: { kind: string; name: string | null; value: string }[];\n try {\n list = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!Array.isArray(list) || !list.length) return undefined;\n const attrs: ObjectAttributes = {};\n for (const e of list) {\n if (e.kind === \"metadata\" && e.name) {\n attrs.metadata = attrs.metadata ?? {};\n attrs.metadata[e.name] = e.value;\n }\n const h = HEADERS.find(([, kind]) => kind === e.kind);\n if (h) (attrs as Record<string, unknown>)[h[0]] = e.value;\n }\n return attrs;\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export { BrokenObjectError, CellOwnedElsewhereError, ObjectClosedError, } from "
12
12
  export { type CellRuntime, type CellRuntimeOptions, createCellRuntime, type WorkerModule, } from "./core/runtime.js";
13
13
  export { shardOf } from "./core/shard.js";
14
14
  export { DurableObjectState } from "./core/state.js";
15
+ export { type FilesRpcOptions, rpcFilesClient, serveFilesApi } from "./ltx/files-rpc.js";
15
16
  export * from "./ports.js";
16
17
  export { parseJsonc } from "./project/jsonc.js";
17
18
  export { createProjectRuntime, type ProjectHost, type ProjectRuntime, type WranglerConfig, } from "./project/wrangler.js";
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ export { BrokenObjectError, CellOwnedElsewhereError, ObjectClosedError, } from "
12
12
  export { createCellRuntime, } from "./core/runtime.js";
13
13
  export { shardOf } from "./core/shard.js";
14
14
  export { DurableObjectState } from "./core/state.js";
15
+ export { rpcFilesClient, serveFilesApi } from "./ltx/files-rpc.js";
15
16
  export * from "./ports.js";
16
17
  export { parseJsonc } from "./project/jsonc.js";
17
18
  export { createProjectRuntime, } from "./project/wrangler.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAyB,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,OAAO,EAGP,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAEjB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAyB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EACL,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,iBAAiB,GAElB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,oBAAoB,GAIrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAA0B,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EACL,iBAAiB,EAGjB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,gBAAgB,EAEhB,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,oBAAoB,GAErB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export { type FilesApiBackupOptions, filesApiBackup } from \"./adapters/files-backup.js\";\nexport { type ChangeLogOptions, filesApiChangeLog } from \"./adapters/files-changelog.js\";\nexport { type FilesApiLtxLogOptions, filesApiLtxLog } from \"./adapters/files-ltx.js\";\nexport { wasmMemoryOpener } from \"./adapters/wasm-sqlite.js\";\nexport {\n AiError,\n type AiRunOptions,\n type WorkersAiOptions,\n workersAi,\n} from \"./bindings/workers-ai.js\";\nexport { type CelldBucketOptions, celldBucket } from \"./bucket/celld-cells.js\";\nexport {\n filesApiObjectStore,\n memoryObjectStore,\n type ObjectStore,\n PreconditionFailedError,\n} from \"./bucket/object-store.js\";\nexport { type S3Options, s3ObjectStore } from \"./bucket/s3-object-store.js\";\nexport { DurableObject, type ExecutionContext, WorkerEntrypoint } from \"./core/durable-object.js\";\nexport {\n DurableObjectNamespace,\n type DurableObjectStub,\n runInDurableObject,\n} from \"./core/namespace.js\";\nexport {\n BrokenObjectError,\n CellOwnedElsewhereError,\n ObjectClosedError,\n} from \"./core/object-host.js\";\nexport {\n type CellRuntime,\n type CellRuntimeOptions,\n createCellRuntime,\n type WorkerModule,\n} from \"./core/runtime.js\";\nexport { shardOf } from \"./core/shard.js\";\nexport { DurableObjectState } from \"./core/state.js\";\nexport * from \"./ports.js\";\nexport { parseJsonc } from \"./project/jsonc.js\";\nexport {\n createProjectRuntime,\n type ProjectHost,\n type ProjectRuntime,\n type WranglerConfig,\n} from \"./project/wrangler.js\";\nexport { CellRouter, type CellRouterOptions, ShardOwnerLostError } from \"./router/cell-router.js\";\nexport {\n createShardWorker,\n type ShardWorker,\n type ShardWorkerOptions,\n shardRouting,\n} from \"./router/shard-worker.js\";\nexport {\n type CellsHttpOptions,\n cellsHttpHandler,\n type RemoteRuntime,\n remoteRuntime,\n} from \"./transport/cells-http.js\";\nexport {\n type CellPort,\n connectRuntime,\n linkOverPort,\n serveHandlerOverPort,\n serveRuntime,\n} from \"./transport/port.js\";\nexport {\n type CellsWebSocketClass,\n createWebSocketClass,\n type WebSocketConnector,\n} from \"./ws/client.js\";\nexport { CellsResponse, takeClientPort, WebSocketPair } from \"./ws/server.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAyB,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,OAAO,EAGP,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAEjB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAyB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EACL,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,iBAAiB,GAElB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAwB,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACzF,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,oBAAoB,GAIrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAA0B,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EACL,iBAAiB,EAGjB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,gBAAgB,EAEhB,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,oBAAoB,GAErB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export { type FilesApiBackupOptions, filesApiBackup } from \"./adapters/files-backup.js\";\nexport { type ChangeLogOptions, filesApiChangeLog } from \"./adapters/files-changelog.js\";\nexport { type FilesApiLtxLogOptions, filesApiLtxLog } from \"./adapters/files-ltx.js\";\nexport { wasmMemoryOpener } from \"./adapters/wasm-sqlite.js\";\nexport {\n AiError,\n type AiRunOptions,\n type WorkersAiOptions,\n workersAi,\n} from \"./bindings/workers-ai.js\";\nexport { type CelldBucketOptions, celldBucket } from \"./bucket/celld-cells.js\";\nexport {\n filesApiObjectStore,\n memoryObjectStore,\n type ObjectStore,\n PreconditionFailedError,\n} from \"./bucket/object-store.js\";\nexport { type S3Options, s3ObjectStore } from \"./bucket/s3-object-store.js\";\nexport { DurableObject, type ExecutionContext, WorkerEntrypoint } from \"./core/durable-object.js\";\nexport {\n DurableObjectNamespace,\n type DurableObjectStub,\n runInDurableObject,\n} from \"./core/namespace.js\";\nexport {\n BrokenObjectError,\n CellOwnedElsewhereError,\n ObjectClosedError,\n} from \"./core/object-host.js\";\nexport {\n type CellRuntime,\n type CellRuntimeOptions,\n createCellRuntime,\n type WorkerModule,\n} from \"./core/runtime.js\";\nexport { shardOf } from \"./core/shard.js\";\nexport { DurableObjectState } from \"./core/state.js\";\nexport { type FilesRpcOptions, rpcFilesClient, serveFilesApi } from \"./ltx/files-rpc.js\";\nexport * from \"./ports.js\";\nexport { parseJsonc } from \"./project/jsonc.js\";\nexport {\n createProjectRuntime,\n type ProjectHost,\n type ProjectRuntime,\n type WranglerConfig,\n} from \"./project/wrangler.js\";\nexport { CellRouter, type CellRouterOptions, ShardOwnerLostError } from \"./router/cell-router.js\";\nexport {\n createShardWorker,\n type ShardWorker,\n type ShardWorkerOptions,\n shardRouting,\n} from \"./router/shard-worker.js\";\nexport {\n type CellsHttpOptions,\n cellsHttpHandler,\n type RemoteRuntime,\n remoteRuntime,\n} from \"./transport/cells-http.js\";\nexport {\n type CellPort,\n connectRuntime,\n linkOverPort,\n serveHandlerOverPort,\n serveRuntime,\n} from \"./transport/port.js\";\nexport {\n type CellsWebSocketClass,\n createWebSocketClass,\n type WebSocketConnector,\n} from \"./ws/client.js\";\nexport { CellsResponse, takeClientPort, WebSocketPair } from \"./ws/server.js\";\n"]}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * A FilesApi across threads: `serveFilesApi(port, files)` answers on one end of a MessagePort
3
+ * for a FilesApi that lives in this thread (the user's own: File System Access, memory, OPFS,
4
+ * a key/value store, S3…), and `rpcFilesClient(port)` is that FilesApi in another thread (the
5
+ * LTX store worker, say). An instance cannot be posted to a worker; a port can.
6
+ *
7
+ * On @statewalker/webrun-rpc: the unary methods are one `callPort` each; a ranged read (the
8
+ * LTX store's page reads) is one `callPort` answered with the bytes; `read` without a length,
9
+ * `list` and `write` stream with `callBidi`. A write is sent in batches of up to `batchBytes`
10
+ * (the LTX encoder yields one small block per page).
11
+ *
12
+ * The client must not live in a thread that blocks on `Atomics.wait` (the SQLite VFS worker):
13
+ * a blocked thread receives no answers.
14
+ */
15
+ import type { FilesApi } from "@statewalker/webrun-files";
16
+ import { type MessageTarget } from "@statewalker/webrun-rpc";
17
+ export interface FilesRpcOptions {
18
+ /** How long one call may take, in ms (a disk, a network store); 60 s by default. */
19
+ timeout?: number;
20
+ }
21
+ /**
22
+ * Answers `rpcFilesClient` calls on `port` with `files`. Several ports may serve one FilesApi
23
+ * (one per worker). Returns the teardown.
24
+ */
25
+ export declare function serveFilesApi(port: MessageTarget, files: FilesApi): () => void;
26
+ /** A FilesApi whose calls go over `port` to a `serveFilesApi`. */
27
+ export declare function rpcFilesClient(port: MessageTarget, opts?: FilesRpcOptions & {
28
+ /** Bytes of a write sent per message; 1 MiB by default. */
29
+ batchBytes?: number;
30
+ }): FilesApi;
@@ -0,0 +1,129 @@
1
+ import { callBidi, callPort, listenBidi, listenPort, } from "@statewalker/webrun-rpc";
2
+ const UNARY = "webrun-files:unary";
3
+ const UNARY_METHODS = ["stats", "exists", "mkdir", "remove", "move", "copy", "readRange"];
4
+ const start = (port) => port.start?.();
5
+ /**
6
+ * The bytes of `c` in a buffer of their own: posting a view clones its WHOLE buffer (a page
7
+ * read as a subarray of a 10 MB file would cross the thread as 10 MB).
8
+ */
9
+ const own = (c) => c.byteOffset === 0 && c.byteLength === c.buffer.byteLength ? c : c.slice();
10
+ async function* owned(chunks) {
11
+ for await (const c of chunks)
12
+ yield own(c);
13
+ }
14
+ async function concat(chunks) {
15
+ const parts = [];
16
+ let n = 0;
17
+ for await (const c of chunks)
18
+ parts.push(c), (n += c.length);
19
+ if (parts.length === 1)
20
+ return own(parts[0]);
21
+ const out = new Uint8Array(n);
22
+ let o = 0;
23
+ for (const p of parts)
24
+ out.set(p, o), (o += p.length);
25
+ return out;
26
+ }
27
+ /**
28
+ * Answers `rpcFilesClient` calls on `port` with `files`. Several ports may serve one FilesApi
29
+ * (one per worker). Returns the teardown.
30
+ */
31
+ export function serveFilesApi(port, files) {
32
+ const offUnary = listenPort(port, async ({ m, a }) => {
33
+ if (!UNARY_METHODS.includes(m))
34
+ throw new Error(`files-rpc: unknown method ${String(m)}`);
35
+ if (m === "readRange") {
36
+ const [path, start, length] = a;
37
+ return concat(files.read(path, { start, length }));
38
+ }
39
+ return files[m].apply(files, a);
40
+ }, { channelName: UNARY });
41
+ const offStream = listenBidi(port, async (input, params) => {
42
+ const { fs, path, opts } = params;
43
+ if (fs === "read")
44
+ return owned(files.read(path, opts));
45
+ if (fs === "list")
46
+ return files.list(path, opts);
47
+ await files.write(path, input);
48
+ return (async function* () { })();
49
+ }, (params) => typeof params.fs === "string");
50
+ start(port);
51
+ return () => {
52
+ offUnary();
53
+ offStream();
54
+ };
55
+ }
56
+ /** A FilesApi whose calls go over `port` to a `serveFilesApi`. */
57
+ export function rpcFilesClient(port, opts = {}) {
58
+ start(port);
59
+ const timeout = opts.timeout ?? 60_000;
60
+ const batchBytes = opts.batchBytes ?? 1 << 20;
61
+ const call = (m, a, signal) => callPort(port, { m, a }, { channelName: UNARY, timeout, signal });
62
+ const unary = (m) => (...a) => call(m, a);
63
+ const stream = (req, input = [], signal) => callBidi(port, input, {
64
+ ...req,
65
+ // Read by the serving side too: its `send` waits this long for each chunk's
66
+ // acknowledgement, which comes when this side's consumer asks for the next one (without
67
+ // it, a consumer pausing over 1 s between chunks failed the stream).
68
+ timeout,
69
+ options: { timeout, bidiTimeout: 2147483647, signal },
70
+ });
71
+ /** Chunks gathered into messages of about `batchBytes`. */
72
+ async function* batched(content) {
73
+ let parts = [];
74
+ let n = 0;
75
+ const flush = () => {
76
+ const out = parts.length === 1 ? own(parts[0]) : new Uint8Array(n);
77
+ if (parts.length > 1) {
78
+ let o = 0;
79
+ for (const p of parts)
80
+ out.set(p, o), (o += p.length);
81
+ }
82
+ parts = [];
83
+ n = 0;
84
+ return out;
85
+ };
86
+ for await (const c of content) {
87
+ if (!c.length)
88
+ continue;
89
+ parts.push(c);
90
+ n += c.length;
91
+ if (n >= batchBytes)
92
+ yield flush();
93
+ }
94
+ if (n)
95
+ yield flush();
96
+ }
97
+ const api = {
98
+ read(path, o) {
99
+ const { start, length, signal } = o ?? {};
100
+ // A ranged read (the LTX store's page reads): one call, one answer.
101
+ if (length !== undefined)
102
+ return (async function* () {
103
+ const bytes = await call("readRange", [path, start ?? 0, length], signal);
104
+ if (bytes.length)
105
+ yield bytes;
106
+ })();
107
+ return stream({ fs: "read", path, opts: { start } }, [], signal);
108
+ },
109
+ list(path, o) {
110
+ return stream({
111
+ fs: "list",
112
+ path,
113
+ opts: { recursive: o?.recursive, after: o?.after },
114
+ });
115
+ },
116
+ async write(path, content) {
117
+ for await (const _ of stream({ fs: "write", path }, batched(content)))
118
+ void _;
119
+ },
120
+ stats: unary("stats"),
121
+ exists: unary("exists"),
122
+ mkdir: unary("mkdir"),
123
+ remove: unary("remove"),
124
+ move: unary("move"),
125
+ copy: unary("copy"),
126
+ };
127
+ return api;
128
+ }
129
+ //# sourceMappingURL=files-rpc.js.map