wasm-idle 1.0.5 → 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 (112) hide show
  1. package/README.md +52 -5
  2. package/dist/index.d.ts +4 -1
  3. package/dist/index.js +2 -0
  4. package/dist/playground/assetBridge.d.ts +11 -2
  5. package/dist/playground/assetBridge.js +190 -46
  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.d.ts +10 -0
  16. package/dist/playground/cachedClang.js +330 -0
  17. package/dist/playground/clang.d.ts +8 -0
  18. package/dist/playground/clang.js +47 -8
  19. package/dist/playground/clangWorkerProtocol.d.ts +57 -0
  20. package/dist/playground/clangWorkerProtocol.js +11 -0
  21. package/dist/playground/clojurescript.js +1 -0
  22. package/dist/playground/clojurescriptPreflight.d.ts +2 -1
  23. package/dist/playground/clojurescriptPreflight.js +1 -0
  24. package/dist/playground/compiledArtifactCache.d.ts +21 -0
  25. package/dist/playground/compiledArtifactCache.js +67 -0
  26. package/dist/playground/elixir.js +4 -1
  27. package/dist/playground/forth.js +1 -0
  28. package/dist/playground/forthPreflight.d.ts +2 -1
  29. package/dist/playground/forthPreflight.js +1 -0
  30. package/dist/playground/fortran.js +7 -1
  31. package/dist/playground/haskell.js +4 -1
  32. package/dist/playground/haskellAssets.d.ts +2 -1
  33. package/dist/playground/haskellAssets.js +8 -8
  34. package/dist/playground/index.d.ts +1 -1
  35. package/dist/playground/index.js +2 -2
  36. package/dist/playground/j.js +1 -0
  37. package/dist/playground/jPreflight.d.ts +2 -1
  38. package/dist/playground/jPreflight.js +1 -0
  39. package/dist/playground/janet.js +1 -0
  40. package/dist/playground/java.js +20 -8
  41. package/dist/playground/julia.js +1 -0
  42. package/dist/playground/lfortranAssets.d.ts +2 -1
  43. package/dist/playground/lfortranAssets.js +1 -0
  44. package/dist/playground/lisp.js +4 -1
  45. package/dist/playground/lispAssets.d.ts +2 -1
  46. package/dist/playground/lispAssets.js +10 -0
  47. package/dist/playground/lldbManifest.d.ts +2 -2
  48. package/dist/playground/lldbManifest.js +17 -3
  49. package/dist/playground/lldbSession.d.ts +1 -0
  50. package/dist/playground/lldbSession.js +2 -1
  51. package/dist/playground/nim.js +1 -0
  52. package/dist/playground/ocaml.d.ts +1 -0
  53. package/dist/playground/ocaml.js +12 -1
  54. package/dist/playground/options.d.ts +2 -0
  55. package/dist/playground/pascal.js +1 -0
  56. package/dist/playground/perl.js +1 -0
  57. package/dist/playground/prolog.js +1 -0
  58. package/dist/playground/python.d.ts +7 -0
  59. package/dist/playground/python.js +41 -8
  60. package/dist/playground/runtimeAssetCache.d.ts +26 -0
  61. package/dist/playground/runtimeAssetCache.js +84 -0
  62. package/dist/playground/runtimeSession.d.ts +21 -0
  63. package/dist/playground/runtimeSession.js +119 -0
  64. package/dist/playground/rust.d.ts +1 -0
  65. package/dist/playground/rust.js +11 -1
  66. package/dist/playground/rustExecutableGraph.d.ts +1 -0
  67. package/dist/playground/rustExecutableGraph.js +1 -0
  68. package/dist/playground/staticRuntimePreflight.d.ts +2 -1
  69. package/dist/playground/staticRuntimePreflight.js +4 -2
  70. package/dist/playground/staticRuntimePreflightExecute.js +1 -0
  71. package/dist/playground/staticRuntimePreflightProtocol.d.ts +2 -1
  72. package/dist/playground/staticWorkerRuntime.d.ts +3 -1
  73. package/dist/playground/staticWorkerRuntime.js +44 -3
  74. package/dist/playground/tcl.js +1 -0
  75. package/dist/playground/tinygo.d.ts +2 -0
  76. package/dist/playground/tinygo.js +57 -3
  77. package/dist/playground/tinygoExecutableGraph.d.ts +4 -1
  78. package/dist/playground/tinygoExecutableGraph.js +59 -7
  79. package/dist/playground/typescript.js +4 -1
  80. package/dist/playground/wasmGoVersion.d.ts +1 -1
  81. package/dist/playground/wasmGoVersion.js +1 -1
  82. package/dist/playground/wasmOcamlVersion.d.ts +2 -2
  83. package/dist/playground/wasmOcamlVersion.js +1 -1
  84. package/dist/playground/wasmRustVersion.d.ts +90 -24
  85. package/dist/playground/wasmRustVersion.js +98 -23
  86. package/dist/playground/wasmTinyGoVersion.d.ts +40 -29
  87. package/dist/playground/wasmTinyGoVersion.js +43 -31
  88. package/dist/playground/worker/assets.d.ts +3 -0
  89. package/dist/playground/worker/assets.js +41 -0
  90. package/dist/playground/worker/cachedClangCompile.d.ts +1 -0
  91. package/dist/playground/worker/cachedClangCompile.js +85 -0
  92. package/dist/playground/worker/cachedClangExecute.d.ts +1 -0
  93. package/dist/playground/worker/cachedClangExecute.js +67 -0
  94. package/dist/playground/worker/clang.js +2 -8
  95. package/dist/playground/worker/clangStreaming.d.ts +1 -1
  96. package/dist/playground/worker/clangStreaming.js +20 -2
  97. package/dist/playground/worker/elixir.js +10 -8
  98. package/dist/playground/worker/fortran.js +4 -7
  99. package/dist/playground/worker/haskell.js +2 -0
  100. package/dist/playground/worker/lisp.js +2 -0
  101. package/dist/playground/worker/ocaml.js +13 -1
  102. package/dist/playground/worker/python.js +3 -2
  103. package/dist/playground/worker/runtimeAssetFetch.d.ts +11 -1
  104. package/dist/playground/worker/runtimeAssetFetch.js +64 -1
  105. package/dist/playground/worker/runtimeModule.d.ts +8 -0
  106. package/dist/playground/worker/runtimeModule.js +49 -0
  107. package/dist/playground/worker/rust.js +9 -2
  108. package/dist/playground/worker/staticRuntimePreflight.js +2 -0
  109. package/dist/playground/worker/typescript.js +4 -1
  110. package/dist/playground/worker/zig.js +7 -4
  111. package/dist/playground/zig.js +4 -1
  112. package/package.json +10 -7
