@workerdeck/sandbox 1.0.0 → 1.1.0
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/build/index.d.mts +0 -1
- package/build/index.mjs +4 -3
- package/build/index.mjs.map +1 -1
- package/package.json +4 -4
package/build/index.d.mts
CHANGED
package/build/index.mjs
CHANGED
|
@@ -57,15 +57,16 @@ const PRELUDE = `
|
|
|
57
57
|
`;
|
|
58
58
|
async function loadEngine(variant) {
|
|
59
59
|
const resolved = await variant;
|
|
60
|
-
|
|
60
|
+
const unwrapped = "default" in resolved ? resolved.default : resolved;
|
|
61
|
+
return { module: await newQuickJSAsyncWASMModuleFromVariant(unwrapped) };
|
|
61
62
|
}
|
|
62
63
|
async function runScript(engine, options) {
|
|
63
64
|
const logs = [];
|
|
64
65
|
const deadline = Date.now() + (options.timeoutMs ?? 5e3);
|
|
65
66
|
let interruptedBy;
|
|
66
67
|
const runtime = engine.module.newRuntime();
|
|
67
|
-
runtime.setMemoryLimit(options.memoryLimitBytes ??
|
|
68
|
-
runtime.setMaxStackSize(options.maxStackSizeBytes ??
|
|
68
|
+
runtime.setMemoryLimit(options.memoryLimitBytes ?? 67108864);
|
|
69
|
+
runtime.setMaxStackSize(options.maxStackSizeBytes ?? 1048576);
|
|
69
70
|
runtime.setInterruptHandler(() => {
|
|
70
71
|
if (options.signal?.aborted) {
|
|
71
72
|
interruptedBy = "aborted";
|
package/build/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/vfs.ts","../src/run-script.ts"],"sourcesContent":["export type SandboxVfs = {\n read(path: string): string | undefined\n write(path: string, content: string): void\n list(dir?: string): string[]\n snapshot(): Record<string, string>\n}\n\nexport function normalizeVfsPath(path: string): string {\n const out: string[] = []\n for (const part of path.split('/')) {\n if (part === '' || part === '.') {\n continue\n }\n if (part === '..') {\n out.pop()\n continue\n }\n out.push(part)\n }\n return '/' + out.join('/')\n}\n\nexport function createVfs(seed?: Record<string, string>): SandboxVfs {\n const files = new Map<string, string>()\n const write = (path: string, content: string): void => {\n files.set(normalizeVfsPath(path), content)\n }\n for (const [path, content] of Object.entries(seed ?? {})) {\n write(path, content)\n }\n return {\n read(path) {\n return files.get(normalizeVfsPath(path))\n },\n write,\n list(dir = '/') {\n const prefix = normalizeVfsPath(dir)\n return [...files.keys()].filter((file) => prefix === '/' || file === prefix || file.startsWith(prefix + '/')).sort()\n },\n snapshot() {\n return Object.fromEntries(files)\n },\n }\n}\n","import {\n newQuickJSAsyncWASMModuleFromVariant,\n type QuickJSAsyncVariant,\n type QuickJSAsyncWASMModule,\n type QuickJSHandle,\n} from 'quickjs-emscripten-core'\nimport type { SandboxVfs } from './vfs.ts'\n\nconst PRELUDE = `\n\"use strict\";\n(() => {\n const fmt = (v) => {\n if (typeof v === 'string') return v\n if (v === undefined) return 'undefined'\n try { return JSON.stringify(v) } catch { return String(v) }\n }\n globalThis.console = Object.freeze({\n log: (...a) => __host_log('log', a.map(fmt).join(' ')),\n warn: (...a) => __host_log('warn', a.map(fmt).join(' ')),\n error: (...a) => __host_log('error', a.map(fmt).join(' ')),\n })\n globalThis.vfs = Object.freeze({\n read: (p) => __host_vfs_read(String(p)),\n write: (p, c) => { __host_vfs_write(String(p), String(c)) },\n list: (d) => JSON.parse(__host_vfs_list(d === undefined ? '/' : String(d))),\n })\n globalThis.fetchText = (u) => __host_fetch_text(String(u))\n})();\n`\n\nexport type SandboxEngine = { module: QuickJSAsyncWASMModule }\n\nexport type SandboxVariantInput =\n | QuickJSAsyncVariant\n | { default: QuickJSAsyncVariant }\n | Promise<QuickJSAsyncVariant | { default: QuickJSAsyncVariant }>\n\nexport async function loadEngine(variant: SandboxVariantInput): Promise<SandboxEngine> {\n const resolved = await variant\n const unwrapped = 'default' in resolved ? resolved.default : resolved\n return { module: await newQuickJSAsyncWASMModuleFromVariant(unwrapped) }\n}\n\nexport type SandboxLog = { level: 'log' | 'warn' | 'error'; text: string }\n\nexport type RunScriptOptions = {\n script: string\n vfs?: SandboxVfs\n fetchText?: (url: string) => Promise<string>\n memoryLimitBytes?: number\n timeoutMs?: number\n maxStackSizeBytes?: number\n signal?: AbortSignal\n}\n\nexport type RunScriptResult =\n | { ok: true; value: unknown; logs: SandboxLog[] }\n | {\n ok: false\n reason: 'exception' | 'timeout' | 'oom' | 'aborted'\n error: string\n logs: SandboxLog[]\n }\n\nexport async function runScript(engine: SandboxEngine, options: RunScriptOptions): Promise<RunScriptResult> {\n const logs: SandboxLog[] = []\n const deadline = Date.now() + (options.timeoutMs ?? 5000)\n let interruptedBy: 'timeout' | 'aborted' | undefined\n\n const runtime = engine.module.newRuntime()\n runtime.setMemoryLimit(options.memoryLimitBytes ?? 64 * 1024 * 1024)\n runtime.setMaxStackSize(options.maxStackSizeBytes ?? 1024 * 1024)\n runtime.setInterruptHandler(() => {\n if (options.signal?.aborted) {\n interruptedBy = 'aborted'\n return true\n }\n if (Date.now() > deadline) {\n interruptedBy = 'timeout'\n return true\n }\n return false\n })\n const context = runtime.newContext()\n\n const defineHostFn = (name: string, fn: (...args: QuickJSHandle[]) => QuickJSHandle | undefined): void => {\n const handle = context.newFunction(name, (...args) => fn(...args) ?? context.undefined)\n context.setProp(context.global, name, handle)\n handle.dispose()\n }\n\n try {\n defineHostFn('__host_log', (levelHandle, textHandle) => {\n const level = context.getString(levelHandle)\n logs.push({\n level: level === 'warn' || level === 'error' ? level : 'log',\n text: context.getString(textHandle),\n })\n return undefined\n })\n defineHostFn('__host_vfs_read', (pathHandle) => {\n const content = options.vfs?.read(context.getString(pathHandle))\n return content === undefined ? undefined : context.newString(content)\n })\n defineHostFn('__host_vfs_write', (pathHandle, contentHandle) => {\n if (!options.vfs) {\n throw new Error('vfs is not enabled for this execution')\n }\n options.vfs.write(context.getString(pathHandle), context.getString(contentHandle))\n return undefined\n })\n defineHostFn('__host_vfs_list', (dirHandle) => {\n const files = options.vfs?.list(context.getString(dirHandle)) ?? []\n return context.newString(JSON.stringify(files))\n })\n {\n const fetchText = options.fetchText\n const handle = context.newAsyncifiedFunction('__host_fetch_text', async (urlHandle) => {\n const url = context.getString(urlHandle)\n if (!fetchText) {\n throw new Error('network access is not enabled for this execution')\n }\n return context.newString(await fetchText(url))\n })\n context.setProp(context.global, '__host_fetch_text', handle)\n handle.dispose()\n }\n\n const prelude = await context.evalCodeAsync(PRELUDE, 'prelude.js')\n context.unwrapResult(prelude).dispose()\n\n const evaluated = await context.evalCodeAsync(options.script, 'script.js')\n if (evaluated.error) {\n const error = context.dump(evaluated.error)\n evaluated.error.dispose()\n return failure(error, interruptedBy, logs)\n }\n runtime.executePendingJobs()\n const evaluatedValue = evaluated.value\n const state = context.getPromiseState(evaluatedValue)\n if (state.type === 'pending') {\n const settledPromise = context.resolvePromise(evaluatedValue)\n runtime.executePendingJobs()\n const settled = await settledPromise\n evaluatedValue.dispose()\n if (settled.error) {\n const error = context.dump(settled.error)\n settled.error.dispose()\n return failure(error, interruptedBy, logs)\n }\n const value = context.dump(settled.value)\n settled.value.dispose()\n return { ok: true, value, logs }\n }\n if (state.type === 'rejected') {\n const error = context.dump(state.error)\n evaluatedValue.dispose()\n return failure(error, interruptedBy, logs)\n }\n const resultHandle = state.type === 'fulfilled' && !state.notAPromise ? state.value : evaluatedValue\n const value = context.dump(resultHandle)\n if (resultHandle !== evaluatedValue) {\n resultHandle.dispose()\n }\n evaluatedValue.dispose()\n return { ok: true, value, logs }\n } catch (error) {\n return failure(error instanceof Error ? error.message : String(error), interruptedBy, logs)\n } finally {\n context.dispose()\n runtime.dispose()\n }\n}\n\nfunction failure(error: unknown, interruptedBy: 'timeout' | 'aborted' | undefined, logs: SandboxLog[]): RunScriptResult {\n const text = describeGuestError(error)\n const reason = interruptedBy ?? (/out of memory/i.test(text) ? 'oom' : 'exception')\n return { ok: false, reason, error: text, logs }\n}\n\nfunction describeGuestError(error: unknown): string {\n if (typeof error === 'string') {\n return error\n }\n if (error && typeof error === 'object') {\n const e = error as { name?: unknown; message?: unknown }\n const name = typeof e.name === 'string' ? e.name : undefined\n const message = typeof e.message === 'string' ? e.message : undefined\n if (name || message) {\n return [name, message].filter(Boolean).join(': ')\n }\n try {\n return JSON.stringify(error)\n } catch {\n return String(error)\n }\n }\n return String(error)\n}\n"],"mappings":";;AAOA,SAAgB,iBAAiB,MAAsB;CACrD,MAAM,MAAgB,EAAE;AACxB,MAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,EAAE;AAClC,MAAI,SAAS,MAAM,SAAS,IAC1B;AAEF,MAAI,SAAS,MAAM;AACjB,OAAI,KAAK;AACT;;AAEF,MAAI,KAAK,KAAK;;AAEhB,QAAO,MAAM,IAAI,KAAK,IAAI;;AAG5B,SAAgB,UAAU,MAA2C;CACnE,MAAM,wBAAQ,IAAI,KAAqB;CACvC,MAAM,SAAS,MAAc,YAA0B;AACrD,QAAM,IAAI,iBAAiB,KAAK,EAAE,QAAQ;;AAE5C,MAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,QAAQ,EAAE,CAAC,CACtD,OAAM,MAAM,QAAQ;AAEtB,QAAO;EACL,KAAK,MAAM;AACT,UAAO,MAAM,IAAI,iBAAiB,KAAK,CAAC;;EAE1C;EACA,KAAK,MAAM,KAAK;GACd,MAAM,SAAS,iBAAiB,IAAI;AACpC,UAAO,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,QAAQ,SAAS,WAAW,OAAO,SAAS,UAAU,KAAK,WAAW,SAAS,IAAI,CAAC,CAAC,MAAM;;EAEtH,WAAW;AACT,UAAO,OAAO,YAAY,MAAM;;EAEnC;;;;AClCH,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;AA6BhB,eAAsB,WAAW,SAAsD;CACrF,MAAM,WAAW,MAAM;AAEvB,QAAO,EAAE,QAAQ,MAAM,qCADL,aAAa,WAAW,SAAS,UAAU,SACS,EAAE;;AAwB1E,eAAsB,UAAU,QAAuB,SAAqD;CAC1G,MAAM,OAAqB,EAAE;CAC7B,MAAM,WAAW,KAAK,KAAK,IAAI,QAAQ,aAAa;CACpD,IAAI;CAEJ,MAAM,UAAU,OAAO,OAAO,YAAY;AAC1C,SAAQ,eAAe,QAAQ,oBAAoB,KAAK,OAAO,KAAK;AACpE,SAAQ,gBAAgB,QAAQ,qBAAqB,OAAO,KAAK;AACjE,SAAQ,0BAA0B;AAChC,MAAI,QAAQ,QAAQ,SAAS;AAC3B,mBAAgB;AAChB,UAAO;;AAET,MAAI,KAAK,KAAK,GAAG,UAAU;AACzB,mBAAgB;AAChB,UAAO;;AAET,SAAO;GACP;CACF,MAAM,UAAU,QAAQ,YAAY;CAEpC,MAAM,gBAAgB,MAAc,OAAsE;EACxG,MAAM,SAAS,QAAQ,YAAY,OAAO,GAAG,SAAS,GAAG,GAAG,KAAK,IAAI,QAAQ,UAAU;AACvF,UAAQ,QAAQ,QAAQ,QAAQ,MAAM,OAAO;AAC7C,SAAO,SAAS;;AAGlB,KAAI;AACF,eAAa,eAAe,aAAa,eAAe;GACtD,MAAM,QAAQ,QAAQ,UAAU,YAAY;AAC5C,QAAK,KAAK;IACR,OAAO,UAAU,UAAU,UAAU,UAAU,QAAQ;IACvD,MAAM,QAAQ,UAAU,WAAW;IACpC,CAAC;IAEF;AACF,eAAa,oBAAoB,eAAe;GAC9C,MAAM,UAAU,QAAQ,KAAK,KAAK,QAAQ,UAAU,WAAW,CAAC;AAChE,UAAO,YAAY,KAAA,IAAY,KAAA,IAAY,QAAQ,UAAU,QAAQ;IACrE;AACF,eAAa,qBAAqB,YAAY,kBAAkB;AAC9D,OAAI,CAAC,QAAQ,IACX,OAAM,IAAI,MAAM,wCAAwC;AAE1D,WAAQ,IAAI,MAAM,QAAQ,UAAU,WAAW,EAAE,QAAQ,UAAU,cAAc,CAAC;IAElF;AACF,eAAa,oBAAoB,cAAc;GAC7C,MAAM,QAAQ,QAAQ,KAAK,KAAK,QAAQ,UAAU,UAAU,CAAC,IAAI,EAAE;AACnE,UAAO,QAAQ,UAAU,KAAK,UAAU,MAAM,CAAC;IAC/C;EACF;GACE,MAAM,YAAY,QAAQ;GAC1B,MAAM,SAAS,QAAQ,sBAAsB,qBAAqB,OAAO,cAAc;IACrF,MAAM,MAAM,QAAQ,UAAU,UAAU;AACxC,QAAI,CAAC,UACH,OAAM,IAAI,MAAM,mDAAmD;AAErE,WAAO,QAAQ,UAAU,MAAM,UAAU,IAAI,CAAC;KAC9C;AACF,WAAQ,QAAQ,QAAQ,QAAQ,qBAAqB,OAAO;AAC5D,UAAO,SAAS;;EAGlB,MAAM,UAAU,MAAM,QAAQ,cAAc,SAAS,aAAa;AAClE,UAAQ,aAAa,QAAQ,CAAC,SAAS;EAEvC,MAAM,YAAY,MAAM,QAAQ,cAAc,QAAQ,QAAQ,YAAY;AAC1E,MAAI,UAAU,OAAO;GACnB,MAAM,QAAQ,QAAQ,KAAK,UAAU,MAAM;AAC3C,aAAU,MAAM,SAAS;AACzB,UAAO,QAAQ,OAAO,eAAe,KAAK;;AAE5C,UAAQ,oBAAoB;EAC5B,MAAM,iBAAiB,UAAU;EACjC,MAAM,QAAQ,QAAQ,gBAAgB,eAAe;AACrD,MAAI,MAAM,SAAS,WAAW;GAC5B,MAAM,iBAAiB,QAAQ,eAAe,eAAe;AAC7D,WAAQ,oBAAoB;GAC5B,MAAM,UAAU,MAAM;AACtB,kBAAe,SAAS;AACxB,OAAI,QAAQ,OAAO;IACjB,MAAM,QAAQ,QAAQ,KAAK,QAAQ,MAAM;AACzC,YAAQ,MAAM,SAAS;AACvB,WAAO,QAAQ,OAAO,eAAe,KAAK;;GAE5C,MAAM,QAAQ,QAAQ,KAAK,QAAQ,MAAM;AACzC,WAAQ,MAAM,SAAS;AACvB,UAAO;IAAE,IAAI;IAAM;IAAO;IAAM;;AAElC,MAAI,MAAM,SAAS,YAAY;GAC7B,MAAM,QAAQ,QAAQ,KAAK,MAAM,MAAM;AACvC,kBAAe,SAAS;AACxB,UAAO,QAAQ,OAAO,eAAe,KAAK;;EAE5C,MAAM,eAAe,MAAM,SAAS,eAAe,CAAC,MAAM,cAAc,MAAM,QAAQ;EACtF,MAAM,QAAQ,QAAQ,KAAK,aAAa;AACxC,MAAI,iBAAiB,eACnB,cAAa,SAAS;AAExB,iBAAe,SAAS;AACxB,SAAO;GAAE,IAAI;GAAM;GAAO;GAAM;UACzB,OAAO;AACd,SAAO,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,eAAe,KAAK;WACnF;AACR,UAAQ,SAAS;AACjB,UAAQ,SAAS;;;AAIrB,SAAS,QAAQ,OAAgB,eAAkD,MAAqC;CACtH,MAAM,OAAO,mBAAmB,MAAM;AAEtC,QAAO;EAAE,IAAI;EAAO,QADL,kBAAkB,iBAAiB,KAAK,KAAK,GAAG,QAAQ;EAC3C,OAAO;EAAM;EAAM;;AAGjD,SAAS,mBAAmB,OAAwB;AAClD,KAAI,OAAO,UAAU,SACnB,QAAO;AAET,KAAI,SAAS,OAAO,UAAU,UAAU;EACtC,MAAM,IAAI;EACV,MAAM,OAAO,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO,KAAA;EACnD,MAAM,UAAU,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,KAAA;AAC5D,MAAI,QAAQ,QACV,QAAO,CAAC,MAAM,QAAQ,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;AAEnD,MAAI;AACF,UAAO,KAAK,UAAU,MAAM;UACtB;AACN,UAAO,OAAO,MAAM;;;AAGxB,QAAO,OAAO,MAAM"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/vfs.ts","../src/run-script.ts"],"sourcesContent":["export type SandboxVfs = {\n read(path: string): string | undefined\n write(path: string, content: string): void\n list(dir?: string): string[]\n snapshot(): Record<string, string>\n}\n\nexport function normalizeVfsPath(path: string): string {\n const out: string[] = []\n for (const part of path.split('/')) {\n if (part === '' || part === '.') {\n continue\n }\n if (part === '..') {\n out.pop()\n continue\n }\n out.push(part)\n }\n return '/' + out.join('/')\n}\n\nexport function createVfs(seed?: Record<string, string>): SandboxVfs {\n const files = new Map<string, string>()\n const write = (path: string, content: string): void => {\n files.set(normalizeVfsPath(path), content)\n }\n for (const [path, content] of Object.entries(seed ?? {})) {\n write(path, content)\n }\n return {\n read(path) {\n return files.get(normalizeVfsPath(path))\n },\n write,\n list(dir = '/') {\n const prefix = normalizeVfsPath(dir)\n return [...files.keys()].filter((file) => prefix === '/' || file === prefix || file.startsWith(prefix + '/')).sort()\n },\n snapshot() {\n return Object.fromEntries(files)\n },\n }\n}\n","import {\n newQuickJSAsyncWASMModuleFromVariant,\n type QuickJSAsyncVariant,\n type QuickJSAsyncWASMModule,\n type QuickJSHandle,\n} from 'quickjs-emscripten-core'\nimport type { SandboxVfs } from './vfs.ts'\n\nconst PRELUDE = `\n\"use strict\";\n(() => {\n const fmt = (v) => {\n if (typeof v === 'string') return v\n if (v === undefined) return 'undefined'\n try { return JSON.stringify(v) } catch { return String(v) }\n }\n globalThis.console = Object.freeze({\n log: (...a) => __host_log('log', a.map(fmt).join(' ')),\n warn: (...a) => __host_log('warn', a.map(fmt).join(' ')),\n error: (...a) => __host_log('error', a.map(fmt).join(' ')),\n })\n globalThis.vfs = Object.freeze({\n read: (p) => __host_vfs_read(String(p)),\n write: (p, c) => { __host_vfs_write(String(p), String(c)) },\n list: (d) => JSON.parse(__host_vfs_list(d === undefined ? '/' : String(d))),\n })\n globalThis.fetchText = (u) => __host_fetch_text(String(u))\n})();\n`\n\nexport type SandboxEngine = { module: QuickJSAsyncWASMModule }\n\nexport type SandboxVariantInput =\n | QuickJSAsyncVariant\n | { default: QuickJSAsyncVariant }\n | Promise<QuickJSAsyncVariant | { default: QuickJSAsyncVariant }>\n\nexport async function loadEngine(variant: SandboxVariantInput): Promise<SandboxEngine> {\n const resolved = await variant\n const unwrapped = 'default' in resolved ? resolved.default : resolved\n return { module: await newQuickJSAsyncWASMModuleFromVariant(unwrapped) }\n}\n\nexport type SandboxLog = { level: 'log' | 'warn' | 'error'; text: string }\n\nexport type RunScriptOptions = {\n script: string\n vfs?: SandboxVfs\n fetchText?: (url: string) => Promise<string>\n memoryLimitBytes?: number\n timeoutMs?: number\n maxStackSizeBytes?: number\n signal?: AbortSignal\n}\n\nexport type RunScriptResult =\n | { ok: true; value: unknown; logs: SandboxLog[] }\n | {\n ok: false\n reason: 'exception' | 'timeout' | 'oom' | 'aborted'\n error: string\n logs: SandboxLog[]\n }\n\nexport async function runScript(engine: SandboxEngine, options: RunScriptOptions): Promise<RunScriptResult> {\n const logs: SandboxLog[] = []\n const deadline = Date.now() + (options.timeoutMs ?? 5000)\n let interruptedBy: 'timeout' | 'aborted' | undefined\n\n const runtime = engine.module.newRuntime()\n runtime.setMemoryLimit(options.memoryLimitBytes ?? 64 * 1024 * 1024)\n runtime.setMaxStackSize(options.maxStackSizeBytes ?? 1024 * 1024)\n runtime.setInterruptHandler(() => {\n if (options.signal?.aborted) {\n interruptedBy = 'aborted'\n return true\n }\n if (Date.now() > deadline) {\n interruptedBy = 'timeout'\n return true\n }\n return false\n })\n const context = runtime.newContext()\n\n const defineHostFn = (name: string, fn: (...args: QuickJSHandle[]) => QuickJSHandle | undefined): void => {\n const handle = context.newFunction(name, (...args) => fn(...args) ?? context.undefined)\n context.setProp(context.global, name, handle)\n handle.dispose()\n }\n\n try {\n defineHostFn('__host_log', (levelHandle, textHandle) => {\n const level = context.getString(levelHandle)\n logs.push({\n level: level === 'warn' || level === 'error' ? level : 'log',\n text: context.getString(textHandle),\n })\n return undefined\n })\n defineHostFn('__host_vfs_read', (pathHandle) => {\n const content = options.vfs?.read(context.getString(pathHandle))\n return content === undefined ? undefined : context.newString(content)\n })\n defineHostFn('__host_vfs_write', (pathHandle, contentHandle) => {\n if (!options.vfs) {\n throw new Error('vfs is not enabled for this execution')\n }\n options.vfs.write(context.getString(pathHandle), context.getString(contentHandle))\n return undefined\n })\n defineHostFn('__host_vfs_list', (dirHandle) => {\n const files = options.vfs?.list(context.getString(dirHandle)) ?? []\n return context.newString(JSON.stringify(files))\n })\n {\n const fetchText = options.fetchText\n const handle = context.newAsyncifiedFunction('__host_fetch_text', async (urlHandle) => {\n const url = context.getString(urlHandle)\n if (!fetchText) {\n throw new Error('network access is not enabled for this execution')\n }\n return context.newString(await fetchText(url))\n })\n context.setProp(context.global, '__host_fetch_text', handle)\n handle.dispose()\n }\n\n const prelude = await context.evalCodeAsync(PRELUDE, 'prelude.js')\n context.unwrapResult(prelude).dispose()\n\n const evaluated = await context.evalCodeAsync(options.script, 'script.js')\n if (evaluated.error) {\n const error = context.dump(evaluated.error)\n evaluated.error.dispose()\n return failure(error, interruptedBy, logs)\n }\n runtime.executePendingJobs()\n const evaluatedValue = evaluated.value\n const state = context.getPromiseState(evaluatedValue)\n if (state.type === 'pending') {\n const settledPromise = context.resolvePromise(evaluatedValue)\n runtime.executePendingJobs()\n const settled = await settledPromise\n evaluatedValue.dispose()\n if (settled.error) {\n const error = context.dump(settled.error)\n settled.error.dispose()\n return failure(error, interruptedBy, logs)\n }\n const value = context.dump(settled.value)\n settled.value.dispose()\n return { ok: true, value, logs }\n }\n if (state.type === 'rejected') {\n const error = context.dump(state.error)\n evaluatedValue.dispose()\n return failure(error, interruptedBy, logs)\n }\n const resultHandle = state.type === 'fulfilled' && !state.notAPromise ? state.value : evaluatedValue\n const value = context.dump(resultHandle)\n if (resultHandle !== evaluatedValue) {\n resultHandle.dispose()\n }\n evaluatedValue.dispose()\n return { ok: true, value, logs }\n } catch (error) {\n return failure(error instanceof Error ? error.message : String(error), interruptedBy, logs)\n } finally {\n context.dispose()\n runtime.dispose()\n }\n}\n\nfunction failure(error: unknown, interruptedBy: 'timeout' | 'aborted' | undefined, logs: SandboxLog[]): RunScriptResult {\n const text = describeGuestError(error)\n const reason = interruptedBy ?? (/out of memory/i.test(text) ? 'oom' : 'exception')\n return { ok: false, reason, error: text, logs }\n}\n\nfunction describeGuestError(error: unknown): string {\n if (typeof error === 'string') {\n return error\n }\n if (error && typeof error === 'object') {\n const e = error as { name?: unknown; message?: unknown }\n const name = typeof e.name === 'string' ? e.name : undefined\n const message = typeof e.message === 'string' ? e.message : undefined\n if (name || message) {\n return [name, message].filter(Boolean).join(': ')\n }\n try {\n return JSON.stringify(error)\n } catch {\n return String(error)\n }\n }\n return String(error)\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workerdeck/sandbox",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The WorkerDeck execution sandbox: QuickJS-NG-in-WASM guest for untrusted, LLM-generated scripts with an in-memory scratch VFS, a hardened by-value host bridge (capability host functions only — no ambient fs/network), and interpreter-enforced memory + wall-clock limits. Engine-variant-injected so server (Node asyncify) and browser (singlefile asyncify) share one guest engine. Leaf package: depends on neither core/server nor any model SDK.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@jitl/quickjs-ng-wasmfile-release-asyncify": "^0.31.0",
|
|
24
|
-
"@types/node": "^
|
|
24
|
+
"@types/node": "^26.4.0",
|
|
25
25
|
"rimraf": "^6.1.3",
|
|
26
|
-
"tsdown": "^0.
|
|
27
|
-
"vitest": "^
|
|
26
|
+
"tsdown": "^0.22.14",
|
|
27
|
+
"vitest": "^4.1.11"
|
|
28
28
|
},
|
|
29
29
|
"author": "Tobias Strebitzer",
|
|
30
30
|
"repository": {
|