wasm-idle 1.0.6 → 1.0.8

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 (95) hide show
  1. package/README.md +18 -5
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.js +1 -0
  4. package/dist/playground/assetBridge.d.ts +6 -1
  5. package/dist/playground/assetBridge.js +77 -4
  6. package/dist/playground/assets.d.ts +9 -1
  7. package/dist/playground/assets.js +29 -5
  8. package/dist/playground/awk.js +1 -0
  9. package/dist/playground/bash.d.ts +1 -0
  10. package/dist/playground/bash.js +7 -1
  11. package/dist/playground/bqn.js +1 -0
  12. package/dist/playground/bqnPreflight.d.ts +2 -1
  13. package/dist/playground/bqnPreflight.js +1 -0
  14. package/dist/playground/c3.js +1 -0
  15. package/dist/playground/cachedClang.js +15 -8
  16. package/dist/playground/clang.d.ts +1 -0
  17. package/dist/playground/clang.js +8 -1
  18. package/dist/playground/clangAssetIntegrity.d.ts +6 -0
  19. package/dist/playground/clangAssetIntegrity.js +3 -2
  20. package/dist/playground/clojurescript.js +1 -0
  21. package/dist/playground/clojurescriptPreflight.d.ts +2 -1
  22. package/dist/playground/clojurescriptPreflight.js +1 -0
  23. package/dist/playground/elixir.js +4 -1
  24. package/dist/playground/forth.js +1 -0
  25. package/dist/playground/forthPreflight.d.ts +2 -1
  26. package/dist/playground/forthPreflight.js +1 -0
  27. package/dist/playground/fortran.js +7 -1
  28. package/dist/playground/haskell.js +4 -1
  29. package/dist/playground/haskellAssets.d.ts +2 -1
  30. package/dist/playground/haskellAssets.js +8 -8
  31. package/dist/playground/index.d.ts +1 -1
  32. package/dist/playground/index.js +2 -2
  33. package/dist/playground/j.js +1 -0
  34. package/dist/playground/jPreflight.d.ts +2 -1
  35. package/dist/playground/jPreflight.js +1 -0
  36. package/dist/playground/janet.js +1 -0
  37. package/dist/playground/java.js +20 -8
  38. package/dist/playground/julia.js +1 -0
  39. package/dist/playground/lfortranAssets.d.ts +2 -1
  40. package/dist/playground/lfortranAssets.js +1 -0
  41. package/dist/playground/lisp.js +4 -1
  42. package/dist/playground/lispAssets.d.ts +2 -1
  43. package/dist/playground/lispAssets.js +10 -0
  44. package/dist/playground/lldbManifest.d.ts +2 -2
  45. package/dist/playground/lldbManifest.js +17 -3
  46. package/dist/playground/lldbSession.d.ts +1 -0
  47. package/dist/playground/lldbSession.js +2 -1
  48. package/dist/playground/nim.js +1 -0
  49. package/dist/playground/ocaml.d.ts +1 -0
  50. package/dist/playground/ocaml.js +12 -1
  51. package/dist/playground/options.d.ts +2 -0
  52. package/dist/playground/pascal.js +1 -0
  53. package/dist/playground/perl.js +1 -0
  54. package/dist/playground/prolog.js +1 -0
  55. package/dist/playground/python.js +3 -1
  56. package/dist/playground/runtimeSession.d.ts +2 -1
  57. package/dist/playground/runtimeSession.js +2 -2
  58. package/dist/playground/rust.d.ts +1 -0
  59. package/dist/playground/rust.js +11 -1
  60. package/dist/playground/rustExecutableGraph.d.ts +1 -0
  61. package/dist/playground/rustExecutableGraph.js +1 -0
  62. package/dist/playground/staticRuntimePreflight.d.ts +2 -1
  63. package/dist/playground/staticRuntimePreflight.js +4 -2
  64. package/dist/playground/staticRuntimePreflightExecute.js +1 -0
  65. package/dist/playground/staticRuntimePreflightProtocol.d.ts +2 -1
  66. package/dist/playground/staticWorkerRuntime.d.ts +3 -1
  67. package/dist/playground/staticWorkerRuntime.js +44 -3
  68. package/dist/playground/tcl.js +1 -0
  69. package/dist/playground/tinygo.d.ts +2 -0
  70. package/dist/playground/tinygo.js +57 -3
  71. package/dist/playground/tinygoExecutableGraph.d.ts +4 -1
  72. package/dist/playground/tinygoExecutableGraph.js +59 -7
  73. package/dist/playground/typescript.js +4 -1
  74. package/dist/playground/wasmGoVersion.d.ts +1 -1
  75. package/dist/playground/wasmGoVersion.js +1 -1
  76. package/dist/playground/wasmOcamlVersion.d.ts +2 -2
  77. package/dist/playground/wasmOcamlVersion.js +1 -1
  78. package/dist/playground/wasmRustVersion.d.ts +90 -24
  79. package/dist/playground/wasmRustVersion.js +98 -23
  80. package/dist/playground/wasmTinyGoVersion.d.ts +40 -29
  81. package/dist/playground/wasmTinyGoVersion.js +43 -31
  82. package/dist/playground/worker/clang.js +1 -5
  83. package/dist/playground/worker/elixir.js +10 -8
  84. package/dist/playground/worker/fortran.js +4 -7
  85. package/dist/playground/worker/haskell.js +2 -0
  86. package/dist/playground/worker/lisp.js +2 -0
  87. package/dist/playground/worker/ocaml.js +13 -1
  88. package/dist/playground/worker/runtimeAssetFetch.d.ts +11 -1
  89. package/dist/playground/worker/runtimeAssetFetch.js +64 -1
  90. package/dist/playground/worker/rust.js +9 -2
  91. package/dist/playground/worker/staticRuntimePreflight.js +2 -0
  92. package/dist/playground/worker/typescript.js +4 -1
  93. package/dist/playground/worker/zig.js +7 -4
  94. package/dist/playground/zig.js +4 -1
  95. package/package.json +10 -7
