/** * Trusted worker bootstrap. Only vm.evalCode executes the untrusted program. * Kept as source so installed/bundled SDKs need no separate worker entry file. * No Node object or callback is injected into QuickJS: its native functions * exchange bounded strings and interpreter-owned promise handles. */ export declare const QUICKJS_WORKER_SOURCE = "\nconst { parentPort, workerData } = require('node:worker_threads')\nconst { newQuickJSWASMModuleFromVariant, newVariant } = require(workerData.corePath)\nconst variantModule = require(workerData.variantPath)\nconst variant = variantModule.default || variantModule\n\nasync function main() {\n\tconst limits = workerData.limits\n\tconst pages = Math.floor(limits.memoryLimitBytes / 65536)\n\tconst wasmMemory = new WebAssembly.Memory({ initial: Math.min(256, pages), maximum: pages })\n\tconst module = await newQuickJSWASMModuleFromVariant(newVariant(variant, { wasmMemory }))\n\tconst runtime = module.newRuntime()\n\truntime.setMemoryLimit(limits.memoryLimitBytes)\n\truntime.setMaxStackSize(512 * 1024)\n\truntime.setInterruptHandler(() => Date.now() >= workerData.deadline)\n\tconst vm = runtime.newContext()\n\tconst pending = new Map()\n\tlet nextId = 0\n\tlet printBytes = 0\n\tlet printCount = 0\n\tlet truncated = false\n\tlet ended = false\n\tlet pumping = false\n\tlet scheduled = false\n\tlet program\n\tconst owned = []\n\n\tfunction keep(result) {\n\t\tconst handle = vm.unwrapResult(result)\n\t\towned.push(handle)\n\t\treturn handle\n\t}\n\t// Capture intrinsics before the program may replace its own globals.\n\tconst encode = keep(vm.evalCode('(' + function () {\n\t\tconst stringify = JSON.stringify\n\t\tconst finite = Number.isFinite\n\t\tconst prototype = Object.getPrototypeOf\n\t\tconst plain = Object.prototype\n\t\tconst isArray = Array.isArray\n\t\tconst keys = Object.keys\n\t\tconst descriptor = Object.getOwnPropertyDescriptor\n\t\treturn function (value) {\n\t\t\tif (value === undefined) return undefined\n\t\t\tconst parents = new Set()\n\t\t\tfunction check(item, depth) {\n\t\t\t\tconst kind = typeof item\n\t\t\t\tif (item === null || kind === 'string' || kind === 'boolean' || (kind === 'number' && finite(item))) return\n\t\t\t\tif (kind !== 'object' || depth > 64 || parents.has(item)) throw new Error('Code runtime values must be JSON-safe.')\n\t\t\t\tif (!isArray(item) && prototype(item) !== plain && prototype(item) !== null) throw new Error('Code runtime values must use plain objects and arrays.')\n\t\t\t\tparents.add(item)\n\t\t\t\tfor (const key of keys(item)) {\n\t\t\t\t\tconst property = descriptor(item, key)\n\t\t\t\t\tif (!property || !('value' in property)) throw new Error('Code runtime values must not contain accessors.')\n\t\t\t\t\tcheck(property.value, depth + 1)\n\t\t\t\t}\n\t\t\t\tparents.delete(item)\n\t\t\t}\n\t\t\tcheck(value, 0)\n\t\t\treturn stringify(value)\n\t\t}\n\t}.toString() + ')()'))\n\tconst decode = keep(vm.evalCode('(function () { const parse = JSON.parse; return function(value) { return parse(value); }; })()'))\n\tconst errorText = keep(vm.evalCode('(function () { const string = String; return function(error) { try { return typeof error.message === \"string\" ? error.message : string(error); } catch { return \"The program failed.\"; } }; })()'))\n\n\tfunction textValue(handle, maximum) {\n\t\tconst length = vm.getProp(handle, 'length')\n\t\ttry {\n\t\t\tif (vm.getNumber(length) > maximum) throw new Error('Code runtime value exceeds ' + maximum + ' bytes.')\n\t\t} finally { length.dispose() }\n\t\tconst text = vm.getString(handle)\n\t\tif (Buffer.byteLength(text) > maximum) throw new Error('Code runtime value exceeds ' + maximum + ' bytes.')\n\t\treturn text\n\t}\n\tfunction serialize(handle, maximum) {\n\t\tif (vm.typeof(handle) === 'undefined') return undefined\n\t\tconst encoded = vm.callFunction(encode, vm.undefined, handle)\n\t\tif (encoded.error) {\n\t\t\tencoded.error.dispose()\n\t\t\tthrow new Error('Code runtime values must be JSON-safe and serializable.')\n\t\t}\n\t\ttry { return textValue(encoded.value, maximum) }\n\t\tfinally { encoded.value.dispose() }\n\t}\n\tfunction failureText(handle) {\n\t\tconst result = vm.callFunction(errorText, vm.undefined, handle)\n\t\tif (result.error) { result.error.dispose(); return 'The program failed.' }\n\t\t// Diagnostics have their own fixed bound. A deliberately tiny data\n\t\t// allowance must not erase the reason or the no-replay guidance for an\n\t\t// effect that completed but whose return value could not be delivered.\n\t\ttry { return textValue(result.value, 4096) }\n\t\tcatch { return 'The program failed with an oversized error.' }\n\t\tfinally { result.value.dispose() }\n\t}\n\tfunction dispose() {\n\t\tfor (const deferred of pending.values()) deferred.dispose()\n\t\tpending.clear()\n\t\tif (program && program.alive) program.dispose()\n\t\tfor (const handle of owned) if (handle.alive) handle.dispose()\n\t\tvm.dispose()\n\t\truntime.dispose()\n\t}\n\tfunction finish(message) {\n\t\tif (ended) return\n\t\tended = true\n\t\t// A guest OOM can make QuickJS teardown throw. The worker still owns\n\t\t// the whole WASM module and is terminated by its parent on settlement.\n\t\ttry { dispose() } catch {}\n\t\tparentPort.postMessage(message)\n\t}\n\tfunction fail(error) {\n\t\tfinish(Date.now() >= workerData.deadline\n\t\t\t? { kind: 'timed-out' }\n\t\t\t: { kind: 'error', error: String(error && error.message || error).slice(0, 4096) })\n\t}\n\tfunction schedule() {\n\t\tif (ended || scheduled) return\n\t\tscheduled = true\n\t\tsetImmediate(() => { scheduled = false; pump() })\n\t}\n\tfunction pump() {\n\t\tif (ended || pumping) return\n\t\tpumping = true\n\t\ttry {\n\t\t\tconst jobs = runtime.executePendingJobs(32)\n\t\t\tif (jobs.error) {\n\t\t\t\tconst error = failureText(jobs.error)\n\t\t\t\tjobs.error.dispose()\n\t\t\t\tthrow new Error(error)\n\t\t\t}\n\t\t\tconst state = vm.getPromiseState(program)\n\t\t\tif (state.type === 'fulfilled') {\n\t\t\t\tlet json\n\t\t\t\ttry { json = serialize(state.value, limits.maxValueBytes) }\n\t\t\t\tfinally { state.value.dispose() }\n\t\t\t\tfinish({ kind: 'done', json })\n\t\t\t} else if (state.type === 'rejected') {\n\t\t\t\tlet error\n\t\t\t\ttry { error = failureText(state.error) }\n\t\t\t\tfinally { state.error.dispose() }\n\t\t\t\tfail(new Error(error))\n\t\t\t} else if (runtime.hasPendingJob()) schedule()\n\t\t} catch (error) { fail(error) }\n\t\tfinally { pumping = false }\n\t}\n\tfunction rejected(message) {\n\t\tconst deferred = vm.newPromise()\n\t\tconst error = vm.newError(message)\n\t\tdeferred.reject(error)\n\t\terror.dispose()\n\t\treturn deferred.handle\n\t}\n\tconst call = vm.newFunction('call', (name, input = vm.undefined) => {\n\t\ttry {\n\t\t\tif (nextId >= limits.maxHostCalls) return rejected('Code runtime host-call limit reached.')\n\t\t\tif (pending.size >= limits.maxPendingHostCalls) return rejected('Code runtime pending host-call limit reached.')\n\t\t\tif (vm.typeof(name) !== 'string') return rejected('A host call requires a tool name string.')\n\t\t\tconst tool = textValue(name, Math.min(limits.maxValueBytes, 1024))\n\t\t\tconst json = serialize(input, limits.maxValueBytes)\n\t\t\tconst id = ++nextId\n\t\t\tconst deferred = vm.newPromise()\n\t\t\tpending.set(id, deferred)\n\t\t\tparentPort.postMessage({ kind: 'call', id, name: tool, json })\n\t\t\treturn deferred.handle\n\t\t} catch (error) { return rejected(String(error.message || error)) }\n\t})\n\tvm.setProp(vm.global, 'call', call)\n\tcall.dispose()\n\tconst print = vm.newFunction('print', (...values) => {\n\t\tif (truncated) return vm.undefined\n\t\ttry {\n\t\t\tconst parts = []\n\t\t\tlet remaining = workerData.maxOutputBytes - printBytes - (printCount > 0 ? 1 : 0)\n\t\t\tfor (const value of values) {\n\t\t\t\tif (parts.length) remaining--\n\t\t\t\tif (remaining < 0) throw new Error('output limit')\n\t\t\t\tconst text = vm.typeof(value) === 'string' ? textValue(value, remaining) : serialize(value, remaining)\n\t\t\t\tconst part = text === undefined ? '' : text\n\t\t\t\tremaining -= Buffer.byteLength(part)\n\t\t\t\tparts.push(part)\n\t\t\t}\n\t\t\tconst line = parts.join(' ')\n\t\t\tconst size = Buffer.byteLength(line) + (printCount > 0 ? 1 : 0)\n\t\t\tif (printBytes + size > workerData.maxOutputBytes) throw new Error('output limit')\n\t\t\t// Empty prints consume a newline after the first, so the byte\n\t\t\t// budget also bounds the number of worker messages.\n\t\t\tprintBytes += size\n\t\t\tprintCount++\n\t\t\tparentPort.postMessage({ kind: 'print', line })\n\t\t} catch {\n\t\t\ttruncated = true\n\t\t\tparentPort.postMessage({ kind: 'truncated' })\n\t\t}\n\t\treturn vm.undefined\n\t})\n\tvm.setProp(vm.global, 'print', print)\n\tprint.dispose()\n\n\tparentPort.on('message', (message) => {\n\t\tif (ended || message.kind !== 'call-result') return\n\t\tconst deferred = pending.get(message.id)\n\t\tif (!deferred) return\n\t\tpending.delete(message.id)\n\t\ttry {\n\t\t\tif (message.ok) {\n\t\t\t\tlet value = vm.undefined\n\t\t\t\tif (message.json !== undefined) {\n\t\t\t\t\tif (typeof message.json !== 'string' || Buffer.byteLength(message.json) > limits.maxValueBytes) throw new Error('Host result exceeds the value limit.')\n\t\t\t\t\tconst input = vm.newString(message.json)\n\t\t\t\t\ttry { value = vm.unwrapResult(vm.callFunction(decode, vm.undefined, input)) }\n\t\t\t\t\tfinally { input.dispose() }\n\t\t\t\t}\n\t\t\t\tdeferred.resolve(value)\n\t\t\t\tif (value !== vm.undefined) value.dispose()\n\t\t\t} else {\n\t\t\t\tconst error = vm.newError(String(message.error).slice(0, 4096))\n\t\t\t\tdeferred.reject(error)\n\t\t\t\terror.dispose()\n\t\t\t}\n\t\t\tdeferred.dispose()\n\t\t\tschedule()\n\t\t} catch (error) { deferred.dispose(); fail(error) }\n\t})\n\ttry {\n\t\tconst result = vm.evalCode('(async () => {\\n' + workerData.source + '\\n})()', 'model-program.js')\n\t\tif (result.error) {\n\t\t\tconst error = failureText(result.error)\n\t\t\tresult.error.dispose()\n\t\t\tfail(new Error(error))\n\t\t} else { program = result.value; pump() }\n\t} catch (error) { fail(error) }\n}\nmain().catch((error) => parentPort.postMessage({ kind: 'error', error: String(error && error.message || error).slice(0, 4096) }))\n"; //# sourceMappingURL=worker-program.d.ts.map