wasm-idle 1.1.0 → 1.1.2

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.
Files changed (145) hide show
  1. package/README.md +140 -37
  2. package/dist/playground/assetBridge.js +106 -31
  3. package/dist/playground/assets.d.ts +2 -2
  4. package/dist/playground/c3.js +22 -0
  5. package/dist/playground/c3Memory.d.ts +19 -0
  6. package/dist/playground/c3Memory.js +117 -0
  7. package/dist/playground/cachedClang.js +143 -34
  8. package/dist/playground/clangAssetIntegrity.js +6 -6
  9. package/dist/playground/clangWorkerProtocol.d.ts +12 -1
  10. package/dist/playground/cobol.d.ts +3 -0
  11. package/dist/playground/cobol.js +10 -1
  12. package/dist/playground/commonlispAssets.d.ts +2 -2
  13. package/dist/playground/compiledArtifactCache.d.ts +3 -1
  14. package/dist/playground/compiledArtifactCache.js +31 -5
  15. package/dist/playground/container/ContainerExplorer.svelte +307 -0
  16. package/dist/playground/container/ContainerExplorer.svelte.d.ts +14 -0
  17. package/dist/playground/container/binding.d.ts +26 -0
  18. package/dist/playground/container/binding.js +247 -0
  19. package/dist/playground/container/clang-runtime.d.ts +38 -0
  20. package/dist/playground/container/clang-runtime.js +343 -0
  21. package/dist/playground/container/client.d.ts +15 -0
  22. package/dist/playground/container/client.js +189 -0
  23. package/dist/playground/container/explorer.d.ts +31 -0
  24. package/dist/playground/container/explorer.js +112 -0
  25. package/dist/playground/container/owner.worker.js +390 -0
  26. package/dist/playground/container/protocol.d.ts +73 -0
  27. package/dist/playground/container/protocol.js +28 -0
  28. package/dist/playground/container/release.d.ts +31 -0
  29. package/dist/playground/container/release.js +612 -0
  30. package/dist/playground/container/runtime-adapter.d.ts +73 -0
  31. package/dist/playground/container/runtime-adapter.js +474 -0
  32. package/dist/playground/container/shell-control.d.ts +49 -0
  33. package/dist/playground/container/shell-control.js +303 -0
  34. package/dist/playground/container/workspace.d.ts +8 -0
  35. package/dist/playground/container/workspace.js +29 -0
  36. package/dist/playground/d.d.ts +6 -1
  37. package/dist/playground/d.js +83 -5
  38. package/dist/playground/dotnet.js +6 -8
  39. package/dist/playground/fortran.d.ts +3 -0
  40. package/dist/playground/fortran.js +10 -1
  41. package/dist/playground/go.js +14 -3
  42. package/dist/playground/goDebugInstrumentation.js +184 -54
  43. package/dist/playground/java.js +3 -2
  44. package/dist/playground/javaRuntimeErrors.d.ts +9 -0
  45. package/dist/playground/javaRuntimeErrors.js +60 -0
  46. package/dist/playground/lean4Assets.d.ts +4 -4
  47. package/dist/playground/lfortran.js +10 -0
  48. package/dist/playground/lfortranAssets.d.ts +2 -2
  49. package/dist/playground/nim.js +22 -0
  50. package/dist/playground/objectivec.d.ts +3 -0
  51. package/dist/playground/objectivec.js +11 -2
  52. package/dist/playground/options.d.ts +2 -0
  53. package/dist/playground/python.js +8 -0
  54. package/dist/playground/runtimeAssetCache.d.ts +1 -32
  55. package/dist/playground/runtimeAssetCache.js +1 -193
  56. package/dist/playground/runtimeSession.d.ts +2 -2
  57. package/dist/playground/runtimeSession.js +11 -11
  58. package/dist/playground/rust.d.ts +6 -0
  59. package/dist/playground/rust.js +103 -6
  60. package/dist/playground/staticStdinRing.d.ts +2 -1
  61. package/dist/playground/staticStdinRing.js +21 -10
  62. package/dist/playground/staticWorkerRuntime.d.ts +15 -1
  63. package/dist/playground/staticWorkerRuntime.js +119 -17
  64. package/dist/playground/tinygo.d.ts +3 -0
  65. package/dist/playground/tinygo.js +81 -6
  66. package/dist/playground/v.d.ts +3 -0
  67. package/dist/playground/v.js +10 -1
  68. package/dist/playground/wasmAwkVersion.d.ts +13 -13
  69. package/dist/playground/wasmAwkVersion.js +4 -4
  70. package/dist/playground/wasmBqnVersion.d.ts +2 -2
  71. package/dist/playground/wasmBqnVersion.js +2 -2
  72. package/dist/playground/wasmC3Version.d.ts +2 -2
  73. package/dist/playground/wasmC3Version.js +2 -2
  74. package/dist/playground/wasmClojureScriptVersion.d.ts +2 -2
  75. package/dist/playground/wasmClojureScriptVersion.js +2 -2
  76. package/dist/playground/wasmCommonLispVersion.d.ts +2 -2
  77. package/dist/playground/wasmCommonLispVersion.js +2 -2
  78. package/dist/playground/wasmDIntegrity.d.ts +5 -5
  79. package/dist/playground/wasmDIntegrity.js +5 -5
  80. package/dist/playground/wasmDVersion.d.ts +16 -1
  81. package/dist/playground/wasmDVersion.js +16 -1
  82. package/dist/playground/wasmDebugVersion.d.ts +1 -1
  83. package/dist/playground/wasmDebugVersion.js +1 -1
  84. package/dist/playground/wasmForthVersion.d.ts +2 -2
  85. package/dist/playground/wasmForthVersion.js +2 -2
  86. package/dist/playground/wasmGleamVersion.d.ts +2 -2
  87. package/dist/playground/wasmGleamVersion.js +2 -2
  88. package/dist/playground/wasmGrainVersion.d.ts +2 -2
  89. package/dist/playground/wasmGrainVersion.js +2 -2
  90. package/dist/playground/wasmJVersion.d.ts +2 -2
  91. package/dist/playground/wasmJVersion.js +2 -2
  92. package/dist/playground/wasmJanetVersion.js +2 -2
  93. package/dist/playground/wasmJuliaVersion.js +2 -2
  94. package/dist/playground/wasmLean4Version.d.ts +5 -5
  95. package/dist/playground/wasmLean4Version.js +5 -5
  96. package/dist/playground/wasmLfortranVersion.d.ts +2 -2
  97. package/dist/playground/wasmLfortranVersion.js +2 -2
  98. package/dist/playground/wasmNimVersion.d.ts +9 -9
  99. package/dist/playground/wasmNimVersion.js +6 -6
  100. package/dist/playground/wasmOcamlVersion.d.ts +2 -2
  101. package/dist/playground/wasmOcamlVersion.js +1 -1
  102. package/dist/playground/wasmPascalVersion.js +2 -2
  103. package/dist/playground/wasmPerlVersion.js +2 -2
  104. package/dist/playground/wasmPrologVersion.d.ts +2 -2
  105. package/dist/playground/wasmPrologVersion.js +2 -2
  106. package/dist/playground/wasmReScriptVersion.d.ts +2 -2
  107. package/dist/playground/wasmReScriptVersion.js +2 -2
  108. package/dist/playground/wasmRustVersion.d.ts +8 -8
  109. package/dist/playground/wasmRustVersion.js +7 -7
  110. package/dist/playground/wasmTclVersion.d.ts +4 -4
  111. package/dist/playground/wasmTclVersion.js +2 -2
  112. package/dist/playground/wasmTinyGoVersion.d.ts +14 -14
  113. package/dist/playground/wasmTinyGoVersion.js +14 -14
  114. package/dist/playground/wasmTypeScriptVersion.d.ts +5 -5
  115. package/dist/playground/wasmTypeScriptVersion.js +5 -5
  116. package/dist/playground/worker/cachedClangCompile.js +52 -4
  117. package/dist/playground/worker/cachedClangExecute.js +6 -5
  118. package/dist/playground/worker/clang.js +32 -10
  119. package/dist/playground/worker/cobol.js +2 -2
  120. package/dist/playground/worker/d.js +12 -5
  121. package/dist/playground/worker/fortran.js +2 -2
  122. package/dist/playground/worker/go.js +16 -5
  123. package/dist/playground/worker/haskell.js +10 -7
  124. package/dist/playground/worker/java.js +75 -10
  125. package/dist/playground/worker/lua.js +2 -3
  126. package/dist/playground/worker/php.js +15 -9
  127. package/dist/playground/worker/python.js +46 -9
  128. package/dist/playground/worker/pythonExecution.js +17 -1
  129. package/dist/playground/worker/pythonWorkspaceFiles.d.ts +6 -0
  130. package/dist/playground/worker/pythonWorkspaceFiles.js +26 -0
  131. package/dist/playground/worker/pythonWorkspaceImports.d.ts +4 -0
  132. package/dist/playground/worker/pythonWorkspaceImports.js +129 -0
  133. package/dist/playground/worker/r.js +13 -6
  134. package/dist/playground/worker/rust.js +34 -2
  135. package/dist/playground/worker/sqlite.js +4 -3
  136. package/dist/playground/worker/tinygo.js +11 -3
  137. package/dist/playground/worker/typescript.js +2 -3
  138. package/dist/playground/worker/v.js +2 -2
  139. package/dist/playground/worker/wat.js +2 -3
  140. package/dist/playground/worker/zig.js +20 -6
  141. package/dist/playground/workerSession.d.ts +1 -28
  142. package/dist/playground/workerSession.js +1 -164
  143. package/package.json +20 -13
  144. package/dist/playground/worker/python.runtime.cases.js +0 -374
  145. /package/dist/playground/{worker/python.runtime.cases.d.ts → container/owner.worker.d.ts} +0 -0
