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
@@ -21,6 +21,8 @@ export interface SandboxWorkspaceFile {
21
21
  content: string;
22
22
  }
23
23
  export interface SandboxExecutionOptions {
24
+ /** Overrides instance/global persistent asset caching for this operation. */
25
+ persistentCache?: import('@wasm-idle/core').RuntimeAssetCacheOptions;
24
26
  debugMode?: BrowserDebugMode;
25
27
  /** @deprecated Use debugMode. true maps to trace unless the caller explicitly selects lldb. */
26
28
  debug?: boolean;
@@ -40,6 +40,7 @@ class Pascal extends StaticWorkerRuntimeSandbox {
40
40
  systemPascalUrl: resolved.systemPascalUrl,
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);
@@ -38,6 +38,7 @@ class Perl 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
  loadedByAsset.set(progress.assetKey, progress.loadedBytes);
@@ -47,6 +47,7 @@ class Prolog extends StaticWorkerRuntimeSandbox {
47
47
  manifestUrl: urls.manifestUrl || '',
48
48
  profile,
49
49
  limits: context.limits,
50
+ persistentCache: context.persistentCache,
50
51
  signal: context.signal,
51
52
  reportProgress(progress) {
52
53
  if (progress.kind === 'asset') {
@@ -205,7 +205,7 @@ class Python {
205
205
  this.pendingInput = [];
206
206
  this.waitingForInput = false;
207
207
  this.pendingEof = false;
208
- const assetConfig = resolveRuntimeAssetConfig('python', runtimeAssets, typeof window !== 'undefined' ? window.location.href : '');
208
+ const assetConfig = resolveRuntimeAssetConfig('python', runtimeAssets, typeof window !== 'undefined' ? window.location.href : '', options.persistentCache);
209
209
  if (!this.isOperationActive(operation))
210
210
  return;
211
211
  const needsWorkerReset = !this.worker ||
@@ -343,11 +343,13 @@ class Python {
343
343
  activePath = options.activePath;
344
344
  debugPath = options.debugPath;
345
345
  workspaceFiles = options.workspaceFiles;
346
+ const persistentCache = options.persistentCache;
346
347
  if (!this.isOperationActive(activeOperation)) {
347
348
  return Promise.reject(this.releaseBeforeSession(activeOperation, 'Python execution cancelled'));
348
349
  }
349
350
  if (debug)
350
351
  requireSharedArrayBuffer('Python debugging');
352
+ this.assetBridge?.setExecutionPersistentCache(persistentCache);
351
353
  this.setBreakpoints(debug ? breakpoints : []);
352
354
  }
353
355
  catch (error) {
@@ -1,3 +1,4 @@
1
+ import { type PlaygroundBindingOptions } from '@wasm-idle/core';
1
2
  import type { PlaygroundBinding, SandboxRuntimeAssets } from './sandbox';
2
3
  import { RuntimeAssetCache } from './runtimeAssetCache';
3
4
  import { CompiledArtifactCache } from './compiledArtifactCache';
@@ -17,4 +18,4 @@ export interface PlaygroundRuntimeSession {
17
18
  * A browser-owned language session. Panels own disposable execution leases, not the
18
19
  * compiler cache. A problem/editor change may release all leases without cooling it.
19
20
  */
20
- export declare function createRuntimeSession(runtimeAssets: SandboxRuntimeAssets): PlaygroundRuntimeSession;
21
+ export declare function createRuntimeSession(runtimeAssets: SandboxRuntimeAssets, options?: PlaygroundBindingOptions): PlaygroundRuntimeSession;
@@ -7,7 +7,7 @@ import { createCachedClangSandbox } from './cachedClang';
7
7
  * A browser-owned language session. Panels own disposable execution leases, not the
8
8
  * compiler cache. A problem/editor change may release all leases without cooling it.
9
9
  */
10
- export function createRuntimeSession(runtimeAssets) {
10
+ export function createRuntimeSession(runtimeAssets, options = {}) {
11
11
  let language;
12
12
  let epoch = 0;
13
13
  let disposed = false;
@@ -86,7 +86,7 @@ export function createRuntimeSession(runtimeAssets) {
86
86
  return target === 'C' || target === 'CPP'
87
87
  ? createCachedClangSandbox(sandbox, target, cache, artifacts)
88
88
  : sandbox;
89
- });
89
+ }, options);
90
90
  leases.add(lease);
91
91
  const binding = core;
92
92
  // Do not override core.dispose in place: the lease calls that exact owner method.
@@ -19,6 +19,7 @@ declare class Rust implements Sandbox {
19
19
  debugManifestUrl: string;
20
20
  debugManifestReceipt?: Readonly<RuntimeAssetIntegrityEntry>;
21
21
  executableGraphFingerprint: string;
22
+ private persistentCacheBaseline?;
22
23
  oncompilerdiagnostic?: (diagnostic: CompilerDiagnostic) => void;
23
24
  waitingForInput: boolean;
24
25
  pendingEof: boolean;
@@ -8,7 +8,7 @@ import { resolveRustNonDebugResourceLimits } from './rustWorkerLimits';
8
8
  import { WASM_RUST_EXECUTABLE_GRAPH_PROFILE, WASM_RUST_RUNTIME_PROFILE } from './wasmRustVersion';
9
9
  import { WorkerSession } from './workerSession';
10
10
  import { reportWorkerInputReady, reportWorkerProgress } from './workerProgress';
11
- import { resolveExecutionLimits, TimeoutError } from '@wasm-idle/core';
11
+ import { resolveExecutionLimits, resolveRuntimeAssetCacheOptions, TimeoutError } from '@wasm-idle/core';
12
12
  const debugBreakpointBufferInts = 1028;
13
13
  const rustLldbSourcePath = '/workspace/main.rs';
14
14
  const outputEncoder = new TextEncoder();
@@ -54,6 +54,7 @@ class Rust {
54
54
  debugManifestUrl = '';
55
55
  debugManifestReceipt;
56
56
  executableGraphFingerprint = '';
57
+ persistentCacheBaseline;
57
58
  oncompilerdiagnostic;
58
59
  waitingForInput = false;
59
60
  pendingEof = false;
@@ -122,6 +123,7 @@ class Rust {
122
123
  let clearCandidateWait = () => { };
123
124
  try {
124
125
  const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
126
+ const persistentCache = resolveRuntimeAssetCacheOptions(typeof runtimeAssets === 'object' ? runtimeAssets.persistentCache : undefined, _options.persistentCache);
125
127
  const nextCompilerUrl = resolveRustCompilerUrl(runtimeAssets, currentUrl);
126
128
  const nextDebugModuleUrl = resolveRustDebugModuleUrl(runtimeAssets, currentUrl);
127
129
  const debugRuntime = resolveDebugRuntimeUrls(runtimeAssets, currentUrl);
@@ -175,6 +177,7 @@ class Rust {
175
177
  this.executableGraphFingerprint !==
176
178
  WASM_RUST_EXECUTABLE_GRAPH_PROFILE.fingerprint;
177
179
  if (!needsWorkerReset) {
180
+ this.persistentCacheBaseline = persistentCache;
178
181
  this.debugRuntimeBaseUrl = nextDebugRuntimeBaseUrl;
179
182
  this.debugManifestUrl = nextDebugManifestUrl;
180
183
  this.debugManifestReceipt = nextDebugManifestReceipt;
@@ -182,6 +185,7 @@ class Rust {
182
185
  return;
183
186
  }
184
187
  nextExecutableGraph = await loadVerifiedRustExecutableGraph({
188
+ persistentCache,
185
189
  moduleUrl: nextCompilerUrl,
186
190
  currentUrl,
187
191
  profile: WASM_RUST_EXECUTABLE_GRAPH_PROFILE,
@@ -255,6 +259,7 @@ class Rust {
255
259
  };
256
260
  candidateWorker.postMessage({
257
261
  load: true,
262
+ persistentCache,
258
263
  compilerUrl: nextExecutableGraph.entryUrl,
259
264
  debugModuleUrl: nextDebugModuleUrl,
260
265
  path: nextAssetPath,
@@ -274,6 +279,7 @@ class Rust {
274
279
  this.waitingForInput = false;
275
280
  this.pendingEof = false;
276
281
  this.compilerUrl = nextCompilerUrl;
282
+ this.persistentCacheBaseline = persistentCache;
277
283
  this.debugModuleUrl = nextDebugModuleUrl;
278
284
  this.assetPath = nextAssetPath;
279
285
  this.debugRuntimeBaseUrl = nextDebugRuntimeBaseUrl;
@@ -360,7 +366,9 @@ class Rust {
360
366
  }
361
367
  let limits;
362
368
  let nonDebugResourceLimits;
369
+ let persistentCache;
363
370
  try {
371
+ persistentCache = resolveRuntimeAssetCacheOptions(this.persistentCacheBaseline, options.persistentCache);
364
372
  limits = resolveExecutionLimits(options.limits);
365
373
  nonDebugResourceLimits =
366
374
  debugMode === 'none' ? resolveRustNonDebugResourceLimits(limits) : undefined;
@@ -567,6 +575,7 @@ class Rust {
567
575
  startPhaseTimeout('run', limits.runTimeoutMs);
568
576
  const compilerWorker = this.worker;
569
577
  const lldbSession = new LldbSandboxSession({
578
+ persistentCache,
570
579
  manifestUrl: this.debugManifestUrl,
571
580
  manifestReceipt: this.debugManifestReceipt,
572
581
  runtimeBaseUrl: this.debugRuntimeBaseUrl,
@@ -671,6 +680,7 @@ class Rust {
671
680
  this.begin = Date.now();
672
681
  try {
673
682
  this.worker.postMessage({
683
+ persistentCache,
674
684
  code,
675
685
  prepare,
676
686
  buffer: this.buffer,
@@ -70,6 +70,7 @@ export interface RustExecutableGraphProgress {
70
70
  readonly totalBytes: number;
71
71
  }
72
72
  export interface LoadRustExecutableGraphOptions {
73
+ readonly persistentCache?: import('@wasm-idle/core').RuntimeAssetCacheOptions;
73
74
  readonly moduleUrl: string;
74
75
  readonly currentUrl?: string;
75
76
  readonly profile: unknown;
@@ -822,6 +822,7 @@ export async function loadVerifiedRustExecutableGraph(options) {
822
822
  if (options.assetTimeoutMs !== undefined)
823
823
  limits.assetTimeoutMs = options.assetTimeoutMs;
824
824
  const preflight = await preflightRuntimeAssets({
825
+ persistentCache: options.persistentCache,
825
826
  manifest: createPreflightManifest(profile, sourceContext.keysByPath),
826
827
  runtimeId: 'rust/executable-graph',
827
828
  rootUrl: sourceContext.storageRootUrl,
@@ -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 StaticRuntimePreflightProgress, type StaticRuntimePreflightRuntimeId } from './staticRuntimePreflightProtocol';
3
3
  export interface StaticRuntimeWorkerPreflightRequest {
4
4
  readonly runtimeId: StaticRuntimePreflightRuntimeId;
@@ -7,6 +7,7 @@ export interface StaticRuntimeWorkerPreflightRequest {
7
7
  readonly manifestUrl: string;
8
8
  readonly profile: unknown;
9
9
  readonly limits?: Partial<ExecutionLimits>;
10
+ readonly persistentCache?: RuntimeAssetCacheOptions;
10
11
  readonly signal?: AbortSignal;
11
12
  readonly reportProgress?: (progress: StaticRuntimePreflightProgress) => void;
12
13
  }
@@ -1,8 +1,9 @@
1
- import { CancelledError, ProtocolError, TimeoutError, WorkerStartupError, resolveExecutionLimits } from '@wasm-idle/core';
1
+ import { CancelledError, ProtocolError, TimeoutError, WorkerStartupError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions } from '@wasm-idle/core';
2
2
  import { STATIC_RUNTIME_PREFLIGHT_PROTOCOL_VERSION, collectStaticRuntimePreflightTransferables, deserializeStaticRuntimePreflightError, isStaticRuntimePreflightProgress, isStaticRuntimePreflightSerializedError } from './staticRuntimePreflightProtocol';
3
3
  const REQUEST_ID = 1;
4
4
  export async function preflightStaticRuntimeAssetsInWorker(request) {
5
5
  const limits = resolveExecutionLimits(request.limits);
6
+ const persistentCache = resolveRuntimeAssetCacheOptions(request.persistentCache);
6
7
  if (request.signal?.aborted) {
7
8
  throw new CancelledError(`${request.displayName} runtime preflight cancelled`, {
8
9
  cause: request.signal.reason,
@@ -210,7 +211,8 @@ export async function preflightStaticRuntimeAssetsInWorker(request) {
210
211
  baseUrl: request.baseUrl,
211
212
  manifestUrl: request.manifestUrl,
212
213
  profile: request.profile,
213
- limits
214
+ limits,
215
+ persistentCache
214
216
  });
215
217
  }
216
218
  catch (error) {
@@ -8,6 +8,7 @@ export async function executeStaticRuntimePreflight(request, reportProgress, sig
8
8
  baseUrl: request.baseUrl,
9
9
  manifestUrl: request.manifestUrl,
10
10
  limits: request.limits,
11
+ persistentCache: request.persistentCache,
11
12
  signal,
12
13
  reportProgress: (progress) => reportProgress({ kind: 'asset', progress })
13
14
  };
@@ -1,4 +1,4 @@
1
- import { type ExecutionLimits, type RuntimeAssetPreflightProgress, type RuntimeErrorCode, type RuntimePhase, type RuntimeResourceKind } from '@wasm-idle/core';
1
+ import { type ExecutionLimits, type RuntimeAssetCacheOptions, type RuntimeAssetPreflightProgress, type RuntimeErrorCode, type RuntimePhase, type RuntimeResourceKind } from '@wasm-idle/core';
2
2
  export declare const STATIC_RUNTIME_PREFLIGHT_PROTOCOL_VERSION: 1;
3
3
  export type StaticRuntimePreflightRuntimeId = 'BQN' | 'CLOJURESCRIPT' | 'FORTH' | 'J' | 'JANET' | 'PROLOG';
4
4
  export type StaticRuntimePreflightProgress = {
@@ -19,6 +19,7 @@ export interface StaticRuntimePreflightRequestMessage {
19
19
  readonly manifestUrl: string;
20
20
  readonly profile: unknown;
21
21
  readonly limits: ExecutionLimits;
22
+ readonly persistentCache?: RuntimeAssetCacheOptions;
22
23
  }
23
24
  export interface StaticRuntimePreflightProgressMessage {
24
25
  readonly protocolVersion: typeof STATIC_RUNTIME_PREFLIGHT_PROTOCOL_VERSION;
@@ -1,5 +1,5 @@
1
1
  import type { PlaygroundRuntimeAssets } from './assets';
2
- import { type ExecutionLimits, type RuntimeAssetIntegrityEntry, type RuntimeStdinMode, type RuntimeWorkerLifetimePolicy } from '@wasm-idle/core';
2
+ import { type ExecutionLimits, type RuntimeAssetIntegrityEntry, type RuntimeAssetCacheOptions, type RuntimeStdinMode, type RuntimeWorkerLifetimePolicy } from '@wasm-idle/core';
3
3
  import { type CompilerDiagnostic, type SandboxExecutionOptions } from './options';
4
4
  import type { Sandbox, SandboxProgress } from './sandbox';
5
5
  type StaticWorkerReceipt = Readonly<Required<Pick<RuntimeAssetIntegrityEntry, 'bytes' | 'sha256'>>>;
@@ -14,6 +14,7 @@ export interface StaticWorkerRuntimeUrls {
14
14
  }
15
15
  export interface StaticWorkerRuntimePreflightContext {
16
16
  readonly limits: ExecutionLimits;
17
+ readonly persistentCache?: RuntimeAssetCacheOptions;
17
18
  readonly signal?: AbortSignal;
18
19
  readonly reportProgress: (value: number, stage?: string) => void;
19
20
  /**
@@ -85,6 +86,7 @@ export declare class StaticWorkerRuntimeSandbox implements Sandbox {
85
86
  private disposePromise;
86
87
  private disposeReason;
87
88
  private lifecycleProgress?;
89
+ private persistentCache?;
88
90
  private readonly progressController;
89
91
  private progressUid;
90
92
  private startingRunId;
@@ -1,4 +1,4 @@
1
- import { AssetNotFoundError, AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, ProtocolError, RuntimeConfigurationError, RuntimeExecutionError, RuntimeProgressController, RuntimeWorkerLifetimeController, TimeoutError, WorkerStartupError, isWasmIdleError, resolveExecutionLimits, validateExecutionWorkspace, verifyRuntimeAssetIntegrity } from '@wasm-idle/core';
1
+ import { AssetNotFoundError, AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, ProtocolError, RuntimeConfigurationError, RuntimeExecutionError, RuntimeProgressController, RuntimeWorkerLifetimeController, TimeoutError, WorkerStartupError, isWasmIdleError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, readPersistentRuntimeAsset, writePersistentRuntimeAsset, validateExecutionWorkspace, verifyRuntimeAssetIntegrity } from '@wasm-idle/core';
2
2
  import { resolveSandboxExecutionArgs } from './options';
3
3
  import { StaticStdinRingHost } from './staticStdinRing';
4
4
  import { deserializeStaticRuntimePreflightError, isStaticRuntimePreflightSerializedError, inspectStaticRuntimePreflightBytes } from './staticRuntimePreflightProtocol';
@@ -39,6 +39,7 @@ export class StaticWorkerRuntimeSandbox {
39
39
  disposePromise = null;
40
40
  disposeReason = null;
41
41
  lifecycleProgress;
42
+ persistentCache;
42
43
  progressController = new RuntimeProgressController();
43
44
  progressUid = 0;
44
45
  startingRunId = null;
@@ -134,7 +135,8 @@ export class StaticWorkerRuntimeSandbox {
134
135
  async load(runtimeAssets = '', code = '', _log = true, _args = [], options = {}, progress) {
135
136
  this.assertNotDisposed();
136
137
  try {
137
- const controls = this.resolveExecutionControls(options);
138
+ const persistentCache = typeof runtimeAssets === 'string' ? undefined : runtimeAssets.persistentCache;
139
+ const controls = this.resolveExecutionControls(options, persistentCache ?? {});
138
140
  this.assertOperationNotDisposed();
139
141
  if (controls.signal?.aborted) {
140
142
  throw new CancelledError(`${this.config.displayName} startup cancelled`, {
@@ -149,6 +151,7 @@ export class StaticWorkerRuntimeSandbox {
149
151
  const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
150
152
  const urls = this.config.resolveRuntimeAssets(runtimeAssets, currentUrl);
151
153
  this.assertOperationNotDisposed();
154
+ this.persistentCache = persistentCache;
152
155
  const nextManifestUrl = urls.manifestUrl || '';
153
156
  const nextManifestFingerprint = urls.manifestFingerprint || '';
154
157
  const nextPreflightKey = urls.preflightKey || '';
@@ -304,9 +307,10 @@ export class StaticWorkerRuntimeSandbox {
304
307
  beginProgressLifecycle(progress, stage) {
305
308
  return this.progressController.begin(`${this.config.languageId.toLowerCase()}-${++this.progressUid}`, progress, stage);
306
309
  }
307
- resolveExecutionControls(options) {
310
+ resolveExecutionControls(options, persistentCache = this.persistentCache) {
308
311
  return {
309
312
  limits: resolveExecutionLimits(options.limits),
313
+ persistentCache: resolveRuntimeAssetCacheOptions(persistentCache, options.persistentCache),
310
314
  ...(options.signal ? { signal: options.signal } : {})
311
315
  };
312
316
  }
@@ -400,6 +404,17 @@ export class StaticWorkerRuntimeSandbox {
400
404
  if (workerRequestUrl.hash) {
401
405
  throw new RuntimeConfigurationError(`${this.config.displayName} worker script URL must not include a fragment`, { runtimeId: this.config.languageId });
402
406
  }
407
+ const persistentIdentity = workerReceipt
408
+ ? {
409
+ url: workerRequestUrl.href,
410
+ sha256: workerReceipt.sha256,
411
+ bytes: workerReceipt.bytes,
412
+ validationKey: JSON.stringify([
413
+ 'static-worker-v1',
414
+ this.config.requireExactWorkerResponseUrl === true
415
+ ])
416
+ }
417
+ : undefined;
403
418
  const phaseController = new AbortController();
404
419
  let timedOut = false;
405
420
  const onAbort = () => phaseController.abort(signal?.reason);
@@ -414,6 +429,18 @@ export class StaticWorkerRuntimeSandbox {
414
429
  throw (phaseController.signal.reason ??
415
430
  new DOMException('Worker script fetch aborted', 'AbortError'));
416
431
  }
432
+ if (persistentIdentity && workerReceipt) {
433
+ const cached = await readPersistentRuntimeAsset({
434
+ identity: persistentIdentity,
435
+ cache: controls.persistentCache,
436
+ signal: phaseController.signal
437
+ });
438
+ if (cached) {
439
+ await this.verifyWorkerReceipt(cached, workerReceipt, phaseController.signal);
440
+ this.reportProgress(progress, 0.2, `${this.config.displayName} worker cached`);
441
+ return Uint8Array.from(cached);
442
+ }
443
+ }
417
444
  const pendingResponse = Promise.resolve(fetch(workerRequestUrl.href, {
418
445
  cache: this.config.inlineVerifiedWorker ? 'no-store' : 'force-cache',
419
446
  credentials: 'omit',
@@ -531,6 +558,12 @@ export class StaticWorkerRuntimeSandbox {
531
558
  const bytes = new Uint8Array(buffer);
532
559
  if (workerReceipt) {
533
560
  await this.verifyWorkerReceipt(bytes, workerReceipt, phaseController.signal);
561
+ await writePersistentRuntimeAsset({
562
+ identity: persistentIdentity,
563
+ cache: controls.persistentCache,
564
+ signal: phaseController.signal,
565
+ bytes
566
+ });
534
567
  return bytes;
535
568
  }
536
569
  return undefined;
@@ -641,6 +674,12 @@ export class StaticWorkerRuntimeSandbox {
641
674
  offset += chunk.byteLength;
642
675
  }
643
676
  await this.verifyWorkerReceipt(bytes, workerReceipt, phaseController.signal);
677
+ await writePersistentRuntimeAsset({
678
+ identity: persistentIdentity,
679
+ cache: controls.persistentCache,
680
+ signal: phaseController.signal,
681
+ bytes
682
+ });
644
683
  return bytes;
645
684
  }
646
685
  return undefined;
@@ -856,6 +895,7 @@ self.postMessage = (message, transferOrOptions) => {
856
895
  progress,
857
896
  controls: {
858
897
  limits: controls.limits,
898
+ persistentCache: controls.persistentCache,
859
899
  signal: startAbortController.signal
860
900
  }
861
901
  };
@@ -916,6 +956,7 @@ self.postMessage = (message, transferOrOptions) => {
916
956
  try {
917
957
  runtimePreflight = await this.config.preflightRuntimeAssets(urls, {
918
958
  limits: controls.limits,
959
+ persistentCache: controls.persistentCache,
919
960
  signal: controls.signal,
920
961
  reportProgress: (value, stage) => this.reportProgress(progress, value, stage),
921
962
  createOwnedDelivery: (payload) => {
@@ -39,6 +39,7 @@ class Tcl extends StaticWorkerRuntimeSandbox {
39
39
  manifestUrl: urls.manifestUrl || '',
40
40
  profile,
41
41
  limits: context.limits,
42
+ persistentCache: context.persistentCache,
42
43
  signal: context.signal,
43
44
  reportProgress(progress) {
44
45
  loadedByAsset.set(progress.assetKey, progress.loadedBytes);
@@ -46,6 +46,8 @@ declare class TinyGo implements Sandbox {
46
46
  rustRuntimeBaseUrl: string;
47
47
  oncompilerdiagnostic?: (diagnostic: CompilerDiagnostic) => void;
48
48
  assetLoader: TinyGoRuntimeAssetLoader | undefined;
49
+ private persistentCache?;
50
+ private persistentCacheBaseline?;
49
51
  runtimeProfile: TinyGoUpstreamRuntimeProfile | undefined;
50
52
  executableGraph: LoadedTinyGoExecutableGraph | null;
51
53
  runtime: TinyGoRuntimeHooks | null;
@@ -5,7 +5,7 @@ import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinB
5
5
  import { createWasmIdleSharedBuffer } from './sharedBuffer';
6
6
  import { WorkerSession } from './workerSession';
7
7
  import { reportWorkerProgress } from './workerProgress';
8
- import { BusyError, CancelledError, DEFAULT_EXECUTION_LIMITS, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, WorkspaceValidationError, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
8
+ import { BusyError, CancelledError, DEFAULT_EXECUTION_LIMITS, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, WorkspaceValidationError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, fetchPinnedRuntimeAsset, validateExecutionWorkspace } from '@wasm-idle/core';
9
9
  const ACTIVITY_PREFIX_PATTERN = /^\[\d{2}:\d{2}:\d{2}\]\s?/gm;
10
10
  const MAX_TIMER_DELAY_MS = 2_147_483_647;
11
11
  const TINYGO_BROWSER_COMPILER_DEFAULT_MAX_WASM_MEMORY_BYTES = 2 * 1024 * 1024 * 1024;
@@ -73,6 +73,8 @@ class TinyGo {
73
73
  rustRuntimeBaseUrl = '';
74
74
  oncompilerdiagnostic;
75
75
  assetLoader = undefined;
76
+ persistentCache;
77
+ persistentCacheBaseline;
76
78
  runtimeProfile = undefined;
77
79
  executableGraph = null;
78
80
  runtime = null;
@@ -117,8 +119,11 @@ class TinyGo {
117
119
  }
118
120
  load(runtimeAssets = '', _code = '', _log = true, _args = [], options = {}, progress) {
119
121
  return this.executeOperation('startup', options, async (operation) => {
122
+ const persistentCache = resolveRuntimeAssetCacheOptions(typeof runtimeAssets === 'object' ? runtimeAssets.persistentCache : undefined, options.persistentCache);
120
123
  try {
121
124
  this.assertOperation(operation);
125
+ this.persistentCacheBaseline = persistentCache;
126
+ this.persistentCache = persistentCache;
122
127
  this.clearPendingStdin();
123
128
  const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
124
129
  this.assertOperation(operation);
@@ -692,6 +697,7 @@ class TinyGo {
692
697
  });
693
698
  }
694
699
  nextExecutableGraph = await loadVerifiedTinyGoExecutableGraph({
700
+ persistentCache: this.persistentCache,
695
701
  moduleUrl,
696
702
  profile: WASM_TINYGO_EXECUTABLE_GRAPH_PROFILE,
697
703
  signal: operation.controller.signal,
@@ -700,6 +706,42 @@ class TinyGo {
700
706
  });
701
707
  this.assertOperation(operation);
702
708
  const executableGraph = nextExecutableGraph;
709
+ // The upstream loader owns gzip fallback and logical-byte verification.
710
+ // Preserve raw .wasm probes; cache only exact profile-pinned transport URLs.
711
+ const transportReceipts = new Map();
712
+ for (const [path, receipt] of [
713
+ [runtimeProfile.manifestPath, runtimeProfile.manifestReceipt],
714
+ ...Object.entries(runtimeProfile.assetReceipts)
715
+ ]) {
716
+ const transportPath = receipt.uncompressedSha256 ? `${path}.gz` : path;
717
+ transportReceipts.set(new URL(transportPath, executableGraph.assetBaseUrl).href, receipt);
718
+ }
719
+ const pinnedFetch = async (input, init) => {
720
+ const url = typeof input === 'string'
721
+ ? input
722
+ : input instanceof URL
723
+ ? input.href
724
+ : input.url;
725
+ const receipt = transportReceipts.get(url);
726
+ if (!receipt)
727
+ return globalThis.fetch(input, init);
728
+ const owner = this.activeOperation;
729
+ if (!owner)
730
+ throw new Error('TinyGo asset load has no active operation');
731
+ this.assertOperation(owner);
732
+ const bytes = await fetchPinnedRuntimeAsset({
733
+ url,
734
+ receipt,
735
+ persistentCache: this.persistentCache,
736
+ maxAssetBytes: owner.limits?.maxAssetBytes ?? maxAssetBytes,
737
+ signal: init?.signal ?? owner.controller.signal
738
+ });
739
+ this.assertOperation(owner);
740
+ // This is a verified byte adapter, not a network response with a fabricated URL.
741
+ return new Response(Uint8Array.from(bytes).buffer, {
742
+ headers: { 'Content-Length': String(bytes.byteLength) }
743
+ });
744
+ };
703
745
  const runtimeModule = (await import(
704
746
  /* @vite-ignore */ executableGraph.entryUrl));
705
747
  this.assertOperation(operation);
@@ -762,7 +804,9 @@ class TinyGo {
762
804
  assetsPromise = loadUpstreamAssets({
763
805
  assetBaseUrl: executableGraph.assetBaseUrl,
764
806
  profile: runtimeProfile,
765
- ...(assetLoader ? { loader: assetLoader } : {}),
807
+ ...(assetLoader
808
+ ? { loader: assetLoader }
809
+ : { fetchImpl: pinnedFetch }),
766
810
  onProgress: commonOptions.onProgress,
767
811
  signal: controller.signal,
768
812
  maxAssetBytes: assetLimit
@@ -1051,6 +1095,7 @@ class TinyGo {
1051
1095
  }
1052
1096
  run(code, prepare, _log = true, _prog, args = [], options = {}) {
1053
1097
  return this.executeOperation('execute', options, async (operation, request) => {
1098
+ this.persistentCache = request.persistentCache;
1054
1099
  this.exit = false;
1055
1100
  try {
1056
1101
  this.begin = Date.now();
@@ -1155,6 +1200,8 @@ class TinyGo {
1155
1200
  throw error;
1156
1201
  }
1157
1202
  }, (operation) => {
1203
+ this.assertOperation(operation);
1204
+ const persistentCache = resolveRuntimeAssetCacheOptions(this.persistentCacheBaseline, options.persistentCache);
1158
1205
  this.assertOperation(operation);
1159
1206
  if (typeof code !== 'string') {
1160
1207
  throw new TypeError('TinyGo source code must be a string');
@@ -1281,7 +1328,14 @@ class TinyGo {
1281
1328
  const buffer = this.buffer;
1282
1329
  this.assertOperation(operation);
1283
1330
  operation.buffer = buffer;
1284
- return { buffer, programArgs, stdin, target, workspaceFiles: runtimeWorkspace };
1331
+ return {
1332
+ buffer,
1333
+ programArgs,
1334
+ stdin,
1335
+ target,
1336
+ workspaceFiles: runtimeWorkspace,
1337
+ persistentCache
1338
+ };
1285
1339
  });
1286
1340
  }
1287
1341
  resetOwnedBuffers(operationBuffer) {
@@ -1,6 +1,6 @@
1
1
  export declare const TINYGO_EXECUTABLE_GRAPH_FORMAT: "wasm-idle-tinygo-executable-graph-v1";
2
2
  export declare const TINYGO_EXECUTABLE_GRAPH_FINGERPRINT_DOMAIN: "wasm-idle:tinygo-executable-graph:v1\n";
3
- export type TinyGoExecutableImportKind = 'static' | 'dynamic' | 'worker';
3
+ export type TinyGoExecutableImportKind = 'static' | 'dynamic' | 'worker' | 'asset';
4
4
  export interface TinyGoExecutableGraphImport {
5
5
  readonly specifier: string;
6
6
  readonly target: string;
@@ -9,6 +9,8 @@ export interface TinyGoExecutableGraphImport {
9
9
  export interface TinyGoExecutableGraphModule {
10
10
  readonly bytes: number;
11
11
  readonly sha256: string;
12
+ readonly uncompressedBytes?: number;
13
+ readonly uncompressedSha256?: string;
12
14
  readonly imports: readonly TinyGoExecutableGraphImport[];
13
15
  }
14
16
  export interface TinyGoExecutableGraphProfile {
@@ -30,6 +32,7 @@ export interface TinyGoExecutableGraphProgress {
30
32
  readonly totalBytes: number;
31
33
  }
32
34
  export interface LoadTinyGoExecutableGraphOptions {
35
+ readonly persistentCache?: import('@wasm-idle/core').RuntimeAssetCacheOptions;
33
36
  readonly moduleUrl: string;
34
37
  readonly currentUrl?: string;
35
38
  readonly profile: unknown;