@execbox/quickjs 0.1.2 → 0.2.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.
Files changed (34) hide show
  1. package/README.md +6 -2
  2. package/dist/index.cjs +70 -7
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +7 -3
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.ts +7 -3
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +67 -4
  9. package/dist/index.js.map +1 -1
  10. package/dist/runner/index.cjs +1 -1
  11. package/dist/runner/index.d.cts +11 -77
  12. package/dist/runner/index.d.cts.map +1 -1
  13. package/dist/runner/index.d.ts +11 -77
  14. package/dist/runner/index.d.ts.map +1 -1
  15. package/dist/runner/index.js +1 -1
  16. package/dist/runner/protocolEndpoint.cjs +5 -1
  17. package/dist/runner/protocolEndpoint.cjs.map +1 -1
  18. package/dist/runner/protocolEndpoint.d.cts +4 -0
  19. package/dist/runner/protocolEndpoint.d.cts.map +1 -1
  20. package/dist/runner/protocolEndpoint.d.ts +4 -0
  21. package/dist/runner/protocolEndpoint.d.ts.map +1 -1
  22. package/dist/runner/protocolEndpoint.js +5 -1
  23. package/dist/runner/protocolEndpoint.js.map +1 -1
  24. package/dist/{runner-9_N9h2rp.cjs → runner-BqkDnP0t.cjs} +109 -1
  25. package/dist/{runner-9_N9h2rp.cjs.map → runner-BqkDnP0t.cjs.map} +1 -1
  26. package/dist/{runner-O4f_FOhI.js → runner-CVaY4RVQ.js} +68 -2
  27. package/dist/{runner-O4f_FOhI.js.map → runner-CVaY4RVQ.js.map} +1 -1
  28. package/dist/{types-BB8mb_-T.d.cts → types-BXi8Lqtk.d.ts} +6 -2
  29. package/dist/types-BXi8Lqtk.d.ts.map +1 -0
  30. package/dist/{types-D7uau0GM.d.ts → types-CVE2n2LY.d.cts} +6 -2
  31. package/dist/types-CVE2n2LY.d.cts.map +1 -0
  32. package/package.json +15 -6
  33. package/dist/types-BB8mb_-T.d.cts.map +0 -1
  34. package/dist/types-D7uau0GM.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"protocolEndpoint.cjs","names":["activeAbortController: AbortController | undefined","activeExecutionId: string | undefined","runQuickJsSession"],"sources":["../../../protocol/src/messages.ts","../../src/runner/protocolEndpoint.ts"],"sourcesContent":["import type {\n ExecuteResult,\n ExecutorRuntimeOptions,\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRuntimeOptions(value: unknown): value is ExecutorRuntimeOptions {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n isFiniteNumber(value.maxLogChars) &&\n isFiniteNumber(value.maxLogLines) &&\n isFiniteNumber(value.memoryLimitBytes) &&\n isFiniteNumber(value.timeoutMs)\n );\n}\n\nfunction isProviderManifest(value: unknown): value is ProviderManifest {\n if (!isRecord(value) || typeof value.name !== \"string\") {\n return false;\n }\n\n if (!isRecord(value.tools) || typeof value.types !== \"string\") {\n return false;\n }\n\n return Object.values(value.tools).every(\n (tool) =>\n isRecord(tool) &&\n typeof tool.originalName === \"string\" &&\n typeof tool.safeName === \"string\" &&\n (tool.description === undefined || typeof tool.description === \"string\"),\n );\n}\n\nfunction isExecuteError(\n value: unknown,\n): value is { code: string; message: string } {\n return (\n isRecord(value) &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n}\n\nfunction isDonePayload(value: unknown): value is DoneMessage {\n if (!isRecord(value) || !isFiniteNumber(value.durationMs)) {\n return false;\n }\n\n if (\n !Array.isArray(value.logs) ||\n !value.logs.every((log) => typeof log === \"string\")\n ) {\n return false;\n }\n\n if (typeof value.ok !== \"boolean\") {\n return false;\n }\n\n return value.ok ? true : isExecuteError(value.error);\n}\n\n/**\n * Message sent from dispatcher to runner to start one execution session.\n */\nexport interface ExecuteMessage {\n code: string;\n id: string;\n options: ExecutorRuntimeOptions;\n providers: ProviderManifest[];\n type: \"execute\";\n}\n\n/**\n * Message sent from dispatcher to request prompt cancellation.\n */\nexport interface CancelMessage {\n id: string;\n type: \"cancel\";\n}\n\n/**\n * Message sent from a runner when guest code invokes a host tool.\n */\nexport interface ToolCallMessage extends ToolCall {\n callId: string;\n type: \"tool_call\";\n}\n\n/**\n * Message carrying a trusted host tool result back to the runner.\n */\nexport type ToolResultMessage = {\n callId: string;\n type: \"tool_result\";\n} & ToolCallResult;\n\n/**\n * Message indicating the runner has finished bootstrapping guest execution timing.\n */\nexport interface StartedMessage {\n id: string;\n type: \"started\";\n}\n\n/**\n * Final successful execution result returned by a runner.\n *\n * Node IPC can omit `undefined` fields during serialization, so `result`\n * remains optional at the protocol boundary and is normalized by the host.\n */\nexport type DoneSuccessMessage<T = unknown> = {\n durationMs: number;\n id: string;\n logs: string[];\n ok: true;\n result?: T;\n type: \"done\";\n};\n\n/**\n * Final failed execution result returned by a runner.\n */\nexport type DoneFailureMessage = {\n id: string;\n type: \"done\";\n} & Extract<ExecuteResult, { ok: false }>;\n\n/**\n * Final execution result returned by a runner.\n */\nexport type DoneMessage = DoneSuccessMessage | DoneFailureMessage;\n\n/**\n * Messages accepted by a runner transport endpoint.\n */\nexport type DispatcherMessage =\n | CancelMessage\n | ExecuteMessage\n | ToolResultMessage;\n\n/**\n * Messages emitted by a runner transport endpoint.\n */\nexport type RunnerMessage = DoneMessage | StartedMessage | ToolCallMessage;\n\n/**\n * Returns whether an unknown value is a dispatcher-to-runner message.\n */\nexport function isDispatcherMessage(\n value: unknown,\n): value is DispatcherMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"cancel\":\n return typeof value.id === \"string\";\n case \"execute\":\n return (\n typeof value.code === \"string\" &&\n typeof value.id === \"string\" &&\n isRuntimeOptions(value.options) &&\n Array.isArray(value.providers) &&\n value.providers.every(isProviderManifest)\n );\n case \"tool_result\":\n if (typeof value.callId !== \"string\" || typeof value.ok !== \"boolean\") {\n return false;\n }\n\n if (value.ok) {\n return \"result\" in value;\n }\n\n return isExecuteError(value.error);\n default:\n return false;\n }\n}\n\n/**\n * Returns whether an unknown value is a runner-to-dispatcher message.\n */\nexport function isRunnerMessage(value: unknown): value is RunnerMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"started\":\n return typeof value.id === \"string\";\n case \"tool_call\":\n return (\n typeof value.callId === \"string\" &&\n typeof value.providerName === \"string\" &&\n typeof value.safeToolName === \"string\" &&\n \"input\" in value\n );\n case \"done\":\n return typeof value.id === \"string\" && isDonePayload(value);\n default:\n return false;\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nimport type {\n DispatcherMessage,\n ExecuteMessage,\n RunnerMessage,\n ToolCallResult,\n} from \"@execbox/protocol\";\nimport { isDispatcherMessage } from \"../../../protocol/src/messages.ts\";\n\nimport { runQuickJsSession } from \"./index.ts\";\n\n/**\n * Minimal worker/process-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/process 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"],"mappings":"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"}
