@execbox/quickjs 0.6.0 → 0.7.1
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/README.md +9 -12
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +51 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{runner-DRLfwiqY.cjs → runner-BeRzBTrn.cjs} +92 -74
- package/dist/runner-BeRzBTrn.cjs.map +1 -0
- package/dist/{runner-oZXbguX3.js → runner-DJd4Bh8V.js} +92 -74
- package/dist/runner-DJd4Bh8V.js.map +1 -0
- package/dist/workerEntry.cjs +105 -3
- package/dist/workerEntry.cjs.map +1 -1
- package/dist/workerEntry.js +104 -2
- package/dist/workerEntry.js.map +1 -1
- package/package.json +2 -29
- package/dist/protocolEndpoint-BGyrwlr_.cjs +0 -112
- package/dist/protocolEndpoint-BGyrwlr_.cjs.map +0 -1
- package/dist/protocolEndpoint-Ceadcq_L.js +0 -107
- package/dist/protocolEndpoint-Ceadcq_L.js.map +0 -1
- package/dist/remoteEndpoint.cjs +0 -45
- package/dist/remoteEndpoint.cjs.map +0 -1
- package/dist/remoteEndpoint.d.cts +0 -29
- package/dist/remoteEndpoint.d.cts.map +0 -1
- package/dist/remoteEndpoint.d.ts +0 -29
- package/dist/remoteEndpoint.d.ts.map +0 -1
- package/dist/remoteEndpoint.js +0 -45
- package/dist/remoteEndpoint.js.map +0 -1
- package/dist/runner/index.cjs +0 -3
- package/dist/runner/index.d.cts +0 -45
- package/dist/runner/index.d.cts.map +0 -1
- package/dist/runner/index.d.ts +0 -45
- package/dist/runner/index.d.ts.map +0 -1
- package/dist/runner/index.js +0 -3
- package/dist/runner/protocolEndpoint.cjs +0 -4
- package/dist/runner/protocolEndpoint.d.cts +0 -22
- package/dist/runner/protocolEndpoint.d.cts.map +0 -1
- package/dist/runner/protocolEndpoint.d.ts +0 -22
- package/dist/runner/protocolEndpoint.d.ts.map +0 -1
- package/dist/runner/protocolEndpoint.js +0 -4
- package/dist/runner-DRLfwiqY.cjs.map +0 -1
- package/dist/runner-oZXbguX3.js.map +0 -1
- package/dist/types-C-XfFJ7u.d.cts +0 -58
- package/dist/types-C-XfFJ7u.d.cts.map +0 -1
- package/dist/types-CE7SvejR.d.ts +0 -58
- package/dist/types-CE7SvejR.d.ts.map +0 -1
|
@@ -55,81 +55,10 @@ function toGuestHandle(context, value) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
//#endregion
|
|
58
|
-
//#region src/runner/
|
|
59
|
-
/**
|
|
60
|
-
* @packageDocumentation
|
|
61
|
-
* Public API for the `@execbox/quickjs/runner` entrypoint.
|
|
62
|
-
*/
|
|
63
|
-
const loadDefaultModule = (0, quickjs_emscripten.memoizePromiseFactory)(() => (0, quickjs_emscripten.newQuickJSWASMModule)(quickjs_emscripten.RELEASE_SYNC));
|
|
58
|
+
//#region src/runner/guestEnvironment.ts
|
|
64
59
|
/**
|
|
65
|
-
*
|
|
60
|
+
* Installs the bounded console capture surface into a QuickJS context.
|
|
66
61
|
*/
|
|
67
|
-
function toExecuteError(error, deadline) {
|
|
68
|
-
if ((0, __execbox_core_runtime.isExecuteFailure)(error)) return {
|
|
69
|
-
code: error.code,
|
|
70
|
-
message: error.message
|
|
71
|
-
};
|
|
72
|
-
const message = (0, __execbox_core_runtime.normalizeThrownMessage)(error);
|
|
73
|
-
if (Date.now() > deadline || message.includes("interrupted")) return {
|
|
74
|
-
code: "timeout",
|
|
75
|
-
message: (0, __execbox_core_runtime.getExecutionTimeoutMessage)()
|
|
76
|
-
};
|
|
77
|
-
if (message.toLowerCase().includes("out of memory")) return {
|
|
78
|
-
code: "memory_limit",
|
|
79
|
-
message
|
|
80
|
-
};
|
|
81
|
-
return {
|
|
82
|
-
code: "runtime_error",
|
|
83
|
-
message
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function errorFromGuestHandle(context, handle, trustedHostErrorKey) {
|
|
87
|
-
const codeHandle = context.getProp(handle, "code");
|
|
88
|
-
const messageHandle = context.getProp(handle, "message");
|
|
89
|
-
const trustedMarkerHandle = context.getProp(handle, trustedHostErrorKey);
|
|
90
|
-
try {
|
|
91
|
-
const code = context.typeof(codeHandle) === "string" ? context.getString(codeHandle) : void 0;
|
|
92
|
-
const trustedHostError = context.typeof(trustedMarkerHandle) === "boolean";
|
|
93
|
-
const message = context.typeof(messageHandle) === "string" ? context.getString(messageHandle) : (0, __execbox_core_runtime.normalizeThrownMessage)(context.dump(handle));
|
|
94
|
-
if (trustedHostError && (0, __execbox_core_runtime.isKnownExecuteErrorCode)(code)) return {
|
|
95
|
-
code,
|
|
96
|
-
message
|
|
97
|
-
};
|
|
98
|
-
return {
|
|
99
|
-
code: "runtime_error",
|
|
100
|
-
message
|
|
101
|
-
};
|
|
102
|
-
} finally {
|
|
103
|
-
codeHandle.dispose();
|
|
104
|
-
messageHandle.dispose();
|
|
105
|
-
trustedMarkerHandle.dispose();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async function waitForPromiseSettlement(runtime, promise, deadline, trustedHostErrorKey) {
|
|
109
|
-
let settled = false;
|
|
110
|
-
let rejection;
|
|
111
|
-
promise.then(() => {
|
|
112
|
-
settled = true;
|
|
113
|
-
}, (error) => {
|
|
114
|
-
settled = true;
|
|
115
|
-
rejection = error;
|
|
116
|
-
});
|
|
117
|
-
while (!settled) {
|
|
118
|
-
if (Date.now() > deadline) throw new __execbox_core_runtime.ExecuteFailure("timeout", (0, __execbox_core_runtime.getExecutionTimeoutMessage)());
|
|
119
|
-
const pendingJobsResult = runtime.executePendingJobs(-1);
|
|
120
|
-
if ((0, quickjs_emscripten.isFail)(pendingJobsResult)) {
|
|
121
|
-
const pendingError = pendingJobsResult.error;
|
|
122
|
-
try {
|
|
123
|
-
const executeError = errorFromGuestHandle(pendingError.context, pendingError, trustedHostErrorKey);
|
|
124
|
-
throw new __execbox_core_runtime.ExecuteFailure(executeError.code, executeError.message);
|
|
125
|
-
} finally {
|
|
126
|
-
pendingError.dispose();
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
130
|
-
}
|
|
131
|
-
if (rejection !== void 0) throw rejection;
|
|
132
|
-
}
|
|
133
62
|
function injectConsole(context, logs) {
|
|
134
63
|
const consoleHandle = context.newObject();
|
|
135
64
|
try {
|
|
@@ -151,6 +80,9 @@ function injectConsole(context, logs) {
|
|
|
151
80
|
consoleHandle.dispose();
|
|
152
81
|
}
|
|
153
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Installs provider namespaces as guest-visible async tool proxies.
|
|
85
|
+
*/
|
|
154
86
|
function injectProviders(context, providers, signal, trustedHostErrorKey, onToolCall) {
|
|
155
87
|
for (const provider of providers) {
|
|
156
88
|
const providerHandle = context.newObject();
|
|
@@ -249,6 +181,92 @@ function createToolHandle(context, providerName, safeToolName, signal, trustedHo
|
|
|
249
181
|
return deferred.handle;
|
|
250
182
|
});
|
|
251
183
|
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/runner/sessionErrors.ts
|
|
187
|
+
/**
|
|
188
|
+
* Converts unexpected executor failures into stable public result errors.
|
|
189
|
+
*/
|
|
190
|
+
function toExecuteError(error, deadline) {
|
|
191
|
+
if ((0, __execbox_core_runtime.isExecuteFailure)(error)) return {
|
|
192
|
+
code: error.code,
|
|
193
|
+
message: error.message
|
|
194
|
+
};
|
|
195
|
+
const message = (0, __execbox_core_runtime.normalizeThrownMessage)(error);
|
|
196
|
+
if (Date.now() > deadline || message.includes("interrupted")) return {
|
|
197
|
+
code: "timeout",
|
|
198
|
+
message: (0, __execbox_core_runtime.getExecutionTimeoutMessage)()
|
|
199
|
+
};
|
|
200
|
+
if (message.toLowerCase().includes("out of memory")) return {
|
|
201
|
+
code: "memory_limit",
|
|
202
|
+
message
|
|
203
|
+
};
|
|
204
|
+
return {
|
|
205
|
+
code: "runtime_error",
|
|
206
|
+
message
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Converts a guest-side error handle into the public execbox error shape.
|
|
211
|
+
*/
|
|
212
|
+
function errorFromGuestHandle(context, handle, trustedHostErrorKey) {
|
|
213
|
+
const codeHandle = context.getProp(handle, "code");
|
|
214
|
+
const messageHandle = context.getProp(handle, "message");
|
|
215
|
+
const trustedMarkerHandle = context.getProp(handle, trustedHostErrorKey);
|
|
216
|
+
try {
|
|
217
|
+
const code = context.typeof(codeHandle) === "string" ? context.getString(codeHandle) : void 0;
|
|
218
|
+
const trustedHostError = context.typeof(trustedMarkerHandle) === "boolean";
|
|
219
|
+
const message = context.typeof(messageHandle) === "string" ? context.getString(messageHandle) : (0, __execbox_core_runtime.normalizeThrownMessage)(context.dump(handle));
|
|
220
|
+
if (trustedHostError && (0, __execbox_core_runtime.isKnownExecuteErrorCode)(code)) return {
|
|
221
|
+
code,
|
|
222
|
+
message
|
|
223
|
+
};
|
|
224
|
+
return {
|
|
225
|
+
code: "runtime_error",
|
|
226
|
+
message
|
|
227
|
+
};
|
|
228
|
+
} finally {
|
|
229
|
+
codeHandle.dispose();
|
|
230
|
+
messageHandle.dispose();
|
|
231
|
+
trustedMarkerHandle.dispose();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Advances QuickJS pending jobs until the resolved promise settles or times out.
|
|
236
|
+
*/
|
|
237
|
+
async function waitForPromiseSettlement(runtime, promise, deadline, trustedHostErrorKey) {
|
|
238
|
+
let settled = false;
|
|
239
|
+
let rejection;
|
|
240
|
+
promise.then(() => {
|
|
241
|
+
settled = true;
|
|
242
|
+
}, (error) => {
|
|
243
|
+
settled = true;
|
|
244
|
+
rejection = error;
|
|
245
|
+
});
|
|
246
|
+
while (!settled) {
|
|
247
|
+
if (Date.now() > deadline) throw new __execbox_core_runtime.ExecuteFailure("timeout", (0, __execbox_core_runtime.getExecutionTimeoutMessage)());
|
|
248
|
+
const pendingJobsResult = runtime.executePendingJobs(-1);
|
|
249
|
+
if ((0, quickjs_emscripten.isFail)(pendingJobsResult)) {
|
|
250
|
+
const pendingError = pendingJobsResult.error;
|
|
251
|
+
try {
|
|
252
|
+
const executeError = errorFromGuestHandle(pendingError.context, pendingError, trustedHostErrorKey);
|
|
253
|
+
throw new __execbox_core_runtime.ExecuteFailure(executeError.code, executeError.message);
|
|
254
|
+
} finally {
|
|
255
|
+
pendingError.dispose();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
259
|
+
}
|
|
260
|
+
if (rejection !== void 0) throw rejection;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/runner/index.ts
|
|
265
|
+
/**
|
|
266
|
+
* @packageDocumentation
|
|
267
|
+
* Internal reusable QuickJS session runner.
|
|
268
|
+
*/
|
|
269
|
+
const loadDefaultModule = (0, quickjs_emscripten.memoizePromiseFactory)(() => (0, quickjs_emscripten.newQuickJSWASMModule)(quickjs_emscripten.RELEASE_SYNC));
|
|
252
270
|
/**
|
|
253
271
|
* Runs one QuickJS-backed execution session using a transport-neutral tool callback.
|
|
254
272
|
*/
|
|
@@ -345,4 +363,4 @@ Object.defineProperty(exports, 'runQuickJsSession', {
|
|
|
345
363
|
return runQuickJsSession;
|
|
346
364
|
}
|
|
347
365
|
});
|
|
348
|
-
//# sourceMappingURL=runner-
|
|
366
|
+
//# sourceMappingURL=runner-BeRzBTrn.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-BeRzBTrn.cjs","names":["ExecuteFailure","input: unknown","ExecuteFailure","responsePromise: Promise<ToolCallResult>","resultHandle: QuickJSHandle | undefined","rejection: unknown","ExecuteFailure","RELEASE_SYNC","logs: string[]"],"sources":["../src/quickjsBridge.ts","../src/runner/guestEnvironment.ts","../src/runner/sessionErrors.ts","../src/runner/index.ts"],"sourcesContent":["import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\n\nimport { ExecuteFailure } from \"@execbox/core/runtime\";\nimport type { ExecuteErrorCode } from \"@execbox/core\";\n\n/**\n * Creates a guest-visible error object that carries a trusted host error code marker.\n */\nexport function createGuestErrorHandle(\n context: QuickJSContext,\n code: ExecuteErrorCode,\n message: string,\n trustedHostErrorKey: string,\n): QuickJSHandle {\n const errorHandle = context.newError({ message, name: \"Error\" });\n const codeHandle = context.newString(code);\n const trustedHostMarkerHandle = context.true;\n\n try {\n context.setProp(errorHandle, \"code\", codeHandle);\n context.setProp(errorHandle, trustedHostErrorKey, trustedHostMarkerHandle);\n return errorHandle;\n } finally {\n codeHandle.dispose();\n trustedHostMarkerHandle.dispose();\n }\n}\n\n/**\n * Converts a guest QuickJS handle into a JSON-compatible host value.\n */\nexport function fromGuestHandle(\n context: QuickJSContext,\n handle: QuickJSHandle,\n): unknown {\n const guestType = context.typeof(handle);\n\n if (guestType === \"undefined\") {\n return undefined;\n }\n\n if (\n guestType === \"function\" ||\n guestType === \"symbol\" ||\n guestType === \"bigint\"\n ) {\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Guest code returned a non-serializable value\",\n );\n }\n\n const jsonHandle = context.getProp(context.global, \"JSON\");\n const stringifyHandle = context.getProp(jsonHandle, \"stringify\");\n\n try {\n const stringified = context.unwrapResult(\n context.callFunction(stringifyHandle, jsonHandle, handle),\n );\n const stringifiedType = context.typeof(stringified);\n\n if (stringifiedType === \"undefined\") {\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Guest code returned a non-serializable value\",\n );\n }\n\n const jsonValue = context.getString(stringified);\n return JSON.parse(jsonValue);\n } catch (error) {\n if (error instanceof ExecuteFailure) {\n throw error;\n }\n\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Guest code returned a non-serializable value\",\n );\n } finally {\n stringifyHandle.dispose();\n jsonHandle.dispose();\n }\n}\n\n/**\n * Converts a host JSON-compatible value into a guest QuickJS handle.\n */\nexport function toGuestHandle(\n context: QuickJSContext,\n value: unknown,\n): QuickJSHandle {\n if (value === undefined) {\n return context.undefined;\n }\n\n const jsonValue = JSON.stringify(value);\n\n if (jsonValue === undefined) {\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Host value is not JSON-serializable\",\n );\n }\n\n return context.unwrapResult(\n context.evalCode(`(${jsonValue})`, \"host-value.json\"),\n );\n}\n","import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\n\nimport {\n ExecuteFailure,\n formatConsoleLine,\n getExecutionTimeoutMessage,\n isExecuteFailure,\n normalizeThrownMessage,\n} from \"@execbox/core/runtime\";\nimport type { ProviderManifest, ToolCallResult } from \"@execbox/core/runtime\";\n\nimport {\n createGuestErrorHandle,\n fromGuestHandle,\n toGuestHandle,\n} from \"../quickjsBridge.ts\";\nimport type { QuickJsSessionRequest } from \"./index.ts\";\n\n/**\n * Installs the bounded console capture surface into a QuickJS context.\n */\nexport function injectConsole(context: QuickJSContext, logs: string[]): void {\n const consoleHandle = context.newObject();\n\n try {\n for (const methodName of [\"log\", \"info\", \"warn\", \"error\"]) {\n const methodHandle = context.newFunction(methodName, (...args) => {\n logs.push(formatConsoleLine(args.map((arg) => context.dump(arg))));\n return context.undefined;\n });\n\n context.setProp(consoleHandle, methodName, methodHandle);\n methodHandle.dispose();\n }\n\n context.setProp(context.global, \"console\", consoleHandle);\n } finally {\n consoleHandle.dispose();\n }\n}\n\n/**\n * Installs provider namespaces as guest-visible async tool proxies.\n */\nexport function injectProviders(\n context: QuickJSContext,\n providers: ProviderManifest[],\n signal: AbortSignal,\n trustedHostErrorKey: string,\n onToolCall: QuickJsSessionRequest[\"onToolCall\"],\n): void {\n for (const provider of providers) {\n const providerHandle = context.newObject();\n\n try {\n for (const [safeToolName] of Object.entries(provider.tools)) {\n const toolHandle = createToolHandle(\n context,\n provider.name,\n safeToolName,\n signal,\n trustedHostErrorKey,\n onToolCall,\n );\n context.setProp(providerHandle, safeToolName, toolHandle);\n toolHandle.dispose();\n }\n\n context.setProp(context.global, provider.name, providerHandle);\n } finally {\n providerHandle.dispose();\n }\n }\n}\n\nfunction createToolHandle(\n context: QuickJSContext,\n providerName: string,\n safeToolName: string,\n signal: AbortSignal,\n trustedHostErrorKey: string,\n onToolCall: QuickJsSessionRequest[\"onToolCall\"],\n): QuickJSHandle {\n return context.newFunction(safeToolName, (...args) => {\n const deferred = context.newPromise();\n const disposeDeferred = () => {\n if (context.alive && deferred.alive) {\n deferred.dispose();\n }\n };\n let input: unknown;\n\n try {\n input =\n args[0] === undefined ? undefined : fromGuestHandle(context, args[0]);\n } catch (error) {\n const executeError = isExecuteFailure(error)\n ? error\n : new ExecuteFailure(\n \"serialization_error\",\n \"Guest code passed a non-serializable tool input\",\n );\n const errorHandle = createGuestErrorHandle(\n context,\n executeError.code,\n executeError.message,\n trustedHostErrorKey,\n );\n\n try {\n deferred.reject(errorHandle);\n return deferred.handle;\n } finally {\n errorHandle.dispose();\n queueMicrotask(disposeDeferred);\n }\n }\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n if (!context.alive || !deferred.alive) {\n disposeDeferred();\n return;\n }\n\n const errorHandle = createGuestErrorHandle(\n context,\n \"timeout\",\n getExecutionTimeoutMessage(),\n trustedHostErrorKey,\n );\n\n try {\n deferred.reject(errorHandle);\n } finally {\n errorHandle.dispose();\n disposeDeferred();\n }\n };\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n\n let responsePromise: Promise<ToolCallResult>;\n\n try {\n if (signal.aborted) {\n throw new ExecuteFailure(\"timeout\", getExecutionTimeoutMessage());\n }\n\n responsePromise = Promise.resolve(\n onToolCall({\n input,\n providerName,\n safeToolName,\n }),\n );\n } catch (error) {\n responsePromise = Promise.reject(error);\n }\n\n void responsePromise\n .then((response) => {\n signal.removeEventListener(\"abort\", onAbort);\n if (!context.alive || !deferred.alive) {\n disposeDeferred();\n return;\n }\n\n let resultHandle: QuickJSHandle | undefined;\n\n try {\n if (!response.ok) {\n const errorHandle = createGuestErrorHandle(\n context,\n response.error.code,\n response.error.message,\n trustedHostErrorKey,\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n return;\n }\n\n resultHandle = toGuestHandle(context, response.result);\n deferred.resolve(resultHandle);\n } finally {\n resultHandle?.dispose();\n disposeDeferred();\n }\n })\n .catch((error) => {\n signal.removeEventListener(\"abort\", onAbort);\n if (!context.alive || !deferred.alive) {\n disposeDeferred();\n return;\n }\n\n const errorHandle = createGuestErrorHandle(\n context,\n isExecuteFailure(error) ? error.code : \"internal_error\",\n normalizeThrownMessage(error),\n trustedHostErrorKey,\n );\n\n try {\n deferred.reject(errorHandle);\n } finally {\n errorHandle.dispose();\n disposeDeferred();\n }\n });\n\n return deferred.handle;\n });\n}\n","import {\n isFail,\n type QuickJSContext,\n type QuickJSHandle,\n type QuickJSRuntime,\n} from \"quickjs-emscripten\";\n\nimport {\n ExecuteFailure,\n getExecutionTimeoutMessage,\n isExecuteFailure,\n isKnownExecuteErrorCode,\n normalizeThrownMessage,\n} from \"@execbox/core/runtime\";\nimport type { ExecuteError } from \"@execbox/core\";\n\n/**\n * Converts unexpected executor failures into stable public result errors.\n */\nexport function toExecuteError(error: unknown, deadline: number): ExecuteError {\n if (isExecuteFailure(error)) {\n return {\n code: error.code,\n message: error.message,\n };\n }\n\n const message = normalizeThrownMessage(error);\n\n if (Date.now() > deadline || message.includes(\"interrupted\")) {\n return {\n code: \"timeout\",\n message: getExecutionTimeoutMessage(),\n };\n }\n\n if (message.toLowerCase().includes(\"out of memory\")) {\n return {\n code: \"memory_limit\",\n message,\n };\n }\n\n return {\n code: \"runtime_error\",\n message,\n };\n}\n\n/**\n * Converts a guest-side error handle into the public execbox error shape.\n */\nexport function errorFromGuestHandle(\n context: QuickJSContext,\n handle: QuickJSHandle,\n trustedHostErrorKey: string,\n): ExecuteError {\n const codeHandle = context.getProp(handle, \"code\");\n const messageHandle = context.getProp(handle, \"message\");\n const trustedMarkerHandle = context.getProp(handle, trustedHostErrorKey);\n\n try {\n const code =\n context.typeof(codeHandle) === \"string\"\n ? context.getString(codeHandle)\n : undefined;\n const trustedHostError = context.typeof(trustedMarkerHandle) === \"boolean\";\n const message =\n context.typeof(messageHandle) === \"string\"\n ? context.getString(messageHandle)\n : normalizeThrownMessage(context.dump(handle));\n\n if (trustedHostError && isKnownExecuteErrorCode(code)) {\n return {\n code,\n message,\n };\n }\n\n return {\n code: \"runtime_error\",\n message,\n };\n } finally {\n codeHandle.dispose();\n messageHandle.dispose();\n trustedMarkerHandle.dispose();\n }\n}\n\n/**\n * Advances QuickJS pending jobs until the resolved promise settles or times out.\n */\nexport async function waitForPromiseSettlement(\n runtime: QuickJSRuntime,\n promise: Promise<unknown>,\n deadline: number,\n trustedHostErrorKey: string,\n): Promise<void> {\n let settled = false;\n let rejection: unknown;\n\n promise.then(\n () => {\n settled = true;\n },\n (error) => {\n settled = true;\n rejection = error;\n },\n );\n\n while (!settled) {\n if (Date.now() > deadline) {\n throw new ExecuteFailure(\"timeout\", getExecutionTimeoutMessage());\n }\n\n const pendingJobsResult = runtime.executePendingJobs(-1);\n if (isFail(pendingJobsResult)) {\n const pendingError = pendingJobsResult.error;\n\n try {\n const executeError = errorFromGuestHandle(\n pendingError.context,\n pendingError,\n trustedHostErrorKey,\n );\n throw new ExecuteFailure(executeError.code, executeError.message);\n } finally {\n pendingError.dispose();\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n\n if (rejection !== undefined) {\n throw rejection;\n }\n}\n","/**\n * @packageDocumentation\n * Internal reusable QuickJS session runner.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport {\n RELEASE_SYNC,\n isFail,\n memoizePromiseFactory,\n newQuickJSWASMModule,\n shouldInterruptAfterDeadline,\n type QuickJSWASMModule,\n} from \"quickjs-emscripten\";\n\nimport {\n normalizeCode,\n resolveExecutorRuntimeOptions,\n truncateLogs,\n} from \"@execbox/core/runtime\";\nimport type { ExecuteResult, ExecutorRuntimeOptions } from \"@execbox/core\";\nimport type {\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core/runtime\";\n\nimport { fromGuestHandle } from \"../quickjsBridge.ts\";\nimport type { QuickJsInlineExecutorOptions } from \"../types.ts\";\nimport { injectConsole, injectProviders } from \"./guestEnvironment.ts\";\nimport {\n errorFromGuestHandle,\n toExecuteError,\n waitForPromiseSettlement,\n} from \"./sessionErrors.ts\";\n\nexport type {\n QuickJsExecutorHost,\n QuickJsExecutorOptions,\n QuickJsHostedMode,\n QuickJsInlineExecutorOptions,\n QuickJsWorkerExecutorOptions,\n WorkerResourceLimits,\n} from \"../types.ts\";\n\nconst loadDefaultModule = memoizePromiseFactory(() =>\n newQuickJSWASMModule(RELEASE_SYNC),\n);\n\n/**\n * Transport-neutral host tool call emitted from a QuickJS session.\n */\nexport type QuickJsSessionToolCall = ToolCall;\n\n/**\n * Input required to run one transport-backed QuickJS execution session.\n */\nexport interface QuickJsSessionRequest {\n /** Optional abort controller that should be triggered when execution stops. */\n abortController?: AbortController;\n\n /** Guest JavaScript source to evaluate inside QuickJS. */\n code: string;\n\n /** Host callback used to fulfill guest tool calls. */\n onToolCall: (call: ToolCall) => Promise<ToolCallResult> | ToolCallResult;\n\n /** Optional hook invoked once the guest runtime has started. */\n onStarted?: () => void;\n\n /** Transport-safe provider manifests exposed to the guest runtime. */\n providers: ProviderManifest[];\n\n /** Optional caller-owned abort signal for the session. */\n signal?: AbortSignal;\n}\n\n/**\n * Options controlling one transport-backed QuickJS session.\n */\nexport type QuickJsSessionOptions = ExecutorRuntimeOptions &\n Pick<QuickJsInlineExecutorOptions, \"loadModule\"> & {\n /** Optional preloaded QuickJS WASM module instance. */\n module?: QuickJSWASMModule;\n };\n\n/**\n * Runs one QuickJS-backed execution session using a transport-neutral tool callback.\n */\nexport async function runQuickJsSession(\n request: QuickJsSessionRequest,\n options: QuickJsSessionOptions = {},\n): Promise<ExecuteResult> {\n const runtimeOptions = resolveExecutorRuntimeOptions(options);\n const loadModule = async () => {\n if (options.module) {\n return options.module;\n }\n\n const loaded = options.loadModule\n ? await options.loadModule()\n : await loadDefaultModule();\n return loaded as QuickJSWASMModule;\n };\n const { maxLogChars, maxLogLines, memoryLimitBytes, timeoutMs } =\n runtimeOptions;\n const startedAt = Date.now();\n const logs: string[] = [];\n const abortController = new AbortController();\n const trustedHostErrorKey = `__execboxHostError_${randomUUID()}`;\n const signal =\n request.abortController?.signal ?? request.signal ?? abortController.signal;\n const module = await loadModule();\n const runtime = module.newRuntime();\n let deadline = Number.POSITIVE_INFINITY;\n runtime.setMemoryLimit(memoryLimitBytes);\n const context = runtime.newContext();\n\n try {\n injectConsole(context, logs);\n injectProviders(\n context,\n request.providers,\n signal,\n trustedHostErrorKey,\n request.onToolCall,\n );\n const executionStartedAt = Date.now();\n deadline = executionStartedAt + timeoutMs;\n const shouldInterrupt = shouldInterruptAfterDeadline(deadline);\n runtime.setInterruptHandler((currentRuntime) => {\n return signal.aborted || shouldInterrupt(currentRuntime);\n });\n request.onStarted?.();\n\n const executableSource = normalizeCode(request.code);\n const functionHandle = context.unwrapResult(\n context.evalCode(`(${executableSource})`, \"sandbox-user-code.js\"),\n );\n\n try {\n const promiseHandle = context.unwrapResult(\n context.callFunction(functionHandle, context.undefined),\n );\n\n try {\n const promiseResult = context.resolvePromise(promiseHandle);\n await waitForPromiseSettlement(\n runtime,\n promiseResult,\n deadline,\n trustedHostErrorKey,\n );\n const settledResult = await promiseResult;\n\n if (isFail(settledResult)) {\n const errorHandle = settledResult.error;\n\n try {\n return {\n durationMs: Date.now() - startedAt,\n error: errorFromGuestHandle(\n context,\n errorHandle,\n trustedHostErrorKey,\n ),\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: false,\n };\n } finally {\n errorHandle.dispose();\n }\n }\n\n try {\n const value = fromGuestHandle(context, settledResult.value);\n\n return {\n durationMs: Date.now() - startedAt,\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: true,\n result: value,\n };\n } catch (error) {\n return {\n durationMs: Date.now() - startedAt,\n error: toExecuteError(error, deadline),\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: false,\n };\n } finally {\n settledResult.value.dispose();\n }\n } finally {\n promiseHandle.dispose();\n }\n } finally {\n functionHandle.dispose();\n }\n } catch (error) {\n abortController.abort();\n\n return {\n durationMs: Date.now() - startedAt,\n error: toExecuteError(error, deadline),\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: false,\n };\n } finally {\n request.abortController?.abort();\n abortController.abort();\n context.dispose();\n runtime.dispose();\n }\n}\n"],"mappings":"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"}
|
|
@@ -55,81 +55,10 @@ function toGuestHandle(context, value) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
//#endregion
|
|
58
|
-
//#region src/runner/
|
|
59
|
-
/**
|
|
60
|
-
* @packageDocumentation
|
|
61
|
-
* Public API for the `@execbox/quickjs/runner` entrypoint.
|
|
62
|
-
*/
|
|
63
|
-
const loadDefaultModule = memoizePromiseFactory(() => newQuickJSWASMModule(RELEASE_SYNC));
|
|
58
|
+
//#region src/runner/guestEnvironment.ts
|
|
64
59
|
/**
|
|
65
|
-
*
|
|
60
|
+
* Installs the bounded console capture surface into a QuickJS context.
|
|
66
61
|
*/
|
|
67
|
-
function toExecuteError(error, deadline) {
|
|
68
|
-
if (isExecuteFailure(error)) return {
|
|
69
|
-
code: error.code,
|
|
70
|
-
message: error.message
|
|
71
|
-
};
|
|
72
|
-
const message = normalizeThrownMessage(error);
|
|
73
|
-
if (Date.now() > deadline || message.includes("interrupted")) return {
|
|
74
|
-
code: "timeout",
|
|
75
|
-
message: getExecutionTimeoutMessage()
|
|
76
|
-
};
|
|
77
|
-
if (message.toLowerCase().includes("out of memory")) return {
|
|
78
|
-
code: "memory_limit",
|
|
79
|
-
message
|
|
80
|
-
};
|
|
81
|
-
return {
|
|
82
|
-
code: "runtime_error",
|
|
83
|
-
message
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function errorFromGuestHandle(context, handle, trustedHostErrorKey) {
|
|
87
|
-
const codeHandle = context.getProp(handle, "code");
|
|
88
|
-
const messageHandle = context.getProp(handle, "message");
|
|
89
|
-
const trustedMarkerHandle = context.getProp(handle, trustedHostErrorKey);
|
|
90
|
-
try {
|
|
91
|
-
const code = context.typeof(codeHandle) === "string" ? context.getString(codeHandle) : void 0;
|
|
92
|
-
const trustedHostError = context.typeof(trustedMarkerHandle) === "boolean";
|
|
93
|
-
const message = context.typeof(messageHandle) === "string" ? context.getString(messageHandle) : normalizeThrownMessage(context.dump(handle));
|
|
94
|
-
if (trustedHostError && isKnownExecuteErrorCode(code)) return {
|
|
95
|
-
code,
|
|
96
|
-
message
|
|
97
|
-
};
|
|
98
|
-
return {
|
|
99
|
-
code: "runtime_error",
|
|
100
|
-
message
|
|
101
|
-
};
|
|
102
|
-
} finally {
|
|
103
|
-
codeHandle.dispose();
|
|
104
|
-
messageHandle.dispose();
|
|
105
|
-
trustedMarkerHandle.dispose();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async function waitForPromiseSettlement(runtime, promise, deadline, trustedHostErrorKey) {
|
|
109
|
-
let settled = false;
|
|
110
|
-
let rejection;
|
|
111
|
-
promise.then(() => {
|
|
112
|
-
settled = true;
|
|
113
|
-
}, (error) => {
|
|
114
|
-
settled = true;
|
|
115
|
-
rejection = error;
|
|
116
|
-
});
|
|
117
|
-
while (!settled) {
|
|
118
|
-
if (Date.now() > deadline) throw new ExecuteFailure("timeout", getExecutionTimeoutMessage());
|
|
119
|
-
const pendingJobsResult = runtime.executePendingJobs(-1);
|
|
120
|
-
if (isFail(pendingJobsResult)) {
|
|
121
|
-
const pendingError = pendingJobsResult.error;
|
|
122
|
-
try {
|
|
123
|
-
const executeError = errorFromGuestHandle(pendingError.context, pendingError, trustedHostErrorKey);
|
|
124
|
-
throw new ExecuteFailure(executeError.code, executeError.message);
|
|
125
|
-
} finally {
|
|
126
|
-
pendingError.dispose();
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
130
|
-
}
|
|
131
|
-
if (rejection !== void 0) throw rejection;
|
|
132
|
-
}
|
|
133
62
|
function injectConsole(context, logs) {
|
|
134
63
|
const consoleHandle = context.newObject();
|
|
135
64
|
try {
|
|
@@ -151,6 +80,9 @@ function injectConsole(context, logs) {
|
|
|
151
80
|
consoleHandle.dispose();
|
|
152
81
|
}
|
|
153
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Installs provider namespaces as guest-visible async tool proxies.
|
|
85
|
+
*/
|
|
154
86
|
function injectProviders(context, providers, signal, trustedHostErrorKey, onToolCall) {
|
|
155
87
|
for (const provider of providers) {
|
|
156
88
|
const providerHandle = context.newObject();
|
|
@@ -249,6 +181,92 @@ function createToolHandle(context, providerName, safeToolName, signal, trustedHo
|
|
|
249
181
|
return deferred.handle;
|
|
250
182
|
});
|
|
251
183
|
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/runner/sessionErrors.ts
|
|
187
|
+
/**
|
|
188
|
+
* Converts unexpected executor failures into stable public result errors.
|
|
189
|
+
*/
|
|
190
|
+
function toExecuteError(error, deadline) {
|
|
191
|
+
if (isExecuteFailure(error)) return {
|
|
192
|
+
code: error.code,
|
|
193
|
+
message: error.message
|
|
194
|
+
};
|
|
195
|
+
const message = normalizeThrownMessage(error);
|
|
196
|
+
if (Date.now() > deadline || message.includes("interrupted")) return {
|
|
197
|
+
code: "timeout",
|
|
198
|
+
message: getExecutionTimeoutMessage()
|
|
199
|
+
};
|
|
200
|
+
if (message.toLowerCase().includes("out of memory")) return {
|
|
201
|
+
code: "memory_limit",
|
|
202
|
+
message
|
|
203
|
+
};
|
|
204
|
+
return {
|
|
205
|
+
code: "runtime_error",
|
|
206
|
+
message
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Converts a guest-side error handle into the public execbox error shape.
|
|
211
|
+
*/
|
|
212
|
+
function errorFromGuestHandle(context, handle, trustedHostErrorKey) {
|
|
213
|
+
const codeHandle = context.getProp(handle, "code");
|
|
214
|
+
const messageHandle = context.getProp(handle, "message");
|
|
215
|
+
const trustedMarkerHandle = context.getProp(handle, trustedHostErrorKey);
|
|
216
|
+
try {
|
|
217
|
+
const code = context.typeof(codeHandle) === "string" ? context.getString(codeHandle) : void 0;
|
|
218
|
+
const trustedHostError = context.typeof(trustedMarkerHandle) === "boolean";
|
|
219
|
+
const message = context.typeof(messageHandle) === "string" ? context.getString(messageHandle) : normalizeThrownMessage(context.dump(handle));
|
|
220
|
+
if (trustedHostError && isKnownExecuteErrorCode(code)) return {
|
|
221
|
+
code,
|
|
222
|
+
message
|
|
223
|
+
};
|
|
224
|
+
return {
|
|
225
|
+
code: "runtime_error",
|
|
226
|
+
message
|
|
227
|
+
};
|
|
228
|
+
} finally {
|
|
229
|
+
codeHandle.dispose();
|
|
230
|
+
messageHandle.dispose();
|
|
231
|
+
trustedMarkerHandle.dispose();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Advances QuickJS pending jobs until the resolved promise settles or times out.
|
|
236
|
+
*/
|
|
237
|
+
async function waitForPromiseSettlement(runtime, promise, deadline, trustedHostErrorKey) {
|
|
238
|
+
let settled = false;
|
|
239
|
+
let rejection;
|
|
240
|
+
promise.then(() => {
|
|
241
|
+
settled = true;
|
|
242
|
+
}, (error) => {
|
|
243
|
+
settled = true;
|
|
244
|
+
rejection = error;
|
|
245
|
+
});
|
|
246
|
+
while (!settled) {
|
|
247
|
+
if (Date.now() > deadline) throw new ExecuteFailure("timeout", getExecutionTimeoutMessage());
|
|
248
|
+
const pendingJobsResult = runtime.executePendingJobs(-1);
|
|
249
|
+
if (isFail(pendingJobsResult)) {
|
|
250
|
+
const pendingError = pendingJobsResult.error;
|
|
251
|
+
try {
|
|
252
|
+
const executeError = errorFromGuestHandle(pendingError.context, pendingError, trustedHostErrorKey);
|
|
253
|
+
throw new ExecuteFailure(executeError.code, executeError.message);
|
|
254
|
+
} finally {
|
|
255
|
+
pendingError.dispose();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
259
|
+
}
|
|
260
|
+
if (rejection !== void 0) throw rejection;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/runner/index.ts
|
|
265
|
+
/**
|
|
266
|
+
* @packageDocumentation
|
|
267
|
+
* Internal reusable QuickJS session runner.
|
|
268
|
+
*/
|
|
269
|
+
const loadDefaultModule = memoizePromiseFactory(() => newQuickJSWASMModule(RELEASE_SYNC));
|
|
252
270
|
/**
|
|
253
271
|
* Runs one QuickJS-backed execution session using a transport-neutral tool callback.
|
|
254
272
|
*/
|
|
@@ -340,4 +358,4 @@ async function runQuickJsSession(request, options = {}) {
|
|
|
340
358
|
|
|
341
359
|
//#endregion
|
|
342
360
|
export { runQuickJsSession as t };
|
|
343
|
-
//# sourceMappingURL=runner-
|
|
361
|
+
//# sourceMappingURL=runner-DJd4Bh8V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-DJd4Bh8V.js","names":["input: unknown","responsePromise: Promise<ToolCallResult>","resultHandle: QuickJSHandle | undefined","rejection: unknown","logs: string[]"],"sources":["../src/quickjsBridge.ts","../src/runner/guestEnvironment.ts","../src/runner/sessionErrors.ts","../src/runner/index.ts"],"sourcesContent":["import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\n\nimport { ExecuteFailure } from \"@execbox/core/runtime\";\nimport type { ExecuteErrorCode } from \"@execbox/core\";\n\n/**\n * Creates a guest-visible error object that carries a trusted host error code marker.\n */\nexport function createGuestErrorHandle(\n context: QuickJSContext,\n code: ExecuteErrorCode,\n message: string,\n trustedHostErrorKey: string,\n): QuickJSHandle {\n const errorHandle = context.newError({ message, name: \"Error\" });\n const codeHandle = context.newString(code);\n const trustedHostMarkerHandle = context.true;\n\n try {\n context.setProp(errorHandle, \"code\", codeHandle);\n context.setProp(errorHandle, trustedHostErrorKey, trustedHostMarkerHandle);\n return errorHandle;\n } finally {\n codeHandle.dispose();\n trustedHostMarkerHandle.dispose();\n }\n}\n\n/**\n * Converts a guest QuickJS handle into a JSON-compatible host value.\n */\nexport function fromGuestHandle(\n context: QuickJSContext,\n handle: QuickJSHandle,\n): unknown {\n const guestType = context.typeof(handle);\n\n if (guestType === \"undefined\") {\n return undefined;\n }\n\n if (\n guestType === \"function\" ||\n guestType === \"symbol\" ||\n guestType === \"bigint\"\n ) {\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Guest code returned a non-serializable value\",\n );\n }\n\n const jsonHandle = context.getProp(context.global, \"JSON\");\n const stringifyHandle = context.getProp(jsonHandle, \"stringify\");\n\n try {\n const stringified = context.unwrapResult(\n context.callFunction(stringifyHandle, jsonHandle, handle),\n );\n const stringifiedType = context.typeof(stringified);\n\n if (stringifiedType === \"undefined\") {\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Guest code returned a non-serializable value\",\n );\n }\n\n const jsonValue = context.getString(stringified);\n return JSON.parse(jsonValue);\n } catch (error) {\n if (error instanceof ExecuteFailure) {\n throw error;\n }\n\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Guest code returned a non-serializable value\",\n );\n } finally {\n stringifyHandle.dispose();\n jsonHandle.dispose();\n }\n}\n\n/**\n * Converts a host JSON-compatible value into a guest QuickJS handle.\n */\nexport function toGuestHandle(\n context: QuickJSContext,\n value: unknown,\n): QuickJSHandle {\n if (value === undefined) {\n return context.undefined;\n }\n\n const jsonValue = JSON.stringify(value);\n\n if (jsonValue === undefined) {\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Host value is not JSON-serializable\",\n );\n }\n\n return context.unwrapResult(\n context.evalCode(`(${jsonValue})`, \"host-value.json\"),\n );\n}\n","import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\n\nimport {\n ExecuteFailure,\n formatConsoleLine,\n getExecutionTimeoutMessage,\n isExecuteFailure,\n normalizeThrownMessage,\n} from \"@execbox/core/runtime\";\nimport type { ProviderManifest, ToolCallResult } from \"@execbox/core/runtime\";\n\nimport {\n createGuestErrorHandle,\n fromGuestHandle,\n toGuestHandle,\n} from \"../quickjsBridge.ts\";\nimport type { QuickJsSessionRequest } from \"./index.ts\";\n\n/**\n * Installs the bounded console capture surface into a QuickJS context.\n */\nexport function injectConsole(context: QuickJSContext, logs: string[]): void {\n const consoleHandle = context.newObject();\n\n try {\n for (const methodName of [\"log\", \"info\", \"warn\", \"error\"]) {\n const methodHandle = context.newFunction(methodName, (...args) => {\n logs.push(formatConsoleLine(args.map((arg) => context.dump(arg))));\n return context.undefined;\n });\n\n context.setProp(consoleHandle, methodName, methodHandle);\n methodHandle.dispose();\n }\n\n context.setProp(context.global, \"console\", consoleHandle);\n } finally {\n consoleHandle.dispose();\n }\n}\n\n/**\n * Installs provider namespaces as guest-visible async tool proxies.\n */\nexport function injectProviders(\n context: QuickJSContext,\n providers: ProviderManifest[],\n signal: AbortSignal,\n trustedHostErrorKey: string,\n onToolCall: QuickJsSessionRequest[\"onToolCall\"],\n): void {\n for (const provider of providers) {\n const providerHandle = context.newObject();\n\n try {\n for (const [safeToolName] of Object.entries(provider.tools)) {\n const toolHandle = createToolHandle(\n context,\n provider.name,\n safeToolName,\n signal,\n trustedHostErrorKey,\n onToolCall,\n );\n context.setProp(providerHandle, safeToolName, toolHandle);\n toolHandle.dispose();\n }\n\n context.setProp(context.global, provider.name, providerHandle);\n } finally {\n providerHandle.dispose();\n }\n }\n}\n\nfunction createToolHandle(\n context: QuickJSContext,\n providerName: string,\n safeToolName: string,\n signal: AbortSignal,\n trustedHostErrorKey: string,\n onToolCall: QuickJsSessionRequest[\"onToolCall\"],\n): QuickJSHandle {\n return context.newFunction(safeToolName, (...args) => {\n const deferred = context.newPromise();\n const disposeDeferred = () => {\n if (context.alive && deferred.alive) {\n deferred.dispose();\n }\n };\n let input: unknown;\n\n try {\n input =\n args[0] === undefined ? undefined : fromGuestHandle(context, args[0]);\n } catch (error) {\n const executeError = isExecuteFailure(error)\n ? error\n : new ExecuteFailure(\n \"serialization_error\",\n \"Guest code passed a non-serializable tool input\",\n );\n const errorHandle = createGuestErrorHandle(\n context,\n executeError.code,\n executeError.message,\n trustedHostErrorKey,\n );\n\n try {\n deferred.reject(errorHandle);\n return deferred.handle;\n } finally {\n errorHandle.dispose();\n queueMicrotask(disposeDeferred);\n }\n }\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n if (!context.alive || !deferred.alive) {\n disposeDeferred();\n return;\n }\n\n const errorHandle = createGuestErrorHandle(\n context,\n \"timeout\",\n getExecutionTimeoutMessage(),\n trustedHostErrorKey,\n );\n\n try {\n deferred.reject(errorHandle);\n } finally {\n errorHandle.dispose();\n disposeDeferred();\n }\n };\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n\n let responsePromise: Promise<ToolCallResult>;\n\n try {\n if (signal.aborted) {\n throw new ExecuteFailure(\"timeout\", getExecutionTimeoutMessage());\n }\n\n responsePromise = Promise.resolve(\n onToolCall({\n input,\n providerName,\n safeToolName,\n }),\n );\n } catch (error) {\n responsePromise = Promise.reject(error);\n }\n\n void responsePromise\n .then((response) => {\n signal.removeEventListener(\"abort\", onAbort);\n if (!context.alive || !deferred.alive) {\n disposeDeferred();\n return;\n }\n\n let resultHandle: QuickJSHandle | undefined;\n\n try {\n if (!response.ok) {\n const errorHandle = createGuestErrorHandle(\n context,\n response.error.code,\n response.error.message,\n trustedHostErrorKey,\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n return;\n }\n\n resultHandle = toGuestHandle(context, response.result);\n deferred.resolve(resultHandle);\n } finally {\n resultHandle?.dispose();\n disposeDeferred();\n }\n })\n .catch((error) => {\n signal.removeEventListener(\"abort\", onAbort);\n if (!context.alive || !deferred.alive) {\n disposeDeferred();\n return;\n }\n\n const errorHandle = createGuestErrorHandle(\n context,\n isExecuteFailure(error) ? error.code : \"internal_error\",\n normalizeThrownMessage(error),\n trustedHostErrorKey,\n );\n\n try {\n deferred.reject(errorHandle);\n } finally {\n errorHandle.dispose();\n disposeDeferred();\n }\n });\n\n return deferred.handle;\n });\n}\n","import {\n isFail,\n type QuickJSContext,\n type QuickJSHandle,\n type QuickJSRuntime,\n} from \"quickjs-emscripten\";\n\nimport {\n ExecuteFailure,\n getExecutionTimeoutMessage,\n isExecuteFailure,\n isKnownExecuteErrorCode,\n normalizeThrownMessage,\n} from \"@execbox/core/runtime\";\nimport type { ExecuteError } from \"@execbox/core\";\n\n/**\n * Converts unexpected executor failures into stable public result errors.\n */\nexport function toExecuteError(error: unknown, deadline: number): ExecuteError {\n if (isExecuteFailure(error)) {\n return {\n code: error.code,\n message: error.message,\n };\n }\n\n const message = normalizeThrownMessage(error);\n\n if (Date.now() > deadline || message.includes(\"interrupted\")) {\n return {\n code: \"timeout\",\n message: getExecutionTimeoutMessage(),\n };\n }\n\n if (message.toLowerCase().includes(\"out of memory\")) {\n return {\n code: \"memory_limit\",\n message,\n };\n }\n\n return {\n code: \"runtime_error\",\n message,\n };\n}\n\n/**\n * Converts a guest-side error handle into the public execbox error shape.\n */\nexport function errorFromGuestHandle(\n context: QuickJSContext,\n handle: QuickJSHandle,\n trustedHostErrorKey: string,\n): ExecuteError {\n const codeHandle = context.getProp(handle, \"code\");\n const messageHandle = context.getProp(handle, \"message\");\n const trustedMarkerHandle = context.getProp(handle, trustedHostErrorKey);\n\n try {\n const code =\n context.typeof(codeHandle) === \"string\"\n ? context.getString(codeHandle)\n : undefined;\n const trustedHostError = context.typeof(trustedMarkerHandle) === \"boolean\";\n const message =\n context.typeof(messageHandle) === \"string\"\n ? context.getString(messageHandle)\n : normalizeThrownMessage(context.dump(handle));\n\n if (trustedHostError && isKnownExecuteErrorCode(code)) {\n return {\n code,\n message,\n };\n }\n\n return {\n code: \"runtime_error\",\n message,\n };\n } finally {\n codeHandle.dispose();\n messageHandle.dispose();\n trustedMarkerHandle.dispose();\n }\n}\n\n/**\n * Advances QuickJS pending jobs until the resolved promise settles or times out.\n */\nexport async function waitForPromiseSettlement(\n runtime: QuickJSRuntime,\n promise: Promise<unknown>,\n deadline: number,\n trustedHostErrorKey: string,\n): Promise<void> {\n let settled = false;\n let rejection: unknown;\n\n promise.then(\n () => {\n settled = true;\n },\n (error) => {\n settled = true;\n rejection = error;\n },\n );\n\n while (!settled) {\n if (Date.now() > deadline) {\n throw new ExecuteFailure(\"timeout\", getExecutionTimeoutMessage());\n }\n\n const pendingJobsResult = runtime.executePendingJobs(-1);\n if (isFail(pendingJobsResult)) {\n const pendingError = pendingJobsResult.error;\n\n try {\n const executeError = errorFromGuestHandle(\n pendingError.context,\n pendingError,\n trustedHostErrorKey,\n );\n throw new ExecuteFailure(executeError.code, executeError.message);\n } finally {\n pendingError.dispose();\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n\n if (rejection !== undefined) {\n throw rejection;\n }\n}\n","/**\n * @packageDocumentation\n * Internal reusable QuickJS session runner.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport {\n RELEASE_SYNC,\n isFail,\n memoizePromiseFactory,\n newQuickJSWASMModule,\n shouldInterruptAfterDeadline,\n type QuickJSWASMModule,\n} from \"quickjs-emscripten\";\n\nimport {\n normalizeCode,\n resolveExecutorRuntimeOptions,\n truncateLogs,\n} from \"@execbox/core/runtime\";\nimport type { ExecuteResult, ExecutorRuntimeOptions } from \"@execbox/core\";\nimport type {\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core/runtime\";\n\nimport { fromGuestHandle } from \"../quickjsBridge.ts\";\nimport type { QuickJsInlineExecutorOptions } from \"../types.ts\";\nimport { injectConsole, injectProviders } from \"./guestEnvironment.ts\";\nimport {\n errorFromGuestHandle,\n toExecuteError,\n waitForPromiseSettlement,\n} from \"./sessionErrors.ts\";\n\nexport type {\n QuickJsExecutorHost,\n QuickJsExecutorOptions,\n QuickJsHostedMode,\n QuickJsInlineExecutorOptions,\n QuickJsWorkerExecutorOptions,\n WorkerResourceLimits,\n} from \"../types.ts\";\n\nconst loadDefaultModule = memoizePromiseFactory(() =>\n newQuickJSWASMModule(RELEASE_SYNC),\n);\n\n/**\n * Transport-neutral host tool call emitted from a QuickJS session.\n */\nexport type QuickJsSessionToolCall = ToolCall;\n\n/**\n * Input required to run one transport-backed QuickJS execution session.\n */\nexport interface QuickJsSessionRequest {\n /** Optional abort controller that should be triggered when execution stops. */\n abortController?: AbortController;\n\n /** Guest JavaScript source to evaluate inside QuickJS. */\n code: string;\n\n /** Host callback used to fulfill guest tool calls. */\n onToolCall: (call: ToolCall) => Promise<ToolCallResult> | ToolCallResult;\n\n /** Optional hook invoked once the guest runtime has started. */\n onStarted?: () => void;\n\n /** Transport-safe provider manifests exposed to the guest runtime. */\n providers: ProviderManifest[];\n\n /** Optional caller-owned abort signal for the session. */\n signal?: AbortSignal;\n}\n\n/**\n * Options controlling one transport-backed QuickJS session.\n */\nexport type QuickJsSessionOptions = ExecutorRuntimeOptions &\n Pick<QuickJsInlineExecutorOptions, \"loadModule\"> & {\n /** Optional preloaded QuickJS WASM module instance. */\n module?: QuickJSWASMModule;\n };\n\n/**\n * Runs one QuickJS-backed execution session using a transport-neutral tool callback.\n */\nexport async function runQuickJsSession(\n request: QuickJsSessionRequest,\n options: QuickJsSessionOptions = {},\n): Promise<ExecuteResult> {\n const runtimeOptions = resolveExecutorRuntimeOptions(options);\n const loadModule = async () => {\n if (options.module) {\n return options.module;\n }\n\n const loaded = options.loadModule\n ? await options.loadModule()\n : await loadDefaultModule();\n return loaded as QuickJSWASMModule;\n };\n const { maxLogChars, maxLogLines, memoryLimitBytes, timeoutMs } =\n runtimeOptions;\n const startedAt = Date.now();\n const logs: string[] = [];\n const abortController = new AbortController();\n const trustedHostErrorKey = `__execboxHostError_${randomUUID()}`;\n const signal =\n request.abortController?.signal ?? request.signal ?? abortController.signal;\n const module = await loadModule();\n const runtime = module.newRuntime();\n let deadline = Number.POSITIVE_INFINITY;\n runtime.setMemoryLimit(memoryLimitBytes);\n const context = runtime.newContext();\n\n try {\n injectConsole(context, logs);\n injectProviders(\n context,\n request.providers,\n signal,\n trustedHostErrorKey,\n request.onToolCall,\n );\n const executionStartedAt = Date.now();\n deadline = executionStartedAt + timeoutMs;\n const shouldInterrupt = shouldInterruptAfterDeadline(deadline);\n runtime.setInterruptHandler((currentRuntime) => {\n return signal.aborted || shouldInterrupt(currentRuntime);\n });\n request.onStarted?.();\n\n const executableSource = normalizeCode(request.code);\n const functionHandle = context.unwrapResult(\n context.evalCode(`(${executableSource})`, \"sandbox-user-code.js\"),\n );\n\n try {\n const promiseHandle = context.unwrapResult(\n context.callFunction(functionHandle, context.undefined),\n );\n\n try {\n const promiseResult = context.resolvePromise(promiseHandle);\n await waitForPromiseSettlement(\n runtime,\n promiseResult,\n deadline,\n trustedHostErrorKey,\n );\n const settledResult = await promiseResult;\n\n if (isFail(settledResult)) {\n const errorHandle = settledResult.error;\n\n try {\n return {\n durationMs: Date.now() - startedAt,\n error: errorFromGuestHandle(\n context,\n errorHandle,\n trustedHostErrorKey,\n ),\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: false,\n };\n } finally {\n errorHandle.dispose();\n }\n }\n\n try {\n const value = fromGuestHandle(context, settledResult.value);\n\n return {\n durationMs: Date.now() - startedAt,\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: true,\n result: value,\n };\n } catch (error) {\n return {\n durationMs: Date.now() - startedAt,\n error: toExecuteError(error, deadline),\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: false,\n };\n } finally {\n settledResult.value.dispose();\n }\n } finally {\n promiseHandle.dispose();\n }\n } finally {\n functionHandle.dispose();\n }\n } catch (error) {\n abortController.abort();\n\n return {\n durationMs: Date.now() - startedAt,\n error: toExecuteError(error, deadline),\n logs: truncateLogs(logs, maxLogLines, maxLogChars),\n ok: false,\n };\n } finally {\n request.abortController?.abort();\n abortController.abort();\n context.dispose();\n runtime.dispose();\n }\n}\n"],"mappings":"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"}
|
package/dist/workerEntry.cjs
CHANGED
|
@@ -1,11 +1,113 @@
|
|
|
1
|
-
require('./runner-
|
|
2
|
-
const require_protocolEndpoint = require('./protocolEndpoint-BGyrwlr_.cjs');
|
|
1
|
+
const require_runner = require('./runner-BeRzBTrn.cjs');
|
|
3
2
|
let node_worker_threads = require("node:worker_threads");
|
|
3
|
+
let __execbox_core_protocol = require("@execbox/core/protocol");
|
|
4
|
+
let node_crypto = require("node:crypto");
|
|
4
5
|
|
|
6
|
+
//#region src/runner/protocolEndpoint.ts
|
|
7
|
+
/**
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
* Internal QuickJS protocol endpoint used by hosted and remote adapters.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Attaches the shared QuickJS protocol loop to a worker messaging port.
|
|
13
|
+
*/
|
|
14
|
+
function attachQuickJsProtocolEndpoint(port) {
|
|
15
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
16
|
+
let activeAbortController;
|
|
17
|
+
let activeExecutionId;
|
|
18
|
+
async function startExecution(message) {
|
|
19
|
+
if (activeExecutionId) {
|
|
20
|
+
port.send({
|
|
21
|
+
durationMs: 0,
|
|
22
|
+
error: {
|
|
23
|
+
code: "internal_error",
|
|
24
|
+
message: "QuickJS endpoint already has an active execution"
|
|
25
|
+
},
|
|
26
|
+
id: message.id,
|
|
27
|
+
logs: [],
|
|
28
|
+
ok: false,
|
|
29
|
+
type: "done"
|
|
30
|
+
});
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const abortController = new AbortController();
|
|
34
|
+
activeAbortController = abortController;
|
|
35
|
+
activeExecutionId = message.id;
|
|
36
|
+
try {
|
|
37
|
+
const result = await require_runner.runQuickJsSession({
|
|
38
|
+
abortController,
|
|
39
|
+
code: message.code,
|
|
40
|
+
onStarted: () => {
|
|
41
|
+
port.send({
|
|
42
|
+
id: message.id,
|
|
43
|
+
type: "started"
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
onToolCall: (call) => new Promise((resolve) => {
|
|
47
|
+
const callId = (0, node_crypto.randomUUID)();
|
|
48
|
+
pendingToolCalls.set(callId, resolve);
|
|
49
|
+
port.send({
|
|
50
|
+
...call,
|
|
51
|
+
callId,
|
|
52
|
+
type: "tool_call"
|
|
53
|
+
});
|
|
54
|
+
}),
|
|
55
|
+
providers: message.providers
|
|
56
|
+
}, message.options);
|
|
57
|
+
port.send({
|
|
58
|
+
...result,
|
|
59
|
+
id: message.id,
|
|
60
|
+
type: "done"
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
port.send({
|
|
64
|
+
durationMs: 0,
|
|
65
|
+
error: {
|
|
66
|
+
code: "internal_error",
|
|
67
|
+
message: error instanceof Error ? error.message : String(error)
|
|
68
|
+
},
|
|
69
|
+
id: message.id,
|
|
70
|
+
logs: [],
|
|
71
|
+
ok: false,
|
|
72
|
+
type: "done"
|
|
73
|
+
});
|
|
74
|
+
} finally {
|
|
75
|
+
pendingToolCalls.clear();
|
|
76
|
+
activeAbortController = void 0;
|
|
77
|
+
activeExecutionId = void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const maybeDetach = port.onMessage((message) => {
|
|
81
|
+
if (!(0, __execbox_core_protocol.isDispatcherMessage)(message)) return;
|
|
82
|
+
switch (message.type) {
|
|
83
|
+
case "cancel":
|
|
84
|
+
if (message.id === activeExecutionId) activeAbortController?.abort();
|
|
85
|
+
break;
|
|
86
|
+
case "execute":
|
|
87
|
+
startExecution(message);
|
|
88
|
+
break;
|
|
89
|
+
case "tool_result": {
|
|
90
|
+
const resolve = pendingToolCalls.get(message.callId);
|
|
91
|
+
pendingToolCalls.delete(message.callId);
|
|
92
|
+
resolve?.(message);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return () => {
|
|
98
|
+
if (typeof maybeDetach === "function") maybeDetach();
|
|
99
|
+
pendingToolCalls.clear();
|
|
100
|
+
activeAbortController?.abort();
|
|
101
|
+
activeAbortController = void 0;
|
|
102
|
+
activeExecutionId = void 0;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
5
107
|
//#region src/workerEntry.ts
|
|
6
108
|
if (!node_worker_threads.parentPort) throw new Error("QuickJsExecutor worker host requires a worker parent port");
|
|
7
109
|
const workerPort = node_worker_threads.parentPort;
|
|
8
|
-
|
|
110
|
+
attachQuickJsProtocolEndpoint({
|
|
9
111
|
onMessage(handler) {
|
|
10
112
|
workerPort.on("message", handler);
|
|
11
113
|
return () => workerPort.off("message", handler);
|
package/dist/workerEntry.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workerEntry.cjs","names":["
|
|
1
|
+
{"version":3,"file":"workerEntry.cjs","names":["activeAbortController: AbortController | undefined","activeExecutionId: string | undefined","runQuickJsSession","parentPort"],"sources":["../src/runner/protocolEndpoint.ts","../src/workerEntry.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Internal QuickJS protocol endpoint used by hosted and remote adapters.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport { isDispatcherMessage } from \"@execbox/core/protocol\";\nimport type {\n DispatcherMessage,\n ExecuteMessage,\n RunnerMessage,\n ToolCallResult,\n} from \"@execbox/core/protocol\";\n\nimport { runQuickJsSession } from \"./index.ts\";\n\n/**\n * Minimal worker-side port used by the shared QuickJS protocol endpoint.\n */\nexport interface QuickJsProtocolPort {\n onMessage(handler: (message: DispatcherMessage) => void): void | (() => void);\n send(message: RunnerMessage): void;\n}\n\n/**\n * Attaches the shared QuickJS protocol loop to a worker messaging port.\n */\nexport function attachQuickJsProtocolEndpoint(\n port: QuickJsProtocolPort,\n): () => void {\n const pendingToolCalls = new Map<string, (result: ToolCallResult) => void>();\n let activeAbortController: AbortController | undefined;\n let activeExecutionId: string | undefined;\n\n async function startExecution(message: ExecuteMessage): Promise<void> {\n if (activeExecutionId) {\n port.send({\n durationMs: 0,\n error: {\n code: \"internal_error\",\n message: \"QuickJS endpoint already has an active execution\",\n },\n id: message.id,\n logs: [],\n ok: false,\n type: \"done\",\n });\n return;\n }\n\n const abortController = new AbortController();\n activeAbortController = abortController;\n activeExecutionId = message.id;\n\n try {\n const result = await runQuickJsSession(\n {\n abortController,\n code: message.code,\n onStarted: () => {\n port.send({\n id: message.id,\n type: \"started\",\n });\n },\n onToolCall: (call) =>\n new Promise<ToolCallResult>((resolve) => {\n const callId = randomUUID();\n pendingToolCalls.set(callId, resolve);\n port.send({\n ...call,\n callId,\n type: \"tool_call\",\n });\n }),\n providers: message.providers,\n },\n message.options,\n );\n\n port.send({\n ...result,\n id: message.id,\n type: \"done\",\n });\n } catch (error) {\n port.send({\n durationMs: 0,\n error: {\n code: \"internal_error\",\n message: error instanceof Error ? error.message : String(error),\n },\n id: message.id,\n logs: [],\n ok: false,\n type: \"done\",\n });\n } finally {\n pendingToolCalls.clear();\n activeAbortController = undefined;\n activeExecutionId = undefined;\n }\n }\n\n const maybeDetach = port.onMessage((message: DispatcherMessage) => {\n if (!isDispatcherMessage(message)) {\n return;\n }\n\n switch (message.type) {\n case \"cancel\":\n if (message.id === activeExecutionId) {\n activeAbortController?.abort();\n }\n break;\n case \"execute\":\n void startExecution(message);\n break;\n case \"tool_result\": {\n const resolve = pendingToolCalls.get(message.callId);\n pendingToolCalls.delete(message.callId);\n resolve?.(message);\n break;\n }\n }\n });\n\n return () => {\n if (typeof maybeDetach === \"function\") {\n maybeDetach();\n }\n pendingToolCalls.clear();\n activeAbortController?.abort();\n activeAbortController = undefined;\n activeExecutionId = undefined;\n };\n}\n","import { parentPort } from \"node:worker_threads\";\n\nimport type { DispatcherMessage, RunnerMessage } from \"@execbox/core/protocol\";\n\nimport { attachQuickJsProtocolEndpoint } from \"./runner/protocolEndpoint.ts\";\n\nif (!parentPort) {\n throw new Error(\"QuickJsExecutor worker host requires a worker parent port\");\n}\n\nconst workerPort = parentPort;\n\nattachQuickJsProtocolEndpoint({\n onMessage(handler: (message: DispatcherMessage) => void): () => void {\n workerPort.on(\"message\", handler);\n return () => workerPort.off(\"message\", handler);\n },\n send(message: RunnerMessage): void {\n workerPort.postMessage(message);\n },\n});\n"],"mappings":";;;;;;;;;;;;;AA2BA,SAAgB,8BACd,MACY;CACZ,MAAM,mCAAmB,IAAI,KAA+C;CAC5E,IAAIA;CACJ,IAAIC;CAEJ,eAAe,eAAe,SAAwC;AACpE,MAAI,mBAAmB;AACrB,QAAK,KAAK;IACR,YAAY;IACZ,OAAO;KACL,MAAM;KACN,SAAS;KACV;IACD,IAAI,QAAQ;IACZ,MAAM,EAAE;IACR,IAAI;IACJ,MAAM;IACP,CAAC;AACF;;EAGF,MAAM,kBAAkB,IAAI,iBAAiB;AAC7C,0BAAwB;AACxB,sBAAoB,QAAQ;AAE5B,MAAI;GACF,MAAM,SAAS,MAAMC,iCACnB;IACE;IACA,MAAM,QAAQ;IACd,iBAAiB;AACf,UAAK,KAAK;MACR,IAAI,QAAQ;MACZ,MAAM;MACP,CAAC;;IAEJ,aAAa,SACX,IAAI,SAAyB,YAAY;KACvC,MAAM,sCAAqB;AAC3B,sBAAiB,IAAI,QAAQ,QAAQ;AACrC,UAAK,KAAK;MACR,GAAG;MACH;MACA,MAAM;MACP,CAAC;MACF;IACJ,WAAW,QAAQ;IACpB,EACD,QAAQ,QACT;AAED,QAAK,KAAK;IACR,GAAG;IACH,IAAI,QAAQ;IACZ,MAAM;IACP,CAAC;WACK,OAAO;AACd,QAAK,KAAK;IACR,YAAY;IACZ,OAAO;KACL,MAAM;KACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;KAChE;IACD,IAAI,QAAQ;IACZ,MAAM,EAAE;IACR,IAAI;IACJ,MAAM;IACP,CAAC;YACM;AACR,oBAAiB,OAAO;AACxB,2BAAwB;AACxB,uBAAoB;;;CAIxB,MAAM,cAAc,KAAK,WAAW,YAA+B;AACjE,MAAI,kDAAqB,QAAQ,CAC/B;AAGF,UAAQ,QAAQ,MAAhB;GACE,KAAK;AACH,QAAI,QAAQ,OAAO,kBACjB,wBAAuB,OAAO;AAEhC;GACF,KAAK;AACH,IAAK,eAAe,QAAQ;AAC5B;GACF,KAAK,eAAe;IAClB,MAAM,UAAU,iBAAiB,IAAI,QAAQ,OAAO;AACpD,qBAAiB,OAAO,QAAQ,OAAO;AACvC,cAAU,QAAQ;AAClB;;;GAGJ;AAEF,cAAa;AACX,MAAI,OAAO,gBAAgB,WACzB,cAAa;AAEf,mBAAiB,OAAO;AACxB,yBAAuB,OAAO;AAC9B,0BAAwB;AACxB,sBAAoB;;;;;;AChIxB,IAAI,CAACC,+BACH,OAAM,IAAI,MAAM,4DAA4D;AAG9E,MAAM,aAAaA;AAEnB,8BAA8B;CAC5B,UAAU,SAA2D;AACnE,aAAW,GAAG,WAAW,QAAQ;AACjC,eAAa,WAAW,IAAI,WAAW,QAAQ;;CAEjD,KAAK,SAA8B;AACjC,aAAW,YAAY,QAAQ;;CAElC,CAAC"}
|