97 lines
2.8 KiB
TypeScript
97 lines
2.8 KiB
TypeScript
// isolator/worker.ts
|
|
// No module cache to ensure fresh code for every execution.
|
|
|
|
const States = Object.freeze({
|
|
SUCCESS: "SUCCESS",
|
|
NOT_A_FUNCTION: "NOT_A_FUNCTION",
|
|
SCRIPT_ERROR: "ERROR",
|
|
});
|
|
|
|
self.onmessage = async (e) => {
|
|
const { code, request, environment, name } = e.data;
|
|
const logs: any[] = [];
|
|
const startTime = performance.now();
|
|
|
|
// Temporarily override console.log and console.error to capture logs
|
|
const oldConsoleLog = console.log;
|
|
const oldConsoleError = console.error;
|
|
console.log = (...args) => {
|
|
logs.push(args);
|
|
oldConsoleLog.apply(console, args);
|
|
};
|
|
console.error = (...args) => {
|
|
logs.push(args);
|
|
oldConsoleError.apply(console, args);
|
|
};
|
|
|
|
try {
|
|
// Make the environment object and response helpers available globally.
|
|
(self as any).environment = environment;
|
|
(self as any).FUNCTION_NAME = name;
|
|
(self as any).Response = (body = "", headers = {}, status = 200) => ({
|
|
body,
|
|
status,
|
|
headers,
|
|
});
|
|
(self as any).JsonResponse = (body = {}, headers = {}, status = 200) =>
|
|
(self as any).Response(
|
|
JSON.stringify(body),
|
|
{ "Content-Type": "application/json", ...headers },
|
|
status
|
|
);
|
|
(self as any).HtmlResponse = (body = "", headers = {}, status = 200) =>
|
|
(self as any).Response(
|
|
body,
|
|
{ "Content-Type": "text/html", ...headers },
|
|
status
|
|
);
|
|
(self as any).TextResponse = (body = "", headers = {}, status = 200) =>
|
|
(self as any).Response(
|
|
body,
|
|
{ "Content-Type": "text/plain", ...headers },
|
|
status
|
|
);
|
|
|
|
// Use a data URL to import the user's code as a fresh ES module on every execution.
|
|
const dataUrl = `data:text/javascript;base64,${btoa(
|
|
unescape(encodeURIComponent(code))
|
|
)}`;
|
|
const userModule = await import(dataUrl);
|
|
|
|
if (typeof userModule.default !== "function") {
|
|
throw new Error(
|
|
"Module does not have a default export or the export is not a function."
|
|
);
|
|
}
|
|
|
|
const userFn = userModule.default;
|
|
const result = await userFn(request);
|
|
const executionTime = performance.now() - startTime;
|
|
|
|
self.postMessage({
|
|
status: States.SUCCESS,
|
|
result,
|
|
logs,
|
|
environment: (self as any).environment, // Return the mutated environment.
|
|
execution_time: executionTime,
|
|
});
|
|
} catch (err) {
|
|
const executionTime = performance.now() - startTime;
|
|
self.postMessage({
|
|
status: States.SCRIPT_ERROR,
|
|
result: {
|
|
name: err.name,
|
|
message: err.message,
|
|
stack: err.stack,
|
|
},
|
|
logs,
|
|
environment,
|
|
execution_time: executionTime,
|
|
});
|
|
} finally {
|
|
// Restore original console functions
|
|
console.log = oldConsoleLog;
|
|
console.error = oldConsoleError;
|
|
}
|
|
};
|