@ai-ecoverse/mcpcat 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3549 @@
1
+ // node_modules/@earendil-works/pi-codemode/dist/runtime/worker.js
2
+ import { parentPort, workerData } from "node:worker_threads";
3
+
4
+ // node_modules/@earendil-works/pi-codemode/dist/runtime/protocol.js
5
+ function isHostToWorkerMessage(value) {
6
+ return typeof value === "object" && value !== null && value.type === "result";
7
+ }
8
+
9
+ // node_modules/quickjs-wasi/dist/wasi-shim.js
10
+ function createWasiShim(memoryAccessor) {
11
+ const ERRNO_SUCCESS = 0;
12
+ const ERRNO_BADF = 8;
13
+ const ERRNO_NOSYS = 52;
14
+ const CLOCK_REALTIME = 0;
15
+ const CLOCK_MONOTONIC = 1;
16
+ return {
17
+ clock_time_get(clockId, _precision, resultPtr) {
18
+ const mem = memoryAccessor();
19
+ const view = new DataView(mem.buffer);
20
+ if (clockId === CLOCK_REALTIME || clockId === CLOCK_MONOTONIC) {
21
+ const timeNs = BigInt(Date.now()) * 1000000n;
22
+ view.setBigUint64(resultPtr, timeNs, true);
23
+ return ERRNO_SUCCESS;
24
+ }
25
+ return ERRNO_NOSYS;
26
+ },
27
+ fd_write(fd, iovsPtr, iovsLen, nwrittenPtr) {
28
+ const mem = memoryAccessor();
29
+ const view = new DataView(mem.buffer);
30
+ const bytes = new Uint8Array(mem.buffer);
31
+ let totalWritten = 0;
32
+ if (fd !== 1 && fd !== 2) {
33
+ return ERRNO_BADF;
34
+ }
35
+ for (let i = 0; i < iovsLen; i++) {
36
+ const bufPtr = view.getUint32(iovsPtr + i * 8, true);
37
+ const bufLen = view.getUint32(iovsPtr + i * 8 + 4, true);
38
+ const chunk = bytes.slice(bufPtr, bufPtr + bufLen);
39
+ const text = new TextDecoder().decode(chunk);
40
+ if (fd === 1) {
41
+ if (typeof process !== "undefined" && process.stdout) {
42
+ process.stdout.write(text);
43
+ } else {
44
+ console.log(text);
45
+ }
46
+ } else {
47
+ if (typeof process !== "undefined" && process.stderr) {
48
+ process.stderr.write(text);
49
+ } else {
50
+ console.error(text);
51
+ }
52
+ }
53
+ totalWritten += bufLen;
54
+ }
55
+ view.setUint32(nwrittenPtr, totalWritten, true);
56
+ return ERRNO_SUCCESS;
57
+ },
58
+ fd_close(_fd) {
59
+ return ERRNO_NOSYS;
60
+ },
61
+ fd_fdstat_get(fd, statPtr) {
62
+ const mem = memoryAccessor();
63
+ const view = new DataView(mem.buffer);
64
+ if (fd === 1 || fd === 2) {
65
+ view.setUint8(statPtr, 2);
66
+ view.setUint16(statPtr + 2, 0, true);
67
+ view.setBigUint64(statPtr + 8, 0n, true);
68
+ view.setBigUint64(statPtr + 16, 0n, true);
69
+ return ERRNO_SUCCESS;
70
+ }
71
+ return ERRNO_BADF;
72
+ },
73
+ fd_seek(_fd, _offset, _whence, _resultPtr) {
74
+ return ERRNO_NOSYS;
75
+ },
76
+ random_get(bufPtr, bufLen) {
77
+ const mem = memoryAccessor();
78
+ const bytes = new Uint8Array(mem.buffer, bufPtr, bufLen);
79
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
80
+ crypto.getRandomValues(bytes);
81
+ } else {
82
+ for (let i = 0; i < bufLen; i++) {
83
+ bytes[i] = Math.floor(Math.random() * 256);
84
+ }
85
+ }
86
+ return ERRNO_SUCCESS;
87
+ }
88
+ };
89
+ }
90
+
91
+ // node_modules/quickjs-wasi/dist/extensions.js
92
+ var decoder = new TextDecoder();
93
+ function parseVersionString(memory, ptr) {
94
+ const mem = new Uint8Array(memory.buffer);
95
+ let end = ptr;
96
+ while (mem[end] !== 0)
97
+ end++;
98
+ if (end === ptr)
99
+ return {};
100
+ const str = decoder.decode(mem.slice(ptr, end));
101
+ const result = {};
102
+ for (const line of str.split("\n")) {
103
+ const eq = line.indexOf("=");
104
+ if (eq > 0) {
105
+ result[line.slice(0, eq)] = line.slice(eq + 1);
106
+ }
107
+ }
108
+ return result;
109
+ }
110
+ function extractExtensionVersions(ext, memory) {
111
+ const versionsFnName = `qjs_ext_${ext.name.replace(/-/g, "_")}_versions`;
112
+ const versionsFn = ext.instance.exports[versionsFnName];
113
+ if (typeof versionsFn !== "function")
114
+ return void 0;
115
+ const ptr = versionsFn();
116
+ if (ptr === 0)
117
+ return void 0;
118
+ return parseVersionString(memory, ptr);
119
+ }
120
+ function readULEB128(bytes, offset) {
121
+ let result = 0;
122
+ let shift = 0;
123
+ while (offset.value < bytes.length) {
124
+ const byte = bytes[offset.value++];
125
+ result |= (byte & 127) << shift;
126
+ if ((byte & 128) === 0)
127
+ break;
128
+ shift += 7;
129
+ }
130
+ return result;
131
+ }
132
+ function parseDylink(module) {
133
+ const sections = WebAssembly.Module.customSections(module, "dylink.0");
134
+ if (sections.length === 0)
135
+ return null;
136
+ const bytes = new Uint8Array(sections[0]);
137
+ const offset = { value: 0 };
138
+ const info = {
139
+ memorySize: 0,
140
+ memoryAlignment: 0,
141
+ tableSize: 0,
142
+ tableAlignment: 0,
143
+ needed: []
144
+ };
145
+ while (offset.value < bytes.length) {
146
+ const subsectionType = readULEB128(bytes, offset);
147
+ const subsectionSize = readULEB128(bytes, offset);
148
+ const subsectionEnd = offset.value + subsectionSize;
149
+ if (subsectionType === 1) {
150
+ info.memorySize = readULEB128(bytes, offset);
151
+ info.memoryAlignment = readULEB128(bytes, offset);
152
+ info.tableSize = readULEB128(bytes, offset);
153
+ info.tableAlignment = readULEB128(bytes, offset);
154
+ } else if (subsectionType === 2) {
155
+ const count = readULEB128(bytes, offset);
156
+ for (let i = 0; i < count; i++) {
157
+ const len = readULEB128(bytes, offset);
158
+ const name = new TextDecoder().decode(bytes.slice(offset.value, offset.value + len));
159
+ offset.value += len;
160
+ info.needed.push(name);
161
+ }
162
+ }
163
+ offset.value = subsectionEnd;
164
+ }
165
+ return info;
166
+ }
167
+ async function loadExtension(descriptor, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy, allocBase) {
168
+ let module;
169
+ if (descriptor.wasm instanceof WebAssembly.Module) {
170
+ module = descriptor.wasm;
171
+ } else {
172
+ module = await WebAssembly.compile(descriptor.wasm);
173
+ }
174
+ const dylink = parseDylink(module);
175
+ if (!dylink) {
176
+ throw new Error(`Extension "${descriptor.name}" is not a WASM shared library (missing dylink.0 section)`);
177
+ }
178
+ const memory = mainExports.memory;
179
+ const table = mainExports.__indirect_function_table;
180
+ const stackPointer = mainExports.__stack_pointer;
181
+ const mallocFn = mainExports.malloc;
182
+ if (!memory)
183
+ throw new Error("Main module does not export memory");
184
+ if (!table)
185
+ throw new Error("Main module does not export __indirect_function_table");
186
+ if (!mallocFn)
187
+ throw new Error("Main module does not export malloc");
188
+ let memoryBase;
189
+ let tableBase;
190
+ if (allocBase) {
191
+ memoryBase = allocBase.memoryBase;
192
+ tableBase = allocBase.tableBase;
193
+ } else {
194
+ if (dylink.memorySize > 0) {
195
+ memoryBase = mallocFn(dylink.memorySize);
196
+ if (memoryBase === 0) {
197
+ throw new Error(`Failed to allocate ${dylink.memorySize} bytes for extension "${descriptor.name}"`);
198
+ }
199
+ new Uint8Array(memory.buffer, memoryBase, dylink.memorySize).fill(0);
200
+ } else {
201
+ memoryBase = 0;
202
+ }
203
+ }
204
+ if (allocBase) {
205
+ tableBase = allocBase.tableBase;
206
+ if (tableBase + dylink.tableSize > table.length) {
207
+ table.grow(tableBase + dylink.tableSize - table.length);
208
+ }
209
+ } else {
210
+ tableBase = table.length;
211
+ if (dylink.tableSize > 0) {
212
+ table.grow(dylink.tableSize);
213
+ }
214
+ }
215
+ const extImports = WebAssembly.Module.imports(module);
216
+ const importObj = {
217
+ env: {},
218
+ "GOT.mem": {},
219
+ "GOT.func": {}
220
+ };
221
+ const needsWasi = extImports.some((imp) => imp.module === "wasi_snapshot_preview1");
222
+ if (needsWasi) {
223
+ const extWasi = descriptor.wasi && memoryProxy ? descriptor.wasi(memoryProxy) : void 0;
224
+ importObj["wasi_snapshot_preview1"] = {
225
+ ...wasiBuiltins,
226
+ // 1. Built-in defaults (lowest priority)
227
+ ...extWasi,
228
+ // 2. Extension-provided
229
+ ...wasiUserOverrides
230
+ // 3. User overrides (highest priority)
231
+ };
232
+ }
233
+ const extExportNames = new Set(WebAssembly.Module.exports(module).filter((e) => e.kind === "function").map((e) => e.name));
234
+ const unresolvedFuncs = /* @__PURE__ */ new Set();
235
+ for (const imp of extImports) {
236
+ if (imp.module === "env") {
237
+ if (imp.name === "memory" && imp.kind === "memory") {
238
+ importObj.env.memory = memory;
239
+ } else if (imp.name === "__indirect_function_table" && imp.kind === "table") {
240
+ importObj.env.__indirect_function_table = table;
241
+ } else if (imp.name === "__memory_base" && imp.kind === "global") {
242
+ importObj.env.__memory_base = new WebAssembly.Global({ value: "i32", mutable: false }, memoryBase);
243
+ } else if (imp.name === "__table_base" && imp.kind === "global") {
244
+ importObj.env.__table_base = new WebAssembly.Global({ value: "i32", mutable: false }, tableBase);
245
+ } else if (imp.name === "__stack_pointer" && imp.kind === "global") {
246
+ importObj.env.__stack_pointer = stackPointer;
247
+ } else if (imp.kind === "function") {
248
+ const resolved = mainExports[imp.name];
249
+ if (resolved && typeof resolved === "function") {
250
+ importObj.env[imp.name] = resolved;
251
+ } else {
252
+ unresolvedFuncs.add(imp.name);
253
+ importObj.env[imp.name] = () => {
254
+ throw new Error(`Extension "${descriptor.name}" called unresolved symbol: env.${imp.name}`);
255
+ };
256
+ }
257
+ } else if (imp.kind === "global") {
258
+ const resolved = mainExports[imp.name];
259
+ if (resolved instanceof WebAssembly.Global) {
260
+ importObj.env[imp.name] = resolved;
261
+ } else {
262
+ importObj.env[imp.name] = new WebAssembly.Global({ value: "i32", mutable: true }, 0);
263
+ }
264
+ }
265
+ } else if (imp.module === "GOT.mem" && imp.kind === "global") {
266
+ importObj["GOT.mem"][imp.name] = new WebAssembly.Global({ value: "i32", mutable: true }, 0);
267
+ } else if (imp.module === "GOT.func" && imp.kind === "global") {
268
+ const resolved = mainExports[imp.name];
269
+ if (resolved && typeof resolved === "function") {
270
+ const idx = table.length;
271
+ table.grow(1);
272
+ table.set(idx, resolved);
273
+ importObj["GOT.func"][imp.name] = new WebAssembly.Global({ value: "i32", mutable: true }, idx);
274
+ } else {
275
+ importObj["GOT.func"][imp.name] = new WebAssembly.Global({ value: "i32", mutable: true }, 0);
276
+ }
277
+ }
278
+ }
279
+ const selfResolvable = [...unresolvedFuncs].filter((name) => extExportNames.has(name));
280
+ const wrappers = {};
281
+ for (const name of selfResolvable) {
282
+ const wrapper = { target: null };
283
+ wrappers[name] = wrapper;
284
+ importObj.env[name] = (...args) => {
285
+ if (!wrapper.target) {
286
+ throw new Error(`Extension "${descriptor.name}" called unresolved symbol during init: env.${name}`);
287
+ }
288
+ return wrapper.target(...args);
289
+ };
290
+ }
291
+ const instance = await WebAssembly.instantiate(module, importObj);
292
+ const extExports = instance.exports;
293
+ for (const name of selfResolvable) {
294
+ const selfExport = extExports[name];
295
+ if (typeof selfExport === "function") {
296
+ wrappers[name].target = selfExport;
297
+ }
298
+ }
299
+ if (typeof extExports.__wasm_apply_data_relocs === "function") {
300
+ extExports.__wasm_apply_data_relocs();
301
+ }
302
+ if (typeof extExports.__wasm_call_ctors === "function") {
303
+ extExports.__wasm_call_ctors();
304
+ }
305
+ const initFn = descriptor.initFn ?? `qjs_ext_${descriptor.name.replace(/-/g, "_")}_init`;
306
+ const ext = {
307
+ name: descriptor.name,
308
+ module,
309
+ instance,
310
+ dylink,
311
+ memoryBase,
312
+ tableBase,
313
+ initFn
314
+ };
315
+ ext.versions = extractExtensionVersions(ext, memory);
316
+ return ext;
317
+ }
318
+ function initExtension(ext, mainExports) {
319
+ const initFunc = ext.instance.exports[ext.initFn];
320
+ if (typeof initFunc !== "function") {
321
+ throw new Error(`Extension "${ext.name}" does not export init function "${ext.initFn}"`);
322
+ }
323
+ const ctxPtr = mainExports.qjs_get_context_ptr();
324
+ const rtPtr = mainExports.qjs_get_runtime_ptr();
325
+ const result = initFunc(ctxPtr, rtPtr);
326
+ if (result !== 0) {
327
+ throw new Error(`Extension "${ext.name}" init function returned error code ${result}`);
328
+ }
329
+ }
330
+ async function restoreExtensions(descriptors, extensionMeta, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy) {
331
+ const loaded = [];
332
+ for (const meta of extensionMeta) {
333
+ const descriptor = descriptors.find((d) => d.name === meta.name);
334
+ if (!descriptor) {
335
+ throw new Error(`Extension "${meta.name}" required by snapshot but not provided`);
336
+ }
337
+ const ext = await loadExtension(descriptor, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy, {
338
+ memoryBase: meta.memoryBase,
339
+ tableBase: meta.tableBase
340
+ });
341
+ ext.initFn = meta.initFn;
342
+ loaded.push(ext);
343
+ }
344
+ return loaded;
345
+ }
346
+
347
+ // node_modules/quickjs-wasi/dist/version.js
348
+ var VERSION = "3.6.2";
349
+
350
+ // node_modules/quickjs-wasi/dist/index.js
351
+ var __addDisposableResource = function(env, value, async) {
352
+ if (value !== null && value !== void 0) {
353
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
354
+ var dispose, inner;
355
+ if (async) {
356
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
357
+ dispose = value[Symbol.asyncDispose];
358
+ }
359
+ if (dispose === void 0) {
360
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
361
+ dispose = value[Symbol.dispose];
362
+ if (async) inner = dispose;
363
+ }
364
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
365
+ if (inner) dispose = function() {
366
+ try {
367
+ inner.call(this);
368
+ } catch (e) {
369
+ return Promise.reject(e);
370
+ }
371
+ };
372
+ env.stack.push({ value, dispose, async });
373
+ } else if (async) {
374
+ env.stack.push({ async: true });
375
+ }
376
+ return value;
377
+ };
378
+ var __disposeResources = /* @__PURE__ */ (function(SuppressedError2) {
379
+ return function(env) {
380
+ function fail(e) {
381
+ env.error = env.hasError ? new SuppressedError2(e, env.error, "An error was suppressed during disposal.") : e;
382
+ env.hasError = true;
383
+ }
384
+ var r, s = 0;
385
+ function next() {
386
+ while (r = env.stack.pop()) {
387
+ try {
388
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
389
+ if (r.dispose) {
390
+ var result = r.dispose.call(r.value);
391
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
392
+ fail(e);
393
+ return next();
394
+ });
395
+ } else s |= 1;
396
+ } catch (e) {
397
+ fail(e);
398
+ }
399
+ }
400
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
401
+ if (env.hasError) throw env.error;
402
+ }
403
+ return next();
404
+ };
405
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
406
+ var e = new Error(message);
407
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
408
+ });
409
+ var MAX_STACK_SIZE = 512 * 1024;
410
+ var EvalFlags = {
411
+ /** Global script mode (default). */
412
+ TYPE_GLOBAL: 0,
413
+ /**
414
+ * Module mode. `evalCode()` returns a handle to a Promise that resolves
415
+ * to the module's namespace object (its exports), or rejects if module
416
+ * evaluation throws. Use together with `executePendingJobs()` and
417
+ * `resolvePromise()`.
418
+ */
419
+ TYPE_MODULE: 1 << 0,
420
+ /** Force strict mode. */
421
+ STRICT: 1 << 3,
422
+ /** Compile only; do not execute. */
423
+ COMPILE_ONLY: 1 << 5,
424
+ /** Omit stack frames before this eval from Error backtraces. */
425
+ BACKTRACE_BARRIER: 1 << 6,
426
+ /**
427
+ * Allow top-level `await` in global scripts. When used, `evalCode()`
428
+ * returns a handle to a Promise that resolves to the completion value.
429
+ * Use together with `executePendingJobs()` and `resolvePromise()`.
430
+ */
431
+ ASYNC: 1 << 7
432
+ };
433
+ var CompileFlags = {
434
+ /** Strip source code from the bytecode (smaller output, no source in errors). */
435
+ STRIP_SOURCE: 1 << 4,
436
+ /** Strip debug information (line numbers, etc.) from the bytecode. */
437
+ STRIP_DEBUG: 1 << 5
438
+ };
439
+ var Intrinsics = {
440
+ /** `Date` constructor and prototype methods. */
441
+ DATE: 1 << 0,
442
+ /** `eval()` and `Function()` constructor. */
443
+ EVAL: 1 << 1,
444
+ /** `RegExp` constructor, prototype methods, and regex literals. */
445
+ REGEXP: 1 << 2,
446
+ /** `JSON.parse()` and `JSON.stringify()`. */
447
+ JSON: 1 << 3,
448
+ /** `Proxy` and `Reflect`. */
449
+ PROXY: 1 << 4,
450
+ /** `Map`, `Set`, `WeakMap`, `WeakSet`. */
451
+ MAP_SET: 1 << 5,
452
+ /** `ArrayBuffer`, `TypedArray` variants, `DataView`. */
453
+ TYPED_ARRAYS: 1 << 6,
454
+ /** `Promise`, `async`/`await`. */
455
+ PROMISE: 1 << 7,
456
+ /** `BigInt`. Note: BigInt is part of BaseObjects in quickjs-ng and cannot be fully removed. */
457
+ BIG_INT: 1 << 8,
458
+ /** `WeakRef` and `FinalizationRegistry`. */
459
+ WEAK_REF: 1 << 9,
460
+ /** `performance.now()`. */
461
+ PERFORMANCE: 1 << 10,
462
+ /** `DOMException` class. */
463
+ DOM_EXCEPTION: 1 << 11,
464
+ /**
465
+ * `atob()` and `btoa()` global functions. Also pulls in `DOMException` as
466
+ * a dependency (errors thrown by these functions are `DOMException`s).
467
+ */
468
+ ATOB_BTOA: 1 << 12,
469
+ /** All intrinsics enabled (default). */
470
+ ALL: 4294967295
471
+ };
472
+ var SNAPSHOT_MAGIC = 1363825491;
473
+ var SNAPSHOT_VERSION = 2;
474
+ var SNAPSHOT_HEADER_SIZE = 24;
475
+ var QuickJS = class _QuickJS {
476
+ exports;
477
+ module;
478
+ instance;
479
+ encoder = new TextEncoder();
480
+ decoder = new TextDecoder();
481
+ disposed = false;
482
+ /** Registry of host callbacks, keyed by function name */
483
+ hostCallbacks = /* @__PURE__ */ new Map();
484
+ /** Counter for internal-only callbacks (e.g. promise settle handlers) */
485
+ nextInternalId = 1;
486
+ interruptHandler = null;
487
+ unhandledRejectionHandler = null;
488
+ moduleNormalizeHandler = null;
489
+ moduleLoadHandler = null;
490
+ timezoneOffsetHandler = null;
491
+ // Cached singleton handles
492
+ _global = null;
493
+ _versions = null;
494
+ _undefined = null;
495
+ _null = null;
496
+ _true = null;
497
+ _false = null;
498
+ // Handles that must be freed on dispose (e.g. unresolved promise resolve/reject functions)
499
+ _ownedHandles = /* @__PURE__ */ new Set();
500
+ /**
501
+ * The innermost active `withScope()` batch, if any. New non-singleton
502
+ * handles register themselves here so they can be freed together.
503
+ * @internal
504
+ */
505
+ _activeScope = null;
506
+ /** Loaded extensions in deterministic order */
507
+ loadedExtensions = [];
508
+ constructor(module) {
509
+ this.module = module;
510
+ this.instance = null;
511
+ this.exports = null;
512
+ }
513
+ setInstance(instance) {
514
+ this.instance = instance;
515
+ this.exports = instance.exports;
516
+ }
517
+ // ---- Cached property accessors ----
518
+ /**
519
+ * Version information for the runtime and loaded native libraries.
520
+ * Always includes `"quickjs-wasi"` (the npm package version) and
521
+ * `"quickjs"` (the QuickJS engine version). Extensions may contribute
522
+ * additional entries for their native dependencies (e.g. `"ada"`, `"mbedtls"`).
523
+ */
524
+ get versions() {
525
+ this.assertNotDisposed();
526
+ if (!this._versions) {
527
+ const result = {
528
+ "quickjs-wasi": VERSION,
529
+ quickjs: this.readCString(this.exports.qjs_get_quickjs_version())
530
+ };
531
+ for (const ext of this.loadedExtensions) {
532
+ if (ext.versions) {
533
+ Object.assign(result, ext.versions);
534
+ }
535
+ }
536
+ this._versions = result;
537
+ }
538
+ return this._versions;
539
+ }
540
+ /** The global object. Cached; do not dispose. */
541
+ get global() {
542
+ if (!this._global) {
543
+ this._global = new JSValueHandle(this, this.exports.qjs_get_global(), true);
544
+ }
545
+ return this._global;
546
+ }
547
+ /** The undefined value. Cached; do not dispose. */
548
+ get undefined() {
549
+ if (!this._undefined) {
550
+ this._undefined = new JSValueHandle(this, this.exports.qjs_get_undefined(), true);
551
+ }
552
+ return this._undefined;
553
+ }
554
+ /** The null value. Cached; do not dispose. */
555
+ get null() {
556
+ if (!this._null) {
557
+ this._null = new JSValueHandle(this, this.exports.qjs_get_null(), true);
558
+ }
559
+ return this._null;
560
+ }
561
+ /** The true value. Cached; do not dispose. */
562
+ get true() {
563
+ if (!this._true) {
564
+ this._true = new JSValueHandle(this, this.exports.qjs_get_true(), true);
565
+ }
566
+ return this._true;
567
+ }
568
+ /** The false value. Cached; do not dispose. */
569
+ get false() {
570
+ if (!this._false) {
571
+ this._false = new JSValueHandle(this, this.exports.qjs_get_false(), true);
572
+ }
573
+ return this._false;
574
+ }
575
+ /**
576
+ * Create a fresh QuickJS VM instance.
577
+ *
578
+ * @param options - Optional configuration. Can also pass raw WASM bytes
579
+ * directly for backwards compatibility.
580
+ */
581
+ static async create(options) {
582
+ const opts = _QuickJS.normalizeOptions(options);
583
+ const module = await _QuickJS.resolveModule(opts.wasm);
584
+ const vm = new _QuickJS(module);
585
+ const { instance, wasiBuiltins, wasiUserOverrides, memoryProxy } = await _QuickJS.instantiate(module, vm, opts.wasi);
586
+ vm.setInstance(instance);
587
+ vm.exports._initialize();
588
+ const result = opts.intrinsics !== void 0 ? vm.exports.qjs_init2(opts.intrinsics) : vm.exports.qjs_init();
589
+ if (result !== 0) {
590
+ throw new Error("Failed to initialize QuickJS runtime");
591
+ }
592
+ if (opts.extensions) {
593
+ const mainExports = instance.exports;
594
+ for (const desc of opts.extensions) {
595
+ const ext = await loadExtension(desc, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy);
596
+ vm.loadedExtensions.push(ext);
597
+ initExtension(ext, mainExports);
598
+ }
599
+ }
600
+ _QuickJS.applyLimits(vm, opts);
601
+ return vm;
602
+ }
603
+ /**
604
+ * Restore a QuickJS VM from a snapshot.
605
+ *
606
+ * @param snapshot - The snapshot to restore from.
607
+ * @param options - Optional configuration. Can also pass raw WASM bytes
608
+ * directly for backwards compatibility.
609
+ */
610
+ static async restore(snapshot, options) {
611
+ const opts = _QuickJS.normalizeOptions(options);
612
+ const module = await _QuickJS.resolveModule(opts.wasm);
613
+ const vm = new _QuickJS(module);
614
+ const { instance, wasiBuiltins, wasiUserOverrides, memoryProxy } = await _QuickJS.instantiate(module, vm, opts.wasi);
615
+ vm.setInstance(instance);
616
+ const mainExports = instance.exports;
617
+ const exportedMemory = vm.exports.memory;
618
+ const currentPages = exportedMemory.buffer.byteLength / 65536;
619
+ const neededPages = Math.ceil(snapshot.memory.byteLength / 65536);
620
+ if (neededPages > currentPages) {
621
+ exportedMemory.grow(neededPages - currentPages);
622
+ }
623
+ if (snapshot.extensions.length > 0) {
624
+ const descriptors = opts.extensions ?? [];
625
+ vm.loadedExtensions = await restoreExtensions(descriptors, snapshot.extensions, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy);
626
+ }
627
+ const dst = new Uint8Array(exportedMemory.buffer);
628
+ dst.set(snapshot.memory);
629
+ vm.exports.qjs_set_runtime_and_context(snapshot.runtimePtr, snapshot.contextPtr);
630
+ vm.exports.__stack_pointer.value = snapshot.stackPointer;
631
+ _QuickJS.applyLimits(vm, opts);
632
+ return vm;
633
+ }
634
+ // ---- Snapshot serialization ----
635
+ /**
636
+ * Serialize a snapshot to a binary buffer for persistent storage.
637
+ *
638
+ * The format includes a versioned header followed by the raw memory.
639
+ * Apply your own compression (gzip, zstd, etc.) on top for smaller
640
+ * storage. The memory compresses well due to its large zero regions.
641
+ *
642
+ * Format (version 1):
643
+ * ```
644
+ * Offset Size Field
645
+ * 0 4 Magic: "QJSS" (0x514A5353, big-endian)
646
+ * 4 1 Version: 1
647
+ * 5 3 Reserved (zero)
648
+ * 8 4 Memory size in bytes (u32 little-endian)
649
+ * 12 4 Stack pointer (u32 little-endian)
650
+ * 16 4 Runtime pointer (u32 little-endian)
651
+ * 20 4 Context pointer (u32 little-endian)
652
+ * 24 N Memory data (N = memory size from offset 8)
653
+ * ```
654
+ */
655
+ static serializeSnapshot(snapshot) {
656
+ const textEncoder = new TextEncoder();
657
+ let extMetaSize = 4;
658
+ const extEncodedNames = [];
659
+ const extEncodedInitFns = [];
660
+ for (const ext of snapshot.extensions) {
661
+ const nameBytes = textEncoder.encode(ext.name);
662
+ const initFnBytes = textEncoder.encode(ext.initFn);
663
+ extEncodedNames.push(nameBytes);
664
+ extEncodedInitFns.push(initFnBytes);
665
+ extMetaSize += 4 + nameBytes.length + 4 + 4 + 4 + initFnBytes.length;
666
+ }
667
+ const totalSize = SNAPSHOT_HEADER_SIZE + extMetaSize + snapshot.memory.byteLength;
668
+ const buffer = new ArrayBuffer(totalSize);
669
+ const view = new DataView(buffer);
670
+ const bytes = new Uint8Array(buffer);
671
+ view.setUint32(0, SNAPSHOT_MAGIC, false);
672
+ view.setUint8(4, SNAPSHOT_VERSION);
673
+ view.setUint32(8, snapshot.memory.byteLength, true);
674
+ view.setUint32(12, snapshot.stackPointer, true);
675
+ view.setUint32(16, snapshot.runtimePtr, true);
676
+ view.setUint32(20, snapshot.contextPtr, true);
677
+ let offset = SNAPSHOT_HEADER_SIZE;
678
+ view.setUint32(offset, snapshot.extensions.length, true);
679
+ offset += 4;
680
+ for (let i = 0; i < snapshot.extensions.length; i++) {
681
+ const ext = snapshot.extensions[i];
682
+ const nameBytes = extEncodedNames[i];
683
+ const initFnBytes = extEncodedInitFns[i];
684
+ view.setUint32(offset, nameBytes.length, true);
685
+ offset += 4;
686
+ bytes.set(nameBytes, offset);
687
+ offset += nameBytes.length;
688
+ view.setUint32(offset, ext.memoryBase, true);
689
+ offset += 4;
690
+ view.setUint32(offset, ext.tableBase, true);
691
+ offset += 4;
692
+ view.setUint32(offset, initFnBytes.length, true);
693
+ offset += 4;
694
+ bytes.set(initFnBytes, offset);
695
+ offset += initFnBytes.length;
696
+ }
697
+ bytes.set(snapshot.memory, offset);
698
+ return bytes;
699
+ }
700
+ /**
701
+ * Deserialize a snapshot from a binary buffer produced by `serializeSnapshot()`.
702
+ */
703
+ static deserializeSnapshot(data) {
704
+ if (data.length < SNAPSHOT_HEADER_SIZE) {
705
+ throw new Error("Invalid snapshot: too small");
706
+ }
707
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
708
+ const magic = view.getUint32(0, false);
709
+ if (magic !== SNAPSHOT_MAGIC) {
710
+ throw new Error(`Invalid snapshot: bad magic (expected 0x${SNAPSHOT_MAGIC.toString(16)}, got 0x${magic.toString(16)})`);
711
+ }
712
+ const version = view.getUint8(4);
713
+ if (version !== SNAPSHOT_VERSION && version !== 1) {
714
+ throw new Error(`Unsupported snapshot version: ${version} (expected ${SNAPSHOT_VERSION})`);
715
+ }
716
+ const memorySize = view.getUint32(8, true);
717
+ const stackPointer = view.getUint32(12, true);
718
+ const runtimePtr = view.getUint32(16, true);
719
+ const contextPtr = view.getUint32(20, true);
720
+ let extensions = [];
721
+ let memoryOffset = SNAPSHOT_HEADER_SIZE;
722
+ if (version >= 2) {
723
+ const extCount = view.getUint32(24, true);
724
+ let offset = 28;
725
+ const textDecoder = new TextDecoder();
726
+ for (let i = 0; i < extCount; i++) {
727
+ const nameLen = view.getUint32(offset, true);
728
+ offset += 4;
729
+ const name = textDecoder.decode(data.slice(offset, offset + nameLen));
730
+ offset += nameLen;
731
+ const memBase = view.getUint32(offset, true);
732
+ offset += 4;
733
+ const tblBase = view.getUint32(offset, true);
734
+ offset += 4;
735
+ const initFnLen = view.getUint32(offset, true);
736
+ offset += 4;
737
+ const initFn = textDecoder.decode(data.slice(offset, offset + initFnLen));
738
+ offset += initFnLen;
739
+ extensions.push({ name, memoryBase: memBase, tableBase: tblBase, initFn });
740
+ }
741
+ memoryOffset = offset;
742
+ }
743
+ const expectedSize = memoryOffset + memorySize;
744
+ if (data.length < expectedSize) {
745
+ throw new Error(`Invalid snapshot: expected ${expectedSize} bytes, got ${data.length}`);
746
+ }
747
+ const memory = data.slice(memoryOffset, memoryOffset + memorySize);
748
+ return { memory, stackPointer, runtimePtr, contextPtr, extensions };
749
+ }
750
+ // ---- Internal instantiation helpers ----
751
+ static normalizeOptions(options) {
752
+ if (!options) {
753
+ return { wasm: void 0 };
754
+ }
755
+ if (options instanceof WebAssembly.Module)
756
+ return { wasm: options };
757
+ if (typeof options === "object" && ("wasm" in options || "wasi" in options || "memoryLimit" in options || "maxStackSize" in options || "interruptHandler" in options || "onUnhandledRejection" in options || "moduleLoader" in options || "intrinsics" in options || "extensions" in options || "timezoneOffset" in options)) {
758
+ const opts = options;
759
+ if (opts.maxStackSize !== void 0 && (!Number.isInteger(opts.maxStackSize) || opts.maxStackSize < 0 || opts.maxStackSize > MAX_STACK_SIZE)) {
760
+ throw new RangeError(`maxStackSize must be an integer between 0 and ${MAX_STACK_SIZE}`);
761
+ }
762
+ return opts;
763
+ }
764
+ return { wasm: options };
765
+ }
766
+ static applyLimits(vm, opts) {
767
+ if (opts.memoryLimit !== void 0) {
768
+ vm.exports.qjs_set_memory_limit(opts.memoryLimit);
769
+ }
770
+ if (opts.maxStackSize !== void 0) {
771
+ vm.exports.qjs_set_max_stack_size(opts.maxStackSize);
772
+ }
773
+ if (opts.interruptHandler) {
774
+ vm.interruptHandler = opts.interruptHandler;
775
+ vm.exports.qjs_set_interrupt_handler(1);
776
+ }
777
+ if (opts.onUnhandledRejection) {
778
+ vm.unhandledRejectionHandler = opts.onUnhandledRejection;
779
+ vm.exports.qjs_set_promise_rejection_handler(1);
780
+ }
781
+ if (opts.moduleLoader) {
782
+ vm.moduleLoadHandler = opts.moduleLoader.load;
783
+ vm.moduleNormalizeHandler = opts.moduleLoader.normalize ?? null;
784
+ vm.exports.qjs_set_module_loader(1);
785
+ }
786
+ const tz = opts.timezoneOffset;
787
+ if (typeof tz === "function") {
788
+ vm.timezoneOffsetHandler = (timeSecs) => -tz(timeSecs) * 60;
789
+ } else if (typeof tz === "number") {
790
+ const offsetSecs = -tz * 60;
791
+ vm.timezoneOffsetHandler = () => offsetSecs;
792
+ } else {
793
+ vm.timezoneOffsetHandler = (timeSecs) => {
794
+ return -new Date(timeSecs * 1e3).getTimezoneOffset() * 60;
795
+ };
796
+ }
797
+ }
798
+ static async resolveModule(wasmInput) {
799
+ if (wasmInput instanceof WebAssembly.Module) {
800
+ return wasmInput;
801
+ }
802
+ if (wasmInput) {
803
+ return WebAssembly.compile(wasmInput);
804
+ }
805
+ throw new TypeError("QuickJS: `wasm` option is required. Provide WASM bytes or a compiled `WebAssembly.Module`. The binary is shipped at `quickjs-wasi/quickjs.wasm` and can be loaded via your environment's preferred mechanism (e.g. `fetch()`, `node:fs/promises`, or a bundler import like Vite's `?url`).");
806
+ }
807
+ static async instantiate(module, vm, wasiOptions) {
808
+ let memory = null;
809
+ const memoryProxy = new Proxy({}, {
810
+ get(_target, prop) {
811
+ return memory[prop];
812
+ }
813
+ });
814
+ const wasiBuiltins = createWasiShim(() => memory);
815
+ const wasiUserOverrides = wasiOptions ? wasiOptions(memoryProxy) : void 0;
816
+ const wasiShim = { ...wasiBuiltins, ...wasiUserOverrides };
817
+ const hostCall = (namePtr, nameLen, thisPtr, argc, argvPtr) => {
818
+ return vm.handleHostCall(namePtr, nameLen, thisPtr, argc, argvPtr);
819
+ };
820
+ const hostInterrupt = () => {
821
+ return vm.interruptHandler ? vm.interruptHandler() ? 1 : 0 : 0;
822
+ };
823
+ const hostPromiseRejection = (promisePtr, reasonPtr, isHandled) => {
824
+ if (!vm.unhandledRejectionHandler) {
825
+ vm.exports.qjs_free_value(promisePtr);
826
+ vm.exports.qjs_free_value(reasonPtr);
827
+ return;
828
+ }
829
+ const promise = new JSValueHandle(vm, promisePtr);
830
+ const reason = new JSValueHandle(vm, reasonPtr);
831
+ try {
832
+ vm.unhandledRejectionHandler(promise, reason, isHandled !== 0);
833
+ } finally {
834
+ promise.dispose();
835
+ reason.dispose();
836
+ }
837
+ };
838
+ const throwIntoContext = (err) => {
839
+ const errHandle = vm.newError(err instanceof Error ? err : String(err));
840
+ vm.exports.qjs_throw(errHandle.ptr);
841
+ errHandle.dispose();
842
+ };
843
+ const assertSyncString = (value, callbackName) => {
844
+ if (typeof value === "string")
845
+ return value;
846
+ const got = value !== null && typeof value === "object" && typeof value.then === "function" ? "a Promise" : `type ${typeof value}`;
847
+ throw new TypeError(`moduleLoader.${callbackName} must synchronously return a string (got ${got}). Async module loading is not supported. Pre-fetch module sources instead (see the "ES Modules" section of the quickjs-wasi README).`);
848
+ };
849
+ const hostModuleNormalize = (baseNamePtr, namePtr) => {
850
+ if (!vm.moduleNormalizeHandler) {
851
+ const name = vm.readCString(namePtr);
852
+ return vm.writeString(name).ptr;
853
+ }
854
+ const baseName = vm.readCString(baseNamePtr);
855
+ const specifier = vm.readCString(namePtr);
856
+ try {
857
+ const normalized = assertSyncString(vm.moduleNormalizeHandler(baseName, specifier), "normalize");
858
+ return vm.writeString(normalized).ptr;
859
+ } catch (err) {
860
+ throwIntoContext(err);
861
+ return 0;
862
+ }
863
+ };
864
+ const hostModuleLoad = (namePtr, outLenPtr) => {
865
+ if (!vm.moduleLoadHandler)
866
+ return 0;
867
+ const name = vm.readCString(namePtr);
868
+ try {
869
+ const source = assertSyncString(vm.moduleLoadHandler(name), "load");
870
+ const { ptr, len } = vm.writeString(source);
871
+ new Uint32Array(vm.exports.memory.buffer, outLenPtr, 1)[0] = len;
872
+ return ptr;
873
+ } catch (err) {
874
+ throwIntoContext(err);
875
+ return 0;
876
+ }
877
+ };
878
+ const hostGetTimezoneOffset = (hi, lo) => {
879
+ const timeSecs = Number(BigInt(hi) << 32n | BigInt(lo >>> 0));
880
+ return vm.timezoneOffsetHandler ? vm.timezoneOffsetHandler(timeSecs) : 0;
881
+ };
882
+ const instance = await WebAssembly.instantiate(module, {
883
+ env: {
884
+ host_call: hostCall,
885
+ host_interrupt: hostInterrupt,
886
+ host_promise_rejection: hostPromiseRejection,
887
+ host_module_normalize: hostModuleNormalize,
888
+ host_module_load: hostModuleLoad,
889
+ host_get_timezone_offset: hostGetTimezoneOffset
890
+ },
891
+ wasi_snapshot_preview1: wasiShim
892
+ });
893
+ memory = instance.exports.memory;
894
+ return { instance, wasiBuiltins, wasiUserOverrides, memoryProxy };
895
+ }
896
+ /**
897
+ * Called from WASM when a host function is invoked from QuickJS code.
898
+ */
899
+ handleHostCall(namePtr, nameLen, thisPtr, argc, argvPtr) {
900
+ const name = this.decoder.decode(new Uint8Array(this.exports.memory.buffer, namePtr, nameLen));
901
+ const callback = this.hostCallbacks.get(name);
902
+ if (!callback) {
903
+ const errHandle = this.newError(`Host callback "${name}" is not registered: it was unregistered, its ephemeral function handle was disposed, or it was never re-registered after a snapshot restore.`);
904
+ this.exports.qjs_throw(errHandle.ptr);
905
+ errHandle.dispose();
906
+ return 0;
907
+ }
908
+ const thisHandle = new JSValueHandle(this, thisPtr, false, true);
909
+ const args = [];
910
+ if (argc > 0 && argvPtr !== 0) {
911
+ const view = new DataView(this.exports.memory.buffer);
912
+ for (let i = 0; i < argc; i++) {
913
+ const argPtr = view.getUint32(argvPtr + i * 4, true);
914
+ args.push(new JSValueHandle(this, argPtr, false, true));
915
+ }
916
+ }
917
+ try {
918
+ const result = callback.call(thisHandle, ...args);
919
+ return this.exports.qjs_dup_value(result.ptr);
920
+ } catch (err) {
921
+ const errHandle = this.newError(err instanceof Error ? err : String(err));
922
+ this.exports.qjs_throw(errHandle.ptr);
923
+ errHandle.dispose();
924
+ return 0;
925
+ }
926
+ }
927
+ // ---- String helpers ----
928
+ /** Write a JS string into WASM memory, returning the pointer. Caller must free. */
929
+ writeString(str) {
930
+ const encoded = encodeWtf8(str);
931
+ const ptr = this.exports.wasm_malloc(encoded.length + 1);
932
+ if (ptr === 0)
933
+ throw new Error("wasm_malloc failed");
934
+ const mem = new Uint8Array(this.exports.memory.buffer);
935
+ mem.set(encoded, ptr);
936
+ mem[ptr + encoded.length] = 0;
937
+ return { ptr, len: encoded.length };
938
+ }
939
+ /** Read a null-terminated C string from WASM memory */
940
+ readCString(ptr) {
941
+ const mem = new Uint8Array(this.exports.memory.buffer);
942
+ let end = ptr;
943
+ while (mem[end] !== 0)
944
+ end++;
945
+ return this.decoder.decode(mem.slice(ptr, end));
946
+ }
947
+ // ---- Public API ----
948
+ /**
949
+ * Check if a result handle is an exception and throw a JSException if so.
950
+ * Used internally by evalCode and callFunction.
951
+ */
952
+ throwIfException(result) {
953
+ if (this.exports.qjs_is_exception(result.ptr) !== 0) {
954
+ const exc = this.getException();
955
+ result.dispose();
956
+ this._ownedHandles.add(exc);
957
+ throw new JSException(exc);
958
+ }
959
+ return result;
960
+ }
961
+ /**
962
+ * Evaluate JavaScript code and return the result as a handle.
963
+ * If the code throws, a `JSException` (which extends `Error`) is thrown
964
+ * on the host side, matching standard JavaScript semantics.
965
+ *
966
+ * @param code - The JavaScript source code to evaluate.
967
+ * @param filename - Optional filename for error stack traces (default `'<eval>'`).
968
+ * @param flags - Optional bitwise OR of `EvalFlags.*` constants.
969
+ * For example, pass `EvalFlags.ASYNC` to allow top-level `await`; the
970
+ * returned handle will be a Promise that resolves to the completion value.
971
+ * With `EvalFlags.TYPE_MODULE` the returned handle is a Promise that
972
+ * resolves to the module's namespace object (its exports).
973
+ */
974
+ evalCode(code, filename = "<eval>", flags = 0) {
975
+ this.assertNotDisposed();
976
+ const codeStr = this.writeString(code);
977
+ const fnStr = this.writeString(filename);
978
+ const resultPtr = this.exports.qjs_eval(codeStr.ptr, codeStr.len, fnStr.ptr, flags);
979
+ this.exports.wasm_free(codeStr.ptr);
980
+ this.exports.wasm_free(fnStr.ptr);
981
+ return this.throwIfException(new JSValueHandle(this, resultPtr));
982
+ }
983
+ /**
984
+ * Compile JavaScript source code to bytecode without executing it.
985
+ * The returned `Uint8Array` can be stored, transferred, or later executed
986
+ * with `evalBytecode()`.
987
+ *
988
+ * @param code - The JavaScript source code to compile.
989
+ * @param filename - Optional filename for error stack traces (default `'<compile>'`).
990
+ * @param evalFlags - Optional bitwise OR of `EvalFlags.*` constants.
991
+ * Use `EvalFlags.TYPE_MODULE` to compile as a module.
992
+ * @param compileFlags - Optional bitwise OR of `CompileFlags.*` constants.
993
+ * Use `CompileFlags.STRIP_SOURCE` and/or `CompileFlags.STRIP_DEBUG` to
994
+ * reduce bytecode size.
995
+ */
996
+ compile(code, filename = "<compile>", evalFlags = 0, compileFlags = 0) {
997
+ this.assertNotDisposed();
998
+ const codeStr = this.writeString(code);
999
+ const fnStr = this.writeString(filename);
1000
+ const outLenPtr = this.exports.wasm_malloc(4);
1001
+ const bufPtr = this.exports.qjs_compile(codeStr.ptr, codeStr.len, fnStr.ptr, evalFlags, compileFlags, outLenPtr);
1002
+ this.exports.wasm_free(codeStr.ptr);
1003
+ this.exports.wasm_free(fnStr.ptr);
1004
+ if (bufPtr === 0) {
1005
+ this.exports.wasm_free(outLenPtr);
1006
+ const exc = this.getException();
1007
+ throw new Error(`Compilation error: ${exc.toString()}`);
1008
+ }
1009
+ const outLen = new Uint32Array(this.exports.memory.buffer, outLenPtr, 1)[0];
1010
+ this.exports.wasm_free(outLenPtr);
1011
+ const bytecode = new Uint8Array(this.exports.memory.buffer, bufPtr, outLen).slice();
1012
+ this.exports.wasm_free(bufPtr);
1013
+ return bytecode;
1014
+ }
1015
+ /**
1016
+ * Execute previously compiled bytecode (from `compile()`).
1017
+ * Returns the evaluation result as a handle.
1018
+ *
1019
+ * For module bytecode (compiled with `EvalFlags.TYPE_MODULE`), the
1020
+ * returned handle is a Promise that resolves to the module's namespace
1021
+ * object (its exports).
1022
+ *
1023
+ * @param bytecode - The bytecode `Uint8Array` from `compile()`.
1024
+ */
1025
+ evalBytecode(bytecode) {
1026
+ this.assertNotDisposed();
1027
+ const bufPtr = this.exports.wasm_malloc(bytecode.byteLength);
1028
+ new Uint8Array(this.exports.memory.buffer, bufPtr, bytecode.byteLength).set(bytecode);
1029
+ const resultPtr = this.exports.qjs_eval_bytecode(bufPtr, bytecode.byteLength);
1030
+ this.exports.wasm_free(bufPtr);
1031
+ return this.throwIfException(new JSValueHandle(this, resultPtr));
1032
+ }
1033
+ /**
1034
+ * Execute all pending microtask jobs (promise reactions, etc.)
1035
+ * Returns the number of jobs executed.
1036
+ */
1037
+ executePendingJobs() {
1038
+ this.assertNotDisposed();
1039
+ let count = 0;
1040
+ while (this.exports.qjs_is_job_pending()) {
1041
+ const result = this.exports.qjs_execute_pending_job();
1042
+ if (result < 0) {
1043
+ const exc = this.getException();
1044
+ throw new Error(`Job execution error: ${exc.toString()}`);
1045
+ }
1046
+ count++;
1047
+ }
1048
+ return count;
1049
+ }
1050
+ /**
1051
+ * Explicitly trigger garbage collection. QuickJS runs GC automatically,
1052
+ * but this can be useful to reclaim memory at a known point or before
1053
+ * taking a snapshot.
1054
+ */
1055
+ runGC() {
1056
+ this.assertNotDisposed();
1057
+ this.exports.qjs_run_gc();
1058
+ }
1059
+ /**
1060
+ * The GC threshold in bytes. When allocated memory exceeds this value,
1061
+ * garbage collection is triggered automatically. Set to 0 to disable
1062
+ * automatic GC.
1063
+ */
1064
+ get gcThreshold() {
1065
+ this.assertNotDisposed();
1066
+ return this.exports.qjs_get_gc_threshold();
1067
+ }
1068
+ set gcThreshold(threshold) {
1069
+ this.assertNotDisposed();
1070
+ this.exports.qjs_set_gc_threshold(threshold);
1071
+ }
1072
+ /**
1073
+ * Get detailed memory usage statistics from the QuickJS runtime.
1074
+ * Returns counts and sizes for atoms, strings, objects, functions, etc.
1075
+ */
1076
+ getMemoryUsage() {
1077
+ this.assertNotDisposed();
1078
+ const bufPtr = this.exports.wasm_malloc(26 * 8);
1079
+ this.exports.qjs_compute_memory_usage(bufPtr);
1080
+ const view = new BigInt64Array(this.exports.memory.buffer, bufPtr, 26);
1081
+ const result = {
1082
+ mallocSize: Number(view[0]),
1083
+ mallocLimit: Number(view[1]),
1084
+ memoryUsedSize: Number(view[2]),
1085
+ mallocCount: Number(view[3]),
1086
+ memoryUsedCount: Number(view[4]),
1087
+ atomCount: Number(view[5]),
1088
+ atomSize: Number(view[6]),
1089
+ strCount: Number(view[7]),
1090
+ strSize: Number(view[8]),
1091
+ objCount: Number(view[9]),
1092
+ objSize: Number(view[10]),
1093
+ propCount: Number(view[11]),
1094
+ propSize: Number(view[12]),
1095
+ shapeCount: Number(view[13]),
1096
+ shapeSize: Number(view[14]),
1097
+ jsFuncCount: Number(view[15]),
1098
+ jsFuncSize: Number(view[16]),
1099
+ jsFuncCodeSize: Number(view[17]),
1100
+ jsFuncPc2lineCount: Number(view[18]),
1101
+ jsFuncPc2lineSize: Number(view[19]),
1102
+ cFuncCount: Number(view[20]),
1103
+ arrayCount: Number(view[21]),
1104
+ fastArrayCount: Number(view[22]),
1105
+ fastArrayElements: Number(view[23]),
1106
+ binaryObjectCount: Number(view[24]),
1107
+ binaryObjectSize: Number(view[25])
1108
+ };
1109
+ this.exports.wasm_free(bufPtr);
1110
+ return result;
1111
+ }
1112
+ /**
1113
+ * Get the global object. Prefer the cached `vm.global` property.
1114
+ */
1115
+ getGlobal() {
1116
+ this.assertNotDisposed();
1117
+ return new JSValueHandle(this, this.exports.qjs_get_global());
1118
+ }
1119
+ /**
1120
+ * Create a new QuickJS string value.
1121
+ */
1122
+ newString(str) {
1123
+ this.assertNotDisposed();
1124
+ const { ptr, len } = this.writeString(str);
1125
+ const resultPtr = this.exports.qjs_new_string(ptr, len);
1126
+ this.exports.wasm_free(ptr);
1127
+ return new JSValueHandle(this, resultPtr);
1128
+ }
1129
+ /**
1130
+ * Create a new QuickJS number value.
1131
+ */
1132
+ newNumber(num) {
1133
+ this.assertNotDisposed();
1134
+ return new JSValueHandle(this, this.exports.qjs_new_number(num));
1135
+ }
1136
+ /**
1137
+ * Create a new QuickJS BigInt value.
1138
+ */
1139
+ newBigInt(val) {
1140
+ this.assertNotDisposed();
1141
+ const lo = Number(val & 0xffffffffn);
1142
+ const hi = Number(val >> 32n & 0xffffffffn);
1143
+ return new JSValueHandle(this, this.exports.qjs_new_big_int64(lo, hi));
1144
+ }
1145
+ /**
1146
+ * Create a new QuickJS object value.
1147
+ */
1148
+ newObject() {
1149
+ this.assertNotDisposed();
1150
+ return new JSValueHandle(this, this.exports.qjs_new_object());
1151
+ }
1152
+ /**
1153
+ * Create a new QuickJS array value.
1154
+ */
1155
+ newArray() {
1156
+ this.assertNotDisposed();
1157
+ return new JSValueHandle(this, this.exports.qjs_new_array());
1158
+ }
1159
+ /**
1160
+ * Create a global symbol (`Symbol.for(description)`).
1161
+ * Global symbols with the same description are always the same symbol,
1162
+ * even across snapshot/restore.
1163
+ */
1164
+ newSymbolFor(description) {
1165
+ this.assertNotDisposed();
1166
+ const { ptr, len } = this.writeString(description);
1167
+ const result = new JSValueHandle(this, this.exports.qjs_new_symbol(ptr, len, 1));
1168
+ this.exports.wasm_free(ptr);
1169
+ return result;
1170
+ }
1171
+ /**
1172
+ * Create a new QuickJS ArrayBuffer by copying data from a host buffer.
1173
+ */
1174
+ newArrayBuffer(data) {
1175
+ this.assertNotDisposed();
1176
+ const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
1177
+ const ptr = this.exports.wasm_malloc(bytes.length);
1178
+ if (ptr === 0)
1179
+ throw new Error("wasm_malloc failed");
1180
+ new Uint8Array(this.exports.memory.buffer).set(bytes, ptr);
1181
+ const result = new JSValueHandle(this, this.exports.qjs_new_array_buffer(ptr, bytes.length));
1182
+ this.exports.wasm_free(ptr);
1183
+ return result;
1184
+ }
1185
+ /**
1186
+ * Create a new QuickJS Uint8Array by copying data from a host buffer.
1187
+ */
1188
+ newUint8Array(data) {
1189
+ this.assertNotDisposed();
1190
+ const ptr = this.exports.wasm_malloc(data.length);
1191
+ if (ptr === 0)
1192
+ throw new Error("wasm_malloc failed");
1193
+ new Uint8Array(this.exports.memory.buffer).set(data, ptr);
1194
+ const result = new JSValueHandle(this, this.exports.qjs_new_uint8_array(ptr, data.length));
1195
+ this.exports.wasm_free(ptr);
1196
+ return result;
1197
+ }
1198
+ /**
1199
+ * Get undefined. Prefer the cached `vm.undefined` property.
1200
+ */
1201
+ getUndefined() {
1202
+ this.assertNotDisposed();
1203
+ return new JSValueHandle(this, this.exports.qjs_get_undefined());
1204
+ }
1205
+ /**
1206
+ * Get null. Prefer the cached `vm.null` property.
1207
+ */
1208
+ getNull() {
1209
+ this.assertNotDisposed();
1210
+ return new JSValueHandle(this, this.exports.qjs_get_null());
1211
+ }
1212
+ /**
1213
+ * Get true. Prefer the cached `vm.true` property.
1214
+ */
1215
+ getTrue() {
1216
+ this.assertNotDisposed();
1217
+ return new JSValueHandle(this, this.exports.qjs_get_true());
1218
+ }
1219
+ /**
1220
+ * Get false. Prefer the cached `vm.false` property.
1221
+ */
1222
+ getFalse() {
1223
+ this.assertNotDisposed();
1224
+ return new JSValueHandle(this, this.exports.qjs_get_false());
1225
+ }
1226
+ /**
1227
+ * Create a new QuickJS function backed by a host callback.
1228
+ *
1229
+ * When the function is called inside QuickJS, the host callback is invoked
1230
+ * with the `this` value and arguments as JSValueHandles.
1231
+ */
1232
+ newFunction(name, fn) {
1233
+ this.assertNotDisposed();
1234
+ if (this.hostCallbacks.has(name)) {
1235
+ throw new Error(`Host callback with name "${name}" is already registered`);
1236
+ }
1237
+ this.hostCallbacks.set(name, fn);
1238
+ const { ptr: namePtr, len: nameLen } = this.writeString(name);
1239
+ const resultPtr = this.exports.qjs_new_host_function(namePtr, nameLen, 0);
1240
+ this.exports.wasm_free(namePtr);
1241
+ return new JSValueHandle(this, resultPtr);
1242
+ }
1243
+ /**
1244
+ * Run `fn` with a handle scope: every handle created during the call is
1245
+ * disposed when it returns, except those passed to `scope.escape()`.
1246
+ *
1247
+ * This is the bulk alternative to disposing handles individually, for code
1248
+ * that creates many intermediates, such as walking a large value:
1249
+ *
1250
+ * ```ts
1251
+ * const name = vm.withScope((scope) => {
1252
+ * const user = root.getProp('user'); // freed automatically
1253
+ * const profile = user.getProp('profile'); // freed automatically
1254
+ * return scope.escape(profile.getProp('name'));
1255
+ * });
1256
+ * ```
1257
+ *
1258
+ * Scopes nest: `escape()` transfers the handle to the enclosing scope when
1259
+ * there is one, so it is still cleaned up at the outer boundary.
1260
+ *
1261
+ * `fn` must be synchronous. Handles created after an `await` are outside
1262
+ * the scope, because it closes as soon as `fn` returns.
1263
+ *
1264
+ * Host callbacks are safe to trigger inside a scope: the `this`/argument
1265
+ * handles the trampoline passes to a callback wrap C-owned pointers and
1266
+ * are exempt from scope tracking (see `handleHostCall`), so the scope
1267
+ * frees only handles the host actually owns. Handles a callback CREATES
1268
+ * (including `dup()`s of its arguments) are tracked normally.
1269
+ */
1270
+ withScope(fn) {
1271
+ this.assertNotDisposed();
1272
+ const enclosing = this._activeScope;
1273
+ const tracked = /* @__PURE__ */ new Set();
1274
+ this._activeScope = tracked;
1275
+ const scope = {
1276
+ escape: (handle) => {
1277
+ tracked.delete(handle);
1278
+ enclosing?.add(handle);
1279
+ return handle;
1280
+ }
1281
+ };
1282
+ try {
1283
+ return fn(scope);
1284
+ } finally {
1285
+ this._activeScope = enclosing;
1286
+ for (const handle of tracked)
1287
+ handle.dispose();
1288
+ }
1289
+ }
1290
+ /**
1291
+ * Export a handle as a snapshot-portable token.
1292
+ *
1293
+ * A handle's heap box lives in the VM's linear memory, so a
1294
+ * `snapshot()` taken while the handle is alive carries it, and a VM
1295
+ * restored from that snapshot has the identical box at the identical
1296
+ * offset. `importHandle(token)` on the restored VM (or on this VM)
1297
+ * re-materializes an owned handle for the same guest value without
1298
+ * evaluating any guest code.
1299
+ *
1300
+ * Contract:
1301
+ * - the handle must stay undisposed until after `snapshot()`; its
1302
+ * box (and the reference it holds) must be part of the memory image;
1303
+ * - the token is only meaningful to THIS VM and VMs restored from a
1304
+ * snapshot of it taken while the handle was alive;
1305
+ * - `importHandle` duplicates the underlying value (fresh reference,
1306
+ * fresh box), so it can be called any number of times and each
1307
+ * returned handle is independently owned and disposable. The
1308
+ * exported box's own reference is intentionally never released on
1309
+ * restored VMs (one retained reference per VM image, reclaimed
1310
+ * with the VM).
1311
+ *
1312
+ * The intended use is boot-time capture: snapshot a VM after capturing
1313
+ * references to pristine intrinsics but BEFORE evaluating untrusted or
1314
+ * user code, then restore per task and import the captured handles,
1315
+ * guaranteeing the references predate anything user code patched,
1316
+ * without re-running capture code in the restored VM (where user-
1317
+ * patched globals could observe it). See vercel/workflow's host-side
1318
+ * serde for a worked example.
1319
+ */
1320
+ exportHandle(handle) {
1321
+ this.assertNotDisposed();
1322
+ if (handle.vm !== this) {
1323
+ throw new Error("exportHandle: handle belongs to a different VM");
1324
+ }
1325
+ if (handle.disposed) {
1326
+ throw new Error("exportHandle: handle is disposed");
1327
+ }
1328
+ if (handle._isBorrowed) {
1329
+ throw new Error("exportHandle: cannot export a borrowed handle (host-callback this/argument); its box is freed when the callback returns. dup() it and export the duplicate.");
1330
+ }
1331
+ return handle.ptr;
1332
+ }
1333
+ /**
1334
+ * Re-materialize a handle from a token produced by `exportHandle`,
1335
+ * on this VM, or on a VM restored from a snapshot taken while the
1336
+ * exported handle was alive. Returns a NEW owned handle (the
1337
+ * underlying value's refcount is incremented); dispose it like any
1338
+ * other handle. See `exportHandle` for the full contract.
1339
+ */
1340
+ importHandle(token) {
1341
+ this.assertNotDisposed();
1342
+ if (!Number.isInteger(token) || token <= 0 || token >= this.exports.memory.buffer.byteLength) {
1343
+ throw new Error(`importHandle: invalid token ${token}`);
1344
+ }
1345
+ return new JSValueHandle(this, this.exports.qjs_dup_value(token));
1346
+ }
1347
+ /**
1348
+ * Create a QuickJS function backed by a host callback whose registration is
1349
+ * tied to the returned handle: disposing the handle unregisters the
1350
+ * callback.
1351
+ *
1352
+ * Use this for short-lived callbacks (e.g. a visitor passed to
1353
+ * `Map.prototype.forEach`) where the name is an implementation detail.
1354
+ * `newFunction()` keeps its callback registered for the lifetime of the VM
1355
+ * (by design, so that names can be re-registered after a snapshot is
1356
+ * restored), which makes it unsuitable for callbacks created in a loop.
1357
+ *
1358
+ * The guest must not retain the function past disposal: calling it after
1359
+ * the handle is disposed throws, because the callback is gone. Ephemeral
1360
+ * functions do not survive snapshot/restore.
1361
+ */
1362
+ newEphemeralFunction(fn) {
1363
+ this.assertNotDisposed();
1364
+ const name = `__ephemeral:${this.nextInternalId++}`;
1365
+ this.hostCallbacks.set(name, fn);
1366
+ const { ptr: namePtr, len: nameLen } = this.writeString(name);
1367
+ const resultPtr = this.exports.qjs_new_host_function(namePtr, nameLen, 0);
1368
+ this.exports.wasm_free(namePtr);
1369
+ const handle = new JSValueHandle(this, resultPtr);
1370
+ handle._onDispose = () => {
1371
+ this.hostCallbacks.delete(name);
1372
+ };
1373
+ return handle;
1374
+ }
1375
+ /**
1376
+ * Remove a host callback registered with `newFunction()` or
1377
+ * `registerHostCallback()`. Returns true if a callback was removed.
1378
+ *
1379
+ * Any QuickJS function still referencing the name will throw when called,
1380
+ * so only unregister once the guest can no longer reach it.
1381
+ */
1382
+ unregisterHostCallback(name) {
1383
+ return this.hostCallbacks.delete(name);
1384
+ }
1385
+ /**
1386
+ * Create an internal host function that bypasses the duplicate-name check.
1387
+ * Used for ephemeral callbacks (promise settle handlers, resolvePromise, etc.)
1388
+ * that are not intended to survive snapshot/restore.
1389
+ */
1390
+ newInternalFunction(name, fn) {
1391
+ this.hostCallbacks.set(name, fn);
1392
+ const { ptr: namePtr, len: nameLen } = this.writeString(name);
1393
+ const resultPtr = this.exports.qjs_new_host_function(namePtr, nameLen, 0);
1394
+ this.exports.wasm_free(namePtr);
1395
+ return new JSValueHandle(this, resultPtr);
1396
+ }
1397
+ /**
1398
+ * Create a new promise.
1399
+ *
1400
+ * Returns a Deferred with:
1401
+ * - `handle` - the QuickJS promise object
1402
+ * - `settled` - a host Promise that resolves when the QuickJS promise settles
1403
+ * - `resolve(value)` - resolve the promise with a QuickJS value
1404
+ * - `reject(value)` - reject the promise with a QuickJS value
1405
+ */
1406
+ newPromise() {
1407
+ this.assertNotDisposed();
1408
+ const resolveOutPtr = this.exports.wasm_malloc(4);
1409
+ const rejectOutPtr = this.exports.wasm_malloc(4);
1410
+ const promisePtr = this.exports.qjs_new_promise(resolveOutPtr, rejectOutPtr);
1411
+ const view = new DataView(this.exports.memory.buffer);
1412
+ const resolvePtr = view.getUint32(resolveOutPtr, true);
1413
+ const rejectPtr = view.getUint32(rejectOutPtr, true);
1414
+ this.exports.wasm_free(resolveOutPtr);
1415
+ this.exports.wasm_free(rejectOutPtr);
1416
+ const promiseHandle = new JSValueHandle(this, promisePtr);
1417
+ const resolveHandle = new JSValueHandle(this, resolvePtr);
1418
+ const rejectHandle = new JSValueHandle(this, rejectPtr);
1419
+ const vm = this;
1420
+ vm._ownedHandles.add(resolveHandle);
1421
+ vm._ownedHandles.add(rejectHandle);
1422
+ let _settled = null;
1423
+ return {
1424
+ handle: promiseHandle,
1425
+ get settled() {
1426
+ if (!_settled) {
1427
+ let settledResolve;
1428
+ _settled = new Promise((res) => {
1429
+ settledResolve = res;
1430
+ });
1431
+ const settleName = `__settle:${vm.nextInternalId++}`;
1432
+ const onSettleFn = vm.newInternalFunction(settleName, () => {
1433
+ settledResolve();
1434
+ vm.hostCallbacks.delete(settleName);
1435
+ return vm.undefined;
1436
+ });
1437
+ vm.promiseThenRaw(promiseHandle, onSettleFn, onSettleFn).dispose();
1438
+ onSettleFn.dispose();
1439
+ }
1440
+ return _settled;
1441
+ },
1442
+ resolve(value) {
1443
+ vm.callFunctionRaw(resolveHandle, vm.undefined, value).dispose();
1444
+ vm._ownedHandles.delete(resolveHandle);
1445
+ resolveHandle.dispose();
1446
+ },
1447
+ reject(value) {
1448
+ vm.callFunctionRaw(rejectHandle, vm.undefined, value).dispose();
1449
+ vm._ownedHandles.delete(rejectHandle);
1450
+ rejectHandle.dispose();
1451
+ }
1452
+ };
1453
+ }
1454
+ /**
1455
+ * Resolve a promise handle. Returns a host-side Promise that resolves
1456
+ * with the settled value/error of the QuickJS promise.
1457
+ *
1458
+ * If the handle is not a promise, it is treated as an already-fulfilled value.
1459
+ *
1460
+ * The returned host Promise resolves to `{ value: JSValueHandle }` on
1461
+ * fulfillment or `{ error: JSValueHandle }` on rejection.
1462
+ */
1463
+ resolvePromise(promiseHandle) {
1464
+ this.assertNotDisposed();
1465
+ if (!this.exports.qjs_is_promise(promiseHandle.ptr)) {
1466
+ return Promise.resolve({ value: promiseHandle.dup() });
1467
+ }
1468
+ const state = this.exports.qjs_promise_state(promiseHandle.ptr);
1469
+ if (state === 1) {
1470
+ return Promise.resolve({ value: new JSValueHandle(this, this.exports.qjs_promise_result(promiseHandle.ptr)) });
1471
+ } else if (state === 2) {
1472
+ return Promise.resolve({ error: new JSValueHandle(this, this.exports.qjs_promise_result(promiseHandle.ptr)) });
1473
+ }
1474
+ return new Promise((hostResolve) => {
1475
+ const id = this.nextInternalId++;
1476
+ const fulfilledName = `__onFulfilled:${id}`;
1477
+ const rejectedName = `__onRejected:${id}`;
1478
+ const onFulfilled = this.newInternalFunction(fulfilledName, (...args) => {
1479
+ const val = args[0]?.dup() ?? this.undefined;
1480
+ this.hostCallbacks.delete(fulfilledName);
1481
+ this.hostCallbacks.delete(rejectedName);
1482
+ hostResolve({ value: val });
1483
+ return this.undefined;
1484
+ });
1485
+ const onRejected = this.newInternalFunction(rejectedName, (...args) => {
1486
+ const val = args[0]?.dup() ?? this.undefined;
1487
+ this.hostCallbacks.delete(fulfilledName);
1488
+ this.hostCallbacks.delete(rejectedName);
1489
+ hostResolve({ error: val });
1490
+ return this.undefined;
1491
+ });
1492
+ this.promiseThenRaw(promiseHandle, onFulfilled, onRejected).dispose();
1493
+ onFulfilled.dispose();
1494
+ onRejected.dispose();
1495
+ });
1496
+ }
1497
+ /**
1498
+ * Subscribe to a promise without executing guest code, via quickjs-ng's
1499
+ * JS_PromiseThen: no Promise.prototype.then lookup, no Symbol.species.
1500
+ * Returns the chained promise. Handler handles are borrowed (caller
1501
+ * still owns and disposes them).
1502
+ * @internal
1503
+ */
1504
+ promiseThenRaw(promise, onFulfilled, onRejected) {
1505
+ return new JSValueHandle(this, this.exports.qjs_promise_then(promise.ptr, onFulfilled.ptr, onRejected.ptr));
1506
+ }
1507
+ /**
1508
+ * Mark a promise as handled: an eventual (or already-recorded) rejection
1509
+ * will not be reported to `onUnhandledRejection`. Useful when the host
1510
+ * observes a rejection through other means (e.g. `resolvePromise()`) and
1511
+ * wants to suppress the unhandled-rejection callback for it.
1512
+ *
1513
+ * No-op if the handle is not a promise.
1514
+ */
1515
+ markPromiseHandled(promise) {
1516
+ this.assertNotDisposed();
1517
+ this.exports.qjs_promise_mark_as_handled(promise.ptr);
1518
+ }
1519
+ /**
1520
+ * Call a QuickJS function. If the function throws, a `JSException`
1521
+ * is thrown on the host side.
1522
+ */
1523
+ callFunction(func, thisVal, ...args) {
1524
+ return this.throwIfException(this.callFunctionRaw(func, thisVal, ...args));
1525
+ }
1526
+ /**
1527
+ * Invoke a QuickJS constructor with `new`, i.e. `new ctor(...args)`.
1528
+ * If the constructor throws (including when `ctor` is not a constructor),
1529
+ * a `JSException` is thrown on the host side.
1530
+ *
1531
+ * This is the counterpart to `callFunction` for building values inside
1532
+ * the VM from the host, e.g. `new Date(iso)` on a constructor captured
1533
+ * before any user code ran.
1534
+ */
1535
+ construct(ctor, ...args) {
1536
+ this.assertNotDisposed();
1537
+ const argc = args.length;
1538
+ let argvPtr = 0;
1539
+ if (argc > 0) {
1540
+ argvPtr = this.exports.wasm_malloc(argc * 4);
1541
+ const view = new DataView(this.exports.memory.buffer);
1542
+ for (let i = 0; i < argc; i++) {
1543
+ view.setUint32(argvPtr + i * 4, args[i].ptr, true);
1544
+ }
1545
+ }
1546
+ const resultPtr = this.exports.qjs_call_constructor(ctor.ptr, argc, argvPtr);
1547
+ if (argvPtr)
1548
+ this.exports.wasm_free(argvPtr);
1549
+ return this.throwIfException(new JSValueHandle(this, resultPtr));
1550
+ }
1551
+ /**
1552
+ * Internal: call a QuickJS function without throwing on exception.
1553
+ * Used by promise plumbing where exceptions are handled differently.
1554
+ */
1555
+ callFunctionRaw(func, thisVal, ...args) {
1556
+ this.assertNotDisposed();
1557
+ const argc = args.length;
1558
+ let argvPtr = 0;
1559
+ if (argc > 0) {
1560
+ argvPtr = this.exports.wasm_malloc(argc * 4);
1561
+ const view = new DataView(this.exports.memory.buffer);
1562
+ for (let i = 0; i < argc; i++) {
1563
+ view.setUint32(argvPtr + i * 4, args[i].ptr, true);
1564
+ }
1565
+ }
1566
+ const resultPtr = this.exports.qjs_call(func.ptr, thisVal.ptr, argc, argvPtr);
1567
+ if (argvPtr)
1568
+ this.exports.wasm_free(argvPtr);
1569
+ return new JSValueHandle(this, resultPtr);
1570
+ }
1571
+ /**
1572
+ * Set a property on an object. Accepts string or JSValueHandle as key.
1573
+ * JSValueHandle keys support symbols (including `Symbol.for()`).
1574
+ */
1575
+ setProp(obj, key, value) {
1576
+ this.assertNotDisposed();
1577
+ if (typeof key === "string") {
1578
+ const { ptr: namePtr } = this.writeString(key);
1579
+ this.exports.qjs_set_prop_string(obj.ptr, namePtr, value.ptr);
1580
+ this.exports.wasm_free(namePtr);
1581
+ } else {
1582
+ this.exports.qjs_set_prop_value(obj.ptr, key.ptr, value.ptr);
1583
+ }
1584
+ }
1585
+ /**
1586
+ * Define a property on an object with explicit property descriptor flags.
1587
+ * Unlike `setProp`, this allows controlling `writable`, `enumerable`, and
1588
+ * `configurable` attributes, matching `Object.defineProperty()` semantics.
1589
+ * Accepts string or JSValueHandle as key (JSValueHandle keys support symbols).
1590
+ *
1591
+ * All flags default to `false` when not specified.
1592
+ */
1593
+ defineProp(obj, key, value, descriptor) {
1594
+ this.assertNotDisposed();
1595
+ let flags = 0;
1596
+ if (descriptor?.configurable)
1597
+ flags |= 1;
1598
+ if (descriptor?.writable)
1599
+ flags |= 2;
1600
+ if (descriptor?.enumerable)
1601
+ flags |= 4;
1602
+ if (typeof key === "string") {
1603
+ const { ptr: namePtr } = this.writeString(key);
1604
+ this.exports.qjs_define_prop_string(obj.ptr, namePtr, value.ptr, flags);
1605
+ this.exports.wasm_free(namePtr);
1606
+ } else {
1607
+ this.exports.qjs_define_prop_value(obj.ptr, key.ptr, value.ptr, flags);
1608
+ }
1609
+ }
1610
+ /**
1611
+ * Get a property from an object using a JSValueHandle key.
1612
+ * Supports symbol keys (including `Symbol.for()`).
1613
+ */
1614
+ getProp(obj, key) {
1615
+ this.assertNotDisposed();
1616
+ return new JSValueHandle(this, this.exports.qjs_get_prop_value(obj.ptr, key.ptr));
1617
+ }
1618
+ /**
1619
+ * Get the current exception, if any.
1620
+ */
1621
+ getException() {
1622
+ this.assertNotDisposed();
1623
+ return new JSValueHandle(this, this.exports.qjs_get_exception());
1624
+ }
1625
+ /**
1626
+ * Create a new QuickJS Error object.
1627
+ * Accepts a string message or a native Error object.
1628
+ */
1629
+ newError(messageOrError) {
1630
+ this.assertNotDisposed();
1631
+ const errPtr = this.exports.qjs_new_error();
1632
+ const errHandle = new JSValueHandle(this, errPtr);
1633
+ if (typeof messageOrError === "string") {
1634
+ const msgHandle = this.newString(messageOrError);
1635
+ errHandle.setProp("message", msgHandle);
1636
+ msgHandle.dispose();
1637
+ } else {
1638
+ const msgHandle = this.newString(messageOrError.message);
1639
+ errHandle.setProp("message", msgHandle);
1640
+ msgHandle.dispose();
1641
+ if (messageOrError.name) {
1642
+ const nameHandle = this.newString(messageOrError.name);
1643
+ errHandle.setProp("name", nameHandle);
1644
+ nameHandle.dispose();
1645
+ }
1646
+ if (messageOrError.stack) {
1647
+ const stackHandle = this.newString(messageOrError.stack);
1648
+ errHandle.setProp("stack", stackHandle);
1649
+ stackHandle.dispose();
1650
+ }
1651
+ }
1652
+ return errHandle;
1653
+ }
1654
+ /**
1655
+ * Get the typeof a handle as a string.
1656
+ */
1657
+ typeof(handle) {
1658
+ this.assertNotDisposed();
1659
+ const e = this.exports;
1660
+ if (e.qjs_is_undefined(handle.ptr))
1661
+ return "undefined";
1662
+ if (e.qjs_is_null(handle.ptr))
1663
+ return "object";
1664
+ if (e.qjs_is_bool(handle.ptr))
1665
+ return "boolean";
1666
+ if (e.qjs_is_number(handle.ptr))
1667
+ return "number";
1668
+ if (e.qjs_is_big_int(handle.ptr))
1669
+ return "bigint";
1670
+ if (e.qjs_is_string(handle.ptr))
1671
+ return "string";
1672
+ if (e.qjs_is_symbol(handle.ptr))
1673
+ return "symbol";
1674
+ if (e.qjs_is_function(handle.ptr))
1675
+ return "function";
1676
+ if (e.qjs_is_object(handle.ptr))
1677
+ return "object";
1678
+ return "unknown";
1679
+ }
1680
+ /**
1681
+ * Convert a QuickJS handle to a host JavaScript value.
1682
+ * Handles strings, numbers, booleans, null, undefined, bigint, arrays,
1683
+ * errors, functions, and plain objects. Circular references in objects
1684
+ * are returned as `undefined`.
1685
+ */
1686
+ dump(handle) {
1687
+ this.assertNotDisposed();
1688
+ return this._dump(handle, /* @__PURE__ */ new Map());
1689
+ }
1690
+ _dump(handle, visited) {
1691
+ const e = this.exports;
1692
+ if (e.qjs_is_undefined(handle.ptr))
1693
+ return void 0;
1694
+ if (e.qjs_is_null(handle.ptr))
1695
+ return null;
1696
+ if (e.qjs_is_bool(handle.ptr))
1697
+ return e.qjs_get_bool(handle.ptr) !== 0;
1698
+ if (e.qjs_is_number(handle.ptr))
1699
+ return e.qjs_get_float64(handle.ptr);
1700
+ if (e.qjs_is_string(handle.ptr))
1701
+ return handle.toString();
1702
+ if (e.qjs_is_big_int(handle.ptr))
1703
+ return handle.toBigInt();
1704
+ if (e.qjs_is_symbol(handle.ptr)) {
1705
+ const descOutPtr = e.wasm_malloc(4);
1706
+ const kind = e.qjs_get_symbol_description(handle.ptr, descOutPtr);
1707
+ const view = new DataView(e.memory.buffer);
1708
+ const descPtr = view.getUint32(descOutPtr, true);
1709
+ e.wasm_free(descOutPtr);
1710
+ if (kind === 1) {
1711
+ const descHandle = new JSValueHandle(this, descPtr);
1712
+ const description = descHandle.toString();
1713
+ descHandle.dispose();
1714
+ return Symbol.for(description);
1715
+ } else if (kind === 2) {
1716
+ const descHandle = new JSValueHandle(this, descPtr);
1717
+ descHandle.dispose();
1718
+ return void 0;
1719
+ }
1720
+ return void 0;
1721
+ }
1722
+ if (e.qjs_is_array_buffer(handle.ptr))
1723
+ return handle.toArrayBuffer();
1724
+ if (e.qjs_is_exception(handle.ptr)) {
1725
+ const exc = this.getException();
1726
+ const msg = exc.toString();
1727
+ exc.dispose();
1728
+ return new Error(msg);
1729
+ }
1730
+ if (e.qjs_is_function(handle.ptr))
1731
+ return void 0;
1732
+ if (e.qjs_is_object(handle.ptr)) {
1733
+ const objPtr = e.qjs_get_value_ptr(handle.ptr);
1734
+ if (objPtr) {
1735
+ const existing = visited.get(objPtr);
1736
+ if (existing !== void 0)
1737
+ return existing;
1738
+ }
1739
+ }
1740
+ if (e.qjs_is_object(handle.ptr)) {
1741
+ const byteOffsetPtr = e.wasm_malloc(4);
1742
+ const byteLengthPtr = e.wasm_malloc(4);
1743
+ const bytesPerElemPtr = e.wasm_malloc(4);
1744
+ const abPtr = e.qjs_get_typed_array_buffer(handle.ptr, byteOffsetPtr, byteLengthPtr, bytesPerElemPtr);
1745
+ const abHandle = new JSValueHandle(this, abPtr);
1746
+ if (e.qjs_is_exception(abHandle.ptr) === 0) {
1747
+ const view = new DataView(e.memory.buffer);
1748
+ const byteOffset = view.getUint32(byteOffsetPtr, true);
1749
+ const byteLength = view.getUint32(byteLengthPtr, true);
1750
+ const bytesPerElement = view.getUint32(bytesPerElemPtr, true);
1751
+ e.wasm_free(byteOffsetPtr);
1752
+ e.wasm_free(byteLengthPtr);
1753
+ e.wasm_free(bytesPerElemPtr);
1754
+ const abLenPtr = e.wasm_malloc(4);
1755
+ const abDataPtr = e.qjs_get_array_buffer(abHandle.ptr, abLenPtr);
1756
+ e.wasm_free(abLenPtr);
1757
+ abHandle.dispose();
1758
+ if (abDataPtr !== 0) {
1759
+ const rawBytes = new Uint8Array(e.memory.buffer, abDataPtr + byteOffset, byteLength).slice();
1760
+ switch (bytesPerElement) {
1761
+ case 1:
1762
+ return rawBytes;
1763
+ case 2:
1764
+ return new Uint16Array(rawBytes.buffer);
1765
+ case 4:
1766
+ return new Uint32Array(rawBytes.buffer);
1767
+ case 8:
1768
+ return new Float64Array(rawBytes.buffer);
1769
+ default:
1770
+ return rawBytes;
1771
+ }
1772
+ }
1773
+ } else {
1774
+ abHandle.dispose();
1775
+ e.wasm_free(byteOffsetPtr);
1776
+ e.wasm_free(byteLengthPtr);
1777
+ e.wasm_free(bytesPerElemPtr);
1778
+ }
1779
+ }
1780
+ if (e.qjs_is_array(handle.ptr)) {
1781
+ const lenHandle = handle.getProp("length");
1782
+ const len = e.qjs_get_float64(lenHandle.ptr);
1783
+ lenHandle.dispose();
1784
+ const arr = [];
1785
+ const objPtr = e.qjs_get_value_ptr(handle.ptr);
1786
+ if (objPtr)
1787
+ visited.set(objPtr, arr);
1788
+ for (let i = 0; i < len; i++) {
1789
+ const elemPtr = e.qjs_get_prop_uint32(handle.ptr, i);
1790
+ const elemHandle = new JSValueHandle(this, elemPtr);
1791
+ arr.push(this._dump(elemHandle, visited));
1792
+ elemHandle.dispose();
1793
+ }
1794
+ return arr;
1795
+ }
1796
+ if (e.qjs_is_error(handle.ptr)) {
1797
+ const nameHandle = handle.getProp("name");
1798
+ const msgHandle = handle.getProp("message");
1799
+ const stackHandle = handle.getProp("stack");
1800
+ const name = nameHandle.isUndefined ? "Error" : nameHandle.toString();
1801
+ const message = msgHandle.isUndefined ? "" : msgHandle.toString();
1802
+ const stack = stackHandle.isUndefined ? void 0 : stackHandle.toString();
1803
+ nameHandle.dispose();
1804
+ msgHandle.dispose();
1805
+ stackHandle.dispose();
1806
+ const err = new Error(message);
1807
+ err.name = name;
1808
+ if (stack !== void 0) {
1809
+ err.stack = stack;
1810
+ }
1811
+ return err;
1812
+ }
1813
+ if (e.qjs_is_object(handle.ptr)) {
1814
+ const keysPtr = e.qjs_get_own_property_names(handle.ptr);
1815
+ const keysHandle = new JSValueHandle(this, keysPtr);
1816
+ if (e.qjs_is_exception(keysHandle.ptr) !== 0) {
1817
+ keysHandle.dispose();
1818
+ return {};
1819
+ }
1820
+ const lenHandle = keysHandle.getProp("length");
1821
+ const len = e.qjs_get_float64(lenHandle.ptr);
1822
+ lenHandle.dispose();
1823
+ const obj = {};
1824
+ const objPtr = e.qjs_get_value_ptr(handle.ptr);
1825
+ if (objPtr)
1826
+ visited.set(objPtr, obj);
1827
+ for (let i = 0; i < len; i++) {
1828
+ const keyPtr = e.qjs_get_prop_uint32(keysHandle.ptr, i);
1829
+ const keyHandle = new JSValueHandle(this, keyPtr);
1830
+ const key = keyHandle.toString();
1831
+ keyHandle.dispose();
1832
+ const valHandle = handle.getProp(key);
1833
+ obj[key] = this._dump(valHandle, visited);
1834
+ valHandle.dispose();
1835
+ }
1836
+ keysHandle.dispose();
1837
+ return obj;
1838
+ }
1839
+ return void 0;
1840
+ }
1841
+ /**
1842
+ * Convert a host JavaScript value to a QuickJS handle.
1843
+ */
1844
+ hostToHandle(value) {
1845
+ this.assertNotDisposed();
1846
+ if (value === void 0)
1847
+ return this.undefined;
1848
+ if (value === null)
1849
+ return this.null;
1850
+ if (value === true)
1851
+ return this.true;
1852
+ if (value === false)
1853
+ return this.false;
1854
+ if (typeof value === "number")
1855
+ return this.newNumber(value);
1856
+ if (typeof value === "string")
1857
+ return this.newString(value);
1858
+ if (typeof value === "bigint")
1859
+ return this.newBigInt(value);
1860
+ if (typeof value === "symbol") {
1861
+ const key = Symbol.keyFor(value);
1862
+ if (key !== void 0) {
1863
+ return this.newSymbolFor(key);
1864
+ }
1865
+ throw new Error(`Cannot convert local symbol to QuickJS handle. Use Symbol.for() for cross-boundary symbols.`);
1866
+ }
1867
+ if (value instanceof Promise) {
1868
+ const deferred = this.newPromise();
1869
+ value.then((r) => {
1870
+ deferred.resolve(this.hostToHandle(r));
1871
+ this.executePendingJobs();
1872
+ }, (err) => {
1873
+ deferred.reject(this.hostToHandle(err));
1874
+ this.executePendingJobs();
1875
+ });
1876
+ return deferred.handle;
1877
+ }
1878
+ if (value instanceof Error) {
1879
+ return this.newError(value);
1880
+ }
1881
+ if (value instanceof ArrayBuffer) {
1882
+ return this.newArrayBuffer(value);
1883
+ }
1884
+ if (value instanceof Uint8Array) {
1885
+ return this.newUint8Array(value);
1886
+ }
1887
+ if (ArrayBuffer.isView(value)) {
1888
+ return this.newArrayBuffer(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
1889
+ }
1890
+ if (Array.isArray(value)) {
1891
+ const arr = this.newArray();
1892
+ for (let i = 0; i < value.length; i++) {
1893
+ const elemHandle = this.hostToHandle(value[i]);
1894
+ this.exports.qjs_set_prop_uint32(arr.ptr, i, elemHandle.ptr);
1895
+ elemHandle.dispose();
1896
+ }
1897
+ return arr;
1898
+ }
1899
+ if (typeof value === "object" && value !== null) {
1900
+ const obj = this.newObject();
1901
+ for (const [key, val] of Object.entries(value)) {
1902
+ const valHandle = this.hostToHandle(val);
1903
+ obj.setProp(key, valHandle);
1904
+ valHandle.dispose();
1905
+ }
1906
+ return obj;
1907
+ }
1908
+ return this.undefined;
1909
+ }
1910
+ // ---- Snapshot / Restore ----
1911
+ /**
1912
+ * Snapshot the entire VM state.
1913
+ *
1914
+ * Returns a snapshot containing the full WASM linear memory. Use
1915
+ * `QuickJS.serializeSnapshot()` to convert to a versioned binary
1916
+ * buffer for persistent storage.
1917
+ */
1918
+ snapshot() {
1919
+ this.assertNotDisposed();
1920
+ return {
1921
+ memory: new Uint8Array(this.exports.memory.buffer).slice(),
1922
+ stackPointer: this.exports.__stack_pointer.value,
1923
+ runtimePtr: this.exports.qjs_get_runtime_ptr(),
1924
+ contextPtr: this.exports.qjs_get_context_ptr(),
1925
+ extensions: this.loadedExtensions.map((ext) => ({
1926
+ name: ext.name,
1927
+ memoryBase: ext.memoryBase,
1928
+ tableBase: ext.tableBase,
1929
+ initFn: ext.initFn
1930
+ }))
1931
+ };
1932
+ }
1933
+ /**
1934
+ * Re-register a host callback after restoring from a snapshot.
1935
+ * The name must match the name passed to `newFunction()` before the snapshot.
1936
+ */
1937
+ registerHostCallback(name, fn) {
1938
+ this.hostCallbacks.set(name, fn);
1939
+ }
1940
+ /**
1941
+ * Dispose the VM, releasing all references to the WASM instance
1942
+ * so it can be garbage collected by the host JS engine.
1943
+ */
1944
+ dispose() {
1945
+ if (!this.disposed) {
1946
+ this.disposed = true;
1947
+ this._global = null;
1948
+ this._undefined = null;
1949
+ this._null = null;
1950
+ this._true = null;
1951
+ this._false = null;
1952
+ this._ownedHandles.clear();
1953
+ this.hostCallbacks.clear();
1954
+ this._activeScope = null;
1955
+ this.exports = null;
1956
+ this.instance = null;
1957
+ this.module = null;
1958
+ }
1959
+ }
1960
+ /**
1961
+ * Support for `using` declarations (Explicit Resource Management).
1962
+ * Automatically disposes the VM when it goes out of scope.
1963
+ *
1964
+ * ```typescript
1965
+ * using vm = await QuickJS.create(wasmBytes);
1966
+ * vm.evalCode('1 + 2');
1967
+ * // vm is automatically disposed here
1968
+ * ```
1969
+ */
1970
+ [Symbol.dispose]() {
1971
+ this.dispose();
1972
+ }
1973
+ assertNotDisposed() {
1974
+ if (this.disposed) {
1975
+ throw new Error("QuickJS instance has been disposed");
1976
+ }
1977
+ }
1978
+ // ---- Internal accessors for JSValueHandle ----
1979
+ /** @internal */
1980
+ _getExports() {
1981
+ return this.exports;
1982
+ }
1983
+ /** @internal */
1984
+ _getMemory() {
1985
+ return this.exports.memory;
1986
+ }
1987
+ /** @internal */
1988
+ _writeString(str) {
1989
+ return this.writeString(str);
1990
+ }
1991
+ /** @internal */
1992
+ _readCString(ptr) {
1993
+ return this.readCString(ptr);
1994
+ }
1995
+ };
1996
+ function stringKeyNeedsValuePath(key) {
1997
+ return key.includes("\0") || LONE_SURROGATE_RE.test(key);
1998
+ }
1999
+ var wtf8Decoder = new TextDecoder();
2000
+ var wtf8Encoder = new TextEncoder();
2001
+ var LONE_SURROGATE_RE = /(?:[\uD800-\uDBFF](?![\uDC00-\uDFFF]))|(?:(?<![\uD800-\uDBFF])[\uDC00-\uDFFF])/;
2002
+ function encodeWtf8(str) {
2003
+ if (!LONE_SURROGATE_RE.test(str))
2004
+ return wtf8Encoder.encode(str);
2005
+ const bytes = [];
2006
+ for (let i = 0; i < str.length; i++) {
2007
+ const code = str.charCodeAt(i);
2008
+ if (code < 128) {
2009
+ bytes.push(code);
2010
+ } else if (code < 2048) {
2011
+ bytes.push(192 | code >> 6, 128 | code & 63);
2012
+ } else if (code >= 55296 && code <= 56319 && i + 1 < str.length) {
2013
+ const next = str.charCodeAt(i + 1);
2014
+ if (next >= 56320 && next <= 57343) {
2015
+ const cp = 65536 + (code - 55296 << 10) + (next - 56320);
2016
+ bytes.push(240 | cp >> 18, 128 | cp >> 12 & 63, 128 | cp >> 6 & 63, 128 | cp & 63);
2017
+ i++;
2018
+ continue;
2019
+ }
2020
+ bytes.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
2021
+ } else {
2022
+ bytes.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
2023
+ }
2024
+ }
2025
+ return new Uint8Array(bytes);
2026
+ }
2027
+ function decodeWtf8(bytes) {
2028
+ let hasSurrogateSequence = false;
2029
+ for (let i2 = 0; i2 < bytes.length - 1; i2++) {
2030
+ if (bytes[i2] === 237 && bytes[i2 + 1] >= 160 && bytes[i2 + 1] <= 191) {
2031
+ hasSurrogateSequence = true;
2032
+ break;
2033
+ }
2034
+ }
2035
+ if (!hasSurrogateSequence)
2036
+ return wtf8Decoder.decode(bytes);
2037
+ let out = "";
2038
+ let i = 0;
2039
+ while (i < bytes.length) {
2040
+ const b0 = bytes[i];
2041
+ if (b0 < 128) {
2042
+ out += String.fromCharCode(b0);
2043
+ i += 1;
2044
+ } else if (b0 < 224) {
2045
+ out += String.fromCharCode((b0 & 31) << 6 | bytes[i + 1] & 63);
2046
+ i += 2;
2047
+ } else if (b0 < 240) {
2048
+ out += String.fromCharCode((b0 & 15) << 12 | (bytes[i + 1] & 63) << 6 | bytes[i + 2] & 63);
2049
+ i += 3;
2050
+ } else {
2051
+ const cp = (b0 & 7) << 18 | (bytes[i + 1] & 63) << 12 | (bytes[i + 2] & 63) << 6 | bytes[i + 3] & 63;
2052
+ out += String.fromCodePoint(cp);
2053
+ i += 4;
2054
+ }
2055
+ }
2056
+ return out;
2057
+ }
2058
+ var JSException = class extends Error {
2059
+ /**
2060
+ * A live handle to the QuickJS exception value. You can read custom
2061
+ * properties, call methods, etc. Must be disposed when done.
2062
+ */
2063
+ handle;
2064
+ // Cached values so they survive handle disposal / VM teardown.
2065
+ // Using # fields keeps them out of console.log / Object.keys output.
2066
+ #name;
2067
+ #message;
2068
+ #stack;
2069
+ /** @internal */
2070
+ constructor(handle) {
2071
+ const env_1 = { stack: [], error: void 0, hasError: false };
2072
+ try {
2073
+ super();
2074
+ this.handle = handle;
2075
+ delete this.stack;
2076
+ const msgHandle = __addDisposableResource(env_1, handle.getProp("message"), false);
2077
+ this.#name = handle.getProp("name").consume((h) => h.isUndefined ? "Error" : h.toString());
2078
+ this.#message = msgHandle.isUndefined ? handle.toString() : msgHandle.toString();
2079
+ this.#stack = handle.getProp("stack").consume((h) => h.isUndefined ? void 0 : h.toString());
2080
+ } catch (e_1) {
2081
+ env_1.error = e_1;
2082
+ env_1.hasError = true;
2083
+ } finally {
2084
+ __disposeResources(env_1);
2085
+ }
2086
+ }
2087
+ get name() {
2088
+ return this.#name;
2089
+ }
2090
+ set name(v) {
2091
+ this.#name = v;
2092
+ }
2093
+ get message() {
2094
+ return this.#message;
2095
+ }
2096
+ set message(v) {
2097
+ this.#message = v;
2098
+ }
2099
+ get stack() {
2100
+ return this.#stack;
2101
+ }
2102
+ set stack(v) {
2103
+ this.#stack = v;
2104
+ }
2105
+ dispose() {
2106
+ this.handle.dispose();
2107
+ }
2108
+ [Symbol.dispose]() {
2109
+ this.handle.dispose();
2110
+ }
2111
+ };
2112
+ var JSValueHandle = class _JSValueHandle {
2113
+ /** The QuickJS VM instance this handle belongs to. */
2114
+ vm;
2115
+ /** @internal */
2116
+ ptr;
2117
+ disposed_ = false;
2118
+ /**
2119
+ * When true, this handle is a cached singleton (e.g. `undefined`, `null`,
2120
+ * `true`, `false`, the global object) and `dispose()` is a no-op. This
2121
+ * prevents code that routinely disposes handles (such as the object/array
2122
+ * branches of `hostToHandle`) from freeing the shared heap `JSValue*` that
2123
+ * the cached singleton still references, which would corrupt later reads.
2124
+ * @internal
2125
+ */
2126
+ singleton;
2127
+ /**
2128
+ * When true, this handle wraps a `JSValue*` OWNED BY THE C CALLER: the
2129
+ * `this`/argument handles the host-call trampoline passes to a host
2130
+ * callback (`handleHostCall`). The C side frees those values after the
2131
+ * call returns, so `dispose()` is a no-op and the handle is never
2132
+ * registered with an active `withScope()` (either would double-free
2133
+ * the guest value and corrupt the heap). A callback that needs to
2134
+ * retain an argument past its own invocation must `dup()` it; the
2135
+ * duplicate takes a fresh reference and behaves like any owned handle.
2136
+ * @internal
2137
+ */
2138
+ borrowed;
2139
+ /**
2140
+ * Extra cleanup to run when this handle is disposed. Used by
2141
+ * `newEphemeralFunction()` to unregister its host callback.
2142
+ * @internal
2143
+ */
2144
+ _onDispose;
2145
+ constructor(vm, ptr, singleton = false, borrowed = false) {
2146
+ this.vm = vm;
2147
+ this.ptr = ptr;
2148
+ this.singleton = singleton;
2149
+ this.borrowed = borrowed;
2150
+ if (!singleton && !borrowed)
2151
+ vm._activeScope?.add(this);
2152
+ }
2153
+ /**
2154
+ * Whether this handle wraps a C-owned pointer (host-callback
2155
+ * `this`/arguments). Borrowed handles must never be exported as
2156
+ * snapshot tokens: the trampoline frees their boxes after the
2157
+ * callback returns. @internal
2158
+ */
2159
+ get _isBorrowed() {
2160
+ return this.borrowed;
2161
+ }
2162
+ /**
2163
+ * Whether `dispose()` has been called on this handle.
2164
+ *
2165
+ * Note that handle methods do not currently guard against use after
2166
+ * disposal: reading from a disposed handle reads freed memory. Check this
2167
+ * when a handle's lifetime is managed elsewhere (e.g. by `withScope()`).
2168
+ */
2169
+ get disposed() {
2170
+ return this.disposed_;
2171
+ }
2172
+ get isUndefined() {
2173
+ return this.vm._getExports().qjs_is_undefined(this.ptr) !== 0;
2174
+ }
2175
+ get isNull() {
2176
+ return this.vm._getExports().qjs_is_null(this.ptr) !== 0;
2177
+ }
2178
+ /**
2179
+ * Get the promise state: 0 = pending, 1 = fulfilled, 2 = rejected
2180
+ */
2181
+ get isBool() {
2182
+ return this.vm._getExports().qjs_is_bool(this.ptr) !== 0;
2183
+ }
2184
+ get isNumber() {
2185
+ return this.vm._getExports().qjs_is_number(this.ptr) !== 0;
2186
+ }
2187
+ get isString() {
2188
+ return this.vm._getExports().qjs_is_string(this.ptr) !== 0;
2189
+ }
2190
+ get isSymbol() {
2191
+ return this.vm._getExports().qjs_is_symbol(this.ptr) !== 0;
2192
+ }
2193
+ get isBigInt() {
2194
+ return this.vm._getExports().qjs_is_big_int(this.ptr) !== 0;
2195
+ }
2196
+ get isObject() {
2197
+ return this.vm._getExports().qjs_is_object(this.ptr) !== 0;
2198
+ }
2199
+ get isArray() {
2200
+ return this.vm._getExports().qjs_is_array(this.ptr) !== 0;
2201
+ }
2202
+ get isFunction() {
2203
+ return this.vm._getExports().qjs_is_function(this.ptr) !== 0;
2204
+ }
2205
+ get isError() {
2206
+ return this.vm._getExports().qjs_is_error(this.ptr) !== 0;
2207
+ }
2208
+ get isPromise() {
2209
+ return this.vm._getExports().qjs_is_promise(this.ptr) !== 0;
2210
+ }
2211
+ get isArrayBuffer() {
2212
+ return this.vm._getExports().qjs_is_array_buffer(this.ptr) !== 0;
2213
+ }
2214
+ /**
2215
+ * Whether this value is a Proxy exotic object.
2216
+ *
2217
+ * This is an engine-level check: it never fires proxy traps and cannot
2218
+ * be determined (or spoofed) from within guest JavaScript. Use
2219
+ * {@link getProxyTarget} / {@link getProxyHandler} to introspect a
2220
+ * detected proxy without executing guest code.
2221
+ */
2222
+ get isProxy() {
2223
+ return this.vm._getExports().qjs_is_proxy(this.ptr) !== 0;
2224
+ }
2225
+ /**
2226
+ * Whether this value is a Map (engine brand check: trap-free,
2227
+ * spoof-proof, and unaffected by prototype/constructor mutation).
2228
+ * A Proxy wrapping a Map returns false.
2229
+ */
2230
+ get isMap() {
2231
+ return this.vm._getExports().qjs_is_map(this.ptr) !== 0;
2232
+ }
2233
+ /**
2234
+ * Whether this value is a Set (engine brand check: trap-free,
2235
+ * spoof-proof, and unaffected by prototype/constructor mutation).
2236
+ * A Proxy wrapping a Set returns false.
2237
+ */
2238
+ get isSet() {
2239
+ return this.vm._getExports().qjs_is_set(this.ptr) !== 0;
2240
+ }
2241
+ /**
2242
+ * Whether this value is a Date (engine brand check: trap-free,
2243
+ * spoof-proof, and unaffected by prototype/constructor mutation).
2244
+ * A Proxy wrapping a Date returns false.
2245
+ */
2246
+ get isDate() {
2247
+ return this.vm._getExports().qjs_is_date(this.ptr) !== 0;
2248
+ }
2249
+ /**
2250
+ * Whether this value is a RegExp (engine brand check: trap-free,
2251
+ * spoof-proof, and unaffected by prototype/constructor mutation).
2252
+ * A Proxy wrapping a RegExp returns false.
2253
+ */
2254
+ get isRegExp() {
2255
+ return this.vm._getExports().qjs_is_regexp(this.ptr) !== 0;
2256
+ }
2257
+ /** Whether this value is a WeakRef (engine brand check). */
2258
+ get isWeakRef() {
2259
+ return this.vm._getExports().qjs_is_weak_ref(this.ptr) !== 0;
2260
+ }
2261
+ /** Whether this value is a WeakMap (engine brand check). */
2262
+ get isWeakMap() {
2263
+ return this.vm._getExports().qjs_is_weak_map(this.ptr) !== 0;
2264
+ }
2265
+ /** Whether this value is a WeakSet (engine brand check). */
2266
+ get isWeakSet() {
2267
+ return this.vm._getExports().qjs_is_weak_set(this.ptr) !== 0;
2268
+ }
2269
+ /** Whether this value is a DataView (engine brand check). */
2270
+ get isDataView() {
2271
+ return this.vm._getExports().qjs_is_data_view(this.ptr) !== 0;
2272
+ }
2273
+ /**
2274
+ * A numeric identity for the underlying heap value, or 0 for values that
2275
+ * are not heap-allocated (numbers, booleans, `null`, `undefined`).
2276
+ *
2277
+ * Two handles to the same underlying object always report the same
2278
+ * identity, and two live handles to different objects always report
2279
+ * different identities, so this is the value to key a `Map` on when
2280
+ * deduplicating or detecting cycles across handles (`dump()` uses it for
2281
+ * exactly that).
2282
+ *
2283
+ * The identity is only meaningful while the value is alive; it is an
2284
+ * address, so it may be reused after every handle to the value has been
2285
+ * disposed. Do not persist it, and do not treat it as unforgeable: a
2286
+ * number read out of the guest can trivially collide with one.
2287
+ */
2288
+ get identity() {
2289
+ return this.vm._getExports().qjs_get_value_ptr(this.ptr);
2290
+ }
2291
+ /**
2292
+ * Extract the value as a boolean, applying JavaScript truthiness
2293
+ * (equivalent to `!!value` inside the VM).
2294
+ */
2295
+ toBoolean() {
2296
+ return this.vm._getExports().qjs_get_bool(this.ptr) !== 0;
2297
+ }
2298
+ /**
2299
+ * The internal QuickJS class ID of this value, or 0 for non-objects.
2300
+ * Useful as a generic engine-level brand when no dedicated `is*`
2301
+ * getter exists. Class IDs are stable within a VM instance but are an
2302
+ * engine implementation detail, so prefer the dedicated getters.
2303
+ */
2304
+ get classId() {
2305
+ return this.vm._getExports().qjs_get_class_id(this.ptr);
2306
+ }
2307
+ /**
2308
+ * The engine-level class name of this value, e.g. `"Object"`, `"Map"`,
2309
+ * `"Date"`, `"RegExp"`, or the registered name of an extension-defined
2310
+ * class like `"URL"`, or `undefined` for non-objects and unnamed
2311
+ * internal classes.
2312
+ *
2313
+ * Unlike `constructorName` (which reads the `constructor` and `name`
2314
+ * properties and can therefore fire getters/proxy traps and be spoofed),
2315
+ * this is trap-free: it reads the engine's class table directly, never
2316
+ * executes guest code, and cannot be forged by reassigning prototypes or
2317
+ * constructors. Note that the engine registers the Proxy class under the
2318
+ * name `"Object"` (mirroring `Object.prototype.toString`), so use `isProxy`
2319
+ * to detect proxies and `getProxyTarget()` to read the target's brand.
2320
+ */
2321
+ get className() {
2322
+ const h = new _JSValueHandle(this.vm, this.vm._getExports().qjs_get_class_name(this.ptr));
2323
+ if (this.vm._getExports().qjs_is_exception(h.ptr) !== 0) {
2324
+ h.dispose();
2325
+ throw new JSException(this.vm.getException());
2326
+ }
2327
+ try {
2328
+ return h.isUndefined ? void 0 : h.toString();
2329
+ } finally {
2330
+ h.dispose();
2331
+ }
2332
+ }
2333
+ get promiseState() {
2334
+ return this.vm._getExports().qjs_promise_state(this.ptr);
2335
+ }
2336
+ /**
2337
+ * Get the typeof this value as a string.
2338
+ * Returns the same values as the native `typeof` operator.
2339
+ */
2340
+ get typeof() {
2341
+ return this.vm.typeof(this);
2342
+ }
2343
+ /**
2344
+ * Get the length property of this value (for arrays, strings, etc.).
2345
+ */
2346
+ get length() {
2347
+ const h = this.getProp("length");
2348
+ const n = h.toNumber();
2349
+ h.dispose();
2350
+ return n;
2351
+ }
2352
+ /**
2353
+ * Get the constructor name of this object, or undefined if unavailable.
2354
+ */
2355
+ get constructorName() {
2356
+ const ctor = this.getProp("constructor");
2357
+ if (ctor.isUndefined || ctor.isNull) {
2358
+ ctor.dispose();
2359
+ return void 0;
2360
+ }
2361
+ const name = ctor.getProp("name");
2362
+ ctor.dispose();
2363
+ if (name.isUndefined || name.isNull) {
2364
+ name.dispose();
2365
+ return void 0;
2366
+ }
2367
+ const result = name.toString();
2368
+ name.dispose();
2369
+ return result;
2370
+ }
2371
+ /**
2372
+ * Get the own enumerable string property names (equivalent to Object.keys()).
2373
+ */
2374
+ keys() {
2375
+ const e = this.vm._getExports();
2376
+ const keysPtr = e.qjs_get_own_property_names(this.ptr);
2377
+ const keysHandle = new _JSValueHandle(this.vm, keysPtr);
2378
+ if (e.qjs_is_exception(keysHandle.ptr) !== 0) {
2379
+ keysHandle.dispose();
2380
+ return [];
2381
+ }
2382
+ const lenHandle = keysHandle.getProp("length");
2383
+ const len = e.qjs_get_float64(lenHandle.ptr);
2384
+ lenHandle.dispose();
2385
+ const result = [];
2386
+ for (let i = 0; i < len; i++) {
2387
+ const keyPtr = e.qjs_get_prop_uint32(keysHandle.ptr, i);
2388
+ const keyHandle = new _JSValueHandle(this.vm, keyPtr);
2389
+ result.push(keyHandle.toString());
2390
+ keyHandle.dispose();
2391
+ }
2392
+ keysHandle.dispose();
2393
+ return result;
2394
+ }
2395
+ /**
2396
+ * Get all own property names including non-enumerable ones
2397
+ * (equivalent to Object.getOwnPropertyNames()).
2398
+ */
2399
+ getOwnPropertyNames() {
2400
+ const e = this.vm._getExports();
2401
+ const keysPtr = e.qjs_get_own_property_names_all(this.ptr);
2402
+ const keysHandle = new _JSValueHandle(this.vm, keysPtr);
2403
+ if (e.qjs_is_exception(keysHandle.ptr) !== 0) {
2404
+ keysHandle.dispose();
2405
+ return [];
2406
+ }
2407
+ const lenHandle = keysHandle.getProp("length");
2408
+ const len = e.qjs_get_float64(lenHandle.ptr);
2409
+ lenHandle.dispose();
2410
+ const result = [];
2411
+ for (let i = 0; i < len; i++) {
2412
+ const keyPtr = e.qjs_get_prop_uint32(keysHandle.ptr, i);
2413
+ const keyHandle = new _JSValueHandle(this.vm, keyPtr);
2414
+ result.push(keyHandle.toString());
2415
+ keyHandle.dispose();
2416
+ }
2417
+ keysHandle.dispose();
2418
+ return result;
2419
+ }
2420
+ /**
2421
+ * Get ALL own property keys (strings and symbols), including
2422
+ * non-enumerable (equivalent to Reflect.ownKeys()).
2423
+ *
2424
+ * String keys are returned as strings; symbol keys are returned as
2425
+ * JSValueHandles which the caller must dispose.
2426
+ *
2427
+ * Trap-free for ordinary objects; fires the `ownKeys` trap for a
2428
+ * Proxy (check {@link isProxy} first if that matters).
2429
+ */
2430
+ getOwnPropertyKeys() {
2431
+ const e = this.vm._getExports();
2432
+ const keysPtr = e.qjs_get_own_property_keys(this.ptr);
2433
+ const keysHandle = new _JSValueHandle(this.vm, keysPtr);
2434
+ if (e.qjs_is_exception(keysHandle.ptr) !== 0) {
2435
+ keysHandle.dispose();
2436
+ return [];
2437
+ }
2438
+ const lenHandle = keysHandle.getProp("length");
2439
+ const len = e.qjs_get_float64(lenHandle.ptr);
2440
+ lenHandle.dispose();
2441
+ const result = [];
2442
+ for (let i = 0; i < len; i++) {
2443
+ const keyPtr = e.qjs_get_prop_uint32(keysHandle.ptr, i);
2444
+ const keyHandle = new _JSValueHandle(this.vm, keyPtr);
2445
+ if (keyHandle.isSymbol) {
2446
+ result.push(keyHandle);
2447
+ } else {
2448
+ result.push(keyHandle.toString());
2449
+ keyHandle.dispose();
2450
+ }
2451
+ }
2452
+ keysHandle.dispose();
2453
+ return result;
2454
+ }
2455
+ /**
2456
+ * Get the own property descriptor for a key WITHOUT invoking getters
2457
+ * (equivalent to Object.getOwnPropertyDescriptor()).
2458
+ *
2459
+ * This is the safe way to inspect a property that may be an accessor:
2460
+ * a data property yields `{ value, writable, enumerable, configurable }`,
2461
+ * an accessor property yields `{ get, set, enumerable, configurable }`
2462
+ * where `get`/`set` are handles to the accessor functions themselves
2463
+ * (never invoked). Returns undefined if there is no such own property.
2464
+ *
2465
+ * The `value`/`get`/`set` handles are owned by the caller and must be
2466
+ * disposed.
2467
+ *
2468
+ * Trap-free for ordinary objects; fires the `getOwnPropertyDescriptor`
2469
+ * trap for a Proxy (check {@link isProxy} first if that matters).
2470
+ */
2471
+ getOwnPropertyDescriptor(key) {
2472
+ const env_2 = { stack: [], error: void 0, hasError: false };
2473
+ try {
2474
+ const e = this.vm._getExports();
2475
+ let keyHandle;
2476
+ let keyPtr;
2477
+ if (typeof key === "string") {
2478
+ keyHandle = this.vm.newString(key);
2479
+ keyPtr = keyHandle.ptr;
2480
+ } else {
2481
+ keyPtr = key.ptr;
2482
+ }
2483
+ const descPtr = e.qjs_get_own_property_descriptor(this.ptr, keyPtr);
2484
+ keyHandle?.dispose();
2485
+ if (descPtr === 0)
2486
+ return void 0;
2487
+ const descHandle = __addDisposableResource(env_2, new _JSValueHandle(this.vm, descPtr), false);
2488
+ if (e.qjs_is_exception(descHandle.ptr) !== 0) {
2489
+ throw new JSException(this.vm.getException());
2490
+ }
2491
+ const enumerable = descHandle.getProp("enumerable").consume((h) => e.qjs_get_bool(h.ptr) !== 0);
2492
+ const configurable = descHandle.getProp("configurable").consume((h) => e.qjs_get_bool(h.ptr) !== 0);
2493
+ if (descHandle.hasOwnProperty("value")) {
2494
+ return {
2495
+ value: descHandle.getProp("value"),
2496
+ writable: descHandle.getProp("writable").consume((h) => e.qjs_get_bool(h.ptr) !== 0),
2497
+ enumerable,
2498
+ configurable
2499
+ };
2500
+ }
2501
+ return {
2502
+ get: descHandle.getProp("get"),
2503
+ set: descHandle.getProp("set"),
2504
+ enumerable,
2505
+ configurable
2506
+ };
2507
+ } catch (e_2) {
2508
+ env_2.error = e_2;
2509
+ env_2.hasError = true;
2510
+ } finally {
2511
+ __disposeResources(env_2);
2512
+ }
2513
+ }
2514
+ /**
2515
+ * Check if a property is an own property (equivalent to Object.prototype.hasOwnProperty).
2516
+ */
2517
+ hasOwnProperty(name) {
2518
+ if (stringKeyNeedsValuePath(name)) {
2519
+ const env_3 = { stack: [], error: void 0, hasError: false };
2520
+ try {
2521
+ const keyHandle = __addDisposableResource(env_3, this.vm.newString(name), false);
2522
+ return this.vm._getExports().qjs_has_own_property_value(this.ptr, keyHandle.ptr) === 1;
2523
+ } catch (e_3) {
2524
+ env_3.error = e_3;
2525
+ env_3.hasError = true;
2526
+ } finally {
2527
+ __disposeResources(env_3);
2528
+ }
2529
+ }
2530
+ const { ptr: namePtr } = this.vm._writeString(name);
2531
+ const result = this.vm._getExports().qjs_has_own_property(this.ptr, namePtr);
2532
+ this.vm._getExports().wasm_free(namePtr);
2533
+ return result === 1;
2534
+ }
2535
+ /**
2536
+ * Check if a property is enumerable (equivalent to Object.prototype.propertyIsEnumerable).
2537
+ */
2538
+ propertyIsEnumerable(name) {
2539
+ if (stringKeyNeedsValuePath(name)) {
2540
+ const env_4 = { stack: [], error: void 0, hasError: false };
2541
+ try {
2542
+ const keyHandle = __addDisposableResource(env_4, this.vm.newString(name), false);
2543
+ return this.vm._getExports().qjs_property_is_enumerable_value(this.ptr, keyHandle.ptr) === 1;
2544
+ } catch (e_4) {
2545
+ env_4.error = e_4;
2546
+ env_4.hasError = true;
2547
+ } finally {
2548
+ __disposeResources(env_4);
2549
+ }
2550
+ }
2551
+ const { ptr: namePtr } = this.vm._writeString(name);
2552
+ const result = this.vm._getExports().qjs_property_is_enumerable(this.ptr, namePtr);
2553
+ this.vm._getExports().wasm_free(namePtr);
2554
+ return result === 1;
2555
+ }
2556
+ /**
2557
+ * Get the prototype of this object (equivalent to Object.getPrototypeOf()).
2558
+ */
2559
+ getPrototypeOf() {
2560
+ const protoPtr = this.vm._getExports().qjs_get_prototype_of(this.ptr);
2561
+ return new _JSValueHandle(this.vm, protoPtr);
2562
+ }
2563
+ /**
2564
+ * Get the `[[ProxyTarget]]` of this Proxy without firing any traps.
2565
+ * Throws {@link JSException} if this value is not a Proxy; check
2566
+ * {@link isProxy} first. Note the target may itself be a Proxy.
2567
+ */
2568
+ getProxyTarget() {
2569
+ const ptr = this.vm._getExports().qjs_get_proxy_target(this.ptr);
2570
+ const handle = new _JSValueHandle(this.vm, ptr);
2571
+ if (this.vm._getExports().qjs_is_exception(handle.ptr) !== 0) {
2572
+ handle.dispose();
2573
+ throw new JSException(this.vm.getException());
2574
+ }
2575
+ return handle;
2576
+ }
2577
+ /**
2578
+ * Get the `[[ProxyHandler]]` of this Proxy without firing any traps.
2579
+ * Throws {@link JSException} if this value is not a Proxy; check
2580
+ * {@link isProxy} first.
2581
+ */
2582
+ getProxyHandler() {
2583
+ const ptr = this.vm._getExports().qjs_get_proxy_handler(this.ptr);
2584
+ const handle = new _JSValueHandle(this.vm, ptr);
2585
+ if (this.vm._getExports().qjs_is_exception(handle.ptr) !== 0) {
2586
+ handle.dispose();
2587
+ throw new JSException(this.vm.getException());
2588
+ }
2589
+ return handle;
2590
+ }
2591
+ /**
2592
+ * Get a property by name.
2593
+ */
2594
+ getProp(name) {
2595
+ if (stringKeyNeedsValuePath(name)) {
2596
+ const env_5 = { stack: [], error: void 0, hasError: false };
2597
+ try {
2598
+ const keyHandle = __addDisposableResource(env_5, this.vm.newString(name), false);
2599
+ return this.vm.getProp(this, keyHandle);
2600
+ } catch (e_5) {
2601
+ env_5.error = e_5;
2602
+ env_5.hasError = true;
2603
+ } finally {
2604
+ __disposeResources(env_5);
2605
+ }
2606
+ }
2607
+ const { ptr: namePtr } = this.vm._writeString(name);
2608
+ const resultPtr = this.vm._getExports().qjs_get_prop_string(this.ptr, namePtr);
2609
+ this.vm._getExports().wasm_free(namePtr);
2610
+ return new _JSValueHandle(this.vm, resultPtr);
2611
+ }
2612
+ /**
2613
+ * Set a property by name.
2614
+ */
2615
+ setProp(name, value) {
2616
+ if (stringKeyNeedsValuePath(name)) {
2617
+ const env_6 = { stack: [], error: void 0, hasError: false };
2618
+ try {
2619
+ const keyHandle = __addDisposableResource(env_6, this.vm.newString(name), false);
2620
+ this.vm.setProp(this, keyHandle, value);
2621
+ return;
2622
+ } catch (e_6) {
2623
+ env_6.error = e_6;
2624
+ env_6.hasError = true;
2625
+ } finally {
2626
+ __disposeResources(env_6);
2627
+ }
2628
+ }
2629
+ const { ptr: namePtr } = this.vm._writeString(name);
2630
+ this.vm._getExports().qjs_set_prop_string(this.ptr, namePtr, value.ptr);
2631
+ this.vm._getExports().wasm_free(namePtr);
2632
+ }
2633
+ /**
2634
+ * Define a property with explicit property descriptor flags.
2635
+ * Unlike `setProp`, this allows controlling `writable`, `enumerable`, and
2636
+ * `configurable` attributes, matching `Object.defineProperty()` semantics.
2637
+ * Accepts string or JSValueHandle as key (JSValueHandle keys support symbols).
2638
+ *
2639
+ * All flags default to `false` when not specified.
2640
+ */
2641
+ defineProp(key, value, descriptor) {
2642
+ let flags = 0;
2643
+ if (descriptor?.configurable)
2644
+ flags |= 1;
2645
+ if (descriptor?.writable)
2646
+ flags |= 2;
2647
+ if (descriptor?.enumerable)
2648
+ flags |= 4;
2649
+ if (typeof key === "string") {
2650
+ if (stringKeyNeedsValuePath(key)) {
2651
+ const env_7 = { stack: [], error: void 0, hasError: false };
2652
+ try {
2653
+ const keyHandle = __addDisposableResource(env_7, this.vm.newString(key), false);
2654
+ this.vm._getExports().qjs_define_prop_value(this.ptr, keyHandle.ptr, value.ptr, flags);
2655
+ return;
2656
+ } catch (e_7) {
2657
+ env_7.error = e_7;
2658
+ env_7.hasError = true;
2659
+ } finally {
2660
+ __disposeResources(env_7);
2661
+ }
2662
+ }
2663
+ const { ptr: namePtr } = this.vm._writeString(key);
2664
+ this.vm._getExports().qjs_define_prop_string(this.ptr, namePtr, value.ptr, flags);
2665
+ this.vm._getExports().wasm_free(namePtr);
2666
+ } else {
2667
+ this.vm._getExports().qjs_define_prop_value(this.ptr, key.ptr, value.ptr, flags);
2668
+ }
2669
+ }
2670
+ /**
2671
+ * Extract the value as a number.
2672
+ */
2673
+ toNumber() {
2674
+ return this.vm._getExports().qjs_get_float64(this.ptr);
2675
+ }
2676
+ /**
2677
+ * Extract the value as a BigInt.
2678
+ */
2679
+ toBigInt() {
2680
+ const e = this.vm._getExports();
2681
+ const loPtr = e.wasm_malloc(4);
2682
+ const hiPtr = e.wasm_malloc(4);
2683
+ const ret = e.qjs_get_big_int64(this.ptr, loPtr, hiPtr);
2684
+ if (ret !== 0) {
2685
+ e.wasm_free(loPtr);
2686
+ e.wasm_free(hiPtr);
2687
+ throw new Error("Failed to convert value to BigInt");
2688
+ }
2689
+ const view = new DataView(e.memory.buffer);
2690
+ const lo = view.getUint32(loPtr, true);
2691
+ const hi = view.getInt32(hiPtr, true);
2692
+ e.wasm_free(loPtr);
2693
+ e.wasm_free(hiPtr);
2694
+ return BigInt(hi) << 32n | BigInt(lo);
2695
+ }
2696
+ /**
2697
+ * Extract the value as an ArrayBuffer (copies from WASM memory).
2698
+ * Works on ArrayBuffer values. For typed arrays, gets the underlying buffer.
2699
+ */
2700
+ toArrayBuffer() {
2701
+ const e = this.vm._getExports();
2702
+ const lenOutPtr = e.wasm_malloc(4);
2703
+ if (e.qjs_is_array_buffer(this.ptr)) {
2704
+ const dataPtr = e.qjs_get_array_buffer(this.ptr, lenOutPtr);
2705
+ if (dataPtr === 0) {
2706
+ e.wasm_free(lenOutPtr);
2707
+ throw new Error("Failed to get ArrayBuffer data");
2708
+ }
2709
+ const view2 = new DataView(e.memory.buffer);
2710
+ const len = view2.getUint32(lenOutPtr, true);
2711
+ e.wasm_free(lenOutPtr);
2712
+ return new Uint8Array(e.memory.buffer, dataPtr, len).slice().buffer;
2713
+ }
2714
+ e.wasm_free(lenOutPtr);
2715
+ const byteOffsetPtr = e.wasm_malloc(4);
2716
+ const byteLengthPtr = e.wasm_malloc(4);
2717
+ const bytesPerElemPtr = e.wasm_malloc(4);
2718
+ const abPtr = e.qjs_get_typed_array_buffer(this.ptr, byteOffsetPtr, byteLengthPtr, bytesPerElemPtr);
2719
+ const abHandle = new _JSValueHandle(this.vm, abPtr);
2720
+ if (this.vm._getExports().qjs_is_exception(abHandle.ptr) !== 0) {
2721
+ abHandle.dispose();
2722
+ e.wasm_free(byteOffsetPtr);
2723
+ e.wasm_free(byteLengthPtr);
2724
+ e.wasm_free(bytesPerElemPtr);
2725
+ throw new Error("Value is not an ArrayBuffer or typed array");
2726
+ }
2727
+ const view = new DataView(e.memory.buffer);
2728
+ const byteOffset = view.getUint32(byteOffsetPtr, true);
2729
+ const byteLength = view.getUint32(byteLengthPtr, true);
2730
+ e.wasm_free(byteOffsetPtr);
2731
+ e.wasm_free(byteLengthPtr);
2732
+ e.wasm_free(bytesPerElemPtr);
2733
+ const abLenPtr = e.wasm_malloc(4);
2734
+ const abDataPtr = e.qjs_get_array_buffer(abHandle.ptr, abLenPtr);
2735
+ e.wasm_free(abLenPtr);
2736
+ abHandle.dispose();
2737
+ if (abDataPtr === 0) {
2738
+ throw new Error("Failed to get ArrayBuffer data from typed array");
2739
+ }
2740
+ return new Uint8Array(e.memory.buffer, abDataPtr + byteOffset, byteLength).slice().buffer;
2741
+ }
2742
+ /**
2743
+ * Extract the value as a Uint8Array (copies from WASM memory).
2744
+ * Works on Uint8Array, ArrayBuffer, and other typed array values.
2745
+ */
2746
+ toUint8Array() {
2747
+ return new Uint8Array(this.toArrayBuffer());
2748
+ }
2749
+ /**
2750
+ * Extract the value as a string. Works on any value.
2751
+ *
2752
+ * For values that are not already strings this performs a JavaScript
2753
+ * string conversion, which **executes guest code**: `toString()` /
2754
+ * `valueOf()` / `Symbol.toPrimitive` on the value or its prototype chain,
2755
+ * and proxy traps. Guard with `isString` when the caller must not run guest
2756
+ * code, and call a captured intrinsic (e.g. `URL.prototype.toString` via
2757
+ * `vm.callFunction`) when a specific conversion is wanted.
2758
+ */
2759
+ toString() {
2760
+ const e = this.vm._getExports();
2761
+ const lenPtr = e.wasm_malloc(4);
2762
+ if (lenPtr === 0)
2763
+ throw new Error("wasm_malloc failed");
2764
+ try {
2765
+ const cstrPtr = e.qjs_get_string_len(this.ptr, lenPtr);
2766
+ if (cstrPtr === 0)
2767
+ return "<null>";
2768
+ const len = new DataView(e.memory.buffer).getUint32(lenPtr, true);
2769
+ const bytes = new Uint8Array(e.memory.buffer, cstrPtr, len);
2770
+ const str = decodeWtf8(bytes);
2771
+ e.qjs_free_cstring(cstrPtr);
2772
+ return str;
2773
+ } finally {
2774
+ e.wasm_free(lenPtr);
2775
+ }
2776
+ }
2777
+ /**
2778
+ * Use this handle, then dispose it. Returns the callback's return value.
2779
+ */
2780
+ consume(fn) {
2781
+ try {
2782
+ return fn(this);
2783
+ } finally {
2784
+ this.dispose();
2785
+ }
2786
+ }
2787
+ /**
2788
+ * Duplicate this handle (increment refcount).
2789
+ */
2790
+ dup() {
2791
+ return new _JSValueHandle(this.vm, this.vm._getExports().qjs_dup_value(this.ptr));
2792
+ }
2793
+ /**
2794
+ * Dispose this handle, freeing the heap-allocated JSValue.
2795
+ * Safe to call after the VM has been disposed (becomes a no-op).
2796
+ */
2797
+ dispose() {
2798
+ if (this.singleton || this.borrowed)
2799
+ return;
2800
+ if (!this.disposed_) {
2801
+ this.disposed_ = true;
2802
+ this._onDispose?.();
2803
+ this._onDispose = void 0;
2804
+ const exports = this.vm._getExports();
2805
+ if (exports) {
2806
+ exports.qjs_free_value(this.ptr);
2807
+ }
2808
+ }
2809
+ }
2810
+ /**
2811
+ * Support for `using` declarations (Explicit Resource Management).
2812
+ * Automatically disposes the handle when it goes out of scope.
2813
+ *
2814
+ * ```typescript
2815
+ * using result = vm.evalCode('1 + 2');
2816
+ * console.log(result.toNumber()); // 3
2817
+ * // result is automatically disposed here
2818
+ * ```
2819
+ */
2820
+ [Symbol.dispose]() {
2821
+ this.dispose();
2822
+ }
2823
+ };
2824
+
2825
+ // node_modules/@earendil-works/pi-codemode/dist/runtime/prelude-source.js
2826
+ var MAX_STORE_VALUE_CHARS = 256 * 1024;
2827
+ var MAX_STORE_TOTAL_CHARS = 1024 * 1024;
2828
+ var MAX_OUTPUT_CHARS = 16 * 1024 * 1024;
2829
+ var MAX_OUTPUT_ITEMS = 1e5;
2830
+ var IMAGE_HELPER_EXPECTS = 'image expects a non-empty image URL string, an object with image_url, or an image block { type: "image", data, mimeType }';
2831
+ var PRELUDE_SOURCE = `(function (bridge, toolsJson, globalsJson, storeJson) {
2832
+ "use strict";
2833
+
2834
+ // Freeze every object reachable from the built-in globals, plus the intrinsics that are only
2835
+ // reachable from instances (iterator and generator prototypes, %TypedArray%).
2836
+ //
2837
+ // Freezing alone breaks ordinary code through the "override mistake": a data property that is
2838
+ // read-only on a prototype cannot be assigned on an instance either, so
2839
+ // this.name = "MyError" in an Error subclass would throw. Commonly overridden properties
2840
+ // become accessors whose setter defines an own property on the instance instead.
2841
+ (function lockdown() {
2842
+ const OVERRIDABLE = new Set(["constructor", "name", "message", "toString", "toLocaleString", "valueOf", "toJSON"]);
2843
+ const seen = new Set([globalThis]);
2844
+ const queue = [];
2845
+ const add = (value) => {
2846
+ if ((typeof value === "object" && value !== null) || typeof value === "function") {
2847
+ if (!seen.has(value)) {
2848
+ seen.add(value);
2849
+ queue.push(value);
2850
+ }
2851
+ }
2852
+ };
2853
+
2854
+ // Accessors from an object literal have no own prototype object, unlike function expressions,
2855
+ // whose prototype.constructor would be converted again without end.
2856
+ function allowOverride(object, key, value, enumerable) {
2857
+ const { get, set } = Object.getOwnPropertyDescriptor(
2858
+ {
2859
+ get accessor() {
2860
+ return value;
2861
+ },
2862
+ set accessor(next) {
2863
+ if (this === object) {
2864
+ throw new TypeError("Cannot assign to read only property '" + String(key) + "' of a built-in");
2865
+ }
2866
+ if ((typeof this !== "object" || this === null) && typeof this !== "function") return;
2867
+ Object.defineProperty(this, key, { value: next, writable: true, enumerable: true, configurable: true });
2868
+ },
2869
+ },
2870
+ "accessor",
2871
+ );
2872
+ Object.defineProperty(object, key, { get, set, enumerable, configurable: false });
2873
+ add(get);
2874
+ add(set);
2875
+ }
2876
+
2877
+ for (const key of Reflect.ownKeys(globalThis)) {
2878
+ const descriptor = Object.getOwnPropertyDescriptor(globalThis, key);
2879
+ add(descriptor.value);
2880
+ add(descriptor.get);
2881
+ add(descriptor.set);
2882
+ if ("value" in descriptor && descriptor.configurable) {
2883
+ Object.defineProperty(globalThis, key, { writable: false, configurable: false });
2884
+ }
2885
+ }
2886
+ add(Object.getPrototypeOf(function* () {}));
2887
+ add(Object.getPrototypeOf(async function () {}));
2888
+ add(Object.getPrototypeOf(async function* () {}));
2889
+ add(Object.getPrototypeOf(Int8Array));
2890
+ add(Object.getPrototypeOf([][Symbol.iterator]()));
2891
+ add(Object.getPrototypeOf(new Map()[Symbol.iterator]()));
2892
+ add(Object.getPrototypeOf(new Set()[Symbol.iterator]()));
2893
+ add(Object.getPrototypeOf(""[Symbol.iterator]()));
2894
+ add(Object.getPrototypeOf(/a/[Symbol.matchAll]("")));
2895
+ if (typeof Iterator === "function") {
2896
+ if (typeof Iterator.prototype.map === "function") add(Object.getPrototypeOf([].values().map((x) => x)));
2897
+ if (typeof Iterator.from === "function") add(Object.getPrototypeOf(Iterator.from({ next() {} })));
2898
+ }
2899
+
2900
+ while (queue.length > 0) {
2901
+ const object = queue.pop();
2902
+ add(Object.getPrototypeOf(object));
2903
+ const descriptors = Object.getOwnPropertyDescriptors(object);
2904
+ for (const key of Reflect.ownKeys(descriptors)) {
2905
+ const descriptor = descriptors[key];
2906
+ if ("value" in descriptor) {
2907
+ add(descriptor.value);
2908
+ if (
2909
+ descriptor.writable &&
2910
+ descriptor.configurable &&
2911
+ (object === Object.prototype || OVERRIDABLE.has(key))
2912
+ ) {
2913
+ allowOverride(object, key, descriptor.value, descriptor.enumerable);
2914
+ }
2915
+ } else {
2916
+ add(descriptor.get);
2917
+ add(descriptor.set);
2918
+ }
2919
+ }
2920
+ Object.freeze(object);
2921
+ }
2922
+ })();
2923
+ const stringify = JSON.stringify;
2924
+ const parse = JSON.parse;
2925
+ const promiseThen = Promise.prototype.then;
2926
+ const ErrorCtor = Error;
2927
+ const TypeErrorCtor = TypeError;
2928
+ const RangeErrorCtor = RangeError;
2929
+ const pending = new Map();
2930
+ let nextId = 1;
2931
+ let finished = false;
2932
+ // Thrown by exit() to unwind the script after it already reported success.
2933
+ const EXIT = Object.freeze({});
2934
+
2935
+ function done(ok, payload, writes) {
2936
+ if (finished) return;
2937
+ finished = true;
2938
+ bridge("done", ok, payload, writes);
2939
+ }
2940
+
2941
+ function serialize(value) {
2942
+ return value === undefined ? undefined : stringify(value);
2943
+ }
2944
+
2945
+ // QuickJS stacks list frames only. Prefix "Name: message" like V8 so the
2946
+ // text reads the same as a Node error, and drop this prelude's frames.
2947
+ function errorText(error) {
2948
+ const head = error.message ? error.name + ": " + error.message : String(error.name);
2949
+ const frames =
2950
+ typeof error.stack === "string"
2951
+ ? error.stack.split("\\n").filter((line) => line.trim() && !line.includes("codemode-prelude.js"))
2952
+ : [];
2953
+ return [head, ...frames].join("\\n");
2954
+ }
2955
+
2956
+ function format(value) {
2957
+ if (typeof value === "string") return value;
2958
+ if (value instanceof ErrorCtor) return errorText(value);
2959
+ try {
2960
+ const json = stringify(value);
2961
+ return json === undefined ? String(value) : json;
2962
+ } catch {
2963
+ return String(value);
2964
+ }
2965
+ }
2966
+
2967
+ // The host requires string fields. A script can set an error's name or message to anything, so
2968
+ // they are coerced, and a value whose coercion throws gets a placeholder.
2969
+ function describeError(error) {
2970
+ try {
2971
+ if (error instanceof ErrorCtor) {
2972
+ return stringify({ name: String(error.name), message: String(error.message), stack: errorText(error) });
2973
+ }
2974
+ return stringify({ message: String(format(error)) });
2975
+ } catch {
2976
+ return stringify({ message: "The script threw a value that cannot be described" });
2977
+ }
2978
+ }
2979
+
2980
+ function caller(kind, name, spread) {
2981
+ return (...args) =>
2982
+ new Promise((resolve, reject) => {
2983
+ let json;
2984
+ try {
2985
+ json = serialize(spread ? args : args[0]);
2986
+ } catch (error) {
2987
+ reject(error);
2988
+ return;
2989
+ }
2990
+ const id = nextId++;
2991
+ pending.set(id, { resolve, reject });
2992
+ bridge(kind, id, name, json);
2993
+ });
2994
+ }
2995
+
2996
+ const tools = Object.create(null);
2997
+ const allTools = [];
2998
+ for (const { name, jsName, description } of parse(toolsJson)) {
2999
+ const fn = caller("call", name);
3000
+ // The first tool wins when two names normalize to the same identifier.
3001
+ if (!(jsName in tools)) {
3002
+ tools[jsName] = fn;
3003
+ allTools.push(Object.freeze({ name: jsName, description }));
3004
+ }
3005
+ if (!(name in tools)) tools[name] = fn;
3006
+ }
3007
+ Object.freeze(tools);
3008
+ Object.freeze(allTools);
3009
+
3010
+ // Reading a member that does not exist throws an error that names the close matches, instead of
3011
+ // a later "not a function". \`in\` checks still work.
3012
+ const comparable = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, "");
3013
+ function guard(target, label, names, hint) {
3014
+ return new Proxy(target, {
3015
+ get(object, property, receiver) {
3016
+ if (typeof property !== "string" || property in object || property in Object.prototype || property === "then" || property === "toJSON") {
3017
+ return Reflect.get(object, property, receiver);
3018
+ }
3019
+ const wanted = comparable(property);
3020
+ const exact = names.filter((name) => comparable(name) === wanted);
3021
+ const close = exact.length > 0 ? exact : names.filter((name) => wanted && (comparable(name).includes(wanted) || wanted.includes(comparable(name))));
3022
+ let message = label + "." + property + " does not exist.";
3023
+ if (close.length > 0) message += " Did you mean " + close.slice(0, 5).map((name) => label + "." + name).join(", ") + "?";
3024
+ else if (names.length <= 20) message += " Available: " + names.join(", ") + ".";
3025
+ if (hint) message += " " + hint;
3026
+ message += ' Check for a member with "' + property + '" in ' + label + ".";
3027
+ throw new TypeErrorCtor(message);
3028
+ },
3029
+ });
3030
+ }
3031
+ const toolsProxy = guard(
3032
+ tools,
3033
+ "tools",
3034
+ allTools.map((tool) => tool.name),
3035
+ "ALL_TOOLS lists every tool; searchTools(query) finds tools by topic.",
3036
+ );
3037
+
3038
+ const namespaces = new Map();
3039
+ for (const { name, spread } of parse(globalsJson)) {
3040
+ const fn = caller("global", name, spread);
3041
+ const dot = name.indexOf(".");
3042
+ if (dot === -1) {
3043
+ Object.defineProperty(globalThis, name, { value: fn, enumerable: true });
3044
+ continue;
3045
+ }
3046
+ const namespace = name.slice(0, dot);
3047
+ if (!namespaces.has(namespace)) namespaces.set(namespace, Object.create(null));
3048
+ namespaces.get(namespace)[name.slice(dot + 1)] = fn;
3049
+ }
3050
+ for (const [namespace, members] of namespaces) {
3051
+ Object.freeze(members);
3052
+ const value = guard(members, namespace, Object.keys(members));
3053
+ Object.defineProperty(globalThis, namespace, { value, enumerable: true });
3054
+ }
3055
+
3056
+ // key -> JSON text. Sizes count key and JSON characters.
3057
+ const stored = new Map(Object.entries(parse(storeJson)));
3058
+ const writes = new Map();
3059
+ let storedChars = 0;
3060
+ for (const [key, json] of stored) storedChars += key.length + json.length;
3061
+
3062
+ const STORE_HINT =
3063
+ "store() is for small state such as IDs or summaries. Show images with image(), keep large data in variables, or write it to a file with a tool.";
3064
+
3065
+ function checkKey(name, key) {
3066
+ if (typeof key !== "string") throw new TypeError(name + "() key must be a string");
3067
+ }
3068
+
3069
+ function store(key, value) {
3070
+ checkKey("store", key);
3071
+ const previous = stored.has(key) ? key.length + stored.get(key).length : 0;
3072
+ if (value === undefined) {
3073
+ stored.delete(key);
3074
+ storedChars -= previous;
3075
+ writes.set(key, undefined);
3076
+ return;
3077
+ }
3078
+ let json;
3079
+ try {
3080
+ json = stringify(value);
3081
+ } catch (error) {
3082
+ throw new TypeError("store(" + stringify(key) + ") value is not JSON-serializable: " + format(error));
3083
+ }
3084
+ if (json === undefined) {
3085
+ throw new TypeError("store(" + stringify(key) + ") value is not JSON-serializable");
3086
+ }
3087
+ if (json.length > ${MAX_STORE_VALUE_CHARS}) {
3088
+ throw new RangeError(
3089
+ "store(" + stringify(key) + ") value has " + json.length + " characters of JSON, more than the limit of ${MAX_STORE_VALUE_CHARS}. " +
3090
+ STORE_HINT,
3091
+ );
3092
+ }
3093
+ const next = storedChars - previous + key.length + json.length;
3094
+ if (next > ${MAX_STORE_TOTAL_CHARS}) {
3095
+ throw new RangeError(
3096
+ "store is full: stored values would exceed ${MAX_STORE_TOTAL_CHARS} characters of JSON. Delete keys with store(key, undefined). " +
3097
+ STORE_HINT,
3098
+ );
3099
+ }
3100
+ stored.set(key, json);
3101
+ storedChars = next;
3102
+ writes.set(key, json);
3103
+ }
3104
+
3105
+ function load(key) {
3106
+ checkKey("load", key);
3107
+ const json = stored.get(key);
3108
+ return json === undefined ? undefined : parse(json);
3109
+ }
3110
+
3111
+ function serializeWrites() {
3112
+ const entries = [];
3113
+ for (const [key, json] of writes) entries.push(json === undefined ? [key] : [key, json]);
3114
+ return stringify(entries);
3115
+ }
3116
+
3117
+ Object.defineProperty(globalThis, "store", { value: store, enumerable: true });
3118
+ Object.defineProperty(globalThis, "load", { value: load, enumerable: true });
3119
+
3120
+ let outputChars = 0;
3121
+ let outputItems = 0;
3122
+
3123
+ // Past the output limits the script fails: done() reports the error, so catching it does not
3124
+ // resume output, and the host ends the script.
3125
+ function output(kind, data, mimeType) {
3126
+ if (finished) return;
3127
+ outputChars += data.length;
3128
+ outputItems++;
3129
+ if (outputChars > ${MAX_OUTPUT_CHARS} || outputItems > ${MAX_OUTPUT_ITEMS}) {
3130
+ const error = new RangeErrorCtor(
3131
+ "script output exceeded the limit of ${MAX_OUTPUT_CHARS} characters or ${MAX_OUTPUT_ITEMS} text(), image(), and console calls. " +
3132
+ "Print a summary instead, or write large data to a file with a tool.",
3133
+ );
3134
+ done(false, describeError(error));
3135
+ throw error;
3136
+ }
3137
+ bridge("output", kind, data, mimeType);
3138
+ }
3139
+
3140
+ // Primitives become their string form, everything else JSON.
3141
+ function outputText(value) {
3142
+ if (value === undefined || value === null || typeof value !== "object" && typeof value !== "function") {
3143
+ return String(value);
3144
+ }
3145
+ const json = stringify(value);
3146
+ return json === undefined ? String(value) : json;
3147
+ }
3148
+
3149
+ function text(value) {
3150
+ let rendered;
3151
+ try {
3152
+ rendered = outputText(value);
3153
+ } catch (error) {
3154
+ throw new TypeErrorCtor(error instanceof ErrorCtor ? error.message : String(error));
3155
+ }
3156
+ output("text", rendered);
3157
+ }
3158
+
3159
+ function imageUrl(value) {
3160
+ if (typeof value === "string") return value;
3161
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3162
+ throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});
3163
+ }
3164
+ if (value.image_url !== undefined) {
3165
+ if (typeof value.image_url !== "string") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});
3166
+ return value.image_url;
3167
+ }
3168
+ if (typeof value.type !== "string") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});
3169
+ if (value.type !== "image") {
3170
+ throw new TypeErrorCtor('image only accepts image blocks, got "' + value.type + '"');
3171
+ }
3172
+ if (typeof value.data !== "string" || value.data === "") throw new TypeErrorCtor("image expected image block data");
3173
+ if (value.data.toLowerCase().startsWith("data:")) return value.data;
3174
+ return "data:;base64," + value.data;
3175
+ }
3176
+
3177
+ // Base64 of the signatures of the formats providers accept inline (PNG, JPEG except
3178
+ // JPEG-LS, GIF, "RIFF....WEBP"). Signatures start at byte 0, so their encodings are prefixes.
3179
+ const IMAGE_SIGNATURES = [
3180
+ ["image/png", /^iVBORw0KGg/],
3181
+ ["image/jpeg", /^[/]9j[/](?!9)/],
3182
+ ["image/gif", /^R0lGOD[dl]h/],
3183
+ ["image/webp", /^UklG.{8}RUJQ/],
3184
+ ];
3185
+
3186
+ function image(value) {
3187
+ const url = imageUrl(value);
3188
+ if (url === "") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});
3189
+ const colon = url.indexOf(":");
3190
+ const scheme = colon === -1 ? "" : url.slice(0, colon).toLowerCase();
3191
+ if (scheme === "http" || scheme === "https") {
3192
+ throw new TypeErrorCtor("remote image URLs are not supported in tool outputs. Pass a base64 data URI instead");
3193
+ }
3194
+ const comma = url.indexOf(",");
3195
+ const header = comma === -1 ? [] : url.slice(colon + 1, comma).split(";");
3196
+ if (scheme !== "data" || comma === -1 || header.slice(1).every((part) => part.toLowerCase() !== "base64")) {
3197
+ throw new TypeErrorCtor("invalid image output. Pass a base64 data URI instead");
3198
+ }
3199
+ // Providers reject the whole request on a bad image, and a persisted image block would be
3200
+ // resent on every later turn. Line breaks from wrapped base64 are dropped. The declared type
3201
+ // is ignored in favor of the detected one, as providers also reject mismatches.
3202
+ const data = url.slice(comma + 1).replace(/\\s+/g, "");
3203
+ if (data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data)) {
3204
+ throw new TypeErrorCtor("invalid image output. The image data is not valid base64 (truncated or corrupted?)");
3205
+ }
3206
+ const head = data.slice(0, 16);
3207
+ const signature = IMAGE_SIGNATURES.find(([, pattern]) => pattern.test(head));
3208
+ if (!signature) {
3209
+ throw new TypeErrorCtor("invalid image output. The image data is not a PNG, JPEG, GIF, or WebP image");
3210
+ }
3211
+ output("image", data, signature[0]);
3212
+ }
3213
+
3214
+ function exit() {
3215
+ let writesJson;
3216
+ try {
3217
+ writesJson = serializeWrites();
3218
+ } catch (error) {
3219
+ done(false, describeError(error));
3220
+ throw EXIT;
3221
+ }
3222
+ done(true, undefined, writesJson);
3223
+ throw EXIT;
3224
+ }
3225
+
3226
+ const console = {};
3227
+ for (const level of ["log", "info", "warn", "error", "debug"]) {
3228
+ console[level] = (...args) => {
3229
+ output("console", args.map(format).join(" "));
3230
+ };
3231
+ }
3232
+ Object.freeze(console);
3233
+
3234
+ Object.defineProperty(globalThis, "tools", { value: toolsProxy, enumerable: true });
3235
+ Object.defineProperty(globalThis, "ALL_TOOLS", { value: allTools, enumerable: true });
3236
+ Object.defineProperty(globalThis, "console", { value: console, enumerable: true });
3237
+ Object.defineProperty(globalThis, "text", { value: text, enumerable: true });
3238
+ Object.defineProperty(globalThis, "image", { value: image, enumerable: true });
3239
+ Object.defineProperty(globalThis, "exit", { value: exit, enumerable: true });
3240
+
3241
+ return {
3242
+ settle(id, ok, payload, propertiesJson) {
3243
+ const entry = pending.get(id);
3244
+ if (!entry) return;
3245
+ pending.delete(id);
3246
+ if (!ok) {
3247
+ const error = new ErrorCtor(payload);
3248
+ if (propertiesJson !== undefined) {
3249
+ const properties = parse(propertiesJson);
3250
+ for (const key of Object.keys(properties)) {
3251
+ if (key === "name" || key === "message" || key === "stack") continue;
3252
+ Object.defineProperty(error, key, { value: properties[key], writable: true, enumerable: true, configurable: true });
3253
+ }
3254
+ }
3255
+ entry.reject(error);
3256
+ return;
3257
+ }
3258
+ let value;
3259
+ try {
3260
+ value = payload === undefined ? undefined : parse(payload);
3261
+ } catch (error) {
3262
+ entry.reject(error);
3263
+ return;
3264
+ }
3265
+ entry.resolve(value);
3266
+ },
3267
+ run(fn) {
3268
+ let promise;
3269
+ try {
3270
+ promise = fn(toolsProxy, console);
3271
+ } catch (error) {
3272
+ done(false, describeError(error));
3273
+ return;
3274
+ }
3275
+ promiseThen.call(
3276
+ promise,
3277
+ (value) => {
3278
+ let json;
3279
+ try {
3280
+ json = serialize(value);
3281
+ } catch (error) {
3282
+ done(false, describeError(error));
3283
+ return;
3284
+ }
3285
+ done(true, json, serializeWrites());
3286
+ },
3287
+ (error) => {
3288
+ done(false, describeError(error));
3289
+ },
3290
+ );
3291
+ },
3292
+ stalled() {
3293
+ if (finished || pending.size > 0) return false;
3294
+ done(
3295
+ false,
3296
+ stringify({
3297
+ name: "Error",
3298
+ message:
3299
+ "The script is waiting on a promise that can never settle: no tool call is pending, and timers do not exist here.",
3300
+ }),
3301
+ );
3302
+ return true;
3303
+ },
3304
+ };
3305
+ })`;
3306
+
3307
+ // node_modules/@earendil-works/pi-codemode/dist/runtime/vm.js
3308
+ var DETERMINISTIC_VERSION = 1;
3309
+ function fnv1a(text) {
3310
+ let hash = 2166136261;
3311
+ for (let index = 0; index < text.length; index++) {
3312
+ hash ^= text.charCodeAt(index);
3313
+ hash = Math.imul(hash, 16777619);
3314
+ }
3315
+ return (hash >>> 0).toString(16).padStart(8, "0");
3316
+ }
3317
+ var PRELUDE_HASH = fnv1a(PRELUDE_SOURCE);
3318
+ function prng(seed) {
3319
+ let state = seed >>> 0;
3320
+ return () => {
3321
+ state = state + 1831565813 >>> 0;
3322
+ let value = Math.imul(state ^ state >>> 15, 1 | state);
3323
+ value = value + Math.imul(value ^ value >>> 7, 61 | value) ^ value;
3324
+ return (value ^ value >>> 14) >>> 0;
3325
+ };
3326
+ }
3327
+ function deterministicWasi(clock) {
3328
+ const random = prng(clock.seed ^ 2654435769);
3329
+ return (memory) => ({
3330
+ ...discardOutput(memory),
3331
+ clock_time_get(clockId, _precision, resultPtr) {
3332
+ let nanoseconds;
3333
+ if (clock.creating)
3334
+ nanoseconds = clockId === 0 ? BigInt(clock.seed + 1) * 1000n : 0n;
3335
+ else if (clockId === 0)
3336
+ nanoseconds = BigInt(Math.round(clock.now)) * 1000000n;
3337
+ else
3338
+ nanoseconds = BigInt(Math.round(clock.now - clock.startedAt)) * 1000000n;
3339
+ new DataView(memory.buffer).setBigUint64(resultPtr, nanoseconds, true);
3340
+ return 0;
3341
+ },
3342
+ random_get(bufPtr, bufLen) {
3343
+ const bytes = new Uint8Array(memory.buffer, bufPtr, bufLen);
3344
+ for (let index = 0; index < bufLen; index += 4) {
3345
+ const value = random();
3346
+ for (let byte = 0; byte < 4 && index + byte < bufLen; byte++)
3347
+ bytes[index + byte] = value >>> byte * 8;
3348
+ }
3349
+ return 0;
3350
+ }
3351
+ });
3352
+ }
3353
+ function discardOutput(memory) {
3354
+ return {
3355
+ fd_write(_fd, iovsPtr, iovsLen, nwrittenPtr) {
3356
+ const view = new DataView(memory.buffer);
3357
+ let written = 0;
3358
+ for (let i = 0; i < iovsLen; i++) {
3359
+ written += view.getUint32(iovsPtr + i * 8 + 4, true);
3360
+ }
3361
+ view.setUint32(nwrittenPtr, written, true);
3362
+ return 0;
3363
+ }
3364
+ };
3365
+ }
3366
+ function describeException(error) {
3367
+ const head = error.message ? `${error.name}: ${error.message}` : error.name;
3368
+ const stack = error.stack?.trimEnd();
3369
+ return JSON.stringify({ name: error.name, message: error.message, stack: stack ? `${head}
3370
+ ${stack}` : head });
3371
+ }
3372
+ var JOBS_PER_POLL = 50;
3373
+ function crashMessage(error) {
3374
+ return { type: "crash", message: error instanceof Error ? `${error.name}: ${error.message}` : String(error) };
3375
+ }
3376
+ async function startVm(options) {
3377
+ const { data, post: post2 } = options;
3378
+ const maxStackSize = options.maxStackSize ?? MAX_STACK_SIZE;
3379
+ const deterministic = data.deterministic;
3380
+ const clock = deterministic && {
3381
+ creating: true,
3382
+ startedAt: deterministic.startedAt,
3383
+ now: deterministic.startedAt,
3384
+ seed: deterministic.seed >>> 0
3385
+ };
3386
+ const vm = await QuickJS.create({
3387
+ wasm: options.wasm,
3388
+ memoryLimit: data.memoryLimitBytes,
3389
+ // Without a guard, deep recursion overflows the wasm stack and traps instead of throwing a
3390
+ // catchable RangeError.
3391
+ maxStackSize,
3392
+ interruptHandler: options.shouldInterrupt,
3393
+ wasi: clock ? deterministicWasi(clock) : discardOutput,
3394
+ ...clock ? { timezoneOffset: 0, intrinsics: Intrinsics.ALL & ~Intrinsics.WEAK_REF } : {}
3395
+ });
3396
+ if (clock)
3397
+ clock.creating = false;
3398
+ let disposed = false;
3399
+ let issued = 0;
3400
+ let nextSeq = 1;
3401
+ let current = 0;
3402
+ const early = /* @__PURE__ */ new Map();
3403
+ const apply = (message) => {
3404
+ vm.withScope(() => {
3405
+ vm.callFunction(settle, api, vm.newNumber(message.id), message.ok ? vm.true : vm.false, message.payload === void 0 ? vm.undefined : vm.newString(message.payload), message.properties === void 0 ? vm.undefined : vm.newString(message.properties));
3406
+ });
3407
+ drain();
3408
+ };
3409
+ const session = {
3410
+ deliver(message) {
3411
+ if (disposed)
3412
+ return;
3413
+ try {
3414
+ if (!clock) {
3415
+ apply(message);
3416
+ return;
3417
+ }
3418
+ const { seq } = message;
3419
+ if (seq === void 0 || !Number.isInteger(seq) || seq < nextSeq || early.has(seq)) {
3420
+ throw new Error(`Result ${message.id} has sequence number ${seq}, expected ${nextSeq} or later, once`);
3421
+ }
3422
+ early.set(seq, message);
3423
+ for (let next = early.get(nextSeq); next !== void 0; next = early.get(nextSeq)) {
3424
+ early.delete(nextSeq);
3425
+ if (next.now !== void 0 && Number.isFinite(next.now))
3426
+ clock.now = Math.max(clock.now, next.now);
3427
+ current = nextSeq;
3428
+ apply(next);
3429
+ post2({ type: "idle", seq: nextSeq, issued });
3430
+ nextSeq++;
3431
+ }
3432
+ } catch (error) {
3433
+ post2(crashMessage(error));
3434
+ }
3435
+ },
3436
+ dispose() {
3437
+ if (disposed)
3438
+ return;
3439
+ disposed = true;
3440
+ vm.dispose();
3441
+ }
3442
+ };
3443
+ let api;
3444
+ let settle;
3445
+ let stalled;
3446
+ const exports = vm._getExports();
3447
+ const drain = () => {
3448
+ let jobs = 0;
3449
+ while (exports.qjs_is_job_pending()) {
3450
+ if (exports.qjs_execute_pending_job() < 0)
3451
+ throw new Error("Promise job failed");
3452
+ if (++jobs % JOBS_PER_POLL === 0 && options.shouldInterrupt())
3453
+ throw new Error("Execution interrupted");
3454
+ }
3455
+ vm.callFunction(stalled, api).dispose();
3456
+ };
3457
+ try {
3458
+ const bridge = vm.newFunction("bridge", (kind, a, b, c) => {
3459
+ switch (kind.toString()) {
3460
+ case "call":
3461
+ case "global":
3462
+ issued++;
3463
+ post2({
3464
+ type: "call",
3465
+ id: a.toNumber(),
3466
+ target: kind.toString() === "call" ? "tool" : "global",
3467
+ name: b.toString(),
3468
+ args: c === void 0 || c.isUndefined ? void 0 : c.toString()
3469
+ });
3470
+ break;
3471
+ case "output":
3472
+ post2({
3473
+ type: "output",
3474
+ item: a.toString() === "image" ? { type: "image", data: b.toString(), mimeType: c.toString() } : a.toString() === "console" ? { type: "text", text: b.toString(), console: true } : { type: "text", text: b.toString() }
3475
+ });
3476
+ break;
3477
+ case "done": {
3478
+ const during = clock ? { during: { seq: current, issued } } : {};
3479
+ if (a.toBoolean()) {
3480
+ post2({
3481
+ type: "done",
3482
+ ok: true,
3483
+ value: b === void 0 || b.isUndefined ? void 0 : b.toString(),
3484
+ writes: c.toString(),
3485
+ ...during
3486
+ });
3487
+ } else {
3488
+ post2({ type: "done", ok: false, error: b.toString(), ...during });
3489
+ }
3490
+ break;
3491
+ }
3492
+ }
3493
+ return vm.undefined;
3494
+ });
3495
+ api = vm.withScope((scope) => scope.escape(vm.callFunction(vm.evalCode(PRELUDE_SOURCE, "codemode-prelude.js"), vm.undefined, bridge, vm.newString(JSON.stringify(data.tools)), vm.newString(JSON.stringify(data.globals)), vm.newString(JSON.stringify(data.store)))));
3496
+ settle = api.getProp("settle");
3497
+ const run = api.getProp("run");
3498
+ stalled = api.getProp("stalled");
3499
+ if (clock) {
3500
+ const versions = vm.versions;
3501
+ const budget = options.interruptBudget ?? "none";
3502
+ post2({
3503
+ type: "started",
3504
+ fingerprint: `quickjs-wasi ${versions["quickjs-wasi"]}, quickjs ${versions.quickjs}, prelude ${PRELUDE_HASH}, deterministic ${DETERMINISTIC_VERSION}, stack ${maxStackSize}, heap ${data.memoryLimitBytes ?? "none"}, budget ${budget}`
3505
+ });
3506
+ }
3507
+ let fn;
3508
+ try {
3509
+ fn = vm.evalCode(`(async (tools, console) => {${data.code}
3510
+ })`, "codemode.js");
3511
+ } catch (error) {
3512
+ if (!(error instanceof JSException))
3513
+ throw error;
3514
+ post2({ type: "done", ok: false, error: describeException(error) });
3515
+ return session;
3516
+ }
3517
+ vm.callFunction(run, api, fn).dispose();
3518
+ fn.dispose();
3519
+ drain();
3520
+ if (clock)
3521
+ post2({ type: "idle", seq: 0, issued });
3522
+ } catch (error) {
3523
+ post2(crashMessage(error));
3524
+ }
3525
+ return session;
3526
+ }
3527
+
3528
+ // node_modules/@earendil-works/pi-codemode/dist/runtime/worker.js
3529
+ function post(message) {
3530
+ parentPort?.postMessage(message);
3531
+ }
3532
+ async function main(data) {
3533
+ const interrupt = new Int32Array(data.interrupt);
3534
+ const session = await startVm({
3535
+ data,
3536
+ wasm: data.wasm,
3537
+ post,
3538
+ shouldInterrupt: () => Atomics.load(interrupt, 0) !== 0
3539
+ });
3540
+ parentPort?.on("message", (message) => {
3541
+ if (isHostToWorkerMessage(message))
3542
+ session.deliver(message);
3543
+ });
3544
+ }
3545
+ if (parentPort) {
3546
+ main(workerData).catch((error) => {
3547
+ post({ type: "crash", message: error instanceof Error ? `${error.name}: ${error.message}` : String(error) });
3548
+ });
3549
+ }