@@ -219,6 +219,7 @@ export async function preflightClojureScriptRuntimeAssets(request) {
219
219
  compiler: compilerRequestUrl
220
220
  },
221
221
  fetch: request.fetch,
222
+ persistentCache: request.persistentCache,
222
223
  signal: controller.signal,
223
224
  limits: { ...limits, maxAssetBytes },
224
225
  maxConcurrentDownloads: 2,
@@ -0,0 +1,21 @@
1
+ import type { BrowserClangArtifact, BrowserClangCompileRequest } from '@wasm-idle/llvm-core/clang';
2
+ /** Only immutable compiler output lives here, never a worker, instance, or filesystem. */
3
+ export declare class CompiledArtifactCache {
4
+ private entries;
5
+ private bytes;
6
+ private hits;
7
+ private misses;
8
+ private maxEntries;
9
+ private maxBytes;
10
+ constructor(maxEntries?: number, maxBytes?: number);
11
+ get(key: string): BrowserClangArtifact | undefined;
12
+ set(key: string, artifact: BrowserClangArtifact): void;
13
+ clear(): void;
14
+ stats(): {
15
+ hits: number;
16
+ misses: number;
17
+ entries: number;
18
+ bytes: number;
19
+ };
20
+ }
21
+ export declare function clangCompileKey(runtimeBaseUrl: string, maxAssetBytes: number, request: BrowserClangCompileRequest, languageSysroots?: boolean): string;
@@ -0,0 +1,67 @@
1
+ /** Only immutable compiler output lives here, never a worker, instance, or filesystem. */
2
+ export class CompiledArtifactCache {
3
+ entries = new Map();
4
+ bytes = 0;
5
+ hits = 0;
6
+ misses = 0;
7
+ maxEntries;
8
+ maxBytes;
9
+ constructor(maxEntries = 8, maxBytes = 32 * 1024 * 1024) {
10
+ this.maxEntries = maxEntries;
11
+ this.maxBytes = maxBytes;
12
+ }
13
+ get(key) {
14
+ const entry = this.entries.get(key);
15
+ if (!entry) {
16
+ this.misses++;
17
+ return undefined;
18
+ }
19
+ this.hits++;
20
+ this.entries.delete(key);
21
+ this.entries.set(key, entry);
22
+ return entry.artifact;
23
+ }
24
+ set(key, artifact) {
25
+ const size = artifact.bytes.byteLength + key.length * 2;
26
+ if (size > this.maxBytes)
27
+ return;
28
+ const old = this.entries.get(key);
29
+ if (old)
30
+ this.bytes -= old.size;
31
+ this.entries.delete(key);
32
+ this.entries.set(key, { artifact, size });
33
+ this.bytes += size;
34
+ while (this.entries.size > this.maxEntries || this.bytes > this.maxBytes) {
35
+ const oldest = this.entries.keys().next().value;
36
+ this.bytes -= this.entries.get(oldest).size;
37
+ this.entries.delete(oldest);
38
+ }
39
+ }
40
+ clear() {
41
+ this.entries.clear();
42
+ this.bytes = 0;
43
+ }
44
+ stats() {
45
+ return {
46
+ hits: this.hits,
47
+ misses: this.misses,
48
+ entries: this.entries.size,
49
+ bytes: this.bytes
50
+ };
51
+ }
52
+ }
53
+ export function clangCompileKey(runtimeBaseUrl, maxAssetBytes, request, languageSysroots = false) {
54
+ return JSON.stringify([
55
+ 'wasm-idle/clang-cache-v2',
56
+ runtimeBaseUrl,
57
+ maxAssetBytes,
58
+ languageSysroots,
59
+ request.language,
60
+ request.code,
61
+ request.activePath,
62
+ request.compileArgs,
63
+ request.cVersion,
64
+ request.cppVersion,
65
+ [...(request.workspaceFiles || [])].sort((a, b) => a.path.localeCompare(b.path))
66
+ ]);
67
+ }
@@ -1,6 +1,6 @@
1
1
  import { resolveElixirBundleUrl, resolveErlangBundleUrl } from './assets';
