wasm-idle 1.0.6 → 1.0.7

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 (93) 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 +70 -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/clojurescript.js +1 -0
  19. package/dist/playground/clojurescriptPreflight.d.ts +2 -1
  20. package/dist/playground/clojurescriptPreflight.js +1 -0
  21. package/dist/playground/elixir.js +4 -1
  22. package/dist/playground/forth.js +1 -0
  23. package/dist/playground/forthPreflight.d.ts +2 -1
  24. package/dist/playground/forthPreflight.js +1 -0
  25. package/dist/playground/fortran.js +7 -1
  26. package/dist/playground/haskell.js +4 -1
  27. package/dist/playground/haskellAssets.d.ts +2 -1
  28. package/dist/playground/haskellAssets.js +8 -8
  29. package/dist/playground/index.d.ts +1 -1
  30. package/dist/playground/index.js +2 -2
  31. package/dist/playground/j.js +1 -0
  32. package/dist/playground/jPreflight.d.ts +2 -1
  33. package/dist/playground/jPreflight.js +1 -0
  34. package/dist/playground/janet.js +1 -0
  35. package/dist/playground/java.js +20 -8
  36. package/dist/playground/julia.js +1 -0
  37. package/dist/playground/lfortranAssets.d.ts +2 -1
  38. package/dist/playground/lfortranAssets.js +1 -0
  39. package/dist/playground/lisp.js +4 -1
  40. package/dist/playground/lispAssets.d.ts +2 -1
  41. package/dist/playground/lispAssets.js +10 -0
  42. package/dist/playground/lldbManifest.d.ts +2 -2
  43. package/dist/playground/lldbManifest.js +17 -3
  44. package/dist/playground/lldbSession.d.ts +1 -0
  45. package/dist/playground/lldbSession.js +2 -1
  46. package/dist/playground/nim.js +1 -0
  47. package/dist/playground/ocaml.d.ts +1 -0
  48. package/dist/playground/ocaml.js +12 -1
  49. package/dist/playground/options.d.ts +2 -0
  50. package/dist/playground/pascal.js +1 -0
  51. package/dist/playground/perl.js +1 -0
  52. package/dist/playground/prolog.js +1 -0
  53. package/dist/playground/python.js +3 -1
  54. package/dist/playground/runtimeSession.d.ts +2 -1
  55. package/dist/playground/runtimeSession.js +2 -2
  56. package/dist/playground/rust.d.ts +1 -0
  57. package/dist/playground/rust.js +11 -1
  58. package/dist/playground/rustExecutableGraph.d.ts +1 -0
  59. package/dist/playground/rustExecutableGraph.js +1 -0
  60. package/dist/playground/staticRuntimePreflight.d.ts +2 -1
  61. package/dist/playground/staticRuntimePreflight.js +4 -2
  62. package/dist/playground/staticRuntimePreflightExecute.js +1 -0
  63. package/dist/playground/staticRuntimePreflightProtocol.d.ts +2 -1
  64. package/dist/playground/staticWorkerRuntime.d.ts +3 -1
  65. package/dist/playground/staticWorkerRuntime.js +44 -3
  66. package/dist/playground/tcl.js +1 -0
  67. package/dist/playground/tinygo.d.ts +2 -0
  68. package/dist/playground/tinygo.js +57 -3
  69. package/dist/playground/tinygoExecutableGraph.d.ts +4 -1
  70. package/dist/playground/tinygoExecutableGraph.js +59 -7
  71. package/dist/playground/typescript.js +4 -1
  72. package/dist/playground/wasmGoVersion.d.ts +1 -1
  73. package/dist/playground/wasmGoVersion.js +1 -1
  74. package/dist/playground/wasmOcamlVersion.d.ts +2 -2
  75. package/dist/playground/wasmOcamlVersion.js +1 -1
  76. package/dist/playground/wasmRustVersion.d.ts +90 -24
  77. package/dist/playground/wasmRustVersion.js +98 -23
  78. package/dist/playground/wasmTinyGoVersion.d.ts +40 -29
  79. package/dist/playground/wasmTinyGoVersion.js +43 -31
  80. package/dist/playground/worker/clang.js +1 -5
  81. package/dist/playground/worker/elixir.js +10 -8
  82. package/dist/playground/worker/fortran.js +4 -7
  83. package/dist/playground/worker/haskell.js +2 -0
  84. package/dist/playground/worker/lisp.js +2 -0
  85. package/dist/playground/worker/ocaml.js +13 -1
  86. package/dist/playground/worker/runtimeAssetFetch.d.ts +11 -1
  87. package/dist/playground/worker/runtimeAssetFetch.js +64 -1
  88. package/dist/playground/worker/rust.js +9 -2
  89. package/dist/playground/worker/staticRuntimePreflight.js +2 -0
  90. package/dist/playground/worker/typescript.js +4 -1
  91. package/dist/playground/worker/zig.js +7 -4
  92. package/dist/playground/zig.js +4 -1
  93. 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.7 / 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.7 / 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.7 | `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.7 | 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.7 | 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';
@@ -379,6 +379,8 @@ export class WorkerAssetBridge {
379
379
  worker;
380
380
  runtime;
381
381
  config;
382
+ persistentCacheBaseline;
383
+ persistentCacheBySignal = new WeakMap();
382
384
  progress;
383
385
  expectedAssets;
384
386
  languageSysroots;
@@ -391,7 +393,8 @@ export class WorkerAssetBridge {
391
393
  this.cache = cache;
392
394
  this.worker = worker;
393
395
  this.runtime = runtime;
394
- this.config = config;
396
+ this.persistentCacheBaseline = resolveRuntimeAssetCacheOptions(config.persistentCache);
397
+ this.config = { ...config, persistentCache: this.persistentCacheBaseline };
395
398
  this.maxAssetBytes = requireBridgeMaxAssetBytes(maxAssetBytes);
396
399
  this.languageSysroots = canUseClangLanguageSysroots(runtime, config, languageSysroots);
397
400
  this.progress = new RuntimeLoadProgress(runtime, this.languageSysroots);
@@ -407,7 +410,17 @@ export class WorkerAssetBridge {
407
410
  this.config.loader === config.loader &&
408
411
  integrityKey(this.config) === integrityKey(config) &&
409
412
  allowedBaseUrlsKey(this.config) === allowedBaseUrlsKey(config) &&
410
- this.config.useAssetBridge === config.useAssetBridge);
413
+ this.config.useAssetBridge === config.useAssetBridge &&
414
+ JSON.stringify(this.persistentCacheBaseline) ===
415
+ JSON.stringify(resolveRuntimeAssetCacheOptions(config.persistentCache)));
416
+ }
417
+ /** Apply one execution's policy without changing the configuration established by load(). */
418
+ setExecutionPersistentCache(override) {
419
+ if (this.state !== 'active')
420
+ throw new Error('Cannot configure an inactive worker asset bridge');
421
+ const cache = resolveRuntimeAssetCacheOptions(this.persistentCacheBaseline, override);
422
+ this.config = { ...this.config, persistentCache: cache };
423
+ return cache;
411
424
  }
412
425
  rebind(worker, config, progress, maxAssetBytes = this.maxAssetBytes, languageSysroots = this.languageSysroots) {
413
426
  if (this.state === 'disposed') {
@@ -430,7 +443,8 @@ export class WorkerAssetBridge {
430
443
  throw new Error('Cannot rebind a disposed worker asset bridge');
431
444
  }
432
445
  this.worker = worker;
433
- this.config = config;
446
+ this.persistentCacheBaseline = resolveRuntimeAssetCacheOptions(config.persistentCache);
447
+ this.config = { ...config, persistentCache: this.persistentCacheBaseline };
434
448
  this.maxAssetBytes = nextMaxAssetBytes;
435
449
  this.languageSysroots = nextLanguageSysroots;
436
450
  this.expectedAssets = expectedAssetsForRuntime(this.runtime, nextLanguageSysroots);
@@ -525,6 +539,7 @@ export class WorkerAssetBridge {
525
539
  const worker = this.worker;
526
540
  const generation = this.generation;
527
541
  const controller = new AbortController();
542
+ this.persistentCacheBySignal.set(controller.signal, resolveRuntimeAssetCacheOptions(this.config.persistentCache));
528
543
  this.activeLoads.add(controller);
529
544
  try {
530
545
  this.validateAssetRequest(request.asset);
@@ -555,6 +570,7 @@ export class WorkerAssetBridge {
555
570
  const receipt = BUNDLED_CLANG_ASSET_INTEGRITY[request.asset];
556
571
  module = await compileVerifiedWasmAsset(new URL(request.asset, this.config.baseUrl).href, receipt, {
557
572
  fetch: globalThis.fetch.bind(globalThis),
573
+ persistentCache: this.persistentCacheBySignal.get(controller.signal),
558
574
  maxAssetBytes: this.maxAssetBytes,
559
575
  signal: controller.signal,
560
576
  onProgress: (loaded, total) => this.progress.update(request.asset, loaded, total)
@@ -831,6 +847,56 @@ export class WorkerAssetBridge {
831
847
  return null;
832
848
  }
833
849
  async fetchAsset(url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(asset)) {
850
+ const requestUrl = this.requireAllowedAssetUrl(asset, url);
851
+ const persistentCache = this.persistentCacheBySignal.get(signal) ?? this.config.persistentCache;
852
+ const configured = this.config.integrity?.[asset];
853
+ const expected = typeof configured === 'string' ? { sha256: configured } : configured;
854
+ const lock = this.config.assetPrefix
855
+ ? resolveRuntimeAssetLockEntry(requestUrl, {
856
+ assetRoot: this.config.baseUrl,
857
+ assetPrefix: this.config.assetPrefix
858
+ })
859
+ : undefined;
860
+ // Existing .gz receipts without a pair describe logical bytes, not stored gzip bytes.
861
+ const receipt = expected && (!asset.endsWith('.gz') || expected.uncompressedSha256) ? expected : lock;
862
+ const identity = receipt
863
+ ? {
864
+ url: requestUrl.href,
865
+ sha256: receipt.sha256,
866
+ bytes: receipt.bytes,
867
+ validationKey: JSON.stringify([
868
+ 'bridge-v1',
869
+ this.config.baseUrl,
870
+ allowedBaseUrlsKey(this.config),
871
+ maxAssetBytes
872
+ ])
873
+ }
874
+ : undefined;
875
+ if (identity && (identity.bytes === undefined || identity.bytes <= maxAssetBytes)) {
876
+ const bytes = await readPersistentRuntimeAsset({
877
+ identity,
878
+ cache: persistentCache,
879
+ signal
880
+ });
881
+ if (bytes) {
882
+ requireRuntimeAssetSize(asset, bytes.byteLength, maxAssetBytes);
883
+ this.progress.update(asset, bytes.byteLength, bytes.byteLength);
884
+ return { bytes, mimeType: receipt?.mediaType, transferOwnership: true };
885
+ }
886
+ }
887
+ const loaded = await this.fetchAssetFromNetwork(url, asset, signal, maxAssetBytes);
888
+ if (identity && !loaded.contentEncoding) {
889
+ // Only checksum-matching bytes are published. Existing runtime validation still runs.
890
+ await writePersistentRuntimeAsset({
891
+ identity,
892
+ cache: persistentCache,
893
+ signal,
894
+ bytes: loaded.bytes
895
+ });
896
+ }
897
+ return loaded;
898
+ }
899
+ async fetchAssetFromNetwork(url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(asset)) {
834
900
  const requestUrl = this.requireAllowedAssetUrl(asset, url);
835
901
  if (signal.aborted)
836
902
  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,
@@ -35,6 +35,7 @@ class ClojureScript 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 { ClojureScriptRuntimePreflightProfile } 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 CLOJURESCRIPT_PREFLIGHT_PROTOCOL: "wasm-idle-clojurescript-preflight";
4
4
  export declare const CLOJURESCRIPT_PREFLIGHT_PROTOCOL_VERSION: 1;
5
5
  export declare const CLOJURESCRIPT_PREFLIGHT_RUNTIME_ID: "CLOJURESCRIPT";
@@ -8,6 +8,7 @@ export interface ClojureScriptRuntimePreflightRequest {
8
8
  readonly manifestUrl: string;
9
9
  readonly profile: ClojureScriptRuntimePreflightProfile;
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;