wasm-idle 1.0.9 → 1.0.11
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 +34 -25
- package/dist/playground/assetBridge.d.ts +1 -1
- package/dist/playground/assetBridge.js +172 -117
- package/dist/playground/assets.d.ts +4 -4
- package/dist/playground/assets.js +129 -286
- package/dist/playground/cachedClang.js +1 -0
- package/dist/playground/clang.js +5 -1
- package/dist/playground/clangWorkerProtocol.d.ts +1 -0
- package/dist/playground/dotnet.js +1 -1
- package/dist/playground/elixir.js +2 -2
- package/dist/playground/fennel.js +1 -1
- package/dist/playground/go.js +1 -1
- package/dist/playground/haskell.js +1 -1
- package/dist/playground/lua.js +1 -1
- package/dist/playground/r.js +1 -1
- package/dist/playground/runtimeAssetCache.d.ts +6 -0
- package/dist/playground/runtimeAssetCache.js +109 -0
- package/dist/playground/rust.js +1 -1
- package/dist/playground/staticRuntimeModuleVersion.d.ts +1 -1
- package/dist/playground/staticRuntimeModuleVersion.js +1 -1
- package/dist/playground/tinygo.js +1 -1
- package/dist/playground/typescript.js +1 -1
- package/dist/playground/wasmBashVersion.d.ts +25 -25
- package/dist/playground/wasmBashVersion.js +12 -12
- package/dist/playground/wasmElixirVersion.d.ts +9 -9
- package/dist/playground/wasmElixirVersion.js +9 -9
- package/dist/playground/wasmHaskellVersion.d.ts +1 -1
- package/dist/playground/wasmHaskellVersion.js +1 -1
- package/dist/playground/wasmLispVersion.d.ts +1 -1
- package/dist/playground/wasmLispVersion.js +1 -1
- package/dist/playground/wasmOcamlVersion.d.ts +4 -4
- package/dist/playground/wasmOcamlVersion.js +3 -3
- package/dist/playground/wasmPrologVersion.d.ts +19 -19
- package/dist/playground/wasmPrologVersion.js +18 -18
- package/dist/playground/wasmTypeScriptVersion.d.ts +5 -5
- package/dist/playground/wasmTypeScriptVersion.js +5 -5
- package/dist/playground/wat.js +1 -1
- package/dist/playground/worker/cachedClangCompile.js +7 -1
- package/dist/playground/worker/clang.js +13 -8
- package/dist/playground/worker/clangStreaming.js +6 -0
- package/dist/playground/worker/elixir.js +1 -1
- package/dist/playground/worker/go.js +1 -1
- package/dist/playground/worker/haskell.js +1 -1
- package/dist/playground/worker/lua.js +1 -1
- package/dist/playground/worker/python.js +7 -3
- package/dist/playground/worker/r.js +1 -1
- package/dist/playground/worker/runtimeModule.d.ts +1 -1
- package/dist/playground/worker/runtimeModule.js +1 -1
- package/dist/playground/worker/rust.js +1 -1
- package/dist/playground/worker/typescript.js +1 -1
- package/dist/playground/worker/wat.js +1 -1
- package/dist/playground/worker/zig.js +1 -1
- package/dist/playground/zig.js +1 -1
- package/package.json +47 -47
|
@@ -225,9 +225,13 @@ class RuntimeLoadProgress {
|
|
|
225
225
|
progress;
|
|
226
226
|
lockedTotal;
|
|
227
227
|
measurementInvalid = false;
|
|
228
|
-
constructor(runtime, languageSysroots = false) {
|
|
228
|
+
constructor(runtime, languageSysroots = false, clangdHeaders = false) {
|
|
229
229
|
this.expectedAssets = expectedAssetsForRuntime(runtime);
|
|
230
230
|
this.optionalAssets = new Set();
|
|
231
|
+
if (runtime === 'clangd' && !clangdHeaders) {
|
|
232
|
+
this.expectedAssets.delete('clangd.headers.json.gz');
|
|
233
|
+
this.optionalAssets.add('clangd.headers.json.gz');
|
|
234
|
+
}
|
|
231
235
|
if (runtime === 'clang') {
|
|
232
236
|
this.expectedAssets.delete(printscanLongDoubleAsset);
|
|
233
237
|
this.optionalAssets.add(printscanLongDoubleAsset);
|
|
@@ -387,7 +391,6 @@ export class WorkerAssetBridge {
|
|
|
387
391
|
runtime;
|
|
388
392
|
config;
|
|
389
393
|
persistentCacheBaseline;
|
|
390
|
-
persistentCacheBySignal = new WeakMap();
|
|
391
394
|
progress;
|
|
392
395
|
expectedAssets;
|
|
393
396
|
languageSysroots;
|
|
@@ -404,7 +407,7 @@ export class WorkerAssetBridge {
|
|
|
404
407
|
this.config = { ...config, persistentCache: this.persistentCacheBaseline };
|
|
405
408
|
this.maxAssetBytes = requireBridgeMaxAssetBytes(maxAssetBytes);
|
|
406
409
|
this.languageSysroots = canUseClangLanguageSysroots(runtime, config, languageSysroots);
|
|
407
|
-
this.progress = new RuntimeLoadProgress(runtime, this.languageSysroots);
|
|
410
|
+
this.progress = new RuntimeLoadProgress(runtime, this.languageSysroots, config.assetPrefix === 'clangd' || !!config.integrity?.['clangd.headers.json.gz']);
|
|
408
411
|
this.expectedAssets = expectedAssetsForRuntime(runtime, this.languageSysroots);
|
|
409
412
|
this.progress.reset(progress);
|
|
410
413
|
}
|
|
@@ -455,7 +458,7 @@ export class WorkerAssetBridge {
|
|
|
455
458
|
this.maxAssetBytes = nextMaxAssetBytes;
|
|
456
459
|
this.languageSysroots = nextLanguageSysroots;
|
|
457
460
|
this.expectedAssets = expectedAssetsForRuntime(this.runtime, nextLanguageSysroots);
|
|
458
|
-
this.progress = new RuntimeLoadProgress(this.runtime, nextLanguageSysroots);
|
|
461
|
+
this.progress = new RuntimeLoadProgress(this.runtime, nextLanguageSysroots, config.assetPrefix === 'clangd' || !!config.integrity?.['clangd.headers.json.gz']);
|
|
459
462
|
this.progress.reset(progress);
|
|
460
463
|
if (this.state !== 'rebinding' || this.generation !== generation) {
|
|
461
464
|
throw new Error('Cannot rebind a disposed worker asset bridge');
|
|
@@ -482,7 +485,7 @@ export class WorkerAssetBridge {
|
|
|
482
485
|
return;
|
|
483
486
|
this.progress.reset(progress);
|
|
484
487
|
}
|
|
485
|
-
configuredReceiptByteLimit(asset, value) {
|
|
488
|
+
configuredReceiptByteLimit(context, asset, value) {
|
|
486
489
|
if (value === undefined)
|
|
487
490
|
return undefined;
|
|
488
491
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
@@ -492,37 +495,37 @@ export class WorkerAssetBridge {
|
|
|
492
495
|
});
|
|
493
496
|
}
|
|
494
497
|
const byteLimit = value;
|
|
495
|
-
if (byteLimit >
|
|
496
|
-
throw runtimeAssetSizeError(asset,
|
|
498
|
+
if (byteLimit > context.maxAssetBytes) {
|
|
499
|
+
throw runtimeAssetSizeError(asset, context.maxAssetBytes);
|
|
497
500
|
}
|
|
498
501
|
return byteLimit;
|
|
499
502
|
}
|
|
500
|
-
runtimeAssetByteLimit(asset) {
|
|
501
|
-
const configured =
|
|
503
|
+
runtimeAssetByteLimit(context, asset) {
|
|
504
|
+
const configured = context.config.integrity?.[asset];
|
|
502
505
|
if (!configured || typeof configured === 'string')
|
|
503
|
-
return
|
|
504
|
-
return (this.configuredReceiptByteLimit(asset, configured.uncompressedBytes ?? configured.bytes) ??
|
|
506
|
+
return context.maxAssetBytes;
|
|
507
|
+
return (this.configuredReceiptByteLimit(context, asset, configured.uncompressedBytes ?? configured.bytes) ?? context.maxAssetBytes);
|
|
505
508
|
}
|
|
506
|
-
sourceAssetByteLimit(asset) {
|
|
507
|
-
const configured =
|
|
509
|
+
sourceAssetByteLimit(context, asset) {
|
|
510
|
+
const configured = context.config.integrity?.[asset];
|
|
508
511
|
if (!configured || typeof configured === 'string')
|
|
509
|
-
return
|
|
512
|
+
return context.maxAssetBytes;
|
|
510
513
|
const paired = configured.uncompressedBytes !== undefined ||
|
|
511
514
|
configured.uncompressedSha256 !== undefined;
|
|
512
515
|
if (asset.endsWith('.gz')) {
|
|
513
516
|
if (!paired)
|
|
514
|
-
return
|
|
515
|
-
const deliveryLimit = this.configuredReceiptByteLimit(asset, configured.bytes);
|
|
516
|
-
const runtimeLimit = this.configuredReceiptByteLimit(asset, configured.uncompressedBytes);
|
|
517
|
+
return context.maxAssetBytes;
|
|
518
|
+
const deliveryLimit = this.configuredReceiptByteLimit(context, asset, configured.bytes);
|
|
519
|
+
const runtimeLimit = this.configuredReceiptByteLimit(context, asset, configured.uncompressedBytes);
|
|
517
520
|
return deliveryLimit !== undefined || runtimeLimit !== undefined
|
|
518
521
|
? Math.max(deliveryLimit ?? 0, runtimeLimit ?? 0)
|
|
519
|
-
:
|
|
522
|
+
: context.maxAssetBytes;
|
|
520
523
|
}
|
|
521
|
-
const deliveryLimit = this.configuredReceiptByteLimit(asset, configured.bytes);
|
|
522
|
-
const runtimeLimit = this.configuredReceiptByteLimit(asset, configured.uncompressedBytes);
|
|
524
|
+
const deliveryLimit = this.configuredReceiptByteLimit(context, asset, configured.bytes);
|
|
525
|
+
const runtimeLimit = this.configuredReceiptByteLimit(context, asset, configured.uncompressedBytes);
|
|
523
526
|
return deliveryLimit !== undefined || runtimeLimit !== undefined
|
|
524
527
|
? Math.max(deliveryLimit ?? 0, runtimeLimit ?? 0)
|
|
525
|
-
:
|
|
528
|
+
: context.maxAssetBytes;
|
|
526
529
|
}
|
|
527
530
|
handleMessage(event) {
|
|
528
531
|
const assetRequest = event.data?.assetRequest;
|
|
@@ -546,69 +549,112 @@ export class WorkerAssetBridge {
|
|
|
546
549
|
const worker = this.worker;
|
|
547
550
|
const generation = this.generation;
|
|
548
551
|
const controller = new AbortController();
|
|
549
|
-
|
|
552
|
+
const progress = this.progress;
|
|
553
|
+
const context = this.captureLoadContext();
|
|
554
|
+
const receiveProgress = (event) => {
|
|
555
|
+
if (controller.signal.aborted || generation !== this.generation)
|
|
556
|
+
return;
|
|
557
|
+
if (event.kind === 'download') {
|
|
558
|
+
progress.update(event.asset, event.loaded, event.total);
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
progress.activity(event.phase, event.asset);
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const loadContext = (report) => ({
|
|
565
|
+
...context,
|
|
566
|
+
progress: {
|
|
567
|
+
update: (asset, loaded, total) => report({ kind: 'download', asset, loaded, total }, `download:${asset}`),
|
|
568
|
+
activity: (phase, asset) => report({ kind: 'activity', asset, phase }, `activity:${asset}`)
|
|
569
|
+
}
|
|
570
|
+
});
|
|
550
571
|
this.activeLoads.add(controller);
|
|
551
572
|
try {
|
|
552
|
-
this.validateAssetRequest(request.asset);
|
|
553
|
-
const
|
|
573
|
+
this.validateAssetRequest(loadContext(receiveProgress), request.asset);
|
|
574
|
+
const identity = [
|
|
554
575
|
this.runtime,
|
|
555
|
-
|
|
556
|
-
this.cache?.identity(
|
|
557
|
-
integrityKey(
|
|
558
|
-
allowedBaseUrlsKey(
|
|
559
|
-
|
|
560
|
-
|
|
576
|
+
context.config.baseUrl,
|
|
577
|
+
this.cache?.identity(context.config.loader),
|
|
578
|
+
integrityKey(context.config),
|
|
579
|
+
allowedBaseUrlsKey(context.config),
|
|
580
|
+
context.config.useAssetBridge,
|
|
581
|
+
context.maxAssetBytes,
|
|
561
582
|
this.languageSysroots,
|
|
562
|
-
request.asset
|
|
563
|
-
|
|
564
|
-
]);
|
|
583
|
+
request.asset
|
|
584
|
+
];
|
|
585
|
+
const bytesKey = JSON.stringify([...identity, 'bytes']);
|
|
586
|
+
const moduleKey = JSON.stringify([...identity, 'module']);
|
|
587
|
+
const share = (key, signal, start, report = receiveProgress) => {
|
|
588
|
+
// Completed verified values can cross storage policies. In-flight work cannot:
|
|
589
|
+
// a request disabling persistence must not join a load that reads or writes it.
|
|
590
|
+
const operationKey = JSON.stringify([key, context.config.persistentCache]);
|
|
591
|
+
return this.cache
|
|
592
|
+
? this.cache.share(operationKey, signal, start, report)
|
|
593
|
+
: start(signal, report);
|
|
594
|
+
};
|
|
595
|
+
const loadBytes = async (signal, report = receiveProgress, retain = false) => {
|
|
596
|
+
let loaded = this.cache?.get(bytesKey);
|
|
597
|
+
if (loaded)
|
|
598
|
+
return loaded;
|
|
599
|
+
loaded = await share(bytesKey, signal, async (operationSignal, publish) => {
|
|
600
|
+
const loaded = await this.loadVerifiedAsset(loadContext(publish), request.asset, operationSignal);
|
|
601
|
+
// Keep shared backing buffers private, even when the result exceeds retention limits.
|
|
602
|
+
return this.cache
|
|
603
|
+
? { bytes: Uint8Array.from(loaded.bytes), mimeType: loaded.mimeType }
|
|
604
|
+
: loaded;
|
|
605
|
+
}, report);
|
|
606
|
+
if (signal.aborted)
|
|
607
|
+
throw runtimeAssetAbortReason(signal);
|
|
608
|
+
if (retain)
|
|
609
|
+
this.cache?.set(bytesKey, loaded, loaded.bytes.byteLength);
|
|
610
|
+
return loaded;
|
|
611
|
+
};
|
|
565
612
|
if (request.module === true) {
|
|
566
613
|
if (!/\.wasm(?:\.gz)?$/u.test(request.asset)) {
|
|
567
614
|
throw new Error('Only runtime Wasm assets can be compiled');
|
|
568
615
|
}
|
|
569
|
-
let module = this.cache?.get(
|
|
616
|
+
let module = this.cache?.get(moduleKey);
|
|
570
617
|
if (!module) {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
request.asset === 'bin/
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
618
|
+
module = await share(moduleKey, controller.signal, async (signal, report) => {
|
|
619
|
+
const streaming = this.runtime === 'clang' &&
|
|
620
|
+
shouldStreamBundledClang(context.config) &&
|
|
621
|
+
(request.asset === 'bin/clang.wasm.gz' ||
|
|
622
|
+
request.asset === 'bin/lld.wasm.gz');
|
|
623
|
+
let bytes;
|
|
624
|
+
let module;
|
|
625
|
+
if (streaming) {
|
|
626
|
+
const receipt = BUNDLED_CLANG_ASSET_INTEGRITY[request.asset];
|
|
627
|
+
module = await compileVerifiedWasmAsset(new URL(request.asset, context.config.baseUrl).href, receipt, {
|
|
628
|
+
fetch: globalThis.fetch.bind(globalThis),
|
|
629
|
+
persistentCache: context.config.persistentCache,
|
|
630
|
+
maxAssetBytes: context.maxAssetBytes,
|
|
631
|
+
signal,
|
|
632
|
+
onProgress: (loaded, total) => report({
|
|
633
|
+
kind: 'download',
|
|
634
|
+
asset: request.asset,
|
|
635
|
+
loaded,
|
|
636
|
+
total
|
|
637
|
+
}, `download:${request.asset}`)
|
|
638
|
+
});
|
|
639
|
+
bytes = receipt.uncompressedBytes;
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
const loaded = await loadBytes(signal, (event) => report(event, `${event.kind}:${event.asset}`));
|
|
643
|
+
bytes = loaded.bytes.byteLength;
|
|
644
|
+
module = await WebAssembly.compile(Uint8Array.from(loaded.bytes));
|
|
645
|
+
}
|
|
646
|
+
if (signal.aborted)
|
|
647
|
+
throw runtimeAssetAbortReason(signal);
|
|
648
|
+
this.cache?.set(moduleKey, module, bytes);
|
|
649
|
+
return module;
|
|
650
|
+
});
|
|
595
651
|
}
|
|
596
652
|
if (controller.signal.aborted || generation !== this.generation)
|
|
597
653
|
return;
|
|
598
654
|
worker.postMessage({ assetResponse: { id: request.id, ok: true, module } });
|
|
599
655
|
return;
|
|
600
656
|
}
|
|
601
|
-
|
|
602
|
-
if (!loaded) {
|
|
603
|
-
loaded = await this.loadVerifiedAsset(request.asset, controller.signal);
|
|
604
|
-
if (controller.signal.aborted || generation !== this.generation)
|
|
605
|
-
return;
|
|
606
|
-
// Keep private copies: never transfer or lend the owner cache's backing buffer.
|
|
607
|
-
if (this.cache) {
|
|
608
|
-
loaded = { bytes: Uint8Array.from(loaded.bytes), mimeType: loaded.mimeType };
|
|
609
|
-
this.cache.set(key, loaded, loaded.bytes.byteLength);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
657
|
+
const loaded = await loadBytes(controller.signal, receiveProgress, true);
|
|
612
658
|
if (this.runtime === 'python' && request.asset === 'pyodide-lock.json') {
|
|
613
659
|
this.pythonPackageAssets = readPythonPackageAssets(loaded.bytes);
|
|
614
660
|
}
|
|
@@ -644,15 +690,24 @@ export class WorkerAssetBridge {
|
|
|
644
690
|
this.activeLoads.delete(controller);
|
|
645
691
|
}
|
|
646
692
|
}
|
|
647
|
-
|
|
648
|
-
|
|
693
|
+
captureLoadContext() {
|
|
694
|
+
return {
|
|
695
|
+
config: { ...this.config },
|
|
696
|
+
maxAssetBytes: this.maxAssetBytes,
|
|
697
|
+
expectedAssets: new Set(this.expectedAssets),
|
|
698
|
+
pythonPackageAssets: new Set(this.pythonPackageAssets),
|
|
699
|
+
progress: this.progress
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
async loadVerifiedAsset(context, asset, signal) {
|
|
703
|
+
const loaded = await this.loadAsset(asset, signal, context);
|
|
649
704
|
const deliveryBytes = canonicalUint8Array(loaded.bytes);
|
|
650
|
-
const sourceAssetByteLimit = this.sourceAssetByteLimit(asset);
|
|
651
|
-
const runtimeAssetByteLimit = this.runtimeAssetByteLimit(asset);
|
|
705
|
+
const sourceAssetByteLimit = this.sourceAssetByteLimit(context, asset);
|
|
706
|
+
const runtimeAssetByteLimit = this.runtimeAssetByteLimit(context, asset);
|
|
652
707
|
requireRuntimeAssetSize(asset, deliveryBytes.byteLength, sourceAssetByteLimit);
|
|
653
708
|
let normalizedRuntimeBytes;
|
|
654
709
|
if (asset.endsWith('.gz')) {
|
|
655
|
-
|
|
710
|
+
context.progress.activity('decompressing', asset);
|
|
656
711
|
normalizedRuntimeBytes = await decompressGzip(deliveryBytes, asset, runtimeAssetByteLimit, signal);
|
|
657
712
|
}
|
|
658
713
|
else {
|
|
@@ -673,10 +728,10 @@ export class WorkerAssetBridge {
|
|
|
673
728
|
signal.addEventListener('abort', cancelOnAbort, { once: true });
|
|
674
729
|
});
|
|
675
730
|
try {
|
|
676
|
-
if (
|
|
677
|
-
|
|
731
|
+
if (context.config.integrity?.[asset]) {
|
|
732
|
+
context.progress.activity('verifying', asset);
|
|
678
733
|
}
|
|
679
|
-
const verification = this.verifyIntegrity(asset, deliveryBytes, runtimeBytes, loaded.mimeType, !httpDecodedGzip);
|
|
734
|
+
const verification = this.verifyIntegrity(context, asset, deliveryBytes, runtimeBytes, loaded.mimeType, !httpDecodedGzip);
|
|
680
735
|
await Promise.race([verification, aborted]);
|
|
681
736
|
}
|
|
682
737
|
finally {
|
|
@@ -694,27 +749,27 @@ export class WorkerAssetBridge {
|
|
|
694
749
|
transferOwnership: normalizedRuntimeBytes === deliveryBytes ? loaded.transferOwnership : true
|
|
695
750
|
};
|
|
696
751
|
}
|
|
697
|
-
validateAssetRequest(asset) {
|
|
698
|
-
if (!
|
|
752
|
+
validateAssetRequest(context, asset) {
|
|
753
|
+
if (!context.expectedAssets.has(asset) && !context.pythonPackageAssets.has(asset)) {
|
|
699
754
|
throw new Error(`Unexpected ${this.runtime} runtime asset: ${asset}`);
|
|
700
755
|
}
|
|
701
|
-
if (
|
|
756
|
+
if (context.config.integrity && !Object.hasOwn(context.config.integrity, asset)) {
|
|
702
757
|
throw new Error(`Runtime asset ${asset} is missing integrity metadata`);
|
|
703
758
|
}
|
|
704
759
|
}
|
|
705
|
-
async loadAsset(asset, signal) {
|
|
706
|
-
this.validateAssetRequest(asset);
|
|
760
|
+
async loadAsset(asset, signal, context = this.captureLoadContext()) {
|
|
761
|
+
this.validateAssetRequest(context, asset);
|
|
707
762
|
if (signal.aborted) {
|
|
708
763
|
throw runtimeAssetAbortReason(signal);
|
|
709
764
|
}
|
|
710
|
-
const sourceAssetByteLimit = this.sourceAssetByteLimit(asset);
|
|
711
|
-
this.runtimeAssetByteLimit(asset);
|
|
765
|
+
const sourceAssetByteLimit = this.sourceAssetByteLimit(context, asset);
|
|
766
|
+
this.runtimeAssetByteLimit(context, asset);
|
|
712
767
|
const reportProgress = (loaded, total) => {
|
|
713
768
|
if (!signal.aborted)
|
|
714
|
-
|
|
769
|
+
context.progress.update(asset, loaded, total);
|
|
715
770
|
};
|
|
716
|
-
if (
|
|
717
|
-
const pendingResult = Promise.resolve(
|
|
771
|
+
if (context.config.loader) {
|
|
772
|
+
const pendingResult = Promise.resolve(context.config.loader({
|
|
718
773
|
runtime: this.runtime,
|
|
719
774
|
asset,
|
|
720
775
|
reportProgress,
|
|
@@ -749,17 +804,17 @@ export class WorkerAssetBridge {
|
|
|
749
804
|
if (signal.aborted) {
|
|
750
805
|
throw runtimeAssetAbortReason(signal);
|
|
751
806
|
}
|
|
752
|
-
const loaded = await this.normalizeLoaderResult(result, asset, signal, sourceAssetByteLimit);
|
|
807
|
+
const loaded = await this.normalizeLoaderResult(context, result, asset, signal, sourceAssetByteLimit);
|
|
753
808
|
if (signal.aborted) {
|
|
754
809
|
throw runtimeAssetAbortReason(signal);
|
|
755
810
|
}
|
|
756
811
|
if (loaded)
|
|
757
812
|
return loaded;
|
|
758
813
|
}
|
|
759
|
-
return await this.fetchAsset(asset, asset, signal, sourceAssetByteLimit);
|
|
814
|
+
return await this.fetchAsset(context, asset, asset, signal, sourceAssetByteLimit);
|
|
760
815
|
}
|
|
761
|
-
async verifyIntegrity(asset, deliveryBytes, runtimeBytes, mimeType, hasDeliveryBytes = true) {
|
|
762
|
-
const configured =
|
|
816
|
+
async verifyIntegrity(context, asset, deliveryBytes, runtimeBytes, mimeType, hasDeliveryBytes = true) {
|
|
817
|
+
const configured = context.config.integrity?.[asset];
|
|
763
818
|
if (!configured)
|
|
764
819
|
return;
|
|
765
820
|
const expected = typeof configured === 'string' ? { sha256: configured } : configured;
|
|
@@ -796,15 +851,15 @@ export class WorkerAssetBridge {
|
|
|
796
851
|
mimeType
|
|
797
852
|
});
|
|
798
853
|
}
|
|
799
|
-
async normalizeLoaderResult(result, asset, signal, maxAssetBytes) {
|
|
854
|
+
async normalizeLoaderResult(context, result, asset, signal, maxAssetBytes) {
|
|
800
855
|
if (!result)
|
|
801
856
|
return null;
|
|
802
857
|
if (typeof result === 'string' || result instanceof URL) {
|
|
803
|
-
return await this.fetchAsset(String(result), asset, signal, maxAssetBytes);
|
|
858
|
+
return await this.fetchAsset(context, String(result), asset, signal, maxAssetBytes);
|
|
804
859
|
}
|
|
805
860
|
const directBytes = snapshotLoaderBytes(result, asset, maxAssetBytes);
|
|
806
861
|
if (directBytes) {
|
|
807
|
-
|
|
862
|
+
context.progress.update(asset, directBytes.byteLength, directBytes.byteLength);
|
|
808
863
|
return { bytes: directBytes, transferOwnership: true };
|
|
809
864
|
}
|
|
810
865
|
const directBlob = tryCanonicalBlob(result);
|
|
@@ -827,23 +882,23 @@ export class WorkerAssetBridge {
|
|
|
827
882
|
requireRuntimeAssetSize(asset, size, maxAssetBytes);
|
|
828
883
|
const source = await readAbortableArrayBuffer(blob, signal);
|
|
829
884
|
const bytes = snapshotMaterializedArrayBuffer(source, asset, maxAssetBytes);
|
|
830
|
-
|
|
885
|
+
context.progress.update(asset, bytes.byteLength, bytes.byteLength);
|
|
831
886
|
return { bytes, mimeType, transferOwnership: true };
|
|
832
887
|
}
|
|
833
888
|
if ('url' in result && result.url) {
|
|
834
|
-
return await this.fetchAsset(String(result.url), asset, signal, maxAssetBytes);
|
|
889
|
+
return await this.fetchAsset(context, String(result.url), asset, signal, maxAssetBytes);
|
|
835
890
|
}
|
|
836
891
|
if ('data' in result) {
|
|
837
892
|
if (typeof result.data === 'string') {
|
|
838
893
|
requireRuntimeAssetSize(asset, boundedUtf8ByteLength(result.data, maxAssetBytes), maxAssetBytes);
|
|
839
894
|
const bytes = canonicalUint8Array(encoder.encode(result.data));
|
|
840
895
|
requireRuntimeAssetSize(asset, bytes.byteLength, maxAssetBytes);
|
|
841
|
-
|
|
896
|
+
context.progress.update(asset, bytes.byteLength, bytes.byteLength);
|
|
842
897
|
return { bytes, mimeType: result.mimeType, transferOwnership: true };
|
|
843
898
|
}
|
|
844
899
|
const bytes = snapshotLoaderBytes(result.data, asset, maxAssetBytes);
|
|
845
900
|
if (bytes) {
|
|
846
|
-
|
|
901
|
+
context.progress.update(asset, bytes.byteLength, bytes.byteLength);
|
|
847
902
|
return {
|
|
848
903
|
bytes,
|
|
849
904
|
mimeType: result.mimeType,
|
|
@@ -853,15 +908,15 @@ export class WorkerAssetBridge {
|
|
|
853
908
|
}
|
|
854
909
|
return null;
|
|
855
910
|
}
|
|
856
|
-
async fetchAsset(url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(asset)) {
|
|
857
|
-
const requestUrl = this.requireAllowedAssetUrl(asset, url);
|
|
858
|
-
const persistentCache =
|
|
859
|
-
const configured =
|
|
911
|
+
async fetchAsset(context, url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(context, asset)) {
|
|
912
|
+
const requestUrl = this.requireAllowedAssetUrl(context, asset, url);
|
|
913
|
+
const persistentCache = context.config.persistentCache;
|
|
914
|
+
const configured = context.config.integrity?.[asset];
|
|
860
915
|
const expected = typeof configured === 'string' ? { sha256: configured } : configured;
|
|
861
|
-
const lock =
|
|
916
|
+
const lock = context.config.assetPrefix
|
|
862
917
|
? resolveRuntimeAssetLockEntry(requestUrl, {
|
|
863
|
-
assetRoot:
|
|
864
|
-
assetPrefix:
|
|
918
|
+
assetRoot: context.config.baseUrl,
|
|
919
|
+
assetPrefix: context.config.assetPrefix
|
|
865
920
|
})
|
|
866
921
|
: undefined;
|
|
867
922
|
// Existing .gz receipts without a pair describe logical bytes, not stored gzip bytes.
|
|
@@ -873,8 +928,8 @@ export class WorkerAssetBridge {
|
|
|
873
928
|
bytes: receipt.bytes,
|
|
874
929
|
validationKey: JSON.stringify([
|
|
875
930
|
'bridge-v1',
|
|
876
|
-
|
|
877
|
-
allowedBaseUrlsKey(
|
|
931
|
+
context.config.baseUrl,
|
|
932
|
+
allowedBaseUrlsKey(context.config),
|
|
878
933
|
maxAssetBytes
|
|
879
934
|
])
|
|
880
935
|
}
|
|
@@ -887,11 +942,11 @@ export class WorkerAssetBridge {
|
|
|
887
942
|
});
|
|
888
943
|
if (bytes) {
|
|
889
944
|
requireRuntimeAssetSize(asset, bytes.byteLength, maxAssetBytes);
|
|
890
|
-
|
|
945
|
+
context.progress.update(asset, bytes.byteLength, bytes.byteLength);
|
|
891
946
|
return { bytes, mimeType: receipt?.mediaType, transferOwnership: true };
|
|
892
947
|
}
|
|
893
948
|
}
|
|
894
|
-
const loaded = await this.fetchAssetFromNetwork(url, asset, signal, maxAssetBytes);
|
|
949
|
+
const loaded = await this.fetchAssetFromNetwork(context, url, asset, signal, maxAssetBytes);
|
|
895
950
|
if (identity && !loaded.contentEncoding) {
|
|
896
951
|
// Only checksum-matching bytes are published. Existing runtime validation still runs.
|
|
897
952
|
await writePersistentRuntimeAsset({
|
|
@@ -903,8 +958,8 @@ export class WorkerAssetBridge {
|
|
|
903
958
|
}
|
|
904
959
|
return loaded;
|
|
905
960
|
}
|
|
906
|
-
async fetchAssetFromNetwork(url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(asset)) {
|
|
907
|
-
const requestUrl = this.requireAllowedAssetUrl(asset, url);
|
|
961
|
+
async fetchAssetFromNetwork(context, url, asset, signal, maxAssetBytes = this.sourceAssetByteLimit(context, asset)) {
|
|
962
|
+
const requestUrl = this.requireAllowedAssetUrl(context, asset, url);
|
|
908
963
|
if (signal.aborted)
|
|
909
964
|
throw runtimeAssetAbortReason(signal);
|
|
910
965
|
const pendingResponse = Promise.resolve(fetch(requestUrl.href, {
|
|
@@ -994,7 +1049,7 @@ export class WorkerAssetBridge {
|
|
|
994
1049
|
const contentEncoding = response.headers.get('content-encoding') || undefined;
|
|
995
1050
|
if (!response.body) {
|
|
996
1051
|
const bytes = snapshotMaterializedArrayBuffer(await readAbortableArrayBuffer(response, signal), asset, maxAssetBytes);
|
|
997
|
-
|
|
1052
|
+
context.progress.update(asset, bytes.byteLength, contentLength ?? bytes.byteLength);
|
|
998
1053
|
return { bytes, contentEncoding, mimeType, transferOwnership: true };
|
|
999
1054
|
}
|
|
1000
1055
|
const reader = response.body.getReader();
|
|
@@ -1062,11 +1117,11 @@ export class WorkerAssetBridge {
|
|
|
1062
1117
|
}
|
|
1063
1118
|
bytes.set(chunk, receivedLength);
|
|
1064
1119
|
receivedLength = nextLength;
|
|
1065
|
-
|
|
1120
|
+
context.progress.update(asset, receivedLength, contentLength);
|
|
1066
1121
|
}
|
|
1067
1122
|
if (receivedLength !== bytes.byteLength)
|
|
1068
1123
|
bytes = bytes.slice(0, receivedLength);
|
|
1069
|
-
|
|
1124
|
+
context.progress.update(asset, receivedLength, contentLength ?? receivedLength);
|
|
1070
1125
|
loadedAsset = { bytes, contentEncoding, mimeType, transferOwnership: true };
|
|
1071
1126
|
}
|
|
1072
1127
|
catch (error) {
|
|
@@ -1105,10 +1160,10 @@ export class WorkerAssetBridge {
|
|
|
1105
1160
|
throw releaseError;
|
|
1106
1161
|
return loadedAsset;
|
|
1107
1162
|
}
|
|
1108
|
-
requireAllowedAssetUrl(asset, value) {
|
|
1163
|
+
requireAllowedAssetUrl(context, asset, value) {
|
|
1109
1164
|
let url;
|
|
1110
1165
|
try {
|
|
1111
|
-
url = new URL(value,
|
|
1166
|
+
url = new URL(value, context.config.baseUrl);
|
|
1112
1167
|
}
|
|
1113
1168
|
catch {
|
|
1114
1169
|
throw new Error(`Runtime asset ${asset} has an invalid URL`);
|
|
@@ -1122,7 +1177,7 @@ export class WorkerAssetBridge {
|
|
|
1122
1177
|
if (url.hash) {
|
|
1123
1178
|
throw new Error(`Runtime asset ${asset} URL must not include a fragment`);
|
|
1124
1179
|
}
|
|
1125
|
-
const allowed = [
|
|
1180
|
+
const allowed = [context.config.baseUrl, ...(context.config.allowedBaseUrls || [])].some((baseUrl) => {
|
|
1126
1181
|
let base;
|
|
1127
1182
|
try {
|
|
1128
1183
|
base = new URL(baseUrl, url);
|
|
@@ -653,15 +653,15 @@ export interface ResolvedZigRuntimeAssetConfig {
|
|
|
653
653
|
stdlibUrl: string;
|
|
654
654
|
integrity: ZigExecutionAssetReceipts;
|
|
655
655
|
}
|
|
656
|
-
export declare const PYTHON_RUNTIME_LOAD_ASSETS: readonly ["pyodide.mjs", "pyodide.asm.
|
|
656
|
+
export declare const PYTHON_RUNTIME_LOAD_ASSETS: readonly ["pyodide.mjs", "pyodide.asm.mjs", "pyodide-lock.json", "pyodide.asm.wasm", "python_stdlib.zip"];
|
|
657
657
|
export declare const JAVA_RUNTIME_LOAD_ASSETS: readonly ["compiler.wasm-runtime.js", "compiler.wasm", "compile-classlib-teavm.bin", "runtime-classlib-teavm.bin"];
|
|
658
658
|
export declare const CLANG_RUNTIME_LOAD_ASSETS: readonly ["runtime-manifest.v1.json", "bin/memfs.wasm.gz", "bin/clang.wasm.gz", "bin/lld.wasm.gz", "bin/sysroot.tar.gz"];
|
|
659
|
-
export declare const CLANGD_RUNTIME_LOAD_ASSETS: readonly ["clangd.js", "clangd.wasm.gz"];
|
|
659
|
+
export declare const CLANGD_RUNTIME_LOAD_ASSETS: readonly ["clangd.js", "clangd.wasm.gz", "clangd.headers.json.gz"];
|
|
660
660
|
export declare const RUNTIME_LOAD_ASSETS: {
|
|
661
|
-
python: readonly ["pyodide.mjs", "pyodide.asm.
|
|
661
|
+
python: readonly ["pyodide.mjs", "pyodide.asm.mjs", "pyodide-lock.json", "pyodide.asm.wasm", "python_stdlib.zip"];
|
|
662
662
|
java: readonly ["compiler.wasm-runtime.js", "compiler.wasm", "compile-classlib-teavm.bin", "runtime-classlib-teavm.bin"];
|
|
663
663
|
clang: readonly ["runtime-manifest.v1.json", "bin/memfs.wasm.gz", "bin/clang.wasm.gz", "bin/lld.wasm.gz", "bin/sysroot.tar.gz"];
|
|
664
|
-
clangd: readonly ["clangd.js", "clangd.wasm.gz"];
|
|
664
|
+
clangd: readonly ["clangd.js", "clangd.wasm.gz", "clangd.headers.json.gz"];
|
|
665
665
|
};
|
|
666
666
|
export declare function resolveRuntimeAssetConfig(runtime: RuntimeAssetRuntime, options: string | PlaygroundRuntimeAssets | undefined, currentUrl?: string, callCache?: RuntimeAssetCacheOptions): ResolvedRuntimeAssetConfig;
|
|
667
667
|
export declare function resolveRustCompilerUrl(options: string | PlaygroundRuntimeAssets | undefined, currentUrl?: string): string;
|