1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// (c) easrng 2024 all rights reserved
import * as SuperJSON from "npm:superjson@2.2.1";
type Log = {
level: string;
args: unknown[];
};
async function execute(
code: string,
): Promise<{ ok: true; logs: Log[] } | { ok: false; error: string }> {
try {
const blob = new Blob([code], {
type: "text/tsx",
});
const url = URL.createObjectURL(blob);
const markStackStart = crypto.randomUUID();
const markStackEnd = crypto.randomUUID();
function cleanStack(stack: string) {
let lines: string[] = [];
for (const line of stack.split("\n")) {
if (line.includes(markStackEnd)) break;
lines.push(line.replace(url, "input.tsx"));
if (line.includes(markStackStart)) {
lines = [];
}
}
return lines.join("\n");
}
const logs: Log[] = [];
globalThis.console = new Proxy(console, {
get(target, key) {
const real = target[key];
if (typeof real === "function" && typeof key === "string") {
const fn = function(...args: any[]) {
logs.push({
level: key,
args,
});
return real.call(this, ...args);
};
Object.defineProperty(fn, "name", {
writable: true,
value: markStackStart,
});
return fn;
}
},
});
async function run() {
try {
await import(url);
} catch (e) {
logs.push({
level: "error",
args: [e.message],
});
}
}
Object.defineProperty(run, "name", {
writable: true,
value: markStackEnd,
});
await run();
URL.revokeObjectURL(url);
return {
ok: true,
logs,
};
} catch (error) {
return {
ok: false,
error: error.message,
};
}
}
export const serializedExecute = async (code: string) => SuperJSON.stringify(await execute(code));