2
2
  import { snapshotElixirRuntimeAssetReceipts } from './elixirAssets';
3
- import { AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
3
+ import { AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, validateExecutionWorkspace } from '@wasm-idle/core';
4
4
  import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
5
5
  import { createWasmIdleSharedBuffer } from './sharedBuffer';
6
6
  import { WorkerSession } from './workerSession';
@@ -285,6 +285,9 @@ class Elixir {
285
285
  worker.onmessage = handler;
286
286
  worker.postMessage({
287
287
  load: true,
288
+ persistentCache: resolveRuntimeAssetCacheOptions(typeof runtimeAssets === 'object'
289
+ ? runtimeAssets?.persistentCache
290
+ : undefined, options.persistentCache),
288
291
  bundleUrl: this.bundleUrl,
289
292
  assetReceipts,
290
293
  maxAssetBytes: limits.maxAssetBytes,
@@ -35,6 +35,7 @@ class Forth 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 { ForthRuntimePreflightProfile } 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 FORTH_PREFLIGHT_PROTOCOL: "wasm-idle-forth-preflight";
4
4
  export declare const FORTH_PREFLIGHT_PROTOCOL_VERSION: 1;
5
5
  export declare const FORTH_PREFLIGHT_RUNTIME_ID: "FORTH";
@@ -8,6 +8,7 @@ export interface ForthRuntimePreflightRequest {
8
8
  readonly manifestUrl: string;
9
9
  readonly profile: ForthRuntimePreflightProfile;
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;
@@ -172,6 +172,7 @@ export async function preflightForthRuntimeAssets(request) {
172
172
  runtime: runtimeRequestUrl
173
173
  },
174
174
  fetch: request.fetch,
175
+ persistentCache: request.persistentCache,
175
176
  signal: request.signal,
176
177
  limits: request.limits,
177
178
  maxConcurrentDownloads: 2,
@@ -1,6 +1,6 @@
1
1
  import { WorkerAssetBridge } from './assetBridge';
2
2
  import { resolveFortranRuntimeAssetConfig, resolveRuntimeAssetConfig } from './assets';
3
- import { AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
3
+ import { AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, validateExecutionWorkspace } from '@wasm-idle/core';
4
4
  import { FORTRAN_EXECUTION_ASSET_NAMES } from './fortranAssets';
5
5
  import { resolveSandboxExecutionArgs } from './options';
6
6
  import { createWasmIdleSharedBuffer } from './sharedBuffer';
@@ -288,6 +288,7 @@ class Fortran {
288
288
  let assetBridge;
289
289
  try {
290
290
  assetBridge = new WorkerAssetBridge(worker, 'clang', clangAssets, progress, limits.maxAssetBytes);
291
+ assetBridge.setExecutionPersistentCache(options.persistentCache);
291
292
  }
292
293
  catch (error) {
293
294
  try {
@@ -353,6 +354,9 @@ class Fortran {
353
354
  worker.onmessage = handler;
354
355
  worker.postMessage({
355
356
  load: true,
357
+ persistentCache: resolveRuntimeAssetCacheOptions(typeof runtimeAssets === 'object'
358
+ ? runtimeAssets?.persistentCache
359
+ : undefined, options.persistentCache),
356
360
  log,
357
361
  code,
358
362
  args,
@@ -373,6 +377,7 @@ class Fortran {
373
377
  if (!assetBridge)
374
378
  return rejectOperation('Fortran asset bridge is not loaded');
375
379
  assetBridge.rebind(worker, clangAssets, progress, limits.maxAssetBytes);
380
+ assetBridge.setExecutionPersistentCache(options.persistentCache);
376
381
  if (!this.isOperationActive(operation) ||
377
382
  this.worker !== worker ||
378
383
  this.assetBridge !== assetBridge) {
@@ -444,6 +449,7 @@ class Fortran {
444
449
  const assetBridge = this.assetBridge;
445
450
  if (!assetBridge)
446
451
  throw 'Fortran asset bridge is not loaded';
452
+ assetBridge.setExecutionPersistentCache(options.persistentCache);
447
453
  const hasExplicitStdin = stdin !== undefined;
448
454
  if (hasExplicitStdin) {
449
455
  activeOperation.explicitStdin = true;
@@ -1,5 +1,5 @@
1
1
  import { resolveHaskellBsdtarUrl, resolveHaskellModuleUrl, resolveHaskellRootfsUrl } from './assets';
2
- import { BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, snapshotHaskellRuntimeAssetReceipts, validateExecutionWorkspace } from '@wasm-idle/core';
2
+ import { BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, snapshotHaskellRuntimeAssetReceipts, validateExecutionWorkspace } from '@wasm-idle/core';
3
3
  import { resolveSandboxExecutionArgs } from './options';
4
4
  import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
5
5
  import { createWasmIdleSharedBuffer } from './sharedBuffer';
@@ -367,6 +367,9 @@ class Haskell {
367
367
  worker.onmessage = handler;
368
368
  worker.postMessage({
369
369
  load: true,
370
+ persistentCache: resolveRuntimeAssetCacheOptions(typeof runtimeAssets === 'object'
371
+ ? runtimeAssets?.persistentCache
372
+ : undefined, options.persistentCache),
370
373
  ...runtime,
371
374
  log: _log
372
375
  });
@@ -1,4 +1,4 @@
1
- import { type HaskellRuntimeAssetName, type HaskellRuntimeAssetReceipt, type HaskellRuntimeAssetReceipts } from '@wasm-idle/core';
1
+ import { type RuntimeAssetCacheOptions, type HaskellRuntimeAssetName, type HaskellRuntimeAssetReceipt, type HaskellRuntimeAssetReceipts } from '@wasm-idle/core';
2
2
  export type { HaskellRuntimeAssetReceipt, HaskellRuntimeAssetReceipts };
3
3
  export interface HaskellRuntimeAssetConfig {
4
4
  readonly moduleUrl: string;
@@ -15,6 +15,7 @@ export interface HaskellRuntimeAssetProgress {
15
15
  export declare function snapshotHaskellRuntimeAssetConfig(config: HaskellRuntimeAssetConfig): HaskellRuntimeAssetConfig;
16
16
  export declare function loadVerifiedHaskellRuntimeAssets(config: HaskellRuntimeAssetConfig, options?: {
17
17
  readonly signal?: AbortSignal;
18
+ readonly persistentCache?: RuntimeAssetCacheOptions;
18
19
  readonly onProgress?: (progress: HaskellRuntimeAssetProgress) => void;
19
20
  }): Promise<Readonly<{
20
21
  config: HaskellRuntimeAssetConfig;
@@ -51,20 +51,20 @@ export async function loadVerifiedHaskellRuntimeAssets(config, options = {}) {
51
51
  ? 'Haskell GHC rootfs'
52
52
  : 'Haskell rootfs extractor',
53
53
  cache: 'no-store',
54
+ expected: receipt,
55
+ verify: (bytes) => verifyRuntimeAssetIntegrity({
56
+ asset,
57
+ bytes,
58
+ expected: receipt,
59
+ runtimeId: 'HASKELL'
60
+ }),
61
+ persistentCache: options.persistentCache,
54
62
  maxAssetBytes: Math.min(receipt.bytes, snapshot.maxAssetBytes),
55
63
  signal: controller.signal,
56
64
  onProgress(progress) {
57
65
  options.onProgress?.({ asset, ...progress });
58
66
  }
59
67
  });
60
- if (controller.signal.aborted)
61
- throw controller.signal.reason;
62
- await verifyRuntimeAssetIntegrity({
63
- asset,
64
- bytes,
65
- expected: receipt,
66
- runtimeId: 'HASKELL'
67
- });
68
68
  if (controller.signal.aborted)
69
69
  throw controller.signal.reason;
70
70
  return bytes;
@@ -3,5 +3,5 @@ import { type PlaygroundBindingOptions } from '@wasm-idle/core';
3
3
  export declare const supportedLanguages: ("C" | "CPP" | "OBJC" | "D" | "TINYGO" | "RUBY" | "PERL" | "TCL" | "AWK" | "PASCAL" | "JANET" | "JULIA" | "NIM" | "BASH" | "BQN" | "CLOJURESCRIPT" | "FORTH" | "J" | "PROLOG" | "C3" | "PYTHON3" | "JAVA" | "RUST" | "GO" | "CSHARP" | "FSHARP" | "VBNET" | "ELIXIR" | "ERLANG" | "GLEAM" | "FORTRAN" | "LFORTRAN" | "COBOL" | "OCAML" | "JAVASCRIPT" | "TYPESCRIPT" | "ASSEMBLYSCRIPT" | "WAT" | "WASM" | "LUA" | "ZIG" | "LISP" | "HASKELL" | "R" | "OCTAVE" | "DUCKDB" | "SQLITE" | "PHP")[];
4
4
  export declare function createPlaygroundBinding(runtimeAssets: SandboxRuntimeAssets, options?: PlaygroundBindingOptions): PlaygroundBinding;
5
5
  declare function playground(language: string): Promise<Sandbox>;
6
- declare function playground(language: string, runtimeAssets: SandboxRuntimeAssets): Promise<BoundSandbox>;
6
+ declare function playground(language: string, runtimeAssets: SandboxRuntimeAssets, options?: PlaygroundBindingOptions): Promise<BoundSandbox>;
7
7
  export default playground;
@@ -353,7 +353,7 @@ export const supportedLanguages = [...supportedLanguageIds];
353
353
  export function createPlaygroundBinding(runtimeAssets, options = {}) {
354
354
  return createCorePlaygroundBinding(runtimeAssets, playground, options);
355
355
  }
356
- async function playground(language, runtimeAssets) {
356
+ async function playground(language, runtimeAssets, options = {}) {
357
357
  const normalizedLanguage = normalizeLanguageId(language);
358
358
  if (!isSupportedLanguageId(normalizedLanguage)) {
359
359
  throw new Error(`Unsupported language: ${language}`);
@@ -362,7 +362,7 @@ async function playground(language, runtimeAssets) {
362
362
  if (!route)
363
363
  throw new Error(`Missing sandbox route: ${normalizedLanguage}`);
364
364
  return runtimeAssets
365
- ? createPlaygroundBinding(runtimeAssets).load(normalizedLanguage)
365
+ ? createPlaygroundBinding(runtimeAssets, options).load(normalizedLanguage)
366
366
  : route.load();
367
367
  }
368
368
  export default playground;
@@ -38,6 +38,7 @@ class J extends StaticWorkerRuntimeSandbox {
38
38
  manifestUrl: urls.manifestUrl || '',
39
39
  profile,
40
40
  limits: context.limits,
41
+ persistentCache: context.persistentCache,
41
42
  signal: context.signal,
42
43
  reportProgress(progress) {
43
44
  if (progress.kind === 'asset') {
@@ -1,5 +1,5 @@
1
1
  import type { JRuntimePreflightProfile } 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 J_PREFLIGHT_PROTOCOL: "wasm-idle-j-preflight";
4
4
  export declare const J_PREFLIGHT_PROTOCOL_VERSION: 1;
5
5
  export declare const J_PREFLIGHT_RUNTIME_ID: "J";
@@ -8,6 +8,7 @@ export interface JRuntimePreflightRequest {
8
8
  readonly manifestUrl: string;
9
9
  readonly profile: JRuntimePreflightProfile;
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 preflightJRuntimeAssets(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,
@@ -40,6 +40,7 @@ class Janet extends StaticWorkerRuntimeSandbox {
40
40
  manifestUrl: urls.manifestUrl || '',
41
41
  profile,
42
42
  limits: context.limits,
43
+ persistentCache: context.persistentCache,
43
44
  signal: context.signal,
44
45
  reportProgress(progress) {
45
46
  if (progress.kind === 'asset') {
@@ -285,10 +285,16 @@ class Java {
285
285
  let resolverAssets = runtimeAssets;
286
286
  if (runtimeAssets && typeof runtimeAssets === 'object') {
287
287
  const runtimeConfig = runtimeAssets.java;
288
+ if (!this.isOperationActive(activeOperation))
289
+ return;
290
+ const persistentCache = runtimeAssets.persistentCache;
288
291
  if (!this.isOperationActive(activeOperation))
289
292
  return;
290
293
  let java;
291
294
  if (runtimeConfig) {
295
+ const persistentCache = runtimeConfig.persistentCache;
296
+ if (!this.isOperationActive(activeOperation))
297
+ return;
292
298
  const baseUrl = runtimeConfig.baseUrl;
293
299
  if (!this.isOperationActive(activeOperation))
294
300
  return;
@@ -352,7 +358,7 @@ class Java {
352
358
  : undefined;
353
359
  if (!this.isOperationActive(activeOperation))
354
360
  return;
355
- java = { baseUrl, loader, integrity, allowedBaseUrls };
361
+ java = { baseUrl, loader, integrity, allowedBaseUrls, persistentCache };
356
362
  }
357
363
  let rootUrl;
358
364
  let rootUrlRead = false;
@@ -367,10 +373,11 @@ class Java {
367
373
  }
368
374
  return rootUrl;
369
375
  },
370
- java
376
+ java,
377
+ persistentCache
371
378
  };
372
379
  }
373
- const assetConfig = resolveRuntimeAssetConfig('java', resolverAssets, currentUrl);
380
+ const assetConfig = resolveRuntimeAssetConfig('java', resolverAssets, currentUrl, options.persistentCache);
374
381
  if (!this.isOperationActive(activeOperation))
375
382
  return;
376
383
  for (const asset of TEAVM_RUNTIME_ASSET_NAMES) {
@@ -449,11 +456,14 @@ class Java {
449
456
  baseUrl: assetConfig.baseUrl,
450
457
  useAssetBridge: assetConfig.useAssetBridge,
451
458
  maxAssetBytes: limits.maxAssetBytes,
452
- streamCompiler: !assetConfig.loader && TEAVM_RUNTIME_ASSET_NAMES.every((asset) => {
453
- const receipt = assetConfig.integrity?.[asset];
454
- const expected = TEAVM_RUNTIME_ASSET_RECEIPTS[asset];
455
- return typeof receipt === 'object' && receipt.bytes === expected.bytes && receipt.sha256 === expected.sha256;
456
- })
459
+ streamCompiler: !assetConfig.loader &&
460
+ TEAVM_RUNTIME_ASSET_NAMES.every((asset) => {
461
+ const receipt = assetConfig.integrity?.[asset];
462
+ const expected = TEAVM_RUNTIME_ASSET_RECEIPTS[asset];
463
+ return (typeof receipt === 'object' &&
464
+ receipt.bytes === expected.bytes &&
465
+ receipt.sha256 === expected.sha256);
466
+ })
457
467
  }
458
468
  });
459
469
  }
@@ -556,9 +566,11 @@ class Java {
556
566
  maxTotalBytes: Math.min(workspaceLimits.maxTotalBytes ?? DEFAULT_WORKSPACE_LIMITS.maxTotalBytes, limits.maxWorkspaceBytes)
557
567
  });
558
568
  stdin = options.stdin;
569
+ const persistentCache = options.persistentCache;
559
570
  if (!this.isOperationActive(activeOperation) || signal?.aborted) {
560
571
  return Promise.reject(this.releaseBeforeSession(activeOperation, 'Java execution cancelled'));
561
572
  }
573
+ assetBridge?.setExecutionPersistentCache(persistentCache);
562
574
  unbindPreSessionAbort();
563
575
  }
564
576
  catch (error) {
@@ -40,6 +40,7 @@ class Julia extends StaticWorkerRuntimeSandbox {
40
40
  manifestUrl: urls.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);
@@ -1,4 +1,4 @@
1
- import { type ExecutionLimits } from '@wasm-idle/core';
1
+ import { type ExecutionLimits, type RuntimeAssetCacheOptions } from '@wasm-idle/core';
2
2
  import type { PlaygroundRuntimeAssets } from './assets';
3
3
  export declare const LFORTRAN_INITIAL_MEMORY_BYTES: number;
4
4
  export declare const LFORTRAN_RUNTIME_MANIFEST: import("@wasm-idle/core").RuntimeRegistryManifest;
@@ -13,6 +13,7 @@ export declare function resolveLfortranRuntimeAssetConfig(assets: string | Playg
13
13
  };
14
14
  export declare function preflightLfortranRuntimeAssets(baseUrl: string, options: {
15
15
  limits: ExecutionLimits;
16
+ persistentCache?: RuntimeAssetCacheOptions;
16
17
  signal?: AbortSignal;
17
18
  reportProgress?: (value: number, stage: string) => void;
18
19
  fetch?: typeof globalThis.fetch;
@@ -100,6 +100,7 @@ export async function preflightLfortranRuntimeAssets(baseUrl, options) {
100
100
  new URL(`${name === 'lfortran.data' ? 'lfortran.data.bin' : name}?v=${asset.sha256}`, baseUrl)
101
101
  ])),
102
102
  limits: options.limits,
103
+ persistentCache: options.persistentCache,
103
104
  signal: options.signal,
104
105
  fetch: options.fetch,
105
106
  redirect: 'error',
@@ -1,5 +1,5 @@
1
1
  import { resolveLispRuntimeAssetConfig } from './assets';
2
- import { BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
2
+ import { BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, validateExecutionWorkspace } from '@wasm-idle/core';
3
3
  import { resolveSandboxExecutionArgs } from './options';
4
4
  import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
5
5
  import { createWasmIdleSharedBuffer } from './sharedBuffer';
@@ -329,6 +329,9 @@ class Lisp {
329
329
  worker.onmessage = handler;
330
330
  worker.postMessage({
331
331
  load: true,
332
+ persistentCache: resolveRuntimeAssetCacheOptions(typeof runtimeAssets === 'object'
333
+ ? runtimeAssets?.persistentCache
334
+ : undefined, options.persistentCache),
332
335
  runtimeConfig: nextRuntimeConfig,
333
336
  maxAssetBytes: limits.maxAssetBytes
334
337
  });
@@ -1,6 +1,7 @@
1
- import { type LispRuntimeModuleEnvironment, type VerifiedLispRuntime } from '@wasm-idle/core';
1
+ import { type RuntimeAssetCacheOptions, type LispRuntimeModuleEnvironment, type VerifiedLispRuntime } from '@wasm-idle/core';
2
2
  import type { ResolvedLispRuntimeAssetConfig } from './assets';
3
3
  export interface LoadVerifiedLispRuntimeAssetsOptions {
4
+ persistentCache?: RuntimeAssetCacheOptions;
4
5
  signal?: AbortSignal;
5
6
  maxAssetBytes?: number;
6
7
  moduleEnvironment?: LispRuntimeModuleEnvironment;
@@ -41,6 +41,8 @@ export async function loadVerifiedLispRuntimeAssets(config, options = {}) {
41
41
  url: manifestUrl.href,
42
42
  label: 'Lisp runtime manifest',
43
43
  cache: 'no-cache',
44
+ expected: config.manifestReceipt,
45
+ persistentCache: options.persistentCache,
44
46
  maxAssetBytes: Math.min(MAX_LISP_MANIFEST_BYTES, maxAssetBytes),
45
47
  signal: options.signal
46
48
  });
@@ -63,6 +65,14 @@ export async function loadVerifiedLispRuntimeAssets(config, options = {}) {
63
65
  url: assetUrl.href,
64
66
  label: `Lisp runtime asset ${asset.logicalPath}`,
65
67
  cache: 'force-cache',
68
+ expected: {
69
+ sha256: asset.sha256,
70
+ bytes: asset.size,
71
+ uncompressedSha256: logicalAsset.sha256,
72
+ uncompressedBytes: logicalAsset.size
73
+ },
74
+ persistentCache: options.persistentCache,
75
+ integrityContext: { asset: asset.logicalPath, runtimeId: 'LISP' },
66
76
  maxAssetBytes: Math.min(maxAssetBytes, Math.max(asset.size, logicalAsset.size)),
67
77
  signal
68
78
  });
@@ -1,3 +1,3 @@
1
- import { type RuntimeAssetIntegrityEntry } from '@wasm-idle/core';
1
+ import { type RuntimeAssetCacheOptions, type RuntimeAssetIntegrityEntry } from '@wasm-idle/core';
2
2
  import { type RuntimeManifestV2 } from '@wasm-idle/llvm-core/debug';
3
- export declare function loadVerifiedDebugRuntimeManifest(url: string, expected: Readonly<RuntimeAssetIntegrityEntry> | undefined, fetchImpl: typeof fetch, signal?: AbortSignal): Promise<RuntimeManifestV2>;
3
+ export declare function loadVerifiedDebugRuntimeManifest(url: string, expected: Readonly<RuntimeAssetIntegrityEntry> | undefined, fetchImpl: typeof fetch, signal?: AbortSignal, persistentCache?: RuntimeAssetCacheOptions): Promise<RuntimeManifestV2>;
@@ -1,4 +1,4 @@
1
- import { AssetIntegrityError, AssetTooLargeError, RuntimeConfigurationError, verifyRuntimeAssetIntegrity } from '@wasm-idle/core';
1
+ import { AssetIntegrityError, AssetTooLargeError, RuntimeConfigurationError, verifyRuntimeAssetIntegrity, readPersistentRuntimeAsset, resolveRuntimeAssetCacheOptions, writePersistentRuntimeAsset } from '@wasm-idle/core';
2
2
  import { parseDebugRuntimeManifest } from '@wasm-idle/llvm-core/debug';
3
3
  const MAX_DEBUG_MANIFEST_BYTES = 64 * 1024;
4
4
  function abortReason(signal) {
@@ -16,7 +16,7 @@ async function cancelResponseBody(response, reason) {
16
16
  // Preserve the validation or lifecycle failure that initiated cancellation.
17
17
  }
18
18
  }
19
- export async function loadVerifiedDebugRuntimeManifest(url, expected, fetchImpl, signal) {
19
+ export async function loadVerifiedDebugRuntimeManifest(url, expected, fetchImpl, signal, persistentCache) {
20
20
  if (!expected || !/^[a-f0-9]{64}$/u.test(expected.sha256)) {
21
21
  throw new RuntimeConfigurationError('LLDB runtime requires an expected manifest SHA-256 receipt.');
22
22
  }
@@ -37,6 +37,18 @@ export async function loadVerifiedDebugRuntimeManifest(url, expected, fetchImpl,
37
37
  ...(expected.bytes === undefined ? {} : { bytes: expected.bytes })
38
38
  });
39
39
  throwIfAborted(signal);
40
+ const policy = resolveRuntimeAssetCacheOptions(persistentCache);
41
+ const cache = {
42
+ ...policy,
43
+ maxEntryBytes: Math.min(policy.maxEntryBytes, MAX_DEBUG_MANIFEST_BYTES)
44
+ };
45
+ const identity = { url, ...receipt, validationKey: 'lldb-manifest-v1' };
46
+ const cached = await readPersistentRuntimeAsset({ identity, cache, signal });
47
+ if (cached) {
48
+ if (cached.byteLength > MAX_DEBUG_MANIFEST_BYTES)
49
+ throw new Error('Cached LLDB manifest exceeds size limit');
50
+ return parseDebugRuntimeManifest(JSON.parse(new TextDecoder().decode(cached)));
51
+ }
40
52
  const response = await fetchImpl(url, { cache: 'no-store', signal });
41
53
  if (!response.ok) {
42
54
  const error = new Error(`Unable to load the LLDB runtime manifest (${response.status}).`);
@@ -151,5 +163,7 @@ export async function loadVerifiedDebugRuntimeManifest(url, expected, fetchImpl,
151
163
  runtimeId: 'wasm-debug',
152
164
  profileId: 'lldb-v2'
153
165
  });
154
- return parseDebugRuntimeManifest(JSON.parse(new TextDecoder().decode(bytes)));
166
+ const manifest = parseDebugRuntimeManifest(JSON.parse(new TextDecoder().decode(bytes)));
167
+ await writePersistentRuntimeAsset({ identity, cache, signal, bytes });
168
+ return manifest;
155
169
  }
@@ -19,6 +19,7 @@ export interface LldbArtifactPayload {
19
19
  }>;
20
20
  }
21
21
  export interface LldbSandboxSessionOptions {
22
+ persistentCache?: import('@wasm-idle/core').RuntimeAssetCacheOptions;
22
23
  manifestUrl: string;
23
24
  manifestReceipt?: Readonly<RuntimeAssetIntegrityEntry>;
24
25
  runtimeBaseUrl: string;
@@ -184,7 +184,7 @@ export class LldbSandboxSession {
184
184
  }
185
185
  let manifest;
186
186
  try {
187
- manifest = await loadVerifiedDebugRuntimeManifest(this.options.manifestUrl, this.options.manifestReceipt, this.options.fetchImpl ?? fetch, startupAbortController.signal);
187
+ manifest = await loadVerifiedDebugRuntimeManifest(this.options.manifestUrl, this.options.manifestReceipt, this.options.fetchImpl ?? fetch, startupAbortController.signal, this.options.persistentCache);
188
188
  }
189
189
  catch (error) {
190
190
  if (lifecycleVersion !== this.lifecycleVersion)
@@ -223,6 +223,7 @@ export class LldbSandboxSession {
223
223
  }));
224
224
  const configuredBreakpointVersion = this.breakpointVersion;
225
225
  session = createBrowserLldbSession({
226
+ persistentCache: this.options.persistentCache,
226
227
  manifest,
227
228
  runtimeBaseUrl: this.options.runtimeBaseUrl,
228
229
  module: this.options.artifact.bytes,
@@ -52,6 +52,7 @@ class Nim extends StaticWorkerRuntimeSandbox {
52
52
  manifestUrl: urls.manifestUrl || '',
53
53
  profile,
54
54
  limits: context.limits,
55
+ persistentCache: context.persistentCache,
55
56
  signal: context.signal,
56
57
  reportProgress(progress) {
57
58
  loadedByAsset.set(progress.assetKey, progress.loadedBytes);
@@ -15,6 +15,7 @@ declare class Ocaml implements Sandbox {
15
15
  private moduleReceiptIdentity;
16
16
  private manifestReceiptIdentity;
17
17
  private maxAssetBytes;
18
+ private persistentCache;
18
19
  oncompilerdiagnostic?: (diagnostic: CompilerDiagnostic) => void;
19
20
  waitingForInput: boolean;
20
21
  pendingEof: boolean;