1
+ {"version":3,"file":"protocolEndpoint.cjs","names":["activeAbortController: AbortController | undefined","activeExecutionId: string | undefined","runQuickJsSession"],"sources":["../../../protocol/src/messages.ts","../../src/runner/protocolEndpoint.ts"],"sourcesContent":["import type {\n ExecuteResult,\n ExecutorRuntimeOptions,\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRuntimeOptions(value: unknown): value is ExecutorRuntimeOptions {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n isFiniteNumber(value.maxLogChars) &&\n isFiniteNumber(value.maxLogLines) &&\n isFiniteNumber(value.memoryLimitBytes) &&\n isFiniteNumber(value.timeoutMs)\n );\n}\n\nfunction isProviderManifest(value: unknown): value is ProviderManifest {\n if (!isRecord(value) || typeof value.name !== \"string\") {\n return false;\n }\n\n if (!isRecord(value.tools) || typeof value.types !== \"string\") {\n return false;\n }\n\n return Object.values(value.tools).every(\n (tool) =>\n isRecord(tool) &&\n typeof tool.originalName === \"string\" &&\n typeof tool.safeName === \"string\" &&\n (tool.description === undefined || typeof tool.description === \"string\"),\n );\n}\n\nfunction isExecuteError(\n value: unknown,\n): value is { code: string; message: string } {\n return (\n isRecord(value) &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n}\n\nfunction isDonePayload(value: unknown): value is DoneMessage {\n if (!isRecord(value) || !isFiniteNumber(value.durationMs)) {\n return false;\n }\n\n if (\n !Array.isArray(value.logs) ||\n !value.logs.every((log) => typeof log === \"string\")\n ) {\n return false;\n }\n\n if (typeof value.ok !== \"boolean\") {\n return false;\n }\n\n return value.ok ? true : isExecuteError(value.error);\n}\n\n/**\n * Message sent from dispatcher to runner to start one execution session.\n */\nexport interface ExecuteMessage {\n code: string;\n id: string;\n options: ExecutorRuntimeOptions;\n providers: ProviderManifest[];\n type: \"execute\";\n}\n\n/**\n * Message sent from dispatcher to request prompt cancellation.\n */\nexport interface CancelMessage {\n id: string;\n type: \"cancel\";\n}\n\n/**\n * Message sent from a runner when guest code invokes a host tool.\n */\nexport interface ToolCallMessage extends ToolCall {\n callId: string;\n type: \"tool_call\";\n}\n\n/**\n * Message carrying a trusted host tool result back to the runner.\n */\nexport type ToolResultMessage = {\n callId: string;\n type: \"tool_result\";\n} & ToolCallResult;\n\n/**\n * Message indicating the runner has finished bootstrapping guest execution timing.\n */\nexport interface StartedMessage {\n id: string;\n type: \"started\";\n}\n\n/**\n * Final successful execution result returned by a runner.\n *\n * Node IPC can omit `undefined` fields during serialization, so `result`\n * remains optional at the protocol boundary and is normalized by the host.\n */\nexport type DoneSuccessMessage<T = unknown> = {\n durationMs: number;\n id: string;\n logs: string[];\n ok: true;\n result?: T;\n type: \"done\";\n};\n\n/**\n * Final failed execution result returned by a runner.\n */\nexport type DoneFailureMessage = {\n id: string;\n type: \"done\";\n} & Extract<ExecuteResult, { ok: false }>;\n\n/**\n * Final execution result returned by a runner.\n */\nexport type DoneMessage = DoneSuccessMessage | DoneFailureMessage;\n\n/**\n * Messages accepted by a runner transport endpoint.\n */\nexport type DispatcherMessage =\n | CancelMessage\n | ExecuteMessage\n | ToolResultMessage;\n\n/**\n * Messages emitted by a runner transport endpoint.\n */\nexport type RunnerMessage = DoneMessage | StartedMessage | ToolCallMessage;\n\n/**\n * Returns whether an unknown value is a dispatcher-to-runner message.\n */\nexport function isDispatcherMessage(\n value: unknown,\n): value is DispatcherMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"cancel\":\n return typeof value.id === \"string\";\n case \"execute\":\n return (\n typeof value.code === \"string\" &&\n typeof value.id === \"string\" &&\n isRuntimeOptions(value.options) &&\n Array.isArray(value.providers) &&\n value.providers.every(isProviderManifest)\n );\n case \"tool_result\":\n if (typeof value.callId !== \"string\" || typeof value.ok !== \"boolean\") {\n return false;\n }\n\n if (value.ok) {\n return \"result\" in value;\n }\n\n return isExecuteError(value.error);\n default:\n return false;\n }\n}\n\n/**\n * Returns whether an unknown value is a runner-to-dispatcher message.\n */\nexport function isRunnerMessage(value: unknown): value is RunnerMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"started\":\n return typeof value.id === \"string\";\n case \"tool_call\":\n return (\n typeof value.callId === \"string\" &&\n typeof value.providerName === \"string\" &&\n typeof value.safeToolName === \"string\" &&\n \"input\" in value\n );\n case \"done\":\n return typeof value.id === \"string\" && isDonePayload(value);\n default:\n return false;\n }\n}\n","/**\n * @packageDocumentation\n * Public API for the `@execbox/quickjs/runner/protocol-endpoint` entrypoint.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n DispatcherMessage,\n ExecuteMessage,\n RunnerMessage,\n ToolCallResult,\n} from \"@execbox/protocol\";\n// This entrypoint is executed directly from source in worker/process tests before\n// workspace packages are built, so its runtime validator must stay source-local.\nimport { isDispatcherMessage } from \"../../../protocol/src/messages.ts\";\n\nimport { runQuickJsSession } from \"./index.ts\";\n\n/**\n * Minimal worker/process-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/process 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"],"mappings":"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"}
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Public TypeScript declarations for this package entrypoint.
4
+ */
1
5
  import { DispatcherMessage, RunnerMessage } from "@execbox/protocol";
