@executor-js/runtime-quickjs 0.0.1-beta.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.
@@ -0,0 +1,10 @@
1
+ import { type CodeExecutor } from "@executor-js/codemode-core";
2
+ import { type QuickJSWASMModule } from "quickjs-emscripten";
3
+ export type QuickJsExecutorOptions = {
4
+ timeoutMs?: number;
5
+ memoryLimitBytes?: number;
6
+ maxStackSizeBytes?: number;
7
+ };
8
+ export declare const setQuickJSModule: (mod: QuickJSWASMModule) => void;
9
+ export declare const makeQuickJsExecutor: (options?: QuickJsExecutorOptions) => CodeExecutor;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAOL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAKF,eAAO,MAAM,gBAAgB,GAAI,KAAK,iBAAiB,SAEtD,CAAC;AA6WF,eAAO,MAAM,mBAAmB,GAAI,UAAS,sBAA2B,KAAG,YAGzE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,293 @@
1
+ // src/index.ts
2
+ import {
3
+ recoverExecutionBody
4
+ } from "@executor-js/codemode-core";
5
+ import * as Data from "effect/Data";
6
+ import * as Effect from "effect/Effect";
7
+ import {
8
+ getQuickJS,
9
+ shouldInterruptAfterDeadline
10
+ } from "quickjs-emscripten";
11
+ var preloadedModule = null;
12
+ var setQuickJSModule = (mod) => {
13
+ preloadedModule = mod;
14
+ };
15
+ var resolveQuickJS = () => preloadedModule ? Promise.resolve(preloadedModule) : getQuickJS();
16
+ var QuickJsExecutionError = class extends Data.TaggedError("QuickJsExecutionError") {
17
+ };
18
+ var DEFAULT_TIMEOUT_MS = 5 * 6e4;
19
+ var EXECUTION_FILENAME = "executor-quickjs-runtime.js";
20
+ var toError = (cause) => cause instanceof Error ? cause : new Error(String(cause));
21
+ var toErrorMessage = (cause) => {
22
+ if (typeof cause === "object" && cause !== null) {
23
+ const stack = "stack" in cause && typeof cause.stack === "string" ? cause.stack : void 0;
24
+ const message = "message" in cause && typeof cause.message === "string" ? cause.message : void 0;
25
+ if (stack) {
26
+ return stack;
27
+ }
28
+ if (message) {
29
+ return message;
30
+ }
31
+ }
32
+ const error = toError(cause);
33
+ return error.stack ?? error.message;
34
+ };
35
+ var serializeJson = (value, label) => {
36
+ if (typeof value === "undefined") {
37
+ return void 0;
38
+ }
39
+ try {
40
+ return JSON.stringify(value);
41
+ } catch (cause) {
42
+ throw new Error(`${label} is not JSON serializable: ${toError(cause).message}`);
43
+ }
44
+ };
45
+ var looksLikeInterruptedError = (message) => /\binterrupted\b/i.test(message);
46
+ var timeoutMessage = (timeoutMs) => `QuickJS execution timed out after ${timeoutMs}ms`;
47
+ var normalizeExecutionError = (cause, deadlineMs, timeoutMs) => {
48
+ const message = toErrorMessage(cause);
49
+ return Date.now() >= deadlineMs && looksLikeInterruptedError(message) ? timeoutMessage(timeoutMs) : message;
50
+ };
51
+ var buildExecutionSource = (code) => {
52
+ const body = recoverExecutionBody(code);
53
+ return [
54
+ '"use strict";',
55
+ "const __invokeTool = __executor_invokeTool;",
56
+ "const __log = __executor_log;",
57
+ "try { delete globalThis.__executor_invokeTool; } catch {}",
58
+ "try { delete globalThis.__executor_log; } catch {}",
59
+ "const __formatLogArg = (value) => {",
60
+ " if (typeof value === 'string') return value;",
61
+ " try {",
62
+ " return JSON.stringify(value);",
63
+ " } catch {",
64
+ " return String(value);",
65
+ " }",
66
+ "};",
67
+ "const __formatLogLine = (args) => args.map(__formatLogArg).join(' ');",
68
+ "const __makeToolsProxy = (path = []) => new Proxy(() => undefined, {",
69
+ " get(_target, prop) {",
70
+ " if (prop === 'then' || typeof prop === 'symbol') {",
71
+ " return undefined;",
72
+ " }",
73
+ " return __makeToolsProxy([...path, String(prop)]);",
74
+ " },",
75
+ " apply(_target, _thisArg, args) {",
76
+ " const toolPath = path.join('.');",
77
+ " if (!toolPath) {",
78
+ " throw new Error('Tool path missing in invocation');",
79
+ " }",
80
+ " return Promise.resolve(__invokeTool(toolPath, args[0])).then((raw) => raw === undefined ? undefined : JSON.parse(raw));",
81
+ " },",
82
+ "});",
83
+ "const tools = __makeToolsProxy();",
84
+ "const console = {",
85
+ " log: (...args) => __log('log', __formatLogLine(args)),",
86
+ " warn: (...args) => __log('warn', __formatLogLine(args)),",
87
+ " error: (...args) => __log('error', __formatLogLine(args)),",
88
+ " info: (...args) => __log('info', __formatLogLine(args)),",
89
+ " debug: (...args) => __log('debug', __formatLogLine(args)),",
90
+ "};",
91
+ "const fetch = (..._args) => {",
92
+ " throw new Error('fetch is disabled in QuickJS executor');",
93
+ "};",
94
+ "(async () => {",
95
+ body,
96
+ "})()"
97
+ ].join("\n");
98
+ };
99
+ var readPropDump = (context, handle, key) => {
100
+ const prop = context.getProp(handle, key);
101
+ try {
102
+ return context.dump(prop);
103
+ } finally {
104
+ prop.dispose();
105
+ }
106
+ };
107
+ var readResultState = (context, handle) => ({
108
+ settled: readPropDump(context, handle, "settled") === true,
109
+ value: readPropDump(context, handle, "v"),
110
+ error: readPropDump(context, handle, "e")
111
+ });
112
+ var createLogBridge = (context, logs) => context.newFunction("__executor_log", (levelHandle, lineHandle) => {
113
+ const level = context.getString(levelHandle);
114
+ const line = context.getString(lineHandle);
115
+ logs.push(`[${level}] ${line}`);
116
+ return context.undefined;
117
+ });
118
+ var createToolBridge = (context, toolInvoker, pendingDeferreds) => context.newFunction("__executor_invokeTool", (pathHandle, argsHandle) => {
119
+ const path = context.getString(pathHandle);
120
+ const args = argsHandle === void 0 || context.typeof(argsHandle) === "undefined" ? void 0 : context.dump(argsHandle);
121
+ const deferred = context.newPromise();
122
+ pendingDeferreds.add(deferred);
123
+ deferred.settled.finally(() => {
124
+ pendingDeferreds.delete(deferred);
125
+ });
126
+ void Effect.runPromise(toolInvoker.invoke({ path, args })).then(
127
+ (value) => {
128
+ if (!deferred.alive) {
129
+ return;
130
+ }
131
+ const serialized = serializeJson(value, `Tool result for ${path}`);
132
+ if (typeof serialized === "undefined") {
133
+ deferred.resolve();
134
+ return;
135
+ }
136
+ const valueHandle = context.newString(serialized);
137
+ deferred.resolve(valueHandle);
138
+ valueHandle.dispose();
139
+ },
140
+ (cause) => {
141
+ if (!deferred.alive) {
142
+ return;
143
+ }
144
+ const errorHandle = context.newError(toErrorMessage(cause));
145
+ deferred.reject(errorHandle);
146
+ errorHandle.dispose();
147
+ }
148
+ );
149
+ return deferred.handle;
150
+ });
151
+ var drainJobs = (context, runtime, deadlineMs, timeoutMs) => {
152
+ while (runtime.hasPendingJob()) {
153
+ if (Date.now() >= deadlineMs) {
154
+ throw new Error(timeoutMessage(timeoutMs));
155
+ }
156
+ const pending = runtime.executePendingJobs();
157
+ if (pending.error) {
158
+ const error = context.dump(pending.error);
159
+ pending.error.dispose();
160
+ throw toError(error);
161
+ }
162
+ }
163
+ };
164
+ var waitForDeferreds = async (pendingDeferreds, deadlineMs, timeoutMs) => {
165
+ const remainingMs = deadlineMs - Date.now();
166
+ if (remainingMs <= 0) {
167
+ throw new Error(timeoutMessage(timeoutMs));
168
+ }
169
+ let timer;
170
+ try {
171
+ await Promise.race([
172
+ Promise.race([...pendingDeferreds].map((deferred) => deferred.settled)),
173
+ new Promise((_, reject) => {
174
+ timer = setTimeout(() => reject(new Error(timeoutMessage(timeoutMs))), remainingMs);
175
+ })
176
+ ]);
177
+ } finally {
178
+ if (timer !== void 0) {
179
+ clearTimeout(timer);
180
+ }
181
+ }
182
+ };
183
+ var drainAsync = async (context, runtime, pendingDeferreds, deadlineMs, timeoutMs) => {
184
+ drainJobs(context, runtime, deadlineMs, timeoutMs);
185
+ while (pendingDeferreds.size > 0) {
186
+ await waitForDeferreds(pendingDeferreds, deadlineMs, timeoutMs);
187
+ drainJobs(context, runtime, deadlineMs, timeoutMs);
188
+ }
189
+ drainJobs(context, runtime, deadlineMs, timeoutMs);
190
+ };
191
+ var evaluateInQuickJs = async (options, code, toolInvoker) => {
192
+ const timeoutMs = Math.max(100, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
193
+ const deadlineMs = Date.now() + timeoutMs;
194
+ const logs = [];
195
+ const pendingDeferreds = /* @__PURE__ */ new Set();
196
+ const QuickJS = await resolveQuickJS();
197
+ const runtime = QuickJS.newRuntime();
198
+ try {
199
+ if (options.memoryLimitBytes !== void 0) {
200
+ runtime.setMemoryLimit(options.memoryLimitBytes);
201
+ }
202
+ if (options.maxStackSizeBytes !== void 0) {
203
+ runtime.setMaxStackSize(options.maxStackSizeBytes);
204
+ }
205
+ runtime.setInterruptHandler(shouldInterruptAfterDeadline(deadlineMs));
206
+ const context = runtime.newContext();
207
+ try {
208
+ const logBridge = createLogBridge(context, logs);
209
+ context.setProp(context.global, "__executor_log", logBridge);
210
+ logBridge.dispose();
211
+ const toolBridge = createToolBridge(context, toolInvoker, pendingDeferreds);
212
+ context.setProp(context.global, "__executor_invokeTool", toolBridge);
213
+ toolBridge.dispose();
214
+ const evaluated = context.evalCode(buildExecutionSource(code), EXECUTION_FILENAME);
215
+ if (evaluated.error) {
216
+ const error = context.dump(evaluated.error);
217
+ evaluated.error.dispose();
218
+ return {
219
+ result: null,
220
+ error: normalizeExecutionError(error, deadlineMs, timeoutMs),
221
+ logs
222
+ };
223
+ }
224
+ context.setProp(context.global, "__executor_result", evaluated.value);
225
+ evaluated.value.dispose();
226
+ const stateResult = context.evalCode(
227
+ "(function(p){ var s = { v: void 0, e: void 0, settled: false }; var formatError = function(e){ if (e && typeof e === 'object') { var message = typeof e.message === 'string' ? e.message : ''; var stack = typeof e.stack === 'string' ? e.stack : ''; if (message && stack) { return stack.indexOf(message) === -1 ? message + '\\n' + stack : stack; } if (message) return message; if (stack) return stack; } return String(e); }; p.then(function(v){ s.v = v; s.settled = true; }, function(e){ s.e = formatError(e); s.settled = true; }); return s; })(__executor_result)"
228
+ );
229
+ if (stateResult.error) {
230
+ const error = context.dump(stateResult.error);
231
+ stateResult.error.dispose();
232
+ return {
233
+ result: null,
234
+ error: normalizeExecutionError(error, deadlineMs, timeoutMs),
235
+ logs
236
+ };
237
+ }
238
+ const stateHandle = stateResult.value;
239
+ try {
240
+ await drainAsync(context, runtime, pendingDeferreds, deadlineMs, timeoutMs);
241
+ const state = readResultState(context, stateHandle);
242
+ if (!state.settled) {
243
+ return {
244
+ result: null,
245
+ error: timeoutMessage(timeoutMs),
246
+ logs
247
+ };
248
+ }
249
+ if (typeof state.error !== "undefined") {
250
+ return {
251
+ result: null,
252
+ error: normalizeExecutionError(state.error, deadlineMs, timeoutMs),
253
+ logs
254
+ };
255
+ }
256
+ return {
257
+ result: state.value,
258
+ logs
259
+ };
260
+ } finally {
261
+ stateHandle.dispose();
262
+ }
263
+ } finally {
264
+ for (const deferred of pendingDeferreds) {
265
+ if (deferred.alive) {
266
+ deferred.dispose();
267
+ }
268
+ }
269
+ pendingDeferreds.clear();
270
+ context.dispose();
271
+ }
272
+ } catch (cause) {
273
+ return {
274
+ result: null,
275
+ error: normalizeExecutionError(cause, deadlineMs, timeoutMs),
276
+ logs
277
+ };
278
+ } finally {
279
+ runtime.dispose();
280
+ }
281
+ };
282
+ var runInQuickJs = (options, code, toolInvoker) => Effect.tryPromise({
283
+ try: () => evaluateInQuickJs(options, code, toolInvoker),
284
+ catch: (cause) => new QuickJsExecutionError({ message: String(cause) })
285
+ });
286
+ var makeQuickJsExecutor = (options = {}) => ({
287
+ execute: (code, toolInvoker) => runInQuickJs(options, code, toolInvoker)
288
+ });
289
+ export {
290
+ makeQuickJsExecutor,
291
+ setQuickJSModule
292
+ };
293
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n recoverExecutionBody,\n type CodeExecutor,\n type ExecuteResult,\n type SandboxToolInvoker,\n} from \"@executor/codemode-core\";\nimport * as Data from \"effect/Data\";\nimport * as Effect from \"effect/Effect\";\nimport {\n getQuickJS,\n shouldInterruptAfterDeadline,\n type QuickJSContext,\n type QuickJSDeferredPromise,\n type QuickJSHandle,\n type QuickJSRuntime,\n type QuickJSWASMModule,\n} from \"quickjs-emscripten\";\n\nexport type QuickJsExecutorOptions = {\n timeoutMs?: number;\n memoryLimitBytes?: number;\n maxStackSizeBytes?: number;\n};\n\n// Allow pre-loading a QuickJS module (e.g. with custom WASM bytes for compiled binaries)\nlet preloadedModule: QuickJSWASMModule | null = null;\n\nexport const setQuickJSModule = (mod: QuickJSWASMModule) => {\n preloadedModule = mod;\n};\n\nconst resolveQuickJS = (): Promise<QuickJSWASMModule> =>\n preloadedModule ? Promise.resolve(preloadedModule) : getQuickJS();\n\nclass QuickJsExecutionError extends Data.TaggedError(\"QuickJsExecutionError\")<{\n readonly message: string;\n}> {}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60_000;\nconst EXECUTION_FILENAME = \"executor-quickjs-runtime.js\";\n\nconst toError = (cause: unknown): Error =>\n cause instanceof Error ? cause : new Error(String(cause));\n\nconst toErrorMessage = (cause: unknown): string => {\n if (typeof cause === \"object\" && cause !== null) {\n const stack = \"stack\" in cause && typeof cause.stack === \"string\" ? cause.stack : undefined;\n const message =\n \"message\" in cause && typeof cause.message === \"string\" ? cause.message : undefined;\n\n if (stack) {\n return stack;\n }\n\n if (message) {\n return message;\n }\n }\n\n const error = toError(cause);\n return error.stack ?? error.message;\n};\n\nconst serializeJson = (value: unknown, label: string): string | undefined => {\n if (typeof value === \"undefined\") {\n return undefined;\n }\n\n try {\n return JSON.stringify(value);\n } catch (cause) {\n throw new Error(`${label} is not JSON serializable: ${toError(cause).message}`);\n }\n};\n\nconst looksLikeInterruptedError = (message: string): boolean => /\\binterrupted\\b/i.test(message);\n\nconst timeoutMessage = (timeoutMs: number): string =>\n `QuickJS execution timed out after ${timeoutMs}ms`;\n\nconst normalizeExecutionError = (cause: unknown, deadlineMs: number, timeoutMs: number): string => {\n const message = toErrorMessage(cause);\n return Date.now() >= deadlineMs && looksLikeInterruptedError(message)\n ? timeoutMessage(timeoutMs)\n : message;\n};\n\nconst buildExecutionSource = (code: string): string => {\n const body = recoverExecutionBody(code);\n\n return [\n '\"use strict\";',\n \"const __invokeTool = __executor_invokeTool;\",\n \"const __log = __executor_log;\",\n \"try { delete globalThis.__executor_invokeTool; } catch {}\",\n \"try { delete globalThis.__executor_log; } catch {}\",\n \"const __formatLogArg = (value) => {\",\n \" if (typeof value === 'string') return value;\",\n \" try {\",\n \" return JSON.stringify(value);\",\n \" } catch {\",\n \" return String(value);\",\n \" }\",\n \"};\",\n \"const __formatLogLine = (args) => args.map(__formatLogArg).join(' ');\",\n \"const __makeToolsProxy = (path = []) => new Proxy(() => undefined, {\",\n \" get(_target, prop) {\",\n \" if (prop === 'then' || typeof prop === 'symbol') {\",\n \" return undefined;\",\n \" }\",\n \" return __makeToolsProxy([...path, String(prop)]);\",\n \" },\",\n \" apply(_target, _thisArg, args) {\",\n \" const toolPath = path.join('.');\",\n \" if (!toolPath) {\",\n \" throw new Error('Tool path missing in invocation');\",\n \" }\",\n \" return Promise.resolve(__invokeTool(toolPath, args[0])).then((raw) => raw === undefined ? undefined : JSON.parse(raw));\",\n \" },\",\n \"});\",\n \"const tools = __makeToolsProxy();\",\n \"const console = {\",\n \" log: (...args) => __log('log', __formatLogLine(args)),\",\n \" warn: (...args) => __log('warn', __formatLogLine(args)),\",\n \" error: (...args) => __log('error', __formatLogLine(args)),\",\n \" info: (...args) => __log('info', __formatLogLine(args)),\",\n \" debug: (...args) => __log('debug', __formatLogLine(args)),\",\n \"};\",\n \"const fetch = (..._args) => {\",\n \" throw new Error('fetch is disabled in QuickJS executor');\",\n \"};\",\n \"(async () => {\",\n body,\n \"})()\",\n ].join(\"\\n\");\n};\n\nconst readPropDump = (context: QuickJSContext, handle: QuickJSHandle, key: string): unknown => {\n const prop = context.getProp(handle, key);\n try {\n return context.dump(prop);\n } finally {\n prop.dispose();\n }\n};\n\nconst readResultState = (\n context: QuickJSContext,\n handle: QuickJSHandle,\n): {\n settled: boolean;\n value: unknown;\n error: unknown;\n} => ({\n settled: readPropDump(context, handle, \"settled\") === true,\n value: readPropDump(context, handle, \"v\"),\n error: readPropDump(context, handle, \"e\"),\n});\n\nconst createLogBridge = (context: QuickJSContext, logs: string[]): QuickJSHandle =>\n context.newFunction(\"__executor_log\", (levelHandle, lineHandle) => {\n const level = context.getString(levelHandle);\n const line = context.getString(lineHandle);\n logs.push(`[${level}] ${line}`);\n return context.undefined;\n });\n\nconst createToolBridge = (\n context: QuickJSContext,\n toolInvoker: SandboxToolInvoker,\n pendingDeferreds: Set<QuickJSDeferredPromise>,\n): QuickJSHandle =>\n context.newFunction(\"__executor_invokeTool\", (pathHandle, argsHandle) => {\n const path = context.getString(pathHandle);\n const args =\n argsHandle === undefined || context.typeof(argsHandle) === \"undefined\"\n ? undefined\n : context.dump(argsHandle);\n const deferred = context.newPromise();\n pendingDeferreds.add(deferred);\n deferred.settled.finally(() => {\n pendingDeferreds.delete(deferred);\n });\n\n void Effect.runPromise(toolInvoker.invoke({ path, args })).then(\n (value) => {\n if (!deferred.alive) {\n return;\n }\n\n const serialized = serializeJson(value, `Tool result for ${path}`);\n if (typeof serialized === \"undefined\") {\n deferred.resolve();\n return;\n }\n\n const valueHandle = context.newString(serialized);\n deferred.resolve(valueHandle);\n valueHandle.dispose();\n },\n (cause) => {\n if (!deferred.alive) {\n return;\n }\n\n const errorHandle = context.newError(toErrorMessage(cause));\n deferred.reject(errorHandle);\n errorHandle.dispose();\n },\n );\n\n return deferred.handle;\n });\n\nconst drainJobs = (\n context: QuickJSContext,\n runtime: QuickJSRuntime,\n deadlineMs: number,\n timeoutMs: number,\n): void => {\n while (runtime.hasPendingJob()) {\n if (Date.now() >= deadlineMs) {\n throw new Error(timeoutMessage(timeoutMs));\n }\n\n const pending = runtime.executePendingJobs();\n if (pending.error) {\n const error = context.dump(pending.error);\n pending.error.dispose();\n throw toError(error);\n }\n }\n};\n\nconst waitForDeferreds = async (\n pendingDeferreds: ReadonlySet<QuickJSDeferredPromise>,\n deadlineMs: number,\n timeoutMs: number,\n): Promise<void> => {\n const remainingMs = deadlineMs - Date.now();\n if (remainingMs <= 0) {\n throw new Error(timeoutMessage(timeoutMs));\n }\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n Promise.race([...pendingDeferreds].map((deferred) => deferred.settled)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(timeoutMessage(timeoutMs))), remainingMs);\n }),\n ]);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n }\n};\n\nconst drainAsync = async (\n context: QuickJSContext,\n runtime: QuickJSRuntime,\n pendingDeferreds: ReadonlySet<QuickJSDeferredPromise>,\n deadlineMs: number,\n timeoutMs: number,\n): Promise<void> => {\n drainJobs(context, runtime, deadlineMs, timeoutMs);\n\n while (pendingDeferreds.size > 0) {\n await waitForDeferreds(pendingDeferreds, deadlineMs, timeoutMs);\n drainJobs(context, runtime, deadlineMs, timeoutMs);\n }\n\n drainJobs(context, runtime, deadlineMs, timeoutMs);\n};\n\nconst evaluateInQuickJs = async (\n options: QuickJsExecutorOptions,\n code: string,\n toolInvoker: SandboxToolInvoker,\n): Promise<ExecuteResult> => {\n const timeoutMs = Math.max(100, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n const deadlineMs = Date.now() + timeoutMs;\n const logs: string[] = [];\n const pendingDeferreds = new Set<QuickJSDeferredPromise>();\n const QuickJS = await resolveQuickJS();\n const runtime = QuickJS.newRuntime();\n\n try {\n if (options.memoryLimitBytes !== undefined) {\n runtime.setMemoryLimit(options.memoryLimitBytes);\n }\n\n if (options.maxStackSizeBytes !== undefined) {\n runtime.setMaxStackSize(options.maxStackSizeBytes);\n }\n\n runtime.setInterruptHandler(shouldInterruptAfterDeadline(deadlineMs));\n\n const context = runtime.newContext();\n try {\n const logBridge = createLogBridge(context, logs);\n context.setProp(context.global, \"__executor_log\", logBridge);\n logBridge.dispose();\n\n const toolBridge = createToolBridge(context, toolInvoker, pendingDeferreds);\n context.setProp(context.global, \"__executor_invokeTool\", toolBridge);\n toolBridge.dispose();\n\n const evaluated = context.evalCode(buildExecutionSource(code), EXECUTION_FILENAME);\n if (evaluated.error) {\n const error = context.dump(evaluated.error);\n evaluated.error.dispose();\n return {\n result: null,\n error: normalizeExecutionError(error, deadlineMs, timeoutMs),\n logs,\n } satisfies ExecuteResult;\n }\n\n context.setProp(context.global, \"__executor_result\", evaluated.value);\n evaluated.value.dispose();\n\n const stateResult = context.evalCode(\n \"(function(p){ var s = { v: void 0, e: void 0, settled: false }; var formatError = function(e){ if (e && typeof e === 'object') { var message = typeof e.message === 'string' ? e.message : ''; var stack = typeof e.stack === 'string' ? e.stack : ''; if (message && stack) { return stack.indexOf(message) === -1 ? message + '\\\\n' + stack : stack; } if (message) return message; if (stack) return stack; } return String(e); }; p.then(function(v){ s.v = v; s.settled = true; }, function(e){ s.e = formatError(e); s.settled = true; }); return s; })(__executor_result)\",\n );\n if (stateResult.error) {\n const error = context.dump(stateResult.error);\n stateResult.error.dispose();\n return {\n result: null,\n error: normalizeExecutionError(error, deadlineMs, timeoutMs),\n logs,\n } satisfies ExecuteResult;\n }\n\n const stateHandle = stateResult.value;\n try {\n await drainAsync(context, runtime, pendingDeferreds, deadlineMs, timeoutMs);\n const state = readResultState(context, stateHandle);\n if (!state.settled) {\n return {\n result: null,\n error: timeoutMessage(timeoutMs),\n logs,\n } satisfies ExecuteResult;\n }\n\n if (typeof state.error !== \"undefined\") {\n return {\n result: null,\n error: normalizeExecutionError(state.error, deadlineMs, timeoutMs),\n logs,\n } satisfies ExecuteResult;\n }\n\n return {\n result: state.value,\n logs,\n } satisfies ExecuteResult;\n } finally {\n stateHandle.dispose();\n }\n } finally {\n for (const deferred of pendingDeferreds) {\n if (deferred.alive) {\n deferred.dispose();\n }\n }\n\n pendingDeferreds.clear();\n context.dispose();\n }\n } catch (cause) {\n return {\n result: null,\n error: normalizeExecutionError(cause, deadlineMs, timeoutMs),\n logs,\n } satisfies ExecuteResult;\n } finally {\n runtime.dispose();\n }\n};\n\nconst runInQuickJs = (\n options: QuickJsExecutorOptions,\n code: string,\n toolInvoker: SandboxToolInvoker,\n): Effect.Effect<ExecuteResult, QuickJsExecutionError> =>\n Effect.tryPromise({\n try: () => evaluateInQuickJs(options, code, toolInvoker),\n catch: (cause) => new QuickJsExecutionError({ message: String(cause) }),\n });\n\nexport const makeQuickJsExecutor = (options: QuickJsExecutorOptions = {}): CodeExecutor => ({\n execute: (code: string, toolInvoker: SandboxToolInvoker) =>\n runInQuickJs(options, code, toolInvoker),\n});\n"],"mappings":";AAAA;AAAA,EACE;AAAA,OAIK;AACP,YAAY,UAAU;AACtB,YAAY,YAAY;AACxB;AAAA,EACE;AAAA,EACA;AAAA,OAMK;AASP,IAAI,kBAA4C;AAEzC,IAAM,mBAAmB,CAAC,QAA2B;AAC1D,oBAAkB;AACpB;AAEA,IAAM,iBAAiB,MACrB,kBAAkB,QAAQ,QAAQ,eAAe,IAAI,WAAW;AAElE,IAAM,wBAAN,cAAyC,iBAAY,uBAAuB,EAEzE;AAAC;AAEJ,IAAM,qBAAqB,IAAI;AAC/B,IAAM,qBAAqB;AAE3B,IAAM,UAAU,CAAC,UACf,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAE1D,IAAM,iBAAiB,CAAC,UAA2B;AACjD,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,UAAM,QAAQ,WAAW,SAAS,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAClF,UAAM,UACJ,aAAa,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AAE5E,QAAI,OAAO;AACT,aAAO;AAAA,IACT;AAEA,QAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,QAAQ,QAAQ,KAAK;AAC3B,SAAO,MAAM,SAAS,MAAM;AAC9B;AAEA,IAAM,gBAAgB,CAAC,OAAgB,UAAsC;AAC3E,MAAI,OAAO,UAAU,aAAa;AAChC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,GAAG,KAAK,8BAA8B,QAAQ,KAAK,EAAE,OAAO,EAAE;AAAA,EAChF;AACF;AAEA,IAAM,4BAA4B,CAAC,YAA6B,mBAAmB,KAAK,OAAO;AAE/F,IAAM,iBAAiB,CAAC,cACtB,qCAAqC,SAAS;AAEhD,IAAM,0BAA0B,CAAC,OAAgB,YAAoB,cAA8B;AACjG,QAAM,UAAU,eAAe,KAAK;AACpC,SAAO,KAAK,IAAI,KAAK,cAAc,0BAA0B,OAAO,IAChE,eAAe,SAAS,IACxB;AACN;AAEA,IAAM,uBAAuB,CAAC,SAAyB;AACrD,QAAM,OAAO,qBAAqB,IAAI;AAEtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,IAAM,eAAe,CAAC,SAAyB,QAAuB,QAAyB;AAC7F,QAAM,OAAO,QAAQ,QAAQ,QAAQ,GAAG;AACxC,MAAI;AACF,WAAO,QAAQ,KAAK,IAAI;AAAA,EAC1B,UAAE;AACA,SAAK,QAAQ;AAAA,EACf;AACF;AAEA,IAAM,kBAAkB,CACtB,SACA,YAKI;AAAA,EACJ,SAAS,aAAa,SAAS,QAAQ,SAAS,MAAM;AAAA,EACtD,OAAO,aAAa,SAAS,QAAQ,GAAG;AAAA,EACxC,OAAO,aAAa,SAAS,QAAQ,GAAG;AAC1C;AAEA,IAAM,kBAAkB,CAAC,SAAyB,SAChD,QAAQ,YAAY,kBAAkB,CAAC,aAAa,eAAe;AACjE,QAAM,QAAQ,QAAQ,UAAU,WAAW;AAC3C,QAAM,OAAO,QAAQ,UAAU,UAAU;AACzC,OAAK,KAAK,IAAI,KAAK,KAAK,IAAI,EAAE;AAC9B,SAAO,QAAQ;AACjB,CAAC;AAEH,IAAM,mBAAmB,CACvB,SACA,aACA,qBAEA,QAAQ,YAAY,yBAAyB,CAAC,YAAY,eAAe;AACvE,QAAM,OAAO,QAAQ,UAAU,UAAU;AACzC,QAAM,OACJ,eAAe,UAAa,QAAQ,OAAO,UAAU,MAAM,cACvD,SACA,QAAQ,KAAK,UAAU;AAC7B,QAAM,WAAW,QAAQ,WAAW;AACpC,mBAAiB,IAAI,QAAQ;AAC7B,WAAS,QAAQ,QAAQ,MAAM;AAC7B,qBAAiB,OAAO,QAAQ;AAAA,EAClC,CAAC;AAED,OAAY,kBAAW,YAAY,OAAO,EAAE,MAAM,KAAK,CAAC,CAAC,EAAE;AAAA,IACzD,CAAC,UAAU;AACT,UAAI,CAAC,SAAS,OAAO;AACnB;AAAA,MACF;AAEA,YAAM,aAAa,cAAc,OAAO,mBAAmB,IAAI,EAAE;AACjE,UAAI,OAAO,eAAe,aAAa;AACrC,iBAAS,QAAQ;AACjB;AAAA,MACF;AAEA,YAAM,cAAc,QAAQ,UAAU,UAAU;AAChD,eAAS,QAAQ,WAAW;AAC5B,kBAAY,QAAQ;AAAA,IACtB;AAAA,IACA,CAAC,UAAU;AACT,UAAI,CAAC,SAAS,OAAO;AACnB;AAAA,MACF;AAEA,YAAM,cAAc,QAAQ,SAAS,eAAe,KAAK,CAAC;AAC1D,eAAS,OAAO,WAAW;AAC3B,kBAAY,QAAQ;AAAA,IACtB;AAAA,EACF;AAEA,SAAO,SAAS;AAClB,CAAC;AAEH,IAAM,YAAY,CAChB,SACA,SACA,YACA,cACS;AACT,SAAO,QAAQ,cAAc,GAAG;AAC9B,QAAI,KAAK,IAAI,KAAK,YAAY;AAC5B,YAAM,IAAI,MAAM,eAAe,SAAS,CAAC;AAAA,IAC3C;AAEA,UAAM,UAAU,QAAQ,mBAAmB;AAC3C,QAAI,QAAQ,OAAO;AACjB,YAAM,QAAQ,QAAQ,KAAK,QAAQ,KAAK;AACxC,cAAQ,MAAM,QAAQ;AACtB,YAAM,QAAQ,KAAK;AAAA,IACrB;AAAA,EACF;AACF;AAEA,IAAM,mBAAmB,OACvB,kBACA,YACA,cACkB;AAClB,QAAM,cAAc,aAAa,KAAK,IAAI;AAC1C,MAAI,eAAe,GAAG;AACpB,UAAM,IAAI,MAAM,eAAe,SAAS,CAAC;AAAA,EAC3C;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,QAAQ,KAAK;AAAA,MACjB,QAAQ,KAAK,CAAC,GAAG,gBAAgB,EAAE,IAAI,CAAC,aAAa,SAAS,OAAO,CAAC;AAAA,MACtE,IAAI,QAAe,CAAC,GAAG,WAAW;AAChC,gBAAQ,WAAW,MAAM,OAAO,IAAI,MAAM,eAAe,SAAS,CAAC,CAAC,GAAG,WAAW;AAAA,MACpF,CAAC;AAAA,IACH,CAAC;AAAA,EACH,UAAE;AACA,QAAI,UAAU,QAAW;AACvB,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;AAEA,IAAM,aAAa,OACjB,SACA,SACA,kBACA,YACA,cACkB;AAClB,YAAU,SAAS,SAAS,YAAY,SAAS;AAEjD,SAAO,iBAAiB,OAAO,GAAG;AAChC,UAAM,iBAAiB,kBAAkB,YAAY,SAAS;AAC9D,cAAU,SAAS,SAAS,YAAY,SAAS;AAAA,EACnD;AAEA,YAAU,SAAS,SAAS,YAAY,SAAS;AACnD;AAEA,IAAM,oBAAoB,OACxB,SACA,MACA,gBAC2B;AAC3B,QAAM,YAAY,KAAK,IAAI,KAAK,QAAQ,aAAa,kBAAkB;AACvE,QAAM,aAAa,KAAK,IAAI,IAAI;AAChC,QAAM,OAAiB,CAAC;AACxB,QAAM,mBAAmB,oBAAI,IAA4B;AACzD,QAAM,UAAU,MAAM,eAAe;AACrC,QAAM,UAAU,QAAQ,WAAW;AAEnC,MAAI;AACF,QAAI,QAAQ,qBAAqB,QAAW;AAC1C,cAAQ,eAAe,QAAQ,gBAAgB;AAAA,IACjD;AAEA,QAAI,QAAQ,sBAAsB,QAAW;AAC3C,cAAQ,gBAAgB,QAAQ,iBAAiB;AAAA,IACnD;AAEA,YAAQ,oBAAoB,6BAA6B,UAAU,CAAC;AAEpE,UAAM,UAAU,QAAQ,WAAW;AACnC,QAAI;AACF,YAAM,YAAY,gBAAgB,SAAS,IAAI;AAC/C,cAAQ,QAAQ,QAAQ,QAAQ,kBAAkB,SAAS;AAC3D,gBAAU,QAAQ;AAElB,YAAM,aAAa,iBAAiB,SAAS,aAAa,gBAAgB;AAC1E,cAAQ,QAAQ,QAAQ,QAAQ,yBAAyB,UAAU;AACnE,iBAAW,QAAQ;AAEnB,YAAM,YAAY,QAAQ,SAAS,qBAAqB,IAAI,GAAG,kBAAkB;AACjF,UAAI,UAAU,OAAO;AACnB,cAAM,QAAQ,QAAQ,KAAK,UAAU,KAAK;AAC1C,kBAAU,MAAM,QAAQ;AACxB,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,OAAO,wBAAwB,OAAO,YAAY,SAAS;AAAA,UAC3D;AAAA,QACF;AAAA,MACF;AAEA,cAAQ,QAAQ,QAAQ,QAAQ,qBAAqB,UAAU,KAAK;AACpE,gBAAU,MAAM,QAAQ;AAExB,YAAM,cAAc,QAAQ;AAAA,QAC1B;AAAA,MACF;AACA,UAAI,YAAY,OAAO;AACrB,cAAM,QAAQ,QAAQ,KAAK,YAAY,KAAK;AAC5C,oBAAY,MAAM,QAAQ;AAC1B,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,OAAO,wBAAwB,OAAO,YAAY,SAAS;AAAA,UAC3D;AAAA,QACF;AAAA,MACF;AAEA,YAAM,cAAc,YAAY;AAChC,UAAI;AACF,cAAM,WAAW,SAAS,SAAS,kBAAkB,YAAY,SAAS;AAC1E,cAAM,QAAQ,gBAAgB,SAAS,WAAW;AAClD,YAAI,CAAC,MAAM,SAAS;AAClB,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,OAAO,eAAe,SAAS;AAAA,YAC/B;AAAA,UACF;AAAA,QACF;AAEA,YAAI,OAAO,MAAM,UAAU,aAAa;AACtC,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,OAAO,wBAAwB,MAAM,OAAO,YAAY,SAAS;AAAA,YACjE;AAAA,UACF;AAAA,QACF;AAEA,eAAO;AAAA,UACL,QAAQ,MAAM;AAAA,UACd;AAAA,QACF;AAAA,MACF,UAAE;AACA,oBAAY,QAAQ;AAAA,MACtB;AAAA,IACF,UAAE;AACA,iBAAW,YAAY,kBAAkB;AACvC,YAAI,SAAS,OAAO;AAClB,mBAAS,QAAQ;AAAA,QACnB;AAAA,MACF;AAEA,uBAAiB,MAAM;AACvB,cAAQ,QAAQ;AAAA,IAClB;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,wBAAwB,OAAO,YAAY,SAAS;AAAA,MAC3D;AAAA,IACF;AAAA,EACF,UAAE;AACA,YAAQ,QAAQ;AAAA,EAClB;AACF;AAEA,IAAM,eAAe,CACnB,SACA,MACA,gBAEO,kBAAW;AAAA,EAChB,KAAK,MAAM,kBAAkB,SAAS,MAAM,WAAW;AAAA,EACvD,OAAO,CAAC,UAAU,IAAI,sBAAsB,EAAE,SAAS,OAAO,KAAK,EAAE,CAAC;AACxE,CAAC;AAEI,IAAM,sBAAsB,CAAC,UAAkC,CAAC,OAAqB;AAAA,EAC1F,SAAS,CAAC,MAAc,gBACtB,aAAa,SAAS,MAAM,WAAW;AAC3C;","names":[]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@executor-js/runtime-quickjs",
3
+ "version": "0.0.1-beta.0",
4
+ "homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/kernel/runtime-quickjs",
5
+ "bugs": {
6
+ "url": "https://github.com/RhysSullivan/executor/issues"
7
+ },
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/RhysSullivan/executor.git",
12
+ "directory": "packages/kernel/runtime-quickjs"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "type": "module",
18
+ "exports": {
19
+ ".": {
20
+ "import": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ }
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",
31
+ "typecheck": "tsgo --noEmit",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest",
34
+ "typecheck:slow": "bunx tsc --noEmit -p tsconfig.json"
35
+ },
36
+ "dependencies": {
37
+ "@executor-js/codemode-core": "0.0.1-beta.0",
38
+ "effect": "^3.21.0",
39
+ "quickjs-emscripten": "^0.31.0"
40
+ },
41
+ "devDependencies": {
42
+ "@effect/vitest": "^0.29.0",
43
+ "@types/node": "^24.3.1",
44
+ "bun-types": "^1.2.22",
45
+ "tsup": "^8.5.0",
46
+ "typescript": "^5.9.3",
47
+ "vitest": "^4.1.3"
48
+ }
49
+ }