@ricsam/isolate-runtime 0.1.15 → 0.1.17
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/dist/cjs/index.cjs +185 -59
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/index.mjs +185 -59
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/index.d.ts +4 -0
- package/package.json +1 -1
package/dist/mjs/index.mjs
CHANGED
|
@@ -632,49 +632,102 @@ function createLocalCustomFunctionsMarshalOptions() {
|
|
|
632
632
|
}
|
|
633
633
|
function createModuleResolver(state) {
|
|
634
634
|
return async (specifier, referrer) => {
|
|
635
|
-
const
|
|
635
|
+
const importerPath = state.moduleToFilename.get(referrer) ?? "<unknown>";
|
|
636
|
+
const importerResolveDir = path.posix.dirname(importerPath);
|
|
637
|
+
const importerStack = state.moduleImportChain.get(importerPath) ?? [];
|
|
638
|
+
const resolvedSpecifier = specifier.startsWith(".") ? path.posix.normalize(path.posix.join(importerResolveDir, specifier)) : specifier;
|
|
639
|
+
state.specifierToImporter.set(resolvedSpecifier, importerPath);
|
|
640
|
+
const staticCached = state.staticModuleCache.get(resolvedSpecifier);
|
|
636
641
|
if (staticCached)
|
|
637
642
|
return staticCached;
|
|
638
|
-
const cached = state.moduleCache.get(
|
|
643
|
+
const cached = state.moduleCache.get(resolvedSpecifier);
|
|
639
644
|
if (cached)
|
|
640
645
|
return cached;
|
|
641
646
|
if (!state.moduleLoader) {
|
|
642
647
|
throw new Error(`No module loader registered. Cannot import: ${specifier}`);
|
|
643
648
|
}
|
|
644
|
-
const importerPath = state.moduleToFilename.get(referrer) ?? "<unknown>";
|
|
645
|
-
const importerResolveDir = path.posix.dirname(importerPath);
|
|
646
649
|
const result = await state.moduleLoader(specifier, {
|
|
647
650
|
path: importerPath,
|
|
648
651
|
resolveDir: importerResolveDir
|
|
649
652
|
});
|
|
650
653
|
const { code, resolveDir } = result;
|
|
654
|
+
if (result.filename.includes("/")) {
|
|
655
|
+
throw new Error(`moduleLoader returned a filename with slashes: "${result.filename}". ` + `filename must be a basename (e.g. "utils.js"), not a path.`);
|
|
656
|
+
}
|
|
657
|
+
const resolvedFilename = path.posix.join(resolveDir, result.filename);
|
|
651
658
|
const hash = contentHash(code);
|
|
652
|
-
const cacheKey = `${
|
|
659
|
+
const cacheKey = `${resolvedSpecifier}:${hash}`;
|
|
660
|
+
const inFlightKey = `${result.static ? "static" : "dynamic"}:${cacheKey}`;
|
|
661
|
+
const staticCachedAfterLoad = state.staticModuleCache.get(resolvedSpecifier);
|
|
662
|
+
if (staticCachedAfterLoad)
|
|
663
|
+
return staticCachedAfterLoad;
|
|
664
|
+
const cachedAfterLoad = state.moduleCache.get(resolvedSpecifier);
|
|
665
|
+
if (cachedAfterLoad)
|
|
666
|
+
return cachedAfterLoad;
|
|
653
667
|
const hashCached = state.moduleCache.get(cacheKey);
|
|
654
668
|
if (hashCached)
|
|
655
669
|
return hashCached;
|
|
656
|
-
|
|
657
|
-
if (
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
670
|
+
const inFlight = state.moduleLoadsInFlight.get(inFlightKey);
|
|
671
|
+
if (inFlight)
|
|
672
|
+
return inFlight;
|
|
673
|
+
const loadPromise = (async () => {
|
|
674
|
+
let mod;
|
|
675
|
+
try {
|
|
676
|
+
let transformed = state.transformCache.get(hash);
|
|
677
|
+
if (!transformed) {
|
|
678
|
+
transformed = await transformModuleCode(code, resolvedSpecifier);
|
|
679
|
+
state.transformCache.set(hash, transformed);
|
|
680
|
+
}
|
|
681
|
+
if (transformed.sourceMap) {
|
|
682
|
+
state.sourceMaps.set(resolvedSpecifier, transformed.sourceMap);
|
|
683
|
+
}
|
|
684
|
+
mod = await state.isolate.compileModule(transformed.code, {
|
|
685
|
+
filename: resolvedSpecifier
|
|
686
|
+
});
|
|
687
|
+
state.moduleToFilename.set(mod, resolvedFilename);
|
|
688
|
+
state.moduleImportChain.set(resolvedFilename, [...importerStack, importerPath]);
|
|
689
|
+
if (result.static) {
|
|
690
|
+
state.staticModuleCache.set(resolvedSpecifier, mod);
|
|
691
|
+
} else {
|
|
692
|
+
state.moduleCache.set(resolvedSpecifier, mod);
|
|
693
|
+
state.moduleCache.set(cacheKey, mod);
|
|
694
|
+
}
|
|
695
|
+
return mod;
|
|
696
|
+
} catch (err) {
|
|
697
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
698
|
+
error.message = `Failed to compile module "${resolvedSpecifier}" (imported by "${importerPath}"):
|
|
699
|
+
${error.message}`;
|
|
700
|
+
if (importerStack.length > 0) {
|
|
701
|
+
error.message += `
|
|
702
|
+
|
|
703
|
+
Import chain:
|
|
704
|
+
${[...importerStack, importerPath].join(`
|
|
705
|
+
-> `)}`;
|
|
706
|
+
}
|
|
707
|
+
if (mod) {
|
|
708
|
+
state.moduleToFilename.delete(mod);
|
|
709
|
+
if (result.static) {
|
|
710
|
+
if (state.staticModuleCache.get(resolvedSpecifier) === mod) {
|
|
711
|
+
state.staticModuleCache.delete(resolvedSpecifier);
|
|
712
|
+
}
|
|
713
|
+
} else {
|
|
714
|
+
if (state.moduleCache.get(resolvedSpecifier) === mod) {
|
|
715
|
+
state.moduleCache.delete(resolvedSpecifier);
|
|
716
|
+
}
|
|
717
|
+
if (state.moduleCache.get(cacheKey) === mod) {
|
|
718
|
+
state.moduleCache.delete(cacheKey);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
throw error;
|
|
723
|
+
}
|
|
724
|
+
})();
|
|
725
|
+
state.moduleLoadsInFlight.set(inFlightKey, loadPromise);
|
|
726
|
+
try {
|
|
727
|
+
return await loadPromise;
|
|
728
|
+
} finally {
|
|
729
|
+
state.moduleLoadsInFlight.delete(inFlightKey);
|
|
663
730
|
}
|
|
664
|
-
const mod = await state.isolate.compileModule(transformed.code, {
|
|
665
|
-
filename: specifier
|
|
666
|
-
});
|
|
667
|
-
const resolvedPath = path.posix.join(resolveDir, path.posix.basename(specifier));
|
|
668
|
-
state.moduleToFilename.set(mod, resolvedPath);
|
|
669
|
-
if (result.static) {
|
|
670
|
-
state.staticModuleCache.set(specifier, mod);
|
|
671
|
-
} else {
|
|
672
|
-
state.moduleCache.set(specifier, mod);
|
|
673
|
-
state.moduleCache.set(cacheKey, mod);
|
|
674
|
-
}
|
|
675
|
-
const resolver = createModuleResolver(state);
|
|
676
|
-
await mod.instantiate(state.context, resolver);
|
|
677
|
-
return mod;
|
|
678
731
|
};
|
|
679
732
|
}
|
|
680
733
|
function convertFetchCallback(callback) {
|
|
@@ -700,10 +753,14 @@ async function createRuntime(options) {
|
|
|
700
753
|
handles: {},
|
|
701
754
|
moduleCache: new Map,
|
|
702
755
|
staticModuleCache: new Map,
|
|
756
|
+
moduleLoadsInFlight: new Map,
|
|
703
757
|
transformCache: new Map,
|
|
704
758
|
moduleToFilename: new Map,
|
|
705
759
|
sourceMaps: new Map,
|
|
760
|
+
moduleImportChain: new Map,
|
|
761
|
+
specifierToImporter: new Map,
|
|
706
762
|
pendingCallbacks: [],
|
|
763
|
+
evalChain: Promise.resolve(),
|
|
707
764
|
moduleLoader: opts.moduleLoader,
|
|
708
765
|
customFunctions: opts.customFunctions
|
|
709
766
|
};
|
|
@@ -839,6 +896,18 @@ async function createRuntime(options) {
|
|
|
839
896
|
throw new Error("Fetch handle not available");
|
|
840
897
|
}
|
|
841
898
|
return state.handles.fetch.onClientWebSocketCommand(callback);
|
|
899
|
+
},
|
|
900
|
+
onEvent(callback) {
|
|
901
|
+
if (!state.handles.fetch) {
|
|
902
|
+
throw new Error("Fetch handle not available");
|
|
903
|
+
}
|
|
904
|
+
return state.handles.fetch.onEvent(callback);
|
|
905
|
+
},
|
|
906
|
+
dispatchEvent(event, payload) {
|
|
907
|
+
if (!state.handles.fetch) {
|
|
908
|
+
throw new Error("Fetch handle not available");
|
|
909
|
+
}
|
|
910
|
+
state.handles.fetch.dispatchEvent(event, payload);
|
|
842
911
|
}
|
|
843
912
|
};
|
|
844
913
|
const timersHandle = {
|
|
@@ -923,45 +992,101 @@ async function createRuntime(options) {
|
|
|
923
992
|
testEnvironment: testEnvironmentHandle,
|
|
924
993
|
playwright: playwrightHandle,
|
|
925
994
|
async eval(code, filenameOrOptions) {
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
const transformed = await transformEntryCode(code, filename);
|
|
930
|
-
if (transformed.sourceMap) {
|
|
931
|
-
state.sourceMaps.set(filename, transformed.sourceMap);
|
|
932
|
-
}
|
|
933
|
-
const mod = await state.isolate.compileModule(transformed.code, {
|
|
934
|
-
filename
|
|
935
|
-
});
|
|
936
|
-
state.moduleToFilename.set(mod, filename);
|
|
937
|
-
const resolver = createModuleResolver(state);
|
|
938
|
-
await mod.instantiate(state.context, resolver);
|
|
939
|
-
await mod.evaluate();
|
|
940
|
-
const ns = mod.namespace;
|
|
941
|
-
const runRef = await ns.get("default", { reference: true });
|
|
995
|
+
const runEval = async () => {
|
|
996
|
+
const options2 = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } : filenameOrOptions;
|
|
997
|
+
const filename = normalizeEntryFilename(options2?.filename);
|
|
942
998
|
try {
|
|
943
|
-
await
|
|
944
|
-
|
|
945
|
-
|
|
999
|
+
const transformed = await transformEntryCode(code, filename);
|
|
1000
|
+
if (transformed.sourceMap) {
|
|
1001
|
+
state.sourceMaps.set(filename, transformed.sourceMap);
|
|
1002
|
+
}
|
|
1003
|
+
const mod = await state.isolate.compileModule(transformed.code, {
|
|
1004
|
+
filename
|
|
946
1005
|
});
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1006
|
+
state.moduleToFilename.set(mod, filename);
|
|
1007
|
+
state.moduleImportChain.set(filename, []);
|
|
1008
|
+
const resolver = createModuleResolver(state);
|
|
1009
|
+
try {
|
|
1010
|
+
await mod.instantiate(state.context, resolver);
|
|
1011
|
+
} catch (err) {
|
|
1012
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1013
|
+
const specifierMatch = error.message.match(/The requested module '([^']+)'/);
|
|
1014
|
+
const exportMatch = error.message.match(/export named '([^']+)'/);
|
|
1015
|
+
const failingSpecifier = specifierMatch?.[1];
|
|
1016
|
+
const failingExport = exportMatch?.[1];
|
|
1017
|
+
const importerFile = failingSpecifier ? state.specifierToImporter.get(failingSpecifier) : undefined;
|
|
1018
|
+
const details = [];
|
|
1019
|
+
if (importerFile) {
|
|
1020
|
+
const chain = state.moduleImportChain.get(importerFile) ?? [];
|
|
1021
|
+
const fullChain = [...chain, importerFile];
|
|
1022
|
+
if (failingSpecifier)
|
|
1023
|
+
fullChain.push(failingSpecifier);
|
|
1024
|
+
const trimmed = fullChain.length > 12 ? fullChain.slice(-12) : fullChain;
|
|
1025
|
+
const prefix = fullChain.length > 12 ? ` ...
|
|
1026
|
+
` : "";
|
|
1027
|
+
details.push(`Import chain:
|
|
1028
|
+
` + prefix + trimmed.map((p) => ` ${p}`).join(`
|
|
1029
|
+
-> `));
|
|
1030
|
+
} else if (failingSpecifier) {
|
|
1031
|
+
for (const [modPath, chain] of state.moduleImportChain) {
|
|
1032
|
+
if (modPath.includes(failingSpecifier) || modPath.endsWith(failingSpecifier)) {
|
|
1033
|
+
const fullChain = [...chain, modPath];
|
|
1034
|
+
const trimmed = fullChain.length > 12 ? fullChain.slice(-12) : fullChain;
|
|
1035
|
+
details.push(`Import chain:
|
|
1036
|
+
` + trimmed.map((p) => ` ${p}`).join(`
|
|
1037
|
+
-> `));
|
|
1038
|
+
break;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (failingExport && failingSpecifier) {
|
|
1043
|
+
details.push(`Hint: If '${failingExport}' is a TypeScript type/interface, use \`import type\` to prevent it from being resolved at runtime:
|
|
1044
|
+
` + ` import type { ${failingExport} } from '${failingSpecifier}';`);
|
|
1045
|
+
}
|
|
1046
|
+
const suffix = details.length > 0 ? `
|
|
1047
|
+
|
|
1048
|
+
` + details.join(`
|
|
1049
|
+
|
|
1050
|
+
`) : "";
|
|
1051
|
+
error.message = `Module instantiation failed: ${error.message}${suffix}`;
|
|
1052
|
+
throw error;
|
|
1053
|
+
}
|
|
1054
|
+
await mod.evaluate();
|
|
1055
|
+
const ns = mod.namespace;
|
|
1056
|
+
const runRef = await ns.get("default", { reference: true });
|
|
1057
|
+
try {
|
|
1058
|
+
await runRef.apply(undefined, [], {
|
|
1059
|
+
result: { promise: true }
|
|
1060
|
+
});
|
|
1061
|
+
} finally {
|
|
1062
|
+
runRef.release();
|
|
1063
|
+
}
|
|
1064
|
+
if (state.pendingCallbacks.length > 0) {
|
|
1065
|
+
await Promise.all(state.pendingCallbacks);
|
|
1066
|
+
state.pendingCallbacks.length = 0;
|
|
1067
|
+
}
|
|
1068
|
+
} catch (err) {
|
|
1069
|
+
const error = err;
|
|
1070
|
+
if (error.stack && state.sourceMaps.size > 0) {
|
|
1071
|
+
error.stack = mapErrorStack(error.stack, state.sourceMaps);
|
|
1072
|
+
}
|
|
1073
|
+
throw error;
|
|
958
1074
|
}
|
|
959
|
-
|
|
960
|
-
|
|
1075
|
+
};
|
|
1076
|
+
const queuedEval = state.evalChain.then(runEval, runEval);
|
|
1077
|
+
state.evalChain = queuedEval.then(() => {
|
|
1078
|
+
return;
|
|
1079
|
+
}, () => {
|
|
1080
|
+
return;
|
|
1081
|
+
});
|
|
1082
|
+
return queuedEval;
|
|
961
1083
|
},
|
|
962
1084
|
clearModuleCache() {
|
|
963
1085
|
state.moduleCache.clear();
|
|
1086
|
+
state.moduleLoadsInFlight.clear();
|
|
964
1087
|
state.moduleToFilename.clear();
|
|
1088
|
+
state.moduleImportChain.clear();
|
|
1089
|
+
state.specifierToImporter.clear();
|
|
965
1090
|
state.sourceMaps.clear();
|
|
966
1091
|
},
|
|
967
1092
|
async dispose() {
|
|
@@ -979,6 +1104,7 @@ async function createRuntime(options) {
|
|
|
979
1104
|
state.handles.console?.dispose();
|
|
980
1105
|
state.handles.core?.dispose();
|
|
981
1106
|
state.moduleCache.clear();
|
|
1107
|
+
state.moduleLoadsInFlight.clear();
|
|
982
1108
|
state.context.release();
|
|
983
1109
|
state.isolate.dispose();
|
|
984
1110
|
}
|
|
@@ -1007,4 +1133,4 @@ export {
|
|
|
1007
1133
|
createNodeFileSystemHandler
|
|
1008
1134
|
};
|
|
1009
1135
|
|
|
1010
|
-
//# debugId=
|
|
1136
|
+
//# debugId=30C3A0A75715847864756E2164756E21
|