package/README.md CHANGED
@@ -15,6 +15,10 @@ Compiler source pins, patches, and reproducible asset builds live in
15
15
  [`seo-rii/wasm-llvm`](https://github.com/seo-rii/wasm-llvm); wasm-idle loads the generated
16
16
  artifacts from external URLs instead of embedding them in npm packages.
17
17
 
18
+ Verified downloads can be retained across reloads using a version-pinned, capacity-bounded
19
+ CacheStorage/IndexedDB cache. See [persistent asset cache configuration and coverage](docs/runtime-asset-cache.md)
20
+ for global/per-call opt-out, cleanup and prefetch APIs.
21
+
18
22
  ## Language support policy
19
23
 
20
24
  wasm-idle language support must run user code through the real language implementation in the
@@ -221,9 +225,9 @@ when they exist.
221
225
  | Language / IDs | Package/version base | Execution defaults / flags | Customization |
222
226
  | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
223
227
  | 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 |
224
- | C<br>`C` | @wasm-idle/llvm-core@1.0.3 / 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` |
225
- | C++<br>`CPP` | @wasm-idle/llvm-core@1.0.3 / 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` |
226
- | Objective-C<br>`OBJC` | GNUstep libobjc2 v2.3 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.3 | `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` |
228
+ | C<br>`C` | @wasm-idle/llvm-core@1.0.8 / 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` |
229
+ | C++<br>`CPP` | @wasm-idle/llvm-core@1.0.8 / 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` |
230
+ | Objective-C<br>`OBJC` | GNUstep libobjc2 v2.3 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.8 | `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` |
227
231
  | Python<br>`PYTHON3` | static ESM `static/pyodide/pyodide.mjs` / pyodide@0.29.3 | loads `pyodide.mjs`, `pyodide.asm.js`, `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` |
228
232
  | Java<br>`JAVA` | @wasm-idle/runtime-teavm@0.0.0 / TeaVM compiler assets | `compiler.wasm` compiles Java to browser WASM/JS; supports `stdin` and `programArgs` | `runtimeAssets.java.baseUrl`/`loader` or `rootUrl` |
229
233
  | Rust<br>`RUST` | wasm-rust@0.1.0 / rust-1.99.0-browser-integrated-v1 + integrated LLVM/LLD 22.1.8 from the `wasm-llvm` producer; exact rustc/LLVM provenance is recorded for LLDB compatibility | browser host `wasm32-wasip1-threads`; default target `wasm32-wasip1`, selectable `wasm32-wasip1`, `wasm32-wasip2`, `wasm32-wasip3`; LLDB mode is currently limited to `wasm32-wasip1` and emits embedded DWARF with `-C debuginfo=2 -C opt-level=0`; normal Preview 1/2/3 execution remains unchanged; supports `stdin` and `programArgs` | `runtimeAssets.rust.compilerUrl`, `runtimeAssets.rust.debugModuleUrl`, or `PUBLIC_WASM_RUST_COMPILER_URL`; `rootUrl`, `rustTargetTriple`, `programArgs`, `debugMode`; compiler requests accept `edition`, `crateType`, `extendedTimeout`, `log`, and `onProgress`; runtime manifest controls compiler memory, timeout, and shared workspace size |
@@ -261,8 +265,8 @@ when they exist.
261
265
  | Ruby<br>`RUBY` | receipt-pinned `static/wasm-ruby` profile produced from @ruby/3.4-wasm-wasi@2.9.3-2.9.4 + @ruby/wasm-wasi@2.9.3-2.9.4 | host-verifies the manifest, canonical stored module and gzip bytes, and logical WASM before transferring three owned buffers to a no-fetch CRuby 3.4 worker; supports `stdin`, `programArgs`, and workspace files | `rootUrl` mirrors reuse the bundled profile; explicit `runtimeAssets.ruby` overrides require one complete profile and same-origin canonical paths; URL-only `PUBLIC_WASM_RUBY_*` overrides fail closed; `stdin`, `programArgs`, `workspaceFiles` |
262
266
  | 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` |
263
267
  | 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 |
264
- | Fortran<br>`FORTRAN` | Netlib f2c 2022-09-09 + `@cowasm/f2c 1.0.0` libf2c + @wasm-idle/llvm-core@1.0.3 | 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` |
265
- | COBOL<br>`COBOL` | GnuCOBOL 3.2 + GMP 6.3.0 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.3 | 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` |
268
+ | Fortran<br>`FORTRAN` | Netlib f2c 2022-09-09 + `@cowasm/f2c 1.0.0` libf2c + @wasm-idle/llvm-core@1.0.8 | 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` |
269
+ | COBOL<br>`COBOL` | GnuCOBOL 3.2 + GMP 6.3.0 assets from the `wasm-llvm` producer + @wasm-idle/llvm-core@1.0.8 | 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` |
266
270
  | 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` |
267
271
  | 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_*` |
268
272
  | DuckDB<br>`DUCKDB` | static ESM `static/wasm-duckdb/runtime.mjs` produced from @duckdb/duckdb-wasm@1.33.1-dev45.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` |
@@ -323,6 +327,15 @@ toolchains can be consumed from pinned external runtime repositories:
323
327
  normal runtime workspace packages. `tools/dool` contains the Docker judge backend for Elixir and
324
328
  the other server-side language runners.
325
329
 
330
+ Deployment builds retain both legacy `.gz` and canonical `.gz.bin` URLs by default.
331
+ After building and compressing the page, `pnpm run compact:build-runtimes` reports
332
+ byte-identical duplicates without changing files. Add `--drop-legacy-aliases` to
333
+ remove those duplicate files and add compatibility routing to the generated service
334
+ worker. This only preserves legacy URLs in service-worker-controlled requests:
335
+ external SDKs and uncontrolled first requests to the removed `.gz` URLs need to
336
+ migrate to `.gz.bin` or use server aliases. Opt in only after that migration. Source
337
+ assets and producer receipts stay intact; rerun compaction after each page build.
338
+
326
339
  Useful workspace commands:
327
340
 
328
341
  ```bash
package/dist/index.d.ts CHANGED
@@ -2,10 +2,11 @@ import playground, { createPlaygroundBinding } from './playground';
2
2
  export default playground;
3
3
  export { createPlaygroundBinding, playground };
4
4
  export { createRuntimeSession } from './playground/runtimeSession';
5
+ export { configureRuntimeAssetCache, createRuntimeAssetCacheBackend, fetchPinnedRuntimeAsset, prefetchRuntimeAssets, resolveRuntimeAssetLockEntry, type PrefetchRuntimeAssetsOptions, type PrefetchRuntimeAssetsResult, type RuntimeAssetCacheStats, type RuntimeAssetCacheBackend, type RuntimeAssetCacheBackendIdentity, type PinnedRuntimeAssetRequest, getRuntimeAssetCacheOptions, getRuntimeAssetCacheStats, clearRuntimeAssetCache, pruneRuntimeAssetCache, requestRuntimeAssetCachePersistence, type RuntimeAssetCacheOptions } from '@wasm-idle/core';
5
6
  export type { PlaygroundRuntimeSession } from './playground/runtimeSession';
6
7
  export { isSharedArrayBufferAvailable, requireSharedArrayBuffer } from './playground/sharedBuffer';
7
8
  export type { DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, TerminalControl } from '@wasm-idle/core';
8
9
  export type { CompilerDiagnostic, SandboxExecutionOptions } from './playground/options';
9
10
  export type { PlaygroundRuntimeAssets, RuntimeAssetConfig, RuntimeAssetLoadRequest, RuntimeAssetLoader, RuntimeAssetLoaderResult } from './playground/assets';
10
11
  export type { BoundSandbox, PlaygroundBinding, PlaygroundTerminalProps, SandboxProgress, SandboxRuntimeAssets } from './playground/sandbox';
11
- export type { PlaygroundBindingOptions } from "@wasm-idle/core";
12
+ export type { PlaygroundBindingOptions } from '@wasm-idle/core';
package/dist/index.js CHANGED
@@ -2,4 +2,5 @@ import playground, { createPlaygroundBinding } from './playground';
2
2
  export default playground;
3
3
  export { createPlaygroundBinding, playground };
4
4
  export { createRuntimeSession } from './playground/runtimeSession';
5
+ export { configureRuntimeAssetCache, createRuntimeAssetCacheBackend, fetchPinnedRuntimeAsset, prefetchRuntimeAssets, resolveRuntimeAssetLockEntry, getRuntimeAssetCacheOptions, getRuntimeAssetCacheStats, clearRuntimeAssetCache, pruneRuntimeAssetCache, requestRuntimeAssetCachePersistence } from '@wasm-idle/core';
5
6
  export { isSharedArrayBufferAvailable, requireSharedArrayBuffer } from './playground/sharedBuffer';
@@ -1,5 +1,5 @@
1
1
  import { type ResolvedRuntimeAssetConfig, type RuntimeAssetRuntime } from './assets';
2
- import { type ProgressLike } from '@wasm-idle/core';
2
+ import { type RuntimeAssetCacheOptions, type ResolvedRuntimeAssetCacheOptions, type ProgressLike } from '@wasm-idle/core';
3
3
  import { RuntimeAssetCache } from './runtimeAssetCache';
4
4
  export declare const boundedUtf8ByteLength: (value: string, maxBytes?: number) => number;
5
5
  export declare class WorkerAssetBridge {
@@ -7,6 +7,8 @@ export declare class WorkerAssetBridge {
7
7
  private worker;
8
8
  private readonly runtime;
9
9
  private config;
10
+ private persistentCacheBaseline;
11
+ private readonly persistentCacheBySignal;
10
12
  private progress;
11
13
  private expectedAssets;
12
14
  private languageSysroots;
@@ -17,6 +19,8 @@ export declare class WorkerAssetBridge {
17
19
  private maxAssetBytes;
18
20
  constructor(worker: Worker, runtime: RuntimeAssetRuntime, config: ResolvedRuntimeAssetConfig, progress?: ProgressLike, maxAssetBytes?: number, languageSysroots?: boolean, cache?: RuntimeAssetCache | undefined);
19
21
  matches(config: ResolvedRuntimeAssetConfig, maxAssetBytes?: number, languageSysroots?: boolean): boolean;
22
+ /** Apply one execution's policy without changing the configuration established by load(). */
23
+ setExecutionPersistentCache(override?: RuntimeAssetCacheOptions): ResolvedRuntimeAssetCacheOptions;
20
24
  rebind(worker: Worker, config: ResolvedRuntimeAssetConfig, progress?: ProgressLike, maxAssetBytes?: number, languageSysroots?: boolean): void;
21
25
  dispose(): void;
22
26
  resetProgress(progress?: ProgressLike): void;
@@ -31,6 +35,7 @@ export declare class WorkerAssetBridge {
31
35
  private verifyIntegrity;
32
36
  private normalizeLoaderResult;
33
37
  private fetchAsset;
38
+ private fetchAssetFromNetwork;
34
39
  private requireAllowedAssetUrl;
35
40
  private abortActiveLoads;
36
41
  }
@@ -1,5 +1,5 @@
1
1
  import { RUNTIME_LOAD_ASSETS } from './assets';
2
- import { ProtocolError, verifyRuntimeAssetIntegrity, verifyRuntimeAssetPair } from '@wasm-idle/core';
2
+ import { ProtocolError, verifyRuntimeAssetIntegrity, verifyRuntimeAssetPair, readPersistentRuntimeAsset, writePersistentRuntimeAsset, resolveRuntimeAssetLockEntry, resolveRuntimeAssetCacheOptions } from '@wasm-idle/core';
3
3
  import { decompressGzip } from '@wasm-idle/llvm-core';
4
4
  import { readPythonPackageAssets } from './pythonPackageLock';
5
5
  import { BUNDLED_CLANG_LANGUAGE_SYSROOT_PROFILES } from './clangAssetIntegrity';
@@ -189,9 +189,12 @@ const transferBuffer = (bytes, transferOwnership = false) => {
189
189
  const cSysrootAsset = BUNDLED_CLANG_LANGUAGE_SYSROOT_PROFILES.c.asset;
190
190
  const cppAddonAsset = BUNDLED_CLANG_LANGUAGE_SYSROOT_PROFILES.cppAddon.asset;
191
191
  const fullSysrootAsset = 'bin/sysroot.tar.gz';
192
+ const printscanLongDoubleAsset = 'libc-printscan-long-double.a.gz';
192
193
  const canUseClangLanguageSysroots = (runtime, config, requested) => runtime === 'clang' && requested && config.useAssetBridge && shouldStreamBundledClang(config);
193
194
  const expectedAssetsForRuntime = (runtime, languageSysroots = false) => {
194
195
  const assets = new Set(RUNTIME_LOAD_ASSETS[runtime]);
196
+ if (runtime === 'clang')
197
+ assets.add(printscanLongDoubleAsset);
195
198
  if (runtime === 'clang' && languageSysroots) {
196
199
  assets.add(cSysrootAsset);
197
200
  assets.add(cppAddonAsset);
@@ -225,6 +228,10 @@ class RuntimeLoadProgress {
225
228
  constructor(runtime, languageSysroots = false) {
226
229
  this.expectedAssets = expectedAssetsForRuntime(runtime);
227
230
  this.optionalAssets = new Set();
231
+ if (runtime === 'clang') {
232
+ this.expectedAssets.delete(printscanLongDoubleAsset);
233
+ this.optionalAssets.add(printscanLongDoubleAsset);
234
+ }
228
235
  if (runtime === 'clang' && languageSysroots) {
229
236
  this.expectedAssets.delete(fullSysrootAsset);
230
237
  this.expectedAssets.add(cSysrootAsset);
@@ -379,6 +386,8 @@ export class WorkerAssetBridge {
379
386
  worker;
380
387
  runtime;
381
388
  config;
389
+ persistentCacheBaseline;
390
+ persistentCacheBySignal = new WeakMap();
382
391
  progress;
383
392
  expectedAssets;
384
393
  languageSysroots;
@@ -391,7 +400,8 @@ export class WorkerAssetBridge {
391
400
  this.cache = cache;
392
401
  this.worker = worker;
393
402
  this.runtime = runtime;
394
- this.config = config;
403
+ this.persistentCacheBaseline = resolveRuntimeAssetCacheOptions(config.persistentCache);
404
+ this.config = { ...config, persistentCache: this.persistentCacheBaseline };
395
405
  this.maxAssetBytes = requireBridgeMaxAssetBytes(maxAssetBytes);
396
406
  this.languageSysroots = canUseClangLanguageSysroots(runtime, config, languageSysroots);
397
407
  this.progress = new RuntimeLoadProgress(runtime, this.languageSysroots);
@@ -407,7 +417,17 @@ export class WorkerAssetBridge {
407
417
  this.config.loader === config.loader &&
408
418
  integrityKey(this.config) === integrityKey(config) &&
409
419
  allowedBaseUrlsKey(this.config) === allowedBaseUrlsKey(config) &&
410
- this.config.useAssetBridge === config.useAssetBridge);
420
+ this.config.useAssetBridge === config.useAssetBridge &&
421
+ JSON.stringify(this.persistentCacheBaseline) ===
422
+ JSON.stringify(resolveRuntimeAssetCacheOptions(config.persistentCache)));
423
+ }
424
+ /** Apply one execution's policy without changing the configuration established by load(). */
425
+ setExecutionPersistentCache(override) {
426
+ if (this.state !== 'active')
427
+ throw new Error('Cannot configure an inactive worker asset bridge');
428
+ const cache = resolveRuntimeAssetCacheOptions(this.persistentCacheBaseline, override);
429
+ this.config = { ...this.config, persistentCache: cache };
430
+ return cache;
411
431
  }
412
432
  rebind(worker, config, progress, maxAssetBytes = this.maxAssetBytes, languageSysroots = this.languageSysroots) {
413
433
  if (this.state === 'disposed') {
@@ -430,7 +450,8 @@ export class WorkerAssetBridge {
430
450
  throw new Error('Cannot rebind a disposed worker asset bridge');
431
451
  }
432
452
  this.worker = worker;
433
- this.config = config;
453
+ this.persistentCacheBaseline = resolveRuntimeAssetCacheOptions(config.persistentCache);
454
+ this.config = { ...config, persistentCache: this.persistentCacheBaseline };
434
455
  this.maxAssetBytes = nextMaxAssetBytes;
435
456
  this.languageSysroots = nextLanguageSysroots;
436
457
  this.expectedAssets = expectedAssetsForRuntime(this.runtime, nextLanguageSysroots);
@@ -525,6 +546,7 @@ export class WorkerAssetBridge {
525
546
  const worker = this.worker;
526
547
  const generation = this.generation;
527
548
  const controller = new AbortController();
549
+ this.persistentCacheBySignal.set(controller.signal, resolveRuntimeAssetCacheOptions(this.config.persistentCache));
528
550
  this.activeLoads.add(controller);
529
551
  try {
530
552
  this.validateAssetRequest(request.asset);
@@ -555,6 +577,7 @@ export class WorkerAssetBridge {
555
577
  const receipt = BUNDLED_CLANG_ASSET_INTEGRITY[request.asset];
556
578
  module = await compileVerifiedWasmAsset(new URL(request.asset, this.config.baseUrl).href, receipt, {
557
579
  fetch: globalThis.fetch.bind(globalThis),
580
+ persistentCache: this.persistentCacheBySignal.get(controller.signal),
558
581
  maxAssetBytes: this.maxAssetBytes,
559
582
  signal: controller.signal,
560
583
  onProgress: (loaded, total) => this.progress.update(request.asset, loaded, total)
@@ -831,6 +854,56 @@ export class WorkerAssetBridge {
831
854
  return null;
832
855
  }
833
856
  async fetchAsset(url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(asset)) {
857
+ const requestUrl = this.requireAllowedAssetUrl(asset, url);
858
+ const persistentCache = this.persistentCacheBySignal.get(signal) ?? this.config.persistentCache;
859
+ const configured = this.config.integrity?.[asset];
860
+ const expected = typeof configured === 'string' ? { sha256: configured } : configured;
861
+ const lock = this.config.assetPrefix
862
+ ? resolveRuntimeAssetLockEntry(requestUrl, {
863
+ assetRoot: this.config.baseUrl,
864
+ assetPrefix: this.config.assetPrefix
865
+ })
866
+ : undefined;
867
+ // Existing .gz receipts without a pair describe logical bytes, not stored gzip bytes.
868
+ const receipt = expected && (!asset.endsWith('.gz') || expected.uncompressedSha256) ? expected : lock;
869
+ const identity = receipt
870
+ ? {
871
+ url: requestUrl.href,
872
+ sha256: receipt.sha256,
873
+ bytes: receipt.bytes,
874
+ validationKey: JSON.stringify([
875
+ 'bridge-v1',
876
+ this.config.baseUrl,
877
+ allowedBaseUrlsKey(this.config),
878
+ maxAssetBytes
879
+ ])
880
+ }
881
+ : undefined;
882
+ if (identity && (identity.bytes === undefined || identity.bytes <= maxAssetBytes)) {
883
+ const bytes = await readPersistentRuntimeAsset({
884
+ identity,
885
+ cache: persistentCache,
886
+ signal
887
+ });
888
+ if (bytes) {
889
+ requireRuntimeAssetSize(asset, bytes.byteLength, maxAssetBytes);
890
+ this.progress.update(asset, bytes.byteLength, bytes.byteLength);
891
+ return { bytes, mimeType: receipt?.mediaType, transferOwnership: true };
892
+ }
893
+ }
894
+ const loaded = await this.fetchAssetFromNetwork(url, asset, signal, maxAssetBytes);
895
+ if (identity && !loaded.contentEncoding) {
896
+ // Only checksum-matching bytes are published. Existing runtime validation still runs.
897
+ await writePersistentRuntimeAsset({
898
+ identity,
899
+ cache: persistentCache,
900
+ signal,
901
+ bytes: loaded.bytes
902
+ });
903
+ }
904
+ return loaded;
905
+ }
906
+ async fetchAssetFromNetwork(url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(asset)) {
834
907
  const requestUrl = this.requireAllowedAssetUrl(asset, url);
835
908
  if (signal.aborted)
836
909
  throw runtimeAssetAbortReason(signal);
@@ -1,3 +1,4 @@
1
+ import { type RuntimeAssetCacheOptions } from '@wasm-idle/core';
1
2
  import { type DOuterAssetReceipts } from './dOuterAssets';
2
3
  import type { ElixirRuntimeAssetReceipts } from './elixirAssets';
3
4
  import { type FortranExecutionAssetReceipts } from './fortranAssets';
@@ -25,6 +26,7 @@ export type RuntimeAssetLoader = (request: RuntimeAssetLoadRequest) => RuntimeAs
25
26
  export type RuntimeAssetIntegrityEntry = CoreRuntimeAssetIntegrityEntry;
26
27
  export type RuntimeAssetIntegrityMap = Record<string, string | RuntimeAssetIntegrityEntry>;
27
28
  export interface RuntimeAssetConfig {
29
+ persistentCache?: import('@wasm-idle/core').RuntimeAssetCacheOptions;
28
30
  baseUrl?: string;
29
31
  loader?: RuntimeAssetLoader;
30
32
  loaderKey?: string;
@@ -139,11 +141,14 @@ export interface LispRuntimeAssetConfig {
139
141
  moduleUrl?: string;
140
142
  manifestUrl?: string;
141
143
  manifestFingerprint?: string;
144
+ /** Optional raw JSON byte receipt; distinct from the canonical manifest fingerprint. */
145
+ manifestReceipt?: RuntimeAssetIntegrityEntry;
142
146
  }
143
147
  export interface ResolvedLispRuntimeAssetConfig {
144
148
  moduleUrl: string;
145
149
  manifestUrl: string;
146
150
  manifestFingerprint: string;
151
+ manifestReceipt?: RuntimeAssetIntegrityEntry;
147
152
  }
148
153
  export interface RubyRuntimeAssetConfig {
149
154
  /** Keep full stdlib compatibility, but load its data separately from the core Wasm. */
@@ -563,6 +568,9 @@ export interface TinyGoRuntimeAssetLoaderRequest {
563
568
  export type TinyGoRuntimeAssetLoaderResult = RuntimeAssetDataResult | RuntimeAssetUrlResult | string | URL | ArrayBuffer | Uint8Array | Blob | null | undefined;
564
569
  export type TinyGoRuntimeAssetLoader = (request: TinyGoRuntimeAssetLoaderRequest) => TinyGoRuntimeAssetLoaderResult | Promise<TinyGoRuntimeAssetLoaderResult>;
565
570
  export interface ResolvedRuntimeAssetConfig {
571
+ persistentCache?: import('@wasm-idle/core').RuntimeAssetCacheOptions;
572
+ /** Built-in lock prefix; custom loaders use only explicitly supplied receipts. */
573
+ assetPrefix?: string;
566
574
  baseUrl: string;
567
575
  loader?: RuntimeAssetLoader;
568
576
  integrity?: RuntimeAssetIntegrityMap;
@@ -607,7 +615,7 @@ export declare const RUNTIME_LOAD_ASSETS: {
607
615
  clang: readonly ["runtime-manifest.v1.json", "bin/memfs.wasm.gz", "bin/clang.wasm.gz", "bin/lld.wasm.gz", "bin/sysroot.tar.gz"];
608
616
  clangd: readonly ["clangd.js", "clangd.wasm.gz"];
609
617
  };
610
- export declare function resolveRuntimeAssetConfig(runtime: RuntimeAssetRuntime, options: string | PlaygroundRuntimeAssets | undefined, currentUrl?: string): ResolvedRuntimeAssetConfig;
618
+ export declare function resolveRuntimeAssetConfig(runtime: RuntimeAssetRuntime, options: string | PlaygroundRuntimeAssets | undefined, currentUrl?: string, callCache?: RuntimeAssetCacheOptions): ResolvedRuntimeAssetConfig;
611
619
  export declare function resolveRustCompilerUrl(options: string | PlaygroundRuntimeAssets | undefined, currentUrl?: string): string;
612
620
  export declare function resolveDebugRuntimeUrls(options: string | PlaygroundRuntimeAssets | undefined, currentUrl?: string): {
613
621
  baseUrl: string;
@@ -1,4 +1,5 @@
1
1
  import { env as dynamicPublicEnv } from '$env/dynamic/public';
2
+ import { resolveRuntimeAssetCacheOptions, resolveRuntimeAssetLockEntry } from '@wasm-idle/core';
2
3
  import { BUNDLED_CLANG_ASSET_INTEGRITY } from './clangAssetIntegrity';
3
4
  import { snapshotDOuterAssetConfig } from './dOuterAssets';
4
5
  import { snapshotFortranExecutionAssetReceipts } from './fortranAssets';
@@ -100,7 +101,21 @@ const RUNTIME_ASSET_FOLDERS = {
100
101
  const resolveRuntimeRootBaseUrl = (config, rootUrl = '', currentUrl = '') => config.resolveRootBaseUrl?.(rootUrl, currentUrl) ||
101
102
  resolveFolderRuntimeBaseUrl(config.folder, rootUrl, currentUrl);
102
103
  const resolveRuntimeConfiguredBaseUrl = (config, baseUrl, currentUrl = '') => config.resolveConfiguredBaseUrl?.(baseUrl, currentUrl) || normalizeBaseUrl(baseUrl, currentUrl);
103
- export function resolveRuntimeAssetConfig(runtime, options, currentUrl = '') {
104
+ export function resolveRuntimeAssetConfig(runtime, options, currentUrl = '', callCache) {
105
+ const config = resolveRuntimeAssetConfigWithoutCache(runtime, options, currentUrl);
106
+ const runtimeConfig = typeof options === 'object' ? options?.[runtime] : undefined;
107
+ const persistentCache = resolveRuntimeAssetCacheOptions(typeof options === 'object' ? options?.persistentCache : undefined, runtimeConfig?.persistentCache, callCache);
108
+ const assetPrefix = !config.loader && !runtimeConfig?.baseUrl
109
+ ? RUNTIME_ASSET_FOLDERS[runtime].folder
110
+ : undefined;
111
+ return {
112
+ ...config,
113
+ persistentCache,
114
+ assetPrefix,
115
+ useAssetBridge: config.useAssetBridge || (persistentCache.enabled && !!assetPrefix)
116
+ };
117
+ }
118
+ function resolveRuntimeAssetConfigWithoutCache(runtime, options, currentUrl = '') {
104
119
  const runtimeFolder = RUNTIME_ASSET_FOLDERS[runtime];
105
120
  if (typeof options === 'string') {
106
121
  const integrity = resolveRuntimeAssetIntegrity(runtime, undefined);
@@ -733,12 +748,21 @@ export function resolveLispRuntimeAssetConfig(options, currentUrl = '') {
733
748
  const configuredFingerprint = configured?.manifestFingerprint?.trim() ||
734
749
  (publicEnv.PUBLIC_WASM_LISP_MANIFEST_FINGERPRINT || '').trim();
735
750
  const usesBundledRoot = !configuredModuleUrl && !publicModuleUrl && rootUrl !== undefined;
751
+ const manifestUrl = configuredManifestUrl
752
+ ? resolveConfiguredUrl(configuredManifestUrl, currentUrl)
753
+ : deriveLispManifestUrl(moduleUrl, currentUrl);
754
+ const manifestReceipt = configured?.manifestReceipt ??
755
+ (usesBundledRoot && !configuredManifestUrl && !configuredFingerprint
756
+ ? resolveRuntimeAssetLockEntry(manifestUrl, {
757
+ assetRoot: new URL('./', new URL(moduleUrl, currentUrl || 'http://localhost/')),
758
+ assetPrefix: 'wasm-lisp'
759
+ })
760
+ : undefined);
736
761
  return {
737
762
  moduleUrl,
738
- manifestUrl: configuredManifestUrl
739
- ? resolveConfiguredUrl(configuredManifestUrl, currentUrl)
740
- : deriveLispManifestUrl(moduleUrl, currentUrl),
741
- manifestFingerprint: configuredFingerprint || (usesBundledRoot ? WASM_LISP_ASSET_VERSION : '')
763
+ manifestUrl,
764
+ manifestFingerprint: configuredFingerprint || (usesBundledRoot ? WASM_LISP_ASSET_VERSION : ''),
765
+ ...(manifestReceipt ? { manifestReceipt: Object.freeze({ ...manifestReceipt }) } : {})
742
766
  };
743
767
  }
744
768
  const RUBY_RUNTIME_CONFIG_KEYS = [
@@ -40,6 +40,7 @@ class Awk extends StaticWorkerRuntimeSandbox {
40
40
  manifestUrl: resolved.manifestUrl,
41
41
  profile,
42
42
  limits: context.limits,
43
+ persistentCache: context.persistentCache,
43
44
  signal: context.signal,
44
45
  reportProgress(progress) {
45
46
  loadedByAsset.set(progress.assetKey, progress.loadedBytes);
@@ -14,6 +14,7 @@ declare class Bash implements Sandbox {
14
14
  private activeOperation;
15
15
  private readyWorker;
16
16
  private loadedConfig;
17
+ private persistentCache?;
17
18
  private requestUid;
18
19
  private sessionUid;
19
20
  private disposed;
@@ -1,7 +1,7 @@
1
1
  import { resolveBashRuntimeAssetConfig } from './assets';
2
2
  import { BASH_WORKER_PROTOCOL_VERSION, isBashWorkerToHostMessage } from './bashWorkerProtocol';
3
3
  import { reportWorkerProgress } from './workerProgress';
4
- import { AssetTooLargeError, AssetIntegrityError, AssetNotFoundError, BusyError, CancelledError, CompileError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, ProtocolError, ResourceLimitError, RuntimeConfigurationError, RuntimeExecutionError, TimeoutError, UnsupportedBrowserFeatureError, UnsupportedLanguageError, WasmIdleError, WorkerStartupError, preflightBashRuntimeAssets, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
4
+ import { AssetTooLargeError, AssetIntegrityError, AssetNotFoundError, BusyError, CancelledError, CompileError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, ProtocolError, ResourceLimitError, RuntimeConfigurationError, RuntimeExecutionError, TimeoutError, UnsupportedBrowserFeatureError, UnsupportedLanguageError, WasmIdleError, WorkerStartupError, preflightBashRuntimeAssets, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, validateExecutionWorkspace } from '@wasm-idle/core';
5
5
  const MAX_TIMER_DELAY_MS = 2_147_483_647;
6
6
  const textEncoder = new TextEncoder();
7
7
  const abortReason = (signal, phase) => signal.reason !== undefined
@@ -29,6 +29,7 @@ class Bash {
29
29
  activeOperation = null;
30
30
  readyWorker = null;
31
31
  loadedConfig = null;
32
+ persistentCache;
32
33
  requestUid = 0;
33
34
  sessionUid = 0;
34
35
  disposed = false;
@@ -85,6 +86,9 @@ class Bash {
85
86
  const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
86
87
  const resolved = resolveBashRuntimeAssetConfig(runtimeAssets, currentUrl);
87
88
  this.requireActive(operation);
89
+ this.persistentCache =
90
+ typeof runtimeAssets === 'string' ? undefined : runtimeAssets.persistentCache;
91
+ operation.persistentCache = resolveRuntimeAssetCacheOptions(this.persistentCache, options.persistentCache);
88
92
  const config = {
89
93
  ...resolved,
90
94
  identity: createBashConfigIdentity(resolved.preflightKey, limits),
@@ -165,6 +169,7 @@ class Bash {
165
169
  this.requireActive(operation);
166
170
  if (signal?.aborted)
167
171
  throw abortReason(signal, operation.stage);
172
+ operation.persistentCache = resolveRuntimeAssetCacheOptions(this.persistentCache, options.persistentCache);
168
173
  const limits = resolveExecutionLimits(options.limits);
169
174
  this.requireActive(operation);
170
175
  if (!this.readyWorker) {
@@ -481,6 +486,7 @@ class Bash {
481
486
  webcUrl: config.webcUrl,
482
487
  profile: config.preflightProfile,
483
488
  limits: config.limits,
489
+ persistentCache: operation.persistentCache,
484
490
  signal: preflightController.signal,
485
491
  reportProgress: ({ assetKey, loadedBytes }) => {
486
492
  loadedByAsset.set(assetKey, loadedBytes);
@@ -35,6 +35,7 @@ class Bqn extends StaticWorkerRuntimeSandbox {
35
35
  manifestUrl: urls.manifestUrl || '',
36
36
  profile,
37
37
  limits: context.limits,
38
+ persistentCache: context.persistentCache,
38
39
  signal: context.signal,
39
40
  reportProgress(progress) {
40
41
  if (progress.kind === 'asset') {
@@ -1,5 +1,5 @@
1
1
  import type { BqnRuntimePreflightProfile } from './assets';
2
- import { type ExecutionLimits, type RuntimeAssetPreflightProgress } from '@wasm-idle/core';
2
+ import { type ExecutionLimits, type RuntimeAssetCacheOptions, type RuntimeAssetPreflightProgress } from '@wasm-idle/core';
3
3
  export declare const BQN_PREFLIGHT_PROTOCOL: "wasm-idle-bqn-preflight";
4
4
  export declare const BQN_PREFLIGHT_PROTOCOL_VERSION: 1;
5
5
  export declare const BQN_PREFLIGHT_RUNTIME_ID: "BQN";
@@ -8,6 +8,7 @@ export interface BqnRuntimePreflightRequest {
8
8
  readonly manifestUrl: string;
9
9
  readonly profile: BqnRuntimePreflightProfile;
10
10
  readonly limits?: Partial<ExecutionLimits>;
11
+ readonly persistentCache?: RuntimeAssetCacheOptions;
11
12
  readonly signal?: AbortSignal;
12
13
  readonly fetch?: typeof globalThis.fetch;
13
14
  readonly reportProgress?: (progress: RuntimeAssetPreflightProgress) => void;
@@ -237,6 +237,7 @@ export async function preflightBqnRuntimeAssets(request) {
237
237
  wasm: wasmRequestUrl
238
238
  },
239
239
  fetch: request.fetch,
240
+ persistentCache: request.persistentCache,
240
241
  signal: controller.signal,
241
242
  limits,
242
243
  maxConcurrentDownloads: 3,
@@ -121,6 +121,7 @@ class C3 extends StaticWorkerRuntimeSandbox {
121
121
  runtimeId: 'C3',
122
122
  rootUrl: urls.baseUrl,
123
123
  limits: context.limits,
124
+ persistentCache: context.persistentCache,
124
125
  signal: context.signal,
125
126
  redirect: 'error',
126
127
  requireExactResponseUrl: true,
@@ -1,4 +1,4 @@
1
- import { resolveExecutionLimits } from '@wasm-idle/core';
1
+ import { resolveExecutionLimits, resolveRuntimeAssetCacheOptions } from '@wasm-idle/core';
2
2
  import { resolveRuntimeAssetConfig } from './assets';
3
3
  import { WorkerAssetBridge } from './assetBridge';
4
4
  import { shouldStreamBundledClang } from './clangStreamingPolicy';
@@ -69,7 +69,7 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
69
69
  cancelWorker?.(new Error('Process terminated'));
70
70
  resetInput();
71
71
  }
72
- async function workerOperation(factory, message, token, progress, compileLimit = 0, signal) {
72
+ async function workerOperation(factory, message, token, progress, compileLimit = 0, signal, executionAssetConfig = assetConfig) {
73
73
  const worker = await factory();
74
74
  if (token !== generation || signal?.aborted) {
75
75
  worker.terminate();
@@ -79,7 +79,7 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
79
79
  let bridge;
80
80
  try {
81
81
  if (compileLimit)
82
- bridge = new WorkerAssetBridge(worker, 'clang', assetConfig, progress, compileLimit, languageSysroots, runtimeCache);
82
+ bridge = new WorkerAssetBridge(worker, 'clang', executionAssetConfig, progress, compileLimit, languageSysroots, runtimeCache);
83
83
  }
84
84
  catch (error) {
85
85
  worker.terminate();
@@ -172,7 +172,7 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
172
172
  throw new Error('C/C++ sandbox was disposed');
173
173
  loadedAssets = assets;
174
174
  const config = typeof assets === 'object' ? assets : undefined;
175
- assetConfig = resolveRuntimeAssetConfig('clang', assets, globalThis.location?.href || 'http://localhost/');
175
+ assetConfig = resolveRuntimeAssetConfig('clang', assets, globalThis.location?.href || 'http://localhost/', options.persistentCache);
176
176
  const debugMode = options.debugMode || (options.debug ? 'trace' : 'none');
177
177
  const cacheEligible = debugMode === 'none' &&
178
178
  shouldStreamBundledClang(assetConfig) &&
@@ -194,16 +194,23 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
194
194
  async run(code, prepare, log = true, progress, args = [], options = {}) {
195
195
  if (disposed)
196
196
  throw new Error('C/C++ sandbox was disposed');
197
+ if (running)
198
+ throw new Error('C/C++ sandbox is already running');
197
199
  if (cached &&
198
200
  ((options.debugMode || (options.debug ? 'trace' : 'none')) !== 'none' ||
199
201
  (options.stdin !== undefined && typeof options.stdin !== 'string') ||
200
202
  options.workspaceFiles?.some((file) => typeof file.content !== 'string'))) {
201
- await overrides.load(loadedAssets, code, log, args, options, progress);
203
+ await overrides.load(loadedAssets, code, log, args, {
204
+ ...options,
205
+ persistentCache: assetConfig.persistentCache
206
+ }, progress);
202
207
  }
203
208
  if (!cached)
204
209
  return legacy.run(code, prepare, log, progress, args, options);
205
- if (running)
206
- throw new Error('C/C++ sandbox is already running');
210
+ const executionAssetConfig = {
211
+ ...assetConfig,
212
+ persistentCache: resolveRuntimeAssetCacheOptions(assetConfig.persistentCache, options.persistentCache)
213
+ };
207
214
  options.signal?.throwIfAborted();
208
215
  const token = ++generation;
209
216
  // Reactive UI arrays/records are Proxies and cannot cross postMessage.
@@ -246,7 +253,7 @@ export function createCachedClangSandbox(legacy, language, runtimeCache, cache =
246
253
  useAssetBridge: assetConfig.useAssetBridge,
247
254
  useModuleBridge: true
248
255
  }
249
- }, token, progress, limit, options.signal);
256
+ }, token, progress, limit, options.signal, executionAssetConfig);
250
257
  if (token !== generation)
251
258
  throw new Error('Process terminated');
252
259
  cache.set(key, artifact);
@@ -27,6 +27,7 @@ declare class Clang implements Sandbox {
27
27
  debugRuntimeBaseUrl: string;
28
28
  debugManifestUrl: string;
29
29
  debugManifestReceipt?: Readonly<RuntimeAssetIntegrityEntry>;
30
+ private persistentCache?;
30
31
  private lldbSession?;
31
32
  private runtimeAssetCache;
32
33
  private ownsRuntimeAssetCache;
@@ -39,6 +39,7 @@ class Clang {
39
39
  debugRuntimeBaseUrl = '';
40
40
  debugManifestUrl = '';
41
41
  debugManifestReceipt;
42
+ persistentCache;
42
43
  lldbSession;
43
44
  runtimeAssetCache = new RuntimeAssetCache();
44
45
  ownsRuntimeAssetCache = true;
@@ -91,9 +92,10 @@ class Clang {
91
92
  this.pendingInput = [];
92
93
  this.waitingForInput = false;
93
94
  this.pendingEof = false;
94
- const assetConfig = resolveRuntimeAssetConfig('clang', runtimeAssets, typeof window !== 'undefined' ? window.location.href : '');
95
+ const assetConfig = resolveRuntimeAssetConfig('clang', runtimeAssets, typeof window !== 'undefined' ? window.location.href : '', options.persistentCache);
95
96
  const debugRuntime = resolveDebugRuntimeUrls(runtimeAssets, typeof window !== 'undefined' ? window.location.href : '');
96
97
  this.debugRuntimeBaseUrl = debugRuntime.baseUrl;
98
+ this.persistentCache = assetConfig.persistentCache;
97
99
  this.debugManifestUrl = debugRuntime.manifestUrl;
98
100
  this.debugManifestReceipt = debugRuntime.manifestReceipt;
99
101
  const bundledAssets = shouldStreamBundledClang(assetConfig);
@@ -191,6 +193,10 @@ class Clang {
191
193
  if (!this.worker)
192
194
  return reject('Worker not loaded');
193
195
  const operation = this.workerSession.beginRun(this.worker, reject);
196
+ const persistentCacheOverride = options.persistentCache;
197
+ if (!this.workerSession.isActive(operation))
198
+ return;
199
+ const persistentCache = this.assetBridge?.setExecutionPersistentCache(persistentCacheOverride);
194
200
  const { compileArgs, programArgs } = resolveSandboxExecutionArgs(this.language, args, options);
195
201
  const sourcePath = normalizeLldbSourcePath(options.debugPath || options.activePath, this.language === 'C' ? 'main.c' : 'main.cc');
196
202
  this.lldbBreakpoints.clear();
@@ -228,6 +234,7 @@ class Clang {
228
234
  if (lldbArtifact) {
229
235
  const compilerWorker = this.worker;
230
236
  const lldbSession = new LldbSandboxSession({
237
+ persistentCache: persistentCache ?? this.persistentCache,
231
238
  manifestUrl: this.debugManifestUrl,
232
239
  manifestReceipt: this.debugManifestReceipt,
233
240
  runtimeBaseUrl: this.debugRuntimeBaseUrl,