2
6
 
3
7
  //#region src/runner/protocolEndpoint.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"protocolEndpoint.d.cts","names":[],"sources":["../../src/runner/protocolEndpoint.ts"],"sourcesContent":[],"mappings":";;;;;;AAeA;AAQgB,UARC,mBAAA,CAQ4B;+BAPd;gBACf;;;;;iBAMA,6BAAA,OACR"}
1
+ {"version":3,"file":"protocolEndpoint.d.cts","names":[],"sources":["../../src/runner/protocolEndpoint.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAqBA,CAAA,CAAA;AAQgB,SAAA,CARC,mBAAA,CAQ4B;+BAPd;gBACf;;;;;iBAMA,6BAAA,OACR"}
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Public TypeScript declarations for this package entrypoint.
4
+ */
1
5
  import { DispatcherMessage, RunnerMessage } from "@execbox/protocol";
2
6
 
3
7
  //#region src/runner/protocolEndpoint.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"protocolEndpoint.d.ts","names":[],"sources":["../../src/runner/protocolEndpoint.ts"],"sourcesContent":[],"mappings":";;;;;;AAeA;AAQgB,UARC,mBAAA,CAQ4B;+BAPd;gBACf;;;;;iBAMA,6BAAA,OACR"}
1
+ {"version":3,"file":"protocolEndpoint.d.ts","names":[],"sources":["../../src/runner/protocolEndpoint.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAqBA,CAAA,CAAA;AAQgB,SAAA,CARC,mBAAA,CAQ4B;+BAPd;gBACf;;;;;iBAMA,6BAAA,OACR"}
@@ -1,4 +1,4 @@
1
- import { t as runQuickJsSession } from "../runner-O4f_FOhI.js";
1
+ import { t as runQuickJsSession } from "../runner-CVaY4RVQ.js";
2
2
  import { randomUUID } from "node:crypto";
3
3
 
4
4
  //#region ../protocol/src/messages.ts
@@ -39,6 +39,10 @@ function isDispatcherMessage(value) {
39
39
  //#endregion
40
40
  //#region src/runner/protocolEndpoint.ts
41
41
  /**
42
+ * @packageDocumentation
43
+ * Public API for the `@execbox/quickjs/runner/protocol-endpoint` entrypoint.
44
+ */
45
+ /**
42
46
  * Attaches the shared QuickJS protocol loop to a worker/process messaging port.
43
47
  */
44
48
  function attachQuickJsProtocolEndpoint(port) {
@@ -1 +1 @@
1
- {"version":3,"file":"protocolEndpoint.js","names":["activeAbortController: AbortController | undefined","activeExecutionId: string | undefined"],"sources":["../../../protocol/src/messages.ts","../../src/runner/protocolEndpoint.ts"],"sourcesContent":["import type {\n ExecuteResult,\n ExecutorRuntimeOptions,\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRuntimeOptions(value: unknown): value is ExecutorRuntimeOptions {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n isFiniteNumber(value.maxLogChars) &&\n isFiniteNumber(value.maxLogLines) &&\n isFiniteNumber(value.memoryLimitBytes) &&\n isFiniteNumber(value.timeoutMs)\n );\n}\n\nfunction isProviderManifest(value: unknown): value is ProviderManifest {\n if (!isRecord(value) || typeof value.name !== \"string\") {\n return false;\n }\n\n if (!isRecord(value.tools) || typeof value.types !== \"string\") {\n return false;\n }\n\n return Object.values(value.tools).every(\n (tool) =>\n isRecord(tool) &&\n typeof tool.originalName === \"string\" &&\n typeof tool.safeName === \"string\" &&\n (tool.description === undefined || typeof tool.description === \"string\"),\n );\n}\n\nfunction isExecuteError(\n value: unknown,\n): value is { code: string; message: string } {\n return (\n isRecord(value) &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n}\n\nfunction isDonePayload(value: unknown): value is DoneMessage {\n if (!isRecord(value) || !isFiniteNumber(value.durationMs)) {\n return false;\n }\n\n if (\n !Array.isArray(value.logs) ||\n !value.logs.every((log) => typeof log === \"string\")\n ) {\n return false;\n }\n\n if (typeof value.ok !== \"boolean\") {\n return false;\n }\n\n return value.ok ? true : isExecuteError(value.error);\n}\n\n/**\n * Message sent from dispatcher to runner to start one execution session.\n */\nexport interface ExecuteMessage {\n code: string;\n id: string;\n options: ExecutorRuntimeOptions;\n providers: ProviderManifest[];\n type: \"execute\";\n}\n\n/**\n * Message sent from dispatcher to request prompt cancellation.\n */\nexport interface CancelMessage {\n id: string;\n type: \"cancel\";\n}\n\n/**\n * Message sent from a runner when guest code invokes a host tool.\n */\nexport interface ToolCallMessage extends ToolCall {\n callId: string;\n type: \"tool_call\";\n}\n\n/**\n * Message carrying a trusted host tool result back to the runner.\n */\nexport type ToolResultMessage = {\n callId: string;\n type: \"tool_result\";\n} & ToolCallResult;\n\n/**\n * Message indicating the runner has finished bootstrapping guest execution timing.\n */\nexport interface StartedMessage {\n id: string;\n type: \"started\";\n}\n\n/**\n * Final successful execution result returned by a runner.\n *\n * Node IPC can omit `undefined` fields during serialization, so `result`\n * remains optional at the protocol boundary and is normalized by the host.\n */\nexport type DoneSuccessMessage<T = unknown> = {\n durationMs: number;\n id: string;\n logs: string[];\n ok: true;\n result?: T;\n type: \"done\";\n};\n\n/**\n * Final failed execution result returned by a runner.\n */\nexport type DoneFailureMessage = {\n id: string;\n type: \"done\";\n} & Extract<ExecuteResult, { ok: false }>;\n\n/**\n * Final execution result returned by a runner.\n */\nexport type DoneMessage = DoneSuccessMessage | DoneFailureMessage;\n\n/**\n * Messages accepted by a runner transport endpoint.\n */\nexport type DispatcherMessage =\n | CancelMessage\n | ExecuteMessage\n | ToolResultMessage;\n\n/**\n * Messages emitted by a runner transport endpoint.\n */\nexport type RunnerMessage = DoneMessage | StartedMessage | ToolCallMessage;\n\n/**\n * Returns whether an unknown value is a dispatcher-to-runner message.\n */\nexport function isDispatcherMessage(\n value: unknown,\n): value is DispatcherMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"cancel\":\n return typeof value.id === \"string\";\n case \"execute\":\n return (\n typeof value.code === \"string\" &&\n typeof value.id === \"string\" &&\n isRuntimeOptions(value.options) &&\n Array.isArray(value.providers) &&\n value.providers.every(isProviderManifest)\n );\n case \"tool_result\":\n if (typeof value.callId !== \"string\" || typeof value.ok !== \"boolean\") {\n return false;\n }\n\n if (value.ok) {\n return \"result\" in value;\n }\n\n return isExecuteError(value.error);\n default:\n return false;\n }\n}\n\n/**\n * Returns whether an unknown value is a runner-to-dispatcher message.\n */\nexport function isRunnerMessage(value: unknown): value is RunnerMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"started\":\n return typeof value.id === \"string\";\n case \"tool_call\":\n return (\n typeof value.callId === \"string\" &&\n typeof value.providerName === \"string\" &&\n typeof value.safeToolName === \"string\" &&\n \"input\" in value\n );\n case \"done\":\n return typeof value.id === \"string\" && isDonePayload(value);\n default:\n return false;\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nimport type {\n DispatcherMessage,\n ExecuteMessage,\n RunnerMessage,\n ToolCallResult,\n} from \"@execbox/protocol\";\nimport { isDispatcherMessage } from \"../../../protocol/src/messages.ts\";\n\nimport { runQuickJsSession } from \"./index.ts\";\n\n/**\n * Minimal worker/process-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/process 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"],"mappings":";;;;AAQA,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU;;AAGhD,SAAS,eAAe,OAAiC;AACvD,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM;;AAG5D,SAAS,iBAAiB,OAAiD;AACzE,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO;AAGT,QACE,eAAe,MAAM,YAAY,IACjC,eAAe,MAAM,YAAY,IACjC,eAAe,MAAM,iBAAiB,IACtC,eAAe,MAAM,UAAU;;AAInC,SAAS,mBAAmB,OAA2C;AACrE,KAAI,CAAC,SAAS,MAAM,IAAI,OAAO,MAAM,SAAS,SAC5C,QAAO;AAGT,KAAI,CAAC,SAAS,MAAM,MAAM,IAAI,OAAO,MAAM,UAAU,SACnD,QAAO;AAGT,QAAO,OAAO,OAAO,MAAM,MAAM,CAAC,OAC/B,SACC,SAAS,KAAK,IACd,OAAO,KAAK,iBAAiB,YAC7B,OAAO,KAAK,aAAa,aACxB,KAAK,gBAAgB,UAAa,OAAO,KAAK,gBAAgB,UAClE;;AAGH,SAAS,eACP,OAC4C;AAC5C,QACE,SAAS,MAAM,IACf,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,YAAY;;;;;AA8G7B,SAAgB,oBACd,OAC4B;AAC5B,KAAI,CAAC,SAAS,MAAM,IAAI,OAAO,MAAM,SAAS,SAC5C,QAAO;AAGT,SAAQ,MAAM,MAAd;EACE,KAAK,SACH,QAAO,OAAO,MAAM,OAAO;EAC7B,KAAK,UACH,QACE,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,OAAO,YACpB,iBAAiB,MAAM,QAAQ,IAC/B,MAAM,QAAQ,MAAM,UAAU,IAC9B,MAAM,UAAU,MAAM,mBAAmB;EAE7C,KAAK;AACH,OAAI,OAAO,MAAM,WAAW,YAAY,OAAO,MAAM,OAAO,UAC1D,QAAO;AAGT,OAAI,MAAM,GACR,QAAO,YAAY;AAGrB,UAAO,eAAe,MAAM,MAAM;EACpC,QACE,QAAO;;;;;;;;;ACzKb,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,MAAM,kBACnB;IACE;IACA,MAAM,QAAQ;IACd,iBAAiB;AACf,UAAK,KAAK;MACR,IAAI,QAAQ;MACZ,MAAM;MACP,CAAC;;IAEJ,aAAa,SACX,IAAI,SAAyB,YAAY;KACvC,MAAM,SAAS,YAAY;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,CAAC,oBAAoB,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"}
1
+ {"version":3,"file":"protocolEndpoint.js","names":["activeAbortController: AbortController | undefined","activeExecutionId: string | undefined"],"sources":["../../../protocol/src/messages.ts","../../src/runner/protocolEndpoint.ts"],"sourcesContent":["import type {\n ExecuteResult,\n ExecutorRuntimeOptions,\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRuntimeOptions(value: unknown): value is ExecutorRuntimeOptions {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n isFiniteNumber(value.maxLogChars) &&\n isFiniteNumber(value.maxLogLines) &&\n isFiniteNumber(value.memoryLimitBytes) &&\n isFiniteNumber(value.timeoutMs)\n );\n}\n\nfunction isProviderManifest(value: unknown): value is ProviderManifest {\n if (!isRecord(value) || typeof value.name !== \"string\") {\n return false;\n }\n\n if (!isRecord(value.tools) || typeof value.types !== \"string\") {\n return false;\n }\n\n return Object.values(value.tools).every(\n (tool) =>\n isRecord(tool) &&\n typeof tool.originalName === \"string\" &&\n typeof tool.safeName === \"string\" &&\n (tool.description === undefined || typeof tool.description === \"string\"),\n );\n}\n\nfunction isExecuteError(\n value: unknown,\n): value is { code: string; message: string } {\n return (\n isRecord(value) &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n}\n\nfunction isDonePayload(value: unknown): value is DoneMessage {\n if (!isRecord(value) || !isFiniteNumber(value.durationMs)) {\n return false;\n }\n\n if (\n !Array.isArray(value.logs) ||\n !value.logs.every((log) => typeof log === \"string\")\n ) {\n return false;\n }\n\n if (typeof value.ok !== \"boolean\") {\n return false;\n }\n\n return value.ok ? true : isExecuteError(value.error);\n}\n\n/**\n * Message sent from dispatcher to runner to start one execution session.\n */\nexport interface ExecuteMessage {\n code: string;\n id: string;\n options: ExecutorRuntimeOptions;\n providers: ProviderManifest[];\n type: \"execute\";\n}\n\n/**\n * Message sent from dispatcher to request prompt cancellation.\n */\nexport interface CancelMessage {\n id: string;\n type: \"cancel\";\n}\n\n/**\n * Message sent from a runner when guest code invokes a host tool.\n */\nexport interface ToolCallMessage extends ToolCall {\n callId: string;\n type: \"tool_call\";\n}\n\n/**\n * Message carrying a trusted host tool result back to the runner.\n */\nexport type ToolResultMessage = {\n callId: string;\n type: \"tool_result\";\n} & ToolCallResult;\n\n/**\n * Message indicating the runner has finished bootstrapping guest execution timing.\n */\nexport interface StartedMessage {\n id: string;\n type: \"started\";\n}\n\n/**\n * Final successful execution result returned by a runner.\n *\n * Node IPC can omit `undefined` fields during serialization, so `result`\n * remains optional at the protocol boundary and is normalized by the host.\n */\nexport type DoneSuccessMessage<T = unknown> = {\n durationMs: number;\n id: string;\n logs: string[];\n ok: true;\n result?: T;\n type: \"done\";\n};\n\n/**\n * Final failed execution result returned by a runner.\n */\nexport type DoneFailureMessage = {\n id: string;\n type: \"done\";\n} & Extract<ExecuteResult, { ok: false }>;\n\n/**\n * Final execution result returned by a runner.\n */\nexport type DoneMessage = DoneSuccessMessage | DoneFailureMessage;\n\n/**\n * Messages accepted by a runner transport endpoint.\n */\nexport type DispatcherMessage =\n | CancelMessage\n | ExecuteMessage\n | ToolResultMessage;\n\n/**\n * Messages emitted by a runner transport endpoint.\n */\nexport type RunnerMessage = DoneMessage | StartedMessage | ToolCallMessage;\n\n/**\n * Returns whether an unknown value is a dispatcher-to-runner message.\n */\nexport function isDispatcherMessage(\n value: unknown,\n): value is DispatcherMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"cancel\":\n return typeof value.id === \"string\";\n case \"execute\":\n return (\n typeof value.code === \"string\" &&\n typeof value.id === \"string\" &&\n isRuntimeOptions(value.options) &&\n Array.isArray(value.providers) &&\n value.providers.every(isProviderManifest)\n );\n case \"tool_result\":\n if (typeof value.callId !== \"string\" || typeof value.ok !== \"boolean\") {\n return false;\n }\n\n if (value.ok) {\n return \"result\" in value;\n }\n\n return isExecuteError(value.error);\n default:\n return false;\n }\n}\n\n/**\n * Returns whether an unknown value is a runner-to-dispatcher message.\n */\nexport function isRunnerMessage(value: unknown): value is RunnerMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"started\":\n return typeof value.id === \"string\";\n case \"tool_call\":\n return (\n typeof value.callId === \"string\" &&\n typeof value.providerName === \"string\" &&\n typeof value.safeToolName === \"string\" &&\n \"input\" in value\n );\n case \"done\":\n return typeof value.id === \"string\" && isDonePayload(value);\n default:\n return false;\n }\n}\n","/**\n * @packageDocumentation\n * Public API for the `@execbox/quickjs/runner/protocol-endpoint` entrypoint.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n DispatcherMessage,\n ExecuteMessage,\n RunnerMessage,\n ToolCallResult,\n} from \"@execbox/protocol\";\n// This entrypoint is executed directly from source in worker/process tests before\n// workspace packages are built, so its runtime validator must stay source-local.\nimport { isDispatcherMessage } from \"../../../protocol/src/messages.ts\";\n\nimport { runQuickJsSession } from \"./index.ts\";\n\n/**\n * Minimal worker/process-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/process 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"],"mappings":"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"}
@@ -28,6 +28,20 @@ function getExecutionTimeoutMessage() {
28
28
  return EXECUTION_TIMEOUT_MESSAGE;
29
29
  }
30
30
  /**
31
+ * Creates the canonical timeout failure result used for preflight cancellation.
32
+ */
33
+ function createTimeoutExecuteResult(durationMs = 0) {
34
+ return {
35
+ durationMs,
36
+ error: {
37
+ code: "timeout",
38
+ message: getExecutionTimeoutMessage()
39
+ },
40
+ logs: [],
41
+ ok: false
42
+ };
43
+ }
44
+ /**
31
45
  * Normalizes an unknown thrown value into a human-readable message.
32
46
  */
33
47
  function normalizeThrownMessage(error) {
@@ -39,6 +53,17 @@ function normalizeThrownMessage(error) {
39
53
  return String(error);
40
54
  }
41
55
  /**
56
+ * Builds the standard tool execution context passed to resolved tool wrappers.
57
+ */
58
+ function createExecutionContext(signal, providerName, safeToolName, originalToolName) {
59
+ return {
60
+ originalToolName,
61
+ providerName,
62
+ safeToolName,
63
+ signal
64
+ };
65
+ }
66
+ /**
42
67
  * Truncates captured logs to the configured line and character limits.
43
68
  */
44
69
  function truncateLogs(logs, maxLogLines, maxLogChars) {
@@ -5226,6 +5251,42 @@ var ExecuteFailure = class extends Error {
5226
5251
  function isExecuteFailure(value) {
5227
5252
  return value instanceof ExecuteFailure;
5228
5253
  }
5254
+ /**
5255
+ * Returns whether a value can be serialized through the JSON-only host/guest boundary.
5256
+ */
5257
+ function isJsonSerializable(value, active = /* @__PURE__ */ new Set(), memo = /* @__PURE__ */ new WeakSet()) {
5258
+ if (value === null) return true;
5259
+ switch (typeof value) {
5260
+ case "string":
5261
+ case "boolean": return true;
5262
+ case "number": return Number.isFinite(value);
5263
+ case "bigint":
5264
+ case "function":
5265
+ case "symbol":
5266
+ case "undefined": return false;
5267
+ case "object": {
5268
+ const objectValue = value;
5269
+ if (memo.has(objectValue)) return true;
5270
+ if (active.has(objectValue)) return false;
5271
+ active.add(objectValue);
5272
+ let isSerializable = false;
5273
+ try {
5274
+ if (Array.isArray(value)) {
5275
+ isSerializable = value.every((item) => isJsonSerializable(item, active, memo));
5276
+ return isSerializable;
5277
+ }
5278
+ const prototype = Object.getPrototypeOf(value);
5279
+ if (prototype !== Object.prototype && prototype !== null) return false;
5280
+ isSerializable = Object.values(value).every((item) => isJsonSerializable(item, active, memo));
5281
+ return isSerializable;
5282
+ } finally {
5283
+ active.delete(objectValue);
5284
+ if (isSerializable) memo.add(objectValue);
5285
+ }
5286
+ }
5287
+ }
5288
+ return false;
5289
+ }
5229
5290
 
5230
5291
  //#endregion
5231
5292
  //#region src/quickjsBridge.ts
@@ -5282,6 +5343,10 @@ function toGuestHandle(context, value) {
5282
5343
 
5283
5344
  //#endregion
5284
5345
  //#region src/runner/index.ts
5346
+ /**
5347
+ * @packageDocumentation
5348
+ * Public API for the `@execbox/quickjs/runner` entrypoint.
5349
+ */
5285
5350
  const DEFAULT_MEMORY_LIMIT_BYTES = 64 * 1024 * 1024;
5286
5351
  const DEFAULT_TIMEOUT_MS = 5e3;
5287
5352
  const DEFAULT_MAX_LOG_LINES = 100;
@@ -5480,6 +5545,7 @@ function createToolHandle(context, providerName, safeToolName, signal, trustedHo
5480
5545
  */
5481
5546
  async function runQuickJsSession(request, options = {}) {
5482
5547
  const loadModule = async () => {
5548
+ if (options.module) return options.module;
5483
5549
  return options.loadModule ? await options.loadModule() : await loadDefaultModule();
5484
5550
  };
5485
5551
  const maxLogChars = options.maxLogChars ?? DEFAULT_MAX_LOG_CHARS;
@@ -5566,10 +5632,52 @@ async function runQuickJsSession(request, options = {}) {
5566
5632
  }
5567
5633
 
5568
5634
  //#endregion
5635
+ Object.defineProperty(exports, 'ExecuteFailure', {
5636
+ enumerable: true,
5637
+ get: function () {
5638
+ return ExecuteFailure;
5639
+ }
5640
+ });
5641
+ Object.defineProperty(exports, 'createExecutionContext', {
5642
+ enumerable: true,
5643
+ get: function () {
5644
+ return createExecutionContext;
5645
+ }
5646
+ });
5647
+ Object.defineProperty(exports, 'createTimeoutExecuteResult', {
5648
+ enumerable: true,
5649
+ get: function () {
5650
+ return createTimeoutExecuteResult;
5651
+ }
5652
+ });
5653
+ Object.defineProperty(exports, 'getExecutionTimeoutMessage', {
5654
+ enumerable: true,
5655
+ get: function () {
5656
+ return getExecutionTimeoutMessage;
5657
+ }
5658
+ });
5659
+ Object.defineProperty(exports, 'isExecuteFailure', {
5660
+ enumerable: true,
5661
+ get: function () {
5662
+ return isExecuteFailure;
5663
+ }
5664
+ });
5665
+ Object.defineProperty(exports, 'isJsonSerializable', {
5666
+ enumerable: true,
5667
+ get: function () {
5668
+ return isJsonSerializable;
5669
+ }
5670
+ });
5671
+ Object.defineProperty(exports, 'normalizeThrownMessage', {
5672
+ enumerable: true,
5673
+ get: function () {
5674
+ return normalizeThrownMessage;
5675
+ }
5676
+ });
5569
5677
  Object.defineProperty(exports, 'runQuickJsSession', {
5570
5678
  enumerable: true,
5571
5679
  get: function () {
5572
5680
  return runQuickJsSession;
5573
5681
  }
5574
5682
  });
5575
- //# sourceMappingURL=runner-9_N9h2rp.cjs.map
5683
+ //# sourceMappingURL=runner-BqkDnP0t.cjs.map