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.
- package/README.md +52 -5
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -0
- package/dist/playground/assetBridge.d.ts +11 -2
- package/dist/playground/assetBridge.js +190 -46
- package/dist/playground/assets.d.ts +9 -1
- package/dist/playground/assets.js +29 -5
- package/dist/playground/awk.js +1 -0
- package/dist/playground/bash.d.ts +1 -0
- package/dist/playground/bash.js +7 -1
- package/dist/playground/bqn.js +1 -0
- package/dist/playground/bqnPreflight.d.ts +2 -1
- package/dist/playground/bqnPreflight.js +1 -0
- package/dist/playground/c3.js +1 -0
- package/dist/playground/cachedClang.d.ts +10 -0
- package/dist/playground/cachedClang.js +330 -0
- package/dist/playground/clang.d.ts +8 -0
- package/dist/playground/clang.js +47 -8
- package/dist/playground/clangWorkerProtocol.d.ts +57 -0
- package/dist/playground/clangWorkerProtocol.js +11 -0
- package/dist/playground/clojurescript.js +1 -0
- package/dist/playground/clojurescriptPreflight.d.ts +2 -1
- package/dist/playground/clojurescriptPreflight.js +1 -0
- package/dist/playground/compiledArtifactCache.d.ts +21 -0
- package/dist/playground/compiledArtifactCache.js +67 -0
- package/dist/playground/elixir.js +4 -1
- package/dist/playground/forth.js +1 -0
- package/dist/playground/forthPreflight.d.ts +2 -1
- package/dist/playground/forthPreflight.js +1 -0
- package/dist/playground/fortran.js +7 -1
- package/dist/playground/haskell.js +4 -1
- package/dist/playground/haskellAssets.d.ts +2 -1
- package/dist/playground/haskellAssets.js +8 -8
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +2 -2
- package/dist/playground/j.js +1 -0
- package/dist/playground/jPreflight.d.ts +2 -1
- package/dist/playground/jPreflight.js +1 -0
- package/dist/playground/janet.js +1 -0
- package/dist/playground/java.js +20 -8
- package/dist/playground/julia.js +1 -0
- package/dist/playground/lfortranAssets.d.ts +2 -1
- package/dist/playground/lfortranAssets.js +1 -0
- package/dist/playground/lisp.js +4 -1
- package/dist/playground/lispAssets.d.ts +2 -1
- package/dist/playground/lispAssets.js +10 -0
- package/dist/playground/lldbManifest.d.ts +2 -2
- package/dist/playground/lldbManifest.js +17 -3
- package/dist/playground/lldbSession.d.ts +1 -0
- package/dist/playground/lldbSession.js +2 -1
- package/dist/playground/nim.js +1 -0
- package/dist/playground/ocaml.d.ts +1 -0
- package/dist/playground/ocaml.js +12 -1
- package/dist/playground/options.d.ts +2 -0
- package/dist/playground/pascal.js +1 -0
- package/dist/playground/perl.js +1 -0
- package/dist/playground/prolog.js +1 -0
- package/dist/playground/python.d.ts +7 -0
- package/dist/playground/python.js +41 -8
- package/dist/playground/runtimeAssetCache.d.ts +26 -0
- package/dist/playground/runtimeAssetCache.js +84 -0
- package/dist/playground/runtimeSession.d.ts +21 -0
- package/dist/playground/runtimeSession.js +119 -0
- package/dist/playground/rust.d.ts +1 -0
- package/dist/playground/rust.js +11 -1
- package/dist/playground/rustExecutableGraph.d.ts +1 -0
- package/dist/playground/rustExecutableGraph.js +1 -0
- package/dist/playground/staticRuntimePreflight.d.ts +2 -1
- package/dist/playground/staticRuntimePreflight.js +4 -2
- package/dist/playground/staticRuntimePreflightExecute.js +1 -0
- package/dist/playground/staticRuntimePreflightProtocol.d.ts +2 -1
- package/dist/playground/staticWorkerRuntime.d.ts +3 -1
- package/dist/playground/staticWorkerRuntime.js +44 -3
- package/dist/playground/tcl.js +1 -0
- package/dist/playground/tinygo.d.ts +2 -0
- package/dist/playground/tinygo.js +57 -3
- package/dist/playground/tinygoExecutableGraph.d.ts +4 -1
- package/dist/playground/tinygoExecutableGraph.js +59 -7
- package/dist/playground/typescript.js +4 -1
- package/dist/playground/wasmGoVersion.d.ts +1 -1
- package/dist/playground/wasmGoVersion.js +1 -1
- package/dist/playground/wasmOcamlVersion.d.ts +2 -2
- package/dist/playground/wasmOcamlVersion.js +1 -1
- package/dist/playground/wasmRustVersion.d.ts +90 -24
- package/dist/playground/wasmRustVersion.js +98 -23
- package/dist/playground/wasmTinyGoVersion.d.ts +40 -29
- package/dist/playground/wasmTinyGoVersion.js +43 -31
- package/dist/playground/worker/assets.d.ts +3 -0
- package/dist/playground/worker/assets.js +41 -0
- package/dist/playground/worker/cachedClangCompile.d.ts +1 -0
- package/dist/playground/worker/cachedClangCompile.js +85 -0
- package/dist/playground/worker/cachedClangExecute.d.ts +1 -0
- package/dist/playground/worker/cachedClangExecute.js +67 -0
- package/dist/playground/worker/clang.js +2 -8
- package/dist/playground/worker/clangStreaming.d.ts +1 -1
- package/dist/playground/worker/clangStreaming.js +20 -2
- package/dist/playground/worker/elixir.js +10 -8
- package/dist/playground/worker/fortran.js +4 -7
- package/dist/playground/worker/haskell.js +2 -0
- package/dist/playground/worker/lisp.js +2 -0
- package/dist/playground/worker/ocaml.js +13 -1
- package/dist/playground/worker/python.js +3 -2
- package/dist/playground/worker/runtimeAssetFetch.d.ts +11 -1
- package/dist/playground/worker/runtimeAssetFetch.js +64 -1
- package/dist/playground/worker/runtimeModule.d.ts +8 -0
- package/dist/playground/worker/runtimeModule.js +49 -0
- package/dist/playground/worker/rust.js +9 -2
- package/dist/playground/worker/staticRuntimePreflight.js +2 -0
- package/dist/playground/worker/typescript.js +4 -1
- package/dist/playground/worker/zig.js +7 -4
- package/dist/playground/zig.js +4 -1
- package/package.json +10 -7
|
@@ -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
|
|
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) => {
|
package/dist/playground/tcl.js
CHANGED
|
@@ -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
|
|
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 {
|
|
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;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RUNTIME_REGISTRY_MANIFEST_SCHEMA_VERSION, RuntimeConfigurationError, preflightRuntimeAssets } from '@wasm-idle/core';
|
|
2
|
+
import { decompressGzip } from '@wasm-idle/llvm-core';
|
|
2
3
|
export const TINYGO_EXECUTABLE_GRAPH_FORMAT = 'wasm-idle-tinygo-executable-graph-v1';
|
|
3
4
|
export const TINYGO_EXECUTABLE_GRAPH_FINGERPRINT_DOMAIN = 'wasm-idle:tinygo-executable-graph:v1\n';
|
|
4
5
|
const SHA256_PATTERN = /^[a-f0-9]{64}$/u;
|
|
@@ -92,8 +93,16 @@ export function snapshotTinyGoExecutableGraphProfile(value) {
|
|
|
92
93
|
const modules = {};
|
|
93
94
|
for (const rawPath of modulePaths) {
|
|
94
95
|
const modulePath = requireSafePath(rawPath, 'TinyGo executable module path');
|
|
96
|
+
const binary = /^assets\/upstream-binaryen-[a-f0-9]{16}\.wasm\.gz\.bin$/.test(modulePath);
|
|
97
|
+
if (!modulePath.endsWith('.js') && !binary)
|
|
98
|
+
throw configurationError('Unsupported TinyGo graph asset path');
|
|
95
99
|
const sourceModule = requireRecord(sourceModules[rawPath], `TinyGo executable module ${modulePath}`);
|
|
96
|
-
requireExactKeys(sourceModule, [
|
|
100
|
+
requireExactKeys(sourceModule, [
|
|
101
|
+
'bytes',
|
|
102
|
+
'sha256',
|
|
103
|
+
'imports',
|
|
104
|
+
...(binary ? ['uncompressedBytes', 'uncompressedSha256'] : [])
|
|
105
|
+
], `TinyGo executable module ${modulePath}`);
|
|
97
106
|
if (!Number.isSafeInteger(sourceModule.bytes) || Number(sourceModule.bytes) <= 0) {
|
|
98
107
|
throw configurationError(`TinyGo executable module ${modulePath} has an invalid size`);
|
|
99
108
|
}
|
|
@@ -104,6 +113,15 @@ export function snapshotTinyGoExecutableGraphProfile(value) {
|
|
|
104
113
|
throw configurationError(`TinyGo executable module ${modulePath} imports must be an array`);
|
|
105
114
|
}
|
|
106
115
|
const specifiers = new Set();
|
|
116
|
+
if (binary &&
|
|
117
|
+
(sourceModule.imports.length ||
|
|
118
|
+
!Number.isSafeInteger(sourceModule.uncompressedBytes) ||
|
|
119
|
+
Number(sourceModule.uncompressedBytes) < 8 ||
|
|
120
|
+
Number(sourceModule.uncompressedBytes) > 64 * 1024 * 1024 ||
|
|
121
|
+
typeof sourceModule.uncompressedSha256 !== 'string' ||
|
|
122
|
+
!SHA256_PATTERN.test(sourceModule.uncompressedSha256))) {
|
|
123
|
+
throw configurationError('Binaryen Wasm has invalid logical receipts or imports');
|
|
124
|
+
}
|
|
107
125
|
const imports = sourceModule.imports.map((rawImport, index) => {
|
|
108
126
|
const graphImport = requireRecord(rawImport, `TinyGo executable module ${modulePath} import ${index}`);
|
|
109
127
|
requireExactKeys(graphImport, ['specifier', 'target', 'kind'], `TinyGo executable module ${modulePath} import ${index}`);
|
|
@@ -113,12 +131,14 @@ export function snapshotTinyGoExecutableGraphProfile(value) {
|
|
|
113
131
|
throw configurationError(`TinyGo executable module ${modulePath} has an invalid or duplicate import specifier`);
|
|
114
132
|
}
|
|
115
133
|
specifiers.add(specifier);
|
|
116
|
-
if (!['static', 'dynamic', 'worker'].includes(String(graphImport.kind))) {
|
|
134
|
+
if (!['static', 'dynamic', 'worker', 'asset'].includes(String(graphImport.kind))) {
|
|
117
135
|
throw configurationError(`TinyGo executable module ${modulePath} import ${specifier} has an invalid kind`);
|
|
118
136
|
}
|
|
119
137
|
if (resolveImportTarget(modulePath, specifier) !== target) {
|
|
120
138
|
throw configurationError(`TinyGo executable module ${modulePath} import ${specifier} does not resolve to ${target}`);
|
|
121
139
|
}
|
|
140
|
+
if ((graphImport.kind === 'asset') !== target.endsWith('.wasm.gz.bin'))
|
|
141
|
+
throw configurationError('TinyGo graph import kind does not match its target');
|
|
122
142
|
importCount += 1;
|
|
123
143
|
if (importCount > MAX_IMPORTS) {
|
|
124
144
|
throw configurationError(`TinyGo executable graph exceeds ${MAX_IMPORTS} imports`);
|
|
@@ -132,10 +152,16 @@ export function snapshotTinyGoExecutableGraphProfile(value) {
|
|
|
132
152
|
modules[modulePath] = Object.freeze({
|
|
133
153
|
bytes: Number(sourceModule.bytes),
|
|
134
154
|
sha256: sourceModule.sha256,
|
|
155
|
+
...(binary
|
|
156
|
+
? {
|
|
157
|
+
uncompressedBytes: Number(sourceModule.uncompressedBytes),
|
|
158
|
+
uncompressedSha256: sourceModule.uncompressedSha256
|
|
159
|
+
}
|
|
160
|
+
: {}),
|
|
135
161
|
imports: Object.freeze(imports)
|
|
136
162
|
});
|
|
137
163
|
}
|
|
138
|
-
if (!Object.prototype.hasOwnProperty.call(modules, entryPath)) {
|
|
164
|
+
if (!Object.prototype.hasOwnProperty.call(modules, entryPath) || !entryPath.endsWith('.js')) {
|
|
139
165
|
throw configurationError('TinyGo executable graph entry module is missing');
|
|
140
166
|
}
|
|
141
167
|
for (const [modulePath, module] of Object.entries(modules)) {
|
|
@@ -179,6 +205,8 @@ export function canonicalTinyGoExecutableGraphProfile(profile) {
|
|
|
179
205
|
for (const modulePath of paths) {
|
|
180
206
|
const module = profile.modules[modulePath];
|
|
181
207
|
canonical += `module\0${modulePath}\0${module.bytes}\0${module.sha256}\n`;
|
|
208
|
+
if (module.uncompressedBytes !== undefined)
|
|
209
|
+
canonical += `wasm\0${modulePath}\0${module.uncompressedBytes}\0${module.uncompressedSha256}\n`;
|
|
182
210
|
}
|
|
183
211
|
const edges = paths.flatMap((modulePath) => profile.modules[modulePath].imports.map((graphImport) => ({
|
|
184
212
|
importer: modulePath,
|
|
@@ -312,11 +340,15 @@ function createPreflightManifest(profile, keysByPath) {
|
|
|
312
340
|
key: keysByPath[modulePath],
|
|
313
341
|
path: modulePath,
|
|
314
342
|
compressedSha256: receipt.sha256,
|
|
315
|
-
uncompressedSha256: receipt.sha256,
|
|
343
|
+
uncompressedSha256: receipt.uncompressedSha256 ?? receipt.sha256,
|
|
316
344
|
compressedBytes: receipt.bytes,
|
|
317
|
-
uncompressedBytes: receipt.bytes,
|
|
318
|
-
mediaType:
|
|
319
|
-
|
|
345
|
+
uncompressedBytes: receipt.uncompressedBytes ?? receipt.bytes,
|
|
346
|
+
mediaType: receipt.uncompressedBytes !== undefined
|
|
347
|
+
? 'application/wasm'
|
|
348
|
+
: 'text/javascript',
|
|
349
|
+
encoding: receipt.uncompressedBytes !== undefined
|
|
350
|
+
? 'gzip'
|
|
351
|
+
: 'identity'
|
|
320
352
|
};
|
|
321
353
|
}),
|
|
322
354
|
contracts: {
|
|
@@ -357,6 +389,7 @@ export async function loadVerifiedTinyGoExecutableGraph(options) {
|
|
|
357
389
|
if (options.assetTimeoutMs !== undefined)
|
|
358
390
|
limits.assetTimeoutMs = options.assetTimeoutMs;
|
|
359
391
|
const preflight = await preflightRuntimeAssets({
|
|
392
|
+
persistentCache: options.persistentCache,
|
|
360
393
|
manifest: createPreflightManifest(profile, urls.keysByPath),
|
|
361
394
|
runtimeId: 'tinygo/executable-graph',
|
|
362
395
|
rootUrl: urls.baseUrl,
|
|
@@ -378,7 +411,17 @@ export async function loadVerifiedTinyGoExecutableGraph(options) {
|
|
|
378
411
|
: undefined
|
|
379
412
|
});
|
|
380
413
|
const sources = {};
|
|
414
|
+
const binaries = {};
|
|
381
415
|
for (const modulePath of Object.keys(profile.modules)) {
|
|
416
|
+
const receipt = profile.modules[modulePath];
|
|
417
|
+
if (receipt.uncompressedBytes !== undefined) {
|
|
418
|
+
const bytes = await decompressGzip(preflight.assets[urls.keysByPath[modulePath]].bytes, modulePath, receipt.uncompressedBytes, options.signal);
|
|
419
|
+
if (bytes.byteLength !== receipt.uncompressedBytes ||
|
|
420
|
+
(await sha256Hex(bytes, options.signal)) !== receipt.uncompressedSha256)
|
|
421
|
+
throw configurationError('Binaryen Wasm logical receipt mismatch');
|
|
422
|
+
binaries[modulePath] = bytes;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
382
425
|
try {
|
|
383
426
|
sources[modulePath] = fatalDecoder.decode(preflight.assets[urls.keysByPath[modulePath]].bytes);
|
|
384
427
|
}
|
|
@@ -420,6 +463,15 @@ export async function loadVerifiedTinyGoExecutableGraph(options) {
|
|
|
420
463
|
};
|
|
421
464
|
try {
|
|
422
465
|
for (const modulePath of order) {
|
|
466
|
+
if (profile.modules[modulePath].uncompressedBytes !== undefined) {
|
|
467
|
+
const bytes = binaries[modulePath];
|
|
468
|
+
const blobUrl = URL.createObjectURL(new Blob([Uint8Array.from(bytes)], { type: 'application/wasm' }));
|
|
469
|
+
ownedUrls.push(blobUrl);
|
|
470
|
+
if (!SAFE_BLOB_URL_PATTERN.test(blobUrl))
|
|
471
|
+
throw configurationError('TinyGo graph received an unsafe Wasm Blob URL');
|
|
472
|
+
moduleUrls[modulePath] = blobUrl;
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
423
475
|
let source = sources[modulePath];
|
|
424
476
|
for (const graphImport of profile.modules[modulePath].imports) {
|
|
425
477
|
source = replaceUniqueSpecifier(source, graphImport.specifier, moduleUrls[graphImport.target], modulePath);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveTypeScriptModuleUrl } from './assets';
|
|
2
|
-
import { AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, validateExecutionWorkspace } from '@wasm-idle/core';
|
|
2
|
+
import { AssetTooLargeError, BusyError, CancelledError, DEFAULT_WORKSPACE_LIMITS, DiagnosticLimitError, OutputLimitError, RuntimeConfigurationError, TimeoutError, resolveExecutionLimits, resolveRuntimeAssetCacheOptions, validateExecutionWorkspace } from '@wasm-idle/core';
|
|
3
3
|
import {} from './options';
|
|
4
4
|
import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
|
|
5
5
|
import { createWasmIdleSharedBuffer } from './sharedBuffer';
|
|
@@ -477,6 +477,9 @@ class TypeScriptSandbox {
|
|
|
477
477
|
}
|
|
478
478
|
worker.postMessage({
|
|
479
479
|
load: true,
|
|
480
|
+
persistentCache: resolveRuntimeAssetCacheOptions(typeof runtimeAssets === 'object'
|
|
481
|
+
? runtimeAssets?.persistentCache
|
|
482
|
+
: undefined, options.persistentCache),
|
|
480
483
|
moduleUrl: nextModuleUrl,
|
|
481
484
|
moduleReceipt: { ...moduleReceipt },
|
|
482
485
|
maxAssetBytes: limits.maxAssetBytes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const WASM_GO_ASSET_VERSION = "
|
|
1
|
+
export declare const WASM_GO_ASSET_VERSION = "c92a5b9dc0c99663";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const WASM_GO_ASSET_VERSION = '
|
|
1
|
+
export const WASM_GO_ASSET_VERSION = 'c92a5b9dc0c99663';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export declare const WASM_OCAML_ASSET_VERSION = "
|
|
1
|
+
export declare const WASM_OCAML_ASSET_VERSION = "0c26bdcda532857e22b68ae61490c18006d3d58e5a06351e48c6c0dfd439c147";
|
|
2
2
|
export declare const WASM_OCAML_RUNTIME_PROFILE: Readonly<{
|
|
3
|
-
fingerprint: "
|
|
3
|
+
fingerprint: "0c26bdcda532857e22b68ae61490c18006d3d58e5a06351e48c6c0dfd439c147";
|
|
4
4
|
moduleReceipt: Readonly<{
|
|
5
5
|
bytes: 1892;
|
|
6
6
|
sha256: "17d80beb633799e9021dc1b851bc76283494d981ec20fc315462d740284fa13a";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const WASM_OCAML_ASSET_VERSION = '
|
|
1
|
+
export const WASM_OCAML_ASSET_VERSION = '0c26bdcda532857e22b68ae61490c18006d3d58e5a06351e48c6c0dfd439c147';
|
|
2
2
|
export const WASM_OCAML_RUNTIME_PROFILE = Object.freeze({
|
|
3
3
|
fingerprint: WASM_OCAML_ASSET_VERSION,
|
|
4
4
|
moduleReceipt: Object.freeze({
|