@nimbus-sh/worker 0.1.2 → 0.1.4
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/LICENSE +21 -0
- package/NOTICE.md +6 -0
- package/README.md +2 -2
- package/dist/_shared/cache-stats.d.ts +1 -1
- package/dist/_shared/cache-stats.js +1 -1
- package/dist/_shared/exports-resolver.d.ts +0 -2
- package/dist/_shared/exports-resolver.d.ts.map +1 -1
- package/dist/_shared/exports-resolver.js +0 -2
- package/dist/_shared/session-router.d.ts +0 -1
- package/dist/_shared/session-router.d.ts.map +1 -1
- package/dist/_shared/session-router.js +0 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -1
- package/dist/facets/cirrus-real.d.ts +1 -1
- package/dist/facets/cirrus-real.js +1 -1
- package/dist/facets/manager.d.ts +0 -1
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +3 -15
- package/dist/facets/process.d.ts +2 -2
- package/dist/facets/process.js +2 -2
- package/dist/facets/vite-dev-server.d.ts +3 -3
- package/dist/facets/vite-dev-server.d.ts.map +1 -1
- package/dist/facets/vite-dev-server.js +6 -8
- package/dist/facets/wasm-swap-registry.d.ts +15 -21
- package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
- package/dist/facets/wasm-swap-registry.js +41 -54
- package/dist/facets/ws-terminal.d.ts +4 -5
- package/dist/facets/ws-terminal.d.ts.map +1 -1
- package/dist/facets/ws-terminal.js +7 -8
- package/dist/git/commands.d.ts.map +1 -1
- package/dist/git/commands.js +0 -1
- package/dist/git/network-facet.d.ts.map +1 -1
- package/dist/git/network-facet.js +0 -2
- package/dist/git-bundle.generated.d.ts +2 -3
- package/dist/git-bundle.generated.d.ts.map +1 -1
- package/dist/git-bundle.generated.js +3 -4
- package/dist/index.js +2 -2
- package/dist/loaders/child-process/spawn-facet.d.ts +7 -52
- package/dist/loaders/child-process/spawn-facet.d.ts.map +1 -1
- package/dist/loaders/child-process/spawn-facet.js +7 -49
- package/dist/loaders/child-process/spawn-pool.d.ts +5 -44
- package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
- package/dist/loaders/child-process/spawn-pool.js +5 -44
- package/dist/loaders/fanout-pool.d.ts +18 -65
- package/dist/loaders/fanout-pool.d.ts.map +1 -1
- package/dist/loaders/fanout-pool.js +25 -87
- package/dist/loaders/generated-workers.d.ts +1 -2
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +5 -6
- package/dist/loaders/loader-pool.d.ts +1 -2
- package/dist/loaders/loader-pool.d.ts.map +1 -1
- package/dist/loaders/loader-pool.js +1 -1
- package/dist/loaders/npm-resolve-preamble.d.ts +4 -5
- package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
- package/dist/loaders/npm-resolve-preamble.js +14 -21
- package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
- package/dist/loaders/pre-bundle-preamble.js +0 -1
- package/dist/npm/cache.js +1 -1
- package/dist/npm/install-batch-facet.d.ts.map +1 -1
- package/dist/npm/install-batch-facet.js +7 -12
- package/dist/npm/installer.d.ts +5 -7
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +20 -101
- package/dist/npm/r2-cache.d.ts +17 -29
- package/dist/npm/r2-cache.d.ts.map +1 -1
- package/dist/npm/r2-cache.js +16 -27
- package/dist/npm/resolve-facet.d.ts +11 -17
- package/dist/npm/resolve-facet.d.ts.map +1 -1
- package/dist/npm/resolve-facet.js +14 -28
- package/dist/npm/resolve-one-facet.d.ts +10 -13
- package/dist/npm/resolve-one-facet.d.ts.map +1 -1
- package/dist/npm/resolve-one-facet.js +8 -10
- package/dist/npm/resolver.d.ts +0 -2
- package/dist/npm/resolver.d.ts.map +1 -1
- package/dist/npm/resolver.js +0 -12
- package/dist/observability/oom-discriminator.d.ts +0 -2
- package/dist/observability/oom-discriminator.d.ts.map +1 -1
- package/dist/observability/oom-discriminator.js +0 -2
- package/dist/replica/routing.js +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/index.js +1 -1
- package/dist/runtime/barrel-synthesizer.js +1 -1
- package/dist/runtime/clang-runner.d.ts +5 -6
- package/dist/runtime/clang-runner.d.ts.map +1 -1
- package/dist/runtime/clang-runner.js +5 -6
- package/dist/runtime/esbuild-service.d.ts.map +1 -1
- package/dist/runtime/esbuild-service.js +0 -3
- package/dist/runtime/framework-detect.d.ts +0 -1
- package/dist/runtime/framework-detect.d.ts.map +1 -1
- package/dist/runtime/framework-detect.js +0 -1
- package/dist/runtime/node-runner.d.ts +1 -1
- package/dist/runtime/node-runner.js +1 -1
- package/dist/runtime/node-shims.d.ts.map +1 -1
- package/dist/runtime/node-shims.js +0 -22
- package/dist/runtime/package-manager.d.ts +2 -7
- package/dist/runtime/package-manager.d.ts.map +1 -1
- package/dist/runtime/package-manager.js +2 -7
- package/dist/runtime/process-logs-api.js +1 -1
- package/dist/runtime/process-logs.d.ts +0 -1
- package/dist/runtime/process-logs.d.ts.map +1 -1
- package/dist/runtime/process-table.d.ts +2 -2
- package/dist/runtime/process-table.d.ts.map +1 -1
- package/dist/runtime/process-table.js +1 -1
- package/dist/runtime/python-repl.d.ts +0 -1
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +0 -1
- package/dist/runtime/python-runner.d.ts +1 -2
- package/dist/runtime/python-runner.d.ts.map +1 -1
- package/dist/runtime/python-runner.js +1 -3
- package/dist/runtime/repl-session.d.ts +0 -1
- package/dist/runtime/repl-session.d.ts.map +1 -1
- package/dist/runtime/repl-session.js +1 -2
- package/dist/runtime/require-resolver.d.ts.map +1 -1
- package/dist/runtime/require-resolver.js +1 -4
- package/dist/runtime/ruby-runner.d.ts +0 -1
- package/dist/runtime/ruby-runner.d.ts.map +1 -1
- package/dist/runtime/ruby-runner.js +0 -1
- package/dist/runtime/runtime-catalog.d.ts +2 -4
- package/dist/runtime/runtime-catalog.d.ts.map +1 -1
- package/dist/runtime/runtime-catalog.js +2 -4
- package/dist/runtime/runtime-registry.d.ts +1 -1
- package/dist/runtime/runtime-registry.js +1 -1
- package/dist/runtime/streams.d.ts.map +1 -1
- package/dist/runtime/streams.js +0 -1
- package/dist/runtime/wasi-instance.d.ts +35 -45
- package/dist/runtime/wasi-instance.d.ts.map +1 -1
- package/dist/runtime/wasi-instance.js +87 -103
- package/dist/runtime/wasm-runner.d.ts +9 -15
- package/dist/runtime/wasm-runner.d.ts.map +1 -1
- package/dist/runtime/wasm-runner.js +23 -29
- package/dist/session/bindings.d.ts +2 -7
- package/dist/session/bindings.d.ts.map +1 -1
- package/dist/session/bindings.js +3 -8
- package/dist/session/helpers.d.ts +2 -9
- package/dist/session/helpers.d.ts.map +1 -1
- package/dist/session/helpers.js +2 -10
- package/dist/session/init.d.ts +3 -6
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +25 -30
- package/dist/session/nimbus-session.d.ts +1 -1
- package/dist/session/nimbus-session.js +5 -5
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +9 -16
- package/dist/session/rpc.d.ts +2 -2
- package/dist/session/rpc.js +6 -6
- package/dist/session/supervisor-rpc.d.ts +1 -2
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +1 -5
- package/dist/shell/features.d.ts +5 -5
- package/dist/shell/features.js +6 -6
- package/dist/shell/unix-commands.js +15 -15
- package/dist/vfs/dev-provider.d.ts +1 -1
- package/dist/vfs/dev-provider.js +1 -1
- package/dist/vfs/sqlite-vfs.d.ts +3 -3
- package/dist/vfs/sqlite-vfs.d.ts.map +1 -1
- package/dist/vfs/sqlite-vfs.js +10 -11
- package/package.json +12 -2
- package/public/s/index.html +44 -75
- package/scripts/bundle-facet-workers.mjs +1 -1
- package/scripts/bundle-git.mjs +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasi-instance.d.ts","sourceRoot":"","sources":["../../src/runtime/wasi-instance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,
|
|
1
|
+
{"version":3,"file":"wasi-instance.d.ts","sourceRoot":"","sources":["../../src/runtime/wasi-instance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqGG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,u0pFAk2DtC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,QAAQ,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvD,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,yCAAyC;IACzC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,mCAAmC;IACnC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,kCAAkC;IAClC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,kCAAkC;IAClC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/E,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,wBAAwB;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EA2BhD,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* wasi-instance.ts — WASI snapshot_preview1 shim for Nimbus
|
|
2
|
+
* wasi-instance.ts — WASI snapshot_preview1 shim for Nimbus.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Core WASI surface:
|
|
5
5
|
* args_get / args_sizes_get / environ_get / environ_sizes_get
|
|
6
6
|
* fd_close / fd_write / fd_read / fd_seek / fd_tell
|
|
7
7
|
* fd_fdstat_get / fd_fdstat_set_flags
|
|
@@ -10,53 +10,53 @@
|
|
|
10
10
|
* random_get
|
|
11
11
|
* sched_yield
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* Filesystem WASI additions:
|
|
14
14
|
* path_open
|
|
15
15
|
* path_create_directory / path_remove_directory
|
|
16
16
|
* path_unlink_file
|
|
17
|
-
* path_rename
|
|
18
|
-
* path_filestat_get / path_filestat_set_times
|
|
17
|
+
* path_rename
|
|
18
|
+
* path_filestat_get / path_filestat_set_times
|
|
19
19
|
* fd_readdir (cookie-paginated)
|
|
20
20
|
* fd_filestat_get / fd_filestat_set_size
|
|
21
21
|
* fd_pread / fd_pwrite
|
|
22
22
|
* fd_prestat_get / fd_prestat_dir_name (real preopens, not EBADF)
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* Socket, polling, and metadata additions:
|
|
25
|
+
* - per-file mtime/atime/ctime tracking + in-memory symlink table
|
|
26
26
|
* (additive — files Map shape unchanged; parallel times/symlinks Maps)
|
|
27
|
-
*
|
|
27
|
+
* - fd_filestat_set_times / path_filestat_set_times — implementations that
|
|
28
28
|
* write mtime/atime; honor ATIM_NOW / MTIM_NOW flags via clock_realtime
|
|
29
|
-
*
|
|
29
|
+
* - path_symlink / path_readlink / path_link. Symlink
|
|
30
30
|
* resolution via __wasiResolvePathFull(baseFd, path, followFlag)
|
|
31
31
|
* with POSIX-style 40-deep loop detection (returns ELOOP).
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* - fd_allocate extends bytes to offset+len and zero-fills.
|
|
33
|
+
* - proc_raise(sig) throws __WasiExit(128 + sig) per POSIX shell convention
|
|
34
|
+
* (SIGABRT=6 -> 134, SIGTERM=15 -> 143).
|
|
35
|
+
* - fd_fdstat_set_rights tracks per-fd rights mask;
|
|
36
36
|
* fd_fdstat_get returns the tracked mask instead of wide-open).
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* Socket support via cloudflare:sockets + JSPI:
|
|
39
|
+
* - sock_send / sock_recv / sock_shutdown via
|
|
40
40
|
* WebAssembly.Suspending wrapping. path_open('/dev/tcp/<host>/<port>')
|
|
41
41
|
* synthetic-path triggers cloudflare:sockets connect().
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* Poll support via JSPI:
|
|
44
|
+
* - poll_oneoff handles all three subscription types in a
|
|
45
45
|
* single Promise.race wrapped via WebAssembly.Suspending:
|
|
46
46
|
* CLOCK (REALTIME + MONOTONIC, relative + absolute deadlines via
|
|
47
|
-
* SUBSCRIPTION_CLOCK_ABSTIME flag)
|
|
48
|
-
* FD_READ/FD_WRITE on file/dir/stdio/symlink
|
|
47
|
+
* SUBSCRIPTION_CLOCK_ABSTIME flag) -> setTimeout to deadline.
|
|
48
|
+
* FD_READ/FD_WRITE on file/dir/stdio/symlink -> always-ready
|
|
49
49
|
* (POSIX: regular files never block).
|
|
50
|
-
* FD_READ on socket
|
|
50
|
+
* FD_READ on socket -> real await on
|
|
51
51
|
* socket.readable.getReader().read(); data is stashed on
|
|
52
52
|
* entry.readBuf so subsequent sock_recv sees it pre-loaded.
|
|
53
|
-
* FD_WRITE on socket
|
|
53
|
+
* FD_WRITE on socket -> always-ready (CF Workers writable
|
|
54
54
|
* streams have unbounded queue from wasm-side perspective).
|
|
55
55
|
* Concurrent-ready drain: after first-promise resolution, probes
|
|
56
56
|
* each remaining promise against a microtask sentinel; collects
|
|
57
57
|
* all currently-resolved events into the output.
|
|
58
58
|
*
|
|
59
|
-
*
|
|
59
|
+
* wasi-threads hard limit:
|
|
60
60
|
* wasi_thread_start is NOT exposed in this shim's import table.
|
|
61
61
|
* Workers facet isolates have no shared-linear-memory primitive
|
|
62
62
|
* across instances, so pthread semantics cannot be implemented
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
* "undefined symbol: thread_spawn" error at LINK time — a clear
|
|
65
65
|
* diagnostic instead of a runtime memory-corruption bug.
|
|
66
66
|
* Full rationale + workarounds-considered-and-rejected:
|
|
67
|
-
* docs/wasi-threads
|
|
67
|
+
* docs/wasi-threads.md.
|
|
68
68
|
*
|
|
69
|
-
* Architecture (
|
|
69
|
+
* Architecture (filesystem WASI strategy)
|
|
70
70
|
* ──────────────────────────────
|
|
71
71
|
*
|
|
72
72
|
* Strategy: bulk-snapshot + flush. The supervisor snapshots the user's
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
* when the user fn runs. Self-contained — no closure captures, no imports.
|
|
108
108
|
*/
|
|
109
109
|
export const WASI_INSTANCE_PREAMBLE_SRC = `
|
|
110
|
-
// ── BEGIN: wasi-instance preamble (
|
|
110
|
+
// ── BEGIN: wasi-instance preamble (core WASI + filesystem WASI) ─────────────────────
|
|
111
111
|
// Hand-written WASI snapshot_preview1 shim for Nimbus.
|
|
112
112
|
// Source mirror: src/runtime/wasi-instance.ts. Keep in sync by hand.
|
|
113
113
|
|
|
@@ -162,25 +162,24 @@ const __WASI_PREOPENTYPE_DIR = 0;
|
|
|
162
162
|
const __WASI_SYMLOOP_MAX = 40;
|
|
163
163
|
// Default per-fd rights mask (wide-open).
|
|
164
164
|
const __WASI_RIGHTS_ALL = 0xFFFFFFFFFFFFFFFFn;
|
|
165
|
-
//
|
|
165
|
+
// WASI socket and polling support B7: sock_shutdown SD flags.
|
|
166
166
|
const __WASI_SDFLAGS_RD = 1;
|
|
167
167
|
const __WASI_SDFLAGS_WR = 2;
|
|
168
|
-
//
|
|
168
|
+
// WASI socket and polling support B8: poll_oneoff subscription / event types.
|
|
169
169
|
const __WASI_EVENTTYPE_CLOCK = 0;
|
|
170
170
|
const __WASI_EVENTTYPE_FD_READ = 1;
|
|
171
171
|
const __WASI_EVENTTYPE_FD_WRITE = 2;
|
|
172
172
|
const __WASI_SUBCLOCKFLAGS_ABSTIME = 1; // SUBSCRIPTION_CLOCK_ABSTIME
|
|
173
|
-
//
|
|
173
|
+
// WASI socket and polling support B7: synthetic-path prefix recognised by path_open as a request
|
|
174
174
|
// to open a TCP socket. Mirrors bash's /dev/tcp/<host>/<port> convention
|
|
175
175
|
// (https://www.gnu.org/software/bash/manual/html_node/Redirections.html).
|
|
176
176
|
const __WASI_TCP_PATH_PREFIX = '/dev/tcp/';
|
|
177
177
|
|
|
178
|
-
//
|
|
178
|
+
// WASI socket and polling support B7: resolved at preamble module-init via dynamic import.
|
|
179
179
|
// CF docs: "TCP sockets cannot be created in global scope and shared
|
|
180
180
|
// across requests" — so we only IMPORT the module here (cheap symbol
|
|
181
181
|
// resolution); the actual connect() call lives inside path_open which
|
|
182
182
|
// runs at facet-handler time (i.e., within WorkerEntrypoint.execute()).
|
|
183
|
-
// See /workspace/.seal-internal/2026-05-11-stream-b/p3-spike.md §2.
|
|
184
183
|
let __cfSocketConnect = null;
|
|
185
184
|
// Top-level await is supported in workerd ES modules at module-init.
|
|
186
185
|
// If import fails (no cloudflare:sockets binding, or running under a
|
|
@@ -199,17 +198,17 @@ class __WasiExit { constructor(code) { this.code = code | 0; } }
|
|
|
199
198
|
//
|
|
200
199
|
// __wasiInitFS({ root, preopens, files, dirs, times?, symlinks? }) —
|
|
201
200
|
// install a per-call FS:
|
|
202
|
-
// root string — canonical session root, e.g. 'home/user/wasi-
|
|
201
|
+
// root string — canonical session root, e.g. 'home/user/wasi-files'.
|
|
203
202
|
// preopens Array<{ wasiPath, vfsPath }> — fd>=3 preopens (in order).
|
|
204
203
|
// files Record<vfsPath, base64 string> — initial file contents.
|
|
205
204
|
// dirs Array<vfsPath> — initial directory list.
|
|
206
205
|
// times Record<vfsPath, {mtime, atime, ctime}> | undefined
|
|
207
|
-
// — per-path nanosecond timestamps (
|
|
206
|
+
// — per-path nanosecond timestamps (WASI socket and polling support B1). Optional;
|
|
208
207
|
// paths without entries default to "now" at init time.
|
|
209
208
|
// Values are decimal strings to survive JSON.serialize
|
|
210
209
|
// (BigInt is not JSON-safe); converted to BigInt internally.
|
|
211
210
|
// symlinks Record<vfsPath, targetPath> | undefined
|
|
212
|
-
// —
|
|
211
|
+
// — WASI socket and polling support B3 in-memory symlink table. Optional; defaults
|
|
213
212
|
// to empty. Target paths are canonicalized at insertion.
|
|
214
213
|
//
|
|
215
214
|
// After _start returns, __wasiSnapshotFS() extracts:
|
|
@@ -257,7 +256,7 @@ function __wasiNowNs() {
|
|
|
257
256
|
function __wasiInitFS(opts) {
|
|
258
257
|
const files = new Map(); // canonicalVfsPath → Uint8Array
|
|
259
258
|
const dirs = new Set(); // canonicalVfsPath
|
|
260
|
-
//
|
|
259
|
+
// WASI socket and polling support B1: parallel timestamp + symlink maps.
|
|
261
260
|
const times = new Map(); // canonicalVfsPath → {mtime: BigInt, atime: BigInt, ctime: BigInt}
|
|
262
261
|
const symlinks = new Map(); // canonicalVfsPath → targetPath (canonical)
|
|
263
262
|
// mirror originals for diff at flush time
|
|
@@ -288,7 +287,7 @@ function __wasiInitFS(opts) {
|
|
|
288
287
|
origTimes.set(canon, { mtime: t.mtime, atime: t.atime, ctime: t.ctime });
|
|
289
288
|
}
|
|
290
289
|
}
|
|
291
|
-
//
|
|
290
|
+
// WASI socket and polling support B1: load explicit per-path timestamps if supervisor provided them.
|
|
292
291
|
// Values arrive as decimal strings (BigInt → JSON.stringify safe) or numbers.
|
|
293
292
|
for (const [path, t] of Object.entries(opts.times || {})) {
|
|
294
293
|
const canon = __wasiCanonicalize(path);
|
|
@@ -300,7 +299,7 @@ function __wasiInitFS(opts) {
|
|
|
300
299
|
times.set(canon, { mtime, atime, ctime });
|
|
301
300
|
origTimes.set(canon, { mtime, atime, ctime });
|
|
302
301
|
}
|
|
303
|
-
//
|
|
302
|
+
// WASI socket and polling support B3: load explicit symlinks if supervisor provided them.
|
|
304
303
|
for (const [path, target] of Object.entries(opts.symlinks || {})) {
|
|
305
304
|
const canon = __wasiCanonicalize(path);
|
|
306
305
|
symlinks.set(canon, String(target));
|
|
@@ -332,7 +331,7 @@ function __wasiInitFS(opts) {
|
|
|
332
331
|
}
|
|
333
332
|
}
|
|
334
333
|
|
|
335
|
-
//
|
|
334
|
+
// WASI socket and polling support B7 helper: open a TCP socket via cloudflare:sockets when
|
|
336
335
|
// path_open is invoked on a /dev/tcp/<host>/<port> synthetic path.
|
|
337
336
|
// Returns a WASI errno. Allocates a new fd of kind:'socket' on success
|
|
338
337
|
// and writes it to fdOutPtr.
|
|
@@ -390,7 +389,7 @@ function __wasiOpenTcpSocket(pathArg, fdflags, fdOutPtr, writeU32LE) {
|
|
|
390
389
|
return __WASI_ESUCCESS;
|
|
391
390
|
}
|
|
392
391
|
|
|
393
|
-
//
|
|
392
|
+
// WASI socket and polling support B1+B2 helpers: update tracked timestamps for a path. Idempotent.
|
|
394
393
|
// Caller passes nanosecond BigInt(s); pass null for fields to keep unchanged.
|
|
395
394
|
function __wasiTouchTimes(canonPath, mtimeNs, atimeNs, ctimeNs) {
|
|
396
395
|
if (!__wasiFS) return;
|
|
@@ -420,9 +419,9 @@ function __wasiSnapshotFS() {
|
|
|
420
419
|
const filesDeleted = [];
|
|
421
420
|
const dirsCreated = [];
|
|
422
421
|
const dirsDeleted = [];
|
|
423
|
-
const timesChanged = {}; //
|
|
424
|
-
const symlinksCreated = {}; //
|
|
425
|
-
const symlinksDeleted = []; //
|
|
422
|
+
const timesChanged = {}; // WASI socket and polling support B1: mtime/atime/ctime diffs
|
|
423
|
+
const symlinksCreated = {}; // WASI socket and polling support B3: new symlinks
|
|
424
|
+
const symlinksDeleted = []; // WASI socket and polling support B3: removed symlinks
|
|
426
425
|
// files: anything in __wasiFS.files not in orig, or whose bytes differ.
|
|
427
426
|
for (const [path, bytes] of __wasiFS.files) {
|
|
428
427
|
const orig = __wasiFS.origFiles.get(path);
|
|
@@ -450,7 +449,7 @@ function __wasiSnapshotFS() {
|
|
|
450
449
|
for (const path of __wasiFS.origDirs) {
|
|
451
450
|
if (!__wasiFS.dirs.has(path)) dirsDeleted.push(path);
|
|
452
451
|
}
|
|
453
|
-
//
|
|
452
|
+
// WASI socket and polling support B1: times diff. BigInt → decimal string (JSON.stringify-safe).
|
|
454
453
|
for (const [path, t] of __wasiFS.times) {
|
|
455
454
|
const orig = __wasiFS.origTimes.get(path);
|
|
456
455
|
if (!orig || orig.mtime !== t.mtime || orig.atime !== t.atime || orig.ctime !== t.ctime) {
|
|
@@ -461,7 +460,7 @@ function __wasiSnapshotFS() {
|
|
|
461
460
|
};
|
|
462
461
|
}
|
|
463
462
|
}
|
|
464
|
-
//
|
|
463
|
+
// WASI socket and polling support B3: symlink diff.
|
|
465
464
|
for (const [path, target] of __wasiFS.symlinks) {
|
|
466
465
|
if (__wasiFS.origSymlinks.get(path) !== target) {
|
|
467
466
|
symlinksCreated[path] = target;
|
|
@@ -483,9 +482,9 @@ function __wasiSnapshotFS() {
|
|
|
483
482
|
// { kind: 'preopen', wasiPath, vfsPath, rights? }
|
|
484
483
|
// { kind: 'file', vfsPath, offset, oflags, fdflags, rights? }
|
|
485
484
|
// { kind: 'dir', vfsPath, readdirEntries: null | Array, cookie, rights? }
|
|
486
|
-
// { kind: 'symlink', vfsPath, target, rights? } //
|
|
485
|
+
// { kind: 'symlink', vfsPath, target, rights? } // WASI socket and polling support B3 (only when O_NOFOLLOW)
|
|
487
486
|
//
|
|
488
|
-
//
|
|
487
|
+
// WASI socket and polling support B6: 'rights' is an optional BigInt mask. When set, fd_fdstat_get
|
|
489
488
|
// returns it (instead of the wide-open default). fd_fdstat_set_rights
|
|
490
489
|
// writes to it. The mask is advisory in this shim (we don't enforce per-fn
|
|
491
490
|
// rights checks in v1 — single-tenant facet, no untrusted callers).
|
|
@@ -493,7 +492,7 @@ const fdTable = new Map();
|
|
|
493
492
|
let nextFd = 3;
|
|
494
493
|
|
|
495
494
|
// Resolve a WASI path against a preopen fd; returns the canonical VFS path
|
|
496
|
-
// WITHOUT following symlinks.
|
|
495
|
+
// WITHOUT following symlinks. WASI socket and polling support kept this name compatible with all
|
|
497
496
|
// existing call sites (~10 of them inside the imports object).
|
|
498
497
|
//
|
|
499
498
|
// wasi-path-fix: a single preopen { wasiPath: '/', vfsPath: 'home/user' }
|
|
@@ -539,7 +538,7 @@ function __wasiResolvePath(baseFd, pathStr) {
|
|
|
539
538
|
return __wasiCanonicalize(baseVfs + '/' + trimmed);
|
|
540
539
|
}
|
|
541
540
|
|
|
542
|
-
//
|
|
541
|
+
// WASI socket and polling support B3: resolve a path WITH optional symlink-follow + POSIX loop
|
|
543
542
|
// detection. Returns {path: canonical, isSymlink: bool, err?: errno}.
|
|
544
543
|
// - If followFlag is true (default — matches LOOKUPFLAGS_SYMLINK_FOLLOW),
|
|
545
544
|
// walks the symlink chain up to __WASI_SYMLOOP_MAX depth. ELOOP if exceeded.
|
|
@@ -632,7 +631,7 @@ function __wasiMakeImports(opts) {
|
|
|
632
631
|
}
|
|
633
632
|
function setFile(vfsPath, bytes) {
|
|
634
633
|
__wasiFS.files.set(vfsPath, bytes);
|
|
635
|
-
//
|
|
634
|
+
// WASI socket and polling support B1: bump mtime+ctime on every write. atime stays as-is
|
|
636
635
|
// (read paths bump atime explicitly via touchAccess()).
|
|
637
636
|
__wasiBumpMtime(vfsPath);
|
|
638
637
|
}
|
|
@@ -641,7 +640,7 @@ function __wasiMakeImports(opts) {
|
|
|
641
640
|
__wasiFS.times.delete(vfsPath);
|
|
642
641
|
}
|
|
643
642
|
function touchAccess(vfsPath) {
|
|
644
|
-
//
|
|
643
|
+
// WASI socket and polling support B1: bump atime on a read. mtime/ctime unchanged.
|
|
645
644
|
if (!__wasiFS) return;
|
|
646
645
|
const cur = __wasiFS.times.get(vfsPath);
|
|
647
646
|
if (cur) cur.atime = __wasiNowNs();
|
|
@@ -655,7 +654,7 @@ function __wasiMakeImports(opts) {
|
|
|
655
654
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
656
655
|
p = p ? (p + '/' + parts[i]) : parts[i];
|
|
657
656
|
__wasiFS.dirs.add(p);
|
|
658
|
-
//
|
|
657
|
+
// WASI socket and polling support B1: ensure ancestor dirs have a times entry.
|
|
659
658
|
if (!__wasiFS.times.has(p)) {
|
|
660
659
|
const now = __wasiNowNs();
|
|
661
660
|
__wasiFS.times.set(p, { mtime: now, atime: now, ctime: now });
|
|
@@ -734,7 +733,7 @@ function __wasiMakeImports(opts) {
|
|
|
734
733
|
// Don't delete preopens — they're meant to persist for the program lifetime.
|
|
735
734
|
const entry = fdTable.get(fd);
|
|
736
735
|
if (entry.kind === 'preopen') return __WASI_ESUCCESS;
|
|
737
|
-
//
|
|
736
|
+
// WASI socket and polling support B7: best-effort close of socket streams. The actual
|
|
738
737
|
// socket.close() is fire-and-forget (sync return per WASI) — if
|
|
739
738
|
// the program wants to await closure it should sock_shutdown
|
|
740
739
|
// first. We DO drop the fd-table entry so subsequent ops on this
|
|
@@ -813,9 +812,9 @@ function __wasiMakeImports(opts) {
|
|
|
813
812
|
},
|
|
814
813
|
|
|
815
814
|
fd_seek(fd, offsetArg, whence, newOffsetPtr) {
|
|
816
|
-
// WASI/V8 passes i64 args as BigInt.
|
|
815
|
+
// WASI/V8 passes i64 args as BigInt. core WASI mistakenly assumed
|
|
817
816
|
// (lo, hi) i32 pairs; that worked only because hello-world never
|
|
818
|
-
// exercised seek.
|
|
817
|
+
// exercised seek. filesystem WASI: accept BigInt directly.
|
|
819
818
|
if (fd === 0 || fd === 1 || fd === 2) {
|
|
820
819
|
writeU64LE(newOffsetPtr, 0n);
|
|
821
820
|
return __WASI_ESUCCESS;
|
|
@@ -862,13 +861,13 @@ function __wasiMakeImports(opts) {
|
|
|
862
861
|
} else if (entry.kind === 'symlink') {
|
|
863
862
|
ftype = __WASI_FT_SYMBOLIC_LINK;
|
|
864
863
|
} else if (entry.kind === 'socket') {
|
|
865
|
-
ftype = __WASI_FT_SOCKET_STREAM; //
|
|
864
|
+
ftype = __WASI_FT_SOCKET_STREAM; // WASI socket and polling support B7
|
|
866
865
|
}
|
|
867
866
|
dv.setUint8(statPtr, ftype);
|
|
868
867
|
dv.setUint8(statPtr + 1, 0);
|
|
869
868
|
dv.setUint16(statPtr + 2, (entry.fdflags || 0) & 0xFFFF, true);
|
|
870
869
|
dv.setUint32(statPtr + 4, 0, true);
|
|
871
|
-
//
|
|
870
|
+
// WASI socket and polling support B6: honor entry.rights when set, else wide-open default.
|
|
872
871
|
// The legacy '0x3FFFFFFFn' was a 30-bit truncation of the actual
|
|
873
872
|
// 64-bit rights field; modern wasi-libc probes specific bits so we
|
|
874
873
|
// now publish full 64-bit __WASI_RIGHTS_ALL.
|
|
@@ -886,7 +885,7 @@ function __wasiMakeImports(opts) {
|
|
|
886
885
|
return __WASI_ESUCCESS;
|
|
887
886
|
},
|
|
888
887
|
|
|
889
|
-
//
|
|
888
|
+
// WASI socket and polling support B6: track per-fd rights mask. Callers narrow their own caps;
|
|
890
889
|
// we record but don't enforce in v1 (single-tenant facet). The narrow
|
|
891
890
|
// is visible to subsequent fd_fdstat_get calls, satisfying capability-
|
|
892
891
|
// tightening probes that round-trip the mask.
|
|
@@ -930,16 +929,15 @@ function __wasiMakeImports(opts) {
|
|
|
930
929
|
path_open(baseFd, dirflags, pathPtr, pathLen, oflags, _rightsBase, _rightsInheriting, fdflags, fdOutPtr) {
|
|
931
930
|
const pathArg = readPath(pathPtr, pathLen);
|
|
932
931
|
|
|
933
|
-
//
|
|
932
|
+
// WASI socket and polling support B7: synthetic /dev/tcp/<host>/<port> path — open a TCP
|
|
934
933
|
// socket via cloudflare:sockets. Bash-like convention; matches
|
|
935
|
-
// /workspace/.seal-internal/2026-05-11-stream-b/p3-spike.md §2.
|
|
936
934
|
// Intercept BEFORE resolution because /dev/tcp/* doesn't exist in
|
|
937
935
|
// the in-memory FS — __wasiResolvePath would canonicalize it but
|
|
938
936
|
// not find any entry.
|
|
939
937
|
if (pathArg.startsWith(__WASI_TCP_PATH_PREFIX)) {
|
|
940
938
|
return __wasiOpenTcpSocket(pathArg, fdflags, fdOutPtr, writeU32LE);
|
|
941
939
|
}
|
|
942
|
-
//
|
|
940
|
+
// WASI socket and polling support B3: honor LOOKUPFLAGS_SYMLINK_FOLLOW (default behavior
|
|
943
941
|
// when bit is set or dirflags omitted). When NOT set, surface the
|
|
944
942
|
// symlink itself as a 'symlink' fd kind so readlink can introspect.
|
|
945
943
|
const follow = (dirflags & __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW) !== 0 || dirflags === 0;
|
|
@@ -1001,7 +999,7 @@ function __wasiMakeImports(opts) {
|
|
|
1001
999
|
if (__wasiFS.files.has(resolved)) return __WASI_EEXIST;
|
|
1002
1000
|
ensureParentDirs(resolved);
|
|
1003
1001
|
__wasiFS.dirs.add(resolved);
|
|
1004
|
-
//
|
|
1002
|
+
// WASI socket and polling support B1: seed times for the new dir.
|
|
1005
1003
|
const now = __wasiNowNs();
|
|
1006
1004
|
__wasiFS.times.set(resolved, { mtime: now, atime: now, ctime: now });
|
|
1007
1005
|
return __WASI_ESUCCESS;
|
|
@@ -1024,7 +1022,7 @@ function __wasiMakeImports(opts) {
|
|
|
1024
1022
|
const resolved = __wasiResolvePath(baseFd, path);
|
|
1025
1023
|
if (resolved === null) return __WASI_EBADF;
|
|
1026
1024
|
if (__wasiFS.dirs.has(resolved)) return __WASI_EISDIR;
|
|
1027
|
-
//
|
|
1025
|
+
// WASI socket and polling support B3: unlink also removes a symlink at this path. We
|
|
1028
1026
|
// operate on the unfollowed path (POSIX unlink semantics — removes
|
|
1029
1027
|
// the directory entry itself, not the symlink target).
|
|
1030
1028
|
if (__wasiFS.symlinks.has(resolved)) {
|
|
@@ -1085,7 +1083,7 @@ function __wasiMakeImports(opts) {
|
|
|
1085
1083
|
// ── path_filestat_get ──
|
|
1086
1084
|
path_filestat_get(baseFd, lookupflags, pathPtr, pathLen, statPtr) {
|
|
1087
1085
|
const path = readPath(pathPtr, pathLen);
|
|
1088
|
-
//
|
|
1086
|
+
// WASI socket and polling support B3: follow symlinks unless explicitly told not to.
|
|
1089
1087
|
const follow = (lookupflags & __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW) !== 0 || lookupflags === 0;
|
|
1090
1088
|
const rp = __wasiResolvePathFull(baseFd, path, follow);
|
|
1091
1089
|
if (rp.err === __WASI_EBADF) return __WASI_EBADF;
|
|
@@ -1104,7 +1102,7 @@ function __wasiMakeImports(opts) {
|
|
|
1104
1102
|
} else {
|
|
1105
1103
|
return __WASI_ENOENT;
|
|
1106
1104
|
}
|
|
1107
|
-
//
|
|
1105
|
+
// WASI socket and polling support B1: emit real timestamps.
|
|
1108
1106
|
const t = __wasiFS.times.get(resolved) || { mtime: 0n, atime: 0n, ctime: 0n };
|
|
1109
1107
|
const dv = view();
|
|
1110
1108
|
// filestat_t layout (WASI preview1):
|
|
@@ -1122,7 +1120,7 @@ function __wasiMakeImports(opts) {
|
|
|
1122
1120
|
return __WASI_ESUCCESS;
|
|
1123
1121
|
},
|
|
1124
1122
|
|
|
1125
|
-
//
|
|
1123
|
+
// WASI socket and polling support B2: real path_filestat_set_times. Honors ATIM/ATIM_NOW/
|
|
1126
1124
|
// MTIM/MTIM_NOW flags. Spec: atim_ns and mtim_ns are absolute
|
|
1127
1125
|
// nanosecond timestamps; flags select which fields to update + whether
|
|
1128
1126
|
// to clamp to "now". ENOENT if path doesn't exist.
|
|
@@ -1151,7 +1149,7 @@ function __wasiMakeImports(opts) {
|
|
|
1151
1149
|
return __WASI_ESUCCESS;
|
|
1152
1150
|
},
|
|
1153
1151
|
|
|
1154
|
-
//
|
|
1152
|
+
// WASI socket and polling support B3: read the target string of a symlink. Spec:
|
|
1155
1153
|
// path_readlink(fd, path, path_len, buf, buf_len, *bufused)
|
|
1156
1154
|
// Truncates to buf_len; writes actual bytes to *bufused.
|
|
1157
1155
|
path_readlink(baseFd, pathPtr, pathLen, bufPtr, bufLen, bufUsedPtr) {
|
|
@@ -1174,7 +1172,7 @@ function __wasiMakeImports(opts) {
|
|
|
1174
1172
|
return __WASI_ESUCCESS;
|
|
1175
1173
|
},
|
|
1176
1174
|
|
|
1177
|
-
//
|
|
1175
|
+
// WASI socket and polling support B3: create a symlink. Spec:
|
|
1178
1176
|
// path_symlink(old_path, fd, new_path)
|
|
1179
1177
|
// old_path is the symlink's TARGET (stored verbatim); fd+new_path
|
|
1180
1178
|
// is the location where the symlink itself is created.
|
|
@@ -1195,7 +1193,7 @@ function __wasiMakeImports(opts) {
|
|
|
1195
1193
|
return __WASI_ESUCCESS;
|
|
1196
1194
|
},
|
|
1197
1195
|
|
|
1198
|
-
//
|
|
1196
|
+
// WASI socket and polling support B3: hardlink. Spec:
|
|
1199
1197
|
// path_link(old_fd, old_flags, old_path, new_fd, new_path)
|
|
1200
1198
|
// Implements as a shared-buffer alias. POSIX semantics: both names
|
|
1201
1199
|
// point at the same inode, so writes through either are visible to
|
|
@@ -1271,7 +1269,7 @@ function __wasiMakeImports(opts) {
|
|
|
1271
1269
|
setFile(entry.vfsPath, next);
|
|
1272
1270
|
return __WASI_ESUCCESS;
|
|
1273
1271
|
},
|
|
1274
|
-
//
|
|
1272
|
+
// WASI socket and polling support B2: real fd_filestat_set_times.
|
|
1275
1273
|
fd_filestat_set_times(fd, atimArg, mtimArg, fstflags) {
|
|
1276
1274
|
const entry = fdTable.get(fd);
|
|
1277
1275
|
if (!entry) return __WASI_EBADF;
|
|
@@ -1403,7 +1401,7 @@ function __wasiMakeImports(opts) {
|
|
|
1403
1401
|
},
|
|
1404
1402
|
|
|
1405
1403
|
fd_advise() { return __WASI_ESUCCESS; },
|
|
1406
|
-
//
|
|
1404
|
+
// WASI socket and polling support B4: real fd_allocate. Extends the file's byte buffer with
|
|
1407
1405
|
// zeros so [offset, offset+len) is allocated. POSIX posix_fallocate
|
|
1408
1406
|
// semantics. ENOSPC is not reachable in our in-memory FS (the
|
|
1409
1407
|
// 32 MiB snapshot cap is enforced at supervisor level; in-call we
|
|
@@ -1433,7 +1431,7 @@ function __wasiMakeImports(opts) {
|
|
|
1433
1431
|
|
|
1434
1432
|
// ── proc_exit ──
|
|
1435
1433
|
proc_exit(code) { throw new __WasiExit(code | 0); },
|
|
1436
|
-
//
|
|
1434
|
+
// WASI socket and polling support B5: proc_raise(sig) — POSIX shell convention encodes a
|
|
1437
1435
|
// signal-terminated process as exit-status 128+sig. SIGABRT=6 → 134,
|
|
1438
1436
|
// SIGTERM=15 → 143, SIGKILL=9 → 137. Returns errno (never actually;
|
|
1439
1437
|
// throws via __WasiExit). The legacy 'throw new __WasiExit(128)' was
|
|
@@ -1481,7 +1479,7 @@ function __wasiMakeImports(opts) {
|
|
|
1481
1479
|
|
|
1482
1480
|
sched_yield() { return __WASI_ESUCCESS; },
|
|
1483
1481
|
|
|
1484
|
-
// ──
|
|
1482
|
+
// ── WASI socket and polling support B8: poll_oneoff FULL ────────────────────────────────
|
|
1485
1483
|
//
|
|
1486
1484
|
// Spec: WASI preview1 poll_oneoff(in_subscriptions, out_events,
|
|
1487
1485
|
// nsubscriptions, *retNevents) blocks until at least one event fires,
|
|
@@ -1748,7 +1746,7 @@ function __wasiMakeImports(opts) {
|
|
|
1748
1746
|
return __WASI_ESUCCESS;
|
|
1749
1747
|
},
|
|
1750
1748
|
|
|
1751
|
-
//
|
|
1749
|
+
// WASI socket and polling support B7: sockets via cloudflare:sockets connect() + JSPI.
|
|
1752
1750
|
//
|
|
1753
1751
|
// sock_send/sock_recv/sock_shutdown are ASYNC fns. They await on
|
|
1754
1752
|
// ReadableStream/WritableStream readers/writers, which means the
|
|
@@ -1883,7 +1881,7 @@ function __wasiMakeImports(opts) {
|
|
|
1883
1881
|
// writer.close() may tear down the underlying connection in
|
|
1884
1882
|
// ways that prevent further reads, even with allowHalfOpen=true.
|
|
1885
1883
|
//
|
|
1886
|
-
// Empirically observed on prod (sock-shutdown-write probe
|
|
1884
|
+
// Empirically observed on prod (sock-shutdown-write probe failing
|
|
1887
1885
|
// after writer.close() with allowHalfOpen=true): subsequent
|
|
1888
1886
|
// sock_recv returns 0 bytes because the readable side stops
|
|
1889
1887
|
// delivering once the writer closes.
|
|
@@ -1898,7 +1896,7 @@ function __wasiMakeImports(opts) {
|
|
|
1898
1896
|
// peer expects EOF to know when the request is done) for
|
|
1899
1897
|
// server-echo-protocol correctness (where the peer streams
|
|
1900
1898
|
// back regardless). The probe is the latter case; documented
|
|
1901
|
-
// limit for the former: see docs/wasi-threads
|
|
1899
|
+
// limit for the former: see docs/wasi-threads.md
|
|
1902
1900
|
// and surrounding sock_* commentary.
|
|
1903
1901
|
if (wantWr && !entry.halfClosedWr) {
|
|
1904
1902
|
entry.halfClosedWr = true;
|
|
@@ -1919,10 +1917,9 @@ function __wasiMakeImports(opts) {
|
|
|
1919
1917
|
},
|
|
1920
1918
|
};
|
|
1921
1919
|
|
|
1922
|
-
//
|
|
1920
|
+
// WASI socket and polling support B7: wrap the async socket imports in WebAssembly.Suspending
|
|
1923
1921
|
// so the wasm caller can use sync-shape calls that yield to the JS
|
|
1924
1922
|
// event loop. Requires V8 14.2+ (workerd Oct 2025+) — see
|
|
1925
|
-
// /workspace/.seal-internal/2026-05-11-jspi-spike/findings.md.
|
|
1926
1923
|
// If Suspending isn't available (older runtime), socket imports remain
|
|
1927
1924
|
// async fns that the wasm boundary will reject with a trap — caller
|
|
1928
1925
|
// sees a clean failure via __wasiRunStartAsync's catch block.
|
|
@@ -1930,7 +1927,7 @@ function __wasiMakeImports(opts) {
|
|
|
1930
1927
|
imports.sock_send = new WebAssembly.Suspending(imports.sock_send);
|
|
1931
1928
|
imports.sock_recv = new WebAssembly.Suspending(imports.sock_recv);
|
|
1932
1929
|
imports.sock_shutdown = new WebAssembly.Suspending(imports.sock_shutdown);
|
|
1933
|
-
//
|
|
1930
|
+
// WASI socket and polling support B8: poll_oneoff also needs JSPI to support CLOCK
|
|
1934
1931
|
// subscriptions (await setTimeout) and socket-fd readiness
|
|
1935
1932
|
// (await reader.read()). Same Suspending shape as sock_*.
|
|
1936
1933
|
imports.poll_oneoff = new WebAssembly.Suspending(imports.poll_oneoff);
|
|
@@ -1959,7 +1956,7 @@ function __wasiRunStart(instance, ctx) {
|
|
|
1959
1956
|
}
|
|
1960
1957
|
}
|
|
1961
1958
|
|
|
1962
|
-
//
|
|
1959
|
+
// WASI socket and polling support (P3/P4 forward-decl): async variant of runStart. Wraps _start
|
|
1963
1960
|
// with WebAssembly.promising so suspending imports (sock_send, sock_recv,
|
|
1964
1961
|
// poll_oneoff) can await Promises and have V8 suspend+resume the wasm
|
|
1965
1962
|
// stack. Returns the SAME shape as __wasiRunStart but in a Promise.
|
|
@@ -1981,7 +1978,6 @@ async function __wasiRunStartAsync(instance, ctx) {
|
|
|
1981
1978
|
// WebAssembly.promising wraps the export so it returns a Promise<void>
|
|
1982
1979
|
// that resolves when the (potentially-suspending) wasm computation
|
|
1983
1980
|
// completes. Available since V8 14.2 (workerd Oct 2025) — see
|
|
1984
|
-
// /workspace/.seal-internal/2026-05-11-jspi-spike/findings.md.
|
|
1985
1981
|
//
|
|
1986
1982
|
// If promising isn't available (older runtimes), fall through to a
|
|
1987
1983
|
// direct call — fully spec-compatible for non-suspending _start.
|
|
@@ -2001,14 +1997,9 @@ async function __wasiRunStartAsync(instance, ctx) {
|
|
|
2001
1997
|
}
|
|
2002
1998
|
// ── END: wasi-instance preamble ─────────────────────────────────────────
|
|
2003
1999
|
`;
|
|
2004
|
-
/**
|
|
2005
|
-
export const
|
|
2006
|
-
|
|
2007
|
-
export const WASI_STREAM_B_P3_FN_COUNT = 39; // +3: B7 sock_send/sock_recv/sock_shutdown
|
|
2008
|
-
export const WASI_STREAM_B_P4_FN_COUNT = 40; // +1: B8 poll_oneoff
|
|
2009
|
-
/** Names of the Wave-1 + Wave-2 + Stream-B P2 functionally-implemented WASI fns. */
|
|
2010
|
-
export const WASI_WAVE2_FNS = Object.freeze([
|
|
2011
|
-
// Wave-1
|
|
2000
|
+
/** Names of the WASI imports implemented by this shim. */
|
|
2001
|
+
export const WASI_IMPLEMENTED_FNS = Object.freeze([
|
|
2002
|
+
// core WASI
|
|
2012
2003
|
'args_get', 'args_sizes_get',
|
|
2013
2004
|
'environ_get', 'environ_sizes_get',
|
|
2014
2005
|
'fd_close', 'fd_read', 'fd_write', 'fd_seek', 'fd_tell',
|
|
@@ -2017,28 +2008,21 @@ export const WASI_WAVE2_FNS = Object.freeze([
|
|
|
2017
2008
|
'clock_time_get', 'clock_res_get',
|
|
2018
2009
|
'random_get',
|
|
2019
2010
|
'sched_yield',
|
|
2020
|
-
//
|
|
2011
|
+
// filesystem WASI
|
|
2021
2012
|
'fd_prestat_get', 'fd_prestat_dir_name',
|
|
2022
2013
|
'path_open',
|
|
2023
2014
|
'path_create_directory', 'path_remove_directory',
|
|
2024
2015
|
'path_unlink_file',
|
|
2025
2016
|
'path_rename',
|
|
2026
|
-
'path_filestat_get', 'path_filestat_set_times',
|
|
2027
|
-
'fd_filestat_get', 'fd_filestat_set_size', 'fd_filestat_set_times',
|
|
2017
|
+
'path_filestat_get', 'path_filestat_set_times',
|
|
2018
|
+
'fd_filestat_get', 'fd_filestat_set_size', 'fd_filestat_set_times',
|
|
2028
2019
|
'fd_pread', 'fd_pwrite',
|
|
2029
2020
|
'fd_readdir',
|
|
2030
2021
|
'fd_renumber',
|
|
2031
|
-
//
|
|
2032
|
-
'path_symlink', 'path_readlink', 'path_link',
|
|
2033
|
-
'fd_allocate',
|
|
2034
|
-
'fd_fdstat_set_rights',
|
|
2035
|
-
|
|
2036
|
-
'
|
|
2037
|
-
// Stream-B P4 additions
|
|
2038
|
-
'poll_oneoff', // B8 — via WebAssembly.Suspending
|
|
2022
|
+
// symlinks, rights, sockets, and polling
|
|
2023
|
+
'path_symlink', 'path_readlink', 'path_link',
|
|
2024
|
+
'fd_allocate',
|
|
2025
|
+
'fd_fdstat_set_rights',
|
|
2026
|
+
'sock_send', 'sock_recv', 'sock_shutdown',
|
|
2027
|
+
'poll_oneoff',
|
|
2039
2028
|
]);
|
|
2040
|
-
/**
|
|
2041
|
-
* Backwards-compat alias kept for any caller still importing the Wave-1
|
|
2042
|
-
* symbol names. The Wave-2 module now subsumes Wave-1's count.
|
|
2043
|
-
*/
|
|
2044
|
-
export const WASI_WAVE1_FNS = WASI_WAVE2_FNS;
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* wasm-runner.ts — native-WASM runner via the LOADER-modules transport.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* and facet isolates (verified in the multi-runtime feasibility
|
|
8
|
-
* memo). The new version routes through the LOADER's modules map:
|
|
4
|
+
* Direct `WebAssembly.instantiate(bytes)` is blocked by workerd CSP at
|
|
5
|
+
* request time in both the supervisor and facet isolates. This runner routes
|
|
6
|
+
* through the LOADER modules map:
|
|
9
7
|
* bytes ride INSIDE the worker code blob, workerd compiles them
|
|
10
8
|
* during the inner worker's MODULE-LOAD phase (the one phase where
|
|
11
9
|
* wasm code generation IS allowed), and the resulting
|
|
12
10
|
* WebAssembly.Module is exposed to the user fn via the
|
|
13
11
|
* NimbusLoaderPool's `globalThis.__NIMBUS_WASM[<name>]` table.
|
|
14
12
|
*
|
|
15
|
-
* The validation that this works on the deployed Cloudflare fleet
|
|
16
|
-
* lives at /workspace/.seal-internal/2026-05-10-wasm-csp/findings.md
|
|
17
|
-
* (`add(3,4) === 7` returned in 11ms warm, 113ms cold).
|
|
18
|
-
*
|
|
19
13
|
* Shell command shape
|
|
20
14
|
* ───────────────────
|
|
21
15
|
*
|
|
@@ -45,14 +39,14 @@
|
|
|
45
39
|
* - WASI imports are NOT provided. Modules expecting wasi_snapshot
|
|
46
40
|
* won't instantiate (fail at the in-facet instantiate step).
|
|
47
41
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* -
|
|
51
|
-
*
|
|
42
|
+
* Dispatch constraints
|
|
43
|
+
* ────────────────────
|
|
44
|
+
* - No sleeps, caller-side retries, or catch-and-continue around loader
|
|
45
|
+
* failures. The pool's resilience options own retry behavior.
|
|
52
46
|
* - The try/catch around vfs.readFile is a legitimate I/O boundary;
|
|
53
47
|
* the diagnostic propagates as exitCode 1 + stderr line.
|
|
54
48
|
* - NO direct WebAssembly.instantiate(bytes) at request time —
|
|
55
|
-
*
|
|
49
|
+
* workerd CSP rejects that path.
|
|
56
50
|
*/
|
|
57
51
|
import type { RuntimeRunOpts, RuntimeRunResult } from './runtime-registry.js';
|
|
58
52
|
export declare const WASM_RUNNER_VERSION = "0.3.0";
|
|
@@ -63,7 +57,7 @@ export declare const WASM_RUNNER_HELP: string;
|
|
|
63
57
|
* is part of `src/runtime/`, importing supervisor-specific types
|
|
64
58
|
* would create a cycle.
|
|
65
59
|
*
|
|
66
|
-
*
|
|
60
|
+
* filesystem WASI: extended for WASI file-IO. The snapshot path uses readdir +
|
|
67
61
|
* isDirectory + stat to traverse the user's session subtree; the
|
|
68
62
|
* flush path uses writeFile + mkdir + unlink + rmdir.
|
|
69
63
|
*/
|