refactor(e2b): group remote providers

This commit is contained in:
Tianyi Cui
2026-08-08 22:19:10 +08:00
parent 6667102890
commit e64d40837c
81 changed files with 171 additions and 249 deletions
+441
View File
@@ -0,0 +1,441 @@
/** E2B process/worker implementation of the harness code-runtime seam. */
import { posix } from 'node:path'
import { stripTypeScriptTypes } from 'node:module'
import type { Context } from 'cordis'
import z from 'schemastery'
import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime'
import type {
CodeBindingNamespace,
CodeJsonValue,
CodeRunFailure,
CodeRunRequest,
CodeRunResult,
} from '@deepseek-ai/dsh-code-runtime'
import {
E2BFrameDecoder,
encodeE2BFrame,
quoteE2BShellArg,
resolveE2BExecutable,
} from '@deepseek-ai/dsh-e2b'
import {
decodeWorkerJson,
encodeWorkerJson,
OutputLedger,
} from '@deepseek-ai/dsh-code-runtime-worker'
import type { WorkerJsonWire } from '@deepseek-ai/dsh-code-runtime-worker'
import { snapshotJsonValue } from '@deepseek-ai/dsh-session'
import E2BSubprocessService from '@deepseek-ai/dsh-subprocess-e2b'
import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
import { CODE_RUNNER_SOURCE } from './runner-source.ts'
/** Runtime configuration; every execution and bridge bound is deployment-tunable. */
export interface Config {
/** Remote worker measured event-loop busy-time budget. */
computeMs?: number
/** Host-observed wall-clock ceiling. */
maxWallMs?: number
/** Combined serialized outer logs/value/diagnostic cap. */
maxOutputBytes?: number
/** Remote worker old-generation heap cap in MiB. */
maxOldGenerationSizeMb?: number
/** Largest decoded bridge frame, including binding traffic. */
maxFrameBytes?: number
/** Remote process-group TERM-to-KILL grace. */
killGraceMs?: number
}
type ResolvedConfig = Required<Config>
interface LiveRun {
settle(failure: CodeRunFailure): void
finished: Promise<void>
}
interface CallMessage {
type: 'call'
id: number
global: string
name: string
args: WorkerJsonWire
}
interface LogMessage {
type: 'log'
text: string
}
interface DoneMessage {
type: 'done'
value?: WorkerJsonWire
error?: CodeRunFailure
}
type RunnerMessage = CallMessage | LogMessage | DoneMessage | { type: 'output-limit' }
const STRIP_WRAP = { prefix: 'async function __dsh_program__() {\n', suffix: '\n}' } as const
const MIN_OUTPUT_BYTES = 4
const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/
/* jscpd:ignore-start -- Backends enforce the same injected-global vocabulary without coupling lifecycle implementations. */
const RESERVED_WORDS = new Set([
'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do',
'else', 'enum', 'export', 'extends', 'false', 'finally', 'for', 'function', 'if', 'import', 'in',
'instanceof', 'new', 'null', 'return', 'super', 'switch', 'this', 'throw', 'true', 'try', 'typeof',
'var', 'void', 'while', 'with', 'yield', 'let', 'static', 'implements', 'interface', 'package',
'private', 'protected', 'public', 'arguments', 'eval',
])
const RESERVED_ERROR_PROPERTIES = new Set(['name', 'message', 'stack'])
/* jscpd:ignore-end */
const FAILURE_KINDS = new Set<CodeRunFailure['kind']>([
'exception', 'timeout', 'abort', 'worker-exit', 'invalid-output', 'output-limit',
])
function messageOf(error: unknown): string {
return error instanceof Error ? error.message : String(error)
}
function parseRunnerMessage(raw: unknown): RunnerMessage | undefined {
if (typeof raw !== 'object' || raw === null) return undefined
const record = raw as Record<string, unknown>
if (record.type === 'output-limit') return { type: 'output-limit' }
if (record.type === 'log') return typeof record.text === 'string' ? { type: 'log', text: record.text } : undefined
if (record.type === 'call') {
if (!Number.isSafeInteger(record.id) || (record.id as number) < 1 || typeof record.global !== 'string' || typeof record.name !== 'string' || !Array.isArray(record.args)) return undefined
return { type: 'call', id: record.id as number, global: record.global, name: record.name, args: record.args as WorkerJsonWire }
}
if (record.type !== 'done') return undefined
if (record.error === undefined) {
return { type: 'done', ...record.value === undefined ? {} : { value: record.value as WorkerJsonWire } }
}
if (typeof record.error !== 'object' || record.error === null) return undefined
const error = record.error as Record<string, unknown>
if (typeof error.kind !== 'string' || !FAILURE_KINDS.has(error.kind as CodeRunFailure['kind']) || typeof error.message !== 'string') return undefined
return { type: 'done', error: { kind: error.kind as CodeRunFailure['kind'], message: error.message } }
}
/** E2B-backed runtime: host-side type stripping, remote worker execution, host binding dispatch. */
export class E2BCodeRuntime extends CodeRuntime {
static inject = ['e2b', 'subprocess']
static Config: z<Config> = z.object({
computeMs: z.number().default(60_000),
maxWallMs: z.number().default(600_000),
maxOutputBytes: z.number().default(67_108_864),
maxOldGenerationSizeMb: z.number().default(512),
maxFrameBytes: z.number().default(268_435_456),
killGraceMs: z.number().default(2_000),
})
readonly language = 'typescript'
readonly isolation = 'container'
private readonly config: ResolvedConfig
private readonly ready: Promise<{ node: string; runner: string }>
private readonly live = new Set<LiveRun>()
private readonly subprocess: E2BSubprocessService
private disposed = false
constructor(ctx: Context, config: Config) {
super(ctx)
if (!(ctx.subprocess instanceof E2BSubprocessService)) {
throw new Error('code-runtime-e2b requires @deepseek-ai/dsh-subprocess-e2b as ctx.subprocess')
}
this.subprocess = ctx.subprocess
this.config = config as ResolvedConfig
for (const [key, value] of Object.entries(this.config)) {
if (!Number.isSafeInteger(value) || value <= 0) {
throw new Error(`code-runtime-e2b: config.${key} must be a positive safe integer`)
}
}
if (this.config.maxOutputBytes < MIN_OUTPUT_BYTES) {
throw new Error(`code-runtime-e2b: config.maxOutputBytes must be at least ${MIN_OUTPUT_BYTES}`)
}
if (this.config.maxWallMs > MAX_TIMER_DELAY_MS) {
throw new Error(`code-runtime-e2b: config.maxWallMs must be at most ${MAX_TIMER_DELAY_MS}`)
}
if (this.config.maxFrameBytes < this.config.maxOutputBytes) {
throw new Error('code-runtime-e2b: config.maxFrameBytes must be at least maxOutputBytes')
}
this.ready = this.prepare()
void this.ready.catch(() => {})
ctx.effect(() => () => this.teardown(), 'E2B code-runtime teardown')
}
/* jscpd:ignore-start -- Seam-level abort and type-strip results remain identical across execution substrates. */
/** Execute one type-stripped program in a fresh E2B worker process. */
async run(request: CodeRunRequest): Promise<CodeRunResult> {
if (this.disposed) throw new Error('code-runtime-e2b: run() after disposal')
const bindings = this.validateBindings(request)
if (request.signal?.aborted === true) {
return this.failure({ kind: 'abort', message: String(request.signal.reason) })
}
let code: string
try {
const stripped = stripTypeScriptTypes(STRIP_WRAP.prefix + request.program + STRIP_WRAP.suffix)
code = stripped.slice(STRIP_WRAP.prefix.length, stripped.length - STRIP_WRAP.suffix.length)
} catch (error: unknown) {
return this.failure({ kind: 'exception', message: messageOf(error) })
}
let runtime: Awaited<typeof this.ready>
try {
runtime = await this.ready
} catch (error: unknown) {
return this.failure({ kind: 'worker-exit', message: `E2B runtime setup failed: ${messageOf(error)}` })
}
// Disposal can race the awaited remote setup after the pre-await check.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (this.disposed) return this.failure({ kind: 'abort', message: 'runtime disposed' })
return await this.execute(request, code, bindings, runtime)
}
/* jscpd:ignore-end */
private async prepare(): Promise<{ node: string; runner: string }> {
const sandbox = await this.ctx.e2b.getSandbox()
const runner = posix.join(this.ctx.e2b.runtimeRoot, 'code-runtime-runner.mjs')
await sandbox.files.write([{ path: runner, data: CODE_RUNNER_SOURCE }])
await sandbox.commands.run(`chmod 600 -- ${quoteE2BShellArg(runner)}`)
const node = await resolveE2BExecutable(sandbox, 'node')
return { node, runner }
}
private failure(error: CodeRunFailure): CodeRunResult {
return new OutputLedger(this.config.maxOutputBytes).failure([], error)
}
/* jscpd:ignore-start -- Binding names have one seam contract while dispatch and teardown remain backend-owned. */
private validateBindings(request: CodeRunRequest): Map<string, CodeBindingNamespace> {
const bindings = new Map<string, CodeBindingNamespace>()
for (const namespace of request.bindings) {
if (!IDENTIFIER.test(namespace.global) || RESERVED_WORDS.has(namespace.global)) {
throw new Error(`code-runtime-e2b: binding global ${JSON.stringify(namespace.global)} is not a usable identifier`)
}
if (namespace.global === 'console' || bindings.has(namespace.global)) {
throw new Error(`code-runtime-e2b: duplicate binding global ${JSON.stringify(namespace.global)}`)
}
bindings.set(namespace.global, namespace)
}
const errorClassNames = new Set<string>()
for (const namespace of request.bindings) {
const descriptor = namespace.errorClass
if (descriptor === undefined) continue
if (!IDENTIFIER.test(descriptor.name) || RESERVED_WORDS.has(descriptor.name)) {
throw new Error(`code-runtime-e2b: binding error class ${JSON.stringify(descriptor.name)} is not a usable identifier`)
}
if (descriptor.name === 'console' || bindings.has(descriptor.name) || errorClassNames.has(descriptor.name)) {
throw new Error(`code-runtime-e2b: duplicate injected global ${JSON.stringify(descriptor.name)}`)
}
if (descriptor.memberNameProperty.length === 0 || RESERVED_ERROR_PROPERTIES.has(descriptor.memberNameProperty)) {
throw new Error(`code-runtime-e2b: binding error member property ${JSON.stringify(descriptor.memberNameProperty)} is not usable`)
}
errorClassNames.add(descriptor.name)
}
return bindings
}
/* jscpd:ignore-end */
private async execute(
request: CodeRunRequest,
code: string,
bindings: Map<string, CodeBindingNamespace>,
runtime: { node: string; runner: string },
): Promise<CodeRunResult> {
const handle = this.subprocess.spawn({
argv: [runtime.node, runtime.runner],
cwd: this.ctx.e2b.cwd,
stdio: { stdin: 'pipe', stdout: 'pipe', stderr: { maxBytes: this.config.maxOutputBytes } },
graceMs: this.config.killGraceMs,
...request.signal === undefined ? {} : { signal: request.signal },
env: {},
})
if (handle.stdin === undefined || handle.stdout === undefined) {
handle.terminate()
await Promise.allSettled([handle.done])
try {
await handle.waitForExit()
} catch (error: unknown) {
return this.failure({ kind: 'worker-exit', message: `E2B runtime cleanup failed: ${messageOf(error)}` })
}
return this.failure({ kind: 'worker-exit', message: 'E2B subprocess dropped a piped runtime stream' })
}
const stdin = handle.stdin
const stdout = handle.stdout
return new Promise<CodeRunResult>((resolve) => {
const output = new OutputLedger(this.config.maxOutputBytes)
const logs: string[] = []
const answered = new Set<number>()
const decoder = new E2BFrameDecoder(this.config.maxFrameBytes)
let settled = false
let finishResolve!: () => void
const finished = new Promise<void>((done) => { finishResolve = done })
const wallTimer: { current: NodeJS.Timeout | undefined } = { current: undefined }
const live: LiveRun = {
finished,
settle: (failure) => { finish(() => output.failure(logs, failure)) },
}
const finish = (result: CodeRunResult | (() => CodeRunResult)): void => {
if (settled) return
settled = true
clearTimeout(wallTimer.current)
request.signal?.removeEventListener('abort', onAbort)
this.live.delete(live)
void new Promise<void>((resume) => { setImmediate(resume) }).then(async () => {
handle.terminate()
await handle.done.catch(() => {})
let cleanupError: unknown
try {
await handle.waitForExit()
} catch (error: unknown) {
cleanupError = error
}
try {
decoder.finish()
} catch (error: unknown) {
result = output.failure(logs, { kind: 'worker-exit', message: messageOf(error) })
}
if (cleanupError !== undefined) {
result = output.failure(logs, { kind: 'worker-exit', message: `E2B runtime cleanup failed: ${messageOf(cleanupError)}` })
}
const final = typeof result === 'function' ? result() : result
finishResolve()
resolve(final)
})
}
const sendReply = (message: unknown): void => {
if (settled) return
stdin.write(encodeE2BFrame(message), (error?: Error | null) => {
if (error !== undefined && error !== null) {
finish(() => output.failure(logs, { kind: 'worker-exit', message: `E2B runtime bridge write failed: ${error.message}` }))
}
})
}
/* jscpd:ignore-start -- Host binding resolution mirrors worker semantics over a different transport. */
const onCall = (message: CallMessage): void => {
if (answered.has(message.id)) return
answered.add(message.id)
const functions = bindings.get(message.global)?.functions
const fn = functions !== undefined && Object.hasOwn(functions, message.name) ? functions[message.name] : undefined
if (typeof fn !== 'function') {
sendReply({ type: 'reply', id: message.id, ok: false, message: `unknown binding ${JSON.stringify(`${message.global}.${message.name}`)}` })
return
}
const args = decodeWorkerJson(message.args)
if (args === undefined) {
sendReply({ type: 'reply', id: message.id, ok: false, message: 'binding arguments must be lossless JSON' })
return
}
void (async () => {
try {
const resolved = await fn(args)
let value: CodeJsonValue | undefined
try {
value = snapshotJsonValue(resolved)
} catch {
value = undefined
}
if (value === undefined) {
sendReply({ type: 'reply', id: message.id, ok: false, message: 'binding resolution must be lossless JSON' })
} else {
sendReply({ type: 'reply', id: message.id, ok: true, value: encodeWorkerJson(value) })
}
} catch (error: unknown) {
sendReply({ type: 'reply', id: message.id, ok: false, message: messageOf(error) })
}
})()
}
/* jscpd:ignore-end */
const onMessage = (raw: unknown): void => {
if (settled) return
const message = parseRunnerMessage(raw)
if (message === undefined) return
if (message.type === 'log') {
if (!output.admit(message.text, logs)) finish(output.limit([...logs, message.text]))
return
}
if (message.type === 'output-limit') {
finish(output.limit(logs))
return
}
if (message.type === 'call') {
onCall(message)
return
}
if (message.error !== undefined) {
finish(() => output.failure(logs, message.error as CodeRunFailure))
} else if (message.value === undefined) {
finish(() => output.success(logs))
} else {
const value = decodeWorkerJson(message.value)
if (value === undefined) finish(() => output.failure(logs, { kind: 'invalid-output', message: 'program completion must be lossless JSON' }))
else finish(() => output.success(logs, value))
}
}
stdout.on('data', (chunk: Buffer) => {
if (settled) return
try {
for (const frame of decoder.push(chunk.toString('utf8'))) onMessage(frame)
} catch (error: unknown) {
finish(() => output.failure(logs, { kind: 'worker-exit', message: `E2B runtime bridge failed: ${messageOf(error)}` }))
}
})
stdout.on('error', (error: Error) => {
finish(() => output.failure(logs, { kind: 'worker-exit', message: `E2B runtime stdout failed: ${error.message}` }))
})
stdin.on('error', (error: Error) => {
finish(() => output.failure(logs, { kind: 'worker-exit', message: `E2B runtime stdin failed: ${error.message}` }))
})
void handle.done.then(
() => {
if (!settled) {
const stderr = handle.collected.stderr?.readFrom(0).text.trim()
finish(() => output.failure(logs, { kind: 'worker-exit', message: stderr === undefined || stderr === '' ? 'E2B runtime exited before completing' : `E2B runtime exited before completing: ${stderr}` }))
}
},
(error: unknown) => {
finish(() => output.failure(logs, { kind: 'worker-exit', message: `E2B runtime spawn failed: ${messageOf(error)}` }))
},
)
const onAbort = (): void => {
finish(() => output.failure(logs, { kind: 'abort', message: String(request.signal?.reason) }))
}
request.signal?.addEventListener('abort', onAbort, { once: true })
wallTimer.current = setTimeout(() => {
finish(() => output.failure(logs, { kind: 'timeout', message: `wall-clock ceiling reached (${this.config.maxWallMs}ms)` }))
}, this.config.maxWallMs)
this.live.add(live)
if (request.signal?.aborted === true) {
onAbort()
return
}
sendReply({
type: 'boot',
code,
namespaces: [...bindings].map(([global, namespace]) => ({
global,
names: Object.keys(namespace.functions),
...namespace.errorClass === undefined ? {} : { errorClass: namespace.errorClass },
})),
computeMs: this.config.computeMs,
maxOutputBytes: this.config.maxOutputBytes,
maxOldGenerationSizeMb: this.config.maxOldGenerationSizeMb,
})
})
}
/* jscpd:ignore-start -- Code-runtime backends share the service lifecycle but own different child identities. */
private async teardown(): Promise<void> {
this.disposed = true
const runs = [...this.live]
for (const run of runs) run.settle({ kind: 'abort', message: 'runtime disposed' })
await Promise.all(runs.map(run => run.finished))
}
/* jscpd:ignore-end */
}
export default E2BCodeRuntime
@@ -0,0 +1,20 @@
/** Package-owned invariant companion for `@deepseek-ai/dsh-code-runtime-e2b`. */
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-code-runtime-e2b'
/** Cordis companion plugin name. */
export const name = 'code-runtime-e2b-invariant'
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** No runtime invariant: the service owns every one-shot remote run. */
const install: InvariantInstaller = () => {}
/** Register this package's invariant companion. */
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */
@@ -0,0 +1,460 @@
/** Dependency-free remote code runner installed inside the E2B sandbox. */
/** Node program that runs one model program in a fresh remote worker thread. */
export const CODE_RUNNER_SOURCE = String.raw`import { Buffer } from 'node:buffer'
import { inspect } from 'node:util'
import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads'
import { createInterface } from 'node:readline'
const emitFrame = message => {
process.stdout.write(Buffer.from(JSON.stringify(message)).toString('base64') + '\n')
}
const parseFrame = line => JSON.parse(Buffer.from(line, 'base64').toString('utf8'))
if (isMainThread) {
const input = createInterface({ input: process.stdin, crlfDelay: Infinity })
let worker
let finished = false
let computeTimer
const finish = message => {
if (finished) return
finished = true
clearInterval(computeTimer)
emitFrame(message)
const current = worker
worker = undefined
Promise.resolve(current ? current.terminate() : undefined).finally(() => {
input.close()
process.stdin.destroy()
})
}
input.on('line', line => {
let message
try {
message = parseFrame(line)
} catch (error) {
process.stderr.write('code-runtime-e2b frame error: ' + String(error) + '\n')
finish({ type: 'done', error: { kind: 'worker-exit', message: 'remote runner received a malformed frame' } })
return
}
if (!worker) {
if (!message || message.type !== 'boot' || typeof message.code !== 'string' || !Array.isArray(message.namespaces)) {
finish({ type: 'done', error: { kind: 'worker-exit', message: 'remote runner received an invalid boot frame' } })
return
}
worker = new Worker(new URL(import.meta.url), {
workerData: message,
env: {},
stdout: true,
stderr: true,
resourceLimits: { maxOldGenerationSizeMb: message.maxOldGenerationSizeMb },
})
worker.stdout.on('data', data => { emitFrame({ type: 'log', text: data.toString('utf8') }) })
worker.stderr.on('data', data => { emitFrame({ type: 'log', text: data.toString('utf8') }) })
worker.on('message', raw => {
if (!raw || typeof raw !== 'object') return
if (raw.type === 'call' && typeof raw.id === 'number' && typeof raw.global === 'string' && typeof raw.name === 'string' && Array.isArray(raw.args)) {
emitFrame({ type: 'call', id: raw.id, global: raw.global, name: raw.name, args: raw.args })
} else if (raw.type === 'log' && typeof raw.text === 'string') {
emitFrame({ type: 'log', text: raw.text })
} else if (raw.type === 'output-limit') {
finish({ type: 'output-limit' })
} else if (raw.type === 'done') {
if (raw.error && typeof raw.error === 'object' && typeof raw.error.kind === 'string' && typeof raw.error.message === 'string') {
finish({ type: 'done', error: { kind: raw.error.kind, message: raw.error.message } })
} else if (raw.value === undefined || Array.isArray(raw.value)) {
finish({ type: 'done', ...(raw.value === undefined ? {} : { value: raw.value }) })
}
}
})
worker.on('error', error => {
finish({ type: 'done', error: { kind: 'worker-exit', message: 'remote worker error: ' + error.message } })
})
worker.on('exit', code => {
if (!finished) finish({ type: 'done', error: { kind: 'worker-exit', message: 'remote worker exited with code ' + code + ' before completing' } })
})
computeTimer = setInterval(() => {
if (!worker) return
if (worker.performance.eventLoopUtilization().active > message.computeMs) {
finish({ type: 'done', error: { kind: 'timeout', message: 'compute budget exhausted (' + message.computeMs + 'ms busy)' } })
}
}, 25)
return
}
if (message && message.type === 'reply' && typeof message.id === 'number' && typeof message.ok === 'boolean') {
worker.postMessage(message.ok
? { type: 'reply', id: message.id, ok: true, value: message.value }
: { type: 'reply', id: message.id, ok: false, message: String(message.message) })
}
})
input.on('close', () => { if (worker && !finished) void worker.terminate() })
} else {
const port = parentPort
if (!port) throw new Error('remote worker requires parentPort')
const CapturedError = Error
const ArrayIsArray = Array.isArray
const ArrayPrototype = Array.prototype
const ObjectPrototype = Object.prototype
const ObjectCreate = Object.create
const ObjectDefineProperty = Object.defineProperty
const ObjectGetPrototypeOf = Object.getPrototypeOf
const ObjectHasOwn = Object.hasOwn
const ObjectKeys = Object.keys
const ObjectIs = Object.is
const ObjectPropertyIsEnumerable = Object.prototype.propertyIsEnumerable
const ReflectOwnKeys = Reflect.ownKeys
const ReflectApply = Reflect.apply
const NumberIsFinite = Number.isFinite
const NumberIsSafeInteger = Number.isSafeInteger
const PromiseCtor = Promise
const PromiseReject = Promise.reject
const QueueMicrotask = queueMicrotask
const BufferByteLength = Buffer.byteLength
const SetCtor = Set
const SetAdd = Set.prototype.add
const SetDelete = Set.prototype.delete
const SetHas = Set.prototype.has
const MapDelete = Map.prototype.delete
const MapGet = Map.prototype.get
const MapSet = Map.prototype.set
const ArrayJoin = Array.prototype.join
const ArrayPop = Array.prototype.pop
const StringCharCodeAt = String.prototype.charCodeAt
const StringSlice = String.prototype.slice
const JSONStringify = JSON.stringify
const StringValue = String
const define = (target, key, value) => {
const descriptor = ObjectCreate(null)
descriptor.value = value
descriptor.enumerable = true
descriptor.configurable = true
descriptor.writable = true
ObjectDefineProperty(target, key, descriptor)
}
const append = (target, value) => { define(target, target.length, value) }
const pop = target => ReflectApply(ArrayPop, target, [])
const setAdd = (target, value) => { ReflectApply(SetAdd, target, [value]) }
const setDelete = (target, value) => { ReflectApply(SetDelete, target, [value]) }
const setHas = (target, value) => ReflectApply(SetHas, target, [value])
const mapDelete = (target, key) => { ReflectApply(MapDelete, target, [key]) }
const mapGet = (target, key) => ReflectApply(MapGet, target, [key])
const mapSet = (target, key, value) => { ReflectApply(MapSet, target, [key, value]) }
const plainObject = value => {
const prototype = ObjectGetPrototypeOf(value)
return prototype === null || prototype === ObjectPrototype
}
const ownEnumerableStringKeys = value => {
const keys = ReflectOwnKeys(value)
for (let index = 0; index < keys.length; index++) {
const key = keys[index]
if (typeof key !== 'string' || !ReflectApply(ObjectPropertyIsEnumerable, value, [key])) return undefined
}
return keys
}
const assign = (destination, value) => {
if (destination.kind === 'root') destination.holder.value = value
else define(destination.target, destination.key, value)
}
const snapshot = input => {
const active = new SetCtor()
const holder = ObjectCreate(null)
const tasks = [{ kind: 'visit', value: input, destination: { kind: 'root', holder } }]
while (tasks.length) {
const task = pop(tasks)
if (task.kind === 'leave') { setDelete(active, task.source); continue }
const candidate = task.value
if (candidate === null || typeof candidate === 'boolean' || typeof candidate === 'string') {
assign(task.destination, candidate); continue
}
if (typeof candidate === 'number') {
if (!NumberIsFinite(candidate) || ObjectIs(candidate, -0)) return undefined
assign(task.destination, candidate); continue
}
if (typeof candidate !== 'object' || setHas(active, candidate)) return undefined
if (ArrayIsArray(candidate)) {
if (ObjectGetPrototypeOf(candidate) !== ArrayPrototype || ReflectOwnKeys(candidate).length !== candidate.length + 1) return undefined
const target = []
assign(task.destination, target)
setAdd(active, candidate)
append(tasks, { kind: 'leave', source: candidate })
for (let index = candidate.length - 1; index >= 0; index--) {
if (!ObjectHasOwn(candidate, index)) return undefined
append(tasks, { kind: 'visit', value: candidate[index], destination: { kind: 'slot', target, key: index } })
}
continue
}
if (!plainObject(candidate)) return undefined
const keys = ownEnumerableStringKeys(candidate)
if (!keys) return undefined
const target = {}
assign(task.destination, target)
setAdd(active, candidate)
append(tasks, { kind: 'leave', source: candidate })
for (let index = keys.length - 1; index >= 0; index--) {
const key = keys[index]
append(tasks, { kind: 'visit', value: candidate[key], destination: { kind: 'slot', target, key } })
}
}
return holder.value
}
const encodeWire = value => {
const wire = []
const pending = [value]
while (pending.length) {
const current = pop(pending)
if (current === null || typeof current === 'boolean' || typeof current === 'number' || typeof current === 'string') {
append(wire, current); continue
}
if (ArrayIsArray(current)) {
append(wire, { kind: 'array', length: current.length })
for (let index = current.length - 1; index >= 0; index--) append(pending, current[index])
} else {
const keys = ObjectKeys(current)
append(wire, { kind: 'object', keys })
for (let index = keys.length - 1; index >= 0; index--) append(pending, current[keys[index]])
}
}
return wire
}
const decodeWire = wire => {
if (!ArrayIsArray(wire) || wire.length === 0) return undefined
const frames = []
let root
let assigned = false
const attach = value => {
const parent = frames[frames.length - 1]
if (!parent) {
if (assigned) return false
root = value; assigned = true; return true
}
if (parent.kind === 'array') append(parent.target, value)
else define(parent.target, parent.keys[parent.index], value)
parent.index += 1
return true
}
for (let tokenIndex = 0; tokenIndex < wire.length; tokenIndex++) {
const token = wire[tokenIndex]
let value
let frame
if (token === null || typeof token === 'boolean' || typeof token === 'string') value = token
else if (typeof token === 'number') {
if (!NumberIsFinite(token) || ObjectIs(token, -0)) return undefined
value = token
} else {
if (!plainObject(token)) return undefined
const keys = ownEnumerableStringKeys(token)
if (!keys || keys.length !== 2 || keys[0] !== 'kind') return undefined
if (token.kind === 'array' && keys[1] === 'length' && NumberIsSafeInteger(token.length) && token.length >= 0) {
value = []
if (token.length > wire.length - tokenIndex - 1) return undefined
if (token.length) frame = { kind: 'array', target: value, length: token.length, index: 0 }
} else if (token.kind === 'object' && keys[1] === 'keys' && ArrayIsArray(token.keys)) {
const unique = new SetCtor()
const objectKeys = []
for (const key of token.keys) {
if (typeof key !== 'string' || setHas(unique, key)) return undefined
setAdd(unique, key); append(objectKeys, key)
}
if (objectKeys.length > wire.length - tokenIndex - 1) return undefined
value = {}
if (objectKeys.length) frame = { kind: 'object', target: value, keys: objectKeys, index: 0 }
} else return undefined
}
if (!attach(value)) return undefined
if (frame) append(frames, frame)
while (frames.length) {
const current = frames[frames.length - 1]
const length = current.kind === 'array' ? current.length : current.keys.length
if (current.index < length) break
pop(frames)
}
}
return frames.length === 0 ? root : undefined
}
const byteLength = text => ReflectApply(BufferByteLength, Buffer, [text])
const jsonStringBytes = text => byteLength(JSONStringify(text))
const jsonValueBytes = value => {
let bytes = 0
const tasks = [{ kind: 'value', value }]
while (tasks.length) {
const task = pop(tasks)
if (task.kind === 'separator') { bytes += 1; continue }
if (task.kind === 'key') { bytes += jsonStringBytes(task.value) + 1; continue }
const current = task.value
if (current === null) bytes += 4
else if (typeof current === 'string') bytes += jsonStringBytes(current)
else if (typeof current === 'number' || typeof current === 'boolean') bytes += byteLength(StringValue(current))
else if (ArrayIsArray(current)) {
bytes += 2
for (let index = current.length - 1; index >= 0; index--) {
append(tasks, { kind: 'value', value: current[index] })
if (index > 0) append(tasks, { kind: 'separator' })
}
} else {
bytes += 2
const keys = ObjectKeys(current)
for (let index = keys.length - 1; index >= 0; index--) {
const key = keys[index]
append(tasks, { kind: 'value', value: current[key] })
append(tasks, { kind: 'key', value: key })
if (index > 0) append(tasks, { kind: 'separator' })
}
}
}
return bytes
}
const truncate = (text, available) => {
if (available < 2) return ''
let result = ''
let bytes = 2
let index = 0
while (index < text.length) {
const first = ReflectApply(StringCharCodeAt, text, [index])
let end = index + 1
if (first >= 0xd800 && first <= 0xdbff && end < text.length) {
const second = ReflectApply(StringCharCodeAt, text, [end])
if (second >= 0xdc00 && second <= 0xdfff) end += 1
}
const character = ReflectApply(StringSlice, text, [index, end])
const cost = jsonStringBytes(character) - 2
if (bytes + cost > available) break
bytes += cost
result += character
index = end
}
return result
}
let logBytes = 2
let logEntries = 0
let limited = false
const pushLog = text => {
if (limited) return
const separator = logEntries > 0 ? 1 : 0
const available = workerData.maxOutputBytes - logBytes - separator
const cost = jsonStringBytes(text)
if (cost > available) {
const prefix = truncate(text, available)
if (prefix) {
logBytes += jsonStringBytes(prefix) + separator
logEntries += 1
port.postMessage({ type: 'log', text: prefix })
}
limited = true
port.postMessage({ type: 'output-limit' })
return
}
logBytes += cost + separator
logEntries += 1
port.postMessage({ type: 'log', text })
}
const originalStdout = process.stdout.write
const originalStderr = process.stderr.write
process.stdout.write = (chunk, ...rest) => {
pushLog(typeof chunk === 'string' ? chunk : StringValue(chunk))
let callback
for (let index = 0; index < rest.length; index++) {
if (typeof rest[index] === 'function') { callback = rest[index]; break }
}
if (callback) QueueMicrotask(() => { callback(null) })
return true
}
process.stderr.write = process.stdout.write
const consoleShim = ObjectCreate(null)
for (const level of ['log', 'info', 'warn', 'error', 'debug']) {
define(consoleShim, level, (...args) => {
const rendered = []
for (let index = 0; index < args.length; index++) {
const value = args[index]
append(rendered, typeof value === 'string' ? value : inspect(value, { depth: 4, maxArrayLength: 100, maxStringLength: 10000 }))
}
pushLog(ReflectApply(ArrayJoin, rendered, [' ']))
})
}
const pending = new Map()
let nextId = 1
const errorClasses = new Map()
for (const namespace of workerData.namespaces) {
if (!namespace.errorClass) continue
const descriptor = namespace.errorClass
mapSet(errorClasses, namespace.global, class BindingCallError extends CapturedError {
constructor(memberName, message) {
super(message)
ObjectDefineProperty(this, 'name', { value: descriptor.name, enumerable: true })
ObjectDefineProperty(this, descriptor.memberNameProperty, { value: memberName, enumerable: true })
}
})
}
port.on('message', message => {
if (!message || message.type !== 'reply' || typeof message.id !== 'number') return
const entry = mapGet(pending, message.id)
if (!entry) return
mapDelete(pending, message.id)
if (!message.ok) { entry.reject(new CapturedError(StringValue(message.message))); return }
const value = decodeWire(message.value)
if (value === undefined) entry.reject(new CapturedError('binding resolution must be lossless JSON'))
else entry.resolve(value)
})
const namespaces = workerData.namespaces.map(namespace => {
const target = ObjectCreate(null)
const ErrorClass = mapGet(errorClasses, namespace.global)
for (const name of namespace.names) {
define(target, name, args => {
const detached = snapshot(args)
if (detached === undefined) {
return ReflectApply(PromiseReject, PromiseCtor, [ErrorClass ? new ErrorClass(name, 'binding arguments must be lossless JSON') : new CapturedError('binding arguments must be lossless JSON')])
}
return new PromiseCtor((resolve, reject) => {
const id = nextId++
mapSet(pending, id, {
resolve,
reject: error => { reject(ErrorClass ? new ErrorClass(name, error.message) : error) },
})
port.postMessage({ type: 'call', id, global: namespace.global, name, args: encodeWire(detached) })
})
})
}
return target
})
const errorClassNames = []
const errorClassValues = []
for (const namespace of workerData.namespaces) {
if (!namespace.errorClass) continue
append(errorClassNames, namespace.errorClass.name)
append(errorClassValues, mapGet(errorClasses, namespace.global))
}
const AsyncFunction = ObjectGetPrototypeOf(async function () {}).constructor
try {
const fn = new AsyncFunction(...workerData.namespaces.map(value => value.global), ...errorClassNames, 'console', '"use strict";\n' + workerData.code)
const value = await fn(...namespaces, ...errorClassValues, consoleShim)
if (!limited) {
if (value === undefined) port.postMessage({ type: 'done' })
else {
const detached = snapshot(value)
if (detached === undefined) {
const message = 'program completion must be lossless JSON'
if (jsonStringBytes(message) > workerData.maxOutputBytes - logBytes) port.postMessage({ type: 'output-limit' })
else port.postMessage({ type: 'done', error: { kind: 'invalid-output', message } })
} else if (jsonValueBytes(detached) > workerData.maxOutputBytes - logBytes) {
port.postMessage({ type: 'output-limit' })
} else {
port.postMessage({ type: 'done', value: encodeWire(detached) })
}
}
}
} catch (error) {
if (!limited) {
let message
try { message = error instanceof CapturedError ? error.stack || error.message : StringValue(error) }
catch { message = 'program threw an unrenderable value' }
if (jsonStringBytes(message) > workerData.maxOutputBytes - logBytes) port.postMessage({ type: 'output-limit' })
else port.postMessage({ type: 'done', error: { kind: 'exception', message } })
}
} finally {
process.stdout.write = originalStdout
process.stderr.write = originalStderr
}
}
`