efa0b0578c
- 沙箱改用 quickjs-emscripten singlefile variant(wasm 內嵌 base64、同步載入), CF Workers 相容;sandbox.mjs 成 Node/Worker 共用 runtime-agnostic 核心。 - sha256 curated builtin 改「純 JS SHA-256 prelude 字串注入」,去掉 node:crypto / async Web Crypto host-call,Node/Worker 皆決定性(card content_hash 逐字等價)。 - index.ts 成可部署 Worker host(Hono,POST /→runCode),自足不走 TinyGo 模板流程。 - 補 wrangler.toml(arcrun-code / code.arcrun.dev)、tsconfig、DEPLOY.md。 - contract stability 修為 floating(過 registry zod schema 驗證)。 - 單測 12/12 全綠(含 card→envelope 與原模組 planCard 逐欄全等)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
51 lines
1.9 KiB
TypeScript
51 lines
1.9 KiB
TypeScript
/**
|
||
* arcrun `code` 零件 —— Worker host(可部署)
|
||
*
|
||
* POST / → { code, input?, limits? }
|
||
* → QuickJS-wasm 沙箱(./sandbox.mjs 的 runCode)
|
||
* → { success:true, data } | { success:false, error, error_type }
|
||
*
|
||
* 封裝=A(quickjs-emscripten singlefile variant):wasm 內嵌為 base64、同步載入,
|
||
* bundler 友善、無需 [[wasm_modules]] 綁定、無需 nodejs_compat(sandbox 用 TextEncoder 計 bytes)。
|
||
*
|
||
* 與其他 logic 零件不同:`code` 是自足 Worker(自帶 index.ts + sandbox.mjs + quickjs variant),
|
||
* 不走 component-worker-template 的 TinyGo-wasm bundling 流程。部署見 DEPLOY.md。
|
||
*/
|
||
|
||
import { Hono } from 'hono';
|
||
import { cors } from 'hono/cors';
|
||
// @ts-expect-error —— sandbox.mjs 為 runtime-agnostic JS 核心(Node 測試與 Worker 共用同一份)
|
||
import { runCode } from './sandbox.mjs';
|
||
|
||
const app = new Hono();
|
||
app.use('*', cors());
|
||
|
||
app.get('/', (c) => c.json({ ok: true, component: 'code' }));
|
||
|
||
app.post('/', async (c) => {
|
||
let body: { code?: unknown; input?: unknown; limits?: Record<string, number> };
|
||
try {
|
||
body = await c.req.json();
|
||
} catch {
|
||
return c.json({ success: false, error: 'request body must be JSON', error_type: 'ContractError' }, 400);
|
||
}
|
||
|
||
if (typeof body.code !== 'string') {
|
||
return c.json({ success: false, error: 'code (string) is required', error_type: 'ContractError' }, 400);
|
||
}
|
||
|
||
try {
|
||
const result = await runCode(body.code, body.input, { limits: body.limits });
|
||
// sandbox 永遠回結構化 envelope;success=false 仍以 200 帶 error_type 回(零件語義層錯,非 HTTP 錯)
|
||
return c.json(result);
|
||
} catch (e) {
|
||
// 理論上 runCode 自己 try/catch;這層是最後保險,Worker 絕不掛。
|
||
return c.json(
|
||
{ success: false, error: e instanceof Error ? e.message : String(e), error_type: 'SandboxError' },
|
||
500,
|
||
);
|
||
}
|
||
});
|
||
|
||
export default app;
|