package/README.md CHANGED
@@ -25,6 +25,33 @@ Verified downloads can be retained across reloads using a version-pinned, capaci
25
25
  CacheStorage/IndexedDB cache. See [persistent asset cache configuration and coverage](docs/runtime-asset-cache.md)
26
26
  for global/per-call opt-out, cleanup and prefetch APIs.
27
27
 
28
+ ## Getting started
29
+
30
+ You need Node.js `^22.22.2`, `^24.15.0`, or `>=26.0.0`, and pnpm 12.9.1. These come from the root
31
+ `package.json` `engines` and `packageManager` fields, and `.npmrc` sets `engine-strict=true`.
32
+ `.tool-versions` pins Node.js 24.20.0 for asdf/mise.
33
+
34
+ ```bash
35
+ pnpm install
36
+ pnpm dev
37
+ ```
38
+
39
+ `pnpm dev` builds the public workspace packages, then starts Vite with the cross-origin isolation
40
+ headers that `SharedArrayBuffer` requires. The app is served under the `/wasm-idle` base path, for
41
+ example `http://localhost:5173/wasm-idle/`.
42
+
43
+ Most runtime assets are checked in under `static/`. Some compiler payloads are gitignored and must
44
+ be prepared locally before those languages can run:
45
+
46
+ - `pnpm run prepare:test-assets` downloads the pinned Clang (with its matching clangd), OCaml,
47
+ C3, LFortran, Lean 4, and Common Lisp payloads. Pass group names, for example
48
+ `-- clang ocaml`, to prepare only some of them.
49
+ - `pnpm run prepare:wasm-debug-release` adds the LLDB debug runtime. Without it, C, C++, and
50
+ `wasm32-wasip1` Rust debug sessions use the trace fallback.
51
+
52
+ Other runtimes are refreshed from their producers with the `sync:*` scripts described under
53
+ [Monorepo layout](#monorepo-layout).
54
+
28
55
  ## Language support policy
29
56
 
30
57
  wasm-idle language support must run user code through the real language implementation in the
@@ -218,6 +245,7 @@ multi-module guests, and Rust WASI Preview 2/3 debugging remain outside the supp
218
245
 
219
246
  ```sh
220
247
  cd ../wasm-llvm
248
+ WASM_LLVM_CLANG_ARTIFACT_DIR=/path/to/verified-clang-artifacts \
221
249
  WASM_LLVM_LLDB_ARTIFACT_DIR=/path/to/lldb-artifacts \
222
250
  WASM_LLVM_WAMR_ARTIFACT_DIR=/path/to/wamr-artifacts \
223
251
  pnpm prepare:clang-release
@@ -227,9 +255,16 @@ WASM_RUST_PRODUCER_OUTPUT_ROOT=/path/to/rust-producer-output \
227
255
  pnpm --dir runtimes/wasm-rust build:producer
228
256
  pnpm sync:wasm-rust
229
257
  pnpm sync:wasm-debug ../wasm-llvm/out/clang-browser
230
- WASM_IDLE_BROWSER_SERVER_MODE=dev pnpm test:browser:debug:lldb
258
+ pnpm test:browser:debug:lldb
231
259
  ```
232
260
 
261
+ The Clang artifact directory must contain the verified build receipt and its matching raw-input
262
+ identities. The producer rejects historical artifacts without that evidence when assembling a new
263
+ release. For the already reviewed bundled debugger, use `pnpm prepare:wasm-debug-release` in
264
+ `wasm-idle` to install the immutable release selected by the tracked profile.
265
+ The browser command uses the qualified preview path; development-server LLDB qualification is
266
+ tracked separately.
267
+
233
268
  The synchronized manifest rejects missing hashes, incompatible Clang/LLDB revisions, and stale
234
269
  worker sidecars. The strict browser test covers real C, C++, and Rust breakpoint, step, output, and
235
270
  termination paths and rejects trace fallback or a missing debug asset. The Rust producer build is
@@ -257,10 +292,10 @@ variables or import SvelteKit modules.
257
292
  | Malbolge<br>`MALBOLGE` | Original Ben Olmstead interpreter, TryItOnline/malbolge b0869870 (public domain), compiled with WASI SDK 33 | Runs the original 59049-cell ternary and self-modifying interpreter; source-file input is separate from byte stdin/stdout; EOF stores 59048; requires at least two non-whitespace source bytes | `runtimeAssets.rootUrl`, `stdin`, `activePath`, `workspaceFiles`; fixed interpreter argv; prepare compiles the runtime without executing or validating the source |
258
293
  | Whitespace<br>`WHITESPACE` | koturn/Whitespace 22a57aab (MIT), compiled with WASI SDK 33 | Runs the upstream Whitespace 0.3 interpreter with a documented divisor-guard correction, copy/slide, heap, labels, calls and signed 32-bit integers; character/numeric stdin and exact stdout; character EOF is -1; source limit 65535 UTF-8 bytes | `runtimeAssets.rootUrl`, `stdin`, `activePath`, `workspaceFiles`; fixed interpreter argv; prepare compiles the runtime without executing or validating the source |
259
294
  | C3<br>`C3` | wasm-llvm/c3-browser: C3 0.8.3 / LLVM 22.1.8 | Verified c3c and builtin LLD compile real C3 in a fresh browser Worker; UTF-8 env.readByte/env.writeByte ABI and exported main; std::io and WASI unavailable | `runtimeAssets.c3.baseUrl`, `stdin`, `activePath`, `workspaceFiles`; fixed compiler flags and bounded Wasm memories |
260
- | C<br>`C` | @wasm-idle/llvm-core@1.1.0 / Clang 22.1.8 WASI sysroot from the `wasm-llvm` producer | `clang` for `wasm32-wasi`; default `-std=gnu11`; LLDB mode compiles untouched source with embedded DWARF at `-g -O0` and runs it in WAMR; normal runs still use the browser WASI host; supports `stdin` and `programArgs` | `runtimeAssets.clang.baseUrl`/`loader` or `rootUrl`; `compileArgs`, `programArgs`, `cVersion`, `activePath`, `workspaceFiles`, `debugMode`, `breakpoints`, `pauseOnEntry` |
261
- | C++<br>`CPP` | @wasm-idle/llvm-core@1.1.0 / Clang 22.1.8 WASI sysroot from the `wasm-llvm` producer | `clang++` for `wasm32-wasi`; default `-std=gnu++20`; LLDB mode compiles untouched source with embedded DWARF at `-g -O0` and runs it in WAMR; normal runs still use the browser WASI host; supports `stdin` and `programArgs` | `runtimeAssets.clang.baseUrl`/`loader` or `rootUrl`; `compileArgs`, `programArgs`, `cppVersion`, `activePath`, `workspaceFiles`, `debugMode`, `breakpoints`, `pauseOnEntry` |
262
- | Objective-C<br>`OBJC` | GNUstep libobjc2 v2.3 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.1.0 | `clang -x objective-c -fobjc-runtime=gnustep-2.0 -fblocks` for `wasm32-wasi`; links `libobjc.a`, `libgnustep-base.a`, and `libffi.a` when Foundation is imported; Foundation headers are inlined from `foundation-headers.json`; includes a constructor wrapper for Objective-C class registration; auto-compiles `.m`/`.mm`/`.c` workspace files; trace debug instruments active source and uses wasm-idle controls; supports `stdin` and `programArgs`; large Objective-C assets may be served as gzip-only `.gz` files through the service worker or worker fallback | `runtimeAssets.objectivec.baseUrl`/`libobjcUrl`/`headersUrl`/`libgnustepBaseUrl`/`libgnustepBaseObjectUrl`/`foundationHeadersUrl`/`libffiUrl` or `PUBLIC_WASM_OBJECTIVEC_*`; `runtimeAssets.clang.baseUrl`/`loader` for the clang toolchain; `activePath`, `workspaceFiles`, `compileArgs`, `debug`, `breakpoints`, `pauseOnEntry` |
263
- | Objective-C++<br>`OBJECTIVECXX` | Same GNUstep libobjc2 v2.3 + libc++ assets as Objective-C from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.1.0; no extra compiler assets | `clang -x objective-c++ -std=gnu++20 -fobjc-runtime=gnustep-2.0 -fblocks` for `wasm32-wasi` with libc++ headers; active file defaults to `main.mm`; links `libobjc.a` (plus GNUstep Base and `libffi.a` when Foundation is imported); auto-compiles `.mm`/`.m`/`.c` workspace files; supports `stdin` and `programArgs`; trace debugging is not supported | Shares `runtimeAssets.objectivec` and `runtimeAssets.clang` with Objective-C; `activePath`, `workspaceFiles`, `compileArgs`, `programArgs` |
295
+ | C<br>`C` | @wasm-idle/llvm-core@1.0.11 / Clang 22.1.8 WASI sysroot from the `wasm-llvm` producer | `clang` for `wasm32-wasi`; default `-std=gnu11`; LLDB mode compiles untouched source with embedded DWARF at `-g -O0` and runs it in WAMR; normal runs still use the browser WASI host; supports `stdin` and `programArgs` | `runtimeAssets.clang.baseUrl`/`loader` or `rootUrl`; `compileArgs`, `programArgs`, `cVersion`, `activePath`, `workspaceFiles`, `debugMode`, `breakpoints`, `pauseOnEntry` |
296
+ | C++<br>`CPP` | @wasm-idle/llvm-core@1.0.11 / Clang 22.1.8 WASI sysroot from the `wasm-llvm` producer | `clang++` for `wasm32-wasi`; default `-std=gnu++20`; LLDB mode compiles untouched source with embedded DWARF at `-g -O0` and runs it in WAMR; normal runs still use the browser WASI host; supports `stdin` and `programArgs` | `runtimeAssets.clang.baseUrl`/`loader` or `rootUrl`; `compileArgs`, `programArgs`, `cppVersion`, `activePath`, `workspaceFiles`, `debugMode`, `breakpoints`, `pauseOnEntry` |
297
+ | Objective-C<br>`OBJC` | GNUstep libobjc2 v2.3 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.11 | `clang -x objective-c -fobjc-runtime=gnustep-2.0 -fblocks` for `wasm32-wasi`; links `libobjc.a`, `libgnustep-base.a`, and `libffi.a` when Foundation is imported; Foundation headers are inlined from `foundation-headers.json`; includes a constructor wrapper for Objective-C class registration; auto-compiles `.m`/`.mm`/`.c` workspace files; trace debug instruments active source and uses wasm-idle controls; supports `stdin` and `programArgs`; large Objective-C assets may be served as gzip-only `.gz` files through the service worker or worker fallback | `runtimeAssets.objectivec.baseUrl`/`libobjcUrl`/`headersUrl`/`libgnustepBaseUrl`/`libgnustepBaseObjectUrl`/`foundationHeadersUrl`/`libffiUrl` or `PUBLIC_WASM_OBJECTIVEC_*`; `runtimeAssets.clang.baseUrl`/`loader` for the clang toolchain; `activePath`, `workspaceFiles`, `compileArgs`, `debug`, `breakpoints`, `pauseOnEntry` |
298
+ | Objective-C++<br>`OBJECTIVECXX` | Same GNUstep libobjc2 v2.3 + libc++ assets as Objective-C from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.11; no extra compiler assets | `clang -x objective-c++ -std=gnu++20 -fobjc-runtime=gnustep-2.0 -fblocks` for `wasm32-wasi` with libc++ headers; active file defaults to `main.mm`; links `libobjc.a` (plus GNUstep Base and `libffi.a` when Foundation is imported); auto-compiles `.mm`/`.m`/`.c` workspace files; supports `stdin` and `programArgs`; trace debugging is not supported | Shares `runtimeAssets.objectivec` and `runtimeAssets.clang` with Objective-C; `activePath`, `workspaceFiles`, `compileArgs`, `programArgs` |
264
299
  | Python<br>`PYTHON3` | static ESM `static/pyodide/pyodide.mjs` / pyodide@314.0.7 | loads `pyodide.mjs`, `pyodide.asm.mjs`, `pyodide.asm.wasm`, and `python_stdlib.zip` from the configured static asset tree on demand; supports `stdin`, workspace files, and trace debugging | `runtimeAssets.python.baseUrl`/`loader` or `rootUrl`; `stdin`, `activePath`, `workspaceFiles`, `debug`, `breakpoints`, `pauseOnEntry`, `debugPath` |
265
300
  | Befunge-93<br>`BEFUNGE93` | catseye/Befunge-93 8fe4065c (BSD-3-Clause), compiled with WASI SDK 33 | Runs the original interpreter with an 80 by 25 wrapping playfield, signed 32-bit stack, string mode and self-modifying p/g instructions; character and integer stdin share the WASI terminal; character EOF is -1 | `runtimeAssets.rootUrl`, `stdin`, `activePath`, `workspaceFiles`; fixed quiet argv; prepare compiles the runtime without executing or validating the source |
266
301
  | Brainfuck<br>`BRAINFUCK` | susam/bfc b1b92fc (MIT), compiled with WASI SDK 33 | Runs the pinned upstream interpreter in a browser Worker with a fresh read-only source filesystem; 30000 wrapping 8-bit cells, UTF-8 byte stdin/stdout, EOF sets the cell to zero | `runtimeAssets.rootUrl`, `stdin`, `activePath`, `workspaceFiles`; fixed interpreter argv; prepare compiles the runtime without executing or validating the source |
@@ -306,9 +341,9 @@ variables or import SvelteKit modules.
306
341
  | Haskell<br>`HASKELL` | ghc-in-browser / GHC 9.14.0.20251031 WASI rootfs | loads `dyld.mjs`, `rootfs.tar.zst`, `bsdtar.wasm`; `compileArgs` become GHC args, otherwise legacy `args` become GHC args | `runtimeAssets.haskell.moduleUrl`/`rootfsUrl`/`bsdtarUrl`; `mainSoPath`, `searchDirs`, `activePath`, `workspaceFiles` |
307
342
  | LFortran<br>`LFORTRAN` | receipt-pinned `wasm-llvm/producer/lfortran-browser` artifacts in `static/wasm-lfortran` | real LFortran 0.65.0-97-gab867a23 LLVM evaluator compiles and executes Emscripten side modules in a fresh Worker; shared-ring stdin supports delayed READ and EOF; experimental Fortran feature coverage | `runtimeAssets.lfortran.baseUrl` relocates the reviewed bundle; `stdin`, `activePath`, workspace data/include files, cancellation and execution limits; no program arguments or multi-file module build orchestration |
308
343
  | Lean 4<br>`LEAN4` | receipt-pinned `wasm-llvm/producer/lean-browser` release downloaded from its immutable commit into `static/wasm-lean4` | real Lean 4.34.1 frontend and IR interpreter (`lean --run`) built for wasm32 Emscripten with pthreads; imports a wasm32 `Init` library compiled by that build; shared-ring stdin supports interactive `getLine` and EOF | `runtimeAssets.lean4.baseUrl` relocates the reviewed bundle; `stdin`, program arguments, `activePath`, cancellation and execution limits; single-file programs importing `Init` only (no `Std`/`Lean` imports or Lake packages) |
309
- | Fortran<br>`FORTRAN` | Netlib f2c 2022-09-09 + `@cowasm/f2c 1.0.0` libf2c + @wasm-idle/llvm-core@1.1.0 | runs `f2c.wasm` in WASI, compiles generated C with the llvm-core Clang host, links `libf2c.a`, then executes the resulting WASI module with `stdin` and `programArgs` | `runtimeAssets.fortran.baseUrl`/`f2cWasmUrl`/`libf2cUrl`/`f2cHeaderUrl`/`analyzerUrl` or `PUBLIC_WASM_FORTRAN_*`; `runtimeAssets.clang.baseUrl`/`loader` for the C backend; `activePath`, `workspaceFiles`, `compileArgs` |
310
- | COBOL<br>`COBOL` | GnuCOBOL 3.2 + GMP 6.3.0 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.1.0 | native gzip delivery for the frontend Wasm and filesystem tar assets; translates free-format COBOL with the real GnuCOBOL `cobc` frontend, compiles the generated C with the llvm-core Clang host, links libcob/GMP, and executes the resulting WASI module with `stdin` and `programArgs` | `runtimeAssets.cobol.baseUrl` or `PUBLIC_WASM_COBOL_BASE_URL`; `runtimeAssets.clang.baseUrl`/`loader` for the C backend; `activePath`, `workspaceFiles`, `compileArgs` |
311
- | V<br>`V` | V 0.5.2 compiler, vlib and WASI C sysroot assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.1.0 | native gzip delivery for the compiler Wasm and filesystem tar assets; translates V to C with the real V compiler (built from the upstream `vc` bootstrap for WASI), compiles the generated C with the llvm-core Clang host, and executes the resulting WASI module with `stdin` and `programArgs` | `runtimeAssets.v.baseUrl` or `PUBLIC_WASM_V_BASE_URL`; `runtimeAssets.clang.baseUrl`/`loader` for the C backend; `activePath`, `workspaceFiles`, `compileArgs` |
344
+ | Fortran<br>`FORTRAN` | Netlib f2c 2022-09-09 + `@cowasm/f2c 1.0.0` libf2c + @wasm-idle/llvm-core@1.0.11 | runs `f2c.wasm` in WASI, compiles generated C with the llvm-core Clang host, links `libf2c.a`, then executes the resulting WASI module with `stdin` and `programArgs` | `runtimeAssets.fortran.baseUrl`/`f2cWasmUrl`/`libf2cUrl`/`f2cHeaderUrl`/`analyzerUrl` or `PUBLIC_WASM_FORTRAN_*`; `runtimeAssets.clang.baseUrl`/`loader` for the C backend; `activePath`, `workspaceFiles`, `compileArgs` |
345
+ | COBOL<br>`COBOL` | GnuCOBOL 3.2 + GMP 6.3.0 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.11 | native gzip delivery for the frontend Wasm and filesystem tar assets; translates free-format COBOL with the real GnuCOBOL `cobc` frontend, compiles the generated C with the llvm-core Clang host, links libcob/GMP, and executes the resulting WASI module with `stdin` and `programArgs` | `runtimeAssets.cobol.baseUrl` or `PUBLIC_WASM_COBOL_BASE_URL`; `runtimeAssets.clang.baseUrl`/`loader` for the C backend; `activePath`, `workspaceFiles`, `compileArgs` |
346
+ | V<br>`V` | V 0.5.2 compiler, vlib and WASI C sysroot assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.11 | native gzip delivery for the compiler Wasm and filesystem tar assets; translates V to C with the real V compiler (built from the upstream `vc` bootstrap for WASI), compiles the generated C with the llvm-core Clang host, and executes the resulting WASI module with `stdin` and `programArgs` | `runtimeAssets.v.baseUrl` or `PUBLIC_WASM_V_BASE_URL`; `runtimeAssets.clang.baseUrl`/`loader` for the C backend; `activePath`, `workspaceFiles`, `compileArgs` |
312
347
  | R<br>`R` | versioned static `static/webr/<hash>/webr.js` / webr@0.6.0 | loads the browser ESM entry `webr.js` and its WebR runtime files from the configured static asset tree on demand; supports `stdin`, `programArgs`, and workspace files | `runtimeAssets.r.baseUrl` or `PUBLIC_WASM_R_BASE_URL`; `stdin`, `programArgs`, `activePath`, `workspaceFiles` |
313
348
  | Octave<br>`OCTAVE` | Octave 10.3.0 (octave-10.3.0-pl5321h996e327_3.tar.bz2) | Octave CLI Emscripten worker; supports `stdin` and `programArgs` | `runtimeAssets.octave.baseUrl`/`workerUrl`/`manifestUrl` or `PUBLIC_WASM_OCTAVE_*` |
314
349
  | DuckDB<br>`DUCKDB` | static ESM `static/wasm-duckdb/runtime.mjs` produced from @duckdb/duckdb-wasm@1.33.1-dev57.0 | selects the best DuckDB-Wasm MVP/EH bundle on demand and creates a fresh in-memory database per run; `stdin` is registered as `stdin.txt` and `/dev/stdin` rather than terminal stdin | `runtimeAssets.duckdb.moduleUrl` or `PUBLIC_WASM_DUCKDB_MODULE_URL` or `rootUrl`; `stdin`, `activePath`, `workspaceFiles` |
@@ -353,19 +388,25 @@ toolchains can be consumed from pinned external runtime repositories:
353
388
  - `packages/react`: React hooks around `@wasm-idle/core`.
354
389
  - `packages/vue`: Vue composables around `@wasm-idle/core`.
355
390
  - `packages/node`: Node.js host helpers for Node-capable sandbox loaders.
356
- - `runtimes/*`: imported runtime/compiler packages such as `wasm-rust`,
357
- `wasm-of-js-of-ocaml`, `wasm-go`, `wasm-dotnet`, `wasm-typescript`,
358
- `wasm-wat`, `wasm-lua`, `wasm-lisp`, `wasm-elixir`, `wasm-tcl`, `wasm-awk`,
359
- `wasm-forth`, `wasm-j`, `wasm-bqn`, `wasm-janet`,
360
- `pyodide`, `teavm`, `assemblyscript`, `ruby`, `r`, and `js-sandbox`.
391
+ - `runtimes/*`: imported runtime/compiler packages `wasm-rust`, `wasm-of-js-of-ocaml`, `wasm-go`,
392
+ `wasm-d`, `wasm-dotnet`, `wasm-typescript`, `wasm-wat`, `wasm-lua`, `wasm-lisp`, `wasm-elixir`,
393
+ `wasm-awk`, `wasm-bash`, `wasm-clojurescript`, `pyodide`, `teavm`, `ruby`, `r`, and
394
+ `js-sandbox`. `wasm-pascal` holds the pas2js compiler wrapper sources and is not a workspace
395
+ package.
396
+ - `runtimes/esolangs`: pinned upstream interpreter sources and licenses for the esoteric
397
+ languages. `pnpm build:esolangs` and the Aheui, APECode, and GolfScript sync scripts turn them
398
+ into `static/wasm-<language>/` assets.
361
399
  - `runtimes/wasm-tinygo`: the public `TINYGO` browser compiler consumer plus an explicitly labeled
362
400
  legacy AST-to-C development harness. Static releases publish only the receipt-verified upstream
363
401
  consumer and its source-pinned toolchain assets.
402
+ - `runtimes/wasm-kotlin` and `runtimes/wasm-scala`: internal compiler candidates. They are not
403
+ registered playground languages or workspace packages.
364
404
  - `producers/wasm-php`: standalone, locked producer for the checked-in PHP 8.4 page asset. It is
365
405
  outside the root workspace and is never published as an npm package.
366
- - `static/wasm-zig`, `static/wasm-haskell`, `static/wasm-julia`, and `static/wasm-nim`: bundled browser runtime and
367
- compiler assets synced from
368
- upstream asset builds rather than local workspace packages.
406
+ - `static/wasm-zig`, `static/wasm-haskell`, `static/wasm-julia`, `static/wasm-nim`,
407
+ `static/wasm-tcl`, `static/wasm-forth`, `static/wasm-j`, `static/wasm-bqn`, and
408
+ `static/wasm-janet`: bundled browser runtime and compiler assets synced from upstream asset
409
+ builds rather than local workspace packages.
369
410
 
370
411
  Deployment builds retain both legacy `.gz` and canonical `.gz.bin` URLs by default.
371
412
  After building and compressing the page, `pnpm run compact:build-runtimes` reports
@@ -388,9 +429,24 @@ pnpm sync:runtime list
388
429
  pnpm sync:runtimes
389
430
  ```
390
431
 
391
- The runtime sync scripts default to `runtimes/<name>/dist`; optional source and target arguments are
392
- for alternate build directories inside the current checkout. PHP is the exception:
393
- `sync:wasm-php` consumes `producers/wasm-php/dist` or `WASM_IDLE_WASM_PHP_DIST`.
432
+ `pnpm sync:runtime list` prints every runtime the wrapper knows. It marks `manual` runtimes, which
433
+ `pnpm sync:runtimes` skips unless `--include-manual` is passed, and `source-required` runtimes,
434
+ which need an explicit source directory and never run from `sync:runtimes`.
435
+
436
+ Default sources differ by runtime:
437
+
438
+ - Runtimes with sources under `runtimes/`, such as `wasm-go`, `wasm-d`, `wasm-dotnet`,
439
+ `wasm-lua`, `wasm-wat`, `wasm-typescript`, `wasm-lisp`, `wasm-awk`, `wasm-pascal`, and
440
+ `wasm-bash`, read `runtimes/<name>/dist`.
441
+ - Some read an installed npm package, such as `webr` or `swipl-wasm`.
442
+ - Some download a pinned upstream release, such as Tcl, Perl, and Octave.
443
+ - Julia and Nim re-verify the checked-in assets and download their pinned release only when those
444
+ assets are missing.
445
+ - J, BQN, and Janet prefer a sibling checkout and otherwise reuse the checked-in assets.
446
+ - Rust, TinyGo, and ClojureScript re-verify and redeploy the checked-in `static/` snapshot.
447
+
448
+ The optional `[sourceDir] [targetDir]` arguments override these defaults. `sync:wasm-php` is not
449
+ part of the wrapper; it consumes `producers/wasm-php/dist` or `WASM_IDLE_WASM_PHP_DIST`.
394
450
 
395
451
  Published packages are built in workspace dependency order. Before publishing, run:
396
452
 
@@ -415,7 +471,7 @@ opaque, receipt-pinned storage paths; these files are deployed page assets, not
415
471
  contents.
416
472
 
417
473
  PHP is built independently under `producers/wasm-php`, with its own lockfile and exact
418
- `@php-wasm/web-8-4@3.1.34` and `@php-wasm/universal@3.1.34` dependencies. Refresh the checked-in
474
+ `@php-wasm/web-8-4@3.1.57` and `@php-wasm/universal@3.1.57` dependencies. Refresh the checked-in
419
475
  page asset only when changing that producer:
420
476
 
421
477
  ```bash
@@ -477,15 +533,26 @@ cd wasm-idle
477
533
  pnpm run sync:wasm-julia
478
534
  ```
479
535
 
480
- Nim browser execution uses the `benagastov/Nim-WASM-Compiler` asset pipeline under
536
+ Nim compiler preparation is owned by `wasm-llvm/producer/nim-browser`; the pinned
537
+ `benagastov/Nim-WASM-Compiler` distribution is delivered under
481
538
  `static/wasm-nim/`: Nim 2.2.4 compiled to WebAssembly emits C, then bundled clang/lld WebAssembly
482
- assets link a runnable WASI module. Refresh the vendored worker/runtime assets with:
539
+ assets link a runnable WASI module. Package the compiler artifacts with the producer,
540
+ then publish the verified bundle and current consumer Worker:
483
541
 
484
542
  ```bash
485
- cd wasm-idle
486
- pnpm run sync:wasm-nim
543
+ # In wasm-llvm: migrate existing verified assets or select a pinned upstream source.
544
+ pnpm package:nim -- --from-runtime /path/to/wasm-idle/static/wasm-nim --out out/nim-browser
545
+ # In wasm-idle:
546
+ pnpm sync:wasm-nim /path/to/wasm-llvm/out/nim-browser
487
547
  ```
488
548
 
549
+ D compiler source patches, porting probes and artifact packaging live in
550
+ `wasm-llvm/producer/d-browser`. Import its verified output through
551
+ `WASM_LLVM_D_ARTIFACT_DIR` when building `runtimes/wasm-d`; see [the D browser integration](docs/d-browser.md).
552
+ C3 and LFortran continue using their existing `wasm-llvm` producers. Compiler preparation for
553
+ these four paths belongs to the producer repository, while execution and cache ownership belong
554
+ to `wasm-idle`.
555
+
489
556
  ## Rust browser integration
490
557
 
491
558
  The demo app publishes the workspace `wasm-rust` compiler as a receipt-pinned executable graph
@@ -627,7 +694,8 @@ are bounded and verified against the exact expanded size and SHA-256.
627
694
 
628
695
  The preparer rejects source or target paths outside their configured roots, checks each redirect
629
696
  before following it, writes atomically, and reuses only matching files. With no group argument,
630
- it prepares both the Clang delivery bundle and the complete OCaml browser compiler graph.
697
+ it prepares the Clang delivery bundle with its matching clangd assets, the complete OCaml browser
698
+ compiler graph, and the C3, LFortran, Lean 4, and Common Lisp payloads.
631
699
  `WASM_IDLE_TEST_ASSET_BASE_URL` can select a compatible mirror with the same receipt-verified bytes.
632
700
  For protected local browser tests, provide `WASM_IDLE_TEST_BYPASS_COOKIE` through the environment
633
701
  in `dev_bypass_waf=<value>` form; the browser cookie jar scopes it to the test origin. Asset
@@ -786,8 +854,8 @@ and other workspace `.sql` files run first. Preloaded stdin is exposed as the se
786
854
  `/dev/blob` (`COPY t FROM '/dev/blob'` or `pg_read_file('/dev/blob')`). Override the module with
787
855
  `PUBLIC_WASM_POSTGRESQL_MODULE_URL` or `runtimeAssets.postgresql.moduleUrl`.
788
856
  PHP dynamically imports the checked-in `static/wasm-php/runtime.mjs` output from the standalone
789
- `producers/wasm-php` build. That producer pins `@php-wasm/web-8-4@3.1.34` and
790
- `@php-wasm/universal@3.1.34`. It always creates PHP 8.4; there is no version field or
857
+ `producers/wasm-php` build. That producer pins `@php-wasm/web-8-4@3.1.57` and
858
+ `@php-wasm/universal@3.1.57`. It always creates PHP 8.4; there is no version field or
791
859
  environment-based version selector. Override only the module location with
792
860
  `PUBLIC_WASM_PHP_MODULE_URL` or `runtimeAssets.php.moduleUrl`. A custom host must serve the entry's
793
861
  sibling chunks and assets with compatible CORS and cross-origin isolation headers; a cross-origin
@@ -855,6 +923,9 @@ the Rust worker:
855
923
 
856
924
  - `wasm32-wasip1` runs as preview1 core wasm through `@bjorn3/browser_wasi_shim`
857
925
  - `wasm32-wasip2` runs as a preview2 component through `preview2-shim` plus transpiled `jco` output
926
+ - `wasm32-wasip3` also returns a component and runs on the same preview2 path. This works only
927
+ while emitted components keep transitional WASIp2 imports; preview3 imports are rejected until a
928
+ browser preview3 shim exists
858
929
 
859
930
  C-family compilation remains hosted by `@wasm-idle/llvm-core`, while Rust delegates artifact
860
931
  execution to `wasm-rust` so the selected target and returned artifact format stay aligned.
@@ -917,7 +988,9 @@ const runtimeAssets: PlaygroundRuntimeAssets = {
917
988
  stdlibUrl: 'https://cdn.example.com/wasm-zig/std.tar.gz'
918
989
  },
919
990
  lisp: {
920
- moduleUrl: 'https://cdn.example.com/wasm-lisp/index.js'
991
+ moduleUrl: 'https://cdn.example.com/wasm-lisp/index.js',
992
+ manifestUrl: 'https://cdn.example.com/wasm-lisp/runtime-manifest.v2.json',
993
+ manifestFingerprint: '<runtime-manifest-fingerprint>'
921
994
  },
922
995
  haskell: {
923
996
  moduleUrl: 'https://cdn.example.com/wasm-haskell/dyld.mjs',
@@ -926,7 +999,9 @@ const runtimeAssets: PlaygroundRuntimeAssets = {
926
999
  },
927
1000
  nim: {
928
1001
  baseUrl: 'https://cdn.example.com/wasm-nim/',
929
- workerUrl: 'https://cdn.example.com/wasm-nim/runner-worker.js'
1002
+ workerUrl: 'https://cdn.example.com/wasm-nim/runner-worker.js',
1003
+ // Complete identity and receipt bundle for the served bytes; see below.
1004
+ ...nimTrustBundle
930
1005
  }
931
1006
  };
932
1007
  ```
@@ -934,12 +1009,22 @@ const runtimeAssets: PlaygroundRuntimeAssets = {
934
1009
  Static module overrides such as PHP's `moduleUrl` identify an entry module, not a self-contained
935
1010
  file. Mirror its complete sibling asset tree at the same relative paths. Cross-origin asset hosts
936
1011
  must provide compatible CORS and COEP/CORP headers and cannot rely on wasm-idle's same-origin gzip
937
- service worker.
1012
+ service worker. The checkout stores several files from the example above only as `.gz`, for
1013
+ example `wasm-zig/zig_small.wasm.gz`, `wasm-wat/index.js.gz`, `wasm-lisp/index.js.gz`, and
1014
+ `wasm-haskell/bsdtar.wasm.gz`. A host for those URLs must return the decompressed bytes, either as
1015
+ a decompressed file or as that `.gz` served with `Content-Encoding: gzip`; Zig's `std.tar.gz` is
1016
+ served as stored.
938
1017
 
939
1018
  Verified static runtimes such as Janet and Julia intentionally omit URL-only examples: a custom
940
1019
  `baseUrl`, `manifestUrl`, or `workerUrl` must be accompanied by every identity and asset-receipt
941
1020
  field declared by that runtime's asset config, including the matching `workerReceipt`. Partial
942
- trust bundles fail closed instead of borrowing receipts from bundled executable bytes.
1021
+ trust bundles fail closed instead of borrowing receipts from bundled executable bytes. In the Nim
1022
+ entry above, `nimTrustBundle` stands for `profileId`, `artifactRevision`, `nimRevision`,
1023
+ `llvmRevision`, `memfsRevision`, `emscriptenRevision`, `manifestFingerprint`, `manifestReceipt`,
1024
+ `nimJavaScriptReceipt`, `nimWasmReceipt`, `nimbaseReceipt`, `clangJavaScriptReceipt`,
1025
+ `clangWasmReceipt`, `lldWasmReceipt`, `memfsWasmReceipt`, `sysrootReceipt`, and `workerReceipt`. An
1026
+ explicit Nim `manifestUrl` must be `runtime-manifest.v2.json?v=<manifestFingerprint>` under
1027
+ `baseUrl`. A `rootUrl` mirror of the bundled Nim files needs no `nim` entry.
943
1028
 
944
1029
  The bundled C/C++ app uses receipt-pinned Clang language sysroots: C initially downloads only the
945
1030
  C base, while C++ or a mixed/opaque-language build loads the C++ add-on before compiling or linking.
@@ -990,8 +1075,8 @@ The pack contains the same locked upstream files, not an import-based subset. Ea
990
1075
  ### Retaining compiler caches across editor navigation
991
1076
 
992
1077
  Create one `createRuntimeSession(assets)` owner per browser application and use
993
- `session.createBinding()` for each editor or execution panel. C/C++ and Python
994
- keep immutable compiler/runtime modules outside their disposable execution Workers:
1078
+ `session.createBinding()` for each editor or execution panel. Clang consumers, Rust,
1079
+ TinyGo, D, C3, Nim, LFortran and Python share a bounded owner for verified assets and compiler modules:
995
1080
 
996
1081
  ```ts
997
1082
  import { createRuntimeSession } from 'wasm-idle';
@@ -1005,12 +1090,14 @@ await panel.dispose(); // close this panel; retain the session's cache
1005
1090
 
1006
1091
  const nextPanel = session.createBinding(); // another problem, same language
1007
1092
  await nextPanel.load('PYTHON');
1008
- await session.selectLanguage('CPP'); // release old-language panels and cache
1093
+ await session.selectLanguage('CPP'); // release old-language panels; retain verified assets
1009
1094
  await session.dispose(); // full, terminal release of this owner
1010
1095
  ```
1011
1096
 
1012
- Selecting a language does not download assets. The owner retains only one language;
1013
- selecting an unsupported/server-only language also releases the previous cache.
1097
+ Selecting a language does not download assets. Only the selected language keeps active
1098
+ execution leases; verified compiler assets survive language changes until LRU eviction
1099
+ or session disposal. Selecting an unsupported/server-only language releases active leases
1100
+ without clearing the session's verified assets.
1014
1101
  Executions never share mutable Wasm instances, user files or stdin. C/C++ additionally
1015
1102
  reuse compiled programs when source, workspace and compiler options match, while
1016
1103
  custom loaders and debugging retain the original execution path. Python still creates
@@ -1019,7 +1106,23 @@ a fresh interpreter after `clear()`; module reuse does not eliminate interpreter
1019
1106
  The asset cache is LRU-bounded to 64 entries and 256 MiB of logical asset bytes
1020
1107
  (not a measurement of the browser engine's compiled-code memory). C/C++ program
1021
1108
  artifacts are independently bounded to 8 entries and 32 MiB. `getCacheStats()` exposes
1022
- cache counters for diagnostics. Other languages currently keep their existing lifecycle.
1109
+ cache counters for diagnostics. COBOL, Fortran, V and Objective-C/Objective-C++ connect
1110
+ their Clang asset bridges to this same owner. Rust, TinyGo, D, C3, Nim and LFortran use one-shot MessagePorts
1111
+ to request compiler modules from the session after checking the pinned artifact receipt.
1112
+ The host verifies the bytes again before returning a module, including on cache hits.
1113
+ Nim also passes verified Clang, LLD and MemFS modules to its nested compiler Worker.
1114
+ C3 partitions its transformed compiler by the configured memory cap; LFortran shares
1115
+ its compiler module while generating fresh dynamic side modules in each execution.
1116
+ Cache identities include artifact receipts, authorization profiles and compilation
1117
+ settings; TinyGo also separates the memory-cap transformation used for each toolchain.
1118
+
1119
+ `@wasm-idle/core` exports `WorkerSession`, `RuntimeAssetCache` and the
1120
+ `createRuntimeWasmModuleService` / `serveRuntimeWasmModule` / `requestRuntimeWasmModule`
1121
+ helpers for hosts implementing the same ownership model. Cancelling one request closes
1122
+ its subscription without terminating another request that uses the same immutable
1123
+ module. Compiler instances, linear memory, files and compiler helper threads remain
1124
+ owned by individual jobs; this cache does not combine the LLVM binaries embedded in
1125
+ different toolchains.
1023
1126
 
1024
1127
  ### Optional idle runtime prewarming
1025
1128
 
@@ -201,20 +201,22 @@ const expectedAssetsForRuntime = (runtime, languageSysroots = false) => {
201
201
  }
202
202
  return assets;
203
203
  };
204
- const integrityKey = (config) => JSON.stringify(Object.entries(config.integrity || {})
205
- .sort(([left], [right]) => left.localeCompare(right))
206
- .map(([asset, entry]) => [
207
- asset,
208
- typeof entry === 'string'
209
- ? entry
210
- : {
211
- sha256: entry.sha256,
212
- bytes: entry.bytes,
213
- mediaType: entry.mediaType,
214
- uncompressedSha256: entry.uncompressedSha256,
215
- uncompressedBytes: entry.uncompressedBytes
216
- }
217
- ]));
204
+ // Read the contract fields directly: valid receipts can use inherited or hidden getters.
205
+ const snapshotIntegrityEntry = (receipt) => typeof receipt === 'string'
206
+ ? receipt
207
+ : Object.freeze({
208
+ sha256: receipt.sha256,
209
+ bytes: receipt.bytes,
210
+ mediaType: receipt.mediaType,
211
+ uncompressedSha256: receipt.uncompressedSha256,
212
+ uncompressedBytes: receipt.uncompressedBytes
213
+ });
214
+ const integrityKey = (config) => {
215
+ const integrity = config.integrity || {};
216
+ return JSON.stringify(Object.getOwnPropertyNames(integrity)
217
+ .sort((left, right) => left.localeCompare(right))
218
+ .map((asset) => [asset, snapshotIntegrityEntry(integrity[asset])]));
219
+ };
218
220
  const allowedBaseUrlsKey = (config) => JSON.stringify([...(config.allowedBaseUrls || [])].sort());
219
221
  class RuntimeLoadProgress {
220
222
  samples = new Map();
@@ -550,7 +552,6 @@ export class WorkerAssetBridge {
550
552
  const generation = this.generation;
551
553
  const controller = new AbortController();
552
554
  const progress = this.progress;
553
- const context = this.captureLoadContext();
554
555
  const receiveProgress = (event) => {
555
556
  if (controller.signal.aborted || generation !== this.generation)
556
557
  return;
@@ -561,15 +562,33 @@ export class WorkerAssetBridge {
561
562
  progress.activity(event.phase, event.asset);
562
563
  }
563
564
  };
564
- const loadContext = (report) => ({
565
- ...context,
566
- progress: {
567
- update: (asset, loaded, total) => report({ kind: 'download', asset, loaded, total }, `download:${asset}`),
568
- activity: (phase, asset) => report({ kind: 'activity', asset, phase }, `activity:${asset}`)
565
+ // A rebind to the same worker aborts this load, but that worker still awaits a reply.
566
+ const replySuperseded = () => {
567
+ if (this.state !== 'active' || this.worker !== worker)
568
+ return;
569
+ try {
570
+ worker.postMessage({
571
+ assetResponse: {
572
+ id: request.id,
573
+ ok: false,
574
+ error: `Runtime asset ${request.asset} request was superseded by a rebind`
575
+ }
576
+ });
569
577
  }
570
- });
578
+ catch {
579
+ // The worker may already be terminated.
580
+ }
581
+ };
571
582
  this.activeLoads.add(controller);
572
583
  try {
584
+ const context = this.captureLoadContext();
585
+ const loadContext = (report) => ({
586
+ ...context,
587
+ progress: {
588
+ update: (asset, loaded, total) => report({ kind: 'download', asset, loaded, total }, `download:${asset}`),
589
+ activity: (phase, asset) => report({ kind: 'activity', asset, phase }, `activity:${asset}`)
590
+ }
591
+ });
573
592
  this.validateAssetRequest(loadContext(receiveProgress), request.asset);
574
593
  const identity = [
575
594
  this.runtime,
@@ -650,7 +669,7 @@ export class WorkerAssetBridge {
650
669
  });
651
670
  }
652
671
  if (controller.signal.aborted || generation !== this.generation)
653
- return;
672
+ return replySuperseded();
654
673
  worker.postMessage({ assetResponse: { id: request.id, ok: true, module } });
655
674
  return;
656
675
  }
@@ -659,7 +678,7 @@ export class WorkerAssetBridge {
659
678
  this.pythonPackageAssets = readPythonPackageAssets(loaded.bytes);
660
679
  }
661
680
  if (controller.signal.aborted || generation !== this.generation)
662
- return;
681
+ return replySuperseded();
663
682
  const buffer = transferBuffer(loaded.bytes, this.cache ? false : loaded.transferOwnership);
664
683
  worker.postMessage({
665
684
  assetResponse: {
@@ -672,7 +691,7 @@ export class WorkerAssetBridge {
672
691
  }
673
692
  catch (error) {
674
693
  if (controller.signal.aborted || generation !== this.generation)
675
- return;
694
+ return replySuperseded();
676
695
  try {
677
696
  worker.postMessage({
678
697
  assetResponse: {
@@ -691,8 +710,24 @@ export class WorkerAssetBridge {
691
710
  }
692
711
  }
693
712
  captureLoadContext() {
713
+ const config = { ...this.config };
714
+ const integrity = config.integrity;
715
+ // Cache identity and verification must observe the same receipt, even if a caller
716
+ // updates its configuration while an asynchronous asset load is in progress.
717
+ // The built-in Clang map and its receipts are frozen; its identity also selects
718
+ // verified streaming, so only caller-owned maps need a new snapshot.
719
+ if (integrity && integrity !== BUNDLED_CLANG_ASSET_INTEGRITY) {
720
+ config.integrity = Object.freeze(Object.fromEntries(
721
+ // Authorization accepts own map entries regardless of enumerability.
722
+ Object.getOwnPropertyNames(integrity).map((asset) => [
723
+ asset,
724
+ snapshotIntegrityEntry(integrity[asset])
725
+ ])));
726
+ }
727
+ if (config.allowedBaseUrls)
728
+ config.allowedBaseUrls = [...config.allowedBaseUrls];
694
729
  return {
695
- config: { ...this.config },
730
+ config,
696
731
  maxAssetBytes: this.maxAssetBytes,
697
732
  expectedAssets: new Set(this.expectedAssets),
698
733
  pythonPackageAssets: new Set(this.pythonPackageAssets),
@@ -743,6 +778,7 @@ export class WorkerAssetBridge {
743
778
  throw runtimeAssetAbortReason(signal);
744
779
  if (this.runtime === 'python' && asset === 'pyodide-lock.json')
745
780
  readPythonPackageAssets(runtimeBytes);
781
+ await loaded.persist?.();
746
782
  return {
747
783
  bytes: runtimeBytes,
748
784
  mimeType: loaded.mimeType,
@@ -768,8 +804,10 @@ export class WorkerAssetBridge {
768
804
  if (!signal.aborted)
769
805
  context.progress.update(asset, loaded, total);
770
806
  };
771
- if (context.config.loader) {
772
- const pendingResult = Promise.resolve(context.config.loader({
807
+ // Do not expose the private verification context as a custom loader's receiver.
808
+ const loader = context.config.loader;
809
+ if (loader) {
810
+ const pendingResult = Promise.resolve(loader({
773
811
  runtime: this.runtime,
774
812
  asset,
775
813
  reportProgress,
@@ -930,7 +968,8 @@ export class WorkerAssetBridge {
930
968
  'bridge-v1',
931
969
  context.config.baseUrl,
932
970
  allowedBaseUrlsKey(context.config),
933
- maxAssetBytes
971
+ maxAssetBytes,
972
+ expected?.mediaType
934
973
  ])
935
974
  }
936
975
  : undefined;
@@ -943,13 +982,44 @@ export class WorkerAssetBridge {
943
982
  if (bytes) {
944
983
  requireRuntimeAssetSize(asset, bytes.byteLength, maxAssetBytes);
945
984
  context.progress.update(asset, bytes.byteLength, bytes.byteLength);
946
- return { bytes, mimeType: receipt?.mediaType, transferOwnership: true };
985
+ // A hit was validated against this same expected MIME type before it was stored.
986
+ return {
987
+ bytes,
988
+ mimeType: expected?.mediaType ?? receipt?.mediaType,
989
+ transferOwnership: true
990
+ };
947
991
  }
948
992
  }
949
993
  const loaded = await this.fetchAssetFromNetwork(context, url, asset, signal, maxAssetBytes);
994
+ if (receipt) {
995
+ // Verify even when storage is disabled, unavailable or skipped. A body that the browser
996
+ // HTTP-decoded and that lost its gzip header is checked against the logical receipt.
997
+ const decoded = !!loaded.contentEncoding && !(loaded.bytes[0] === 0x1f && loaded.bytes[1] === 0x8b);
998
+ if (decoded && receipt.uncompressedSha256 !== undefined) {
999
+ await verifyRuntimeAssetIntegrity({
1000
+ asset,
1001
+ bytes: loaded.bytes,
1002
+ expected: {
1003
+ sha256: receipt.sha256,
1004
+ uncompressedSha256: receipt.uncompressedSha256,
1005
+ uncompressedBytes: receipt.uncompressedBytes
1006
+ },
1007
+ stage: 'uncompressed'
1008
+ });
1009
+ }
1010
+ else if (!decoded || !asset.endsWith('.gz')) {
1011
+ // Unpaired receipts for other assets already describe their logical bytes.
1012
+ await verifyRuntimeAssetIntegrity({
1013
+ asset,
1014
+ bytes: loaded.bytes,
1015
+ expected: { sha256: receipt.sha256, bytes: receipt.bytes }
1016
+ });
1017
+ }
1018
+ // A decoded .gz body with an unpaired receipt is left to runtime validation.
1019
+ }
950
1020
  if (identity && !loaded.contentEncoding) {
951
- // Only checksum-matching bytes are published. Existing runtime validation still runs.
952
- await writePersistentRuntimeAsset({
1021
+ // A hit skips the response MIME check, so publish only bytes that passed it.
1022
+ loaded.persist = () => writePersistentRuntimeAsset({
953
1023
  identity,
954
1024
  cache: persistentCache,
955
1025
  signal,
@@ -1177,6 +1247,11 @@ export class WorkerAssetBridge {
1177
1247
  if (url.hash) {
1178
1248
  throw new Error(`Runtime asset ${asset} URL must not include a fragment`);
1179
1249
  }
1250
+ // The prefix check below sees `/base/..%2fother` as inside `/base/`, but a server that
1251
+ // decodes the separator before resolving dot segments serves `/other`.
1252
+ if (/%2f|%5c/iu.test(url.pathname)) {
1253
+ throw new Error(`Runtime asset ${asset} URL must not include encoded path separators`);
1254
+ }
1180
1255
  const allowed = [context.config.baseUrl, ...(context.config.allowedBaseUrls || [])].some((baseUrl) => {
1181
1256
  let base;
1182
1257
  try {
@@ -663,12 +663,12 @@ export interface ResolvedZigRuntimeAssetConfig {
663
663
  integrity: ZigExecutionAssetReceipts;
664
664
  }
665
665
  export declare const PYTHON_RUNTIME_LOAD_ASSETS: readonly ["pyodide.mjs", "pyodide.asm.mjs", "pyodide-lock.json", "pyodide.asm.wasm", "python_stdlib.zip"];
666
- export declare const JAVA_RUNTIME_LOAD_ASSETS: readonly ["compiler.wasm-runtime.js", "compiler.wasm", "compile-classlib-teavm.bin", "runtime-classlib-teavm.bin"];
666
+ export declare const JAVA_RUNTIME_LOAD_ASSETS: readonly ["compiler.wasm-runtime.js", "compiler.wasm", "compiler.wasm-deobfuscator.wasm", "compile-classlib-teavm.bin", "runtime-classlib-teavm.bin"];
667
667
  export declare const CLANG_RUNTIME_LOAD_ASSETS: readonly ["runtime-manifest.v1.json", "bin/memfs.wasm.gz", "bin/clang.wasm.gz", "bin/lld.wasm.gz", "bin/sysroot.tar.gz"];
668
668
  export declare const CLANGD_RUNTIME_LOAD_ASSETS: readonly ["clangd.js", "clangd.wasm.gz", "clangd.headers.json.gz"];
669
669
  export declare const RUNTIME_LOAD_ASSETS: {
670
670
  python: readonly ["pyodide.mjs", "pyodide.asm.mjs", "pyodide-lock.json", "pyodide.asm.wasm", "python_stdlib.zip"];
671
- java: readonly ["compiler.wasm-runtime.js", "compiler.wasm", "compile-classlib-teavm.bin", "runtime-classlib-teavm.bin"];
671
+ java: readonly ["compiler.wasm-runtime.js", "compiler.wasm", "compiler.wasm-deobfuscator.wasm", "compile-classlib-teavm.bin", "runtime-classlib-teavm.bin"];
672
672
  clang: readonly ["runtime-manifest.v1.json", "bin/memfs.wasm.gz", "bin/clang.wasm.gz", "bin/lld.wasm.gz", "bin/sysroot.tar.gz"];
673
673
  clangd: readonly ["clangd.js", "clangd.wasm.gz", "clangd.headers.json.gz"];
674
674
  };