@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.
- package/dist/adapters/ltx-vfs.js +26 -4
- package/dist/adapters/ltx-vfs.js.map +1 -1
- package/dist/adapters/node-sqlite-module.d.ts +9 -0
- package/dist/adapters/node-sqlite-module.js +28 -0
- package/dist/adapters/node-sqlite-module.js.map +1 -0
- package/dist/adapters/node-sqlite.js +2 -3
- package/dist/adapters/node-sqlite.js.map +1 -1
- package/dist/browser.d.ts +3 -0
- package/dist/browser.js +2 -0
- package/dist/browser.js.map +1 -1
- package/dist/bucket/sqlite-object-store.js +2 -2
- package/dist/bucket/sqlite-object-store.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ltx/files-rpc.d.ts +30 -0
- package/dist/ltx/files-rpc.js +129 -0
- package/dist/ltx/files-rpc.js.map +1 -0
- package/dist/ltx/ltx-host.d.ts +63 -0
- package/dist/ltx/ltx-host.js +46 -0
- package/dist/ltx/ltx-host.js.map +1 -0
- package/dist/ltx/ltx-page-server.d.ts +42 -1
- package/dist/ltx/ltx-page-server.js +101 -21
- package/dist/ltx/ltx-page-server.js.map +1 -1
- package/dist/ltx/ltx-pages.d.ts +5 -0
- package/dist/ltx/ltx-pages.js +32 -3
- package/dist/ltx/ltx-pages.js.map +1 -1
- package/dist/ltx/ltx-store-worker.js +35 -22
- package/dist/ltx/ltx-store-worker.js.map +1 -1
- package/dist/project/browser-host.d.ts +32 -3
- package/dist/project/browser-host.js +45 -18
- package/dist/project/browser-host.js.map +1 -1
- package/package.json +2 -2
package/dist/ltx/ltx-pages.js
CHANGED
|
@@ -113,16 +113,44 @@ function pagesOf(files, path, header, index) {
|
|
|
113
113
|
* in TXID order. Only headers and page indexes are read.
|
|
114
114
|
*/
|
|
115
115
|
export async function openPagedCell(files, paths) {
|
|
116
|
-
const
|
|
117
|
-
opened
|
|
116
|
+
const settled = await Promise.all(paths.map((p) => openLtxPages(files, p).then((f) => ({ f }), (error) => ({ p, error }))));
|
|
117
|
+
const opened = [];
|
|
118
|
+
const skipped = [];
|
|
119
|
+
for (const r of settled) {
|
|
120
|
+
if ("f" in r)
|
|
121
|
+
opened.push(r.f);
|
|
122
|
+
// A snapshot that does not open (a compaction's move done as a copy, cut short): the
|
|
123
|
+
// files it was made from are all still there, so the cell is read from them.
|
|
124
|
+
else if (/(^|\/)0{15}1-[0-9a-f]{16}\.ltx$/.test(r.p)) {
|
|
125
|
+
console.warn(`cellb ltx: skipping ${r.p}, which does not open:`, r.error);
|
|
126
|
+
skipped.push(r.error);
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
throw r.error;
|
|
130
|
+
}
|
|
131
|
+
// By maxTXID; at the same maxTXID, a snapshot (minTXID 1) after the incremental file it
|
|
132
|
+
// folded in: a compaction interrupted between writing its snapshot and removing the files it
|
|
133
|
+
// replaces leaves both, and the snapshot is what the cell is.
|
|
134
|
+
opened.sort((a, b) => a.header.maxTXID !== b.header.maxTXID
|
|
135
|
+
? a.header.maxTXID < b.header.maxTXID
|
|
136
|
+
? -1
|
|
137
|
+
: 1
|
|
138
|
+
: a.header.minTXID > b.header.minTXID
|
|
139
|
+
? -1
|
|
140
|
+
: a.header.minTXID < b.header.minTXID
|
|
141
|
+
? 1
|
|
142
|
+
: 0);
|
|
118
143
|
let snapshotAt = -1;
|
|
119
144
|
opened.forEach((f, i) => {
|
|
120
145
|
if (f.header.minTXID === 1n)
|
|
121
146
|
snapshotAt = i;
|
|
122
147
|
});
|
|
148
|
+
// No other snapshot to read the cell from: the skipped one's own error is the reason.
|
|
123
149
|
if (snapshotAt < 0)
|
|
124
|
-
throw new Error("ltx: no snapshot among the cell's files");
|
|
150
|
+
throw skipped[0] ?? new Error("ltx: no snapshot among the cell's files");
|
|
125
151
|
const chain = opened.slice(snapshotAt);
|
|
152
|
+
/** Files the newest snapshot covers (left by an interrupted compaction): not read. */
|
|
153
|
+
const superseded = opened.slice(0, snapshotAt).map((f) => f.path);
|
|
126
154
|
for (let i = 1; i < chain.length; i++)
|
|
127
155
|
if (chain[i].header.minTXID !== chain[i - 1].header.maxTXID + 1n)
|
|
128
156
|
throw new Error(`ltx: gap before ${chain[i].path}`);
|
|
@@ -136,6 +164,7 @@ export async function openPagedCell(files, paths) {
|
|
|
136
164
|
pageCount: newest.commit,
|
|
137
165
|
maxTXID: newest.maxTXID,
|
|
138
166
|
files: chain,
|
|
167
|
+
superseded,
|
|
139
168
|
source: (pgno) => owner.get(pgno)?.path,
|
|
140
169
|
async readPage(pgno) {
|
|
141
170
|
const page = pgno <= cell.pageCount ? await owner.get(pgno)?.readPage(pgno) : undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ltx-pages.js","sourceRoot":"","sources":["../../src/ltx/ltx-pages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Page-level random access to a cell kept as celld keeps it: LTX files in a bucket\n * (`…/ltx/e<epoch>/<level>/<min>-<max>.ltx`), a snapshot (TXID 1..N) and the incremental files\n * after it. Nothing is read whole: an LTX file ends with a page index (pgno → offset, size), so\n * opening a file reads its 100-byte header and its index, and a page is ONE range read plus an\n * LZ4 decode. The newest file holding a page wins; `compact` folds them into a new snapshot.\n *\n * This is the read side a SQLite VFS needs to serve a database from any FilesApi (OPFS, File\n * System Access, IndexedDB, S3…) without loading it: xRead → `readPage` (through a page cache);\n * the write side is the existing LTX log (one incremental file per commit).\n */\nimport type { FilesApi } from \"@statewalker/webrun-files\";\nimport { Crc64 } from \"./crc64.js\";\nimport { CHECKSUM_FLAG, type LtxHeader, lockPgno } from \"./ltx.js\";\nimport { lz4Compress, lz4Decompress, lz4FrameDecompress } from \"./lz4.js\";\n\nconst HEADER_SIZE = 100;\nconst PAGE_HEADER_FLAG_SIZE = 1;\n\nasync function readRange(\n files: FilesApi,\n path: string,\n start: number,\n length: number,\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n for await (const c of files.read(path, { start, length })) chunks.push(c);\n const got = chunks.reduce((n, c) => n + c.length, 0);\n // A short read is a file that changed or went away under its reader: say which, rather than\n // decode past its end (\"Offset is outside the bounds of the DataView\").\n if (got !== length) {\n const st = await files.stats(path).catch(() => undefined);\n throw new LtxShortReadError(\n `ltx: short read of ${path}: ${got} of ${length} bytes at ${start} (file ${st?.kind === \"file\" ? `${(st as { size: number }).size} bytes` : \"missing\"})`,\n );\n }\n if (chunks.length === 1) return chunks[0];\n const out = new Uint8Array(got);\n let o = 0;\n for (const c of chunks) out.set(c, o), (o += c.length);\n return out;\n}\n\n/** A range read that got fewer bytes than asked: the file changed or was removed meanwhile. */\nexport class LtxShortReadError extends Error {\n name = \"LtxShortReadError\";\n}\n\nexport interface LtxPages {\n path: string;\n header: LtxHeader;\n /** pgno → [offset of the page's 6-byte header, size including it]. */\n index: Map<number, [number, number]>;\n /** One range read and an LZ4 decode. */\n readPage(pgno: number): Promise<Uint8Array | undefined>;\n /** Several pages of this file with ONE range read (they are stored in pgno order). */\n readPages(pgnos: number[]): Promise<Map<number, Uint8Array>>;\n}\n\n/** Opens an LTX file for page reads: reads its header and its page index only. */\nexport async function openLtxPages(\n files: FilesApi,\n path: string,\n /** The header and index of a file this process just wrote: nothing is read back. */\n known?: { header: LtxHeader; index: Map<number, [number, number]> },\n): Promise<LtxPages> {\n if (known) return pagesOf(files, path, known.header, known.index);\n const size =\n (await files.stats(path))?.kind === \"file\"\n ? ((await files.stats(path)) as { size: number }).size\n : 0;\n if (size < HEADER_SIZE + 6 + 24) throw new Error(`ltx: ${path} is too small`);\n const head = await readRange(files, path, 0, HEADER_SIZE);\n const hv = new DataView(head.buffer, head.byteOffset, head.byteLength);\n if (new TextDecoder().decode(head.subarray(0, 4)) !== \"LTX1\")\n throw new Error(`ltx: ${path}: bad magic`);\n const header: LtxHeader = {\n flags: hv.getUint32(4),\n pageSize: hv.getUint32(8),\n commit: hv.getUint32(12),\n minTXID: hv.getBigUint64(16),\n maxTXID: hv.getBigUint64(24),\n timestamp: Number(hv.getBigInt64(32)),\n preApplyChecksum: hv.getBigUint64(40),\n };\n // Trailer: … index | u64 index length | u64 post-apply checksum | u64 file checksum.\n const tail = await readRange(files, path, size - 24, 24);\n const idxLen = Number(new DataView(tail.buffer, tail.byteOffset, 24).getBigUint64(0));\n const idx = await readRange(files, path, size - 24 - idxLen, idxLen);\n const index = new Map<number, [number, number]>();\n let o = 0;\n const varint = () => {\n let x = 0;\n let shift = 0;\n let b: number;\n do {\n b = idx[o++];\n x += (b & 0x7f) * 2 ** shift;\n shift += 7;\n } while (b & 0x80);\n return x;\n };\n for (;;) {\n const pgno = varint();\n if (pgno === 0) break;\n const offset = varint();\n index.set(pgno, [offset, varint()]);\n }\n return pagesOf(files, path, header, index);\n}\n\nfunction pagesOf(\n files: FilesApi,\n path: string,\n header: LtxHeader,\n index: Map<number, [number, number]>,\n): LtxPages {\n const decodePage = (b: Uint8Array) => {\n const v = new DataView(b.buffer, b.byteOffset, b.byteLength);\n if (v.getUint16(4) & PAGE_HEADER_FLAG_SIZE)\n return lz4Decompress(b.subarray(10, 10 + v.getUint32(6)), header.pageSize);\n return lz4FrameDecompress(b.subarray(6), header.pageSize);\n };\n return {\n path,\n header,\n index,\n async readPage(pgno) {\n const at = index.get(pgno);\n if (!at) return undefined;\n return decodePage(await readRange(files, path, at[0], at[1]));\n },\n async readPages(pgnos) {\n const out = new Map<number, Uint8Array>();\n const wanted = pgnos.filter((p) => index.has(p));\n if (!wanted.length) return out;\n const spans = wanted.map((p) => index.get(p) as [number, number]);\n const start = Math.min(...spans.map((s) => s[0]));\n const end = Math.max(...spans.map((s) => s[0] + s[1]));\n const b = await readRange(files, path, start, end - start);\n for (const [i, p] of wanted.entries())\n out.set(p, decodePage(b.subarray(spans[i][0] - start, spans[i][0] - start + spans[i][1])));\n return out;\n },\n };\n}\n\nexport interface PagedCell {\n pageSize: number;\n /** Database size in pages, after the newest file. */\n pageCount: number;\n maxTXID: bigint;\n /** The files, oldest first (the snapshot, then the incremental ones). */\n files: LtxPages[];\n /** The page as of the newest file holding it (zeros past the database end). */\n readPage(pgno: number): Promise<Uint8Array>;\n /** Pages `from`..`from+count-1` (within the database), one range read per file they live in. */\n readRun(from: number, count: number): Promise<Map<number, Uint8Array>>;\n /** Which file serves each page (for tests and traces). */\n source(pgno: number): string | undefined;\n /**\n * Adds the cell's next file (the one just written after `maxTXID`): reads its header and index\n * only, so a commit costs one file whatever the number of files before it.\n */\n append(\n path: string,\n known?: { header: LtxHeader; index: Map<number, [number, number]> },\n ): Promise<void>;\n}\n\n/**\n * A cell's pages over its LTX files: the newest snapshot (min TXID 1) and the files after it,\n * in TXID order. Only headers and page indexes are read.\n */\nexport async function openPagedCell(files: FilesApi, paths: string[]): Promise<PagedCell> {\n const opened = await Promise.all(paths.map((p) => openLtxPages(files, p)));\n opened.sort((a, b) =>\n a.header.maxTXID < b.header.maxTXID ? -1 : a.header.maxTXID > b.header.maxTXID ? 1 : 0,\n );\n let snapshotAt = -1;\n opened.forEach((f, i) => {\n if (f.header.minTXID === 1n) snapshotAt = i;\n });\n if (snapshotAt < 0) throw new Error(\"ltx: no snapshot among the cell's files\");\n const chain = opened.slice(snapshotAt);\n for (let i = 1; i < chain.length; i++)\n if (chain[i].header.minTXID !== chain[i - 1].header.maxTXID + 1n)\n throw new Error(`ltx: gap before ${chain[i].path}`);\n let newest = chain[chain.length - 1].header;\n const owner = new Map<number, LtxPages>();\n for (const f of chain) for (const pgno of f.index.keys()) owner.set(pgno, f);\n const cell: PagedCell = {\n pageSize: newest.pageSize,\n pageCount: newest.commit,\n maxTXID: newest.maxTXID,\n files: chain,\n source: (pgno) => owner.get(pgno)?.path,\n async readPage(pgno) {\n const page = pgno <= cell.pageCount ? await owner.get(pgno)?.readPage(pgno) : undefined;\n return page ?? new Uint8Array(cell.pageSize);\n },\n async readRun(from, count) {\n const byFile = new Map<LtxPages, number[]>();\n const out = new Map<number, Uint8Array>();\n for (let p = from; p < from + count && p <= cell.pageCount; p++) {\n const f = owner.get(p);\n if (!f) out.set(p, new Uint8Array(cell.pageSize));\n else byFile.set(f, [...(byFile.get(f) ?? []), p]);\n }\n for (const [f, pgnos] of byFile) for (const [p, d] of await f.readPages(pgnos)) out.set(p, d);\n return out;\n },\n async append(path, known) {\n const f = await openLtxPages(files, path, known);\n if (f.header.minTXID !== cell.maxTXID + 1n)\n throw new Error(`ltx: ${path} does not follow TXID ${cell.maxTXID}`);\n chain.push(f);\n for (const pgno of f.index.keys()) owner.set(pgno, f);\n newest = f.header;\n cell.pageCount = newest.commit;\n cell.maxTXID = newest.maxTXID;\n for (const [pgno] of owner) if (pgno > cell.pageCount) owner.delete(pgno);\n },\n };\n return cell;\n}\n\n/**\n * An LTX file produced page by page, as celld writes it (block format: size-prefixed LZ4 page\n * blocks, page index, trailer, CRC-64/ISO over the uncompressed pages): the bytes come out as an\n * async stream while `pages` is consumed, so a writer holds one page at a time plus the index\n * (a few bytes per page), never the database.\n */\nexport async function* encodeLtxStream(\n header: LtxHeader,\n pages: AsyncIterable<[number, Uint8Array]>,\n postApplyChecksum = 0n,\n /** Filled while encoding: the file's page index (what `openLtxPages` would read back). */\n written?: { index: Map<number, [number, number]> },\n): AsyncGenerator<Uint8Array> {\n // Coalesced into 256 KiB chunks: a writer pays per call (an OPFS SyncAccessHandle write, a\n // stream write), and a page makes three small pieces.\n yield* coalesce(encodePieces(header, pages, postApplyChecksum, written), 256 * 1024);\n}\n\nasync function* coalesce(src: AsyncIterable<Uint8Array>, size: number): AsyncGenerator<Uint8Array> {\n let buf = new Uint8Array(size);\n let n = 0;\n for await (const piece of src) {\n if (piece.length >= size) {\n if (n) yield buf.slice(0, n), (n = 0);\n yield piece;\n continue;\n }\n if (n + piece.length > size) {\n yield buf.slice(0, n);\n buf = new Uint8Array(size);\n n = 0;\n }\n buf.set(piece, n);\n n += piece.length;\n }\n if (n) yield buf.slice(0, n);\n}\n\nasync function* encodePieces(\n header: LtxHeader,\n pages: AsyncIterable<[number, Uint8Array]>,\n postApplyChecksum: bigint,\n written?: { index: Map<number, [number, number]> },\n): AsyncGenerator<Uint8Array> {\n const crc = new Crc64();\n const head = new Uint8Array(HEADER_SIZE);\n const v = new DataView(head.buffer);\n head.set(new TextEncoder().encode(\"LTX1\"), 0);\n const flags =\n header.flags ?? (header.preApplyChecksum === 0n && postApplyChecksum === 0n ? 2 : 0);\n v.setUint32(4, flags);\n v.setUint32(8, header.pageSize);\n v.setUint32(12, header.commit);\n v.setBigUint64(16, header.minTXID);\n v.setBigUint64(24, header.maxTXID);\n v.setBigInt64(32, BigInt(header.timestamp));\n v.setBigUint64(40, header.preApplyChecksum);\n v.setBigUint64(72, header.nodeID ?? 0n);\n crc.update(head);\n yield head;\n const index: number[] = [];\n const uvarint = (n: number) => {\n while (n >= 0x80) index.push((n & 0x7f) | 0x80), (n = Math.floor(n / 128));\n index.push(n);\n };\n let offset = HEADER_SIZE;\n const lock = lockPgno(header.pageSize);\n let last = 0;\n for await (const [pgno, data] of pages) {\n if (pgno === lock) continue;\n if (pgno <= last) throw new Error(\"ltx: pages must come in ascending order\");\n last = pgno;\n const compressed = lz4Compress(data);\n const ph = new Uint8Array(10);\n const pv = new DataView(ph.buffer);\n pv.setUint32(0, pgno);\n pv.setUint16(4, PAGE_HEADER_FLAG_SIZE);\n pv.setUint32(6, compressed.length);\n crc.update(ph).update(data); // the checksum covers uncompressed pages (encodeLtx's `feed`)\n uvarint(pgno), uvarint(offset), uvarint(10 + compressed.length);\n written?.index.set(pgno, [offset, 10 + compressed.length]);\n offset += 10 + compressed.length;\n yield ph;\n yield compressed;\n }\n const end = new Uint8Array(6);\n uvarint(0);\n const idx = Uint8Array.from(index);\n const tail = new Uint8Array(16);\n const tv = new DataView(tail.buffer);\n tv.setBigUint64(0, BigInt(idx.length));\n tv.setBigUint64(8, postApplyChecksum);\n crc.update(end).update(idx).update(tail);\n const sum = new Uint8Array(8);\n new DataView(sum.buffer).setBigUint64(0, CHECKSUM_FLAG | crc.digest());\n yield end;\n yield idx;\n yield tail;\n yield sum;\n}\n\n/**\n * Folds a cell's files into one snapshot (TXID 1..maxTXID) written to `files` at `path`, page by\n * page: each page is read by range from the file that holds it and streamed into the new file,\n * so memory stays at one page (plus the index), whatever the database size. The caller removes\n * the files it replaces once this resolves.\n */\nexport async function compactPagedCellTo(\n cell: PagedCell,\n files: FilesApi,\n path: string,\n timestamp = Date.now(),\n): Promise<void> {\n // In runs of 256 pages: one range read per file a run touches (not one read per page).\n async function* pages(): AsyncGenerator<[number, Uint8Array]> {\n for (let from = 1; from <= cell.pageCount; from += 256) {\n const run = await cell.readRun(from, 256);\n for (let pgno = from; pgno < from + 256 && pgno <= cell.pageCount; pgno++)\n yield [pgno, run.get(pgno) ?? new Uint8Array(cell.pageSize)];\n }\n }\n await files.write(\n path,\n encodeLtxStream(\n {\n pageSize: cell.pageSize,\n commit: cell.pageCount,\n minTXID: 1n,\n maxTXID: cell.maxTXID,\n timestamp,\n preApplyChecksum: 0n,\n },\n pages(),\n ),\n );\n}\n\n/** The compacted snapshot as bytes (small cells, tests); compactPagedCellTo streams it. */\nexport async function compactPagedCell(\n cell: PagedCell,\n timestamp = Date.now(),\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n async function* pages(): AsyncGenerator<[number, Uint8Array]> {\n for (let pgno = 1; pgno <= cell.pageCount; pgno++) yield [pgno, await cell.readPage(pgno)];\n }\n for await (const c of encodeLtxStream(\n {\n pageSize: cell.pageSize,\n commit: cell.pageCount,\n minTXID: 1n,\n maxTXID: cell.maxTXID,\n timestamp,\n preApplyChecksum: 0n,\n },\n pages(),\n ))\n chunks.push(c);\n const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let o = 0;\n for (const c of chunks) out.set(c, o), (o += c.length);\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ltx-pages.js","sourceRoot":"","sources":["../../src/ltx/ltx-pages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Page-level random access to a cell kept as celld keeps it: LTX files in a bucket\n * (`…/ltx/e<epoch>/<level>/<min>-<max>.ltx`), a snapshot (TXID 1..N) and the incremental files\n * after it. Nothing is read whole: an LTX file ends with a page index (pgno → offset, size), so\n * opening a file reads its 100-byte header and its index, and a page is ONE range read plus an\n * LZ4 decode. The newest file holding a page wins; `compact` folds them into a new snapshot.\n *\n * This is the read side a SQLite VFS needs to serve a database from any FilesApi (OPFS, File\n * System Access, IndexedDB, S3…) without loading it: xRead → `readPage` (through a page cache);\n * the write side is the existing LTX log (one incremental file per commit).\n */\nimport type { FilesApi } from \"@statewalker/webrun-files\";\nimport { Crc64 } from \"./crc64.js\";\nimport { CHECKSUM_FLAG, type LtxHeader, lockPgno } from \"./ltx.js\";\nimport { lz4Compress, lz4Decompress, lz4FrameDecompress } from \"./lz4.js\";\n\nconst HEADER_SIZE = 100;\nconst PAGE_HEADER_FLAG_SIZE = 1;\n\nasync function readRange(\n files: FilesApi,\n path: string,\n start: number,\n length: number,\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n for await (const c of files.read(path, { start, length })) chunks.push(c);\n const got = chunks.reduce((n, c) => n + c.length, 0);\n // A short read is a file that changed or went away under its reader: say which, rather than\n // decode past its end (\"Offset is outside the bounds of the DataView\").\n if (got !== length) {\n const st = await files.stats(path).catch(() => undefined);\n throw new LtxShortReadError(\n `ltx: short read of ${path}: ${got} of ${length} bytes at ${start} (file ${st?.kind === \"file\" ? `${(st as { size: number }).size} bytes` : \"missing\"})`,\n );\n }\n if (chunks.length === 1) return chunks[0];\n const out = new Uint8Array(got);\n let o = 0;\n for (const c of chunks) out.set(c, o), (o += c.length);\n return out;\n}\n\n/** A range read that got fewer bytes than asked: the file changed or was removed meanwhile. */\nexport class LtxShortReadError extends Error {\n name = \"LtxShortReadError\";\n}\n\nexport interface LtxPages {\n path: string;\n header: LtxHeader;\n /** pgno → [offset of the page's 6-byte header, size including it]. */\n index: Map<number, [number, number]>;\n /** One range read and an LZ4 decode. */\n readPage(pgno: number): Promise<Uint8Array | undefined>;\n /** Several pages of this file with ONE range read (they are stored in pgno order). */\n readPages(pgnos: number[]): Promise<Map<number, Uint8Array>>;\n}\n\n/** Opens an LTX file for page reads: reads its header and its page index only. */\nexport async function openLtxPages(\n files: FilesApi,\n path: string,\n /** The header and index of a file this process just wrote: nothing is read back. */\n known?: { header: LtxHeader; index: Map<number, [number, number]> },\n): Promise<LtxPages> {\n if (known) return pagesOf(files, path, known.header, known.index);\n const size =\n (await files.stats(path))?.kind === \"file\"\n ? ((await files.stats(path)) as { size: number }).size\n : 0;\n if (size < HEADER_SIZE + 6 + 24) throw new Error(`ltx: ${path} is too small`);\n const head = await readRange(files, path, 0, HEADER_SIZE);\n const hv = new DataView(head.buffer, head.byteOffset, head.byteLength);\n if (new TextDecoder().decode(head.subarray(0, 4)) !== \"LTX1\")\n throw new Error(`ltx: ${path}: bad magic`);\n const header: LtxHeader = {\n flags: hv.getUint32(4),\n pageSize: hv.getUint32(8),\n commit: hv.getUint32(12),\n minTXID: hv.getBigUint64(16),\n maxTXID: hv.getBigUint64(24),\n timestamp: Number(hv.getBigInt64(32)),\n preApplyChecksum: hv.getBigUint64(40),\n };\n // Trailer: … index | u64 index length | u64 post-apply checksum | u64 file checksum.\n const tail = await readRange(files, path, size - 24, 24);\n const idxLen = Number(new DataView(tail.buffer, tail.byteOffset, 24).getBigUint64(0));\n const idx = await readRange(files, path, size - 24 - idxLen, idxLen);\n const index = new Map<number, [number, number]>();\n let o = 0;\n const varint = () => {\n let x = 0;\n let shift = 0;\n let b: number;\n do {\n b = idx[o++];\n x += (b & 0x7f) * 2 ** shift;\n shift += 7;\n } while (b & 0x80);\n return x;\n };\n for (;;) {\n const pgno = varint();\n if (pgno === 0) break;\n const offset = varint();\n index.set(pgno, [offset, varint()]);\n }\n return pagesOf(files, path, header, index);\n}\n\nfunction pagesOf(\n files: FilesApi,\n path: string,\n header: LtxHeader,\n index: Map<number, [number, number]>,\n): LtxPages {\n const decodePage = (b: Uint8Array) => {\n const v = new DataView(b.buffer, b.byteOffset, b.byteLength);\n if (v.getUint16(4) & PAGE_HEADER_FLAG_SIZE)\n return lz4Decompress(b.subarray(10, 10 + v.getUint32(6)), header.pageSize);\n return lz4FrameDecompress(b.subarray(6), header.pageSize);\n };\n return {\n path,\n header,\n index,\n async readPage(pgno) {\n const at = index.get(pgno);\n if (!at) return undefined;\n return decodePage(await readRange(files, path, at[0], at[1]));\n },\n async readPages(pgnos) {\n const out = new Map<number, Uint8Array>();\n const wanted = pgnos.filter((p) => index.has(p));\n if (!wanted.length) return out;\n const spans = wanted.map((p) => index.get(p) as [number, number]);\n const start = Math.min(...spans.map((s) => s[0]));\n const end = Math.max(...spans.map((s) => s[0] + s[1]));\n const b = await readRange(files, path, start, end - start);\n for (const [i, p] of wanted.entries())\n out.set(p, decodePage(b.subarray(spans[i][0] - start, spans[i][0] - start + spans[i][1])));\n return out;\n },\n };\n}\n\nexport interface PagedCell {\n pageSize: number;\n /** Database size in pages, after the newest file. */\n pageCount: number;\n maxTXID: bigint;\n /** The files, oldest first (the snapshot, then the incremental ones). */\n files: LtxPages[];\n /**\n * Older files the newest snapshot already holds (an interrupted compaction's): never read;\n * a writer that owns the cell removes them.\n */\n superseded: string[];\n /** The page as of the newest file holding it (zeros past the database end). */\n readPage(pgno: number): Promise<Uint8Array>;\n /** Pages `from`..`from+count-1` (within the database), one range read per file they live in. */\n readRun(from: number, count: number): Promise<Map<number, Uint8Array>>;\n /** Which file serves each page (for tests and traces). */\n source(pgno: number): string | undefined;\n /**\n * Adds the cell's next file (the one just written after `maxTXID`): reads its header and index\n * only, so a commit costs one file whatever the number of files before it.\n */\n append(\n path: string,\n known?: { header: LtxHeader; index: Map<number, [number, number]> },\n ): Promise<void>;\n}\n\n/**\n * A cell's pages over its LTX files: the newest snapshot (min TXID 1) and the files after it,\n * in TXID order. Only headers and page indexes are read.\n */\nexport async function openPagedCell(files: FilesApi, paths: string[]): Promise<PagedCell> {\n const settled = await Promise.all(\n paths.map((p) =>\n openLtxPages(files, p).then(\n (f) => ({ f }),\n (error: unknown) => ({ p, error }),\n ),\n ),\n );\n const opened: LtxPages[] = [];\n const skipped: unknown[] = [];\n for (const r of settled) {\n if (\"f\" in r) opened.push(r.f);\n // A snapshot that does not open (a compaction's move done as a copy, cut short): the\n // files it was made from are all still there, so the cell is read from them.\n else if (/(^|\\/)0{15}1-[0-9a-f]{16}\\.ltx$/.test(r.p)) {\n console.warn(`cellb ltx: skipping ${r.p}, which does not open:`, r.error);\n skipped.push(r.error);\n } else throw r.error;\n }\n // By maxTXID; at the same maxTXID, a snapshot (minTXID 1) after the incremental file it\n // folded in: a compaction interrupted between writing its snapshot and removing the files it\n // replaces leaves both, and the snapshot is what the cell is.\n opened.sort((a, b) =>\n a.header.maxTXID !== b.header.maxTXID\n ? a.header.maxTXID < b.header.maxTXID\n ? -1\n : 1\n : a.header.minTXID > b.header.minTXID\n ? -1\n : a.header.minTXID < b.header.minTXID\n ? 1\n : 0,\n );\n let snapshotAt = -1;\n opened.forEach((f, i) => {\n if (f.header.minTXID === 1n) snapshotAt = i;\n });\n // No other snapshot to read the cell from: the skipped one's own error is the reason.\n if (snapshotAt < 0) throw skipped[0] ?? new Error(\"ltx: no snapshot among the cell's files\");\n const chain = opened.slice(snapshotAt);\n /** Files the newest snapshot covers (left by an interrupted compaction): not read. */\n const superseded = opened.slice(0, snapshotAt).map((f) => f.path);\n for (let i = 1; i < chain.length; i++)\n if (chain[i].header.minTXID !== chain[i - 1].header.maxTXID + 1n)\n throw new Error(`ltx: gap before ${chain[i].path}`);\n let newest = chain[chain.length - 1].header;\n const owner = new Map<number, LtxPages>();\n for (const f of chain) for (const pgno of f.index.keys()) owner.set(pgno, f);\n const cell: PagedCell = {\n pageSize: newest.pageSize,\n pageCount: newest.commit,\n maxTXID: newest.maxTXID,\n files: chain,\n superseded,\n source: (pgno) => owner.get(pgno)?.path,\n async readPage(pgno) {\n const page = pgno <= cell.pageCount ? await owner.get(pgno)?.readPage(pgno) : undefined;\n return page ?? new Uint8Array(cell.pageSize);\n },\n async readRun(from, count) {\n const byFile = new Map<LtxPages, number[]>();\n const out = new Map<number, Uint8Array>();\n for (let p = from; p < from + count && p <= cell.pageCount; p++) {\n const f = owner.get(p);\n if (!f) out.set(p, new Uint8Array(cell.pageSize));\n else byFile.set(f, [...(byFile.get(f) ?? []), p]);\n }\n for (const [f, pgnos] of byFile) for (const [p, d] of await f.readPages(pgnos)) out.set(p, d);\n return out;\n },\n async append(path, known) {\n const f = await openLtxPages(files, path, known);\n if (f.header.minTXID !== cell.maxTXID + 1n)\n throw new Error(`ltx: ${path} does not follow TXID ${cell.maxTXID}`);\n chain.push(f);\n for (const pgno of f.index.keys()) owner.set(pgno, f);\n newest = f.header;\n cell.pageCount = newest.commit;\n cell.maxTXID = newest.maxTXID;\n for (const [pgno] of owner) if (pgno > cell.pageCount) owner.delete(pgno);\n },\n };\n return cell;\n}\n\n/**\n * An LTX file produced page by page, as celld writes it (block format: size-prefixed LZ4 page\n * blocks, page index, trailer, CRC-64/ISO over the uncompressed pages): the bytes come out as an\n * async stream while `pages` is consumed, so a writer holds one page at a time plus the index\n * (a few bytes per page), never the database.\n */\nexport async function* encodeLtxStream(\n header: LtxHeader,\n pages: AsyncIterable<[number, Uint8Array]>,\n postApplyChecksum = 0n,\n /** Filled while encoding: the file's page index (what `openLtxPages` would read back). */\n written?: { index: Map<number, [number, number]> },\n): AsyncGenerator<Uint8Array> {\n // Coalesced into 256 KiB chunks: a writer pays per call (an OPFS SyncAccessHandle write, a\n // stream write), and a page makes three small pieces.\n yield* coalesce(encodePieces(header, pages, postApplyChecksum, written), 256 * 1024);\n}\n\nasync function* coalesce(src: AsyncIterable<Uint8Array>, size: number): AsyncGenerator<Uint8Array> {\n let buf = new Uint8Array(size);\n let n = 0;\n for await (const piece of src) {\n if (piece.length >= size) {\n if (n) yield buf.slice(0, n), (n = 0);\n yield piece;\n continue;\n }\n if (n + piece.length > size) {\n yield buf.slice(0, n);\n buf = new Uint8Array(size);\n n = 0;\n }\n buf.set(piece, n);\n n += piece.length;\n }\n if (n) yield buf.slice(0, n);\n}\n\nasync function* encodePieces(\n header: LtxHeader,\n pages: AsyncIterable<[number, Uint8Array]>,\n postApplyChecksum: bigint,\n written?: { index: Map<number, [number, number]> },\n): AsyncGenerator<Uint8Array> {\n const crc = new Crc64();\n const head = new Uint8Array(HEADER_SIZE);\n const v = new DataView(head.buffer);\n head.set(new TextEncoder().encode(\"LTX1\"), 0);\n const flags =\n header.flags ?? (header.preApplyChecksum === 0n && postApplyChecksum === 0n ? 2 : 0);\n v.setUint32(4, flags);\n v.setUint32(8, header.pageSize);\n v.setUint32(12, header.commit);\n v.setBigUint64(16, header.minTXID);\n v.setBigUint64(24, header.maxTXID);\n v.setBigInt64(32, BigInt(header.timestamp));\n v.setBigUint64(40, header.preApplyChecksum);\n v.setBigUint64(72, header.nodeID ?? 0n);\n crc.update(head);\n yield head;\n const index: number[] = [];\n const uvarint = (n: number) => {\n while (n >= 0x80) index.push((n & 0x7f) | 0x80), (n = Math.floor(n / 128));\n index.push(n);\n };\n let offset = HEADER_SIZE;\n const lock = lockPgno(header.pageSize);\n let last = 0;\n for await (const [pgno, data] of pages) {\n if (pgno === lock) continue;\n if (pgno <= last) throw new Error(\"ltx: pages must come in ascending order\");\n last = pgno;\n const compressed = lz4Compress(data);\n const ph = new Uint8Array(10);\n const pv = new DataView(ph.buffer);\n pv.setUint32(0, pgno);\n pv.setUint16(4, PAGE_HEADER_FLAG_SIZE);\n pv.setUint32(6, compressed.length);\n crc.update(ph).update(data); // the checksum covers uncompressed pages (encodeLtx's `feed`)\n uvarint(pgno), uvarint(offset), uvarint(10 + compressed.length);\n written?.index.set(pgno, [offset, 10 + compressed.length]);\n offset += 10 + compressed.length;\n yield ph;\n yield compressed;\n }\n const end = new Uint8Array(6);\n uvarint(0);\n const idx = Uint8Array.from(index);\n const tail = new Uint8Array(16);\n const tv = new DataView(tail.buffer);\n tv.setBigUint64(0, BigInt(idx.length));\n tv.setBigUint64(8, postApplyChecksum);\n crc.update(end).update(idx).update(tail);\n const sum = new Uint8Array(8);\n new DataView(sum.buffer).setBigUint64(0, CHECKSUM_FLAG | crc.digest());\n yield end;\n yield idx;\n yield tail;\n yield sum;\n}\n\n/**\n * Folds a cell's files into one snapshot (TXID 1..maxTXID) written to `files` at `path`, page by\n * page: each page is read by range from the file that holds it and streamed into the new file,\n * so memory stays at one page (plus the index), whatever the database size. The caller removes\n * the files it replaces once this resolves.\n */\nexport async function compactPagedCellTo(\n cell: PagedCell,\n files: FilesApi,\n path: string,\n timestamp = Date.now(),\n): Promise<void> {\n // In runs of 256 pages: one range read per file a run touches (not one read per page).\n async function* pages(): AsyncGenerator<[number, Uint8Array]> {\n for (let from = 1; from <= cell.pageCount; from += 256) {\n const run = await cell.readRun(from, 256);\n for (let pgno = from; pgno < from + 256 && pgno <= cell.pageCount; pgno++)\n yield [pgno, run.get(pgno) ?? new Uint8Array(cell.pageSize)];\n }\n }\n await files.write(\n path,\n encodeLtxStream(\n {\n pageSize: cell.pageSize,\n commit: cell.pageCount,\n minTXID: 1n,\n maxTXID: cell.maxTXID,\n timestamp,\n preApplyChecksum: 0n,\n },\n pages(),\n ),\n );\n}\n\n/** The compacted snapshot as bytes (small cells, tests); compactPagedCellTo streams it. */\nexport async function compactPagedCell(\n cell: PagedCell,\n timestamp = Date.now(),\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n async function* pages(): AsyncGenerator<[number, Uint8Array]> {\n for (let pgno = 1; pgno <= cell.pageCount; pgno++) yield [pgno, await cell.readPage(pgno)];\n }\n for await (const c of encodeLtxStream(\n {\n pageSize: cell.pageSize,\n commit: cell.pageCount,\n minTXID: 1n,\n maxTXID: cell.maxTXID,\n timestamp,\n preApplyChecksum: 0n,\n },\n pages(),\n ))\n chunks.push(c);\n const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let o = 0;\n for (const c of chunks) out.set(c, o), (o += c.length);\n return out;\n}\n"]}
|
|
@@ -1,35 +1,48 @@
|
|
|
1
|
-
/// <reference lib="webworker" />
|
|
2
|
-
/**
|
|
3
|
-
* The LTX store as a worker of its own (spawned by a shard worker that runs cells on the LTX
|
|
4
|
-
* VFS): cells' LTX files in an OPFS directory, in celld's layout. The shard connects with
|
|
5
|
-
* `{ op: "init", sab, dir, compactAfter }`, then sends the VFS's requests; answers go into
|
|
6
|
-
* the shared buffer.
|
|
7
|
-
*/
|
|
8
1
|
import { BrowserFilesApi } from "@statewalker/webrun-files-browser";
|
|
9
2
|
import { MemFilesApi } from "@statewalker/webrun-files-mem";
|
|
3
|
+
import { rpcFilesClient } from "./files-rpc.js";
|
|
10
4
|
import { ltxCellStore } from "./ltx-page-server.js";
|
|
11
5
|
import { opfsSyncFiles } from "./opfs-sync-files.js";
|
|
6
|
+
async function open(m) {
|
|
7
|
+
const f = m.files ?? "opfs-sync";
|
|
8
|
+
if (f === "memory")
|
|
9
|
+
return { files: new MemFilesApi() };
|
|
10
|
+
if (typeof f === "object" && "port" in f)
|
|
11
|
+
// Free space of a FilesApi elsewhere is unknown here: compactions are not held back.
|
|
12
|
+
return { files: rpcFilesClient(f.port), room: async () => undefined };
|
|
13
|
+
if (typeof f === "object" && "module" in f) {
|
|
14
|
+
const mod = (await import(/* @vite-ignore */ f.module));
|
|
15
|
+
const create = mod.createFilesApi ?? mod.default;
|
|
16
|
+
if (typeof create !== "function")
|
|
17
|
+
throw new Error(`ltx store: ${f.module} exports no createFilesApi (or default) function`);
|
|
18
|
+
const room = mod.room;
|
|
19
|
+
return {
|
|
20
|
+
files: await create(f.args),
|
|
21
|
+
room: room ? () => room(f.args) : async () => undefined,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const root = await navigator.storage.getDirectory();
|
|
25
|
+
const dir = await root.getDirectoryHandle(m.dir, { create: true });
|
|
26
|
+
return { files: f === "opfs" ? new BrowserFilesApi({ rootHandle: dir }) : opfsSyncFiles(dir) };
|
|
27
|
+
}
|
|
12
28
|
let store;
|
|
13
29
|
let ready;
|
|
14
30
|
self.onmessage = (e) => {
|
|
15
31
|
const m = e.data;
|
|
16
32
|
if (m?.op === "init") {
|
|
17
33
|
ready = (async () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
})();
|
|
31
|
-
store = ltxCellStore(files, m.sab, { compactAfter: m.compactAfter, lockScope: m.dir });
|
|
32
|
-
postMessage({ op: "ready" });
|
|
34
|
+
try {
|
|
35
|
+
const { files, room } = await open(m);
|
|
36
|
+
store = ltxCellStore(files, m.sab, {
|
|
37
|
+
compactAfter: m.compactAfter,
|
|
38
|
+
lockScope: m.dir,
|
|
39
|
+
room,
|
|
40
|
+
});
|
|
41
|
+
postMessage({ op: "ready" });
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
postMessage({ op: "failed", error: String(err?.message ?? err) });
|
|
45
|
+
}
|
|
33
46
|
})();
|
|
34
47
|
return;
|
|
35
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ltx-store-worker.js","sourceRoot":"","sources":["../../src/ltx/ltx-store-worker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ltx-store-worker.js","sourceRoot":"","sources":["../../src/ltx/ltx-store-worker.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAqB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,KAAK,UAAU,IAAI,CACjB,CAAe;IAEf,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,WAAW,CAAC;IACjC,IAAI,CAAC,KAAK,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,WAAW,EAAE,EAAE,CAAC;IACxD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,IAAI,CAAC;QACtC,qFAAqF;QACrF,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;IACxE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAIrD,CAAC;QACF,MAAM,MAAM,GAAG,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,OAAO,CAAC;QACjD,IAAI,OAAO,MAAM,KAAK,UAAU;YAC9B,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,MAAM,kDAAkD,CAAC,CAAC;QAC5F,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,OAAO;YACL,KAAK,EAAE,MAAM,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAC3B,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,SAAS;SACxD,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IACpD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,OAAO,EAAE,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;AACjG,CAAC;AAED,IAAI,KAAkD,CAAC;AACvD,IAAI,KAAgC,CAAC;AACrC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAe,EAAE,EAAE;IACnC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QACrB,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE;YAClB,IAAI,CAAC;gBACH,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,CAAiB,CAAC,CAAC;gBACtD,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE;oBACjC,YAAY,EAAE,CAAC,CAAC,YAAY;oBAC5B,SAAS,EAAE,CAAC,CAAC,GAAG;oBAChB,IAAI;iBACL,CAAC,CAAC;gBACH,WAAW,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YAC/B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,WAAW,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/E,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO;IACT,CAAC;IACD,KAAK,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC,CAAC","sourcesContent":["/// <reference lib=\"webworker\" />\n/**\n * The LTX store as a worker of its own (spawned by a shard worker that runs cells on the LTX\n * VFS): cells' LTX files on a FilesApi, in celld's layout. The shard connects with\n * `{ op: \"init\", sab, dir, compactAfter, files, … }` (an `LtxStoreInit`), then sends the VFS's\n * requests; answers go into the shared buffer.\n */\nimport type { FilesApi } from \"@statewalker/webrun-files\";\nimport { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { MemFilesApi } from \"@statewalker/webrun-files-mem\";\nimport { rpcFilesClient } from \"./files-rpc.js\";\nimport { type LtxStoreInit, ltxCellStore } from \"./ltx-page-server.js\";\nimport { opfsSyncFiles } from \"./opfs-sync-files.js\";\n\nasync function open(\n m: LtxStoreInit,\n): Promise<{ files: FilesApi; room?: () => Promise<number | undefined> }> {\n const f = m.files ?? \"opfs-sync\";\n if (f === \"memory\") return { files: new MemFilesApi() };\n if (typeof f === \"object\" && \"port\" in f)\n // Free space of a FilesApi elsewhere is unknown here: compactions are not held back.\n return { files: rpcFilesClient(f.port), room: async () => undefined };\n if (typeof f === \"object\" && \"module\" in f) {\n const mod = (await import(/* @vite-ignore */ f.module)) as {\n default?: (args: unknown) => FilesApi | Promise<FilesApi>;\n createFilesApi?: (args: unknown) => FilesApi | Promise<FilesApi>;\n room?: (args: unknown) => Promise<number | undefined>;\n };\n const create = mod.createFilesApi ?? mod.default;\n if (typeof create !== \"function\")\n throw new Error(`ltx store: ${f.module} exports no createFilesApi (or default) function`);\n const room = mod.room;\n return {\n files: await create(f.args),\n room: room ? () => room(f.args) : async () => undefined,\n };\n }\n const root = await navigator.storage.getDirectory();\n const dir = await root.getDirectoryHandle(m.dir, { create: true });\n return { files: f === \"opfs\" ? new BrowserFilesApi({ rootHandle: dir }) : opfsSyncFiles(dir) };\n}\n\nlet store: ReturnType<typeof ltxCellStore> | undefined;\nlet ready: Promise<void> | undefined;\nself.onmessage = (e: MessageEvent) => {\n const m = e.data;\n if (m?.op === \"init\") {\n ready = (async () => {\n try {\n const { files, room } = await open(m as LtxStoreInit);\n store = ltxCellStore(files, m.sab, {\n compactAfter: m.compactAfter,\n lockScope: m.dir,\n room,\n });\n postMessage({ op: \"ready\" });\n } catch (err) {\n postMessage({ op: \"failed\", error: String((err as Error)?.message ?? err) });\n }\n })();\n return;\n }\n void ready?.then(() => store?.handle(m));\n};\n"]}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { WasmSqliteDriver } from "../adapters/wasm-sqlite.js";
|
|
1
2
|
import type { AssetFiles } from "../bindings/assets.js";
|
|
2
3
|
import type { WorkersAiOptions } from "../bindings/workers-ai.js";
|
|
3
4
|
import { type ObjectStore } from "../bucket/object-store.js";
|
|
4
5
|
import type { CellRuntimeOptions } from "../core/runtime.js";
|
|
6
|
+
import type { LtxStoreFiles } from "../ltx/ltx-page-server.js";
|
|
5
7
|
import { populatesProcessEnv, processEnvOf, type WranglerConfig } from "./wrangler.js";
|
|
6
8
|
export { populatesProcessEnv, processEnvOf };
|
|
7
9
|
/**
|
|
@@ -59,10 +61,24 @@ export type BrowserBucket = {
|
|
|
59
61
|
leaseTtlMs?: number;
|
|
60
62
|
compactAfter?: number;
|
|
61
63
|
/**
|
|
62
|
-
* The cells' FilesApi in the store worker
|
|
63
|
-
* `opfs-sync`), OPFS
|
|
64
|
+
* The cells' FilesApi in the store worker. A preset on OPFS directory `ltx`: synchronous
|
|
65
|
+
* handles (default, `opfs-sync`), OPFS's asynchronous API (`opfs`), or memory (nothing
|
|
66
|
+
* kept). Or the app's own FilesApi, opened before cellb starts: `{ port }` from
|
|
67
|
+
* `filesApiPort(files)` (served where the app opened it), or `{ module, args }` (built in
|
|
68
|
+
* the store worker). `ltx` then names the storage (the scope of the cells' Web Locks).
|
|
69
|
+
* A port is transferred to the store worker, so it serves one runtime: give each
|
|
70
|
+
* `browserProjectRuntime` a new `filesApiPort`.
|
|
64
71
|
*/
|
|
65
|
-
files?:
|
|
72
|
+
files?: LtxStoreFiles;
|
|
73
|
+
/**
|
|
74
|
+
* A store already running elsewhere (`serveLtxStore(files)`, on the page): no store
|
|
75
|
+
* worker; the VFS sends its reads and commits there. `files` is then ignored. One store
|
|
76
|
+
* per runtime; the app calls its `close()` when the runtime ends.
|
|
77
|
+
*/
|
|
78
|
+
ltxStore?: {
|
|
79
|
+
sab: SharedArrayBuffer;
|
|
80
|
+
port: MessagePort;
|
|
81
|
+
};
|
|
66
82
|
} | {
|
|
67
83
|
store: ObjectStore;
|
|
68
84
|
node: string;
|
|
@@ -110,6 +126,19 @@ export interface BrowserProjectOptions {
|
|
|
110
126
|
/** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */
|
|
111
127
|
ai?: WorkersAiOptions;
|
|
112
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Cells on the LTX VFS: each cell is a SQLite database whose main file is its LTX files, read
|
|
131
|
+
* page by page (src/adapters/ltx-vfs.ts) from a store: a store worker of this worker's own (on
|
|
132
|
+
* OPFS, memory, or the app's FilesApi through a port or a module), or a store the app runs
|
|
133
|
+
* elsewhere (`ltxStore`).
|
|
134
|
+
*/
|
|
135
|
+
export declare function ltxOpener(sqlite3: unknown, dir: string, compactAfter?: number, files?: LtxStoreFiles, ltxStore?: {
|
|
136
|
+
sab: SharedArrayBuffer;
|
|
137
|
+
port: MessagePort;
|
|
138
|
+
}): Promise<((cellKey: string) => WasmSqliteDriver) & {
|
|
139
|
+
release: () => void;
|
|
140
|
+
reserve: (n: number) => Promise<number>;
|
|
141
|
+
}>;
|
|
113
142
|
/**
|
|
114
143
|
* A project's runtime in this worker: installs the Workers globals, imports the code and
|
|
115
144
|
* builds its Worker Loader; `close()` also releases the node's bucket lease.
|
|
@@ -28,21 +28,50 @@ async function bucketStore(b) {
|
|
|
28
28
|
return filesApiObjectStore(new BrowserFilesApi({ rootHandle: await root.getDirectoryHandle(b.opfs, { create: true }) }), "");
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Cells on the LTX VFS:
|
|
32
|
-
*
|
|
31
|
+
* Cells on the LTX VFS: each cell is a SQLite database whose main file is its LTX files, read
|
|
32
|
+
* page by page (src/adapters/ltx-vfs.ts) from a store: a store worker of this worker's own (on
|
|
33
|
+
* OPFS, memory, or the app's FilesApi through a port or a module), or a store the app runs
|
|
34
|
+
* elsewhere (`ltxStore`).
|
|
33
35
|
*/
|
|
34
|
-
async function ltxOpener(sqlite3, dir, compactAfter, files) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
export async function ltxOpener(sqlite3, dir, compactAfter, files, ltxStore) {
|
|
37
|
+
let sab;
|
|
38
|
+
let post;
|
|
39
|
+
let release;
|
|
40
|
+
if (ltxStore) {
|
|
41
|
+
// The store runs elsewhere (serveLtxStore): only the VFS here.
|
|
42
|
+
sab = ltxStore.sab;
|
|
43
|
+
const port = ltxStore.port;
|
|
44
|
+
post = (m) => port.postMessage(m);
|
|
45
|
+
release = () => port.close();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const store = new Worker(new URL("../ltx/ltx-store-worker.js", import.meta.url) /* `.js` in dist/ (scripts/build.mjs) */, { type: "module" });
|
|
49
|
+
sab = new SharedArrayBuffer(8 + 16 * 65536); // room for a read-ahead run of 64 KiB pages
|
|
50
|
+
// Wait until the store worker runs before any synchronous call: a nested worker is started
|
|
51
|
+
// (its script fetched) through this worker's event loop, which Atomics.wait would block.
|
|
52
|
+
const ready = new Promise((resolve, reject) => {
|
|
53
|
+
store.addEventListener("message", (e) => {
|
|
54
|
+
if (e.data?.op === "ready")
|
|
55
|
+
resolve();
|
|
56
|
+
else if (e.data?.op === "failed")
|
|
57
|
+
reject(new Error(`ltx store worker: ${e.data.error}`));
|
|
58
|
+
});
|
|
59
|
+
store.addEventListener("error", (e) => reject(new Error(`ltx store worker: ${e.message}`)));
|
|
60
|
+
});
|
|
61
|
+
// A port to the app's FilesApi moves on to the store worker.
|
|
62
|
+
const transfer = files && typeof files === "object" && "port" in files ? [files.port] : [];
|
|
63
|
+
try {
|
|
64
|
+
store.postMessage({ op: "init", sab, dir, compactAfter, files }, transfer);
|
|
65
|
+
await ready;
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
store.terminate(); // a store worker that did not start is not left behind
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
post = (m) => store.postMessage(m);
|
|
72
|
+
release = () => store.terminate();
|
|
73
|
+
}
|
|
74
|
+
const { name } = installLtxVfs(sqlite3, { sab, post });
|
|
46
75
|
const s3 = sqlite3;
|
|
47
76
|
const open = (cellKey) => {
|
|
48
77
|
const db = new s3.oo1.DB({ filename: cellKey, vfs: name, flags: "c" });
|
|
@@ -52,9 +81,7 @@ async function ltxOpener(sqlite3, dir, compactAfter, files) {
|
|
|
52
81
|
return new WasmSqliteDriver(db, undefined, undefined, sqlite3.capi);
|
|
53
82
|
};
|
|
54
83
|
return Object.assign(open, {
|
|
55
|
-
release
|
|
56
|
-
store.terminate();
|
|
57
|
-
},
|
|
84
|
+
release,
|
|
58
85
|
reserve: async (n) => n,
|
|
59
86
|
});
|
|
60
87
|
}
|
|
@@ -128,7 +155,7 @@ export async function browserProjectRuntime(opts) {
|
|
|
128
155
|
const site = "site" in opts.code ? opts.code.site : undefined;
|
|
129
156
|
// With an IndexedDB bucket, cells live in memory and in the bucket's logs (no OPFS pool).
|
|
130
157
|
const openSql = opts.bucket && "ltx" in opts.bucket
|
|
131
|
-
? await ltxOpener(opts.sqlite3, opts.bucket.ltx, opts.bucket.compactAfter, opts.bucket.files)
|
|
158
|
+
? await ltxOpener(opts.sqlite3, opts.bucket.ltx, opts.bucket.compactAfter, opts.bucket.files, opts.bucket.ltxStore)
|
|
132
159
|
: opts.bucket && "idb" in opts.bucket
|
|
133
160
|
? Object.assign(wasmMemoryOpener(opts.sqlite3), {
|
|
134
161
|
release() { },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/project/browser-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { installLtxVfs } from \"../adapters/ltx-vfs.js\";\nimport {\n sahpoolOpener,\n tuneCellConnection,\n WasmSqliteDriver,\n wasmMemoryOpener,\n} from \"../adapters/wasm-sqlite.js\";\nimport type { AssetFiles } from \"../bindings/assets.js\";\nimport type { WorkersAiOptions } from \"../bindings/workers-ai.js\";\nimport { celldBucket } from \"../bucket/celld-cells.js\";\nimport { idbObjectStore } from \"../bucket/idb-object-store.js\";\nimport { filesApiObjectStore, type ObjectStore } from \"../bucket/object-store.js\";\nimport { s3ObjectStore } from \"../bucket/s3-object-store.js\";\nimport type { CellRuntimeOptions, WorkerModule } from \"../core/runtime.js\";\nimport { browserIsolatedLoader } from \"../isolate/browser.js\";\nimport { installAsyncContext } from \"../node-compat/async_hooks.js\";\nimport { installNodeGlobals } from \"../node-compat/install.js\";\nimport { browserModuleLoader } from \"./browser-modules.js\";\nimport * as workersModule from \"./cloudflare-workers.js\";\nimport { siteModuleLoader, workersHostRegistry } from \"./site-loader.js\";\nimport { type WorkerScope, workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n loadTimeEnv,\n populatesProcessEnv,\n processEnvOf,\n type WranglerConfig,\n} from \"./wrangler.js\";\n\nexport { populatesProcessEnv, processEnvOf };\n\n/**\n * Where a browser-hosted project keeps its cells when they must outlive the page or move to\n * other nodes: a celld fleet bucket. Cells, facets and alarms are then exactly celld's\n * (ownership in `own.json`, LTX logs, wake index) and R2 objects live in it too, so the same\n * cells can be served by this browser, by other browsers and by celld nodes, in turn.\n *\n * - `s3`: an S3-compatible bucket, reached directly (the bucket must allow CORS for the page's\n * origin: methods GET/PUT/DELETE/HEAD, request headers `authorization`, `content-type`,\n * `x-amz-*`, `if-match`, `if-none-match`; exposed headers `etag`, `last-modified`,\n * `x-amz-meta-celld-r2`) or through a same-origin proxy (`endpoint` = the proxy,\n * `signAs` = the real endpoint: SigV4 signs the real host and path).\n * - `opfs`: a bucket in this origin's OPFS — persistence without a server. Conditional writes\n * are atomic only within one writer, so one tab or worker at a time should own its cells.\n * - `store`: any ObjectStore.\n */\nexport type BrowserBucket =\n | {\n s3: {\n endpoint: string;\n signAs?: string;\n bucket: string;\n prefix?: string;\n region?: string;\n accessKeyId: string;\n secretAccessKey: string;\n };\n node: string;\n leaseTtlMs?: number;\n }\n | { opfs: string; node: string; leaseTtlMs?: number }\n /**\n * `idb`: a bucket in this origin's IndexedDB (atomic conditional writes across tabs and\n * workers). Cells then run SQLite in memory and persist through the bucket's page-level logs:\n * no OPFS pool, so any number of workers can serve cells at once.\n */\n | { idb: string; node: string; leaseTtlMs?: number }\n /**\n * `ltx`: cells as celld keeps them, LTX files (a snapshot and one file per commit) in an OPFS\n * directory, read page by page (a SQLite VFS over a store worker): no OPFS pool, and a\n * cell's memory is its page cache, not its database. A cell is folded into one snapshot\n * (streamed) past `compactAfter` files (default 64), or once the files after its snapshot hold\n * more than half of it. See docs/browser-host.md.\n */\n | {\n ltx: string;\n node: string;\n leaseTtlMs?: number;\n compactAfter?: number;\n /**\n * The cells' FilesApi in the store worker: OPFS through synchronous handles (default,\n * `opfs-sync`), OPFS through its asynchronous API (`opfs`), or memory (nothing kept).\n */\n files?: \"opfs\" | \"opfs-sync\" | \"memory\";\n }\n | { store: ObjectStore; node: string; leaseTtlMs?: number };\n\nexport interface BrowserProjectOptions {\n config: WranglerConfig;\n /**\n * The project's Worker code, imported in this realm once its Workers globals (and with\n * nodejs_compat `Buffer` and `process`) are installed:\n * - `bundle`: one ES module built for browsers (`bundleWorkerForBrowser`), whose\n * `cloudflare:workers` is `PROJECT_WORKERS_MODULE_SHIM` and whose Workers globals read\n * `globalThis.__cellsGlobals`\n * (`null`: the project has no `main`). Worker Loader code becomes Blob-URL modules.\n * - `site`: the base URL of the project's site (`createProjectSite`, hosted by\n * webrun-site-host). `main` and Worker Loader code are imported from it.\n */\n code: { bundle: string | null } | { site: string };\n /**\n * A Dedicated Worker script that serves one loaded Worker (`serveIsolate`): Worker Loader\n * code then runs isolated, one Dedicated Worker per loaded Worker, as celld's isolates.\n * The package ships one: `@statewalker/cellb/isolate-worker`. A function instead starts the\n * Dedicated Worker itself (`() => new Worker(new URL(…, import.meta.url), { type: \"module\" })`,\n * a form bundlers follow).\n */\n isolateScript?: URL | (() => Worker);\n /** An initialized SQLite WASM module (`@sqlite.org/sqlite-wasm`). */\n sqlite3: unknown;\n /** OPFS sahpool name for this host's SQLite files (one pool per worker). */\n pool: string;\n /** OPFS directory for the project's FilesApi (Workers' fs-like bindings, R2 without bucket). */\n filesDir: string;\n assetFiles?: AssetFiles;\n bucket?: BrowserBucket;\n /**\n * Cells this runtime does not host: where to send their events (a `Send` over a MessagePort\n * to the runtime that hosts them, `linkOverPort`), or undefined to host the cell here. With\n * one runtime per worker and `shardOf` as the placement, cells run in parallel threads.\n */\n route?: CellRuntimeOptions[\"route\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */\n ai?: WorkersAiOptions;\n}\n\nasync function bucketStore(b: BrowserBucket): Promise<ObjectStore> {\n if (\"store\" in b) return b.store;\n if (\"s3\" in b) return s3ObjectStore({ region: \"us-east-1\", ...b.s3 });\n if (\"idb\" in b) return idbObjectStore(b.idb);\n if (\"ltx\" in b) throw new Error(\"an ltx directory is cell storage, not a bucket\");\n const root = await navigator.storage.getDirectory();\n return filesApiObjectStore(\n new BrowserFilesApi({ rootHandle: await root.getDirectoryHandle(b.opfs, { create: true }) }),\n \"\",\n );\n}\n\n/**\n * Cells on the LTX VFS: a store worker owns the OPFS directory; each cell is a SQLite database\n * whose main file is its LTX files, read page by page (src/adapters/ltx-vfs.ts).\n */\nasync function ltxOpener(sqlite3: unknown, dir: string, compactAfter?: number, files?: string) {\n const store = new Worker(\n new URL(\"../ltx/ltx-store-worker.ts\", import.meta.url) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n const sab = new SharedArrayBuffer(8 + 16 * 65536); // room for a read-ahead run of 64 KiB pages\n // Wait until the store worker runs before any synchronous call: a nested worker is started\n // (its script fetched) through this worker's event loop, which Atomics.wait would block.\n const ready = new Promise<void>((resolve, reject) => {\n store.addEventListener(\"message\", (e) => e.data?.op === \"ready\" && resolve(), { once: false });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files });\n await ready;\n const { name } = installLtxVfs(sqlite3, { sab, post: (m) => store.postMessage(m) });\n const s3 = sqlite3 as { oo1: { DB: new (o: Record<string, unknown>) => any } };\n const open = (cellKey: string) => {\n const db = new s3.oo1.DB({ filename: cellKey, vfs: name, flags: \"c\" });\n tuneCellConnection(sqlite3, db);\n db.exec(\"PRAGMA journal_mode=MEMORY; PRAGMA synchronous=FULL;\");\n // SQLite's C API for inTransaction() only (no page hook or session capture on this VFS).\n return new WasmSqliteDriver(db, undefined, undefined, (sqlite3 as { capi: never }).capi);\n };\n return Object.assign(open, {\n release() {\n store.terminate();\n },\n reserve: async (n: number) => n,\n });\n}\n\n/** Installs the Workers globals the code reads, then imports its `main`. */\nasync function importWorkerCode(\n config: WranglerConfig,\n code: BrowserProjectOptions[\"code\"],\n scope: WorkerScope,\n): Promise<WorkerModule> {\n const flags = config.compatibility_flags ?? [];\n const nodeCompat = flags.some((f) => f.startsWith(\"nodejs_compat\"));\n if (nodeCompat) {\n installNodeGlobals();\n // node:* for bundles built with cellbHostModule (another bundler than bundleWorkerForBrowser);\n // loaded after installNodeGlobals(), as the npm `util` polyfill reads `process`.\n (globalThis as Record<string, unknown>).__cellsNodeModules = (\n await import(\"../node-compat/browser-registry.js\")\n ).nodeRegistryEntries;\n if (populatesProcessEnv(config)) {\n const env = processEnvOf(config);\n // The bundle's own `process` reads it when evaluated; a site's modules use this realm's.\n (globalThis as Record<string, unknown>).__cellsProcessEnv = env;\n Object.assign((globalThis as { process: { env: Record<string, string> } }).process.env, env);\n }\n // node:async_hooks: continuations carry their AsyncLocalStorage stores (with AsyncContext\n // the engine does, and this installs nothing). The code's awaits are lowered so that they go\n // through them: by bundleWorkerForBrowser for a bundle, by createProjectSite (nodeCompat) for\n // a site's modules.\n installAsyncContext();\n }\n const globals = {\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocketPair: flags.includes(\"websocket_standard_binary_type\")\n ? workersGlobals.StandardWebSocketPair\n : workersGlobals.WebSocketPair,\n };\n if (\"site\" in code) {\n workersHostRegistry({\n workersModule,\n projectWorkersModule: {\n ...workersModule,\n env: scope.env,\n exports: scope.exports,\n waitUntil: scope.waitUntil,\n },\n loadedPrefix: `${code.site}loaded/`,\n emailModule: await import(\"./cloudflare-email.js\"),\n ...globals,\n // Loaded on demand, after installNodeGlobals(): the npm `util` polyfill reads `process`\n // when it is imported.\n node: nodeCompat\n ? (await import(\"../node-compat/browser-registry.js\")).nodeRegistryEntries\n : undefined,\n });\n return config.main\n ? await import(/* @vite-ignore */ `${code.site}modules/~/${config.main}`)\n : { default: {} };\n }\n const g = globalThis as Record<string, unknown>;\n g.__cellsWorkersModule = workersModule;\n g.__cellsProjectScope = scope; // `env` and `exports` of the bundle's cloudflare:workers\n g.__cellsGlobals = globals;\n return code.bundle\n ? await import(\n /* @vite-ignore */ URL.createObjectURL(new Blob([code.bundle], { type: \"text/javascript\" }))\n )\n : { default: {} };\n}\n\n/**\n * A project's runtime in this worker: installs the Workers globals, imports the code and\n * builds its Worker Loader; `close()` also releases the node's bucket lease.\n */\nexport async function browserProjectRuntime(opts: BrowserProjectOptions) {\n const scope = workerScope(loadTimeEnv(opts.config, opts.ai));\n const module = await importWorkerCode(opts.config, opts.code, scope);\n const site = \"site\" in opts.code ? opts.code.site : undefined;\n // With an IndexedDB bucket, cells live in memory and in the bucket's logs (no OPFS pool).\n const openSql =\n opts.bucket && \"ltx\" in opts.bucket\n ? await ltxOpener(opts.sqlite3, opts.bucket.ltx, opts.bucket.compactAfter, opts.bucket.files)\n : opts.bucket && \"idb\" in opts.bucket\n ? Object.assign(wasmMemoryOpener(opts.sqlite3 as never), {\n release() {},\n reserve: async (n: number) => n,\n })\n : await sahpoolOpener(opts.sqlite3 as never, {\n name: opts.pool,\n initialCapacity: 64, // grows on demand (sahpoolOpener)\n });\n const root = await navigator.storage.getDirectory();\n const files = new BrowserFilesApi({\n rootHandle: await root.getDirectoryHandle(opts.filesDir, { create: true }),\n });\n // An `ltx` directory is the cells' own storage (the VFS), not a fleet bucket.\n const store = opts.bucket && !(\"ltx\" in opts.bucket) ? await bucketStore(opts.bucket) : undefined;\n const shared =\n opts.bucket && store\n ? celldBucket(store, { node: opts.bucket.node, leaseTtlMs: opts.bucket.leaseTtlMs })\n : undefined;\n const { runtime, unsupported } = createProjectRuntime(opts.config, module, {\n openSql,\n files,\n assetFiles: opts.assetFiles,\n loadModules: site ? siteModuleLoader(site) : browserModuleLoader(),\n isolatedModules: opts.isolateScript\n ? browserIsolatedLoader({\n isolateScript: opts.isolateScript,\n siteBaseUrl: site,\n storagePrefix: `${opts.pool}-iso`,\n storage: () => shared, // facets of loaded code are logged like the root's own\n })\n : undefined,\n storage: shared, // R2 objects in the fleet bucket too, as celld keeps them\n route: opts.route,\n ai: opts.ai,\n });\n scope.bind(runtime);\n return {\n runtime,\n unsupported,\n bucket: shared,\n close: async () => {\n await runtime.close();\n openSql.release(); // the pool's files, for the next worker that opens it\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/project/browser-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAoB,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,aAAa,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAoB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,mBAAmB,EACnB,YAAY,GAEb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAC;AA4G7C,KAAK,UAAU,WAAW,CAAC,CAAgB;IACzC,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IACjC,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IACpD,OAAO,mBAAmB,CACxB,IAAI,eAAe,CAAC,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAC5F,EAAE,CACH,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAgB,EAChB,GAAW,EACX,YAAqB,EACrB,KAAqB,EACrB,QAAwD;IAExD,IAAI,GAAsB,CAAC;IAC3B,IAAI,IAA0B,CAAC;IAC/B,IAAI,OAAmB,CAAC;IACxB,IAAI,QAAQ,EAAE,CAAC;QACb,+DAA+D;QAC/D,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC;QACnB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAClC,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,IAAI,MAAM,CACtB,IAAI,GAAG,CACL,4BAA4B,EAC5B,OAAO,IAAI,CAAC,GAAG,CAChB,CAAC,wCAAwC,EAC1C,EAAE,IAAI,EAAE,QAAQ,EAAE,CACnB,CAAC;QACF,GAAG,GAAG,IAAI,iBAAiB,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,4CAA4C;QACzF,2FAA2F;QAC3F,yFAAyF;QACzF,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClD,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;gBACtC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,OAAO;oBAAE,OAAO,EAAE,CAAC;qBACjC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,QAAQ;oBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,KAAe,EAAE,CAAC,CAAC,CAAC;YACrE,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9F,CAAC,CAAC,CAAC;QACH,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,IAAI,CAAC;YACH,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC3E,MAAM,KAAK,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,uDAAuD;YAC1E,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IACpC,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,MAAM,EAAE,GAAG,OAAmE,CAAC;IAC/E,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,EAAE;QAC/B,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACvE,kBAAkB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,EAAE,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QAChE,yFAAyF;QACzF,OAAO,IAAI,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAG,OAA2B,CAAC,IAAI,CAAC,CAAC;IAC3F,CAAC,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QACzB,OAAO;QACP,OAAO,EAAE,KAAK,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;KAChC,CAAC,CAAC;AACL,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,gBAAgB,CAC7B,MAAsB,EACtB,IAAmC,EACnC,KAAkB;IAElB,MAAM,KAAK,GAAG,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAC/C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;IACpE,IAAI,UAAU,EAAE,CAAC;QACf,kBAAkB,EAAE,CAAC;QACrB,+FAA+F;QAC/F,iFAAiF;QAChF,UAAsC,CAAC,kBAAkB,GAAG,CAC3D,MAAM,MAAM,CAAC,oCAAoC,CAAC,CACnD,CAAC,mBAAmB,CAAC;QACtB,IAAI,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACjC,yFAAyF;YACxF,UAAsC,CAAC,iBAAiB,GAAG,GAAG,CAAC;YAChE,MAAM,CAAC,MAAM,CAAE,UAA2D,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC/F,CAAC;QACD,0FAA0F;QAC1F,6FAA6F;QAC7F,8FAA8F;QAC9F,oBAAoB;QACpB,mBAAmB,EAAE,CAAC;IACxB,CAAC;IACD,MAAM,OAAO,GAAG;QACd,GAAG,cAAc;QACjB,OAAO,EAAE,cAAc,CAAC,YAAY;QACpC,QAAQ,EAAE,cAAc,CAAC,aAAa;QACtC,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,gCAAgC,CAAC;YAC7D,CAAC,CAAC,cAAc,CAAC,qBAAqB;YACtC,CAAC,CAAC,cAAc,CAAC,aAAa;KACjC,CAAC;IACF,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,mBAAmB,CAAC;YAClB,aAAa;YACb,oBAAoB,EAAE;gBACpB,GAAG,aAAa;gBAChB,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,SAAS,EAAE,KAAK,CAAC,SAAS;aAC3B;YACD,YAAY,EAAE,GAAG,IAAI,CAAC,IAAI,SAAS;YACnC,WAAW,EAAE,MAAM,MAAM,CAAC,uBAAuB,CAAC;YAClD,GAAG,OAAO;YACV,wFAAwF;YACxF,uBAAuB;YACvB,IAAI,EAAE,UAAU;gBACd,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,oCAAoC,CAAC,CAAC,CAAC,mBAAmB;gBAC1E,CAAC,CAAC,SAAS;SACd,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI;YAChB,CAAC,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAC,IAAI,aAAa,MAAM,CAAC,IAAI,EAAE,CAAC;YACzE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtB,CAAC;IACD,MAAM,CAAC,GAAG,UAAqC,CAAC;IAChD,CAAC,CAAC,oBAAoB,GAAG,aAAa,CAAC;IACvC,CAAC,CAAC,mBAAmB,GAAG,KAAK,CAAC,CAAC,yDAAyD;IACxF,CAAC,CAAC,cAAc,GAAG,OAAO,CAAC;IAC3B,OAAO,IAAI,CAAC,MAAM;QAChB,CAAC,CAAC,MAAM,MAAM;QACV,kBAAkB,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAC7F;QACH,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAA2B;IACrE,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrE,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9D,0FAA0F;IAC1F,MAAM,OAAO,GACX,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM;QACjC,CAAC,CAAC,MAAM,SAAS,CACb,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,MAAM,CAAC,GAAG,EACf,IAAI,CAAC,MAAM,CAAC,YAAY,EACxB,IAAI,CAAC,MAAM,CAAC,KAAK,EACjB,IAAI,CAAC,MAAM,CAAC,QAAQ,CACrB;QACH,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM;YACnC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAgB,CAAC,EAAE;gBACrD,OAAO,KAAI,CAAC;gBACZ,OAAO,EAAE,KAAK,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;aAChC,CAAC;YACJ,CAAC,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,OAAgB,EAAE;gBACzC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,eAAe,EAAE,EAAE,EAAE,kCAAkC;aACxD,CAAC,CAAC;IACX,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC;QAChC,UAAU,EAAE,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAC3E,CAAC,CAAC;IACH,8EAA8E;IAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,MAAM,MAAM,GACV,IAAI,CAAC,MAAM,IAAI,KAAK;QAClB,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACpF,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;QACzE,OAAO;QACP,KAAK;QACL,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE;QAClE,eAAe,EAAE,IAAI,CAAC,aAAa;YACjC,CAAC,CAAC,qBAAqB,CAAC;gBACpB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE,GAAG,IAAI,CAAC,IAAI,MAAM;gBACjC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,uDAAuD;aAC/E,CAAC;YACJ,CAAC,CAAC,SAAS;QACb,OAAO,EAAE,MAAM,EAAE,0DAA0D;QAC3E,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,EAAE,EAAE,IAAI,CAAC,EAAE;KACZ,CAAC,CAAC;IACH,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,OAAO;QACL,OAAO;QACP,WAAW;QACX,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,sDAAsD;QAC3E,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { installLtxVfs } from \"../adapters/ltx-vfs.js\";\nimport {\n sahpoolOpener,\n tuneCellConnection,\n WasmSqliteDriver,\n wasmMemoryOpener,\n} from \"../adapters/wasm-sqlite.js\";\nimport type { AssetFiles } from \"../bindings/assets.js\";\nimport type { WorkersAiOptions } from \"../bindings/workers-ai.js\";\nimport { celldBucket } from \"../bucket/celld-cells.js\";\nimport { idbObjectStore } from \"../bucket/idb-object-store.js\";\nimport { filesApiObjectStore, type ObjectStore } from \"../bucket/object-store.js\";\nimport { s3ObjectStore } from \"../bucket/s3-object-store.js\";\nimport type { CellRuntimeOptions, WorkerModule } from \"../core/runtime.js\";\nimport { browserIsolatedLoader } from \"../isolate/browser.js\";\nimport type { LtxStoreFiles } from \"../ltx/ltx-page-server.js\";\nimport { installAsyncContext } from \"../node-compat/async_hooks.js\";\nimport { installNodeGlobals } from \"../node-compat/install.js\";\nimport { browserModuleLoader } from \"./browser-modules.js\";\nimport * as workersModule from \"./cloudflare-workers.js\";\nimport { siteModuleLoader, workersHostRegistry } from \"./site-loader.js\";\nimport { type WorkerScope, workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n loadTimeEnv,\n populatesProcessEnv,\n processEnvOf,\n type WranglerConfig,\n} from \"./wrangler.js\";\n\nexport { populatesProcessEnv, processEnvOf };\n\n/**\n * Where a browser-hosted project keeps its cells when they must outlive the page or move to\n * other nodes: a celld fleet bucket. Cells, facets and alarms are then exactly celld's\n * (ownership in `own.json`, LTX logs, wake index) and R2 objects live in it too, so the same\n * cells can be served by this browser, by other browsers and by celld nodes, in turn.\n *\n * - `s3`: an S3-compatible bucket, reached directly (the bucket must allow CORS for the page's\n * origin: methods GET/PUT/DELETE/HEAD, request headers `authorization`, `content-type`,\n * `x-amz-*`, `if-match`, `if-none-match`; exposed headers `etag`, `last-modified`,\n * `x-amz-meta-celld-r2`) or through a same-origin proxy (`endpoint` = the proxy,\n * `signAs` = the real endpoint: SigV4 signs the real host and path).\n * - `opfs`: a bucket in this origin's OPFS — persistence without a server. Conditional writes\n * are atomic only within one writer, so one tab or worker at a time should own its cells.\n * - `store`: any ObjectStore.\n */\nexport type BrowserBucket =\n | {\n s3: {\n endpoint: string;\n signAs?: string;\n bucket: string;\n prefix?: string;\n region?: string;\n accessKeyId: string;\n secretAccessKey: string;\n };\n node: string;\n leaseTtlMs?: number;\n }\n | { opfs: string; node: string; leaseTtlMs?: number }\n /**\n * `idb`: a bucket in this origin's IndexedDB (atomic conditional writes across tabs and\n * workers). Cells then run SQLite in memory and persist through the bucket's page-level logs:\n * no OPFS pool, so any number of workers can serve cells at once.\n */\n | { idb: string; node: string; leaseTtlMs?: number }\n /**\n * `ltx`: cells as celld keeps them, LTX files (a snapshot and one file per commit) in an OPFS\n * directory, read page by page (a SQLite VFS over a store worker): no OPFS pool, and a\n * cell's memory is its page cache, not its database. A cell is folded into one snapshot\n * (streamed) past `compactAfter` files (default 64), or once the files after its snapshot hold\n * more than half of it. See docs/browser-host.md.\n */\n | {\n ltx: string;\n node: string;\n leaseTtlMs?: number;\n compactAfter?: number;\n /**\n * The cells' FilesApi in the store worker. A preset on OPFS directory `ltx`: synchronous\n * handles (default, `opfs-sync`), OPFS's asynchronous API (`opfs`), or memory (nothing\n * kept). Or the app's own FilesApi, opened before cellb starts: `{ port }` from\n * `filesApiPort(files)` (served where the app opened it), or `{ module, args }` (built in\n * the store worker). `ltx` then names the storage (the scope of the cells' Web Locks).\n * A port is transferred to the store worker, so it serves one runtime: give each\n * `browserProjectRuntime` a new `filesApiPort`.\n */\n files?: LtxStoreFiles;\n /**\n * A store already running elsewhere (`serveLtxStore(files)`, on the page): no store\n * worker; the VFS sends its reads and commits there. `files` is then ignored. One store\n * per runtime; the app calls its `close()` when the runtime ends.\n */\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort };\n }\n | { store: ObjectStore; node: string; leaseTtlMs?: number };\n\nexport interface BrowserProjectOptions {\n config: WranglerConfig;\n /**\n * The project's Worker code, imported in this realm once its Workers globals (and with\n * nodejs_compat `Buffer` and `process`) are installed:\n * - `bundle`: one ES module built for browsers (`bundleWorkerForBrowser`), whose\n * `cloudflare:workers` is `PROJECT_WORKERS_MODULE_SHIM` and whose Workers globals read\n * `globalThis.__cellsGlobals`\n * (`null`: the project has no `main`). Worker Loader code becomes Blob-URL modules.\n * - `site`: the base URL of the project's site (`createProjectSite`, hosted by\n * webrun-site-host). `main` and Worker Loader code are imported from it.\n */\n code: { bundle: string | null } | { site: string };\n /**\n * A Dedicated Worker script that serves one loaded Worker (`serveIsolate`): Worker Loader\n * code then runs isolated, one Dedicated Worker per loaded Worker, as celld's isolates.\n * The package ships one: `@statewalker/cellb/isolate-worker`. A function instead starts the\n * Dedicated Worker itself (`() => new Worker(new URL(…, import.meta.url), { type: \"module\" })`,\n * a form bundlers follow).\n */\n isolateScript?: URL | (() => Worker);\n /** An initialized SQLite WASM module (`@sqlite.org/sqlite-wasm`). */\n sqlite3: unknown;\n /** OPFS sahpool name for this host's SQLite files (one pool per worker). */\n pool: string;\n /** OPFS directory for the project's FilesApi (Workers' fs-like bindings, R2 without bucket). */\n filesDir: string;\n assetFiles?: AssetFiles;\n bucket?: BrowserBucket;\n /**\n * Cells this runtime does not host: where to send their events (a `Send` over a MessagePort\n * to the runtime that hosts them, `linkOverPort`), or undefined to host the cell here. With\n * one runtime per worker and `shardOf` as the placement, cells run in parallel threads.\n */\n route?: CellRuntimeOptions[\"route\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */\n ai?: WorkersAiOptions;\n}\n\nasync function bucketStore(b: BrowserBucket): Promise<ObjectStore> {\n if (\"store\" in b) return b.store;\n if (\"s3\" in b) return s3ObjectStore({ region: \"us-east-1\", ...b.s3 });\n if (\"idb\" in b) return idbObjectStore(b.idb);\n if (\"ltx\" in b) throw new Error(\"an ltx directory is cell storage, not a bucket\");\n const root = await navigator.storage.getDirectory();\n return filesApiObjectStore(\n new BrowserFilesApi({ rootHandle: await root.getDirectoryHandle(b.opfs, { create: true }) }),\n \"\",\n );\n}\n\n/**\n * Cells on the LTX VFS: each cell is a SQLite database whose main file is its LTX files, read\n * page by page (src/adapters/ltx-vfs.ts) from a store: a store worker of this worker's own (on\n * OPFS, memory, or the app's FilesApi through a port or a module), or a store the app runs\n * elsewhere (`ltxStore`).\n */\nexport async function ltxOpener(\n sqlite3: unknown,\n dir: string,\n compactAfter?: number,\n files?: LtxStoreFiles,\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort },\n) {\n let sab: SharedArrayBuffer;\n let post: (m: unknown) => void;\n let release: () => void;\n if (ltxStore) {\n // The store runs elsewhere (serveLtxStore): only the VFS here.\n sab = ltxStore.sab;\n const port = ltxStore.port;\n post = (m) => port.postMessage(m);\n release = () => port.close();\n } else {\n const store = new Worker(\n new URL(\n \"../ltx/ltx-store-worker.ts\",\n import.meta.url,\n ) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n sab = new SharedArrayBuffer(8 + 16 * 65536); // room for a read-ahead run of 64 KiB pages\n // Wait until the store worker runs before any synchronous call: a nested worker is started\n // (its script fetched) through this worker's event loop, which Atomics.wait would block.\n const ready = new Promise<void>((resolve, reject) => {\n store.addEventListener(\"message\", (e) => {\n if (e.data?.op === \"ready\") resolve();\n else if (e.data?.op === \"failed\")\n reject(new Error(`ltx store worker: ${e.data.error as string}`));\n });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n // A port to the app's FilesApi moves on to the store worker.\n const transfer = files && typeof files === \"object\" && \"port\" in files ? [files.port] : [];\n try {\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files }, transfer);\n await ready;\n } catch (err) {\n store.terminate(); // a store worker that did not start is not left behind\n throw err;\n }\n post = (m) => store.postMessage(m);\n release = () => store.terminate();\n }\n const { name } = installLtxVfs(sqlite3, { sab, post });\n const s3 = sqlite3 as { oo1: { DB: new (o: Record<string, unknown>) => any } };\n const open = (cellKey: string) => {\n const db = new s3.oo1.DB({ filename: cellKey, vfs: name, flags: \"c\" });\n tuneCellConnection(sqlite3, db);\n db.exec(\"PRAGMA journal_mode=MEMORY; PRAGMA synchronous=FULL;\");\n // SQLite's C API for inTransaction() only (no page hook or session capture on this VFS).\n return new WasmSqliteDriver(db, undefined, undefined, (sqlite3 as { capi: never }).capi);\n };\n return Object.assign(open, {\n release,\n reserve: async (n: number) => n,\n });\n}\n\n/** Installs the Workers globals the code reads, then imports its `main`. */\nasync function importWorkerCode(\n config: WranglerConfig,\n code: BrowserProjectOptions[\"code\"],\n scope: WorkerScope,\n): Promise<WorkerModule> {\n const flags = config.compatibility_flags ?? [];\n const nodeCompat = flags.some((f) => f.startsWith(\"nodejs_compat\"));\n if (nodeCompat) {\n installNodeGlobals();\n // node:* for bundles built with cellbHostModule (another bundler than bundleWorkerForBrowser);\n // loaded after installNodeGlobals(), as the npm `util` polyfill reads `process`.\n (globalThis as Record<string, unknown>).__cellsNodeModules = (\n await import(\"../node-compat/browser-registry.js\")\n ).nodeRegistryEntries;\n if (populatesProcessEnv(config)) {\n const env = processEnvOf(config);\n // The bundle's own `process` reads it when evaluated; a site's modules use this realm's.\n (globalThis as Record<string, unknown>).__cellsProcessEnv = env;\n Object.assign((globalThis as { process: { env: Record<string, string> } }).process.env, env);\n }\n // node:async_hooks: continuations carry their AsyncLocalStorage stores (with AsyncContext\n // the engine does, and this installs nothing). The code's awaits are lowered so that they go\n // through them: by bundleWorkerForBrowser for a bundle, by createProjectSite (nodeCompat) for\n // a site's modules.\n installAsyncContext();\n }\n const globals = {\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocketPair: flags.includes(\"websocket_standard_binary_type\")\n ? workersGlobals.StandardWebSocketPair\n : workersGlobals.WebSocketPair,\n };\n if (\"site\" in code) {\n workersHostRegistry({\n workersModule,\n projectWorkersModule: {\n ...workersModule,\n env: scope.env,\n exports: scope.exports,\n waitUntil: scope.waitUntil,\n },\n loadedPrefix: `${code.site}loaded/`,\n emailModule: await import(\"./cloudflare-email.js\"),\n ...globals,\n // Loaded on demand, after installNodeGlobals(): the npm `util` polyfill reads `process`\n // when it is imported.\n node: nodeCompat\n ? (await import(\"../node-compat/browser-registry.js\")).nodeRegistryEntries\n : undefined,\n });\n return config.main\n ? await import(/* @vite-ignore */ `${code.site}modules/~/${config.main}`)\n : { default: {} };\n }\n const g = globalThis as Record<string, unknown>;\n g.__cellsWorkersModule = workersModule;\n g.__cellsProjectScope = scope; // `env` and `exports` of the bundle's cloudflare:workers\n g.__cellsGlobals = globals;\n return code.bundle\n ? await import(\n /* @vite-ignore */ URL.createObjectURL(new Blob([code.bundle], { type: \"text/javascript\" }))\n )\n : { default: {} };\n}\n\n/**\n * A project's runtime in this worker: installs the Workers globals, imports the code and\n * builds its Worker Loader; `close()` also releases the node's bucket lease.\n */\nexport async function browserProjectRuntime(opts: BrowserProjectOptions) {\n const scope = workerScope(loadTimeEnv(opts.config, opts.ai));\n const module = await importWorkerCode(opts.config, opts.code, scope);\n const site = \"site\" in opts.code ? opts.code.site : undefined;\n // With an IndexedDB bucket, cells live in memory and in the bucket's logs (no OPFS pool).\n const openSql =\n opts.bucket && \"ltx\" in opts.bucket\n ? await ltxOpener(\n opts.sqlite3,\n opts.bucket.ltx,\n opts.bucket.compactAfter,\n opts.bucket.files,\n opts.bucket.ltxStore,\n )\n : opts.bucket && \"idb\" in opts.bucket\n ? Object.assign(wasmMemoryOpener(opts.sqlite3 as never), {\n release() {},\n reserve: async (n: number) => n,\n })\n : await sahpoolOpener(opts.sqlite3 as never, {\n name: opts.pool,\n initialCapacity: 64, // grows on demand (sahpoolOpener)\n });\n const root = await navigator.storage.getDirectory();\n const files = new BrowserFilesApi({\n rootHandle: await root.getDirectoryHandle(opts.filesDir, { create: true }),\n });\n // An `ltx` directory is the cells' own storage (the VFS), not a fleet bucket.\n const store = opts.bucket && !(\"ltx\" in opts.bucket) ? await bucketStore(opts.bucket) : undefined;\n const shared =\n opts.bucket && store\n ? celldBucket(store, { node: opts.bucket.node, leaseTtlMs: opts.bucket.leaseTtlMs })\n : undefined;\n const { runtime, unsupported } = createProjectRuntime(opts.config, module, {\n openSql,\n files,\n assetFiles: opts.assetFiles,\n loadModules: site ? siteModuleLoader(site) : browserModuleLoader(),\n isolatedModules: opts.isolateScript\n ? browserIsolatedLoader({\n isolateScript: opts.isolateScript,\n siteBaseUrl: site,\n storagePrefix: `${opts.pool}-iso`,\n storage: () => shared, // facets of loaded code are logged like the root's own\n })\n : undefined,\n storage: shared, // R2 objects in the fleet bucket too, as celld keeps them\n route: opts.route,\n ai: opts.ai,\n });\n scope.bind(runtime);\n return {\n runtime,\n unsupported,\n bucket: shared,\n close: async () => {\n await runtime.close();\n openSql.release(); // the pool's files, for the next worker that opens it\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/cellb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "cellb: isomorphic Durable Objects runtime (celld/Cloudflare-compatible surface) for browsers and servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@statewalker/webrun-files-browser": "^0.10.0",
|
|
60
60
|
"@statewalker/webrun-files-mem": "^0.10.0",
|
|
61
61
|
"@statewalker/webrun-files-node": "^0.10.3",
|
|
62
|
-
"@statewalker/webrun-http-browser": "^0.12.
|
|
62
|
+
"@statewalker/webrun-http-browser": "^0.12.2",
|
|
63
63
|
"@statewalker/webrun-http-streams": "^0.4.0",
|
|
64
64
|
"@statewalker/webrun-rpc": "^0.10.0",
|
|
65
65
|
"@statewalker/webrun-streams": "^0.2.3",
|