102 lines · 4.1 KB · TypeScript
RawDownload
/** * Build the ES module source that runs inside the dynamic Worker. * * The module exports a `WorkerEntrypoint` subclass with an `evaluate` * method that: * 1. Captures console output into `__logs`. * 2. Creates a recursive `tools` Proxy that dispatches calls via RPC. * 3. Executes the normalised user code with a `Promise.race` timeout. * 4. Returns `{ result, error?, logs }`. */export const buildExecutorModule = (body: string, timeoutMs: number): string =>  [    'import { WorkerEntrypoint } from "cloudflare:workers";',    "",    "export default class CodeExecutor extends WorkerEntrypoint {",    "  async evaluate(__dispatcher) {",    "    const __logs = [];",    '    console.log = (...a) => { __logs.push(a.map(String).join(" ")); };',    '    console.warn = (...a) => { __logs.push("[warn] " + a.map(String).join(" ")); };',    '    console.error = (...a) => { __logs.push("[error] " + a.map(String).join(" ")); };',    "    const __serializeErrorValue = (value) => {",    "      if (value instanceof Error) {",    "        return {",    "          __type: 'Error',",    "          name: value.name,",    "          message: value.message,",    "          ...(typeof value.stack === 'string' && value.stack.length > 0 ? { stack: value.stack } : {}),",    "        };",    "      }",    "      if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {",    "        return value;",    "      }",    "      try {",    "        return JSON.parse(JSON.stringify(value));",    "      } catch {",    "        return String(value);",    "      }",    "    };",    "    const __renderMessage = (value) => {",    "      if (typeof value === 'string') return value;",    "      if (value && typeof value === 'object' && value.__type === 'Error' && typeof value.message === 'string') {",    "        return value.message;",    "      }",    "      if (value instanceof Error) return value.message;",    "      if (value && typeof value === 'object' && typeof value.message === 'string') return value.message;",    "      if (typeof value === 'undefined') return 'Unknown error';",    "      if (value && typeof value === 'object') {",    "        try {",    "          return JSON.stringify(value);",    "        } catch {",    "          return String(value);",    "        }",    "      }",    "      return String(value);",    "    };",    "    const __serializeThrownError = (err) => {",    "      const primary = __serializeErrorValue(err);",    "      return {",    "        kind: 'unknown',",    "        message: __renderMessage(primary),",    "        primary,",    "        failures: [],",    "        defects: [],",    "        interrupted: false,",    "      };",    "    };",    "",    "    const __makeToolsProxy = (path = []) => new Proxy(() => undefined, {",    "      get(_target, prop) {",    "        if (prop === 'then' || typeof prop === 'symbol') return undefined;",    "        return __makeToolsProxy([...path, String(prop)]);",    "      },",    "      apply(_target, _thisArg, args) {",    "        const toolPath = path.join('.');",    "        if (!toolPath) throw new Error('Tool path missing in invocation');",    "        return __dispatcher.call(toolPath, JSON.stringify(args[0] ?? {})).then((raw) => {",    "          const data = JSON.parse(raw);",    "          if (!data.ok) {",    "            throw (data.error && data.error.primary !== null ? data.error.primary : data.error.message);",    "          }",    "          return data.result;",    "        });",    "      },",    "    });",    "    const tools = __makeToolsProxy();",    "",    "    try {",    "      const result = await Promise.race([",    "        (async () => {",    body,    "        })(),",    "        new Promise((_, reject) =>",    `          setTimeout(() => reject(new Error("Execution timed out after ${timeoutMs}ms")), ${timeoutMs})`,    "        ),",    "      ]);",    "      return { result, logs: __logs };",    "    } catch (err) {",    "      return { result: undefined, error: __serializeThrownError(err), logs: __logs };",    "    }",    "  }",    "}",  ].join("\n");