space-data-module-sdk 0.8.24 → 0.8.25
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/docs/isomorphic-pthreads.html +29 -5
- package/docs/isomorphic-pthreads.md +98 -8
- package/package.json +1 -1
- package/src/host/browserModuleHarness.js +13 -0
- package/src/host/hostWorkerBundleSources.js +3 -3
- package/src/host/nodeSyncFsIo.js +3 -1
- package/src/host/wasiThreadBrowserWorker.mjs +41 -21
- package/src/host/wasiThreadHost.js +279 -150
- package/src/host/wasiThreadPool.js +389 -0
- package/src/host/wasiThreadWorker.mjs +62 -20
- package/src/host/wasiThreadWorkerRuntime.js +6 -1
- package/src/index.d.ts +15 -0
- package/src/testing/index.d.ts +2 -0
|
@@ -156,6 +156,27 @@ node --test test/direct-call-constructors.test.js</code></pre></div>
|
|
|
156
156
|
<h3 id="guest-thread-faults"><a class="anchor" href="#guest-thread-faults" aria-hidden="true">#</a>Guest thread faults</h3>
|
|
157
157
|
<p>A guest thread that traps never finishes the pthread exit protocol. WasmEdge cancels the whole command. In the browser and Node harnesses the joining thread stays blocked inside the guest and cannot run the worker's error event, so the worker itself writes <code>[wasi-thread] guest thread N trapped: ...</code> to stderr (Node) or the console (browser). The call still does not return.</p>
|
|
158
158
|
<p>V8 (Node 20 to 25) checks bulk memory operations, and every access when the WebAssembly trap handler is off (Node on Linux arm64), against a per-instance copy of a shared memory's size. That copy is refreshed asynchronously after another thread grows the memory, so a thread that writes into memory another thread has just grown can trap with "memory access out of bounds", even after synchronizing with the growing thread. The guest's allocator uses the heap the artifact was linked with and then grows the memory, so a larger imported initial memory does not prevent it.</p>
|
|
159
|
+
<h3 id="sdk-0825-one-pool-protocol-threads-reused-within-an-invoke-spawns-from-any-thread"><a class="anchor" href="#sdk-0825-one-pool-protocol-threads-reused-within-an-invoke-spawns-from-any-thread" aria-hidden="true">#</a>SDK 0.8.25: one pool protocol; threads reused within an invoke; spawns from any thread</h3>
|
|
160
|
+
<p>A guest runs <code>pthread_create</code> through <code>pthread_join</code> without yielding the spawning thread's event loop, often for a whole invoke that spawns wave after wave of threads (conjunction screening spawns a coarse wave, then a refine wave), and any guest thread may call <code>pthread_create</code>. Through 0.8.24:</p>
|
|
161
|
+
<ul>
|
|
162
|
+
<li>a pooled browser worker was sent each thread by message and went back to idle only when the spawner handled its <code>{t:"exit"}</code> message, which could not happen until the invoke returned. One invoke could spawn at most <code>poolSize</code> threads in total, however few ran at once, and a guest that spawned more got <code>EAGAIN</code> (<code>std::thread</code> aborts with <code>unreachable</code>);</li>
|
|
163
|
+
<li>Node started a worker per spawn. Its live-thread count and the join of a finished worker waited for <code>exit</code> events on the blocked event loop, so an explicit <code>poolSize</code> had the same limit, and a guest that started thousands of threads kept thousands of finished workers;</li>
|
|
164
|
+
<li>a spawn from a guest thread other than the main thread always returned -1.</li>
|
|
165
|
+
</ul>
|
|
166
|
+
<p>From 0.8.25 both runtimes share one pool protocol (<code>src/host/wasiThreadPool.js</code>), a <code>SharedArrayBuffer</code> every thread of the process holds: a tid counter, spawn counters, and per worker a slot (<code>PENDING</code>, <code>IDLE</code>, <code>CLAIMED</code>, <code>ASSIGNED</code>, <code>RUNNING</code>, <code>RETIRED</code>, plus the tid and start argument). A pool worker blocks on its slot between threads. A spawner on any thread claims an <code>IDLE</code> slot with a compare-exchange, writes the tid and argument, marks it <code>ASSIGNED</code> and notifies it. The worker runs <code>wasi_thread_start</code>, then marks the slot <code>IDLE</code> and bumps a release generation that waiting spawners sleep on. No step needs an event loop, so:</p>
|
|
167
|
+
<ul>
|
|
168
|
+
<li>a pool bounds how many threads run <strong>at the same time</strong>, not how many one invoke may start (measured: 14,000 threads in one invoke ran on 7 Node workers);</li>
|
|
169
|
+
<li>every guest thread's own <code>wasi.thread-spawn</code> is the pool's, so a guest thread can start threads of its own;</li>
|
|
170
|
+
<li>Node reuses its workers. With no <code>poolSize</code> it grows the pool to at most 1024 workers; with one, to <code>poolSize</code>. A spawn that finds every worker busy waits up to 2 ms for one to come free, then starts a new worker from the spawning thread, which may itself be a pool worker (a Node worker starts without its parent's event loop). Idle workers do not keep the process alive;</li>
|
|
171
|
+
<li>the browser keeps its pre-started warm pool (a browser worker cannot start while its parent is blocked). Its workers now serve their slots and never return to their event loop after the probe.</li>
|
|
172
|
+
</ul>
|
|
173
|
+
<p>A joined thread's worker is still a few instructions from returning when the joiner wakes, so a wave spawned right after a join can find the pool busy for a moment (measured in headless Chromium: 0 to 30 µs). A spawn that finds every thread busy and cannot grow the pool therefore waits on the generation for up to <code>spawnWaitMs</code> (default 250 ms; harness option <code>wasiThreadSpawnWaitMs</code>) before it is declined. After one wait runs out, later spawns from that thread are declined at once until some thread finishes, so a pool held by long-running threads costs one wait, not one per spawn. The wait uses <code>Atomics.wait</code>, which workers and Node allow; where it is not allowed (a window's main thread) a spawn never waits.</p>
|
|
174
|
+
<p><code>spawnReport()</code> counts spawns from every thread (<code>spawned</code>, <code>waited</code>, and <code>pool-exhausted</code> declines); <code>onSpawnDeclined</code> fires for the owning thread's spawns. A Node worker started by a guest thread reports a guest fault on stderr only; <code>onGuestError</code> covers workers the owning thread started and every browser worker.</p>
|
|
175
|
+
<p>A browser worker that answers the probe without the pool protocol (a worker script from an older SDK) still works: the owning thread sends it its threads by <code>{t:"run"}</code> and frees it on <code>{t:"exit"}</code>, as before, and guest threads never spawn onto it. A worker served from the matching SDK gets the fix.</p>
|
|
176
|
+
<p><code>test/wasi-thread-pool-reuse-guest.test.js</code> compiles a guest that spawns 3 waves of <code>poolSize - 1</code> threads (the main thread runs one stripe), 3 waves of <code>poolSize</code> threads, and 3 waves whose threads a non-main guest thread spawns, in one invoke. It checks the output bytes and spawn counts in Node (explicit pool, no pool, and 14,000 threads on at most 16 workers), in headless Chromium, Firefox and WebKit, and across the three parity lanes:</p>
|
|
177
|
+
<div class="codeblock"><div class="codeblock-head">sh</div><pre><code>SPACE_DATA_MODULE_SDK_ENABLE_BROWSER_THREADS=1 \
|
|
178
|
+
SPACE_DATA_MODULE_SDK_ENABLE_TRI_RUNTIME_PARITY=1 \
|
|
179
|
+
node --test test/wasi-thread-pool-reuse-guest.test.js</code></pre></div>
|
|
159
180
|
<p>The old source path <code>src/testing/browserModuleHarness.js</code> remains a pure compatibility re-export. New browser consumers should use the public <code>space-data-module-sdk/host/browser-module</code> entry point.</p>
|
|
160
181
|
<h2 id="4-integrators-the-browser-worker-anchor-required-when-you-bundle"><a class="anchor" href="#4-integrators-the-browser-worker-anchor-required-when-you-bundle" aria-hidden="true">#</a>4. Integrators: the browser worker anchor (REQUIRED when you bundle)</h2>
|
|
161
182
|
<p>The browser leg of the wasi-threads host runs each guest pthread on a pooled module <code>Worker</code>. That worker is a <strong>served asset</strong>, and the SDK cannot guess where your build published it.</p>
|
|
@@ -177,7 +198,7 @@ setBrowserWasiThreadWorkerBase("js/vendor/space-data-module-sdk/src/host/&q
|
|
|
177
198
|
<div class="table-wrap"><table><thead><tr><th>Source</th><th>Option / API</th></tr></thead><tbody><tr><td>1. Explicit worker file</td><td><code>browserWorkerUrl</code> / <code>wasiThreadWorkerUrl</code></td></tr><tr><td>2. Explicit directory</td><td><code>browserWorkerBaseUrl</code> / <code>wasiThreadWorkerBaseUrl</code></td></tr><tr><td>3. Process-wide base</td><td><code>setBrowserWasiThreadWorkerBase(base)</code></td></tr><tr><td>4. Packaged sibling</td><td><code>new URL("./wasiThreadBrowserWorker.mjs", import.meta.url)</code></td></tr></tbody></table></div>
|
|
178
199
|
<p>Rules that make this contract honest:</p>
|
|
179
200
|
<ul>
|
|
180
|
-
<li><strong>The anchor names a DIRECTORY that serves the WHOLE chain.</strong> <code>wasiThreadBrowserWorker.mjs</code> imports <code>./wasiThreadWorkerRuntime.js</code
|
|
201
|
+
<li><strong>The anchor names a DIRECTORY that serves the WHOLE chain.</strong> <code>wasiThreadBrowserWorker.mjs</code> imports <code>./wasiThreadWorkerRuntime.js</code> and <code>./wasiThreadPool.js</code>, which import their own siblings. Staging the single <code>.mjs</code> next to your bundle does <strong>not</strong> work.</li>
|
|
181
202
|
<li><strong>A relative base resolves against the document</strong>; absolute URLs pass through unchanged.</li>
|
|
182
203
|
<li><strong>No consumer-side <code>location</code> sniffing.</strong> Forking worker resolution per consumer is not the contract; you already know your build's layout, so state it.</li>
|
|
183
204
|
<li><strong>No fetch-and-retry probe.</strong> Resolution never touches the network: Node never fetches, and browser thread count may not become a function of network timing.</li>
|
|
@@ -188,8 +209,8 @@ setBrowserWasiThreadWorkerBase("js/vendor/space-data-module-sdk/src/host/&q
|
|
|
188
209
|
<p>The FlatSQL partition store (stack design <code>docs/architecture/flatsql-partition-store.md</code>, §5.5, §5.6, §18 T9, A7, A36, A38, A39) runs one wasi-threads artifact as a writer instance and reader instances, each with guest threads that call FlatSQL's seven <code>env.flatsql_io_*</code> imports. This section is the SDK half: the thread pool, the I/O channel and workers, the Node provider, link shim v2, the worker bundles and the browser capability probe.</p>
|
|
189
210
|
<h3 id="explicit-pool-size-partial-spawns-supervision-hooks"><a class="anchor" href="#explicit-pool-size-partial-spawns-supervision-hooks" aria-hidden="true">#</a>Explicit pool size, partial spawns, supervision hooks</h3>
|
|
190
211
|
<p><code>createWasiThreadSpawn</code> options added in 0.8.22:</p>
|
|
191
|
-
<div class="table-wrap"><table><thead><tr><th>Option</th><th>Effect</th></tr></thead><tbody><tr><td><code>poolSize</code></td><td>Browser: pre-start exactly this many workers, independent of <code>hardwareConcurrency - 1</code> (pools are sized for isolation: writers + lanes). Node: cap on live guest threads. Arming is partial: workers that fail to start are dropped, the rest serve.</td></tr><tr><td><code>extraImports</code></td><td>Per-worker import objects, as structured-cloneable descriptors (below). Factories run once per worker.</td></tr><tr><td><code>instanceId</code>, <code>onGuestError(instanceId, tid, error)</code></td><td>Called when a guest thread traps or its worker dies (A36). A dead pooled worker leaves the pool.</td></tr><tr><td><code>onSpawnDeclined({ reason, poolSize, declined })</code></td><td>Called for every spawn that returns -1. Reasons: <code>pool-exhausted</code>, <code>pool-not-armed</code>, <code>threads-unavailable</code>, <code>pool-empty</code>, <code>worker-create-failed</code>, <code>dispatch-failed</code>, <code>hostcall-channel-missing</code>, <code>terminated</code>.</td></tr><tr><td><code>probeTimeoutMs</code></td><td>Browser warm-pool probe deadline.</td></tr><tr><td><code>browserWorkerType: "classic"</code></td><td>Spawn classic workers, for the blob bundles below.</td></tr></tbody></table></div>
|
|
192
|
-
<p>The returned host adds <code>spawnReport()</code>: <code>{ poolSize, armed, failedToArm, spawned, declined, declinedByReason, lastDeclineReason, active, idle }</code
|
|
212
|
+
<div class="table-wrap"><table><thead><tr><th>Option</th><th>Effect</th></tr></thead><tbody><tr><td><code>poolSize</code></td><td>Browser: pre-start exactly this many workers, independent of <code>hardwareConcurrency - 1</code> (pools are sized for isolation: writers + lanes). Node: cap on live guest threads (the pool grows to it on demand; without it, to 1024). Arming is partial: workers that fail to start are dropped, the rest serve.</td></tr><tr><td><code>extraImports</code></td><td>Per-worker import objects, as structured-cloneable descriptors (below). Factories run once per worker.</td></tr><tr><td><code>instanceId</code>, <code>onGuestError(instanceId, tid, error)</code></td><td>Called when a guest thread traps or its worker dies (A36). A dead pooled worker leaves the pool. In Node, for workers the owning thread started.</td></tr><tr><td><code>onSpawnDeclined({ reason, poolSize, declined })</code></td><td>Called for every spawn from the owning thread that returns -1. Reasons: <code>pool-exhausted</code>, <code>pool-not-armed</code>, <code>threads-unavailable</code>, <code>pool-empty</code>, <code>worker-create-failed</code>, <code>dispatch-failed</code>, <code>hostcall-channel-missing</code>, <code>terminated</code>.</td></tr><tr><td><code>probeTimeoutMs</code></td><td>Browser warm-pool probe deadline.</td></tr><tr><td><code>spawnWaitMs</code></td><td>How long a spawn that finds every pool thread busy waits for one to finish before it returns -1 (default 250; 0 never waits). Added in 0.8.25; see "one pool protocol" in §3.</td></tr><tr><td><code>browserWorkerType: "classic"</code></td><td>Spawn classic workers, for the blob bundles below.</td></tr></tbody></table></div>
|
|
213
|
+
<p>The returned host adds <code>spawnReport()</code>: <code>{ poolSize, armed, failedToArm, spawned, waited, declined, declinedByReason, lastDeclineReason, active, idle }</code> (Node adds <code>workers</code>). The counts cover spawns from every thread of the process. The implicit (no <code>poolSize</code>) path keeps its all-or-nothing arming.</p>
|
|
193
214
|
<p><code>extraImports</code> entries (the same descriptors work in the engine worker through <code>resolveExtraImports</code>):</p>
|
|
194
215
|
<div class="table-wrap"><table><thead><tr><th>Descriptor</th><th>Imports</th></tr></thead><tbody><tr><td><code>{ provider: "flatsql-io", instanceId, channels, mirror?, trace? }</code></td><td><code>env.flatsql_io_*</code> over one SAB I/O channel per I/O worker. Each worker claims its own request slot.</td></tr><tr><td><code>{ provider: "flatsql-io-node", root, table, instanceId }</code></td><td><code>env.flatsql_io_*</code> over synchronous <code>fs</code> (Node workers).</td></tr><tr><td><code>{ moduleUrl, exportName?, config? }</code></td><td>A factory module (module workers and Node only).</td></tr></tbody></table></div>
|
|
195
216
|
<p>A module that bundles this host into an IIFE or a blob: module worker has no usable <code>import.meta.url</code>. <code>DEFAULT_BROWSER_WORKER_URL</code> is then <code>null</code> instead of a module-evaluation <code>TypeError</code>, and such hosts pass <code>browserWorkerUrl</code>.</p>
|
|
@@ -216,7 +237,7 @@ setBrowserWasiThreadWorkerBase("js/vendor/space-data-module-sdk/src/host/&q
|
|
|
216
237
|
<p>Store lock (A37): with <code>lock: { name }</code> the I/O worker takes that Web Lock before it opens any handle and releases it only after <code>stop()</code> has closed them, so the lock lives exactly as long as the handles. <code>ifAvailable: true</code> fails the start with <code>lockUnavailable</code> instead of waiting; <code>busyRetry</code> retries a handle a previous leader still holds, with backoff. Measured takeover (holder <code>stop()</code> to successor ready): 5 ms Chromium, 52 ms Firefox, 5 ms WebKit. Leadership, follower proxying and heartbeats are the engine's (sdn-js, T10).</p>
|
|
217
238
|
<p>Head mirror (A7): with <code>mirror: { buffer, suffixes: ["/h.fsh"] }</code>, the writer I/O worker copies every write to a matching path into a seqlock mirror in a SharedArrayBuffer (<code>sabIoMirror.js</code>), and reader imports configured with the same mirror serve reads of those paths from it without a round trip.</p>
|
|
218
239
|
<h3 id="node-synchronous-fs-56"><a class="anchor" href="#node-synchronous-fs-56" aria-hidden="true">#</a>Node synchronous fs (§5.6)</h3>
|
|
219
|
-
<p><code>nodeSyncFsIo.js</code>: synchronous <code>fs</code> in each worker over a shared virtual-handle table in a SharedArrayBuffer (<code>createNodeSyncFsIoTable</code>). A handle is <code>(slot << 8) | gen</code>; each worker opens its own fd for a slot on first use and drops stale fds when the generation moves. Paths are confined below <code>root</code>, including through symlinked parents. <code>sync</code> is <code>fdatasync</code> (libuv issues <code>F_FULLFSYNC</code> on darwin). <code>revokeNodeSyncFsIoInstance</code> follows A23: it sets the revoked flag and waits for the instance's in-flight calls to drain. Fault injection (§19, 22.3a-7) belongs to FlatSQL's Node host (T4); <code>interpose</code> wraps every syscall for it.</p>
|
|
240
|
+
<p><code>nodeSyncFsIo.js</code>: synchronous <code>fs</code> in each worker over a shared virtual-handle table in a SharedArrayBuffer (<code>createNodeSyncFsIoTable</code>). A handle is <code>(slot << 8) | gen</code>; each worker opens its own fd for a slot on first use and drops stale fds when the generation moves. Paths are confined below <code>root</code>, including through symlinked parents; a filesystem root (<code>root: "/"</code>) reaches every path under it (through 0.8.24 every such path was <code>ACCESS</code>). <code>sync</code> is <code>fdatasync</code> (libuv issues <code>F_FULLFSYNC</code> on darwin). <code>revokeNodeSyncFsIoInstance</code> follows A23: it sets the revoked flag and waits for the instance's in-flight calls to drain. Fault injection (§19, 22.3a-7) belongs to FlatSQL's Node host (T4); <code>interpose</code> wraps every syscall for it.</p>
|
|
220
241
|
<h3 id="link-shim-v2"><a class="anchor" href="#link-shim-v2" aria-hidden="true">#</a>Link shim v2</h3>
|
|
221
242
|
<p><code>FLATSQL_LINK_SHIM_V2_WASM</code> (<code>src/flow/flatsqlLinkShim.js</code>) is a deterministic module that imports the reader instance's SHARED lane memory as <code>flatsql.memory</code> and gives a linked flow the lane mailbox as direct calls. v1 is unchanged (sha256 <code>8d83e69b…</code>), because today's linked flows use it. v2 sha256: <code>67d5b2d9bc2d1b346a14a253a586fd4d08c8056d54eb62701b48000585ed9613</code>.</p>
|
|
222
243
|
<div class="table-wrap"><table><thead><tr><th>Export</th><th>Result</th></tr></thead><tbody><tr><td><code>mb_submit(mailbox, op, req_ptr, req_len)</code></td><td><code>seq</code>, or -1 when the mailbox holds a request</td></tr><tr><td><code>mb_poll(mailbox, seq)</code></td><td>1 when complete</td></tr><tr><td><code>mb_wait(mailbox, seq, poll_ns: i64, max_polls)</code></td><td>the lane's status, or -110 after <code>max_polls</code> bounded waits (<code>max_polls <= 0</code>: no limit)</td></tr><tr><td><code>mb_release(mailbox, seq)</code></td><td>0, or -1 when not complete</td></tr><tr><td><code>mb_cancel(mailbox, seq)</code></td><td>0; the lane polls the cancel word</td></tr><tr><td><code>load32_acquire</code>, <code>store32_release</code>, <code>peek8/32/64</code>, <code>poke8/32</code>, <code>fnv1a64</code>, <code>count_frames</code></td><td>as in v1, over lane memory</td></tr></tbody></table></div>
|
|
@@ -248,7 +269,7 @@ const pool = await createWasiThreadSpawn({
|
|
|
248
269
|
<p><code>runFlatsqlIoConformance(io)</code> (<code>flatsqlIoConformance.js</code>) is one script for every host (22.3a-6): 15 cases covering statuses, short reads, sparse writes, truncation, EXCL/TRUNC/PROBE/UNLINK/UNLINK_IF_UNUSED/CREATE_PARENTS/ DELETE_ON_CLOSE/OPEN_DEFERRED, access modes, confinement and multi-handle visibility. It passes on the Node sync-fs provider, on the channel over the memory backend (blocking and async clients, both doorbells), on the blob bundle run as a standalone script, and on OPFS and memory in Chromium, Firefox and WebKit. Plain <code>UNLINK</code> of an open path is <code>BUSY</code> in the I/O worker (OPFS cannot remove a file with an open sync handle) and succeeds on POSIX hosts; the script does not test it.</p>
|
|
249
270
|
<h3 id="measured-acceptance-18-t9-a7-a38"><a class="anchor" href="#measured-acceptance-18-t9-a7-a38" aria-hidden="true">#</a>Measured acceptance (§18 T9, A7, A38)</h3>
|
|
250
271
|
<p>Owner's Mac Studio (Apple M3 Ultra, 28 cores, macOS 26.3.1), 2026-09-27, headless, final full run of <code>test/opfs-io-worker.browser.test.js</code>. The machine was shared with other lanes (load average 23-33 on 28 cores). Latencies are guest-observed import calls (<code>trace</code>), in microseconds.</p>
|
|
251
|
-
<div class="table-wrap"><table><thead><tr><th>Item</th><th>Chromium 153</th><th>Firefox 155</th><th>WebKit 26.6</th></tr></thead><tbody><tr><td>#1 8 threads, mixed I/O + 200 async opens + 50 unlinks through 1 I/O worker: errors / lost writes</td><td>0 / 0</td><td>0 / 0</td><td>0 / 0</td></tr><tr><td>same run, 4 KiB read p50 / p99</td><td>50 / 2145</td><td>260 / 8180</td><td>60 / 2660</td></tr><tr><td>same run, message doorbell: errors / lost writes</td><td>0 / 0</td><td>0 / 0</td><td>0 / 0</td></tr><tr><td>A7 lane 4 KiB read p99 during 100 x 4 MiB write+flush, same partition</td><td>790 (active file, shared mode)</td><td>120 (sealed segment)</td><td>40 (sealed segment)</td></tr><tr><td>A7 same, other partition</td><td>45</td><td>120</td><td>40</td></tr><tr><td>A7 writer flush p50 / p99 (4 MiB)</td><td>6365 / 28945</td><td>3540 / 27740</td><td>5260 / 70700</td></tr><tr><td>#2 500 ms open, median of 3 runs: other threads' read p99, baseline / during</td><td>85 / 85</td><td>440 / 400</td><td>60 / 60</td></tr><tr><td>#2 longest other-thread read while the open was pending</td><td>1020</td><td>18500</td><td>320</td></tr><tr><td>A38 OPEN_DEFERRED: open returns in / first write waits (ms)</td><td>3.8 / 504</td><td>28.8 / 511</td><td>5.2 / 755</td></tr><tr><td>#3 <code>poolSize=6</code> on <code>hardwareConcurrency=2</code
|
|
272
|
+
<div class="table-wrap"><table><thead><tr><th>Item</th><th>Chromium 153</th><th>Firefox 155</th><th>WebKit 26.6</th></tr></thead><tbody><tr><td>#1 8 threads, mixed I/O + 200 async opens + 50 unlinks through 1 I/O worker: errors / lost writes</td><td>0 / 0</td><td>0 / 0</td><td>0 / 0</td></tr><tr><td>same run, 4 KiB read p50 / p99</td><td>50 / 2145</td><td>260 / 8180</td><td>60 / 2660</td></tr><tr><td>same run, message doorbell: errors / lost writes</td><td>0 / 0</td><td>0 / 0</td><td>0 / 0</td></tr><tr><td>A7 lane 4 KiB read p99 during 100 x 4 MiB write+flush, same partition</td><td>790 (active file, shared mode)</td><td>120 (sealed segment)</td><td>40 (sealed segment)</td></tr><tr><td>A7 same, other partition</td><td>45</td><td>120</td><td>40</td></tr><tr><td>A7 writer flush p50 / p99 (4 MiB)</td><td>6365 / 28945</td><td>3540 / 27740</td><td>5260 / 70700</td></tr><tr><td>#2 500 ms open, median of 3 runs: other threads' read p99, baseline / during</td><td>85 / 85</td><td>440 / 400</td><td>60 / 60</td></tr><tr><td>#2 longest other-thread read while the open was pending</td><td>1020</td><td>18500</td><td>320</td></tr><tr><td>A38 OPEN_DEFERRED: open returns in / first write waits (ms)</td><td>3.8 / 504</td><td>28.8 / 511</td><td>5.2 / 755</td></tr><tr><td>#3 <code>poolSize=6</code> on <code>hardwareConcurrency=2</code> (<code>spawnWaitMs: 0</code> since 0.8.25)</td><td>6 workers; 7th spawn -1, reported <code>pool-exhausted</code></td><td>same</td><td>same</td></tr><tr><td>#5 link shim v2 (Node 25): 10,000 calls, lost completions</td><td>0 with a notifying lane, 0 with a lane that never notifies, 0 spinning (<code>poll_ns = 0</code>)</td><td></td><td></td></tr></tbody></table></div>
|
|
252
273
|
<p>Chromium's same-partition A7 p99 varies with host load: 90, 110, 295 and 790 over four runs with the adaptive spin (below), and 125-1165 over four runs before it. The original #1 target (4 KiB read p99 <= 200 µs under the mixed load) is not met through one I/O worker; A7 replaced #1 with the <= 1 ms lane target, which is met. Firefox and WebKit have no shared handle modes, so their lanes read a partition's sealed segment; per §22.4-6 those browsers get no local store.</p>
|
|
253
274
|
<p>Adaptive waits: an idle I/O worker polls its doorbell for 50 µs, and a blocking client polls for its answer for 20 µs, before sleeping (<code>spinMicros</code>), so back-to-back requests skip a thread wake-up. In the Node channel test this took the fast-thread read p50 from 30-39 µs to 11-12 µs.</p>
|
|
254
275
|
<h2 id="tests"><a class="anchor" href="#tests" aria-hidden="true">#</a>Tests</h2>
|
|
@@ -259,6 +280,8 @@ const pool = await createWasiThreadSpawn({
|
|
|
259
280
|
<li><code>test/guest-link-symbol-prefix.test.js</code> — the guest-link prefix is the full injective hex of the pluginId; two previously-colliding ids now get distinct prefixes; fresh prefixes match the committed modules-branch artifacts byte-for-byte; and the compose path treats the guest-link metadata's <code>symbolPrefix</code> / <code>methodSymbols</code> as authoritative (never re-derived), keeping a legacy truncated-prefix artifact compatible.</li>
|
|
260
281
|
</ul>
|
|
261
282
|
<ul>
|
|
283
|
+
<li><code>test/wasi-thread-pool-reuse.test.js</code> — the pool protocol with no message and no event-loop turn: 3 waves of <code>poolSize - 1</code> and of <code>poolSize</code> spawns, a spawn that blocks until a thread finishes on another thread, a spawn from a thread that is not the owner, the <code>spawnWaitMs</code> bound and the no-second-wait rule, an older worker script and a late <code>{t:"exit"}</code>, a dead worker, <code>terminateAll</code>.</li>
|
|
284
|
+
<li><code>test/wasi-thread-pool-reuse-guest.test.js</code> — the real wave guest in Node, headless Chromium, Firefox and WebKit, and the three parity lanes (the browser and parity runs are env-gated, see §3).</li>
|
|
262
285
|
<li><code>test/wasi-thread-pool-size.test.js</code> — explicit <code>poolSize</code> (6 workers on <code>hardwareConcurrency=2</code>, the 7th spawn -1 and reported), partial arming, extraImports delivery, <code>onGuestError</code>, classic workers.</li>
|
|
263
286
|
<li><code>test/sab-io-channel.test.js</code> — the I/O channel under a real wasi-threads guest (<code>test/support/flatsql-io/ioGuestWasm.mjs</code>): 8 threads of mixed I/O in both doorbell modes, a 500 ms open blocking only its caller, OPEN_DEFERRED, revocation, a dead I/O worker, supervisor restart, 256 KiB steps, the head mirror, scratch vs direct transfers, pre-open, and path-hash routing.</li>
|
|
264
287
|
<li><code>test/node-sync-fs-io.test.js</code> — shared handles across workers, stale handles, CREATE_PARENTS, UNLINK_IF_UNUSED, confinement, A23 revocation.</li>
|
|
@@ -294,6 +317,7 @@ const pool = await createWasiThreadSpawn({
|
|
|
294
317
|
<li><a class="depth-3" href="#sdk-0820-command-hosts">SDK 0.8.20 command hosts</a></li>
|
|
295
318
|
<li><a class="depth-3" href="#sdk-0821-constructors-on-the-direct-surface">SDK 0.8.21: constructors on the direct surface</a></li>
|
|
296
319
|
<li><a class="depth-3" href="#guest-thread-faults">Guest thread faults</a></li>
|
|
320
|
+
<li><a class="depth-3" href="#sdk-0825-one-pool-protocol-threads-reused-within-an-invoke-spawns-from-any-thread">SDK 0.8.25: one pool protocol; threads reused within an invoke; spawns from any thread</a></li>
|
|
297
321
|
<li><a class="depth-2" href="#4-integrators-the-browser-worker-anchor-required-when-you-bundle">4. Integrators: the browser worker anchor (REQUIRED when you bundle)</a></li>
|
|
298
322
|
<li><a class="depth-2" href="#5-flatsql-partition-store-host-io-sdk-0822">5. FlatSQL partition store host I/O (SDK 0.8.22)</a></li>
|
|
299
323
|
<li><a class="depth-3" href="#explicit-pool-size-partial-spawns-supervision-hooks">Explicit pool size, partial spawns, supervision hooks</a></li>
|
|
@@ -261,6 +261,83 @@ synchronizing with the growing thread. The guest's allocator uses the heap the
|
|
|
261
261
|
artifact was linked with and then grows the memory, so a larger imported initial
|
|
262
262
|
memory does not prevent it.
|
|
263
263
|
|
|
264
|
+
### SDK 0.8.25: one pool protocol; threads reused within an invoke; spawns from any thread
|
|
265
|
+
|
|
266
|
+
A guest runs `pthread_create` through `pthread_join` without yielding the
|
|
267
|
+
spawning thread's event loop, often for a whole invoke that spawns wave after
|
|
268
|
+
wave of threads (conjunction screening spawns a coarse wave, then a refine
|
|
269
|
+
wave), and any guest thread may call `pthread_create`. Through 0.8.24:
|
|
270
|
+
|
|
271
|
+
- a pooled browser worker was sent each thread by message and went back to
|
|
272
|
+
idle only when the spawner handled its `{t:"exit"}` message, which could not
|
|
273
|
+
happen until the invoke returned. One invoke could spawn at most `poolSize`
|
|
274
|
+
threads in total, however few ran at once, and a guest that spawned more got
|
|
275
|
+
`EAGAIN` (`std::thread` aborts with `unreachable`);
|
|
276
|
+
- Node started a worker per spawn. Its live-thread count and the join of a
|
|
277
|
+
finished worker waited for `exit` events on the blocked event loop, so an
|
|
278
|
+
explicit `poolSize` had the same limit, and a guest that started thousands of
|
|
279
|
+
threads kept thousands of finished workers;
|
|
280
|
+
- a spawn from a guest thread other than the main thread always returned -1.
|
|
281
|
+
|
|
282
|
+
From 0.8.25 both runtimes share one pool protocol (`src/host/wasiThreadPool.js`),
|
|
283
|
+
a `SharedArrayBuffer` every thread of the process holds: a tid counter, spawn
|
|
284
|
+
counters, and per worker a slot (`PENDING`, `IDLE`, `CLAIMED`, `ASSIGNED`,
|
|
285
|
+
`RUNNING`, `RETIRED`, plus the tid and start argument). A pool worker blocks on
|
|
286
|
+
its slot between threads. A spawner on any thread claims an `IDLE` slot with a
|
|
287
|
+
compare-exchange, writes the tid and argument, marks it `ASSIGNED` and notifies
|
|
288
|
+
it. The worker runs `wasi_thread_start`, then marks the slot `IDLE` and bumps a
|
|
289
|
+
release generation that waiting spawners sleep on. No step needs an event loop,
|
|
290
|
+
so:
|
|
291
|
+
|
|
292
|
+
- a pool bounds how many threads run **at the same time**, not how many one
|
|
293
|
+
invoke may start (measured: 14,000 threads in one invoke ran on 7 Node
|
|
294
|
+
workers);
|
|
295
|
+
- every guest thread's own `wasi.thread-spawn` is the pool's, so a guest thread
|
|
296
|
+
can start threads of its own;
|
|
297
|
+
- Node reuses its workers. With no `poolSize` it grows the pool to at most 1024
|
|
298
|
+
workers; with one, to `poolSize`. A spawn that finds every worker busy waits
|
|
299
|
+
up to 2 ms for one to come free, then starts a new worker from the spawning
|
|
300
|
+
thread, which may itself be a pool worker (a Node worker starts without its
|
|
301
|
+
parent's event loop). Idle workers do not keep the process alive;
|
|
302
|
+
- the browser keeps its pre-started warm pool (a browser worker cannot start
|
|
303
|
+
while its parent is blocked). Its workers now serve their slots and never
|
|
304
|
+
return to their event loop after the probe.
|
|
305
|
+
|
|
306
|
+
A joined thread's worker is still a few instructions from returning when the
|
|
307
|
+
joiner wakes, so a wave spawned right after a join can find the pool busy for a
|
|
308
|
+
moment (measured in headless Chromium: 0 to 30 µs). A spawn that finds every
|
|
309
|
+
thread busy and cannot grow the pool therefore waits on the generation for up
|
|
310
|
+
to `spawnWaitMs` (default 250 ms; harness option `wasiThreadSpawnWaitMs`) before
|
|
311
|
+
it is declined. After one wait runs out, later spawns from that thread are
|
|
312
|
+
declined at once until some thread finishes, so a pool held by long-running
|
|
313
|
+
threads costs one wait, not one per spawn. The wait uses `Atomics.wait`, which
|
|
314
|
+
workers and Node allow; where it is not allowed (a window's main thread) a spawn
|
|
315
|
+
never waits.
|
|
316
|
+
|
|
317
|
+
`spawnReport()` counts spawns from every thread (`spawned`, `waited`, and
|
|
318
|
+
`pool-exhausted` declines); `onSpawnDeclined` fires for the owning thread's
|
|
319
|
+
spawns. A Node worker started by a guest thread reports a guest fault on stderr
|
|
320
|
+
only; `onGuestError` covers workers the owning thread started and every browser
|
|
321
|
+
worker.
|
|
322
|
+
|
|
323
|
+
A browser worker that answers the probe without the pool protocol (a worker
|
|
324
|
+
script from an older SDK) still works: the owning thread sends it its threads by
|
|
325
|
+
`{t:"run"}` and frees it on `{t:"exit"}`, as before, and guest threads never
|
|
326
|
+
spawn onto it. A worker served from the matching SDK gets the fix.
|
|
327
|
+
|
|
328
|
+
`test/wasi-thread-pool-reuse-guest.test.js` compiles a guest that spawns 3
|
|
329
|
+
waves of `poolSize - 1` threads (the main thread runs one stripe), 3 waves of
|
|
330
|
+
`poolSize` threads, and 3 waves whose threads a non-main guest thread spawns, in
|
|
331
|
+
one invoke. It checks the output bytes and spawn counts in Node (explicit pool,
|
|
332
|
+
no pool, and 14,000 threads on at most 16 workers), in headless Chromium,
|
|
333
|
+
Firefox and WebKit, and across the three parity lanes:
|
|
334
|
+
|
|
335
|
+
```sh
|
|
336
|
+
SPACE_DATA_MODULE_SDK_ENABLE_BROWSER_THREADS=1 \
|
|
337
|
+
SPACE_DATA_MODULE_SDK_ENABLE_TRI_RUNTIME_PARITY=1 \
|
|
338
|
+
node --test test/wasi-thread-pool-reuse-guest.test.js
|
|
339
|
+
```
|
|
340
|
+
|
|
264
341
|
The old source path `src/testing/browserModuleHarness.js` remains a pure
|
|
265
342
|
compatibility re-export. New browser consumers should use the public
|
|
266
343
|
`space-data-module-sdk/host/browser-module` entry point.
|
|
@@ -312,8 +389,9 @@ participates:
|
|
|
312
389
|
Rules that make this contract honest:
|
|
313
390
|
|
|
314
391
|
- **The anchor names a DIRECTORY that serves the WHOLE chain.**
|
|
315
|
-
`wasiThreadBrowserWorker.mjs` imports `./wasiThreadWorkerRuntime.js
|
|
316
|
-
|
|
392
|
+
`wasiThreadBrowserWorker.mjs` imports `./wasiThreadWorkerRuntime.js` and
|
|
393
|
+
`./wasiThreadPool.js`, which import their own siblings. Staging the single
|
|
394
|
+
`.mjs` next to your bundle does **not** work.
|
|
317
395
|
- **A relative base resolves against the document**; absolute URLs pass through
|
|
318
396
|
unchanged.
|
|
319
397
|
- **No consumer-side `location` sniffing.** Forking worker resolution per
|
|
@@ -348,15 +426,17 @@ worker bundles and the browser capability probe.
|
|
|
348
426
|
|
|
349
427
|
| Option | Effect |
|
|
350
428
|
| --- | --- |
|
|
351
|
-
| `poolSize` | Browser: pre-start exactly this many workers, independent of `hardwareConcurrency - 1` (pools are sized for isolation: writers + lanes). Node: cap on live guest threads. Arming is partial: workers that fail to start are dropped, the rest serve. |
|
|
429
|
+
| `poolSize` | Browser: pre-start exactly this many workers, independent of `hardwareConcurrency - 1` (pools are sized for isolation: writers + lanes). Node: cap on live guest threads (the pool grows to it on demand; without it, to 1024). Arming is partial: workers that fail to start are dropped, the rest serve. |
|
|
352
430
|
| `extraImports` | Per-worker import objects, as structured-cloneable descriptors (below). Factories run once per worker. |
|
|
353
|
-
| `instanceId`, `onGuestError(instanceId, tid, error)` | Called when a guest thread traps or its worker dies (A36). A dead pooled worker leaves the pool. |
|
|
354
|
-
| `onSpawnDeclined({ reason, poolSize, declined })` | Called for every spawn that returns -1. Reasons: `pool-exhausted`, `pool-not-armed`, `threads-unavailable`, `pool-empty`, `worker-create-failed`, `dispatch-failed`, `hostcall-channel-missing`, `terminated`. |
|
|
431
|
+
| `instanceId`, `onGuestError(instanceId, tid, error)` | Called when a guest thread traps or its worker dies (A36). A dead pooled worker leaves the pool. In Node, for workers the owning thread started. |
|
|
432
|
+
| `onSpawnDeclined({ reason, poolSize, declined })` | Called for every spawn from the owning thread that returns -1. Reasons: `pool-exhausted`, `pool-not-armed`, `threads-unavailable`, `pool-empty`, `worker-create-failed`, `dispatch-failed`, `hostcall-channel-missing`, `terminated`. |
|
|
355
433
|
| `probeTimeoutMs` | Browser warm-pool probe deadline. |
|
|
434
|
+
| `spawnWaitMs` | How long a spawn that finds every pool thread busy waits for one to finish before it returns -1 (default 250; 0 never waits). Added in 0.8.25; see "one pool protocol" in §3. |
|
|
356
435
|
| `browserWorkerType: "classic"` | Spawn classic workers, for the blob bundles below. |
|
|
357
436
|
|
|
358
437
|
The returned host adds `spawnReport()`: `{ poolSize, armed, failedToArm, spawned,
|
|
359
|
-
declined, declinedByReason, lastDeclineReason, active, idle }
|
|
438
|
+
waited, declined, declinedByReason, lastDeclineReason, active, idle }` (Node adds
|
|
439
|
+
`workers`). The counts cover spawns from every thread of the process. The implicit
|
|
360
440
|
(no `poolSize`) path keeps its all-or-nothing arming.
|
|
361
441
|
|
|
362
442
|
`extraImports` entries (the same descriptors work in the engine worker through
|
|
@@ -461,7 +541,8 @@ same mirror serve reads of those paths from it without a round trip.
|
|
|
461
541
|
table in a SharedArrayBuffer (`createNodeSyncFsIoTable`). A handle is
|
|
462
542
|
`(slot << 8) | gen`; each worker opens its own fd for a slot on first use and
|
|
463
543
|
drops stale fds when the generation moves. Paths are confined below `root`,
|
|
464
|
-
including through symlinked parents
|
|
544
|
+
including through symlinked parents; a filesystem root (`root: "/"`) reaches
|
|
545
|
+
every path under it (through 0.8.24 every such path was `ACCESS`). `sync` is `fdatasync` (libuv issues
|
|
465
546
|
`F_FULLFSYNC` on darwin). `revokeNodeSyncFsIoInstance` follows A23: it sets the
|
|
466
547
|
revoked flag and waits for the instance's in-flight calls to drain. Fault
|
|
467
548
|
injection (§19, 22.3a-7) belongs to FlatSQL's Node host (T4); `interpose` wraps
|
|
@@ -580,7 +661,7 @@ guest-observed import calls (`trace`), in microseconds.
|
|
|
580
661
|
| #2 500 ms open, median of 3 runs: other threads' read p99, baseline / during | 85 / 85 | 440 / 400 | 60 / 60 |
|
|
581
662
|
| #2 longest other-thread read while the open was pending | 1020 | 18500 | 320 |
|
|
582
663
|
| A38 OPEN_DEFERRED: open returns in / first write waits (ms) | 3.8 / 504 | 28.8 / 511 | 5.2 / 755 |
|
|
583
|
-
| #3 `poolSize=6` on `hardwareConcurrency=2` | 6 workers; 7th spawn -1, reported `pool-exhausted` | same | same |
|
|
664
|
+
| #3 `poolSize=6` on `hardwareConcurrency=2` (`spawnWaitMs: 0` since 0.8.25) | 6 workers; 7th spawn -1, reported `pool-exhausted` | same | same |
|
|
584
665
|
| #5 link shim v2 (Node 25): 10,000 calls, lost completions | 0 with a notifying lane, 0 with a lane that never notifies, 0 spinning (`poll_ns = 0`) | | |
|
|
585
666
|
|
|
586
667
|
Chromium's same-partition A7 p99 varies with host load: 90, 110, 295 and 790
|
|
@@ -623,6 +704,15 @@ the fast-thread read p50 from 30-39 µs to 11-12 µs.
|
|
|
623
704
|
`symbolPrefix` / `methodSymbols` as authoritative (never re-derived), keeping a
|
|
624
705
|
legacy truncated-prefix artifact compatible.
|
|
625
706
|
|
|
707
|
+
- `test/wasi-thread-pool-reuse.test.js` — the pool protocol with no message
|
|
708
|
+
and no event-loop turn: 3 waves of `poolSize - 1` and of `poolSize` spawns, a
|
|
709
|
+
spawn that blocks until a thread finishes on another thread, a spawn from a
|
|
710
|
+
thread that is not the owner, the `spawnWaitMs` bound and the no-second-wait
|
|
711
|
+
rule, an older worker script and a late `{t:"exit"}`, a dead worker,
|
|
712
|
+
`terminateAll`.
|
|
713
|
+
- `test/wasi-thread-pool-reuse-guest.test.js` — the real wave guest in Node,
|
|
714
|
+
headless Chromium, Firefox and WebKit, and the three parity lanes (the
|
|
715
|
+
browser and parity runs are env-gated, see §3).
|
|
626
716
|
- `test/wasi-thread-pool-size.test.js` — explicit `poolSize` (6 workers on
|
|
627
717
|
`hardwareConcurrency=2`, the 7th spawn -1 and reported), partial arming,
|
|
628
718
|
extraImports delivery, `onGuestError`, classic workers.
|
package/package.json
CHANGED
|
@@ -384,6 +384,7 @@ async function instantiateBrowserModule(options = {}) {
|
|
|
384
384
|
// Browser warm-pool sizing: cap pooled workers at how many guest threads
|
|
385
385
|
// the module will actually ask for. Ignored by the Node lazy path.
|
|
386
386
|
requestedThreads: options.maxThreads,
|
|
387
|
+
poolSize: options.wasiThreadPoolSize,
|
|
387
388
|
hostcallChannel: options.threadHostcallChannel,
|
|
388
389
|
requiresHostcalls: needsHostBridge,
|
|
389
390
|
enableBrowserThreads: options.enableBrowserWasiThreads,
|
|
@@ -395,6 +396,7 @@ async function instantiateBrowserModule(options = {}) {
|
|
|
395
396
|
// packaged sibling, i.e. today's unbundled behavior.
|
|
396
397
|
browserWorkerBaseUrl: options.wasiThreadWorkerBaseUrl,
|
|
397
398
|
browserWorkerUrl: options.wasiThreadWorkerUrl,
|
|
399
|
+
spawnWaitMs: options.wasiThreadSpawnWaitMs,
|
|
398
400
|
});
|
|
399
401
|
importObject.wasi = {
|
|
400
402
|
...(importObject.wasi ?? {}),
|
|
@@ -469,6 +471,13 @@ async function instantiateBrowserModule(options = {}) {
|
|
|
469
471
|
* @param {number} [options.maxThreads] - Upper bound on guest threads; sizes the
|
|
470
472
|
* browser wasi-threads warm pool. Ignored by single-thread artifacts and by
|
|
471
473
|
* the Node lazy worker path.
|
|
474
|
+
* @param {number} [options.wasiThreadPoolSize] - Explicit wasi-threads pool size
|
|
475
|
+
* (createWasiThreadSpawn `poolSize`): the browser pre-starts exactly this many
|
|
476
|
+
* workers; Node caps live guest threads at it. Unset: the browser pool is
|
|
477
|
+
* min(hardwareConcurrency - 1, maxThreads) and Node spawns without a cap.
|
|
478
|
+
* @param {number} [options.wasiThreadSpawnWaitMs] - How long a guest spawn that
|
|
479
|
+
* finds every pooled thread busy waits for one to finish before
|
|
480
|
+
* pthread_create fails (createWasiThreadSpawn `spawnWaitMs`, default 250).
|
|
472
481
|
*/
|
|
473
482
|
export async function createBrowserModuleHarness(options = {}) {
|
|
474
483
|
let wasmSource = options.wasmSource;
|
|
@@ -578,6 +587,8 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
578
587
|
enableBrowserWasiThreads: options.enableBrowserWasiThreads,
|
|
579
588
|
wasiThreadWorkerBaseUrl: options.wasiThreadWorkerBaseUrl,
|
|
580
589
|
wasiThreadWorkerUrl: options.wasiThreadWorkerUrl,
|
|
590
|
+
wasiThreadSpawnWaitMs: options.wasiThreadSpawnWaitMs,
|
|
591
|
+
wasiThreadPoolSize: options.wasiThreadPoolSize,
|
|
581
592
|
});
|
|
582
593
|
const { instance, bridge, wasi, memory, threadHost } = activeContext;
|
|
583
594
|
let lastCommandContext = null;
|
|
@@ -842,6 +853,8 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
842
853
|
enableBrowserWasiThreads: options.enableBrowserWasiThreads,
|
|
843
854
|
wasiThreadWorkerBaseUrl: options.wasiThreadWorkerBaseUrl,
|
|
844
855
|
wasiThreadWorkerUrl: options.wasiThreadWorkerUrl,
|
|
856
|
+
wasiThreadSpawnWaitMs: options.wasiThreadSpawnWaitMs,
|
|
857
|
+
wasiThreadPoolSize: options.wasiThreadPoolSize,
|
|
845
858
|
});
|
|
846
859
|
lastCommandContext = commandContext;
|
|
847
860
|
try {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Self-contained classic-script worker bundles, spawned from blob: URLs
|
|
3
3
|
// (design A39). Rebuild after changing any file they bundle.
|
|
4
4
|
|
|
5
|
-
/** src/host/wasiThreadBrowserWorker.mjs, sha256
|
|
6
|
-
export const WASI_THREAD_POOL_WORKER_BUNDLE = "(()=>{var ct=new TextDecoder,it=new TextEncoder,J=\"$bin\";function at(e){return e instanceof Uint8Array||e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function ut(e){return e instanceof Uint8Array?e:e instanceof ArrayBuffer?new Uint8Array(e):new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}function z(e,t){if(e==null)return e??null;if(at(e)){let r=t.length;return t.push(ut(e)),{[J]:r}}return e instanceof Date?e.toISOString():typeof e==\"bigint\"?e.toString():Array.isArray(e)?e.map(r=>z(r,t)):typeof e==\"object\"?Object.fromEntries(Object.entries(e).filter(([,r])=>r!==void 0).map(([r,n])=>[r,z(n,t)])):e}function P(e,t){if(e==null)return e;if(Array.isArray(e))return e.map(r=>P(r,t));if(typeof e==\"object\"){let r=Object.keys(e);if(r.length===1&&r[0]===J){let n=e[J];if(!Number.isInteger(n)||n<0||n>=t.length)throw new RangeError(`Hostcall envelope references missing binary segment ${n}.`);return t[n]}return Object.fromEntries(r.map(n=>[n,P(e[n],t)]))}return e}function ee(e,t=[]){let r=it.encode(JSON.stringify(e??null)),n=4+r.length+4;for(let E of t)n+=4+E.length;let o=new Uint8Array(n),c=new DataView(o.buffer),a=0;c.setUint32(a,r.length,!0),a+=4,o.set(r,a),a+=r.length,c.setUint32(a,t.length,!0),a+=4;for(let E of t)c.setUint32(a,E.length,!0),a+=4,o.set(E,a),a+=E.length;return o}function W(e){if(!(e instanceof Uint8Array))throw new TypeError(\"Hostcall envelope must be a Uint8Array.\");if(e.length<8)throw new RangeError(\"Hostcall envelope is truncated.\");let t=new DataView(e.buffer,e.byteOffset,e.byteLength),r=0,n=t.getUint32(r,!0);if(r+=4,r+n+4>e.length)throw new RangeError(\"Hostcall envelope meta exceeds envelope bounds.\");let o=JSON.parse(ct.decode(e.subarray(r,r+n)));r+=n;let c=t.getUint32(r,!0);r+=4;let a=[];for(let E=0;E<c;E+=1){if(r+4>e.length)throw new RangeError(\"Hostcall envelope segment table is truncated.\");let d=t.getUint32(r,!0);if(r+=4,r+d>e.length)throw new RangeError(\"Hostcall envelope segment exceeds envelope bounds.\");a.push(e.subarray(r,r+d)),r+=d}return{meta:o,segments:a}}function fe(e){let{meta:t,segments:r}=W(e);return P(t,r)}var lt=new TextDecoder,re=\"space_data_module_host\",v=0,te=1,Br=Object.freeze([\"host.runtimeTarget\",\"host.listCapabilities\",\"host.listSupportedCapabilities\",\"host.listOperations\",\"host.hasCapability\",\"clock.now\",\"clock.monotonicNow\",\"clock.nowIso\",\"random.bytes\",\"schedule.parse\",\"schedule.matches\",\"schedule.next\",\"filesystem.resolvePath\"]);function ft(e,t){let r=String(e??\"\").trim();if(!r)throw new TypeError(`${t} is required.`);return r}function Ae(e){if(typeof e!=\"function\")throw new TypeError(\"getMemory must be a function returning WebAssembly.Memory.\");let t=e();if(!t||typeof t!=\"object\"||!(\"buffer\"in t))throw new TypeError(\"getMemory must return a WebAssembly.Memory-like object.\");let r=t.buffer;if(!(r instanceof ArrayBuffer||r instanceof SharedArrayBuffer))throw new TypeError(\"Hostcall memory buffer must be an ArrayBuffer or SharedArrayBuffer.\");return r}function _e(e,t,r,n){if(!Number.isInteger(t)||t<0)throw new RangeError(`${n} pointer must be a non-negative integer.`);if(!Number.isInteger(r)||r<0)throw new RangeError(`${n} length must be a non-negative integer.`);let o=Ae(e);if(t+r>o.byteLength)throw new RangeError(`${n} range exceeds guest memory bounds.`);return new Uint8Array(o,t,r)}function _t(e,t,r,n){if(!Number.isInteger(t)||t<0)throw new RangeError(\"Response pointer must be a non-negative integer.\");if(!Number.isInteger(n)||n<0)throw new RangeError(\"Response max length must be a non-negative integer.\");let o=r instanceof Uint8Array?r:new Uint8Array(r),c=Ae(e),a=Math.min(o.length,n);if(t+a>c.byteLength)throw new RangeError(\"Response range exceeds guest memory bounds.\");return new Uint8Array(c,t,a).set(o.subarray(0,a)),a}function Et(e){if(e.length===0)return null;let{meta:t,segments:r}=W(e);return P(t,r)}function Ee(e,t=null){return{name:e?.name??\"Error\",message:e?.message??String(e),code:e?.code??null,operation:e?.operation??t,capability:e?.capability??null}}function At(e){return e!==null&&typeof e==\"object\"&&typeof e.then==\"function\"}function de(e={}){let t=e.dispatch;if(typeof t!=\"function\")throw new TypeError(\"createHostcallBridge requires a dispatch function.\");let r=e.getMemory,n=ft(e.moduleName??re,\"Hostcall import module name\"),o=Number.isInteger(e.maxRequestBytes)?e.maxRequestBytes:16*1024*1024,c=Number.isInteger(e.maxResponseBytes)?e.maxResponseBytes:64*1024*1024,a=v,E={ok:!0,result:null},d=ee(E,[]);function p(s,i){let u=[],m=z(i,u),S=ee(m,u);if(S.length>c)throw new Error(`Hostcall response exceeds ${c} byte limit.`);a=s,E=i,d=S}function A(s,i,u,m){try{if(m>o)throw new Error(`Hostcall request exceeds ${o} byte limit.`);let S=lt.decode(_e(r,s,i,\"Operation\")),w=Et(_e(r,u,m,\"Payload\")),L=t(S,w);if(At(L))throw new Error(`Operation \"${S}\" returned a Promise. The synchronous hostcall ABI only supports synchronous operations.`);return p(v,{ok:!0,result:L===void 0?null:L}),v}catch(S){try{p(te,{ok:!1,error:Ee(S)})}catch(w){p(te,{ok:!1,error:Ee(w)})}return te}}function T(){return d.length}function f(s,i){return _t(r,s,d,i)}function _(){return p(v,{ok:!0,result:null}),v}function h(){return a}return{moduleName:n,imports:{[n]:{call:A,response_len:T,read_response:f,clear_response:_,last_status_code:h}},getLastEnvelope(){return structuredClone(E)},getLastResponseBytes(){return new Uint8Array(d)},getLastResponseEnvelope(){let{meta:s,segments:i}=W(d);return P(s,i)}}}var Cr=Object.freeze({READ:1,WRITE:2,CREATE:4,EXCL:8,TRUNC:16,DELETE_ON_CLOSE:32,PROBE:64,UNLINK:128,CREATE_PARENTS:256,UNLINK_IF_UNUSED:512,OPEN_DEFERRED:1024}),Nr=Object.freeze({OK:0,GENERIC:-1,NOENT:-2,ACCESS:-3,IO:-4,NOSPACE:-5,BADHANDLE:-6,BUSY:-7});var Dr=Object.freeze([\"flatsql_io_open\",\"flatsql_io_read\",\"flatsql_io_write\",\"flatsql_io_truncate\",\"flatsql_io_sync\",\"flatsql_io_size\",\"flatsql_io_close\"]),j=4096;var Fr=typeof TextDecoder==\"function\"?new TextDecoder(\"utf-8\",{fatal:!0}):null;function Se(e){let t=2166136261;for(let r=0;r<e.length;r+=1)t^=e[r],t=Math.imul(t,16777619);return t>>>0}var dt=1330201683,St=1,pt=0,yt=1,mt=2,ht=3,Rt=4,ye=5;var Ot=7;var It=9,Z=10,Tt=11;var gt=13,ge=64,me=ge*4;var wt=1;var xt=1,Lt=2,Bt=3,k=32767,V=0,we=1,he=2,bt=3,Ct=4,Nt=5,Dt=6,Ft=7,Mt=8,Ht=9,Re=10,xe=11,Ut=12,Pt=13,Qt=8,Le=9,ne=128,oe=0,vt=1,qt=2;var kt=4,Vt=0;var Yt=0,Gt=1,$t=1,q=2,X=3,Kt=4,zt=5,Wt=6,jt=7;var Ur=64*1024;var Oe=250,Xt=20;function Ie(){return typeof performance<\"u\"&&performance.now?performance.now():Date.now()}function Zt(e,t){return Math.ceil(e/t)*t}function Be(e){if(typeof SharedArrayBuffer!=\"function\"||!(e instanceof SharedArrayBuffer))throw new TypeError(\"The SAB I/O channel requires a SharedArrayBuffer (cross-origin isolation in browsers).\")}function Jt(e){Be(e);let t=new Int32Array(e,0,ge);if(t[pt]!==dt||t[yt]!==St)throw new TypeError(\"Not a SAB I/O channel buffer (bad magic or version).\");let r=t[mt],n=t[ht],o=t[Rt],c=t[Tt],a=Zt(me+o*4,64),E=new Int32Array(e,me,o),d=[];for(let p=0;p<r;p+=1){let A=a+p*n;d.push({index:p,base:A,i32:new Int32Array(e,A,ne/4),f64:new Float64Array(e,A,ne/8),data:new Uint8Array(e,A+ne,c)})}return{buffer:e,header:t,instances:E,slots:d,slotCount:r,slotBytes:n,dataBytes:c,maxInstances:o,channelId:t[gt]}}function er(e){return`sdm-sab-io-doorbell-${e}`}function tr(e,t){Atomics.add(e.header,ye,1),Atomics.notify(e.header,ye),Atomics.load(e.header,Ot)===wt&&t()?.postMessage(0)}function rr(e){let t=null;return{get(){return!t&&typeof BroadcastChannel==\"function\"&&(t=new BroadcastChannel(e)),t},close(){t?.close(),t=null}}}var nr=typeof TextEncoder==\"function\"?new TextEncoder:null;function or(){return(Math.random()*2147483646|0)+1}function sr(e,t){let r=(Atomics.add(e.header,It,1)>>>0)%e.slotCount;for(let n=0;n<e.slotCount;n+=1){let o=e.slots[(r+n)%e.slotCount];if(Atomics.compareExchange(o.i32,V,oe,vt)===oe)return Atomics.store(o.i32,we,t),o}return null}function Te(e,t){Atomics.store(t.i32,we,0),Atomics.store(t.i32,V,oe),Atomics.add(e.header,Z,1),Atomics.notify(e.header,Z)}function cr(e,t,r){let n=e.i32;n[Ct]=t,n[Nt]=r.instanceId??k,n[Dt]=r.handle??-1,n[Ft]=r.flags??0,n[Mt]=r.ptr??0,n[Ht]=r.len??0,n[Pt]=r.dataInSlot?Gt:Yt,n[xe]=0,e.f64[Qt]=r.offset??0,e.f64[Le]=0,r.path?(e.data.set(r.path,0),n[Re]=r.path.length):n[Re]=0}function ir(e){return Atomics.load(e.i32,xe)}function be(e={}){Be(e.buffer);let t=Jt(e.buffer),r=Number.isInteger(e.instanceId)?e.instanceId:k;if(r!==k&&(r<0||r>=t.maxInstances))throw new RangeError(`instanceId ${r} is outside 0..${t.maxInstances-1}.`);let n=typeof e.getMemory==\"function\"?e.getMemory:()=>null,o=Number.isFinite(e.spinMicros)?Math.max(0,e.spinMicros):Xt,c=or(),a=rr(er(t.channelId)),E=0;function d(){for(;;){let s=Atomics.load(t.header,Z),i=sr(t,c);if(i)return i;Atomics.wait(t.header,Z,s,Oe)}}function p(s,i,u){let m=Atomics.load(s.i32,he)+1|0||1;cr(s,i,u),Atomics.store(s.i32,Ut,Vt),Atomics.store(s.i32,he,m),Atomics.store(s.i32,V,qt),tr(t,a.get);let S=o>0?Ie()+o/1e3:0;for(;;){let w=Atomics.load(s.i32,V);if(w===kt&&Atomics.load(s.i32,bt)===m)break;S>0&&Ie()<S||Atomics.wait(s.i32,V,w,Oe)}return E+=1,{status:ir(s),result:s.f64[Le]}}function A(s,i){let u=d();try{return p(u,s,i)}finally{Te(t,u)}}function T(){return r!==k&&Atomics.load(t.instances,r)===xt}function f(){if(r===k)return!1;let s=Atomics.load(t.instances,r);return s===Lt||s===Bt}function _(s,i,u,m){let S=0;for(;S<u.length;){let w=Math.min(t.dataBytes,u.length-S),L=d(),b;try{s===X&&L.data.set(u.subarray(S,S+w),0),b=p(L,s,{instanceId:r,dataInSlot:!0,handle:i,ptr:0,len:w,offset:m+S}).status,s===q&&b>0&&u.set(L.data.subarray(0,b),S)}finally{Te(t,L)}if(b<0)return S>0&&s===q?S:b;if(S+=b,b<w)break}return S}function h(s,i){let u=n(),m=u?.buffer??u;return!m||s<0||i<0||s+i>m.byteLength?null:new Uint8Array(m,s,i)}return{instanceId:r,get requests(){return E},open(s,i){let u=typeof s==\"string\"?nr.encode(s):s;return!(u instanceof Uint8Array)||u.length===0?-1:u.length>Math.min(t.dataBytes,j)?-1:A($t,{instanceId:r,flags:i|0,path:u}).status},read(s,i,u,m){if(u===0)return 0;if(T())return A(q,{instanceId:r,handle:s,ptr:i,len:u,offset:m}).status;let S=h(i,u);return S?_(q,s,S,m):f()?-3:-1},write(s,i,u,m){if(u===0)return 0;if(T())return A(X,{instanceId:r,handle:s,ptr:i,len:u,offset:m}).status;let S=h(i,u);return S?_(X,s,S,m):f()?-3:-1},readInto(s,i,u){return i.length===0?0:_(q,s,i,u)},writeFrom(s,i,u){return i.length===0?0:_(X,s,i,u)},truncate(s,i){return A(Kt,{instanceId:r,handle:s,offset:i}).status},sync(s){return A(zt,{instanceId:r,handle:s}).status},size(s){let{status:i,result:u}=A(Wt,{instanceId:r,handle:s});return i<0?i:u},close(s){return A(jt,{instanceId:r,handle:s}).status},release(){a.close()}}}var ar=typeof TextEncoder==\"function\"?new TextEncoder:null;function ur(e){let t=2166136261;for(let r=0;r<e.length;r+=1)t^=e[r],t=Math.imul(t,16777619);return t|0}var Ce=new WeakMap;function Ne(e){let t=Ce.get(e);if(t)return t;let r=new Int32Array(e,0,16);if(r[0]!==1380795475||r[1]!==1)throw new TypeError(\"Not a SAB I/O mirror buffer.\");let n=r[2],o=r[3],c=r[4],a=64,E=a+n*32,d=E+n*c;return t={entries:n,entryBytes:o,maxPathBytes:c,i32:new Int32Array(e,a,n*32/4),f64:new Float64Array(e,a,n*32/8),paths:new Uint8Array(e,E,n*c),data:new Uint8Array(e,d,n*o)},Ce.set(e,t),t}function lr(e){return typeof e==\"string\"?ar.encode(e):e}function fr(e,t,r){let n=t*8;if(Atomics.load(e.i32,n+3)!==r.length)return!1;let o=t*e.maxPathBytes;for(let c=0;c<r.length;c+=1)if(e.paths[o+c]!==r[c])return!1;return!0}function _r(e,t,r){let n=(r>>>0)%e.entries;for(let o=0;o<e.entries;o+=1){let c=n*8,a=Atomics.load(e.i32,c+0);if(a===0)return-1;if((a===2||a===3)&&Atomics.load(e.i32,c+2)===r&&fr(e,n,t))return n;n=(n+1)%e.entries}return-1}function De(e,t){let r=Ne(e),n=lr(t);if(n.length>r.maxPathBytes)return-1;let o=_r(r,n,ur(n));return o<0?-1:Atomics.load(r.i32,o*(32/4)+0)===2?o:-1}function Fe(e,t,r,n){let o=Ne(e),c=t*(32/4),a=t*(32/8)+3,E=t*o.entryBytes;for(let d=0;d<64;d+=1){let p=Atomics.load(o.i32,c+1);if(p&1)continue;if(Atomics.load(o.i32,c+0)!==2)return-1;let A=o.f64[a],T=Atomics.load(o.i32,c+4),f;if(n>=A)f=0;else{let _=Math.min(r.length,A-n);n+_>T?f=-1:(r.set(o.data.subarray(E+n,E+n+_),0),f=_)}if(Atomics.load(o.i32,c+1)===p)return f}return-1}function Me(e=[\"/h.fsh\"]){let t=Array.from(e,String);return r=>{let n=String(r);for(let o of t)if(n.endsWith(o)||n===o.replace(/^\\//,\"\"))return!0;return!1}}var Er=\"flatsql-io\",N=Object.freeze({open:1,read:2,write:3,truncate:4,sync:5,size:6,close:7,mirrorRead:8}),He=24,Ue=16777215;function se(){return typeof performance<\"u\"&&performance.now?performance.now()*1e3:Date.now()*1e3}function Ar(e){if(!e?.buffer)return null;let t=new Int32Array(e.buffer,0,4),r=t[1],n=new Float64Array(e.buffer,16,r),o=new Uint8Array(e.buffer,16+r*8,r);return(c,a)=>{let E=Atomics.add(t,0,1);E<r&&(n[E]=se()-a,o[E]=c)}}function dr(e,t,r){if(!e||r<=0||r>j||t<0)return null;let n=e.buffer??e;return t+r>n.byteLength?null:new Uint8Array(n,t,r).slice()}function Sr(e={}){let t=e.getMemory;if(typeof t!=\"function\")throw new TypeError(\"createFlatsqlIoImports requires getMemory().\");let r=Array.isArray(e.provider)?e.provider:[e.provider];if(r.length===0||r.some(f=>!f||typeof f.open!=\"function\"))throw new TypeError(\"createFlatsqlIoImports requires at least one provider.\");if(r.length>127)throw new RangeError(\"At most 127 providers can be routed.\");let n=r.length>1,o=Ar(e.trace),c=e.mirror?.buffer??null,a=c?Me(e.mirror.suffixes??[\"/h.fsh\"]):null,E=new Map,d=new TextDecoder;function p(f){if(!n)return{provider:r[0],local:f};let _=f>>>He,h=r[_];return h?{provider:h,local:f&Ue}:null}function A(f,_,h){let s=o?se():0,i;try{i=h()}catch{i=_}return o&&o(f,s),i}return{env:{flatsql_io_open(f,_,h){return A(N.open,-1,()=>{let s=dr(t(),f,_);if(!s)return-1;let i=n?Se(s)%r.length:0,u=r[i].open(s,h|0);if(u<0)return u;if(n&&u>Ue)return-4;let m=n?i<<He|u:u;if(a){let S=d.decode(s);a(S)&&E.set(m,S)}return m})},flatsql_io_read(f,_,h,s){if(c&&E.has(f)){let i=o?se():0;try{let u=t(),m=u.buffer??u;if(_>=0&&h>=0&&_+h<=m.byteLength){let S=De(c,E.get(f));if(S>=0){let w=Fe(c,S,new Uint8Array(m,_,h),s);if(w>=0)return o&&o(N.mirrorRead,i),w}}}catch{}}return A(N.read,-4,()=>{let i=p(f);return i?i.provider.read(i.local,_,h,s):-6})},flatsql_io_write(f,_,h,s){return A(N.write,-4,()=>{let i=p(f);return i?i.provider.write(i.local,_,h,s):-6})},flatsql_io_truncate(f,_){return A(N.truncate,-4,()=>{let h=p(f);return h?h.provider.truncate(h.local,_):-6})},flatsql_io_sync(f){return A(N.sync,-4,()=>{let _=p(f);return _?_.provider.sync(_.local):-6})},flatsql_io_size(f){return A(N.size,-4,()=>{let _=p(f);return _?_.provider.size(_.local):-6})},flatsql_io_close(f){return A(N.close,-4,()=>{E.delete(f);let _=p(f);return _?_.provider.close(_.local):-6})}}}}function pr(e,{getMemory:t}){let r=Array.isArray(e.channels)?e.channels:[e.channel??e.buffer];if(r.length===0||r.some(c=>!(c instanceof SharedArrayBuffer)))throw new TypeError(\"A flatsql-io descriptor needs channels: SharedArrayBuffer[].\");let n=r.map(c=>be({buffer:c,instanceId:e.instanceId,getMemory:t}));return{imports:Sr({getMemory:t,provider:n,mirror:e.mirror,trace:e.trace}),close(){for(let c of n)c.release()}}}function Pe(e,t){let r=[],n=[];for(let o of e??[]){let c;if(typeof o==\"function\")c=o(t);else if(o&&o.provider===Er)c=pr(o,t);else if(o&&typeof o.factory==\"function\")c=o.factory({...t,config:o.config});else throw new TypeError(`Unresolvable extraImports entry ${JSON.stringify(o?.provider??o?.moduleUrl??typeof o)}; pass a factory function, a { provider: \"flatsql-io\" } descriptor, or (module workers) a { moduleUrl } descriptor.`);c&&c.imports&&typeof c.close==\"function\"?(r.push(c.imports),n.push(c.close)):c&&r.push(c)}return{fragments:r,close(){for(let o of n)try{o()}catch{}}}}function Qe(e,t){for(let r of t)for(let[n,o]of Object.entries(r??{}))e[n]={...e[n]??{},...o};return e}var Y=0,yr=1,mr=2,qe=4,ce=0,ve=1;var hr=0;var ie=qe*4,Rr=4*1024*1024;function Or(e){if(typeof SharedArrayBuffer!=\"function\"||!(e instanceof SharedArrayBuffer))throw new TypeError(\"SAB hostcall channel requires a SharedArrayBuffer (cross-origin isolation in browsers).\")}function ke(e={}){if(typeof SharedArrayBuffer!=\"function\")throw new Error(\"SharedArrayBuffer is unavailable; the async hostcall bridge requires it (browsers additionally require cross-origin isolation: COOP+COEP).\");let t=Number.isInteger(e.maxResponseBytes)?e.maxResponseBytes:Rr;if(t<=0)throw new RangeError(\"maxResponseBytes must be a positive integer.\");return new SharedArrayBuffer(ie+t)}function Ve(e={}){Or(e.buffer);let t=e.postRequest;if(typeof t!=\"function\")throw new TypeError(\"createSabHostcallClientDispatch requires a postRequest function.\");let r=Number.isFinite(e.timeoutMs)&&e.timeoutMs>0?e.timeoutMs:12e4,n=new Int32Array(e.buffer,0,qe),o=e.buffer.byteLength-ie;return function(a,E=null){if(Atomics.store(n,Y,ve),t({operation:a,params:E}),Atomics.wait(n,Y,ve,r)===\"timed-out\")throw Atomics.store(n,Y,ce),new Error(`Hostcall \"${a}\" timed out after ${r}ms waiting for the controlling thread.`);let p=Atomics.load(n,yr),A=Atomics.load(n,mr);if(A<0||A>o)throw Atomics.store(n,Y,ce),new RangeError(`Hostcall \"${a}\" response length ${A} exceeds channel capacity ${o}.`);let T=new Uint8Array(A);T.set(new Uint8Array(e.buffer,ie,A)),Atomics.store(n,Y,ce);let f=fe(T);if(p!==hr){let _=new Error(f?.message??`Hostcall \"${a}\" failed on the host thread.`);throw _.name=f?.name??\"Error\",_.code=f?.code??null,_.operation=f?.operation??a,_.capability=f?.capability??null,_}return f}}var ae=class extends Error{constructor(t){super(`WASI exit with code ${t}`),this.name=\"WasiExitError\",this.code=t}};function Ir(e,t,r,n){for(;;){let o=Atomics.load(e,t);if(r>n-o)return-1;if(Atomics.compareExchange(e,t,o,o+r)===o)return o}}function Ye(e={}){let t=e.processState,r=t?.args??e.args??[],n=t?.env??e.env??{},o=t?.input??new Uint8Array(e.stdinBytes??[]),c=e.logOutput===!0,a=e.performance??globalThis.performance??{now:()=>Date.now(),timeOrigin:0},E=e.crypto??globalThis.crypto??null,d=[],p=[],A=0,T=null;function f(l){T=l}function _(){return T}function h(){return new Uint8Array(T.buffer)}function s(){return new DataView(T.buffer)}let u=Object.entries(n).map(([l,y])=>`${l}=${y}`).map(l=>new TextEncoder().encode(l)),m=r.map(l=>new TextEncoder().encode(l));function S(l,y,O){let I;if(l===0)I=BigInt(Math.round((a.timeOrigin+a.now())*1e6));else if(l===1)I=BigInt(Math.round(a.now()*1e6));else return 28;return s().setBigUint64(O,I,!0),0}function w(l,y,O,I){if(l!==1&&l!==2)return 8;let R=l===1?d:p,g=0,M=s(),H=h();for(let U=0;U<O;U++){let K=y+U*8,D=M.getUint32(K,!0),x=M.getUint32(K+4,!0);if(t){let B=l===1?t.stdout:t.stderr,le=Ir(t.control,l,x,B.length);if(le<0)return 51;B.set(H.subarray(D,D+x),le)}else R.push(H.slice(D,D+x));g+=x}return M.setUint32(I,g,!0),0}function L(l,y,O,I){if(l!==0)return s().setUint32(I,0,!0),8;let R=s(),g=h(),M=0;for(let H=0;H<O;H+=1){let U=y+H*8,K=R.getUint32(U,!0),D=R.getUint32(U+4,!0),x,B;if(t)do x=Atomics.load(t.control,0),B=Math.min(D,o.length-x);while(Atomics.compareExchange(t.control,0,x,x+B)!==x);else x=A,B=Math.min(D,o.length-x),A+=B;if(B===0){if(x>=o.length)break;continue}g.set(o.subarray(x,x+B),K),M+=B}return R.setUint32(I,M,!0),0}function b(l){return l<=2?0:8}function Ke(l,y,O,I){return l<=2?70:8}function ze(l,y){if(l>2)return 8;let O=s();return O.setUint8(y,2),O.setUint16(y+2,0,!0),O.setBigUint64(y+8,0n,!0),O.setBigUint64(y+16,0n,!0),0}function We(l,y){return l<=2?0:8}function je(l,y){return 8}function Xe(l,y,O){return 8}function Ze(){return 8}function Je(l,y){let O=s();O.setUint32(l,u.length,!0);let I=0;for(let R of u)I+=R.length+1;return O.setUint32(y,I,!0),0}function et(l,y){let O=s(),I=h(),R=y;for(let g=0;g<u.length;g++)O.setUint32(l+g*4,R,!0),I.set(u[g],R),R+=u[g].length,I[R]=0,R+=1;return 0}function tt(l,y){let O=s();O.setUint32(l,m.length,!0);let I=0;for(let R of m)I+=R.length+1;return O.setUint32(y,I,!0),0}function rt(l,y){let O=s(),I=h(),R=y;for(let g=0;g<m.length;g++)O.setUint32(l+g*4,R,!0),I.set(m[g],R),R+=m[g].length,I[R]=0,R+=1;return 0}function nt(l,y){return E?.getRandomValues?(E.getRandomValues(h().subarray(l,l+y)),0):52}function ot(l){throw t&&(Atomics.store(t.control,4,l),Atomics.store(t.control,3,1)),c&&ue(),new ae(l)}function st(){return 0}function ue(){if(d.length>0){let l=$(d);if(c){let y=new TextDecoder().decode(l);y&&console.log(y)}d.length=0}if(p.length>0){let l=$(p);if(c){let y=new TextDecoder().decode(l);y&&console.warn(y)}p.length=0}}function $(l){let y=0;for(let R of l)y+=R.length;let O=new Uint8Array(y),I=0;for(let R of l)O.set(R,I),I+=R.length;return O}return{imports:{wasi_snapshot_preview1:{clock_time_get:S,fd_write:w,fd_read:L,fd_close:b,fd_seek:Ke,fd_fdstat_get:ze,fd_fdstat_set_flags:We,fd_prestat_get:je,fd_prestat_dir_name:Xe,path_open:Ze,environ_sizes_get:Je,environ_get:et,args_sizes_get:tt,args_get:rt,random_get:nt,proc_exit:ot,sched_yield:st}},setMemory:f,getMemory:_,flushOutput:ue,get stdout(){return t?t.stdout.slice(0,Atomics.load(t.control,1)):$(d)},get stderr(){return t?t.stderr.slice(0,Atomics.load(t.control,2)):$(p)}}}var Tr=\"sdm.thread-hostcall\";function gr(e){return WebAssembly.Module.imports(e).some(t=>t.module===re)}function wr(e){if(!e||typeof e!=\"object\")throw new Error(\"A threaded guest that imports space_data_module_host requires an owning hostcall channel.\");let t=String(e.channelName??\"\").trim(),r=String(e.token??\"\").trim();if(!t||!r)throw new Error(\"The owning thread-hostcall channel name and token are required.\");if(typeof BroadcastChannel!=\"function\")throw new Error(\"BroadcastChannel is required for nested pthread hostcalls.\");let n=ke({maxResponseBytes:e.maxResponseBytes}),o=new BroadcastChannel(t),c=1;return{dispatch:Ve({buffer:n,timeoutMs:e.timeoutMs,postRequest(E){o.postMessage({type:Tr,token:r,requestId:c++,buffer:n,...E})}}),close(){o.close()}}}function Ge({wasmModule:e,memory:t,hostcallChannel:r,processState:n,extraImports:o,workerIndex:c,tid:a}={}){let E=Ye({processState:n});E.setMemory(t);let d=null,p=null,A={...E.imports,env:{memory:t},wasi:{\"thread-spawn\":()=>-1}};if(gr(e)){p=wr(r);let f=de({dispatch:p.dispatch,getMemory:()=>d?.exports?.memory??t});Object.assign(A,f.imports)}let T=Pe(o,{memory:t,getMemory:()=>d?.exports?.memory??t,workerIndex:c??null,tid:a??null});return Qe(A,T.fragments),A.env.memory=t,{imports:A,instantiate(){return d=new WebAssembly.Instance(e,A),E.setMemory(d.exports.memory??t),d},close(){p?.close(),T.close()}}}async function $e(e){let t=[];for(let r of e??[])if(r&&typeof r.moduleUrl==\"string\"){let o=(await import(r.moduleUrl))[r.exportName??\"default\"];if(typeof o!=\"function\")throw new TypeError(`extraImports module ${r.moduleUrl} exports no factory \"${r.exportName??\"default\"}\".`);t.push({factory:o,config:r.config??null})}else t.push(r);return t}var G=null;self.onmessage=async e=>{let t=e.data??{};if(t.t===\"probe\"){try{let r=await $e(t.extraImports??[]);G=Ge({wasmModule:t.wasmModule,memory:t.memory,hostcallChannel:t.hostcallChannel??null,processState:t.processState,extraImports:r,workerIndex:t.workerIndex}),G.instantiate(),self.postMessage({t:\"ready\",ok:!0})}catch(r){G?.close(),G=null,self.postMessage({t:\"ready\",ok:!1,error:String(r?.message??r)})}return}if(t.t===\"run\"){try{G.instantiate().exports.wasi_thread_start(t.tid,t.startArg)}catch(r){r&&r.name===\"WasiExitError\"||(console.error(`[wasi-thread] guest thread ${t.tid} trapped:`,r),self.postMessage({t:\"error\",tid:t.tid,error:String(r?.message??r)}))}self.postMessage({t:\"exit\",tid:t.tid})}};})();\n";
|
|
7
|
-
export const WASI_THREAD_POOL_WORKER_BUNDLE_SHA256 = "
|
|
5
|
+
/** src/host/wasiThreadBrowserWorker.mjs, sha256 9098a64250e10a167cc6d4c24d535283f77245101f1b3710fdd71f0ce0fbcae6. */
|
|
6
|
+
export const WASI_THREAD_POOL_WORKER_BUNDLE = "(()=>{var ge=new TextDecoder,we=new TextEncoder,at=\"$bin\";function xe(t){return t instanceof Uint8Array||t instanceof ArrayBuffer||ArrayBuffer.isView(t)}function Le(t){return t instanceof Uint8Array?t:t instanceof ArrayBuffer?new Uint8Array(t):new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}function J(t,e){if(t==null)return t??null;if(xe(t)){let r=e.length;return e.push(Le(t)),{[at]:r}}return t instanceof Date?t.toISOString():typeof t==\"bigint\"?t.toString():Array.isArray(t)?t.map(r=>J(r,e)):typeof t==\"object\"?Object.fromEntries(Object.entries(t).filter(([,r])=>r!==void 0).map(([r,n])=>[r,J(n,e)])):t}function Q(t,e){if(t==null)return t;if(Array.isArray(t))return t.map(r=>Q(r,e));if(typeof t==\"object\"){let r=Object.keys(t);if(r.length===1&&r[0]===at){let n=t[at];if(!Number.isInteger(n)||n<0||n>=e.length)throw new RangeError(`Hostcall envelope references missing binary segment ${n}.`);return e[n]}return Object.fromEntries(r.map(n=>[n,Q(t[n],e)]))}return t}function ut(t,e=[]){let r=we.encode(JSON.stringify(t??null)),n=4+r.length+4;for(let f of e)n+=4+f.length;let o=new Uint8Array(n),c=new DataView(o.buffer),a=0;c.setUint32(a,r.length,!0),a+=4,o.set(r,a),a+=r.length,c.setUint32(a,e.length,!0),a+=4;for(let f of e)c.setUint32(a,f.length,!0),a+=4,o.set(f,a),a+=f.length;return o}function tt(t){if(!(t instanceof Uint8Array))throw new TypeError(\"Hostcall envelope must be a Uint8Array.\");if(t.length<8)throw new RangeError(\"Hostcall envelope is truncated.\");let e=new DataView(t.buffer,t.byteOffset,t.byteLength),r=0,n=e.getUint32(r,!0);if(r+=4,r+n+4>t.length)throw new RangeError(\"Hostcall envelope meta exceeds envelope bounds.\");let o=JSON.parse(ge.decode(t.subarray(r,r+n)));r+=n;let c=e.getUint32(r,!0);r+=4;let a=[];for(let f=0;f<c;f+=1){if(r+4>t.length)throw new RangeError(\"Hostcall envelope segment table is truncated.\");let y=e.getUint32(r,!0);if(r+=4,r+y>t.length)throw new RangeError(\"Hostcall envelope segment exceeds envelope bounds.\");a.push(t.subarray(r,r+y)),r+=y}return{meta:o,segments:a}}function Ot(t){let{meta:e,segments:r}=tt(t);return Q(e,r)}var Be=new TextDecoder,ft=\"space_data_module_host\",G=0,lt=1,fn=Object.freeze([\"host.runtimeTarget\",\"host.listCapabilities\",\"host.listSupportedCapabilities\",\"host.listOperations\",\"host.hasCapability\",\"clock.now\",\"clock.monotonicNow\",\"clock.nowIso\",\"random.bytes\",\"schedule.parse\",\"schedule.matches\",\"schedule.next\",\"filesystem.resolvePath\"]);function be(t,e){let r=String(t??\"\").trim();if(!r)throw new TypeError(`${e} is required.`);return r}function wt(t){if(typeof t!=\"function\")throw new TypeError(\"getMemory must be a function returning WebAssembly.Memory.\");let e=t();if(!e||typeof e!=\"object\"||!(\"buffer\"in e))throw new TypeError(\"getMemory must return a WebAssembly.Memory-like object.\");let r=e.buffer;if(!(r instanceof ArrayBuffer||r instanceof SharedArrayBuffer))throw new TypeError(\"Hostcall memory buffer must be an ArrayBuffer or SharedArrayBuffer.\");return r}function Tt(t,e,r,n){if(!Number.isInteger(e)||e<0)throw new RangeError(`${n} pointer must be a non-negative integer.`);if(!Number.isInteger(r)||r<0)throw new RangeError(`${n} length must be a non-negative integer.`);let o=wt(t);if(e+r>o.byteLength)throw new RangeError(`${n} range exceeds guest memory bounds.`);return new Uint8Array(o,e,r)}function Ce(t,e,r,n){if(!Number.isInteger(e)||e<0)throw new RangeError(\"Response pointer must be a non-negative integer.\");if(!Number.isInteger(n)||n<0)throw new RangeError(\"Response max length must be a non-negative integer.\");let o=r instanceof Uint8Array?r:new Uint8Array(r),c=wt(t),a=Math.min(o.length,n);if(e+a>c.byteLength)throw new RangeError(\"Response range exceeds guest memory bounds.\");return new Uint8Array(c,e,a).set(o.subarray(0,a)),a}function Ne(t){if(t.length===0)return null;let{meta:e,segments:r}=tt(t);return Q(e,r)}function gt(t,e=null){return{name:t?.name??\"Error\",message:t?.message??String(t),code:t?.code??null,operation:t?.operation??e,capability:t?.capability??null}}function De(t){return t!==null&&typeof t==\"object\"&&typeof t.then==\"function\"}function xt(t={}){let e=t.dispatch;if(typeof e!=\"function\")throw new TypeError(\"createHostcallBridge requires a dispatch function.\");let r=t.getMemory,n=be(t.moduleName??ft,\"Hostcall import module name\"),o=Number.isInteger(t.maxRequestBytes)?t.maxRequestBytes:16*1024*1024,c=Number.isInteger(t.maxResponseBytes)?t.maxResponseBytes:64*1024*1024,a=G,f={ok:!0,result:null},y=ut(f,[]);function m(s,i){let u=[],p=J(i,u),E=ut(p,u);if(E.length>c)throw new Error(`Hostcall response exceeds ${c} byte limit.`);a=s,f=i,y=E}function S(s,i,u,p){try{if(p>o)throw new Error(`Hostcall request exceeds ${o} byte limit.`);let E=Be.decode(Tt(r,s,i,\"Operation\")),g=Ne(Tt(r,u,p,\"Payload\")),w=e(E,g);if(De(w))throw new Error(`Operation \"${E}\" returned a Promise. The synchronous hostcall ABI only supports synchronous operations.`);return m(G,{ok:!0,result:w===void 0?null:w}),G}catch(E){try{m(lt,{ok:!1,error:gt(E)})}catch(g){m(lt,{ok:!1,error:gt(g)})}return lt}}function T(){return y.length}function _(s,i){return Ce(r,s,y,i)}function A(){return m(G,{ok:!0,result:null}),G}function l(){return a}return{moduleName:n,imports:{[n]:{call:S,response_len:T,read_response:_,clear_response:A,last_status_code:l}},getLastEnvelope(){return structuredClone(f)},getLastResponseBytes(){return new Uint8Array(y)},getLastResponseEnvelope(){let{meta:s,segments:i}=tt(y);return Q(s,i)}}}var An=Object.freeze({READ:1,WRITE:2,CREATE:4,EXCL:8,TRUNC:16,DELETE_ON_CLOSE:32,PROBE:64,UNLINK:128,CREATE_PARENTS:256,UNLINK_IF_UNUSED:512,OPEN_DEFERRED:1024}),dn=Object.freeze({OK:0,GENERIC:-1,NOENT:-2,ACCESS:-3,IO:-4,NOSPACE:-5,BADHANDLE:-6,BUSY:-7});var En=Object.freeze([\"flatsql_io_open\",\"flatsql_io_read\",\"flatsql_io_write\",\"flatsql_io_truncate\",\"flatsql_io_sync\",\"flatsql_io_size\",\"flatsql_io_close\"]),et=4096;var Sn=typeof TextDecoder==\"function\"?new TextDecoder(\"utf-8\",{fatal:!0}):null;function Lt(t){let e=2166136261;for(let r=0;r<t.length;r+=1)e^=t[r],e=Math.imul(e,16777619);return e>>>0}var Fe=1330201683,Me=1,He=0,Ue=1,Pe=2,ve=3,Qe=4,bt=5;var ke=7;var qe=9,nt=10,Ge=11;var We=13,Ut=64,Ct=Ut*4;var Ye=1;var Ve=1,$e=2,Ke=3,Y=32767,V=0,Pt=1,Nt=2,ze=3,je=4,Xe=5,Ze=6,Je=7,tr=8,er=9,Dt=10,vt=11,rr=12,nr=13,or=8,Qt=9,_t=128,At=0,sr=1,cr=2;var ir=4,ar=0;var ur=0,lr=1,fr=1,W=2,rt=3,_r=4,Ar=5,dr=6,Er=7;var yn=64*1024;var Ft=250,Sr=20;function Mt(){return typeof performance<\"u\"&&performance.now?performance.now():Date.now()}function pr(t,e){return Math.ceil(t/e)*e}function kt(t){if(typeof SharedArrayBuffer!=\"function\"||!(t instanceof SharedArrayBuffer))throw new TypeError(\"The SAB I/O channel requires a SharedArrayBuffer (cross-origin isolation in browsers).\")}function mr(t){kt(t);let e=new Int32Array(t,0,Ut);if(e[He]!==Fe||e[Ue]!==Me)throw new TypeError(\"Not a SAB I/O channel buffer (bad magic or version).\");let r=e[Pe],n=e[ve],o=e[Qe],c=e[Ge],a=pr(Ct+o*4,64),f=new Int32Array(t,Ct,o),y=[];for(let m=0;m<r;m+=1){let S=a+m*n;y.push({index:m,base:S,i32:new Int32Array(t,S,_t/4),f64:new Float64Array(t,S,_t/8),data:new Uint8Array(t,S+_t,c)})}return{buffer:t,header:e,instances:f,slots:y,slotCount:r,slotBytes:n,dataBytes:c,maxInstances:o,channelId:e[We]}}function yr(t){return`sdm-sab-io-doorbell-${t}`}function hr(t,e){Atomics.add(t.header,bt,1),Atomics.notify(t.header,bt),Atomics.load(t.header,ke)===Ye&&e()?.postMessage(0)}function Rr(t){let e=null;return{get(){return!e&&typeof BroadcastChannel==\"function\"&&(e=new BroadcastChannel(t)),e},close(){e?.close(),e=null}}}var Ir=typeof TextEncoder==\"function\"?new TextEncoder:null;function Or(){return(Math.random()*2147483646|0)+1}function Tr(t,e){let r=(Atomics.add(t.header,qe,1)>>>0)%t.slotCount;for(let n=0;n<t.slotCount;n+=1){let o=t.slots[(r+n)%t.slotCount];if(Atomics.compareExchange(o.i32,V,At,sr)===At)return Atomics.store(o.i32,Pt,e),o}return null}function Ht(t,e){Atomics.store(e.i32,Pt,0),Atomics.store(e.i32,V,At),Atomics.add(t.header,nt,1),Atomics.notify(t.header,nt)}function gr(t,e,r){let n=t.i32;n[je]=e,n[Xe]=r.instanceId??Y,n[Ze]=r.handle??-1,n[Je]=r.flags??0,n[tr]=r.ptr??0,n[er]=r.len??0,n[nr]=r.dataInSlot?lr:ur,n[vt]=0,t.f64[or]=r.offset??0,t.f64[Qt]=0,r.path?(t.data.set(r.path,0),n[Dt]=r.path.length):n[Dt]=0}function wr(t){return Atomics.load(t.i32,vt)}function qt(t={}){kt(t.buffer);let e=mr(t.buffer),r=Number.isInteger(t.instanceId)?t.instanceId:Y;if(r!==Y&&(r<0||r>=e.maxInstances))throw new RangeError(`instanceId ${r} is outside 0..${e.maxInstances-1}.`);let n=typeof t.getMemory==\"function\"?t.getMemory:()=>null,o=Number.isFinite(t.spinMicros)?Math.max(0,t.spinMicros):Sr,c=Or(),a=Rr(yr(e.channelId)),f=0;function y(){for(;;){let s=Atomics.load(e.header,nt),i=Tr(e,c);if(i)return i;Atomics.wait(e.header,nt,s,Ft)}}function m(s,i,u){let p=Atomics.load(s.i32,Nt)+1|0||1;gr(s,i,u),Atomics.store(s.i32,rr,ar),Atomics.store(s.i32,Nt,p),Atomics.store(s.i32,V,cr),hr(e,a.get);let E=o>0?Mt()+o/1e3:0;for(;;){let g=Atomics.load(s.i32,V);if(g===ir&&Atomics.load(s.i32,ze)===p)break;E>0&&Mt()<E||Atomics.wait(s.i32,V,g,Ft)}return f+=1,{status:wr(s),result:s.f64[Qt]}}function S(s,i){let u=y();try{return m(u,s,i)}finally{Ht(e,u)}}function T(){return r!==Y&&Atomics.load(e.instances,r)===Ve}function _(){if(r===Y)return!1;let s=Atomics.load(e.instances,r);return s===$e||s===Ke}function A(s,i,u,p){let E=0;for(;E<u.length;){let g=Math.min(e.dataBytes,u.length-E),w=y(),B;try{s===rt&&w.data.set(u.subarray(E,E+g),0),B=m(w,s,{instanceId:r,dataInSlot:!0,handle:i,ptr:0,len:g,offset:p+E}).status,s===W&&B>0&&u.set(w.data.subarray(0,B),E)}finally{Ht(e,w)}if(B<0)return E>0&&s===W?E:B;if(E+=B,B<g)break}return E}function l(s,i){let u=n(),p=u?.buffer??u;return!p||s<0||i<0||s+i>p.byteLength?null:new Uint8Array(p,s,i)}return{instanceId:r,get requests(){return f},open(s,i){let u=typeof s==\"string\"?Ir.encode(s):s;return!(u instanceof Uint8Array)||u.length===0?-1:u.length>Math.min(e.dataBytes,et)?-1:S(fr,{instanceId:r,flags:i|0,path:u}).status},read(s,i,u,p){if(u===0)return 0;if(T())return S(W,{instanceId:r,handle:s,ptr:i,len:u,offset:p}).status;let E=l(i,u);return E?A(W,s,E,p):_()?-3:-1},write(s,i,u,p){if(u===0)return 0;if(T())return S(rt,{instanceId:r,handle:s,ptr:i,len:u,offset:p}).status;let E=l(i,u);return E?A(rt,s,E,p):_()?-3:-1},readInto(s,i,u){return i.length===0?0:A(W,s,i,u)},writeFrom(s,i,u){return i.length===0?0:A(rt,s,i,u)},truncate(s,i){return S(_r,{instanceId:r,handle:s,offset:i}).status},sync(s){return S(Ar,{instanceId:r,handle:s}).status},size(s){let{status:i,result:u}=S(dr,{instanceId:r,handle:s});return i<0?i:u},close(s){return S(Er,{instanceId:r,handle:s}).status},release(){a.close()}}}var xr=typeof TextEncoder==\"function\"?new TextEncoder:null;function Lr(t){let e=2166136261;for(let r=0;r<t.length;r+=1)e^=t[r],e=Math.imul(e,16777619);return e|0}var Gt=new WeakMap;function Wt(t){let e=Gt.get(t);if(e)return e;let r=new Int32Array(t,0,16);if(r[0]!==1380795475||r[1]!==1)throw new TypeError(\"Not a SAB I/O mirror buffer.\");let n=r[2],o=r[3],c=r[4],a=64,f=a+n*32,y=f+n*c;return e={entries:n,entryBytes:o,maxPathBytes:c,i32:new Int32Array(t,a,n*32/4),f64:new Float64Array(t,a,n*32/8),paths:new Uint8Array(t,f,n*c),data:new Uint8Array(t,y,n*o)},Gt.set(t,e),e}function Br(t){return typeof t==\"string\"?xr.encode(t):t}function br(t,e,r){let n=e*8;if(Atomics.load(t.i32,n+3)!==r.length)return!1;let o=e*t.maxPathBytes;for(let c=0;c<r.length;c+=1)if(t.paths[o+c]!==r[c])return!1;return!0}function Cr(t,e,r){let n=(r>>>0)%t.entries;for(let o=0;o<t.entries;o+=1){let c=n*8,a=Atomics.load(t.i32,c+0);if(a===0)return-1;if((a===2||a===3)&&Atomics.load(t.i32,c+2)===r&&br(t,n,e))return n;n=(n+1)%t.entries}return-1}function Yt(t,e){let r=Wt(t),n=Br(e);if(n.length>r.maxPathBytes)return-1;let o=Cr(r,n,Lr(n));return o<0?-1:Atomics.load(r.i32,o*(32/4)+0)===2?o:-1}function Vt(t,e,r,n){let o=Wt(t),c=e*(32/4),a=e*(32/8)+3,f=e*o.entryBytes;for(let y=0;y<64;y+=1){let m=Atomics.load(o.i32,c+1);if(m&1)continue;if(Atomics.load(o.i32,c+0)!==2)return-1;let S=o.f64[a],T=Atomics.load(o.i32,c+4),_;if(n>=S)_=0;else{let A=Math.min(r.length,S-n);n+A>T?_=-1:(r.set(o.data.subarray(f+n,f+n+A),0),_=A)}if(Atomics.load(o.i32,c+1)===m)return _}return-1}function $t(t=[\"/h.fsh\"]){let e=Array.from(t,String);return r=>{let n=String(r);for(let o of e)if(n.endsWith(o)||n===o.replace(/^\\//,\"\"))return!0;return!1}}var Nr=\"flatsql-io\",F=Object.freeze({open:1,read:2,write:3,truncate:4,sync:5,size:6,close:7,mirrorRead:8}),Kt=24,zt=16777215;function dt(){return typeof performance<\"u\"&&performance.now?performance.now()*1e3:Date.now()*1e3}function Dr(t){if(!t?.buffer)return null;let e=new Int32Array(t.buffer,0,4),r=e[1],n=new Float64Array(t.buffer,16,r),o=new Uint8Array(t.buffer,16+r*8,r);return(c,a)=>{let f=Atomics.add(e,0,1);f<r&&(n[f]=dt()-a,o[f]=c)}}function Fr(t,e,r){if(!t||r<=0||r>et||e<0)return null;let n=t.buffer??t;return e+r>n.byteLength?null:new Uint8Array(n,e,r).slice()}function Mr(t={}){let e=t.getMemory;if(typeof e!=\"function\")throw new TypeError(\"createFlatsqlIoImports requires getMemory().\");let r=Array.isArray(t.provider)?t.provider:[t.provider];if(r.length===0||r.some(_=>!_||typeof _.open!=\"function\"))throw new TypeError(\"createFlatsqlIoImports requires at least one provider.\");if(r.length>127)throw new RangeError(\"At most 127 providers can be routed.\");let n=r.length>1,o=Dr(t.trace),c=t.mirror?.buffer??null,a=c?$t(t.mirror.suffixes??[\"/h.fsh\"]):null,f=new Map,y=new TextDecoder;function m(_){if(!n)return{provider:r[0],local:_};let A=_>>>Kt,l=r[A];return l?{provider:l,local:_&zt}:null}function S(_,A,l){let s=o?dt():0,i;try{i=l()}catch{i=A}return o&&o(_,s),i}return{env:{flatsql_io_open(_,A,l){return S(F.open,-1,()=>{let s=Fr(e(),_,A);if(!s)return-1;let i=n?Lt(s)%r.length:0,u=r[i].open(s,l|0);if(u<0)return u;if(n&&u>zt)return-4;let p=n?i<<Kt|u:u;if(a){let E=y.decode(s);a(E)&&f.set(p,E)}return p})},flatsql_io_read(_,A,l,s){if(c&&f.has(_)){let i=o?dt():0;try{let u=e(),p=u.buffer??u;if(A>=0&&l>=0&&A+l<=p.byteLength){let E=Yt(c,f.get(_));if(E>=0){let g=Vt(c,E,new Uint8Array(p,A,l),s);if(g>=0)return o&&o(F.mirrorRead,i),g}}}catch{}}return S(F.read,-4,()=>{let i=m(_);return i?i.provider.read(i.local,A,l,s):-6})},flatsql_io_write(_,A,l,s){return S(F.write,-4,()=>{let i=m(_);return i?i.provider.write(i.local,A,l,s):-6})},flatsql_io_truncate(_,A){return S(F.truncate,-4,()=>{let l=m(_);return l?l.provider.truncate(l.local,A):-6})},flatsql_io_sync(_){return S(F.sync,-4,()=>{let A=m(_);return A?A.provider.sync(A.local):-6})},flatsql_io_size(_){return S(F.size,-4,()=>{let A=m(_);return A?A.provider.size(A.local):-6})},flatsql_io_close(_){return S(F.close,-4,()=>{f.delete(_);let A=m(_);return A?A.provider.close(A.local):-6})}}}}function Hr(t,{getMemory:e}){let r=Array.isArray(t.channels)?t.channels:[t.channel??t.buffer];if(r.length===0||r.some(c=>!(c instanceof SharedArrayBuffer)))throw new TypeError(\"A flatsql-io descriptor needs channels: SharedArrayBuffer[].\");let n=r.map(c=>qt({buffer:c,instanceId:t.instanceId,getMemory:e}));return{imports:Mr({getMemory:e,provider:n,mirror:t.mirror,trace:t.trace}),close(){for(let c of n)c.release()}}}function jt(t,e){let r=[],n=[];for(let o of t??[]){let c;if(typeof o==\"function\")c=o(e);else if(o&&o.provider===Nr)c=Hr(o,e);else if(o&&typeof o.factory==\"function\")c=o.factory({...e,config:o.config});else throw new TypeError(`Unresolvable extraImports entry ${JSON.stringify(o?.provider??o?.moduleUrl??typeof o)}; pass a factory function, a { provider: \"flatsql-io\" } descriptor, or (module workers) a { moduleUrl } descriptor.`);c&&c.imports&&typeof c.close==\"function\"?(r.push(c.imports),n.push(c.close)):c&&r.push(c)}return{fragments:r,close(){for(let o of n)try{o()}catch{}}}}function Xt(t,e){for(let r of e)for(let[n,o]of Object.entries(r??{}))t[n]={...t[n]??{},...o};return t}var $=0,Ur=1,Pr=2,Jt=4,Et=0,Zt=1;var vr=0;var St=Jt*4,Qr=4*1024*1024;function kr(t){if(typeof SharedArrayBuffer!=\"function\"||!(t instanceof SharedArrayBuffer))throw new TypeError(\"SAB hostcall channel requires a SharedArrayBuffer (cross-origin isolation in browsers).\")}function te(t={}){if(typeof SharedArrayBuffer!=\"function\")throw new Error(\"SharedArrayBuffer is unavailable; the async hostcall bridge requires it (browsers additionally require cross-origin isolation: COOP+COEP).\");let e=Number.isInteger(t.maxResponseBytes)?t.maxResponseBytes:Qr;if(e<=0)throw new RangeError(\"maxResponseBytes must be a positive integer.\");return new SharedArrayBuffer(St+e)}function ee(t={}){kr(t.buffer);let e=t.postRequest;if(typeof e!=\"function\")throw new TypeError(\"createSabHostcallClientDispatch requires a postRequest function.\");let r=Number.isFinite(t.timeoutMs)&&t.timeoutMs>0?t.timeoutMs:12e4,n=new Int32Array(t.buffer,0,Jt),o=t.buffer.byteLength-St;return function(a,f=null){if(Atomics.store(n,$,Zt),e({operation:a,params:f}),Atomics.wait(n,$,Zt,r)===\"timed-out\")throw Atomics.store(n,$,Et),new Error(`Hostcall \"${a}\" timed out after ${r}ms waiting for the controlling thread.`);let m=Atomics.load(n,Ur),S=Atomics.load(n,Pr);if(S<0||S>o)throw Atomics.store(n,$,Et),new RangeError(`Hostcall \"${a}\" response length ${S} exceeds channel capacity ${o}.`);let T=new Uint8Array(S);T.set(new Uint8Array(t.buffer,St,S)),Atomics.store(n,$,Et);let _=Ot(T);if(m!==vr){let A=new Error(_?.message??`Hostcall \"${a}\" failed on the host thread.`);throw A.name=_?.name??\"Error\",A.code=_?.code??null,A.operation=_?.operation??a,A.capability=_?.capability??null,A}return _}}var pt=class extends Error{constructor(e){super(`WASI exit with code ${e}`),this.name=\"WasiExitError\",this.code=e}};function qr(t,e,r,n){for(;;){let o=Atomics.load(t,e);if(r>n-o)return-1;if(Atomics.compareExchange(t,e,o,o+r)===o)return o}}function re(t={}){let e=t.processState,r=e?.args??t.args??[],n=e?.env??t.env??{},o=e?.input??new Uint8Array(t.stdinBytes??[]),c=t.logOutput===!0,a=t.performance??globalThis.performance??{now:()=>Date.now(),timeOrigin:0},f=t.crypto??globalThis.crypto??null,y=[],m=[],S=0,T=null;function _(d){T=d}function A(){return T}function l(){return new Uint8Array(T.buffer)}function s(){return new DataView(T.buffer)}let u=Object.entries(n).map(([d,h])=>`${d}=${h}`).map(d=>new TextEncoder().encode(d)),p=r.map(d=>new TextEncoder().encode(d));function E(d,h,I){let O;if(d===0)O=BigInt(Math.round((a.timeOrigin+a.now())*1e6));else if(d===1)O=BigInt(Math.round(a.now()*1e6));else return 28;return s().setBigUint64(I,O,!0),0}function g(d,h,I,O){if(d!==1&&d!==2)return 8;let R=d===1?y:m,x=0,U=s(),P=l();for(let v=0;v<I;v++){let Z=h+v*8,M=U.getUint32(Z,!0),L=U.getUint32(Z+4,!0);if(e){let N=d===1?e.stdout:e.stderr,It=qr(e.control,d,L,N.length);if(It<0)return 51;N.set(P.subarray(M,M+L),It)}else R.push(P.slice(M,M+L));x+=L}return U.setUint32(O,x,!0),0}function w(d,h,I,O){if(d!==0)return s().setUint32(O,0,!0),8;let R=s(),x=l(),U=0;for(let P=0;P<I;P+=1){let v=h+P*8,Z=R.getUint32(v,!0),M=R.getUint32(v+4,!0),L,N;if(e)do L=Atomics.load(e.control,0),N=Math.min(M,o.length-L);while(Atomics.compareExchange(e.control,0,L,L+N)!==L);else L=S,N=Math.min(M,o.length-L),S+=N;if(N===0){if(L>=o.length)break;continue}x.set(o.subarray(L,L+N),Z),U+=N}return R.setUint32(O,U,!0),0}function B(d){return d<=2?0:8}function q(d,h,I,O){return d<=2?70:8}function Ae(d,h){if(d>2)return 8;let I=s();return I.setUint8(h,2),I.setUint16(h+2,0,!0),I.setBigUint64(h+8,0n,!0),I.setBigUint64(h+16,0n,!0),0}function de(d,h){return d<=2?0:8}function Ee(d,h){return 8}function Se(d,h,I){return 8}function pe(){return 8}function me(d,h){let I=s();I.setUint32(d,u.length,!0);let O=0;for(let R of u)O+=R.length+1;return I.setUint32(h,O,!0),0}function ye(d,h){let I=s(),O=l(),R=h;for(let x=0;x<u.length;x++)I.setUint32(d+x*4,R,!0),O.set(u[x],R),R+=u[x].length,O[R]=0,R+=1;return 0}function he(d,h){let I=s();I.setUint32(d,p.length,!0);let O=0;for(let R of p)O+=R.length+1;return I.setUint32(h,O,!0),0}function Re(d,h){let I=s(),O=l(),R=h;for(let x=0;x<p.length;x++)I.setUint32(d+x*4,R,!0),O.set(p[x],R),R+=p[x].length,O[R]=0,R+=1;return 0}function Ie(d,h){return f?.getRandomValues?(f.getRandomValues(l().subarray(d,d+h)),0):52}function Oe(d){throw e&&(Atomics.store(e.control,4,d),Atomics.store(e.control,3,1)),c&&Rt(),new pt(d)}function Te(){return 0}function Rt(){if(y.length>0){let d=X(y);if(c){let h=new TextDecoder().decode(d);h&&console.log(h)}y.length=0}if(m.length>0){let d=X(m);if(c){let h=new TextDecoder().decode(d);h&&console.warn(h)}m.length=0}}function X(d){let h=0;for(let R of d)h+=R.length;let I=new Uint8Array(h),O=0;for(let R of d)I.set(R,O),O+=R.length;return I}return{imports:{wasi_snapshot_preview1:{clock_time_get:E,fd_write:g,fd_read:w,fd_close:B,fd_seek:q,fd_fdstat_get:Ae,fd_fdstat_set_flags:de,fd_prestat_get:Ee,fd_prestat_dir_name:Se,path_open:pe,environ_sizes_get:me,environ_get:ye,args_sizes_get:he,args_get:Re,random_get:Ie,proc_exit:Oe,sched_yield:Te}},setMemory:_,getMemory:A,flushOutput:Rt,get stdout(){return e?e.stdout.slice(0,Atomics.load(e.control,1)):X(y)},get stderr(){return e?e.stderr.slice(0,Atomics.load(e.control,2)):X(m)}}}var Gr=\"sdm.thread-hostcall\";function Wr(t){return WebAssembly.Module.imports(t).some(e=>e.module===ft)}function Yr(t){if(!t||typeof t!=\"object\")throw new Error(\"A threaded guest that imports space_data_module_host requires an owning hostcall channel.\");let e=String(t.channelName??\"\").trim(),r=String(t.token??\"\").trim();if(!e||!r)throw new Error(\"The owning thread-hostcall channel name and token are required.\");if(typeof BroadcastChannel!=\"function\")throw new Error(\"BroadcastChannel is required for nested pthread hostcalls.\");let n=te({maxResponseBytes:t.maxResponseBytes}),o=new BroadcastChannel(e),c=1;return{dispatch:ee({buffer:n,timeoutMs:t.timeoutMs,postRequest(f){o.postMessage({type:Gr,token:r,requestId:c++,buffer:n,...f})}}),close(){o.close()}}}function ne({wasmModule:t,memory:e,hostcallChannel:r,processState:n,extraImports:o,workerIndex:c,tid:a,threadSpawn:f}={}){let y=re({processState:n});y.setMemory(e);let m=null,S=null,T={...y.imports,env:{memory:e},wasi:{\"thread-spawn\":typeof f==\"function\"?f:()=>-1}};if(Wr(t)){S=Yr(r);let A=xt({dispatch:S.dispatch,getMemory:()=>m?.exports?.memory??e});Object.assign(T,A.imports)}let _=jt(o,{memory:e,getMemory:()=>m?.exports?.memory??e,workerIndex:c??null,tid:a??null});return Xt(T,_.fragments),T.env.memory=e,{imports:T,instantiate(){return m=new WebAssembly.Instance(t,T),y.setMemory(m.exports.memory??e),m},close(){S?.close(),_.close()}}}async function oe(t){let e=[];for(let r of t??[])if(r&&typeof r.moduleUrl==\"string\"){let o=(await import(r.moduleUrl))[r.exportName??\"default\"];if(typeof o!=\"function\")throw new TypeError(`extraImports module ${r.moduleUrl} exports no factory \"${r.exportName??\"default\"}\".`);e.push({factory:o,config:r.config??null})}else e.push(r);return e}var Vr=Object.freeze({PENDING:0,IDLE:1,CLAIMED:2,ASSIGNED:3,RUNNING:4,RETIRED:5}),{PENDING:Mn,IDLE:K,CLAIMED:se,ASSIGNED:z,RUNNING:st,RETIRED:yt}=Vr,ct=0,$r=1,Kr=2,zr=3,jr=4,ot=5,Xr=6,Zr=8,Jr=8,b=0,ht=1,ae=2,ce=3,tn=4,ie=1,en=536870911,rn=2;var C=t=>Zr+Jr*t;function mt(){return typeof performance<\"u\"&&typeof performance.now==\"function\"?performance.now():Date.now()}function it(t){Atomics.add(t,ct,1),Atomics.notify(t,ct)}function nn(t,e,r){Atomics.store(t,C(e)+b,r),Atomics.notify(t,C(e)+b),it(t)}function ue(t,e){nn(t.control,e,yt)}function on(t,e,r){let{control:n}=t,o=C(e);for(;;){let c=Atomics.load(n,o+b);if(c!==z&&c!==st||Atomics.load(n,o+ht)!==r)return!1;if(Atomics.compareExchange(n,o+b,c,K)===c)return it(n),!0}}function sn(t,e){let{control:r}=t,n=C(e);return Atomics.compareExchange(r,n+b,z,st)!==z?null:{tid:Atomics.load(r,n+ht),startArg:Atomics.load(r,n+ae)}}function cn(t,e){let{control:r}=t;Atomics.compareExchange(r,C(e)+b,st,K)===st&&it(r)}function le(t,e,{runThread:r,osThreadId:n=0}){let{control:o}=t,c=C(e)+b;for(n&&Atomics.store(o,C(e)+tn,n);;){let a=Atomics.load(o,c);if(a===yt)return;if(a!==z){Atomics.wait(o,c,a);continue}let f=sn(t,e);if(f){if(r(f.tid,f.startArg)===!1){ue(t,e);return}cn(t,e)}}}function fe(t,{owner:e=!1,grow:r=null,dispatchMessage:n=null}={}){let{control:o,spawnWaitMs:c}=t,a=Atomics.load(o,Xr),f=null,y=!0,m=l=>e||(Atomics.load(o,C(l)+ce)&ie)===0,S=()=>{let l=Math.min(Atomics.load(o,ot),a),s=0;for(let i=0;i<l;i+=1)if(m(i)){if(Atomics.compareExchange(o,C(i)+b,K,se)===K)return{slot:i,live:s+1};Atomics.load(o,C(i)+b)!==yt&&(s+=1)}return{slot:-1,live:s}},T=()=>{for(;;){let l=Atomics.load(o,ot);if(l>=a)return-1;if(Atomics.compareExchange(o,ot,l,l+1)===l)return Atomics.store(o,C(l)+b,se),l}},_=()=>{let l=T();if(l<0)return{slot:-1,reason:null};try{return r(l),{slot:l,reason:null}}catch{return ue(t,l),{slot:-1,reason:\"worker-create-failed\"}}},A=()=>{let l=S();if(l.slot>=0)return{slot:l.slot,waited:!1,reason:null};let s=typeof r==\"function\",i=mt(),u=i+(y?c:0),p=i+(y?Math.min(rn,c):0),E=!1;for(;;){let g=Atomics.load(o,ct);if(l=S(),l.slot>=0)return{slot:l.slot,waited:E,reason:null};let w=s&&Math.min(Atomics.load(o,ot),a)<a;if(w&&(l.live===0||mt()>=p)){let q=_();if(q.slot>=0||q.reason)return{...q,waited:E};continue}if(l.live===0)return{slot:-1,waited:E,reason:\"pool-exhausted\"};if(g===f&&!w)return{slot:-1,waited:E,reason:\"pool-exhausted\"};let B=(w?p:u)-mt();if(!w&&B<=0)return f=g,{slot:-1,waited:E,reason:\"pool-exhausted\"};if(B>0){try{Atomics.wait(o,ct,g,B)}catch{if(y=!1,!w)return{slot:-1,waited:E,reason:\"pool-exhausted\"};p=0;continue}E=!0}}};return l=>{let s=A();if(s.slot<0)return s.reason===\"pool-exhausted\"&&Atomics.add(o,jr,1),{tid:-1,slot:-1,reason:s.reason};let{slot:i}=s,u=C(i),p=Atomics.add(o,$r,1);if(p>en)return Atomics.store(o,u+b,K),it(o),{tid:-1,slot:-1,reason:\"tid-exhausted\"};if(Atomics.store(o,u+ht,p),Atomics.store(o,u+ae,l|0),Atomics.store(o,u+b,z),(Atomics.load(o,u+ce)&ie)!==0)try{n(i,p,l)}catch{return on(t,i,p),{tid:-1,slot:-1,reason:\"dispatch-failed\"}}else Atomics.notify(o,u+b);return Atomics.add(o,Kr,1),s.waited&&Atomics.add(o,zr,1),{tid:p,slot:i,reason:null}}}var j=null;function _e(t,e){try{return j.instantiate().exports.wasi_thread_start(t,e),!0}catch(r){return r&&r.name===\"WasiExitError\"?!0:(console.error(`[wasi-thread] guest thread ${t} trapped:`,r),self.postMessage({t:\"error\",tid:t,error:String(r?.message??r)}),!1)}}self.onmessage=async t=>{let e=t.data??{};if(e.t===\"probe\"){let r=e.pool??null;try{let n=await oe(e.extraImports??[]),o=r?fe(r):null;j=ne({wasmModule:e.wasmModule,memory:e.memory,hostcallChannel:e.hostcallChannel??null,processState:e.processState,extraImports:n,workerIndex:e.workerIndex,threadSpawn:o?c=>o(c).tid:void 0}),j.instantiate(),self.postMessage({t:\"ready\",ok:!0,protocol:2})}catch(n){j?.close(),j=null,self.postMessage({t:\"ready\",ok:!1,error:String(n?.message??n)});return}r&&le(r,e.slot,{runThread:_e});return}e.t===\"run\"&&(_e(e.tid,e.startArg),self.postMessage({t:\"exit\",tid:e.tid}))};})();\n";
|
|
7
|
+
export const WASI_THREAD_POOL_WORKER_BUNDLE_SHA256 = "9098a64250e10a167cc6d4c24d535283f77245101f1b3710fdd71f0ce0fbcae6";
|
|
8
8
|
|
|
9
9
|
/** src/host/opfsIoWorker.mjs, sha256 9b5cf50741217bd829e7f1ee4cbdbf3e6b6b8ecc20a700501adf0faf9ee429b1. */
|
|
10
10
|
export const FLATSQL_IO_WORKER_BUNDLE = "(()=>{var Nn=Object.freeze({READ:1,WRITE:2,CREATE:4,EXCL:8,TRUNC:16,DELETE_ON_CLOSE:32,PROBE:64,UNLINK:128,CREATE_PARENTS:256,UNLINK_IF_UNUSED:512,OPEN_DEFERRED:1024}),Cn=Object.freeze({OK:0,GENERIC:-1,NOENT:-2,ACCESS:-3,IO:-4,NOSPACE:-5,BADHANDLE:-6,BUSY:-7});var Fn=Object.freeze([\"flatsql_io_open\",\"flatsql_io_read\",\"flatsql_io_write\",\"flatsql_io_truncate\",\"flatsql_io_sync\",\"flatsql_io_size\",\"flatsql_io_close\"]),Ye=4096;function vt(t,{during:n}={}){if(!t)return-1;let r=typeof t.code==\"string\"?t.code:null;if(r)switch(r){case\"ENOENT\":case\"ENOTDIR\":return-2;case\"EACCES\":case\"EPERM\":case\"EROFS\":return-3;case\"ENOSPC\":case\"EDQUOT\":return-5;case\"EBADF\":return-4;case\"EEXIST\":return-1;case\"EBUSY\":case\"ETXTBSY\":return-7;case\"ENAMETOOLONG\":case\"EINVAL\":return-1;default:return-4}switch(t.name){case\"NotFoundError\":return-2;case\"NoModificationAllowedError\":return-7;case\"InvalidStateError\":return n===\"open\"?-7:-6;case\"QuotaExceededError\":return-5;case\"TypeMismatchError\":case\"SecurityError\":case\"NotAllowedError\":return-3;case\"InvalidModificationError\":return-7;case\"TypeError\":case\"RangeError\":return-1;default:return-4}}var N=class extends Error{constructor(n,r){super(r??`flatsql_io status ${n}`),this.name=\"FlatsqlIoStatusError\",this.status=n}};function V(t,n){return t&&typeof t.status==\"number\"&&t.status<0?t.status:vt(t,n)}function oe(t){if(typeof t!=\"string\"||t.length===0||t.includes(\"\\0\"))return-1;let n=[];for(let r of t.split(\"/\"))if(!(r===\"\"||r===\".\")){if(r===\"..\")return-3;n.push(r)}return n.length===0?-1:n}var Ve=typeof TextDecoder==\"function\"?new TextDecoder(\"utf-8\",{fatal:!0}):null;function Ge(t){if(!Ve||t.length===0||t.length>Ye)return-1;let n=t.buffer instanceof ArrayBuffer?t:new Uint8Array(t);try{return Ve.decode(n)}catch{return-1}}var Vt=1330201683,Yt=1,Gt=0,qt=1,Wt=2,$t=3,Kt=4,H=5,Ie=6,We=7,$e=8;var Xt=11,Ke=12,zt=13,Xe=64,qe=Xe*4;var ze=1,Ze=2;var se=0,Oe=1,Je=0,ae=1,ie=2,ce=3,je=32767,G=0;var Zt=2,Jt=3,et=4,tt=5,nt=6,rt=7,ot=8,st=9,at=10,jt=11,en=12,it=13,ct=8,tn=9,de=128;var _e=2,_t=3,nn=4;var rn=1;var ft=1,pe=1,fe=2,he=3,Re=4,Te=5,me=6,Le=7;var Mn=64*1024;function on(t,n){return Math.ceil(t/n)*n}function sn(t){if(typeof SharedArrayBuffer!=\"function\"||!(t instanceof SharedArrayBuffer))throw new TypeError(\"The SAB I/O channel requires a SharedArrayBuffer (cross-origin isolation in browsers).\")}function lt(t){sn(t);let n=new Int32Array(t,0,Xe);if(n[Gt]!==Vt||n[qt]!==Yt)throw new TypeError(\"Not a SAB I/O channel buffer (bad magic or version).\");let r=n[Wt],s=n[$t],f=n[Kt],a=n[Xt],l=on(qe+f*4,64),L=new Int32Array(t,qe,f),S=[];for(let p=0;p<r;p+=1){let T=l+p*s;S.push({index:p,base:T,i32:new Int32Array(t,T,de/4),f64:new Float64Array(t,T,de/8),data:new Uint8Array(t,T+de,a)})}return{buffer:t,header:n,instances:L,slots:S,slotCount:r,slotBytes:s,dataBytes:a,maxInstances:f,channelId:n[zt]}}function ut(t){return`sdm-sab-io-doorbell-${t}`}function an(t){return`sdm-sab-io-done-${t}`}var Qn=typeof TextEncoder==\"function\"?new TextEncoder:null;var Y=null;function cn(t){return typeof BroadcastChannel!=\"function\"?null:((!Y||Y.id!==t.channelId)&&(Y?.channel.close(),Y={id:t.channelId,channel:new BroadcastChannel(an(t.channelId))}),Y.channel)}function Et(t,n,r,s=0){n.f64[tn]=s,Atomics.store(n.i32,jt,r|0),Atomics.store(n.i32,Jt,Atomics.load(n.i32,Zt)),Atomics.store(n.i32,G,nn),Atomics.notify(n.i32,G),Atomics.load(n.i32,en)===rn&&cn(t)?.postMessage(n.index)}var _n=typeof TextEncoder==\"function\"?new TextEncoder:null;function St(t){let n=2166136261;for(let r=0;r<t.length;r+=1)n^=t[r],n=Math.imul(n,16777619);return n|0}var At=new WeakMap;function ye(t){let n=At.get(t);if(n)return n;let r=new Int32Array(t,0,16);if(r[0]!==1380795475||r[1]!==1)throw new TypeError(\"Not a SAB I/O mirror buffer.\");let s=r[2],f=r[3],a=r[4],l=64,L=l+s*32,S=L+s*a;return n={entries:s,entryBytes:f,maxPathBytes:a,i32:new Int32Array(t,l,s*32/4),f64:new Float64Array(t,l,s*32/8),paths:new Uint8Array(t,L,s*a),data:new Uint8Array(t,S,s*f)},At.set(t,n),n}function dt(t){return ye(t).entryBytes}function It(t){return typeof t==\"string\"?_n.encode(t):t}function fn(t,n,r){let s=n*8;if(Atomics.load(t.i32,s+3)!==r.length)return!1;let f=n*t.maxPathBytes;for(let a=0;a<r.length;a+=1)if(t.paths[f+a]!==r[a])return!1;return!0}function Ot(t,n,r){let s=(r>>>0)%t.entries;for(let f=0;f<t.entries;f+=1){let a=s*8,l=Atomics.load(t.i32,a+0);if(l===0)return-1;if((l===2||l===3)&&Atomics.load(t.i32,a+2)===r&&fn(t,s,n))return s;s=(s+1)%t.entries}return-1}function ln(t,n,r){let s=(r>>>0)%t.entries;for(let f=0;f<t.entries;f+=1){let a=s*8;if(Atomics.compareExchange(t.i32,a+0,0,1)===0)return t.paths.set(n,s*t.maxPathBytes),Atomics.store(t.i32,a+3,n.length),Atomics.store(t.i32,a+2,r),Atomics.store(t.i32,a+4,0),t.f64[s*(32/8)+3]=0,Atomics.store(t.i32,a+0,3),s;s=(s+1)%t.entries}return-1}function W(t,n,r,s,{truncateTo:f}={}){let a=ye(t),l=It(n);if(l.length>a.maxPathBytes)return!1;let L=St(l),S=Ot(a,l,L);if(S<0&&(S=ln(a,l,L)),S<0)return!1;let p=S*(32/4),T=S*(32/8)+3,A=S*a.entryBytes,c=Atomics.load(a.i32,p+0)===2;Atomics.add(a.i32,p+1,1);let E=c?a.f64[T]:0,d=c?Atomics.load(a.i32,p+4):0;if(c||a.data.fill(0,A,A+a.entryBytes),s.length>0&&r<a.entryBytes){let m=Math.min(a.entryBytes,r+s.length);r>d&&a.data.fill(0,A+d,A+r),a.data.set(s.subarray(0,m-r),A+r)}return s.length>0&&(E=Math.max(E,r+s.length)),f!==void 0&&(f<d&&a.data.fill(0,A+f,A+d),E=f),d=Math.min(E,a.entryBytes),a.f64[T]=E,Atomics.store(a.i32,p+4,d),Atomics.store(a.i32,p+0,2),Atomics.add(a.i32,p+1,1),!0}function we(t,n){let r=ye(t),s=It(n);if(s.length>r.maxPathBytes)return;let f=Ot(r,s,St(s));if(f<0)return;let a=f*(32/4);Atomics.add(r.i32,a+1,1),Atomics.store(r.i32,a+0,3),Atomics.store(r.i32,a+4,0),r.f64[f*(32/8)+3]=0,Atomics.add(r.i32,a+1,1)}function pt(t=[\"/h.fsh\"]){let n=Array.from(t,String);return r=>{let s=String(r);for(let f of n)if(s.endsWith(f)||s===f.replace(/^\\//,\"\"))return!0;return!1}}var Ce=256*1024,dn=50,In=8,Tt=250,mt=16777215,R=0,xe=1,Lt=2;function le(){return typeof performance<\"u\"&&performance.now?performance.now():Date.now()}function On(){if(typeof MessageChannel==\"function\"){let t=new MessageChannel,n=[];return t.port1.onmessage=()=>n.shift()?.(),t.port1.unref?.(),t.port2.unref?.(),()=>new Promise(r=>{n.push(r),t.port2.postMessage(0)})}return()=>new Promise(t=>setTimeout(t,0))}function yt(t={}){let n=lt(t.buffer),r=t.backend;if(!r||typeof r.openFile!=\"function\")throw new TypeError(\"createFlatsqlIoServer requires a backend with openFile().\");let s=Number.isInteger(t.chunkBytes)&&t.chunkBytes>0?t.chunkBytes:Ce,f=t.doorbell??\"auto\",a=f===\"message\"||f===\"auto\"&&typeof Atomics.waitAsync!=\"function\"?Oe:se,l=t.mirror??null,L=Number.isFinite(t.spinMicros)?Math.max(0,t.spinMicros):dn,S=typeof t.onEvent==\"function\"?t.onEvent:null,p=On(),T=new Map,A=new Map,c=new Map,E=new Map,d=new Map,m=[],y=new Set,x=1,F=!1,g=null,D=null,U=null,J=null,j=!1,w={served:0,opens:0,deferredOpens:0,parked:0,chunks:0,busy:0,revoked:0,sharedViewsRejected:!1,maxReady:0};function v(e){if(S)try{S(e)}catch{}}function ee(){if(a===se)Atomics.add(n.header,H,1),Atomics.notify(n.header,H);else{let e=D;D=null,e?.()}}async function Ft(e){if(a===se){let o=Atomics.waitAsync(n.header,H,e,Tt);o.async&&await o.value;return}Atomics.load(n.header,H)===e&&await new Promise(o=>{let _=setTimeout(()=>{D===u&&(D=null),o()},Tt),u=()=>{clearTimeout(_),o()};D=u})}function Ae(e,o){let u=(d.get(e)??Promise.resolve()).then(o,o),i=u.then(()=>{},()=>{});return d.set(e,i),i.then(()=>{d.get(e)===i&&d.delete(e)}),u}function gt(){for(let e=0;e<mt;e+=1){let o=x;if(x=x>=mt?1:x+1,!c.has(o))return o}return-1}function te(e,o,_){let u=gt();if(u<0)return-1;let i=(_&2)!==0,O={id:u,entry:e,instanceId:o,canWrite:i,canRead:!i||(_&1)!==0};c.set(u,O),e.refs+=1,_&32&&(e.deleteOnClose=!0);let I=E.get(o);return I||(I=new Set,E.set(o,I)),I.add(u),u}function ne(e){if(!(e.refs>0||e.pins>0)){if(A.get(e.path)===e&&A.delete(e.path),e.file){try{e.file.close()}catch{}e.file=null}e.deleteOnClose&&e.openStatus===0&&Ae(e.path,async()=>{try{await r.remove(e.path,e.components)}catch{}l&&l.write!==!1&&we(l.buffer,e.path)})}}function De(e){c.delete(e.id)&&(E.get(e.instanceId)?.delete(e.id),e.entry.refs-=1,ne(e.entry))}function Dt(e){return e===je?ae:e<0||e>=n.maxInstances?-1:Atomics.load(n.instances,e)}function Se(e){let o=Dt(e);return o===ie||o===ce}function Me(e){let{slot:o,ptr:_,len:u}=e;if(u<0||_<0)return null;if(e.dataMode===ft)return _+u>o.data.length?null:o.data.subarray(_,_+u);let i=T.get(e.instanceId),O=i?.buffer??i;return!O||_+u>O.byteLength?null:new Uint8Array(O,_,u)}function Qe(e){return(!J||J.length<e)&&(J=new Uint8Array(Math.max(e,s))),J.subarray(0,e)}function Pe(e,o,_){if(!j)try{return e.read(o,{at:_})}catch(O){if(!(O instanceof TypeError)||!(o.buffer instanceof SharedArrayBuffer))throw O;j=!0,w.sharedViewsRejected=!0,v({type:\"shared-views-rejected\"})}let u=Qe(o.length),i=e.read(u,{at:_});return o.set(u.subarray(0,i),0),i}function Mt(e,o,_){if(!j)try{return e.write(o,{at:_})}catch(i){if(!(i instanceof TypeError)||!(o.buffer instanceof SharedArrayBuffer))throw i;j=!0,w.sharedViewsRejected=!0,v({type:\"shared-views-rejected\"})}let u=Qe(o.length);return u.set(o,0),e.write(u,{at:_})}function h(e,o,_=0){y.delete(e.slot.index),w.served+=1,Atomics.add(n.header,Ke,1),Et(n,e.slot,o,_)}function Qt(e){let o=e.i32;return{slot:e,op:o[et],instanceId:o[tt],handleId:o[nt],flags:o[rt],ptr:o[ot],len:o[st],dataMode:o[it],pathLen:o[at],offset:e.f64[ct],done:0,phase:0}}function He(){let e=0;for(let o of n.slots)y.has(o.index)||Atomics.load(o.i32,G)===_e&&Atomics.compareExchange(o.i32,G,_e,_t)===_e&&(y.add(o.index),m.push(Qt(o)),e+=1);return m.length>w.maxReady&&(w.maxReady=m.length),e}function Ue(){for(let e=0;e<n.maxInstances;e+=1){if(Atomics.load(n.instances,e)!==ie)continue;let o=E.get(e);if(o){for(let _ of Array.from(o)){let u=c.get(_);u&&De(u)}E.delete(e)}T.delete(e),w.revoked+=1,Atomics.store(n.instances,e,ce),Atomics.notify(n.instances,e),v({type:\"revoked\",instanceId:e})}}function re(e,o){return w.parked+=1,o.waiters.push(e),Lt}function ke(e,o,_){if(e.opening=null,e.openStatus=o,e.file=_??null,o===0&&l&&l.write!==!1&&l.match(e.path)&&e.file)try{let i=e.file.getSize(),O=new Uint8Array(Math.min(i,dt(l.buffer)));O.length>0&&Pe(e.file,O,0),W(l.buffer,e.path,0,O,{truncateTo:i})}catch{}let u=e.waiters;e.waiters=[];for(let i of u)i.op===pe&&i.phase===1&&i.entry===e&&(o<0?i.result=o:Se(i.instanceId)?i.result=-3:i.result=te(e,i.instanceId,i.flags),i.phase=2),m.push(i);o<0&&e.refs===0&&e.pins===0&&A.get(e.path)===e?A.delete(e.path):o===0&&e.refs===0&&e.pins===0&&ne(e),ee()}function be(e,o){w.opens+=1,e.opening=Ae(e.path,async()=>{try{let _=await r.openFile(e.path,e.components,o);ke(e,0,_)}catch(_){ke(e,V(_,{during:\"open\"}),null)}})}function Pt(e){if(e.phase===2)return h(e,e.result),R;if(Se(e.instanceId))return h(e,-3),R;if(e.path===void 0){let I=e.slot.data.slice(0,Math.max(0,e.pathLen)),Q=Ge(I);if(typeof Q!=\"string\")return h(e,Q),R;let P=oe(Q);if(!Array.isArray(P))return h(e,P),R;e.path=P.join(\"/\"),e.components=P}let{path:o,components:_,flags:u}=e,i=A.get(o);if(u&704)return i?.opening?re(e,i):u&64?i&&i.openStatus===0?(h(e,0),R):ve(e,async()=>await r.exists(o,_)?0:-2):i&&i.refs>0?(w.busy+=1,h(e,-7),R):(i&&i.pins>0&&(i.pins=0,ne(i)),ve(e,async()=>(await r.remove(o,_),l&&l.write!==!1&&we(l.buffer,o),0)));if(i){if(i.opening){if(u&1024){w.deferredOpens+=1;let I=te(i,e.instanceId,u);return h(e,I),R}return re(e,i)}if(i.openStatus===0){if(u&8)return h(e,-1),R;if(u&16&&u&2)try{i.file.truncate(0),l&&l.write!==!1&&l.match(o)&&W(l.buffer,o,0,new Uint8Array(0),{truncateTo:0})}catch(Q){return h(e,V(Q)),R}let I=te(i,e.instanceId,u);return h(e,I),R}A.get(o)===i&&A.delete(o)}let O={path:o,components:_,file:null,opening:null,openStatus:0,refs:0,pins:0,deleteOnClose:!1,waiters:[]};if(A.set(o,O),be(O,u),u&1024){w.deferredOpens+=1;let I=te(O,e.instanceId,u);return h(e,I),R}return e.phase=1,e.entry=O,re(e,O)}function ve(e,o){return e.phase=2,Ae(e.path,async()=>{try{e.result=await o()}catch(_){e.result=V(_)}m.push(e),ee()}),w.parked+=1,Lt}function Ht(e){if(Se(e.instanceId))return h(e,-3),R;let o=c.get(e.handleId);if(!o)return h(e,-6),R;let _=o.entry;if(_.opening)return re(e,_);if(e.op===Le)return De(o),h(e,0),R;if(_.openStatus<0||!_.file)return h(e,_.openStatus<0?_.openStatus:-6),R;let u=_.file;try{switch(e.op){case fe:{if(!o.canRead)return h(e,-4),R;let i=Me(e);if(!i)return h(e,-1),R;let O=Math.min(s,e.len-e.done),I=Pe(u,i.subarray(e.done,e.done+O),e.offset+e.done);return w.chunks+=1,e.done+=I,I<O||e.done>=e.len?(h(e,e.done),R):xe}case he:{if(!o.canWrite)return h(e,-4),R;let i=Me(e);if(!i)return h(e,-1),R;let O=Math.min(s,e.len-e.done),I=i.subarray(e.done,e.done+O),Q=e.offset+e.done,P=Mt(u,I,Q);return w.chunks+=1,l&&l.write!==!1&&l.match(_.path)&&W(l.buffer,_.path,Q,I.subarray(0,P)),e.done+=P,P<O||e.done>=e.len?(h(e,e.done),R):xe}case Re:return o.canWrite?(u.truncate(e.offset),l&&l.write!==!1&&l.match(_.path)&&W(l.buffer,_.path,0,new Uint8Array(0),{truncateTo:e.offset}),h(e,0),R):(h(e,-4),R);case Te:return u.flush(),h(e,0),R;case me:return h(e,0,u.getSize()),R;default:return h(e,-1),R}}catch(i){let O=V(i);return h(e,e.done>0&&e.op===fe?e.done:O),R}}function Ut(e){try{return e.op===pe?Pt(e):e.op===fe||e.op===he||e.op===Re||e.op===Te||e.op===me||e.op===Le?Ht(e):(h(e,-1),R)}catch(o){return v({type:\"step-error\",error:o}),h(e,-4),R}}function kt(){let e=le();for(;m.length>0;){let o=m.shift();if(Ut(o)===xe&&m.push(o),Ue(),He(),le()-e>In)return!1}return!0}async function bt(){for(Atomics.store(n.header,We,a),Atomics.add(n.header,$e,1),Atomics.store(n.header,Ie,ze);F;){let e=Atomics.load(n.header,H);Ue(),He();let o=kt();if(!F)break;if(!o||m.length>0){await p();continue}if(L>0){let _=le()+L/1e3;for(;le()<_&&Atomics.load(n.header,H)===e;);if(Atomics.load(n.header,H)!==e)continue}await Ft(e)}}return{doorbellMode:a,stats:w,start(){return F||(F=!0,a===Oe&&typeof BroadcastChannel==\"function\"&&(U=new BroadcastChannel(ut(n.channelId)),U.onmessage=()=>{let e=D;D=null,e?.()}),g=bt().catch(e=>{throw v({type:\"loop-error\",error:e}),e})),g},async stop(){F=!1,ee();try{await g}catch{}U?.close(),U=null;for(let e of A.values())try{e.file?.close()}catch{}A.clear(),c.clear(),E.clear(),Atomics.store(n.header,Ie,Ze)},attachMemory(e,o){if(!Number.isInteger(e)||e<0||e>=n.maxInstances)return!1;let _=Atomics.load(n.instances,e);return _===ie||_===ce?!1:(T.set(e,o),Atomics.store(n.instances,e,ae),!0)},detachMemory(e){T.delete(e),Atomics.load(n.instances,e)===ae&&Atomics.store(n.instances,e,Je)},async preopen(e,o=7){let _=await Promise.all(e.map(async u=>{let i=oe(String(u));if(!Array.isArray(i))return i;let O=i.join(\"/\"),I=A.get(O);return I||(I={path:O,components:i,file:null,opening:null,openStatus:0,refs:0,pins:0,deleteOnClose:!1,waiters:[]},A.set(O,I),be(I,o&-1025)),I.pins+=1,I.opening&&await I.opening,I.openStatus<0?(I.pins=Math.max(0,I.pins-1),I.openStatus):0}));return ee(),_},releasePreopen(e){for(let o of e){let _=oe(String(o));if(!Array.isArray(_))continue;let u=A.get(_.join(\"/\"));u&&u.pins>0&&(u.pins-=1,ne(u))}},inventory(){return{files:Array.from(A.values()).map(e=>({path:e.path,refs:e.refs,pins:e.pins,opening:!!e.opening,openStatus:e.openStatus})),handles:c.size}}}}var vn=263;var Fe=class{constructor(){this.bytes=new Uint8Array(0),this.length=0}ensureCapacity(n,r){if(n<=this.bytes.length)return;let s=Math.max(64,this.bytes.length);for(;s<n;)s*=2;r.reserve(s-this.bytes.length);let f=new Uint8Array(s);f.set(this.bytes.subarray(0,this.length)),this.bytes=f}};function wt(t={}){let n=Number.isFinite(t.maxBytes)?t.maxBytes:1/0,r=new Map,s=new Set([\"\"]),f=0,a={reserve(S){if(f+S>n)throw new N(-5,\"memory store budget exhausted\");f+=S},release(S){f=Math.max(0,f-S)}};function l(S){return S.slice(0,-1).join(\"/\")}function L(S){let p=!1,T=()=>{if(p){let c=new Error(\"handle closed\");throw c.name=\"InvalidStateError\",c}let A=r.get(S);if(!A){let c=new Error(\"file removed\");throw c.name=\"NotFoundError\",c}return A};return{read(A,{at:c=0}={}){let E=T();if(c>=E.length)return 0;let d=Math.min(A.length,E.length-c);return A.set(E.bytes.subarray(c,c+d),0),d},write(A,{at:c=0}={}){let E=T(),d=c+A.length;return E.ensureCapacity(d,a),c>E.length&&E.bytes.fill(0,E.length,c),E.bytes.set(A,c),d>E.length&&(E.length=d),A.length},truncate(A){let c=T();A>c.length&&(c.ensureCapacity(A,a),c.bytes.fill(0,c.length,A)),c.length=A},flush(){T()},getSize(){return T().length},close(){p=!0}}}return{kind:\"memory\",openFile(S,p,T){let A=l(p);if(!s.has(A)){if(!(T&256)||!(T&4))throw new N(-2,`no directory ${A}`);for(let E=1;E<p.length;E+=1)s.add(p.slice(0,E).join(\"/\"))}if(s.has(S))throw new N(-3,`${S} is a directory`);let c=r.get(S);if(c&&T&8)throw new N(-1,`${S} exists`);if(c)T&16&&(c.length=0);else{if(!(T&4))throw new N(-2,`no file ${S}`);c=new Fe,r.set(S,c)}return L(S)},exists(S){return r.has(S)||s.has(S)},remove(S){let p=r.get(S);if(!p)throw new N(-2,`no file ${S}`);a.release(p.bytes.length),r.delete(S)},reset(){r.clear(),s.clear(),s.add(\"\"),f=0},usage(){return{files:r.size,allocatedBytes:f}},list(){return Array.from(r.keys()).sort()}}}var Ee=\"readwrite-unsafe\";function hn(t){let n=new Error(t);return n.name=\"NotFoundError\",n}function Bt(t){return new Promise(n=>setTimeout(n,t))}async function Rn(t,n=\".sdm-mode-probe\"){let r=null,s=null;try{let f=await t.getFileHandle(n,{create:!0});return r=await f.createSyncAccessHandle({mode:Ee}),r.mode!==Ee?{supported:!1,detail:\"mode option ignored\"}:(s=await f.createSyncAccessHandle({mode:Ee}),{supported:!0,detail:\"two readwrite-unsafe handles\"})}catch(f){return{supported:!1,detail:`${f?.name??\"Error\"}: ${f?.message??f}`}}finally{try{s?.close()}catch{}try{r?.close()}catch{}try{await t.removeEntry(n)}catch{}}}async function Tn(t,n=\".sdm-view-probe\"){let r=null;try{r=await(await t.getFileHandle(n,{create:!0})).createSyncAccessHandle();let f=new Uint8Array(new SharedArrayBuffer(16));f.fill(90);let a=r.write(f,{at:0}),l=new Uint8Array(new SharedArrayBuffer(16)),L=r.read(l,{at:0});return a===16&&L===16&&l[15]===90}catch{return!1}finally{try{r?.close()}catch{}try{await t.removeEntry(n)}catch{}}}function xt(t={}){let n=t.root??null,r=!1,s=null,f=t.handleMode??\"auto\",a=typeof t.openDelayMs==\"function\"?t.openDelayMs:null,l=new Map,L={attempts:Math.max(0,t.busyRetry?.attempts??0),baseMs:Math.max(1,t.busyRetry?.baseMs??10)};async function S(c){for(let E=0;;E+=1)try{return r?await c.createSyncAccessHandle({mode:Ee}):await c.createSyncAccessHandle()}catch(d){if(!(d?.name===\"NoModificationAllowedError\"||d?.name===\"InvalidStateError\")||E>=L.attempts)throw d;await Bt(L.baseMs*2**Math.min(E,8))}}async function p(){if(!n){if(typeof navigator>\"u\"||!navigator.storage?.getDirectory)throw new N(-1,\"OPFS is unavailable here\");if(n=await navigator.storage.getDirectory(),t.rootDirectory)for(let E of String(t.rootDirectory).split(\"/\").filter(Boolean))n=await n.getDirectoryHandle(E,{create:!0})}let c=await Rn(n);if(s=await Tn(n),f===\"shared\"&&!c.supported)throw new N(-1,`shared OPFS handle modes are unsupported here (${c.detail})`);return r=f!==\"exclusive\"&&c.supported,l.set(\"\",n),{sharedModes:r,sharedModesDetail:c.detail,sharedViews:s}}async function T(c,E){let d=c.join(\"/\"),m=l.get(d);if(m)return m;let y=n,x=\"\";for(let F of c){x=x?`${x}/${F}`:F;let g=l.get(x);if(g){y=g;continue}y=await y.getDirectoryHandle(F,{create:E}),l.set(x,y)}return y}async function A(c,E){try{return await c.getFileHandle(E)}catch(d){if(d?.name===\"NotFoundError\")return null;throw d}}return{kind:\"opfs\",init:p,get sharedModes(){return r},get sharedViews(){return s},async openFile(c,E,d){if(n||await p(),a){let U=a(c);U>0&&await Bt(U)}let m=(d&4)!==0,y=m&&(d&256)!==0,x=await T(E.slice(0,-1),y),F=E[E.length-1],g=null;if(d&8&&await A(x,F))throw new N(-1,`${c} exists`);g=await x.getFileHandle(F,{create:m});let D=await S(g);return d&16&&D.truncate(0),D},async exists(c,E){n||await p();let d;try{d=await T(E.slice(0,-1),!1)}catch(y){if(y?.name===\"NotFoundError\"||y?.name===\"TypeMismatchError\")return!1;throw y}let m=E[E.length-1];if(await A(d,m))return!0;try{return await d.getDirectoryHandle(m),!0}catch{return!1}},async remove(c,E){n||await p();let d;try{d=await T(E.slice(0,-1),!1)}catch(m){throw m?.name===\"TypeMismatchError\"?hn(c):m}await d.removeEntry(E[E.length-1])},async clear(){n||await p();for await(let c of n.keys())await n.removeEntry(c,{recursive:!0});l.clear(),l.set(\"\",n)}}}var Nt=\"node:\";var mn=typeof process<\"u\"&&!!process.release&&process.release.name===\"node\",B=null,M=null,Z=null;function Ln({name:t,ifAvailable:n=!1}){return typeof navigator>\"u\"||!navigator.locks?Promise.reject(new Error(\"Web Locks are unavailable in this context\")):new Promise((r,s)=>{navigator.locks.request(t,{mode:\"exclusive\",ifAvailable:n},f=>{if(!f){r(!1);return}return r(!0),new Promise(a=>{Z=a})}).catch(s)})}function ge(t){return`${t?.name??\"Error\"}: ${t?.message??String(t)}`}function yn(t){if(!t||!t.pattern||!(t.ms>0))return;let n=new RegExp(t.pattern);return r=>n.test(r)?t.ms:0}async function wn(t,n){let r=t.role===\"reader\"?\"reader\":\"writer\";if(t.lock?.name&&!await Ln(t.lock)){let l=new Error(`the store lock ${t.lock.name} is held by another context`);throw l.name=\"LockUnavailableError\",l}t.backend===\"memory\"?M=wt({maxBytes:t.memoryMaxBytes}):M=xt({rootDirectory:t.rootDirectory,handleMode:t.handleMode??\"auto\",openDelayMs:yn(t.openDelay),busyRetry:t.busyRetry??void 0});let s={backend:M.kind,role:r,lock:t.lock?.name??null};M.init&&Object.assign(s,await M.init());let f=t.mirror?.buffer?{buffer:t.mirror.buffer,match:pt(t.mirror.suffixes??[\"/h.fsh\"]),write:t.mirror.write??r===\"writer\"}:null;return B=yt({buffer:t.buffer,backend:M,chunkBytes:t.chunkBytes??Ce,doorbell:t.doorbell??\"auto\",mirror:f,onEvent(a){(a.type===\"loop-error\"||a.type===\"step-error\")&&n({t:\"event\",event:{type:a.type,error:ge(a.error)}})}}),s.doorbellMode=B.doorbellMode===1?\"message\":\"atomics\",B.start().catch(a=>{setTimeout(()=>{throw a},0)}),s}async function Ct(t,n){switch(t?.t){case\"init\":try{let r=await wn(t,n);n({t:\"ready\",ok:!0,info:r})}catch(r){Z?.(),Z=null,n({t:\"ready\",ok:!1,error:ge(r),lockUnavailable:r?.name===\"LockUnavailableError\"})}return;case\"attach\":n({t:\"attached\",instanceId:t.instanceId,ok:!!B?.attachMemory(t.instanceId,t.memory)});return;case\"detach\":B?.detachMemory(t.instanceId);return;case\"preopen\":{let r=B?await B.preopen(t.paths??[],t.flags):[];n({t:\"preopened\",id:t.id,statuses:r});return}case\"release-preopen\":B?.releasePreopen(t.paths??[]);return;case\"stats\":n({t:\"stats\",id:t.id,stats:B?{...B.stats}:null,inventory:B?B.inventory():null,usage:M?.usage?M.usage():null});return;case\"reset\":M?.reset?.(),n({t:\"reset\",id:t.id});return;case\"clear\":try{await M?.clear?.(),n({t:\"cleared\",id:t.id,ok:!0})}catch(r){n({t:\"cleared\",id:t.id,ok:!1,error:ge(r)})}return;case\"stop\":await B?.stop(),B=null,Z?.(),Z=null,n({t:\"stopped\",id:t.id});return;default:}}function Bn(){let t=n=>self.postMessage(n);self.onmessage=n=>{Ct(n.data,t)}}async function xn(){let t=Nt+\"worker_threads\",{parentPort:n}=await import(t);if(!n)return;let r=s=>n.postMessage(s);n.on(\"message\",s=>{Ct(s,r)})}mn?xn():typeof self<\"u\"&&typeof self.postMessage==\"function\"&&typeof window>\"u\"&&Bn();})();\n";
|
package/src/host/nodeSyncFsIo.js
CHANGED
|
@@ -198,8 +198,10 @@ export function createNodeSyncFsIo(options = {}) {
|
|
|
198
198
|
|
|
199
199
|
const call = (op, fn, ...args) => interpose(op, fn, args);
|
|
200
200
|
|
|
201
|
+
// A filesystem root ("/", "C:\\") already ends with the separator.
|
|
201
202
|
function within(candidate, base) {
|
|
202
|
-
|
|
203
|
+
const prefix = base.endsWith(path.sep) ? base : base + path.sep;
|
|
204
|
+
return candidate === base || candidate.startsWith(prefix);
|
|
203
205
|
}
|
|
204
206
|
|
|
205
207
|
function resolvePath(relative) {
|