/* eslint-disable @typescript-eslint/no-explicit-any */ const { QJSWorker: NativeQJSWorker } = require("../index.node"); import { EventEmitter } from "events"; export type EvalStats = { interrupts: number; evalTimeMs: number; cpuTimeMs: number; }; export type QuickJSMemoryStats = Record; export type QuickJSImportsResult = string | boolean | { src?: string; resolve?: string }; export type QuickJSOptions = { console?: Console; channelSize?: number; maxEvalMs?: number; maxCpuMs?: number; maxMemoryBytes?: number; maxStackSizeBytes?: number; maxInterrupt?: number; gcThresholdAlloc?: number; gcIntervalMs?: number; globals?: Record; modules?: Record | Map; imports?: ((moduleName: string) => QuickJSImportsResult) | boolean; }; export type EvalOptions = { filename?: string; args?: any[]; maxEvalMs?: number; maxCpuMs?: number; }; export type QuickJSHandleType = | "undefined" | "null" | "boolean" | "number" | "string" | "bigint" | "symbol" | "function" | "array" | "object" | "date" | "regexp" | "map" | "set" | "arraybuffer" | "typedarray" | "error" | "promise"; export type QuickJSHandleTypeInfo = { type: QuickJSHandleType; callable: boolean; constructorName?: string; }; export type QuickJSHandleExecOptions = { maxEvalMs?: number; maxCpuMs?: number }; export type QuickJSHandleAwaitOptions = QuickJSHandleExecOptions & { returnValue?: boolean; untilNonPromise?: boolean; }; export type QuickJSHandleApplyOp = | { op: "get"; path?: string } | { op: "set"; path: string; value: any } | { op: "call"; path?: string; args?: any[] } | { op: "has"; path: string } | { op: "delete"; path: string } | { op: "getType"; path?: string } | { op: "toJSON"; path?: string } | { op: "isCallable"; path?: string } | { op: "isPromise"; path?: string }; export type QuickJSHandle = { readonly id: string; readonly rootType: QuickJSHandleTypeInfo; readonly disposed: boolean; get(path?: string, options?: QuickJSHandleExecOptions): Promise; has(path: string, options?: QuickJSHandleExecOptions): Promise; set(path: string, value: any, options?: QuickJSHandleExecOptions): Promise; delete(path: string, options?: QuickJSHandleExecOptions): Promise; keys(path?: string, options?: QuickJSHandleExecOptions): Promise; entries(path?: string, options?: QuickJSHandleExecOptions): Promise; getOwnPropertyDescriptor(path: string, options?: QuickJSHandleExecOptions): Promise; define(path: string, descriptor: PropertyDescriptor, options?: QuickJSHandleExecOptions): Promise; instanceOf(constructorPath: string, options?: QuickJSHandleExecOptions): Promise; isCallable(path?: string, options?: QuickJSHandleExecOptions): Promise; isPromise(path?: string, options?: QuickJSHandleExecOptions): Promise; call(args?: any[], options?: QuickJSHandleExecOptions): Promise; call(path: string, args?: any[], options?: QuickJSHandleExecOptions): Promise; construct(args?: any[], options?: QuickJSHandleExecOptions): Promise; await(options?: QuickJSHandleAwaitOptions): Promise; clone(options?: QuickJSHandleExecOptions): Promise; toJSON(path?: string, options?: QuickJSHandleExecOptions): Promise; apply(ops: QuickJSHandleApplyOp[], options?: QuickJSHandleExecOptions): Promise; getType(path?: string, options?: QuickJSHandleExecOptions): Promise; dispose(options?: QuickJSHandleExecOptions): Promise; [Symbol.asyncDispose](): Promise; _run?: (op: QuickJSHandleApplyOp | Record, options?: QuickJSHandleExecOptions) => Promise; }; export type QuickJSHandleApi = { get(path: string, options?: QuickJSHandleExecOptions): Promise; tryGet(path: string, options?: QuickJSHandleExecOptions): Promise; eval(source: string, options?: QuickJSHandleExecOptions): Promise; }; export type QuickJSGlobalApi = { set(path: string, value: any, options?: QuickJSHandleExecOptions): Promise; get(path: string, options?: QuickJSHandleExecOptions): Promise; has(path: string, options?: QuickJSHandleExecOptions): Promise; delete(path: string, options?: QuickJSHandleExecOptions): Promise; keys(path?: string, options?: QuickJSHandleExecOptions): Promise; entries(path?: string, options?: QuickJSHandleExecOptions): Promise; getOwnPropertyDescriptor(path: string, options?: QuickJSHandleExecOptions): Promise; define(path: string, descriptor: PropertyDescriptor, options?: QuickJSHandleExecOptions): Promise; isCallable(path?: string, options?: QuickJSHandleExecOptions): Promise; isPromise(path?: string, options?: QuickJSHandleExecOptions): Promise; call(path: string, args?: any[], options?: QuickJSHandleExecOptions): Promise; construct(path: string, args?: any[], options?: QuickJSHandleExecOptions): Promise; await(path: string, options?: QuickJSHandleAwaitOptions): Promise; clone(path: string, options?: QuickJSHandleExecOptions): Promise; toJSON(path?: string, options?: QuickJSHandleExecOptions): Promise; apply(path: string, ops: QuickJSHandleApplyOp[], options?: QuickJSHandleExecOptions): Promise; getType(path?: string, options?: QuickJSHandleExecOptions): Promise; instanceOf(path: string, constructorPath: string, options?: QuickJSHandleExecOptions): Promise; }; export type QuickJSModuleEvalOptions = EvalOptions & { moduleName?: string; cjs?: boolean; }; export type QuickJSModuleApi = { import = Record>(specifier: string): Promise; eval = Record>(source: string, options?: QuickJSModuleEvalOptions): Promise; register(moduleName: string, source: string, options?: QuickJSModuleEvalOptions): Promise; clear(moduleName: string): Promise; }; type NativeQuickJSWorker = { on(event: string, cb: (...args: any[]) => void): void; close(): Promise; ref(): void; unref(): void; activeTimerCount?(): number; isClosed(): boolean; eval(code: string, options?: any): Promise<[any, EvalStats]>; evalSync(code: string, options?: any): [any, EvalStats]; setGlobal(key: string, value: any): Promise; postMessage(msg: any): any; postMessages?(msgs: any[]): any; postMessageFrame?(frame: Uint8Array): any; postMessagesFrame?(frames: Uint8Array[] | Uint8Array): any; drainMessages?(): any[]; drainMessagesFrame?(): Uint8Array; getByteCode(code: string): Promise; loadByteCode(bytes: Uint8Array): Promise; gc(): Promise; memory(): Promise; cpu(measureMs: number): Promise; }; export type QuickJSCpuOptions = { measureMs?: number }; export type QuickJSCpuStats = { cpuTimeMs: number; measureMs: number; usagePercentage: number; }; export type QuickJSWindowOptions = { windowMs?: number }; export type QuickJSRatesStats = { windowMs: number; evalPerSec: number; handlePerSec: number; globalPerSec: number; modulePerSec: number; messagesPerSec: number; otherPerSec: number; }; export type QuickJSLatencyStats = { windowMs: number; count: number; avgMs: number; maxMs: number; }; export type QuickJSEventLoopLagOptions = { measureMs?: number }; export type QuickJSEventLoopLagStats = { measureMs: number; lagMs: number; }; export type QuickJSTotalsStats = { ops: number; errors: number; eval: number; handle: number; global: number; module: number; other: number; messagesOut: number; messagesIn: number; bytesOut: number; bytesIn: number; }; export type QuickJSStatsResetOptions = { totals?: boolean; }; export type QuickJSStatsApi = { readonly activeOps: number; readonly lastExecution: EvalStats | null; cpu(options?: QuickJSCpuOptions): Promise; rates(options?: QuickJSWindowOptions): Promise; latency(options?: QuickJSWindowOptions): Promise; eventLoopLag(options?: QuickJSEventLoopLagOptions): Promise; readonly totals: QuickJSTotalsStats; reset(options?: QuickJSStatsResetOptions): void; memory(): Promise; }; export type QuickJSRuntimeEvent = { kind: string; ts: number; opId?: string; hostFile?: string; hostLine?: number; hostColumn?: number; hostCallSite?: string; hostImmediateFile?: string; hostImmediateLine?: number; hostImmediateColumn?: number; hostImmediateCallSite?: string; [key: string]: any; }; export type QuickJSErrorEvent = QuickJSRuntimeEvent & { kind: "error.thrown"; surface: "eval" | "evalSync"; error: any; }; const HANDLE_BRIDGE_KEY = "__quickjs_worker_bridge_v1"; const HANDLE_INSTALL_SOURCE = ` (function () { const key = ${JSON.stringify(HANDLE_BRIDGE_KEY)}; if (globalThis[key] && globalThis[key].__bridgeVersion === 1) return true; const forbidden = new Set(["__proto__", "prototype", "constructor"]); const handles = new Map(); let nextId = 1; const fail = (code, message) => { const e = new Error(String(message || code)); e.code = code; throw e; }; const splitPath = (path) => { if (path == null || path === "") return []; if (typeof path !== "string") fail("HANDLE_PATH_INVALID", "Path must be a string"); const segs = path.split(".").map((s) => s.trim()).filter(Boolean); for (const seg of segs) { if (forbidden.has(seg)) fail("HANDLE_PATH_FORBIDDEN", "Forbidden path segment"); } return segs; }; const mustObjectLike = (value, path) => { const t = typeof value; if (value == null || (t !== "object" && t !== "function")) { fail("HANDLE_PATH_INVALID", "Cannot traverse path " + String(path || "")); } }; const resolve = (base, path) => { const segs = splitPath(path); let cur = base; for (const seg of segs) { mustObjectLike(cur, path); cur = cur[seg]; } return cur; }; const resolveWithExistence = (base, path) => { const segs = splitPath(path); let cur = base; for (const seg of segs) { mustObjectLike(cur, path); if (!(seg in Object(cur))) return { exists: false, value: undefined }; cur = cur[seg]; } return { exists: true, value: cur }; }; const resolveParent = (base, path) => { const segs = splitPath(path); if (segs.length === 0) fail("HANDLE_PATH_INVALID", "Path cannot be empty"); let cur = base; for (let i = 0; i < segs.length - 1; i += 1) { mustObjectLike(cur, path); cur = cur[segs[i]]; } mustObjectLike(cur, path); return { parent: cur, key: segs[segs.length - 1] }; }; const typeInfo = (value) => { const t = typeof value; if (value === undefined) return { type: "undefined", callable: false }; if (value === null) return { type: "null", callable: false }; if (t === "boolean") return { type: "boolean", callable: false }; if (t === "number") return { type: "number", callable: false }; if (t === "string") return { type: "string", callable: false }; if (t === "bigint") return { type: "bigint", callable: false }; if (t === "symbol") return { type: "symbol", callable: false }; if (t === "function") { return { type: "function", callable: true, constructorName: value && value.constructor && value.constructor.name ? value.constructor.name : undefined, }; } if (Array.isArray(value)) return { type: "array", callable: false, constructorName: "Array" }; if (value instanceof Date) return { type: "date", callable: false, constructorName: "Date" }; if (value instanceof RegExp) return { type: "regexp", callable: false, constructorName: "RegExp" }; if (value instanceof Map) return { type: "map", callable: false, constructorName: "Map" }; if (value instanceof Set) return { type: "set", callable: false, constructorName: "Set" }; if (typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer) { return { type: "arraybuffer", callable: false, constructorName: "ArrayBuffer" }; } if (typeof ArrayBuffer !== "undefined" && typeof ArrayBuffer.isView === "function" && ArrayBuffer.isView(value)) { return { type: "typedarray", callable: false, constructorName: value && value.constructor && value.constructor.name ? value.constructor.name : undefined, }; } if (value instanceof Error) { return { type: "error", callable: false, constructorName: value && value.constructor && value.constructor.name ? value.constructor.name : "Error", }; } if (value && typeof value.then === "function") return { type: "promise", callable: false }; return { type: "object", callable: false, constructorName: value && value.constructor && value.constructor.name ? value.constructor.name : undefined, }; }; const jsonSnapshot = (value) => { const seen = new WeakSet(); const encode = (v) => { if (v === undefined || v === null) return v; const t = typeof v; if (t === "string" || t === "boolean" || t === "number") return v; if (t === "bigint") return { __bigint: String(v) }; if (t === "function") return "[Function]"; if (t === "symbol") return String(v); if (v instanceof Date) return { __date: v.toISOString() }; if (v instanceof RegExp) return { __regexp: { source: v.source, flags: v.flags } }; if (v instanceof Map) return { __map: Array.from(v.entries()).map(([k, val]) => [encode(k), encode(val)]) }; if (v instanceof Set) return { __set: Array.from(v.values()).map(encode) }; if (v instanceof Error) { const out = { name: v.name, message: v.message }; if (typeof v.stack === "string") out.stack = v.stack; if ("code" in v && v.code != null) out.code = v.code; return { __quickjs_worker_type: "error", value: out }; } if (typeof ArrayBuffer !== "undefined" && typeof ArrayBuffer.isView === "function" && ArrayBuffer.isView(v)) { return Array.from(new Uint8Array(v.buffer, v.byteOffset, v.byteLength)); } if (typeof ArrayBuffer !== "undefined" && v instanceof ArrayBuffer) { return Array.from(new Uint8Array(v)); } if (t === "object") { if (seen.has(v)) return "[Circular]"; seen.add(v); if (Array.isArray(v)) return v.map(encode); const out = Object.create(null); for (const [k, val] of Object.entries(v)) out[k] = encode(val); return out; } return undefined; }; return encode(value); }; const create = (value) => { const id = "h:" + nextId++; handles.set(id, value); return { id, rootType: typeInfo(value) }; }; const getHandleValue = (id) => { if (!handles.has(id)) fail("HANDLE_NOT_FOUND", "Unknown handle id"); return handles.get(id); }; const getValue = (id, path) => resolve(getHandleValue(id), path); const getValueOrMissing = (id, path) => resolveWithExistence(getHandleValue(id), path); const applyOp = async (payload) => { const id = String(payload && payload.id || ""); if (!id) fail("HANDLE_ID_REQUIRED", "Handle id is required"); const op = String(payload && payload.op || "get"); const path = payload ? payload.path : undefined; if (op === "dispose") { handles.delete(id); return undefined; } if (op === "clone") { return create(getHandleValue(id)); } if (op === "get") { return getValue(id, path); } if (op === "set") { const target = getHandleValue(id); if (path == null || path === "") fail("HANDLE_PATH_INVALID", "set path is required"); const ref = resolveParent(target, path); ref.parent[ref.key] = payload.value; return undefined; } if (op === "has") { return getValueOrMissing(id, path).exists; } if (op === "delete") { const target = getHandleValue(id); if (path == null || path === "") fail("HANDLE_PATH_INVALID", "delete path is required"); const ref = resolveParent(target, path); return delete ref.parent[ref.key]; } if (op === "keys") { const value = getValue(id, path); if (value == null) return []; if (value instanceof Map || value instanceof Set) return Array.from(value.keys()); if (typeof value === "object" || typeof value === "function") return Object.keys(value); return []; } if (op === "entries") { const value = getValue(id, path); if (value == null) return []; if (value instanceof Map) return Array.from(value.entries()); if (value instanceof Set) return Array.from(value.entries()); if (typeof value === "object" || typeof value === "function") return Object.entries(value); return []; } if (op === "getType") { return typeInfo(getValue(id, path)); } if (op === "getOwnPropertyDescriptor") { if (path == null || path === "") fail("HANDLE_PATH_INVALID", "descriptor path is required"); const ref = resolveParent(getHandleValue(id), path); return Object.getOwnPropertyDescriptor(ref.parent, ref.key); } if (op === "define") { if (path == null || path === "") fail("HANDLE_PATH_INVALID", "define path is required"); const ref = resolveParent(getHandleValue(id), path); Object.defineProperty(ref.parent, ref.key, payload.descriptor || {}); return true; } if (op === "toJSON") { return jsonSnapshot(getValue(id, path)); } if (op === "isCallable") { return typeof getValue(id, path) === "function"; } if (op === "isPromise") { const value = getValue(id, path); return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function"; } if (op === "call") { const fn = getValue(id, path); if (typeof fn !== "function") fail("HANDLE_NOT_CALLABLE", "Target is not callable"); const thisArg = path ? resolveParent(getHandleValue(id), path).parent : undefined; return await fn.apply(thisArg, Array.isArray(payload.args) ? payload.args : []); } if (op === "construct") { const Ctor = getValue(id, path); if (typeof Ctor !== "function") fail("HANDLE_NOT_CONSTRUCTABLE", "Target is not constructable"); return new Ctor(...(Array.isArray(payload.args) ? payload.args : [])); } if (op === "instanceOf") { const value = getValue(id, path); const ctor = resolve(globalThis, payload.constructorPath); return value instanceof ctor; } if (op === "await") { let value = getHandleValue(id); const untilNonPromise = payload && payload.untilNonPromise === true; while (value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function") { value = await value; handles.set(id, value); if (!untilNonPromise) break; } return payload && payload.returnValue === false ? undefined : value; } fail("HANDLE_OP_UNKNOWN", "Unknown handle op " + op); }; const globalOp = async (payload) => { const op = String(payload && payload.op || "get"); const path = payload ? payload.path : undefined; const temp = create(globalThis); try { if (op === "set") { if (path == null || path === "") fail("HANDLE_PATH_INVALID", "set path is required"); const ref = resolveParent(globalThis, path); ref.parent[ref.key] = payload.value; return undefined; } if (op === "clone") { return create(resolve(globalThis, path)); } if (op === "define") { if (path == null || path === "") fail("HANDLE_PATH_INVALID", "define path is required"); const ref = resolveParent(globalThis, path); Object.defineProperty(ref.parent, ref.key, payload.descriptor || {}); return true; } if (op === "getOwnPropertyDescriptor") { if (path == null || path === "") fail("HANDLE_PATH_INVALID", "descriptor path is required"); const ref = resolveParent(globalThis, path); return Object.getOwnPropertyDescriptor(ref.parent, ref.key); } if (op === "instanceOf") { const value = resolve(globalThis, path); const ctor = resolve(globalThis, payload.constructorPath); return value instanceof ctor; } return await applyOp({ ...payload, id: temp.id, path }); } finally { handles.delete(temp.id); } }; const importModule = async (specifier) => { const spec = String(specifier); const mod = await import(spec); const meta = create(mod); const out = Object.create(null); out.__quickjs_worker_handle_id = meta.id; out.__quickjs_worker_module_spec = spec; out.__quickjs_worker_module_keys = Object.keys(mod); for (const key of out.__quickjs_worker_module_keys) { const value = mod[key]; if (typeof value === "function") { out[key] = { __quickjs_worker_type: "module_fn", __quickjs_worker_handle_id: meta.id, name: key }; } else { out[key] = value; } } if ("default" in mod && !("default" in out)) { const value = mod.default; out.default = typeof value === "function" ? { __quickjs_worker_type: "module_fn", __quickjs_worker_handle_id: meta.id, name: "default" } : value; if (!out.__quickjs_worker_module_keys.includes("default")) out.__quickjs_worker_module_keys.push("default"); } out.rootType = meta.rootType; return out; }; globalThis[key] = { __bridgeVersion: 1, create, createFromGlobal: (path) => create(resolve(globalThis, path)), tryCreateFromGlobal: (path) => { const found = resolveWithExistence(globalThis, path); if (!found.exists) return undefined; return create(found.value); }, createFromEval: (src) => create((0, eval)(String(src))), applyOp, globalOp, importModule, }; return true; })() `; const HANDLE_RUN_SOURCE = `(__payload) => globalThis[${JSON.stringify(HANDLE_BRIDGE_KEY)}].applyOp(__payload)`; const GLOBAL_RUN_SOURCE = `(__payload) => globalThis[${JSON.stringify(HANDLE_BRIDGE_KEY)}].globalOp(__payload)`; const HANDLE_CREATE_FROM_EVAL_SOURCE = `(__src) => globalThis[${JSON.stringify(HANDLE_BRIDGE_KEY)}].createFromEval(__src)`; const HANDLE_CREATE_FROM_GLOBAL_SOURCE = `(__path) => globalThis[${JSON.stringify(HANDLE_BRIDGE_KEY)}].createFromGlobal(__path)`; const HANDLE_TRY_CREATE_FROM_GLOBAL_SOURCE = `(__path) => globalThis[${JSON.stringify(HANDLE_BRIDGE_KEY)}].tryCreateFromGlobal(__path)`; const MODULE_IMPORT_SOURCE = `(__spec) => globalThis[${JSON.stringify(HANDLE_BRIDGE_KEY)}].importModule(__spec)`; function buildCjsEvalEsmSource(source: string): string { const q = JSON.stringify; const requires: string[] = []; const seen = new Set(); const re = /\brequire\s*\(\s*(['"])([^"'\\]*(?:\\.[^"'\\]*)*)\1\s*\)/g; let match: RegExpExecArray | null = null; while ((match = re.exec(source))) { const raw = String(match[2] || ""); if (!raw || seen.has(raw)) continue; seen.add(raw); requires.push(raw); } const names: string[] = []; const addName = (name: string) => { const n = String(name || "").trim(); if (!n || n === "default" || n === "__esModule") return; if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(n)) return; if (!names.includes(n)) names.push(n); }; for (const reName of [ /\bexports\.([A-Za-z_$][A-Za-z0-9_$]*)\s*=/g, /\bmodule\.exports\.([A-Za-z_$][A-Za-z0-9_$]*)\s*=/g, /\bObject\.defineProperty\(\s*(?:exports|module\.exports)\s*,\s*(['"])([A-Za-z_$][A-Za-z0-9_$]*)\1/g, ]) { let m: RegExpExecArray | null = null; while ((m = reName.exec(source))) addName(m[m.length - 1] as string); } const lines: string[] = []; for (let i = 0; i < requires.length; i += 1) lines.push(`import * as __qjsReq${i} from ${q(requires[i])};`); lines.push("const exports = {};"); lines.push('const module = { exports, filename: "", id: "", loaded: false, parent: null, children: [], paths: [] };'); lines.push("const __qjsRequireMap = new Map();"); for (let i = 0; i < requires.length; i += 1) lines.push(`__qjsRequireMap.set(${q(requires[i])}, __qjsReq${i});`); lines.push("const require = (spec) => { const m = __qjsRequireMap.get(String(spec)); if (!m) throw new Error(`Unsupported require(): ${String(spec)}`); if (m && typeof m === 'object' && 'default' in m && m.default != null) return m.default; return m; };"); lines.push(`const __qjsSource = ${q(source)};`); lines.push('const __qjsFn = new Function("exports", "require", "module", "__filename", "__dirname", __qjsSource);'); lines.push('try { __qjsFn.call(module.exports, module.exports, require, module, module.filename, "."); } finally { module.loaded = true; }'); lines.push("const __qjsFinal = module.exports;"); lines.push("const __qjsNamed = (__qjsFinal && (typeof __qjsFinal === 'object' || typeof __qjsFinal === 'function')) ? __qjsFinal : Object.create(null);"); lines.push("export default __qjsFinal;"); for (const name of names) lines.push(`export const ${name} = __qjsNamed[${q(name)}];`); return `${lines.join("\n")}\n`; } function normalizeEvalOptions(options?: any): any { if (options == null) return undefined; if (typeof options === "string") return { filename: options }; const out: any = {}; if (typeof options.filename === "string") out.filename = options.filename; if (Array.isArray(options.args)) out.args = options.args; if (typeof options.maxEvalMs === "number") out.maxEvalMs = options.maxEvalMs; if (typeof options.maxCpuMs === "number") out.maxCpuMs = options.maxCpuMs; return out; } function safeString(value: any): string { return String(value == null ? "" : value); } function isSimpleGlobalPath(path: string): boolean { return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(safeString(path).trim()); } function normalizeImportsResult(result: any, specifier: string): any { if (typeof result === "string") return result; if (result && typeof result === "object") { if (typeof result.src === "string") return result.src; if (typeof result.resolve === "string") return { resolve: result.resolve }; } if (result === false) { return `throw new Error(${JSON.stringify(`Import blocked: ${specifier}`)});`; } if (result === true || result == null) { return `throw new Error(${JSON.stringify(`Import not resolved: ${specifier}`)});`; } return `throw new Error(${JSON.stringify(`Unsupported import response for: ${specifier}`)});`; } type QuickJSStatsKind = "eval" | "handle" | "global" | "module" | "message" | "other"; type QuickJSOpSample = { ts: number; kind: QuickJSStatsKind; durationMs: number; }; const STATS_MIN_WINDOW_MS = 10; const STATS_DEFAULT_WINDOW_MS = 1000; const STATS_MAX_WINDOW_MS = 60_000; const STATS_RETENTION_MS = 5 * 60_000; const EVENT_LOOP_DEFAULT_MEASURE_MS = 20; const CPU_DEFAULT_MEASURE_MS = 100; function clampStatWindow(value: any, fallback: number): number { const parsed = Number(value); if (!Number.isFinite(parsed)) return fallback; return Math.max(STATS_MIN_WINDOW_MS, Math.min(STATS_MAX_WINDOW_MS, Math.trunc(parsed))); } function normalizeThrownError(error: any): any { if (!error || typeof error !== "object") return error; const message = typeof error.message === "string" ? error.message : ""; const name = typeof error.name === "string" && error.name ? error.name : "Error"; if (message && typeof error.stack === "string" && !error.stack.includes(message)) { try { error.stack = `${name}: ${message}\n${error.stack}`; } catch { // ignore non-writable stack properties } } return error; } function estimateTransferBytes(value: any): number { if (value == null) return 0; if (typeof value === "string") return Buffer.byteLength(value); if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") { return Buffer.byteLength(String(value)); } if (value instanceof ArrayBuffer) return value.byteLength; if (typeof ArrayBuffer !== "undefined" && typeof ArrayBuffer.isView === "function" && ArrayBuffer.isView(value)) { return value.byteLength; } if (Array.isArray(value)) { return value.length * 8; } if (value && typeof value === "object") { return Object.keys(value).length * 16; } return 0; } function isBinaryPayload(value: any): boolean { if (value instanceof ArrayBuffer) return true; if (typeof ArrayBuffer !== "undefined" && typeof ArrayBuffer.isView === "function" && ArrayBuffer.isView(value)) return true; return false; } function normalizeBinaryPayload(value: any): Uint8Array { if (value instanceof Uint8Array) return value; if (value instanceof ArrayBuffer) return new Uint8Array(value); if (typeof ArrayBuffer !== "undefined" && typeof ArrayBuffer.isView === "function" && ArrayBuffer.isView(value)) { return new Uint8Array(value.buffer, value.byteOffset, value.byteLength); } return value; } const FRAME_TAG_UNDEFINED = 0; const FRAME_TAG_NULL = 1; const FRAME_TAG_FALSE = 2; const FRAME_TAG_TRUE = 3; const FRAME_TAG_NUMBER = 4; const FRAME_TAG_STRING = 5; const FRAME_TAG_DATE = 6; const FRAME_TAG_BUFFER = 7; const FRAME_TAG_ARRAY = 8; const FRAME_TAG_OBJECT = 9; const FRAME_TAG_ERROR = 10; const FRAME_TAG_NUMBER_ARRAY = 11; const FRAME_TAG_FLAT_OBJECT = 12; const FRAME_TAG_BIGINT = 13; const FRAME_MAX_DEPTH = 64; const LARGE_BINARY_FRAME_THRESHOLD = 16 * 1024; const textEncoder = new TextEncoder(); const textDecoder = new TextDecoder(); function isPlainObject(value: any): value is Record { if (!value || typeof value !== "object") return false; const proto = Object.getPrototypeOf(value); return proto === Object.prototype || proto === null; } function isFlatRecord(value: any): value is Record { if (!isPlainObject(value)) return false; for (const entry of Object.values(value)) { if ( entry !== null && entry !== undefined && typeof entry !== "string" && typeof entry !== "number" && typeof entry !== "bigint" && typeof entry !== "boolean" ) { return false; } } return true; } function writeU32LE(out: number[], value: number): void { const n = value >>> 0; out.push(n & 255, (n >>> 8) & 255, (n >>> 16) & 255, (n >>> 24) & 255); } function writeF64LE(out: number[], value: number): void { const buf = new ArrayBuffer(8); new DataView(buf).setFloat64(0, value, true); const bytes = new Uint8Array(buf); for (const b of bytes) out.push(b); } function writeBytes(out: number[], bytes: Uint8Array): void { writeU32LE(out, bytes.byteLength); for (const b of bytes) out.push(b); } function writeString(out: number[], value: string): void { writeBytes(out, textEncoder.encode(String(value))); } function writeOptionalString(out: number[], value: string | null | undefined): void { if (typeof value === "string") { out.push(1); writeString(out, value); } else { out.push(0); } } function frameStringSize(value: string): number { return 4 + textEncoder.encode(String(value)).byteLength; } function frameFlatValueSize(value: any): number { if (value === undefined || value === null || typeof value === "boolean") return 1; if (typeof value === "number") return 1 + 8; if (typeof value === "bigint") return 1 + frameStringSize(String(value)); return 1 + frameStringSize(String(value)); } function encodeFlatValueInto(view: DataView, out: Uint8Array, offset: number, value: any): number { if (value === undefined) { out[offset] = FRAME_TAG_UNDEFINED; return offset + 1; } if (value === null) { out[offset] = FRAME_TAG_NULL; return offset + 1; } if (value === false) { out[offset] = FRAME_TAG_FALSE; return offset + 1; } if (value === true) { out[offset] = FRAME_TAG_TRUE; return offset + 1; } if (typeof value === "number") { out[offset] = FRAME_TAG_NUMBER; view.setFloat64(offset + 1, value, true); return offset + 9; } if (typeof value === "bigint") { const bytes = textEncoder.encode(String(value)); out[offset] = FRAME_TAG_BIGINT; view.setUint32(offset + 1, bytes.byteLength, true); out.set(bytes, offset + 5); return offset + 5 + bytes.byteLength; } const bytes = textEncoder.encode(String(value)); out[offset] = FRAME_TAG_STRING; view.setUint32(offset + 1, bytes.byteLength, true); out.set(bytes, offset + 5); return offset + 5 + bytes.byteLength; } function encodeFlatRecordFrame(value: Record): Uint8Array { const entries = Object.entries(value); let size = 1 + 4; for (const [key, entry] of entries) { size += frameStringSize(key); size += frameFlatValueSize(entry); } const out = new Uint8Array(size); out[0] = FRAME_TAG_FLAT_OBJECT; const view = new DataView(out.buffer, out.byteOffset, out.byteLength); view.setUint32(1, entries.length, true); let offset = 5; for (const [key, entry] of entries) { const keyBytes = textEncoder.encode(key); view.setUint32(offset, keyBytes.byteLength, true); out.set(keyBytes, offset + 4); offset += 4 + keyBytes.byteLength; offset = encodeFlatValueInto(view, out, offset, entry); } return out; } function encodeMessageFrameInto(out: number[], value: any, depth = 0): void { if (depth > FRAME_MAX_DEPTH) throw new Error("Structured frame depth exceeded"); if (value === undefined) { out.push(FRAME_TAG_UNDEFINED); return; } if (value === null) { out.push(FRAME_TAG_NULL); return; } if (value === false) { out.push(FRAME_TAG_FALSE); return; } if (value === true) { out.push(FRAME_TAG_TRUE); return; } if (typeof value === "number") { out.push(FRAME_TAG_NUMBER); writeF64LE(out, value); return; } if (typeof value === "bigint") { out.push(FRAME_TAG_BIGINT); writeString(out, String(value)); return; } if (typeof value === "string") { out.push(FRAME_TAG_STRING); writeString(out, value); return; } if (value instanceof Date) { out.push(FRAME_TAG_DATE); writeF64LE(out, value.getTime()); return; } if (isBinaryPayload(value)) { out.push(FRAME_TAG_BUFFER); writeBytes(out, normalizeBinaryPayload(value)); return; } if (Array.isArray(value)) { if (value.every((item) => typeof item === "number")) { out.push(FRAME_TAG_NUMBER_ARRAY); writeU32LE(out, value.length); for (const item of value) writeF64LE(out, item); return; } out.push(FRAME_TAG_ARRAY); writeU32LE(out, value.length); for (const item of value) encodeMessageFrameInto(out, item, depth + 1); return; } if (value instanceof Error) { out.push(FRAME_TAG_ERROR); writeString(out, value.name || "Error"); writeString(out, value.message || ""); writeOptionalString(out, typeof value.stack === "string" ? value.stack : undefined); writeOptionalString(out, value && typeof (value as any).code === "string" ? (value as any).code : undefined); return; } if (isFlatRecord(value)) { const entries = Object.entries(value); out.push(FRAME_TAG_FLAT_OBJECT); writeU32LE(out, entries.length); for (const [key, entry] of entries) { writeString(out, key); encodeMessageFrameInto(out, entry, depth + 1); } return; } if (isPlainObject(value)) { const entries = Object.entries(value); out.push(FRAME_TAG_OBJECT); writeU32LE(out, entries.length); for (const [key, entry] of entries) { writeString(out, key); encodeMessageFrameInto(out, entry, depth + 1); } return; } throw new Error(`Unsupported framed message value: ${Object.prototype.toString.call(value)}`); } function encodeMessageFrame(value: any): Uint8Array { if (isBinaryPayload(value)) { const bytes = normalizeBinaryPayload(value); const out = new Uint8Array(1 + 4 + bytes.byteLength); out[0] = FRAME_TAG_BUFFER; const view = new DataView(out.buffer, out.byteOffset, out.byteLength); view.setUint32(1, bytes.byteLength, true); out.set(bytes, 5); return out; } if (Array.isArray(value) && value.every((item) => typeof item === "number")) { const out = new Uint8Array(1 + 4 + (value.length * 8)); out[0] = FRAME_TAG_NUMBER_ARRAY; const view = new DataView(out.buffer, out.byteOffset, out.byteLength); view.setUint32(1, value.length, true); let offset = 5; for (const item of value) { view.setFloat64(offset, item, true); offset += 8; } return out; } if (isFlatRecord(value)) { return encodeFlatRecordFrame(value); } const out: number[] = []; encodeMessageFrameInto(out, value, 0); return Uint8Array.from(out); } function encodeMessageFrameBatch(values: any[]): Uint8Array { return encodeMessageFrame(values); } function isFrameEncodable(value: any, depth = 0): boolean { if (depth > FRAME_MAX_DEPTH) return false; if ( value === undefined || value === null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean" ) { return true; } if (value instanceof Date || value instanceof Error) return true; if (isBinaryPayload(value)) return true; if (Array.isArray(value)) { for (const item of value) { if (!isFrameEncodable(item, depth + 1)) return false; } return true; } if (isPlainObject(value)) { for (const entry of Object.values(value)) { if (!isFrameEncodable(entry, depth + 1)) return false; } return true; } return false; } function shouldUseFrameLane(value: any): boolean { if (Array.isArray(value) && value.every((item) => typeof item === "number")) return true; if (isFlatRecord(value)) return true; return isBinaryPayload(value) && normalizeBinaryPayload(value).byteLength >= LARGE_BINARY_FRAME_THRESHOLD; } function shouldUseBatchFrameLane(values: any[]): boolean { if (values.length === 0) return false; if (values.every((item) => isBinaryPayload(item) && normalizeBinaryPayload(item).byteLength >= LARGE_BINARY_FRAME_THRESHOLD)) { return true; } return values.length > 1 && values.every((item) => isFrameEncodable(item)); } function readU8(frame: Uint8Array, state: { offset: number }): number { if (state.offset >= frame.byteLength) throw new Error("Unexpected end of frame"); return frame[state.offset++]; } function readU32LE(frame: Uint8Array, state: { offset: number }): number { if (state.offset + 4 > frame.byteLength) throw new Error("Unexpected end of frame"); const view = new DataView(frame.buffer, frame.byteOffset + state.offset, 4); state.offset += 4; return view.getUint32(0, true); } function readF64LE(frame: Uint8Array, state: { offset: number }): number { if (state.offset + 8 > frame.byteLength) throw new Error("Unexpected end of frame"); const view = new DataView(frame.buffer, frame.byteOffset + state.offset, 8); state.offset += 8; return view.getFloat64(0, true); } function readBytes(frame: Uint8Array, state: { offset: number }): Uint8Array { const len = readU32LE(frame, state); if (state.offset + len > frame.byteLength) throw new Error("Unexpected end of frame"); const out = frame.slice(state.offset, state.offset + len); state.offset += len; return out; } function readString(frame: Uint8Array, state: { offset: number }): string { return textDecoder.decode(readBytes(frame, state)); } function readOptionalString(frame: Uint8Array, state: { offset: number }): string | undefined { const tag = readU8(frame, state); if (tag === 0) return undefined; if (tag === 1) return readString(frame, state); throw new Error("Invalid optional string tag"); } function decodeMessageFrame(frameLike: Uint8Array | ArrayBuffer): any { const frame = frameLike instanceof Uint8Array ? frameLike : new Uint8Array(frameLike); const state = { offset: 0 }; const value = decodeMessageFrameAt(frame, state, 0); if (state.offset !== frame.byteLength) throw new Error("Trailing bytes in frame"); return value; } function decodeMessageFrameAt(frame: Uint8Array, state: { offset: number }, depth: number): any { if (depth > FRAME_MAX_DEPTH) throw new Error("Structured frame depth exceeded"); switch (readU8(frame, state)) { case FRAME_TAG_UNDEFINED: return undefined; case FRAME_TAG_NULL: return null; case FRAME_TAG_FALSE: return false; case FRAME_TAG_TRUE: return true; case FRAME_TAG_NUMBER: return readF64LE(frame, state); case FRAME_TAG_BIGINT: return BigInt(readString(frame, state)); case FRAME_TAG_STRING: return readString(frame, state); case FRAME_TAG_DATE: return new Date(readF64LE(frame, state)); case FRAME_TAG_BUFFER: return readBytes(frame, state); case FRAME_TAG_ARRAY: { const len = readU32LE(frame, state); const out = new Array(len); for (let i = 0; i < len; i += 1) out[i] = decodeMessageFrameAt(frame, state, depth + 1); return out; } case FRAME_TAG_NUMBER_ARRAY: { const len = readU32LE(frame, state); const out = new Array(len); for (let i = 0; i < len; i += 1) out[i] = readF64LE(frame, state); return out; } case FRAME_TAG_OBJECT: { const len = readU32LE(frame, state); const out: Record = {}; for (let i = 0; i < len; i += 1) { out[readString(frame, state)] = decodeMessageFrameAt(frame, state, depth + 1); } return out; } case FRAME_TAG_FLAT_OBJECT: { const len = readU32LE(frame, state); const out: Record = {}; for (let i = 0; i < len; i += 1) { out[readString(frame, state)] = decodeMessageFrameAt(frame, state, depth + 1); } return out; } case FRAME_TAG_ERROR: { const err = new Error(readString(frame, state)); err.name = readString(frame, state); const stack = readOptionalString(frame, state); if (stack) err.stack = stack; const code = readOptionalString(frame, state); if (code) (err as any).code = code; return err; } default: throw new Error("Unknown frame tag"); } } function createEmptyTotals(): QuickJSTotalsStats { return { ops: 0, errors: 0, eval: 0, handle: 0, global: 0, module: 0, other: 0, messagesOut: 0, messagesIn: 0, bytesOut: 0, bytesIn: 0, }; } export class QuickJSWorker extends EventEmitter { id: string; _lastExecution: EvalStats | null; _closed: boolean; _bridgeReady: boolean; _bridgePromise: Promise | null; _moduleCounter: number; _modules: Map; _activeHandles: Set; _userImports: any; _rawOptions: QuickJSOptions; _native: NativeQuickJSWorker; _activeOpsCount: number; _opSamples: QuickJSOpSample[]; _totalsStats: QuickJSTotalsStats; _closeNotified: boolean; _messageHandlers: Set<(msg: any) => void>; _messageBatchHandlers: Set<(msgs: any[]) => void>; _closeHandlers: Set<() => void>; _runtimeHandlers: Set<(event: QuickJSRuntimeEvent) => void>; _errorHandlers: Set<(event: QuickJSErrorEvent) => void>; _hostCallsiteByOpId: Map>; _nextOpId: number; _messageDrainScheduled: boolean; _loopRefCount: number; _timerLoopHeld: boolean; module: QuickJSModuleApi; handle: QuickJSHandleApi; global: QuickJSGlobalApi; stats: QuickJSStatsApi; constructor(options: QuickJSOptions = {}) { super(); this.id = `qjs:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`; this._lastExecution = null; this._closed = false; this._bridgeReady = false; this._bridgePromise = null; this._moduleCounter = 0; this._modules = new Map(); this._activeHandles = new Set(); this._activeOpsCount = 0; this._opSamples = []; this._totalsStats = createEmptyTotals(); this._closeNotified = false; this._messageHandlers = new Set(); this._messageBatchHandlers = new Set(); this._closeHandlers = new Set(); this._runtimeHandlers = new Set(); this._errorHandlers = new Set(); this._hostCallsiteByOpId = new Map(); this._nextOpId = 0; this._messageDrainScheduled = false; this._loopRefCount = 0; this._timerLoopHeld = false; this._userImports = typeof options.imports === "function" ? options.imports : options.imports; this._rawOptions = { ...options }; if (options.modules instanceof Map) { for (const [key, value] of options.modules.entries()) this._modules.set(String(key), this._normalizeModuleSource(value)); } else if (options.modules && typeof options.modules === "object") { for (const [key, value] of Object.entries(options.modules)) this._modules.set(String(key), this._normalizeModuleSource(value)); } const nativeOptions = { ...options }; delete nativeOptions.modules; nativeOptions.imports = this._composeImports(); this._native = NativeQJSWorker(nativeOptions) as NativeQuickJSWorker; this._native.on("messageBatch", () => this._scheduleMessageDrain()); this._native.on("message", (msg: any) => { this._recordTotals("message"); this._recordOp("message", Date.now()); this._totalsStats.messagesIn += 1; this._totalsStats.bytesIn += estimateTransferBytes(msg); this._dispatchMessage(msg); }); this._native.on("timerState", (active: boolean) => { if (active) this._retainLoopRef(); else this._releaseLoopRef(); }); this._native.on("close", () => { this._closed = true; this._dispatchClose(); }); this.module = { import: (specifier: string) => this._moduleImport(specifier), eval: (source: string, moduleOptions?: any) => this._moduleEval(source, moduleOptions), register: (moduleName: string, source: string, moduleOptions?: any) => this._moduleRegister(moduleName, source, moduleOptions), clear: (moduleName: string) => this._moduleClear(moduleName), }; this.handle = { get: (path: string, handleOptions?: any) => this._handleGet(path, handleOptions), tryGet: (path: string, handleOptions?: any) => this._handleTryGet(path, handleOptions), eval: (source: string, handleOptions?: any) => this._handleEval(source, handleOptions), }; this.global = { set: (path: string, value: any, execOptions?: any) => this._globalSet(path, value, execOptions), get: (path: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "get", path }, execOptions)), has: (path: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "has", path }, execOptions)), delete: (path: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "delete", path }, execOptions)), keys: (path?: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "keys", path }, execOptions)), entries: (path?: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "entries", path }, execOptions)), getOwnPropertyDescriptor: (path: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "getOwnPropertyDescriptor", path }, execOptions)), define: (path: string, descriptor: PropertyDescriptor, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "define", path, descriptor }, execOptions)), isCallable: (path?: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "isCallable", path }, execOptions)), isPromise: (path?: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "isPromise", path }, execOptions)), call: (path: string, args?: any[], execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "call", path, args: Array.isArray(args) ? args : [] }, execOptions)), construct: (path: string, args?: any[], execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "construct", path, args: Array.isArray(args) ? args : [] }, execOptions)), await: (path: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "await", path, ...(execOptions || {}) }, execOptions)), clone: async (path: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._createHandleFromMeta(await this._globalOp({ op: "clone", path }, execOptions), execOptions)), toJSON: (path?: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "toJSON", path }, execOptions)), apply: async (path: string, ops: any[], execOptions?: any) => { return this._trackAsyncOp("global", async () => { const handle = await this._createHandleFromMeta(await this._globalOp({ op: "clone", path }, execOptions), execOptions); try { const results: any[] = []; for (const op of ops || []) results.push(await handle._run!(op, execOptions)); return results as T; } finally { await handle.dispose(); } }); }, getType: (path?: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "getType", path }, execOptions)), instanceOf: (path: string, constructorPath: string, execOptions?: any) => this._trackAsyncOp("global", async () => this._globalOp({ op: "instanceOf", path, constructorPath }, execOptions)), }; const self = this; this.stats = { get activeOps() { return self._activeOpsCount; }, get lastExecution() { return self._lastExecution; }, cpu: (statsOptions?: QuickJSCpuOptions) => self._statsCpu(statsOptions), rates: (statsOptions?: QuickJSWindowOptions) => self._statsRates(statsOptions), latency: (statsOptions?: QuickJSWindowOptions) => self._statsLatency(statsOptions), eventLoopLag: (statsOptions?: QuickJSEventLoopLagOptions) => self._statsEventLoopLag(statsOptions), get totals() { return { ...self._totalsStats }; }, reset: (statsOptions?: QuickJSStatsResetOptions) => self._statsReset(statsOptions), memory: () => self.memory(), }; } _normalizeModuleSource(value: any): string { if (typeof value === "string") return value; if (value && typeof value === "object" && typeof value.src === "string") return value.src; return safeString(value); } _composeImports(): any { const self = this; return function composedImports(specifier: string) { const spec = safeString(specifier); if (self._modules.has(spec)) return self._modules.get(spec); const user = self._userImports; if (typeof user === "function") { let result = user(spec); let depth = 0; while (result && typeof result === "object" && typeof result.resolve === "string" && depth < 8) { const next = safeString(result.resolve); if (self._modules.has(next)) return self._modules.get(next); result = user(next); depth += 1; } return normalizeImportsResult(result, spec); } if (user === false) return normalizeImportsResult(false, spec); return normalizeImportsResult(undefined, spec); }; } _emitRuntime(kind: string, extra?: any): void { const opId = typeof extra?.opId === "string" ? String(extra.opId) : ""; const hostMeta = opId ? this._hostCallsiteByOpId.get(opId) : undefined; const payload = { ...(hostMeta || {}), kind, ts: Date.now(), ...(extra || {}) }; this._dispatchRuntime(payload); if (opId) { if (kind === "error.thrown") { this._hostCallsiteByOpId.delete(opId); } else if ((kind === "eval.end" || kind === "evalSync.end") && extra?.ok === true) { this._hostCallsiteByOpId.delete(opId); } } } _dispatchMessage(msg: any): void { if (this._messageHandlers.size === 0) return; for (const handler of this._messageHandlers) { try { handler(msg); } catch { // ignore subscriber errors } } } _dispatchMessageBatch(msgs: any[]): void { if (this._messageBatchHandlers.size === 0) return; for (const handler of this._messageBatchHandlers) { try { handler(msgs); } catch { // ignore subscriber errors } } } _scheduleMessageDrain(): void { if (this._messageDrainScheduled) return; this._messageDrainScheduled = true; queueMicrotask(() => { this._messageDrainScheduled = false; if (typeof this._native.drainMessagesFrame === "function") { for (;;) { const frame = this._native.drainMessagesFrame(); const items = decodeMessageFrame(frame) as any[]; if (!Array.isArray(items) || items.length === 0) break; this._recordTotals("message"); this._recordOp("message", Date.now()); this._totalsStats.messagesIn += items.length; this._totalsStats.bytesIn += frame.byteLength; this._dispatchMessageBatch(items); for (const item of items) this._dispatchMessage(item); } return; } if (typeof this._native.drainMessages !== "function") return; for (;;) { const batch = this._native.drainMessages(); const items = Array.isArray(batch) ? batch : []; if (items.length === 0) break; this._recordTotals("message"); this._recordOp("message", Date.now()); this._totalsStats.messagesIn += items.length; this._totalsStats.bytesIn += items.reduce((sum, item) => sum + estimateTransferBytes(item), 0); this._dispatchMessageBatch(items); for (const item of items) this._dispatchMessage(item); } }); } _dispatchClose(): void { if (this._closeNotified) return; this._closeNotified = true; if (this._closeHandlers.size === 0) return; for (const handler of [...this._closeHandlers]) { try { handler(); } catch { // ignore subscriber errors } } } _dispatchRuntime(event: QuickJSRuntimeEvent): void { if (this._runtimeHandlers.size === 0) return; for (const handler of [...this._runtimeHandlers]) { try { handler(event); } catch { // ignore subscriber errors } } } _dispatchError(surface: "eval" | "evalSync", error: any, opId?: string): void { const event: QuickJSErrorEvent = { kind: "error.thrown", ts: Date.now(), opId, surface, error, }; const hostMeta = opId ? this._hostCallsiteByOpId.get(opId) : undefined; this._emitRuntime("error.thrown", { ...event }); if (this._errorHandlers.size === 0) return; for (const handler of [...this._errorHandlers]) { try { handler({ ...(hostMeta || {}), ...event }); } catch { // ignore subscriber errors } } } _startRuntimeOp(kind: "eval.begin" | "evalSync.begin", extra?: Record): string { const opId = `op:${++this._nextOpId}`; const hostMeta = this._captureHostCallsiteMeta(); if (typeof hostMeta.hostFile === "string") this._hostCallsiteByOpId.set(opId, hostMeta); this._emitRuntime(kind, { ...(extra || {}), opId }); return opId; } _captureHostCallsiteMeta(): Partial { if (this._runtimeHandlers.size === 0 && this._errorHandlers.size === 0) return {}; const stack = String(new Error().stack ?? ""); if (!stack) return {}; const lines = stack .split("\n") .slice(1) .map((line) => line.trim()) .filter(Boolean); const candidates: Array<{ file: string; line: number; column: number }> = []; for (const line of lines) { let loc = ""; const paren = line.match(/\((.*)\)\s*$/); if (paren?.[1]) loc = paren[1]; else { const bare = line.match(/^at\s+(.+)$/); if (bare?.[1]) loc = bare[1]; } if (!loc) continue; if ( loc.startsWith("node:") || loc.includes("node:internal") || loc.includes("/node_modules/") || loc.includes("\\node_modules\\") ) { continue; } const match = loc.match(/^(.*):(\d+):(\d+)$/); if (!match) continue; const file = String(match[1] || ""); const hostLine = Number(match[2]); const hostColumn = Number(match[3]); if (!Number.isFinite(hostLine) || !Number.isFinite(hostColumn)) continue; const normalized = file.replaceAll("\\", "/"); if (normalized.endsWith("/src/worker.ts") || normalized.endsWith("/dist/worker.js")) continue; candidates.push({ file, line: hostLine, column: hostColumn }); } if (candidates.length === 0) return {}; const immediate = candidates[0]; const origin = candidates[candidates.length - 1]; return { hostFile: origin.file, hostLine: origin.line, hostColumn: origin.column, hostCallSite: `${origin.file}:${origin.line}:${origin.column}`, hostImmediateFile: immediate.file, hostImmediateLine: immediate.line, hostImmediateColumn: immediate.column, hostImmediateCallSite: `${immediate.file}:${immediate.line}:${immediate.column}`, }; } on(event: "message", cb: (msg: any) => void): this; on(event: "messageBatch", cb: (msgs: any[]) => void): this; on(event: "close", cb: () => void): this; on(event: "runtime", cb: (event: QuickJSRuntimeEvent) => void): this; on(event: "error", cb: (event: QuickJSErrorEvent) => void): this; on(event: string, cb: (...args: any[]) => void): this { if (typeof cb !== "function") return this; if (event === "message") { this._messageHandlers.add(cb as (msg: any) => void); return this; } if (event === "messageBatch") { this._messageBatchHandlers.add(cb as (msgs: any[]) => void); return this; } if (event === "close") { this._closeHandlers.add(cb as () => void); return this; } if (event === "runtime") { this._runtimeHandlers.add(cb as (event: QuickJSRuntimeEvent) => void); return this; } if (event === "error") { this._errorHandlers.add(cb as (event: QuickJSErrorEvent) => void); return this; } super.on(event, cb); return this; } off(event: "message", cb?: (msg: any) => void): this; off(event: "messageBatch", cb?: (msgs: any[]) => void): this; off(event: "close", cb?: () => void): this; off(event: "runtime", cb?: (event: QuickJSRuntimeEvent) => void): this; off(event: "error", cb?: (event: QuickJSErrorEvent) => void): this; off(event: string, cb?: (...args: any[]) => void): this { if (event === "message") { if (cb) this._messageHandlers.delete(cb as (msg: any) => void); else this._messageHandlers.clear(); return this; } if (event === "messageBatch") { if (cb) this._messageBatchHandlers.delete(cb as (msgs: any[]) => void); else this._messageBatchHandlers.clear(); return this; } if (event === "close") { if (cb) this._closeHandlers.delete(cb as () => void); else this._closeHandlers.clear(); return this; } if (event === "runtime") { if (cb) this._runtimeHandlers.delete(cb as (event: QuickJSRuntimeEvent) => void); else this._runtimeHandlers.clear(); return this; } if (event === "error") { if (cb) this._errorHandlers.delete(cb as (event: QuickJSErrorEvent) => void); else this._errorHandlers.clear(); return this; } if (cb) super.off(event, cb); else super.removeAllListeners(event); return this; } async _ensureBridge(): Promise { if (this._bridgeReady) return; if (this._bridgePromise) return this._bridgePromise; this._bridgePromise = this._evalRaw(HANDLE_INSTALL_SOURCE).then(() => { this._bridgeReady = true; }).finally(() => { this._bridgePromise = null; }); return this._bridgePromise; } _normalizeOptions(options?: EvalOptions | string): EvalOptions | undefined { return normalizeEvalOptions(options); } _pruneOpSamples(now = Date.now()): void { const cutoff = now - STATS_RETENTION_MS; while (this._opSamples.length > 0 && this._opSamples[0].ts < cutoff) { this._opSamples.shift(); } } _recordOp(kind: QuickJSStatsKind, startedAt: number): void { const now = Date.now(); this._opSamples.push({ ts: now, kind, durationMs: Math.max(0, now - startedAt) }); this._pruneOpSamples(now); } _recordTotals(kind: QuickJSStatsKind): void { this._totalsStats.ops += 1; if (kind === "message") { this._totalsStats.other += 1; return; } this._totalsStats[kind] += 1; } _retainLoopRef(): void { if (this._closed) return; this._loopRefCount += 1; if (this._loopRefCount === 1) { this._native.ref(); } } _releaseLoopRef(): void { if (this._loopRefCount <= 0) return; this._loopRefCount -= 1; if (this._loopRefCount === 0 && !this._closed) { this._native.unref(); } } _syncTimerLoopRef(): void { const count = typeof this._native.activeTimerCount === "function" ? this._native.activeTimerCount() : 0; if (count > 0) { if (!this._timerLoopHeld) { this._timerLoopHeld = true; this._retainLoopRef(); } return; } if (this._timerLoopHeld) { this._timerLoopHeld = false; this._releaseLoopRef(); } } async _trackAsyncOp(kind: QuickJSStatsKind, run: () => Promise): Promise { const startedAt = Date.now(); this._activeOpsCount += 1; this._recordTotals(kind); this._retainLoopRef(); try { return await run(); } catch (error) { this._totalsStats.errors += 1; throw error; } finally { this._activeOpsCount = Math.max(0, this._activeOpsCount - 1); this._syncTimerLoopRef(); this._releaseLoopRef(); this._recordOp(kind, startedAt); } } _trackSyncOp(kind: QuickJSStatsKind, run: () => T): T { const startedAt = Date.now(); this._recordTotals(kind); try { return run(); } catch (error) { this._totalsStats.errors += 1; throw error; } finally { this._syncTimerLoopRef(); this._recordOp(kind, startedAt); } } async _evalRaw(code: string, options: EvalOptions | undefined = undefined): Promise { const opId = this._startRuntimeOp("eval.begin", { filename: options && options.filename, args: Array.isArray(options?.args) ? options?.args : undefined, }); try { const [result, stats] = await this._native.eval(safeString(code), options); this._lastExecution = stats; this._emitRuntime("eval.end", { opId, ok: true }); return result; } catch (error) { error = normalizeThrownError(error); this._emitRuntime("eval.end", { opId, ok: false }); this._dispatchError("eval", error, opId); throw error; } } _evalSyncRaw(code: string, options: EvalOptions | undefined = undefined): T { const opId = this._startRuntimeOp("evalSync.begin", { filename: options && options.filename, args: Array.isArray(options?.args) ? options?.args : undefined, }); try { const [result, stats] = this._native.evalSync(safeString(code), options); this._lastExecution = stats; this._emitRuntime("evalSync.end", { opId, ok: true }); return result; } catch (error) { error = normalizeThrownError(error); this._emitRuntime("evalSync.end", { opId, ok: false }); this._dispatchError("evalSync", error, opId); throw error; } } _collectWindowSamples(windowMs: number): QuickJSOpSample[] { const normalized = clampStatWindow(windowMs, STATS_DEFAULT_WINDOW_MS); const now = Date.now(); this._pruneOpSamples(now); const cutoff = now - normalized; return this._opSamples.filter((sample) => sample.ts >= cutoff); } async _statsCpu(options?: QuickJSCpuOptions): Promise { const measureMs = clampStatWindow(options && options.measureMs, CPU_DEFAULT_MEASURE_MS); return this._trackAsyncOp("other", async () => this._native.cpu(measureMs)); } async _statsRates(options?: QuickJSWindowOptions): Promise { const windowMs = clampStatWindow(options && options.windowMs, STATS_DEFAULT_WINDOW_MS); const samples = this._collectWindowSamples(windowMs); const rateFor = (kind: QuickJSStatsKind) => samples.filter((sample) => sample.kind === kind).length * 1000 / windowMs; return { windowMs, evalPerSec: rateFor("eval"), handlePerSec: rateFor("handle"), globalPerSec: rateFor("global"), modulePerSec: rateFor("module"), messagesPerSec: rateFor("message"), otherPerSec: rateFor("other"), }; } async _statsLatency(options?: QuickJSWindowOptions): Promise { const windowMs = clampStatWindow(options && options.windowMs, STATS_DEFAULT_WINDOW_MS); const samples = this._collectWindowSamples(windowMs); const count = samples.length; const total = samples.reduce((sum, sample) => sum + sample.durationMs, 0); const maxMs = samples.reduce((max, sample) => Math.max(max, sample.durationMs), 0); return { windowMs, count, avgMs: count > 0 ? total / count : 0, maxMs, }; } async _statsEventLoopLag(options?: QuickJSEventLoopLagOptions): Promise { const measureMs = clampStatWindow(options && options.measureMs, EVENT_LOOP_DEFAULT_MEASURE_MS); const startedAt = Date.now(); await new Promise((resolve) => setTimeout(resolve, measureMs)); return { measureMs, lagMs: Math.max(0, Date.now() - startedAt - measureMs), }; } _statsReset(options?: QuickJSStatsResetOptions): void { this._opSamples = []; if (!options || options.totals !== false) { this._totalsStats = createEmptyTotals(); } } async eval(code: string, options: EvalOptions | string | undefined = undefined): Promise { const opts = this._normalizeOptions(options); return this._trackAsyncOp("eval", () => this._evalRaw(code, opts)); } evalSync(code: string, options: EvalOptions | string | undefined = undefined): T { const opts = this._normalizeOptions(options); return this._trackSyncOp("eval", () => this._evalSyncRaw(code, opts)); } async evalModule = Record>(code: string, options: QuickJSModuleEvalOptions | string | undefined = undefined): Promise { const normalized = typeof options === "string" ? { filename: options } : options; return this.module.eval(code, normalized); } async _globalOp(payload: any, options?: any): Promise { await this._ensureBridge(); return this._evalRaw(GLOBAL_RUN_SOURCE, { ...(options || {}), args: [payload] }); } async _globalSet(path: string, value: any, options?: any): Promise { return this._trackAsyncOp("global", async () => { const key = safeString(path).trim(); if (!key) throw new Error("global.set(path, value) requires non-empty path"); if (isSimpleGlobalPath(key)) { return this._native.setGlobal(key, value); } return this._globalOp({ op: "set", path: key, value }, options); }); } async setGlobal(key: string, value: any): Promise { return this.global.set(key, value); } postMessage(msg: any): any { this._recordTotals("message"); this._recordOp("message", Date.now()); this._totalsStats.messagesOut += 1; this._totalsStats.bytesOut += estimateTransferBytes(msg); if (typeof this._native.postMessageFrame === "function" && shouldUseFrameLane(msg)) { return this._native.postMessageFrame(encodeMessageFrame(msg)); } return this._native.postMessage(isBinaryPayload(msg) ? normalizeBinaryPayload(msg) : msg); } postMessages(messages: any[]): any { const items = Array.isArray(messages) ? messages : []; this._recordTotals("message"); this._recordOp("message", Date.now()); this._totalsStats.messagesOut += items.length; this._totalsStats.bytesOut += items.reduce((sum, item) => sum + estimateTransferBytes(item), 0); if ( typeof this._native.postMessagesFrame === "function" && shouldUseBatchFrameLane(items) ) { return this._native.postMessagesFrame(encodeMessageFrameBatch(items)); } if (typeof this._native.postMessages === "function") { return this._native.postMessages(items.map((item) => isBinaryPayload(item) ? normalizeBinaryPayload(item) : item)); } for (const item of items) { this._native.postMessage(isBinaryPayload(item) ? normalizeBinaryPayload(item) : item); } } async getByteCode(code: string): Promise { return this._trackAsyncOp("other", async () => this._native.getByteCode(safeString(code))); } async loadByteCode(bytes: Uint8Array): Promise { return this._trackAsyncOp("other", async () => this._native.loadByteCode(bytes)); } async gc(): Promise { return this._trackAsyncOp("other", async () => this._native.gc()); } async memory(): Promise { return this._trackAsyncOp("other", async () => this._native.memory()); } async close(): Promise { if (this.isClosed()) return; this._retainLoopRef(); try { await this._native.close(); this._closed = true; this._dispatchClose(); await new Promise((resolve) => setTimeout(resolve, 10)); } finally { this._timerLoopHeld = false; this._loopRefCount = 0; } } isClosed(): boolean { return this._closed || this._native.isClosed(); } async [Symbol.asyncDispose](): Promise { if (!this.isClosed()) await this.close(); } async _moduleRegister(moduleName: string, source: string, options: any = undefined): Promise { return this._trackAsyncOp("module", async () => { const name = safeString(moduleName).trim(); if (!name) throw new Error("module.register(moduleName, source) requires non-empty moduleName"); const normalized = options && options.cjs ? buildCjsEvalEsmSource(safeString(source)) : this._normalizeModuleSource(source); this._modules.set(name, normalized); }); } async _moduleClear(moduleName: string): Promise { return this._trackAsyncOp("module", async () => { const name = safeString(moduleName).trim(); if (!name) throw new Error("module.clear(moduleName) requires non-empty moduleName"); return this._modules.delete(name); }); } async _moduleEval = Record>(source: string, options: any = undefined): Promise { return this._trackAsyncOp("module", async () => { const moduleName = options && typeof options.moduleName === "string" && options.moduleName.trim() ? options.moduleName.trim() : `quickjs:module:${++this._moduleCounter}`; const normalized = options && options.cjs ? buildCjsEvalEsmSource(safeString(source)) : this._normalizeModuleSource(source); this._modules.set(moduleName, normalized); return this._moduleImportRaw(moduleName); }); } async _moduleImport = Record>(specifier: string): Promise { return this._trackAsyncOp("module", async () => this._moduleImportRaw(specifier)); } async _moduleImportRaw = Record>(specifier: string): Promise { await this._ensureBridge(); const meta = await this._evalRaw(MODULE_IMPORT_SOURCE, { filename: ``, args: [safeString(specifier)], }); return this._wrapModuleNamespace(meta); } _wrapModuleNamespace>(meta: any): T { if (!meta || typeof meta !== "object") return meta; const handleId = meta.__quickjs_worker_handle_id; const out: any = Object.create(null); const keys = Array.isArray(meta.__quickjs_worker_module_keys) ? meta.__quickjs_worker_module_keys : Object.keys(meta); for (const key of keys) { const value = meta[key]; if (value && typeof value === "object" && value.__quickjs_worker_type === "module_fn") { const fnHandleId = value.__quickjs_worker_handle_id || handleId; out[key] = (...args: any[]) => this._trackAsyncOp("module", async () => this._runHandleOp({ id: fnHandleId, op: "call", path: key, args })); } else { out[key] = value; } } Object.defineProperty(out, "__handleId", { value: handleId, enumerable: false, configurable: false, writable: false, }); Object.defineProperty(out, Symbol.asyncDispose, { value: async () => { if (handleId) { await this._trackAsyncOp("module", async () => this._runHandleOp({ id: handleId, op: "dispose" }).catch(() => undefined)); } }, enumerable: false, }); return out as T; } async _runHandleOp(payload: any, options: any = undefined): Promise { await this._ensureBridge(); return this._evalRaw(HANDLE_RUN_SOURCE, { ...(options || {}), args: [payload] }); } async _createHandleFromMeta(meta: any, defaultOptions: any = undefined): Promise { if (!meta || typeof meta !== "object" || typeof meta.id !== "string") { throw new Error("Invalid handle metadata returned from runtime"); } const self = this; const id = meta.id; const rootType = meta.rootType || { type: "object", callable: false }; this._activeHandles.add(id); let disposed = false; const ensureLive = () => { if (disposed) { const error: any = new Error(`Handle ${id} is disposed`); error.code = "HANDLE_DISPOSED"; throw error; } }; const handle: any = { id, rootType, get disposed() { return disposed; }, _run: async (op: any, execOptions?: any) => { ensureLive(); return self._trackAsyncOp("handle", async () => self._runHandleOp({ id, ...(op || {}) }, execOptions || defaultOptions)); }, get: (path?: string, execOptions?: any) => handle._run({ op: "get", path }, execOptions), has: (path: string, execOptions?: any) => handle._run({ op: "has", path }, execOptions), set: (path: string, value: any, execOptions?: any) => handle._run({ op: "set", path, value }, execOptions), delete: (path: string, execOptions?: any) => handle._run({ op: "delete", path }, execOptions), keys: (path?: string, execOptions?: any) => handle._run({ op: "keys", path }, execOptions), entries: (path?: string, execOptions?: any) => handle._run({ op: "entries", path }, execOptions), getOwnPropertyDescriptor: async (path: string, execOptions?: any) => handle._run({ op: "getOwnPropertyDescriptor", path }, execOptions), define: async (path: string, descriptor: PropertyDescriptor, execOptions?: any) => handle._run({ op: "define", path, descriptor }, execOptions), instanceOf: async (constructorPath: string, execOptions?: any) => handle._run({ op: "instanceOf", constructorPath }, execOptions), isCallable: (path?: string, execOptions?: any) => handle._run({ op: "isCallable", path }, execOptions), isPromise: (path?: string, execOptions?: any) => handle._run({ op: "isPromise", path }, execOptions), call: (pathOrArgs?: any, argsOrOptions?: any, maybeOptions?: any) => { if (typeof pathOrArgs === "string") { return handle._run({ op: "call", path: pathOrArgs, args: Array.isArray(argsOrOptions) ? argsOrOptions : [] }, maybeOptions); } return handle._run({ op: "call", args: Array.isArray(pathOrArgs) ? pathOrArgs : [] }, argsOrOptions); }, construct: (args?: any[], execOptions?: any) => handle._run({ op: "construct", args: Array.isArray(args) ? args : [] }, execOptions), await: (execOptions?: any) => handle._run({ op: "await", ...(execOptions || {}) }, execOptions), clone: async (execOptions?: any) => self._createHandleFromMeta(await handle._run({ op: "clone" }, execOptions), execOptions), toJSON: (path?: string, execOptions?: any) => handle._run({ op: "toJSON", path }, execOptions), apply: async (ops: any[], execOptions?: any) => { const results: any[] = []; for (const op of Array.isArray(ops) ? ops : []) results.push(await handle._run(op, execOptions)); return results; }, getType: (path?: string, execOptions?: any) => handle._run({ op: "getType", path }, execOptions), dispose: async (execOptions?: any) => { if (disposed) return; disposed = true; self._activeHandles.delete(id); await self._trackAsyncOp("handle", async () => self._runHandleOp({ id, op: "dispose" }, execOptions || defaultOptions).catch(() => undefined)); }, }; Object.defineProperty(handle, Symbol.asyncDispose, { value: async () => handle.dispose(), enumerable: false, }); return handle; } async _handleGet(path: string, options: any = undefined): Promise { return this._trackAsyncOp("handle", async () => { await this._ensureBridge(); const meta = await this._evalRaw(HANDLE_CREATE_FROM_GLOBAL_SOURCE, { ...(options || {}), args: [safeString(path)] }); return this._createHandleFromMeta(meta, options); }); } async _handleTryGet(path: string, options: any = undefined): Promise { return this._trackAsyncOp("handle", async () => { await this._ensureBridge(); const meta = await this._evalRaw(HANDLE_TRY_CREATE_FROM_GLOBAL_SOURCE, { ...(options || {}), args: [safeString(path)] }); if (!meta) return undefined; return this._createHandleFromMeta(meta, options); }); } async _handleEval(source: string, options: any = undefined): Promise { return this._trackAsyncOp("handle", async () => { await this._ensureBridge(); const meta = await this._evalRaw(HANDLE_CREATE_FROM_EVAL_SOURCE, { ...(options || {}), args: [safeString(source)] }); return this._createHandleFromMeta(meta, options); }); } }