@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/cjs/index.cjs
CHANGED
|
@@ -670,49 +670,102 @@ function createLocalCustomFunctionsMarshalOptions() {
|
|
|
670
670
|
}
|
|
671
671
|
function createModuleResolver(state) {
|
|
672
672
|
return async (specifier, referrer) => {
|
|
673
|
-
const
|
|
673
|
+
const importerPath = state.moduleToFilename.get(referrer) ?? "<unknown>";
|
|
674
|
+
const importerResolveDir = import_node_path.default.posix.dirname(importerPath);
|
|
675
|
+
const importerStack = state.moduleImportChain.get(importerPath) ?? [];
|
|
676
|
+
const resolvedSpecifier = specifier.startsWith(".") ? import_node_path.default.posix.normalize(import_node_path.default.posix.join(importerResolveDir, specifier)) : specifier;
|
|
677
|
+
state.specifierToImporter.set(resolvedSpecifier, importerPath);
|
|
678
|
+
const staticCached = state.staticModuleCache.get(resolvedSpecifier);
|
|
674
679
|
if (staticCached)
|
|
675
680
|
return staticCached;
|
|
676
|
-
const cached = state.moduleCache.get(
|
|
681
|
+
const cached = state.moduleCache.get(resolvedSpecifier);
|
|
677
682
|
if (cached)
|
|
678
683
|
return cached;
|
|
679
684
|
if (!state.moduleLoader) {
|
|
680
685
|
throw new Error(`No module loader registered. Cannot import: ${specifier}`);
|
|
681
686
|
}
|
|
682
|
-
const importerPath = state.moduleToFilename.get(referrer) ?? "<unknown>";
|
|
683
|
-
const importerResolveDir = import_node_path.default.posix.dirname(importerPath);
|
|
684
687
|
const result = await state.moduleLoader(specifier, {
|
|
685
688
|
path: importerPath,
|
|
686
689
|
resolveDir: importerResolveDir
|
|
687
690
|
});
|
|
688
691
|
const { code, resolveDir } = result;
|
|
692
|
+
if (result.filename.includes("/")) {
|
|
693
|
+
throw new Error(`moduleLoader returned a filename with slashes: "${result.filename}". ` + `filename must be a basename (e.g. "utils.js"), not a path.`);
|
|
694
|
+
}
|
|
695
|
+
const resolvedFilename = import_node_path.default.posix.join(resolveDir, result.filename);
|
|
689
696
|
const hash = import_isolate_transform.contentHash(code);
|
|
690
|
-
const cacheKey = `${
|
|
697
|
+
const cacheKey = `${resolvedSpecifier}:${hash}`;
|
|
698
|
+
const inFlightKey = `${result.static ? "static" : "dynamic"}:${cacheKey}`;
|
|
699
|
+
const staticCachedAfterLoad = state.staticModuleCache.get(resolvedSpecifier);
|
|
700
|
+
if (staticCachedAfterLoad)
|
|
701
|
+
return staticCachedAfterLoad;
|
|
702
|
+
const cachedAfterLoad = state.moduleCache.get(resolvedSpecifier);
|
|
703
|
+
if (cachedAfterLoad)
|
|
704
|
+
return cachedAfterLoad;
|
|
691
705
|
const hashCached = state.moduleCache.get(cacheKey);
|
|
692
706
|
if (hashCached)
|
|
693
707
|
return hashCached;
|
|
694
|
-
|
|
695
|
-
if (
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
708
|
+
const inFlight = state.moduleLoadsInFlight.get(inFlightKey);
|
|
709
|
+
if (inFlight)
|
|
710
|
+
return inFlight;
|
|
711
|
+
const loadPromise = (async () => {
|
|
712
|
+
let mod;
|
|
713
|
+
try {
|
|
714
|
+
let transformed = state.transformCache.get(hash);
|
|
715
|
+
if (!transformed) {
|
|
716
|
+
transformed = await import_isolate_transform.transformModuleCode(code, resolvedSpecifier);
|
|
717
|
+
state.transformCache.set(hash, transformed);
|
|
718
|
+
}
|
|
719
|
+
if (transformed.sourceMap) {
|
|
720
|
+
state.sourceMaps.set(resolvedSpecifier, transformed.sourceMap);
|
|
721
|
+
}
|
|
722
|
+
mod = await state.isolate.compileModule(transformed.code, {
|
|
723
|
+
filename: resolvedSpecifier
|
|
724
|
+
});
|
|
725
|
+
state.moduleToFilename.set(mod, resolvedFilename);
|
|
726
|
+
state.moduleImportChain.set(resolvedFilename, [...importerStack, importerPath]);
|
|
727
|
+
if (result.static) {
|
|
728
|
+
state.staticModuleCache.set(resolvedSpecifier, mod);
|
|
729
|
+
} else {
|
|
730
|
+
state.moduleCache.set(resolvedSpecifier, mod);
|
|
731
|
+
state.moduleCache.set(cacheKey, mod);
|
|
732
|
+
}
|
|
733
|
+
return mod;
|
|
734
|
+
} catch (err) {
|
|
735
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
736
|
+
error.message = `Failed to compile module "${resolvedSpecifier}" (imported by "${importerPath}"):
|
|
737
|
+
${error.message}`;
|
|
738
|
+
if (importerStack.length > 0) {
|
|
739
|
+
error.message += `
|
|
740
|
+
|
|
741
|
+
Import chain:
|
|
742
|
+
${[...importerStack, importerPath].join(`
|
|
743
|
+
-> `)}`;
|
|
744
|
+
}
|
|
745
|
+
if (mod) {
|
|
746
|
+
state.moduleToFilename.delete(mod);
|
|
747
|
+
if (result.static) {
|
|
748
|
+
if (state.staticModuleCache.get(resolvedSpecifier) === mod) {
|
|
749
|
+
state.staticModuleCache.delete(resolvedSpecifier);
|
|
750
|
+
}
|
|
751
|
+
} else {
|
|
752
|
+
if (state.moduleCache.get(resolvedSpecifier) === mod) {
|
|
753
|
+
state.moduleCache.delete(resolvedSpecifier);
|
|
754
|
+
}
|
|
755
|
+
if (state.moduleCache.get(cacheKey) === mod) {
|
|
756
|
+
state.moduleCache.delete(cacheKey);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
throw error;
|
|
761
|
+
}
|
|
762
|
+
})();
|
|
763
|
+
state.moduleLoadsInFlight.set(inFlightKey, loadPromise);
|
|
764
|
+
try {
|
|
765
|
+
return await loadPromise;
|
|
766
|
+
} finally {
|
|
767
|
+
state.moduleLoadsInFlight.delete(inFlightKey);
|
|
712
768
|
}
|
|
713
|
-
const resolver = createModuleResolver(state);
|
|
714
|
-
await mod.instantiate(state.context, resolver);
|
|
715
|
-
return mod;
|
|
716
769
|
};
|
|
717
770
|
}
|
|
718
771
|
function convertFetchCallback(callback) {
|
|
@@ -738,10 +791,14 @@ async function createRuntime(options) {
|
|
|
738
791
|
handles: {},
|
|
739
792
|
moduleCache: new Map,
|
|
740
793
|
staticModuleCache: new Map,
|
|
794
|
+
moduleLoadsInFlight: new Map,
|
|
741
795
|
transformCache: new Map,
|
|
742
796
|
moduleToFilename: new Map,
|
|
743
797
|
sourceMaps: new Map,
|
|
798
|
+
moduleImportChain: new Map,
|
|
799
|
+
specifierToImporter: new Map,
|
|
744
800
|
pendingCallbacks: [],
|
|
801
|
+
evalChain: Promise.resolve(),
|
|
745
802
|
moduleLoader: opts.moduleLoader,
|
|
746
803
|
customFunctions: opts.customFunctions
|
|
747
804
|
};
|
|
@@ -877,6 +934,18 @@ async function createRuntime(options) {
|
|
|
877
934
|
throw new Error("Fetch handle not available");
|
|
878
935
|
}
|
|
879
936
|
return state.handles.fetch.onClientWebSocketCommand(callback);
|
|
937
|
+
},
|
|
938
|
+
onEvent(callback) {
|
|
939
|
+
if (!state.handles.fetch) {
|
|
940
|
+
throw new Error("Fetch handle not available");
|
|
941
|
+
}
|
|
942
|
+
return state.handles.fetch.onEvent(callback);
|
|
943
|
+
},
|
|
944
|
+
dispatchEvent(event, payload) {
|
|
945
|
+
if (!state.handles.fetch) {
|
|
946
|
+
throw new Error("Fetch handle not available");
|
|
947
|
+
}
|
|
948
|
+
state.handles.fetch.dispatchEvent(event, payload);
|
|
880
949
|
}
|
|
881
950
|
};
|
|
882
951
|
const timersHandle = {
|
|
@@ -961,45 +1030,101 @@ async function createRuntime(options) {
|
|
|
961
1030
|
testEnvironment: testEnvironmentHandle,
|
|
962
1031
|
playwright: playwrightHandle,
|
|
963
1032
|
async eval(code, filenameOrOptions) {
|
|
964
|
-
const
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
const transformed = await import_isolate_transform.transformEntryCode(code, filename);
|
|
968
|
-
if (transformed.sourceMap) {
|
|
969
|
-
state.sourceMaps.set(filename, transformed.sourceMap);
|
|
970
|
-
}
|
|
971
|
-
const mod = await state.isolate.compileModule(transformed.code, {
|
|
972
|
-
filename
|
|
973
|
-
});
|
|
974
|
-
state.moduleToFilename.set(mod, filename);
|
|
975
|
-
const resolver = createModuleResolver(state);
|
|
976
|
-
await mod.instantiate(state.context, resolver);
|
|
977
|
-
await mod.evaluate();
|
|
978
|
-
const ns = mod.namespace;
|
|
979
|
-
const runRef = await ns.get("default", { reference: true });
|
|
1033
|
+
const runEval = async () => {
|
|
1034
|
+
const options2 = typeof filenameOrOptions === "string" ? { filename: filenameOrOptions } : filenameOrOptions;
|
|
1035
|
+
const filename = import_isolate_protocol.normalizeEntryFilename(options2?.filename);
|
|
980
1036
|
try {
|
|
981
|
-
await
|
|
982
|
-
|
|
983
|
-
|
|
1037
|
+
const transformed = await import_isolate_transform.transformEntryCode(code, filename);
|
|
1038
|
+
if (transformed.sourceMap) {
|
|
1039
|
+
state.sourceMaps.set(filename, transformed.sourceMap);
|
|
1040
|
+
}
|
|
1041
|
+
const mod = await state.isolate.compileModule(transformed.code, {
|
|
1042
|
+
filename
|
|
984
1043
|
});
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1044
|
+
state.moduleToFilename.set(mod, filename);
|
|
1045
|
+
state.moduleImportChain.set(filename, []);
|
|
1046
|
+
const resolver = createModuleResolver(state);
|
|
1047
|
+
try {
|
|
1048
|
+
await mod.instantiate(state.context, resolver);
|
|
1049
|
+
} catch (err) {
|
|
1050
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1051
|
+
const specifierMatch = error.message.match(/The requested module '([^']+)'/);
|
|
1052
|
+
const exportMatch = error.message.match(/export named '([^']+)'/);
|
|
1053
|
+
const failingSpecifier = specifierMatch?.[1];
|
|
1054
|
+
const failingExport = exportMatch?.[1];
|
|
1055
|
+
const importerFile = failingSpecifier ? state.specifierToImporter.get(failingSpecifier) : undefined;
|
|
1056
|
+
const details = [];
|
|
1057
|
+
if (importerFile) {
|
|
1058
|
+
const chain = state.moduleImportChain.get(importerFile) ?? [];
|
|
1059
|
+
const fullChain = [...chain, importerFile];
|
|
1060
|
+
if (failingSpecifier)
|
|
1061
|
+
fullChain.push(failingSpecifier);
|
|
1062
|
+
const trimmed = fullChain.length > 12 ? fullChain.slice(-12) : fullChain;
|
|
1063
|
+
const prefix = fullChain.length > 12 ? ` ...
|
|
1064
|
+
` : "";
|
|
1065
|
+
details.push(`Import chain:
|
|
1066
|
+
` + prefix + trimmed.map((p) => ` ${p}`).join(`
|
|
1067
|
+
-> `));
|
|
1068
|
+
} else if (failingSpecifier) {
|
|
1069
|
+
for (const [modPath, chain] of state.moduleImportChain) {
|
|
1070
|
+
if (modPath.includes(failingSpecifier) || modPath.endsWith(failingSpecifier)) {
|
|
1071
|
+
const fullChain = [...chain, modPath];
|
|
1072
|
+
const trimmed = fullChain.length > 12 ? fullChain.slice(-12) : fullChain;
|
|
1073
|
+
details.push(`Import chain:
|
|
1074
|
+
` + trimmed.map((p) => ` ${p}`).join(`
|
|
1075
|
+
-> `));
|
|
1076
|
+
break;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
if (failingExport && failingSpecifier) {
|
|
1081
|
+
details.push(`Hint: If '${failingExport}' is a TypeScript type/interface, use \`import type\` to prevent it from being resolved at runtime:
|
|
1082
|
+
` + ` import type { ${failingExport} } from '${failingSpecifier}';`);
|
|
1083
|
+
}
|
|
1084
|
+
const suffix = details.length > 0 ? `
|
|
1085
|
+
|
|
1086
|
+
` + details.join(`
|
|
1087
|
+
|
|
1088
|
+
`) : "";
|
|
1089
|
+
error.message = `Module instantiation failed: ${error.message}${suffix}`;
|
|
1090
|
+
throw error;
|
|
1091
|
+
}
|
|
1092
|
+
await mod.evaluate();
|
|
1093
|
+
const ns = mod.namespace;
|
|
1094
|
+
const runRef = await ns.get("default", { reference: true });
|
|
1095
|
+
try {
|
|
1096
|
+
await runRef.apply(undefined, [], {
|
|
1097
|
+
result: { promise: true }
|
|
1098
|
+
});
|
|
1099
|
+
} finally {
|
|
1100
|
+
runRef.release();
|
|
1101
|
+
}
|
|
1102
|
+
if (state.pendingCallbacks.length > 0) {
|
|
1103
|
+
await Promise.all(state.pendingCallbacks);
|
|
1104
|
+
state.pendingCallbacks.length = 0;
|
|
1105
|
+
}
|
|
1106
|
+
} catch (err) {
|
|
1107
|
+
const error = err;
|
|
1108
|
+
if (error.stack && state.sourceMaps.size > 0) {
|
|
1109
|
+
error.stack = import_isolate_transform.mapErrorStack(error.stack, state.sourceMaps);
|
|
1110
|
+
}
|
|
1111
|
+
throw error;
|
|
996
1112
|
}
|
|
997
|
-
|
|
998
|
-
|
|
1113
|
+
};
|
|
1114
|
+
const queuedEval = state.evalChain.then(runEval, runEval);
|
|
1115
|
+
state.evalChain = queuedEval.then(() => {
|
|
1116
|
+
return;
|
|
1117
|
+
}, () => {
|
|
1118
|
+
return;
|
|
1119
|
+
});
|
|
1120
|
+
return queuedEval;
|
|
999
1121
|
},
|
|
1000
1122
|
clearModuleCache() {
|
|
1001
1123
|
state.moduleCache.clear();
|
|
1124
|
+
state.moduleLoadsInFlight.clear();
|
|
1002
1125
|
state.moduleToFilename.clear();
|
|
1126
|
+
state.moduleImportChain.clear();
|
|
1127
|
+
state.specifierToImporter.clear();
|
|
1003
1128
|
state.sourceMaps.clear();
|
|
1004
1129
|
},
|
|
1005
1130
|
async dispose() {
|
|
@@ -1017,10 +1142,11 @@ async function createRuntime(options) {
|
|
|
1017
1142
|
state.handles.console?.dispose();
|
|
1018
1143
|
state.handles.core?.dispose();
|
|
1019
1144
|
state.moduleCache.clear();
|
|
1145
|
+
state.moduleLoadsInFlight.clear();
|
|
1020
1146
|
state.context.release();
|
|
1021
1147
|
state.isolate.dispose();
|
|
1022
1148
|
}
|
|
1023
1149
|
};
|
|
1024
1150
|
}
|
|
1025
1151
|
|
|
1026
|
-
//# debugId=
|
|
1152
|
+
//# debugId=AFA261ED8389256764756E2164756E21
|