@ricsam/quickjs-core 0.2.16 → 0.2.17

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.
package/README.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # @ricsam/quickjs-core
2
2
 
3
- Core utilities and Web Streams API.
3
+ Core utilities and Web Streams API for QuickJS runtime bindings.
4
+
5
+ > **Note**: This is a low-level package. For most use cases, use [`@ricsam/quickjs-runtime`](../runtime) with `createRuntime()` instead.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ bun add @ricsam/quickjs-core
11
+ ```
12
+
13
+ ## Setup
4
14
 
5
15
  ```typescript
6
16
  import { setupCore } from "@ricsam/quickjs-core";
@@ -8,12 +18,13 @@ import { setupCore } from "@ricsam/quickjs-core";
8
18
  const handle = setupCore(context);
9
19
  ```
10
20
 
11
- **Injected Globals:**
21
+ ## Injected Globals
22
+
12
23
  - `ReadableStream`, `WritableStream`, `TransformStream`
13
24
  - `ReadableStreamDefaultReader`, `WritableStreamDefaultWriter`
14
25
  - `Blob`, `File`
15
26
 
16
- **Usage in QuickJS:**
27
+ ## Usage in QuickJS
17
28
 
18
29
  ```javascript
19
30
  // Streams
@@ -35,4 +46,100 @@ const text = await blob.text(); // "hello world"
35
46
  // File
36
47
  const file = new File(["content"], "file.txt", { type: "text/plain" });
37
48
  console.log(file.name); // "file.txt"
38
- ```
49
+ ```
50
+
51
+ ## Core Utilities
52
+
53
+ ```typescript
54
+ import {
55
+ // Marshalling
56
+ marshal, // JS value -> QuickJS handle
57
+ unmarshal, // QuickJS handle -> JS value
58
+
59
+ // Handle utilities
60
+ isHandle, // Check if value is a QuickJS handle
61
+ getHandleType, // Get handle type as string
62
+
63
+ // Scope management
64
+ withScope, // Automatic handle cleanup
65
+ withScopeAsync, // Async version
66
+
67
+ // Class/function builders
68
+ defineClass,
69
+ defineFunction,
70
+ defineAsyncFunction,
71
+ defineAsyncIteratorFunction, // For async generators
72
+ cleanupAsyncIterators, // Cleanup on context disposal
73
+
74
+ // State management
75
+ createStateMap,
76
+ getState,
77
+ setState,
78
+ } from "@ricsam/quickjs-core";
79
+ ```
80
+
81
+ ### Marshalling Example
82
+
83
+ ```typescript
84
+ // Marshal JS values to QuickJS
85
+ const handle = marshal(context, {
86
+ name: "test",
87
+ values: [1, 2, 3],
88
+ callback: (x) => x * 2,
89
+ });
90
+
91
+ // Unmarshal QuickJS values to JS
92
+ const value = unmarshal(context, handle);
93
+ ```
94
+
95
+ ### Custom Class Definition
96
+
97
+ ```typescript
98
+ const PointClass = defineClass(context, stateMap, {
99
+ name: "Point",
100
+ construct: ([x, y]) => ({ x: Number(x), y: Number(y) }),
101
+ properties: {
102
+ x: {
103
+ get() { return this.x; },
104
+ set(v) { this.x = Number(v); },
105
+ },
106
+ y: {
107
+ get() { return this.y; },
108
+ set(v) { this.y = Number(v); },
109
+ },
110
+ },
111
+ methods: {
112
+ distance() {
113
+ return Math.sqrt(this.x ** 2 + this.y ** 2);
114
+ },
115
+ },
116
+ });
117
+
118
+ context.setProp(context.global, "Point", PointClass);
119
+ ```
120
+
121
+ ### Async Iterator Function
122
+
123
+ Define functions that return async iterables (for streaming data):
124
+
125
+ ```typescript
126
+ import { defineAsyncIteratorFunction, cleanupAsyncIterators } from "@ricsam/quickjs-core";
127
+
128
+ const streamFn = defineAsyncIteratorFunction(context, "streamNumbers", async function* (count) {
129
+ for (let i = 0; i < Number(count); i++) {
130
+ await new Promise(r => setTimeout(r, 100));
131
+ yield i;
132
+ }
133
+ });
134
+
135
+ context.setProp(context.global, "streamNumbers", streamFn);
136
+ streamFn.dispose();
137
+
138
+ // In QuickJS:
139
+ // for await (const n of streamNumbers(5)) {
140
+ // console.log(n); // 0, 1, 2, 3, 4
141
+ // }
142
+
143
+ // Clean up before context disposal
144
+ cleanupAsyncIterators(context);
145
+ ```
@@ -31,11 +31,160 @@ var __export = (target, all) => {
31
31
  var exports_function_builder = {};
32
32
  __export(exports_function_builder, {
33
33
  defineFunction: () => defineFunction,
34
- defineAsyncFunction: () => defineAsyncFunction
34
+ defineAsyncIteratorFunction: () => defineAsyncIteratorFunction,
35
+ defineAsyncFunction: () => defineAsyncFunction,
36
+ cleanupAsyncIterators: () => cleanupAsyncIterators
35
37
  });
36
38
  module.exports = __toCommonJS(exports_function_builder);
37
39
  var import_unmarshal = require("./unmarshal.cjs");
38
40
  var import_marshal = require("./marshal.cjs");
41
+ var generatorRegistries = new WeakMap;
42
+ var generatorCounters = new WeakMap;
43
+ var setupContexts = new WeakSet;
44
+ function getGeneratorRegistry(context) {
45
+ let registry = generatorRegistries.get(context);
46
+ if (!registry) {
47
+ registry = new Map;
48
+ generatorRegistries.set(context, registry);
49
+ }
50
+ return registry;
51
+ }
52
+ function nextGeneratorId(context) {
53
+ let counter = generatorCounters.get(context);
54
+ if (!counter) {
55
+ counter = { value: 0 };
56
+ generatorCounters.set(context, counter);
57
+ }
58
+ return ++counter.value;
59
+ }
60
+ function registerGenerator(context, generator) {
61
+ const id = nextGeneratorId(context);
62
+ const registry = getGeneratorRegistry(context);
63
+ registry.set(id, generator);
64
+ return id;
65
+ }
66
+ function setupAsyncIteratorInfrastructure(context) {
67
+ if (setupContexts.has(context)) {
68
+ return;
69
+ }
70
+ setupContexts.add(context);
71
+ const nextFn = context.newFunction("__asyncIteratorNext__", (idHandle) => {
72
+ const id = context.getNumber(idHandle);
73
+ const registry = getGeneratorRegistry(context);
74
+ const generator = registry.get(id);
75
+ if (!generator) {
76
+ const deferred2 = context.newPromise();
77
+ const errorHandle = context.newError(`Generator ${id} not found`);
78
+ deferred2.reject(errorHandle);
79
+ errorHandle.dispose();
80
+ context.runtime.executePendingJobs();
81
+ return deferred2.handle;
82
+ }
83
+ const deferred = context.newPromise();
84
+ generator.next().then((result) => {
85
+ if (!context.alive)
86
+ return;
87
+ const resultHandle = import_marshal.marshal(context, {
88
+ value: result.value,
89
+ done: result.done
90
+ });
91
+ deferred.resolve(resultHandle);
92
+ resultHandle.dispose();
93
+ if (result.done) {
94
+ registry.delete(id);
95
+ }
96
+ context.runtime.executePendingJobs();
97
+ }).catch((error) => {
98
+ if (!context.alive)
99
+ return;
100
+ const errorHandle = context.newError(error instanceof Error ? error.message : String(error));
101
+ deferred.reject(errorHandle);
102
+ errorHandle.dispose();
103
+ registry.delete(id);
104
+ context.runtime.executePendingJobs();
105
+ });
106
+ return deferred.handle;
107
+ });
108
+ context.setProp(context.global, "__asyncIteratorNext__", nextFn);
109
+ nextFn.dispose();
110
+ const returnFn = context.newFunction("__asyncIteratorReturn__", (idHandle, valueHandle) => {
111
+ const id = context.getNumber(idHandle);
112
+ const value = import_unmarshal.unmarshal(context, valueHandle);
113
+ const registry = getGeneratorRegistry(context);
114
+ const generator = registry.get(id);
115
+ const deferred = context.newPromise();
116
+ if (!generator) {
117
+ const resultHandle = import_marshal.marshal(context, { value, done: true });
118
+ deferred.resolve(resultHandle);
119
+ resultHandle.dispose();
120
+ context.runtime.executePendingJobs();
121
+ return deferred.handle;
122
+ }
123
+ generator.return(value).then((result) => {
124
+ if (!context.alive)
125
+ return;
126
+ const resultHandle = import_marshal.marshal(context, {
127
+ value: result.value,
128
+ done: result.done
129
+ });
130
+ deferred.resolve(resultHandle);
131
+ resultHandle.dispose();
132
+ registry.delete(id);
133
+ context.runtime.executePendingJobs();
134
+ }).catch((error) => {
135
+ if (!context.alive)
136
+ return;
137
+ const errorHandle = context.newError(error instanceof Error ? error.message : String(error));
138
+ deferred.reject(errorHandle);
139
+ errorHandle.dispose();
140
+ registry.delete(id);
141
+ context.runtime.executePendingJobs();
142
+ });
143
+ return deferred.handle;
144
+ });
145
+ context.setProp(context.global, "__asyncIteratorReturn__", returnFn);
146
+ returnFn.dispose();
147
+ const throwFn = context.newFunction("__asyncIteratorThrow__", (idHandle, errorHandle) => {
148
+ const id = context.getNumber(idHandle);
149
+ const errorValue = import_unmarshal.unmarshal(context, errorHandle);
150
+ const registry = getGeneratorRegistry(context);
151
+ const generator = registry.get(id);
152
+ const deferred = context.newPromise();
153
+ if (!generator) {
154
+ const errHandle = context.newError(errorValue instanceof Error ? errorValue.message : String(errorValue));
155
+ deferred.reject(errHandle);
156
+ errHandle.dispose();
157
+ context.runtime.executePendingJobs();
158
+ return deferred.handle;
159
+ }
160
+ const error = errorValue instanceof Error ? errorValue : new Error(String(errorValue));
161
+ generator.throw(error).then((result) => {
162
+ if (!context.alive)
163
+ return;
164
+ const resultHandle = import_marshal.marshal(context, {
165
+ value: result.value,
166
+ done: result.done
167
+ });
168
+ deferred.resolve(resultHandle);
169
+ resultHandle.dispose();
170
+ if (result.done) {
171
+ registry.delete(id);
172
+ }
173
+ context.runtime.executePendingJobs();
174
+ }).catch((err) => {
175
+ if (!context.alive)
176
+ return;
177
+ const errHandle = context.newError(err instanceof Error ? err.message : String(err));
178
+ deferred.reject(errHandle);
179
+ errHandle.dispose();
180
+ registry.delete(id);
181
+ context.runtime.executePendingJobs();
182
+ });
183
+ return deferred.handle;
184
+ });
185
+ context.setProp(context.global, "__asyncIteratorThrow__", throwFn);
186
+ throwFn.dispose();
187
+ }
39
188
  function defineFunction(context, name, fn) {
40
189
  return context.newFunction(name, (...argHandles) => {
41
190
  const args = argHandles.map((h) => import_unmarshal.unmarshal(context, h));
@@ -71,6 +220,39 @@ function defineAsyncFunction(context, name, fn) {
71
220
  return deferred.handle;
72
221
  });
73
222
  }
223
+ function defineAsyncIteratorFunction(context, name, fn) {
224
+ setupAsyncIteratorInfrastructure(context);
225
+ return context.newFunction(name, (...argHandles) => {
226
+ const args = argHandles.map((h) => import_unmarshal.unmarshal(context, h));
227
+ try {
228
+ const generator = fn(...args);
229
+ const generatorId = registerGenerator(context, generator);
230
+ const result = context.evalCode(`({
231
+ [Symbol.asyncIterator]() {
232
+ return {
233
+ next: () => __asyncIteratorNext__(${generatorId}),
234
+ return: (v) => __asyncIteratorReturn__(${generatorId}, v),
235
+ throw: (e) => __asyncIteratorThrow__(${generatorId}, e)
236
+ };
237
+ }
238
+ })`);
239
+ if (result.error) {
240
+ const err = context.dump(result.error);
241
+ result.error.dispose();
242
+ const registry = getGeneratorRegistry(context);
243
+ registry.delete(generatorId);
244
+ throw context.newError(String(err));
245
+ }
246
+ return result.value;
247
+ } catch (error) {
248
+ throw context.newError(error instanceof Error ? error.message : String(error));
249
+ }
250
+ });
251
+ }
252
+ function cleanupAsyncIterators(context) {
253
+ generatorRegistries.delete(context);
254
+ generatorCounters.delete(context);
255
+ }
74
256
  })
75
257
 
76
- //# debugId=C5D7588C3C8B806E64756E2164756E21
258
+ //# debugId=679B9EDB41D36FF564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/function-builder.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { unmarshal } from \"./unmarshal.cjs\";\nimport { marshal } from \"./marshal.cjs\";\n\n/**\n * Define a global function in the QuickJS context\n *\n * @returns Handle to the function (caller must manage disposal)\n *\n * @example\n * const logFn = defineFunction(context, \"log\", (...args) => {\n * console.log(\"[QuickJS]\", ...args);\n * });\n * context.setProp(context.global, \"log\", logFn);\n */\nexport function defineFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => unknown\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n try {\n // Call host function\n const result = fn(...args);\n\n // Marshal result\n return marshal(context, result);\n } catch (error) {\n // Throw error in QuickJS\n throw context.newError(\n error instanceof Error ? error.message : String(error)\n );\n }\n });\n}\n\n/**\n * Define an async function that returns a promise to QuickJS\n *\n * @example\n * const fetchFn = defineAsyncFunction(context, \"fetch\", async (url) => {\n * const response = await fetch(String(url));\n * return response.text();\n * });\n */\nexport function defineAsyncFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => Promise<unknown>\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n // Create a promise in QuickJS\n const deferred = context.newPromise();\n\n // Call the async function\n fn(...args)\n .then((result) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const resultHandle = marshal(context, result);\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const errorHandle = marshal(\n context,\n error instanceof Error\n ? { name: error.name, message: error.message }\n : { message: String(error) }\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n });\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { unmarshal } from \"./unmarshal.cjs\";\nimport { marshal } from \"./marshal.cjs\";\n\n/**\n * Registry for async generators, scoped per-context.\n * Uses WeakMap to automatically clean up when context is GC'd.\n */\nconst generatorRegistries = new WeakMap<\n QuickJSContext,\n Map<number, AsyncGenerator<unknown, unknown, unknown>>\n>();\n\n/**\n * Counter for generating unique generator IDs per context.\n */\nconst generatorCounters = new WeakMap<QuickJSContext, { value: number }>();\n\n/**\n * Track which contexts have had async iterator infrastructure set up.\n */\nconst setupContexts = new WeakSet<QuickJSContext>();\n\n/**\n * Get or create the generator registry for a context.\n */\nfunction getGeneratorRegistry(\n context: QuickJSContext\n): Map<number, AsyncGenerator<unknown, unknown, unknown>> {\n let registry = generatorRegistries.get(context);\n if (!registry) {\n registry = new Map();\n generatorRegistries.set(context, registry);\n }\n return registry;\n}\n\n/**\n * Get next generator ID for a context.\n */\nfunction nextGeneratorId(context: QuickJSContext): number {\n let counter = generatorCounters.get(context);\n if (!counter) {\n counter = { value: 0 };\n generatorCounters.set(context, counter);\n }\n return ++counter.value;\n}\n\n/**\n * Register a generator and return its ID.\n */\nfunction registerGenerator(\n context: QuickJSContext,\n generator: AsyncGenerator<unknown, unknown, unknown>\n): number {\n const id = nextGeneratorId(context);\n const registry = getGeneratorRegistry(context);\n registry.set(id, generator);\n return id;\n}\n\n/**\n * Setup async iterator infrastructure helpers in the context.\n * These are global functions that proxy to host-side generators.\n */\nfunction setupAsyncIteratorInfrastructure(context: QuickJSContext): void {\n if (setupContexts.has(context)) {\n return;\n }\n setupContexts.add(context);\n\n // __asyncIteratorNext__(id) - calls generator.next()\n const nextFn = context.newFunction(\n \"__asyncIteratorNext__\",\n (idHandle: QuickJSHandle) => {\n const id = context.getNumber(idHandle);\n const registry = getGeneratorRegistry(context);\n const generator = registry.get(id);\n\n if (!generator) {\n // Generator not found - already cleaned up or invalid ID\n const deferred = context.newPromise();\n const errorHandle = context.newError(`Generator ${id} not found`);\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n return deferred.handle;\n }\n\n const deferred = context.newPromise();\n\n generator\n .next()\n .then((result) => {\n if (!context.alive) return;\n\n const resultHandle = marshal(context, {\n value: result.value,\n done: result.done,\n });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n\n // Clean up if done\n if (result.done) {\n registry.delete(id);\n }\n\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n if (!context.alive) return;\n\n // Create a proper Error object for rejection\n const errorHandle = context.newError(\n error instanceof Error ? error.message : String(error)\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n\n // Clean up on error\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n }\n );\n context.setProp(context.global, \"__asyncIteratorNext__\", nextFn);\n nextFn.dispose();\n\n // __asyncIteratorReturn__(id, value) - calls generator.return(value)\n const returnFn = context.newFunction(\n \"__asyncIteratorReturn__\",\n (idHandle: QuickJSHandle, valueHandle: QuickJSHandle) => {\n const id = context.getNumber(idHandle);\n const value = unmarshal(context, valueHandle);\n const registry = getGeneratorRegistry(context);\n const generator = registry.get(id);\n\n const deferred = context.newPromise();\n\n if (!generator) {\n // Generator not found - return a completed result\n const resultHandle = marshal(context, { value, done: true });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n context.runtime.executePendingJobs();\n return deferred.handle;\n }\n\n generator\n .return(value)\n .then((result) => {\n if (!context.alive) return;\n\n const resultHandle = marshal(context, {\n value: result.value,\n done: result.done,\n });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n\n // Always clean up after return\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n if (!context.alive) return;\n\n const errorHandle = context.newError(\n error instanceof Error ? error.message : String(error)\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n }\n );\n context.setProp(context.global, \"__asyncIteratorReturn__\", returnFn);\n returnFn.dispose();\n\n // __asyncIteratorThrow__(id, error) - calls generator.throw(error)\n const throwFn = context.newFunction(\n \"__asyncIteratorThrow__\",\n (idHandle: QuickJSHandle, errorHandle: QuickJSHandle) => {\n const id = context.getNumber(idHandle);\n const errorValue = unmarshal(context, errorHandle);\n const registry = getGeneratorRegistry(context);\n const generator = registry.get(id);\n\n const deferred = context.newPromise();\n\n if (!generator) {\n // Generator not found - reject with a proper error\n const errHandle = context.newError(\n errorValue instanceof Error ? errorValue.message : String(errorValue)\n );\n deferred.reject(errHandle);\n errHandle.dispose();\n context.runtime.executePendingJobs();\n return deferred.handle;\n }\n\n // Convert to Error if needed\n const error =\n errorValue instanceof Error\n ? errorValue\n : new Error(String(errorValue));\n\n generator\n .throw(error)\n .then((result) => {\n if (!context.alive) return;\n\n const resultHandle = marshal(context, {\n value: result.value,\n done: result.done,\n });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n\n if (result.done) {\n registry.delete(id);\n }\n\n context.runtime.executePendingJobs();\n })\n .catch((err) => {\n if (!context.alive) return;\n\n const errHandle = context.newError(\n err instanceof Error ? err.message : String(err)\n );\n deferred.reject(errHandle);\n errHandle.dispose();\n\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n }\n );\n context.setProp(context.global, \"__asyncIteratorThrow__\", throwFn);\n throwFn.dispose();\n}\n\n/**\n * Define a global function in the QuickJS context\n *\n * @returns Handle to the function (caller must manage disposal)\n *\n * @example\n * const logFn = defineFunction(context, \"log\", (...args) => {\n * console.log(\"[QuickJS]\", ...args);\n * });\n * context.setProp(context.global, \"log\", logFn);\n */\nexport function defineFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => unknown\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n try {\n // Call host function\n const result = fn(...args);\n\n // Marshal result\n return marshal(context, result);\n } catch (error) {\n // Throw error in QuickJS\n throw context.newError(\n error instanceof Error ? error.message : String(error)\n );\n }\n });\n}\n\n/**\n * Define an async function that returns a promise to QuickJS\n *\n * @example\n * const fetchFn = defineAsyncFunction(context, \"fetch\", async (url) => {\n * const response = await fetch(String(url));\n * return response.text();\n * });\n */\nexport function defineAsyncFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => Promise<unknown>\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n // Create a promise in QuickJS\n const deferred = context.newPromise();\n\n // Call the async function\n fn(...args)\n .then((result) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const resultHandle = marshal(context, result);\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const errorHandle = marshal(\n context,\n error instanceof Error\n ? { name: error.name, message: error.message }\n : { message: String(error) }\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n });\n}\n\n/**\n * Define an async iterator function that returns an async iterable to QuickJS.\n * The host function should be an async generator.\n *\n * @example\n * const streamFn = defineAsyncIteratorFunction(context, \"stream\", async function* (n) {\n * for (let i = 0; i < n; i++) {\n * yield i;\n * }\n * return \"done\";\n * });\n *\n * // In QuickJS:\n * // for await (const value of stream(3)) { console.log(value); }\n * // Outputs: 0, 1, 2\n */\nexport function defineAsyncIteratorFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => AsyncGenerator<unknown, unknown, unknown>\n): QuickJSHandle {\n // Ensure infrastructure is set up\n setupAsyncIteratorInfrastructure(context);\n\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n try {\n // Call host function to get generator instance\n const generator = fn(...args);\n\n // Register generator and get ID\n const generatorId = registerGenerator(context, generator);\n\n // Create proxy object that implements async iterator protocol\n // This object when iterated will call our infrastructure helpers\n const result = context.evalCode(`({\n [Symbol.asyncIterator]() {\n return {\n next: () => __asyncIteratorNext__(${generatorId}),\n return: (v) => __asyncIteratorReturn__(${generatorId}, v),\n throw: (e) => __asyncIteratorThrow__(${generatorId}, e)\n };\n }\n })`);\n\n if (result.error) {\n const err = context.dump(result.error);\n result.error.dispose();\n // Clean up the registered generator since we failed\n const registry = getGeneratorRegistry(context);\n registry.delete(generatorId);\n throw context.newError(String(err));\n }\n\n return result.value;\n } catch (error) {\n // Throw error in QuickJS\n throw context.newError(\n error instanceof Error ? error.message : String(error)\n );\n }\n });\n}\n\n/**\n * Clean up all async iterator state for a context.\n * Should be called before context disposal.\n */\nexport function cleanupAsyncIterators(context: QuickJSContext): void {\n generatorRegistries.delete(context);\n generatorCounters.delete(context);\n // Note: setupContexts uses WeakSet, so no need to explicitly delete\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAC0B,IAA1B;AACwB,IAAxB;AAaO,SAAS,cAAc,CAC5B,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,2BAAU,SAAS,CAAC,CAAC;AAAA,IAExD,IAAI;AAAA,MAEF,MAAM,SAAS,GAAG,GAAG,IAAI;AAAA,MAGzB,OAAO,uBAAQ,SAAS,MAAM;AAAA,MAC9B,OAAO,OAAO;AAAA,MAEd,MAAM,QAAQ,SACZ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA;AAAA,GAEH;AAAA;AAYI,SAAS,mBAAmB,CACjC,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,2BAAU,SAAS,CAAC,CAAC;AAAA,IAGxD,MAAM,WAAW,QAAQ,WAAW;AAAA,IAGpC,GAAG,GAAG,IAAI,EACP,KAAK,CAAC,WAAW;AAAA,MAEhB,IAAI,CAAC,QAAQ,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,MACA,MAAM,eAAe,uBAAQ,SAAS,MAAM;AAAA,MAC5C,SAAS,QAAQ,YAAY;AAAA,MAC7B,aAAa,QAAQ;AAAA,MACrB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC,EACA,MAAM,CAAC,UAAU;AAAA,MAEhB,IAAI,CAAC,QAAQ,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,MACA,MAAM,cAAc,uBAClB,SACA,iBAAiB,QACb,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ,IAC3C,EAAE,SAAS,OAAO,KAAK,EAAE,CAC/B;AAAA,MACA,SAAS,OAAO,WAAW;AAAA,MAC3B,YAAY,QAAQ;AAAA,MACpB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC;AAAA,IAEH,OAAO,SAAS;AAAA,GACjB;AAAA;",
8
- "debugId": "C5D7588C3C8B806E64756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAC0B,IAA1B;AACwB,IAAxB;AAMA,IAAM,sBAAsB,IAAI;AAQhC,IAAM,oBAAoB,IAAI;AAK9B,IAAM,gBAAgB,IAAI;AAK1B,SAAS,oBAAoB,CAC3B,SACwD;AAAA,EACxD,IAAI,WAAW,oBAAoB,IAAI,OAAO;AAAA,EAC9C,IAAI,CAAC,UAAU;AAAA,IACb,WAAW,IAAI;AAAA,IACf,oBAAoB,IAAI,SAAS,QAAQ;AAAA,EAC3C;AAAA,EACA,OAAO;AAAA;AAMT,SAAS,eAAe,CAAC,SAAiC;AAAA,EACxD,IAAI,UAAU,kBAAkB,IAAI,OAAO;AAAA,EAC3C,IAAI,CAAC,SAAS;AAAA,IACZ,UAAU,EAAE,OAAO,EAAE;AAAA,IACrB,kBAAkB,IAAI,SAAS,OAAO;AAAA,EACxC;AAAA,EACA,OAAO,EAAE,QAAQ;AAAA;AAMnB,SAAS,iBAAiB,CACxB,SACA,WACQ;AAAA,EACR,MAAM,KAAK,gBAAgB,OAAO;AAAA,EAClC,MAAM,WAAW,qBAAqB,OAAO;AAAA,EAC7C,SAAS,IAAI,IAAI,SAAS;AAAA,EAC1B,OAAO;AAAA;AAOT,SAAS,gCAAgC,CAAC,SAA+B;AAAA,EACvE,IAAI,cAAc,IAAI,OAAO,GAAG;AAAA,IAC9B;AAAA,EACF;AAAA,EACA,cAAc,IAAI,OAAO;AAAA,EAGzB,MAAM,SAAS,QAAQ,YACrB,yBACA,CAAC,aAA4B;AAAA,IAC3B,MAAM,KAAK,QAAQ,UAAU,QAAQ;AAAA,IACrC,MAAM,WAAW,qBAAqB,OAAO;AAAA,IAC7C,MAAM,YAAY,SAAS,IAAI,EAAE;AAAA,IAEjC,IAAI,CAAC,WAAW;AAAA,MAEd,MAAM,YAAW,QAAQ,WAAW;AAAA,MACpC,MAAM,cAAc,QAAQ,SAAS,aAAa,cAAc;AAAA,MAChE,UAAS,OAAO,WAAW;AAAA,MAC3B,YAAY,QAAQ;AAAA,MACpB,QAAQ,QAAQ,mBAAmB;AAAA,MACnC,OAAO,UAAS;AAAA,IAClB;AAAA,IAEA,MAAM,WAAW,QAAQ,WAAW;AAAA,IAEpC,UACG,KAAK,EACL,KAAK,CAAC,WAAW;AAAA,MAChB,IAAI,CAAC,QAAQ;AAAA,QAAO;AAAA,MAEpB,MAAM,eAAe,uBAAQ,SAAS;AAAA,QACpC,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,MACf,CAAC;AAAA,MACD,SAAS,QAAQ,YAAY;AAAA,MAC7B,aAAa,QAAQ;AAAA,MAGrB,IAAI,OAAO,MAAM;AAAA,QACf,SAAS,OAAO,EAAE;AAAA,MACpB;AAAA,MAEA,QAAQ,QAAQ,mBAAmB;AAAA,KACpC,EACA,MAAM,CAAC,UAAU;AAAA,MAChB,IAAI,CAAC,QAAQ;AAAA,QAAO;AAAA,MAGpB,MAAM,cAAc,QAAQ,SAC1B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA,MACA,SAAS,OAAO,WAAW;AAAA,MAC3B,YAAY,QAAQ;AAAA,MAGpB,SAAS,OAAO,EAAE;AAAA,MAElB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC;AAAA,IAEH,OAAO,SAAS;AAAA,GAEpB;AAAA,EACA,QAAQ,QAAQ,QAAQ,QAAQ,yBAAyB,MAAM;AAAA,EAC/D,OAAO,QAAQ;AAAA,EAGf,MAAM,WAAW,QAAQ,YACvB,2BACA,CAAC,UAAyB,gBAA+B;AAAA,IACvD,MAAM,KAAK,QAAQ,UAAU,QAAQ;AAAA,IACrC,MAAM,QAAQ,2BAAU,SAAS,WAAW;AAAA,IAC5C,MAAM,WAAW,qBAAqB,OAAO;AAAA,IAC7C,MAAM,YAAY,SAAS,IAAI,EAAE;AAAA,IAEjC,MAAM,WAAW,QAAQ,WAAW;AAAA,IAEpC,IAAI,CAAC,WAAW;AAAA,MAEd,MAAM,eAAe,uBAAQ,SAAS,EAAE,OAAO,MAAM,KAAK,CAAC;AAAA,MAC3D,SAAS,QAAQ,YAAY;AAAA,MAC7B,aAAa,QAAQ;AAAA,MACrB,QAAQ,QAAQ,mBAAmB;AAAA,MACnC,OAAO,SAAS;AAAA,IAClB;AAAA,IAEA,UACG,OAAO,KAAK,EACZ,KAAK,CAAC,WAAW;AAAA,MAChB,IAAI,CAAC,QAAQ;AAAA,QAAO;AAAA,MAEpB,MAAM,eAAe,uBAAQ,SAAS;AAAA,QACpC,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,MACf,CAAC;AAAA,MACD,SAAS,QAAQ,YAAY;AAAA,MAC7B,aAAa,QAAQ;AAAA,MAGrB,SAAS,OAAO,EAAE;AAAA,MAElB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC,EACA,MAAM,CAAC,UAAU;AAAA,MAChB,IAAI,CAAC,QAAQ;AAAA,QAAO;AAAA,MAEpB,MAAM,cAAc,QAAQ,SAC1B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA,MACA,SAAS,OAAO,WAAW;AAAA,MAC3B,YAAY,QAAQ;AAAA,MAEpB,SAAS,OAAO,EAAE;AAAA,MAElB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC;AAAA,IAEH,OAAO,SAAS;AAAA,GAEpB;AAAA,EACA,QAAQ,QAAQ,QAAQ,QAAQ,2BAA2B,QAAQ;AAAA,EACnE,SAAS,QAAQ;AAAA,EAGjB,MAAM,UAAU,QAAQ,YACtB,0BACA,CAAC,UAAyB,gBAA+B;AAAA,IACvD,MAAM,KAAK,QAAQ,UAAU,QAAQ;AAAA,IACrC,MAAM,aAAa,2BAAU,SAAS,WAAW;AAAA,IACjD,MAAM,WAAW,qBAAqB,OAAO;AAAA,IAC7C,MAAM,YAAY,SAAS,IAAI,EAAE;AAAA,IAEjC,MAAM,WAAW,QAAQ,WAAW;AAAA,IAEpC,IAAI,CAAC,WAAW;AAAA,MAEd,MAAM,YAAY,QAAQ,SACxB,sBAAsB,QAAQ,WAAW,UAAU,OAAO,UAAU,CACtE;AAAA,MACA,SAAS,OAAO,SAAS;AAAA,MACzB,UAAU,QAAQ;AAAA,MAClB,QAAQ,QAAQ,mBAAmB;AAAA,MACnC,OAAO,SAAS;AAAA,IAClB;AAAA,IAGA,MAAM,QACJ,sBAAsB,QAClB,aACA,IAAI,MAAM,OAAO,UAAU,CAAC;AAAA,IAElC,UACG,MAAM,KAAK,EACX,KAAK,CAAC,WAAW;AAAA,MAChB,IAAI,CAAC,QAAQ;AAAA,QAAO;AAAA,MAEpB,MAAM,eAAe,uBAAQ,SAAS;AAAA,QACpC,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,MACf,CAAC;AAAA,MACD,SAAS,QAAQ,YAAY;AAAA,MAC7B,aAAa,QAAQ;AAAA,MAErB,IAAI,OAAO,MAAM;AAAA,QACf,SAAS,OAAO,EAAE;AAAA,MACpB;AAAA,MAEA,QAAQ,QAAQ,mBAAmB;AAAA,KACpC,EACA,MAAM,CAAC,QAAQ;AAAA,MACd,IAAI,CAAC,QAAQ;AAAA,QAAO;AAAA,MAEpB,MAAM,YAAY,QAAQ,SACxB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA,MACA,SAAS,OAAO,SAAS;AAAA,MACzB,UAAU,QAAQ;AAAA,MAElB,SAAS,OAAO,EAAE;AAAA,MAElB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC;AAAA,IAEH,OAAO,SAAS;AAAA,GAEpB;AAAA,EACA,QAAQ,QAAQ,QAAQ,QAAQ,0BAA0B,OAAO;AAAA,EACjE,QAAQ,QAAQ;AAAA;AAcX,SAAS,cAAc,CAC5B,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,2BAAU,SAAS,CAAC,CAAC;AAAA,IAExD,IAAI;AAAA,MAEF,MAAM,SAAS,GAAG,GAAG,IAAI;AAAA,MAGzB,OAAO,uBAAQ,SAAS,MAAM;AAAA,MAC9B,OAAO,OAAO;AAAA,MAEd,MAAM,QAAQ,SACZ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA;AAAA,GAEH;AAAA;AAYI,SAAS,mBAAmB,CACjC,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,2BAAU,SAAS,CAAC,CAAC;AAAA,IAGxD,MAAM,WAAW,QAAQ,WAAW;AAAA,IAGpC,GAAG,GAAG,IAAI,EACP,KAAK,CAAC,WAAW;AAAA,MAEhB,IAAI,CAAC,QAAQ,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,MACA,MAAM,eAAe,uBAAQ,SAAS,MAAM;AAAA,MAC5C,SAAS,QAAQ,YAAY;AAAA,MAC7B,aAAa,QAAQ;AAAA,MACrB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC,EACA,MAAM,CAAC,UAAU;AAAA,MAEhB,IAAI,CAAC,QAAQ,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,MACA,MAAM,cAAc,uBAClB,SACA,iBAAiB,QACb,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ,IAC3C,EAAE,SAAS,OAAO,KAAK,EAAE,CAC/B;AAAA,MACA,SAAS,OAAO,WAAW;AAAA,MAC3B,YAAY,QAAQ;AAAA,MACpB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC;AAAA,IAEH,OAAO,SAAS;AAAA,GACjB;AAAA;AAmBI,SAAS,2BAA2B,CACzC,SACA,MACA,IACe;AAAA,EAEf,iCAAiC,OAAO;AAAA,EAExC,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,2BAAU,SAAS,CAAC,CAAC;AAAA,IAExD,IAAI;AAAA,MAEF,MAAM,YAAY,GAAG,GAAG,IAAI;AAAA,MAG5B,MAAM,cAAc,kBAAkB,SAAS,SAAS;AAAA,MAIxD,MAAM,SAAS,QAAQ,SAAS;AAAA;AAAA;AAAA,gDAGU;AAAA,qDACK;AAAA,mDACF;AAAA;AAAA;AAAA,SAG1C;AAAA,MAEH,IAAI,OAAO,OAAO;AAAA,QAChB,MAAM,MAAM,QAAQ,KAAK,OAAO,KAAK;AAAA,QACrC,OAAO,MAAM,QAAQ;AAAA,QAErB,MAAM,WAAW,qBAAqB,OAAO;AAAA,QAC7C,SAAS,OAAO,WAAW;AAAA,QAC3B,MAAM,QAAQ,SAAS,OAAO,GAAG,CAAC;AAAA,MACpC;AAAA,MAEA,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MAEd,MAAM,QAAQ,SACZ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA;AAAA,GAEH;AAAA;AAOI,SAAS,qBAAqB,CAAC,SAA+B;AAAA,EACnE,oBAAoB,OAAO,OAAO;AAAA,EAClC,kBAAkB,OAAO,OAAO;AAAA;",
8
+ "debugId": "679B9EDB41D36FF564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -58,6 +58,7 @@ __export(exports_src, {
58
58
  getClassInstanceState: () => import_class_helpers.getClassInstanceState,
59
59
  defineFunction: () => import_function_builder.defineFunction,
60
60
  defineClass: () => import_class_builder2.defineClass,
61
+ defineAsyncIteratorFunction: () => import_function_builder.defineAsyncIteratorFunction,
61
62
  defineAsyncFunction: () => import_function_builder.defineAsyncFunction,
62
63
  createWritableStream: () => import_writable_stream2.createWritableStream,
63
64
  createURLSearchParamsClass: () => import_url_search_params2.createURLSearchParamsClass,
@@ -79,6 +80,7 @@ __export(exports_src, {
79
80
  cleanupUnmarshaledHandles: () => import_unmarshal.cleanupUnmarshaledHandles,
80
81
  cleanupInstanceStateById: () => import_instance_state.cleanupInstanceState,
81
82
  cleanupInstanceState: () => import_class_builder2.cleanupInstanceState,
83
+ cleanupAsyncIterators: () => import_function_builder.cleanupAsyncIterators,
82
84
  classCoercer: () => import_coerce.classCoercer,
83
85
  addURLSearchParamsLinkage: () => import_url2.addURLSearchParamsLinkage,
84
86
  addURLSearchParamsGetter: () => import_url2.addURLSearchParamsGetter,
@@ -285,4 +287,4 @@ function setupCore(context, options) {
285
287
  }
286
288
  })
287
289
 
288
- //# debugId=AAC8B5BEA5BE896D64756E2164756E21
290
+ //# debugId=2704213322BFE26C64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { SetupCoreOptions, CoreHandle, StateMap } from \"./types.cjs\";\nimport { createStateMap } from \"./class-builder.cjs\";\nimport {\n createReadableStreamClass,\n createReadableStreamDefaultReaderClass,\n createReadableStream,\n} from \"./streams/readable-stream.cjs\";\nimport {\n createWritableStreamClass,\n createWritableStreamDefaultWriterClass,\n} from \"./streams/writable-stream.cjs\";\nimport { createTransformStreamClass } from \"./streams/transform-stream.cjs\";\nimport { createBlobClass } from \"./blob.cjs\";\nimport { createFileClass } from \"./file.cjs\";\nimport { createDOMExceptionClass } from \"./dom-exception.cjs\";\nimport { createURLSearchParamsClass } from \"./url-search-params.cjs\";\nimport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.cjs\";\n\n/**\n * Setup core APIs in a QuickJS context\n *\n * Injects the following globals:\n * - ReadableStream, WritableStream, TransformStream\n * - ReadableStreamDefaultReader, WritableStreamDefaultWriter\n * - Blob\n * - File\n * - DOMException\n * - URL, URLSearchParams\n * - TextEncoder, TextDecoder\n *\n * @example\n * const handle = setupCore(context);\n *\n * context.evalCode(`\n * const blob = new Blob([\"hello\", \" \", \"world\"], { type: \"text/plain\" });\n * const text = await blob.text(); // \"hello world\"\n *\n * const stream = new ReadableStream({\n * start(controller) {\n * controller.enqueue(\"chunk1\");\n * controller.enqueue(\"chunk2\");\n * controller.close();\n * }\n * });\n * `);\n */\nexport function setupCore(\n context: QuickJSContext,\n options?: SetupCoreOptions\n): CoreHandle {\n const stateMap = options?.stateMap ?? createStateMap();\n const handles: { name: string; handle: QuickJSHandle }[] = [];\n\n // Create ReadableStreamDefaultReader class first\n const ReadableStreamDefaultReader = createReadableStreamDefaultReaderClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"ReadableStreamDefaultReader\",\n ReadableStreamDefaultReader\n );\n ReadableStreamDefaultReader.dispose();\n\n // Create ReadableStream class\n const readerClassRef = context.getProp(context.global, \"ReadableStreamDefaultReader\");\n const ReadableStream = createReadableStreamClass(\n context,\n stateMap,\n readerClassRef\n );\n readerClassRef.dispose();\n context.setProp(context.global, \"ReadableStream\", ReadableStream);\n ReadableStream.dispose();\n\n // Create WritableStreamDefaultWriter class first\n const WritableStreamDefaultWriter = createWritableStreamDefaultWriterClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"WritableStreamDefaultWriter\",\n WritableStreamDefaultWriter\n );\n WritableStreamDefaultWriter.dispose();\n\n // Create WritableStream class\n const writerClassRef = context.getProp(context.global, \"WritableStreamDefaultWriter\");\n const WritableStream = createWritableStreamClass(\n context,\n stateMap,\n writerClassRef\n );\n writerClassRef.dispose();\n context.setProp(context.global, \"WritableStream\", WritableStream);\n WritableStream.dispose();\n\n // Create TransformStream class\n const TransformStream = createTransformStreamClass(context, stateMap);\n context.setProp(context.global, \"TransformStream\", TransformStream);\n TransformStream.dispose();\n\n // Create Blob class with stream factory\n const BlobClass = createBlobClass(context, stateMap, (source) =>\n createReadableStream(context, stateMap, source)\n );\n context.setProp(context.global, \"Blob\", BlobClass);\n BlobClass.dispose();\n\n // Create File class (extends Blob)\n const blobClassRef = context.getProp(context.global, \"Blob\");\n const FileClass = createFileClass(context, stateMap, blobClassRef);\n blobClassRef.dispose();\n context.setProp(context.global, \"File\", FileClass);\n FileClass.dispose();\n\n // Create DOMException class\n const DOMExceptionClass = createDOMExceptionClass(context, stateMap);\n context.setProp(context.global, \"DOMException\", DOMExceptionClass);\n DOMExceptionClass.dispose();\n\n // Create URLSearchParams class\n const URLSearchParamsClass = createURLSearchParamsClass(context, stateMap);\n context.setProp(context.global, \"URLSearchParams\", URLSearchParamsClass);\n URLSearchParamsClass.dispose();\n\n // Add Symbol.iterator support for URLSearchParams\n const urlSearchParamsIteratorResult = context.evalCode(`\n URLSearchParams.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (urlSearchParamsIteratorResult.error) {\n urlSearchParamsIteratorResult.error.dispose();\n } else {\n urlSearchParamsIteratorResult.value.dispose();\n }\n\n // Create URL class (depends on URLSearchParams)\n const URLClass = createURLClass(context, stateMap);\n context.setProp(context.global, \"URL\", URLClass);\n URLClass.dispose();\n\n // Add searchParams getter to URL that returns URLSearchParams instance\n // Uses JavaScript closures to sync URLSearchParams mutations back to URL\n addURLSearchParamsLinkage(context);\n\n // TextEncoder/TextDecoder - pure JS implementation for UTF-8\n const textEncodingCode = `\n(function() {\n class TextEncoder {\n constructor(encoding = \"utf-8\") {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n }\n\n encode(input = \"\") {\n const str = String(input);\n const bytes = [];\n\n for (let i = 0; i < str.length; i++) {\n let charCode = str.charCodeAt(i);\n\n if (charCode < 0x80) {\n bytes.push(charCode);\n } else if (charCode < 0x800) {\n bytes.push(0xC0 | (charCode >> 6));\n bytes.push(0x80 | (charCode & 0x3F));\n } else if (charCode >= 0xD800 && charCode <= 0xDBFF) {\n const nextCharCode = str.charCodeAt(++i);\n if (nextCharCode >= 0xDC00 && nextCharCode <= 0xDFFF) {\n const codePoint = 0x10000 + ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00);\n bytes.push(0xF0 | (codePoint >> 18));\n bytes.push(0x80 | ((codePoint >> 12) & 0x3F));\n bytes.push(0x80 | ((codePoint >> 6) & 0x3F));\n bytes.push(0x80 | (codePoint & 0x3F));\n }\n } else if (charCode < 0x10000) {\n bytes.push(0xE0 | (charCode >> 12));\n bytes.push(0x80 | ((charCode >> 6) & 0x3F));\n bytes.push(0x80 | (charCode & 0x3F));\n }\n }\n\n return new Uint8Array(bytes);\n }\n\n encodeInto(source, destination) {\n const encoded = this.encode(source);\n const len = Math.min(encoded.length, destination.length);\n destination.set(encoded.subarray(0, len));\n return { read: source.length, written: len };\n }\n }\n\n class TextDecoder {\n constructor(encoding = \"utf-8\", options = {}) {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n this.fatal = Boolean(options.fatal);\n this.ignoreBOM = Boolean(options.ignoreBOM);\n }\n\n decode(input, options = {}) {\n if (!input) return \"\";\n\n let bytes;\n if (input instanceof ArrayBuffer) {\n bytes = new Uint8Array(input);\n } else if (ArrayBuffer.isView(input)) {\n bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);\n } else if (input instanceof Uint8Array) {\n bytes = input;\n } else {\n throw new TypeError(\"The provided value is not of type '(ArrayBuffer or ArrayBufferView)'\");\n }\n\n let offset = 0;\n if (!this.ignoreBOM && bytes.length >= 3 &&\n bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) {\n offset = 3;\n }\n\n let result = \"\";\n for (let i = offset; i < bytes.length;) {\n const byte1 = bytes[i++];\n\n if (byte1 < 0x80) {\n result += String.fromCharCode(byte1);\n } else if ((byte1 & 0xE0) === 0xC0) {\n const byte2 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x1F) << 6) | byte2);\n } else if ((byte1 & 0xF0) === 0xE0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3);\n } else if ((byte1 & 0xF8) === 0xF0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n const byte4 = bytes[i++] & 0x3F;\n const codePoint = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4;\n const adjusted = codePoint - 0x10000;\n result += String.fromCharCode(0xD800 + (adjusted >> 10), 0xDC00 + (adjusted & 0x3FF));\n }\n }\n\n return result;\n }\n }\n\n globalThis.TextEncoder = TextEncoder;\n globalThis.TextDecoder = TextDecoder;\n})();\n`;\n\n const textEncodingResult = context.evalCode(textEncodingCode);\n if (textEncodingResult.error) {\n console.error(\"Failed to setup TextEncoder/TextDecoder\");\n textEncodingResult.error.dispose();\n } else {\n textEncodingResult.value.dispose();\n }\n\n /**\n * @returns CoreHandle with shared stateMap and dispose method\n *\n * **dispose() behavior:**\n * - Clears internal handle tracking array\n * - Does NOT dispose globals (ReadableStream, Blob, etc.) - they are owned\n * by context.global and cleaned up by context.dispose()\n * - Call before context.dispose() to release internal references\n *\n * @see PATTERNS.md for implementation patterns\n */\n return {\n stateMap,\n dispose() {\n // Note: handles set on global (ReadableStream, Blob, etc.) are NOT disposed here\n // They are owned by the global object and will be cleaned up by context.dispose()\n // Disposing them before context disposal causes QuickJS GC assertion failures\n handles.length = 0;\n },\n };\n}\n\n// Re-export types\nexport type {\n Scope,\n MarshalOptions,\n UnmarshalOptions,\n PropertyDescriptor,\n ClassDefinition,\n StateMap,\n SetupCoreOptions,\n CoreHandle,\n QuickJSContext,\n QuickJSHandle,\n QuickJSRuntime,\n} from \"./types.cjs\";\nexport { INTERNAL_STATE } from \"./types.cjs\";\n\n// Re-export utilities\nexport { withScope, withScopeAsync } from \"./scope.cjs\";\nexport { marshal, isHandle, getHandleType } from \"./marshal.cjs\";\nexport { unmarshal, cleanupUnmarshaledHandles } from \"./unmarshal.cjs\";\nexport { defineFunction, defineAsyncFunction } from \"./function-builder.cjs\";\nexport {\n defineClass,\n createStateMap,\n getState,\n setState,\n getInstanceState,\n setInstanceState,\n getInstanceStateById,\n cleanupInstanceState,\n clearAllInstanceState,\n} from \"./class-builder.cjs\";\n\n// Re-export class instance helpers for cross-class access\nexport {\n isDefineClassInstance,\n isInstanceOf,\n getClassInstanceState,\n getInstanceId,\n getClassName,\n createClassTypeGuard,\n isUnmarshalledRequest,\n isUnmarshalledResponse,\n isUnmarshalledHeaders,\n isUnmarshalledFormData,\n} from \"./class-helpers.cjs\";\nexport type { DefineClassInstance, TypedClassInstance } from \"./class-helpers.cjs\";\n\n// Re-export instance state management\nexport {\n nextInstanceId,\n registerInstance,\n getInstanceMetadata,\n getInstanceClassName,\n cleanupInstanceState as cleanupInstanceStateById,\n} from \"./instance-state.cjs\";\nexport type { InstanceMetadata } from \"./instance-state.cjs\";\n\n// Re-export stream utilities\nexport {\n createReadableStream,\n consumeReadableStream,\n} from \"./streams/readable-stream.cjs\";\nexport { createWritableStream } from \"./streams/writable-stream.cjs\";\n\n// Re-export Blob/File utilities\nexport { createBlob } from \"./blob.cjs\";\nexport { createFile } from \"./file.cjs\";\n\n// Re-export URL utilities\nexport { createURLSearchParamsClass } from \"./url-search-params.cjs\";\nexport type { URLSearchParamsState } from \"./url-search-params.cjs\";\nexport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.cjs\";\nexport type { URLState } from \"./url.cjs\";\n\n// Re-export coercion utilities\nexport {\n createCoercer,\n classCoercer,\n instanceOrShape,\n coerceURL,\n coerceToURLString,\n coerceHeaders,\n coerceBody,\n coerceRequestInit,\n coerceResponseInit,\n} from \"./coerce.cjs\";\nexport type {\n Coercer,\n CoercionResult,\n URLCoerced,\n HeadersCoerced,\n RequestInitCoerced,\n ResponseInitCoerced,\n} from \"./coerce.cjs\";\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { SetupCoreOptions, CoreHandle, StateMap } from \"./types.cjs\";\nimport { createStateMap } from \"./class-builder.cjs\";\nimport {\n createReadableStreamClass,\n createReadableStreamDefaultReaderClass,\n createReadableStream,\n} from \"./streams/readable-stream.cjs\";\nimport {\n createWritableStreamClass,\n createWritableStreamDefaultWriterClass,\n} from \"./streams/writable-stream.cjs\";\nimport { createTransformStreamClass } from \"./streams/transform-stream.cjs\";\nimport { createBlobClass } from \"./blob.cjs\";\nimport { createFileClass } from \"./file.cjs\";\nimport { createDOMExceptionClass } from \"./dom-exception.cjs\";\nimport { createURLSearchParamsClass } from \"./url-search-params.cjs\";\nimport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.cjs\";\n\n/**\n * Setup core APIs in a QuickJS context\n *\n * Injects the following globals:\n * - ReadableStream, WritableStream, TransformStream\n * - ReadableStreamDefaultReader, WritableStreamDefaultWriter\n * - Blob\n * - File\n * - DOMException\n * - URL, URLSearchParams\n * - TextEncoder, TextDecoder\n *\n * @example\n * const handle = setupCore(context);\n *\n * context.evalCode(`\n * const blob = new Blob([\"hello\", \" \", \"world\"], { type: \"text/plain\" });\n * const text = await blob.text(); // \"hello world\"\n *\n * const stream = new ReadableStream({\n * start(controller) {\n * controller.enqueue(\"chunk1\");\n * controller.enqueue(\"chunk2\");\n * controller.close();\n * }\n * });\n * `);\n */\nexport function setupCore(\n context: QuickJSContext,\n options?: SetupCoreOptions\n): CoreHandle {\n const stateMap = options?.stateMap ?? createStateMap();\n const handles: { name: string; handle: QuickJSHandle }[] = [];\n\n // Create ReadableStreamDefaultReader class first\n const ReadableStreamDefaultReader = createReadableStreamDefaultReaderClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"ReadableStreamDefaultReader\",\n ReadableStreamDefaultReader\n );\n ReadableStreamDefaultReader.dispose();\n\n // Create ReadableStream class\n const readerClassRef = context.getProp(context.global, \"ReadableStreamDefaultReader\");\n const ReadableStream = createReadableStreamClass(\n context,\n stateMap,\n readerClassRef\n );\n readerClassRef.dispose();\n context.setProp(context.global, \"ReadableStream\", ReadableStream);\n ReadableStream.dispose();\n\n // Create WritableStreamDefaultWriter class first\n const WritableStreamDefaultWriter = createWritableStreamDefaultWriterClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"WritableStreamDefaultWriter\",\n WritableStreamDefaultWriter\n );\n WritableStreamDefaultWriter.dispose();\n\n // Create WritableStream class\n const writerClassRef = context.getProp(context.global, \"WritableStreamDefaultWriter\");\n const WritableStream = createWritableStreamClass(\n context,\n stateMap,\n writerClassRef\n );\n writerClassRef.dispose();\n context.setProp(context.global, \"WritableStream\", WritableStream);\n WritableStream.dispose();\n\n // Create TransformStream class\n const TransformStream = createTransformStreamClass(context, stateMap);\n context.setProp(context.global, \"TransformStream\", TransformStream);\n TransformStream.dispose();\n\n // Create Blob class with stream factory\n const BlobClass = createBlobClass(context, stateMap, (source) =>\n createReadableStream(context, stateMap, source)\n );\n context.setProp(context.global, \"Blob\", BlobClass);\n BlobClass.dispose();\n\n // Create File class (extends Blob)\n const blobClassRef = context.getProp(context.global, \"Blob\");\n const FileClass = createFileClass(context, stateMap, blobClassRef);\n blobClassRef.dispose();\n context.setProp(context.global, \"File\", FileClass);\n FileClass.dispose();\n\n // Create DOMException class\n const DOMExceptionClass = createDOMExceptionClass(context, stateMap);\n context.setProp(context.global, \"DOMException\", DOMExceptionClass);\n DOMExceptionClass.dispose();\n\n // Create URLSearchParams class\n const URLSearchParamsClass = createURLSearchParamsClass(context, stateMap);\n context.setProp(context.global, \"URLSearchParams\", URLSearchParamsClass);\n URLSearchParamsClass.dispose();\n\n // Add Symbol.iterator support for URLSearchParams\n const urlSearchParamsIteratorResult = context.evalCode(`\n URLSearchParams.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (urlSearchParamsIteratorResult.error) {\n urlSearchParamsIteratorResult.error.dispose();\n } else {\n urlSearchParamsIteratorResult.value.dispose();\n }\n\n // Create URL class (depends on URLSearchParams)\n const URLClass = createURLClass(context, stateMap);\n context.setProp(context.global, \"URL\", URLClass);\n URLClass.dispose();\n\n // Add searchParams getter to URL that returns URLSearchParams instance\n // Uses JavaScript closures to sync URLSearchParams mutations back to URL\n addURLSearchParamsLinkage(context);\n\n // TextEncoder/TextDecoder - pure JS implementation for UTF-8\n const textEncodingCode = `\n(function() {\n class TextEncoder {\n constructor(encoding = \"utf-8\") {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n }\n\n encode(input = \"\") {\n const str = String(input);\n const bytes = [];\n\n for (let i = 0; i < str.length; i++) {\n let charCode = str.charCodeAt(i);\n\n if (charCode < 0x80) {\n bytes.push(charCode);\n } else if (charCode < 0x800) {\n bytes.push(0xC0 | (charCode >> 6));\n bytes.push(0x80 | (charCode & 0x3F));\n } else if (charCode >= 0xD800 && charCode <= 0xDBFF) {\n const nextCharCode = str.charCodeAt(++i);\n if (nextCharCode >= 0xDC00 && nextCharCode <= 0xDFFF) {\n const codePoint = 0x10000 + ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00);\n bytes.push(0xF0 | (codePoint >> 18));\n bytes.push(0x80 | ((codePoint >> 12) & 0x3F));\n bytes.push(0x80 | ((codePoint >> 6) & 0x3F));\n bytes.push(0x80 | (codePoint & 0x3F));\n }\n } else if (charCode < 0x10000) {\n bytes.push(0xE0 | (charCode >> 12));\n bytes.push(0x80 | ((charCode >> 6) & 0x3F));\n bytes.push(0x80 | (charCode & 0x3F));\n }\n }\n\n return new Uint8Array(bytes);\n }\n\n encodeInto(source, destination) {\n const encoded = this.encode(source);\n const len = Math.min(encoded.length, destination.length);\n destination.set(encoded.subarray(0, len));\n return { read: source.length, written: len };\n }\n }\n\n class TextDecoder {\n constructor(encoding = \"utf-8\", options = {}) {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n this.fatal = Boolean(options.fatal);\n this.ignoreBOM = Boolean(options.ignoreBOM);\n }\n\n decode(input, options = {}) {\n if (!input) return \"\";\n\n let bytes;\n if (input instanceof ArrayBuffer) {\n bytes = new Uint8Array(input);\n } else if (ArrayBuffer.isView(input)) {\n bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);\n } else if (input instanceof Uint8Array) {\n bytes = input;\n } else {\n throw new TypeError(\"The provided value is not of type '(ArrayBuffer or ArrayBufferView)'\");\n }\n\n let offset = 0;\n if (!this.ignoreBOM && bytes.length >= 3 &&\n bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) {\n offset = 3;\n }\n\n let result = \"\";\n for (let i = offset; i < bytes.length;) {\n const byte1 = bytes[i++];\n\n if (byte1 < 0x80) {\n result += String.fromCharCode(byte1);\n } else if ((byte1 & 0xE0) === 0xC0) {\n const byte2 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x1F) << 6) | byte2);\n } else if ((byte1 & 0xF0) === 0xE0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3);\n } else if ((byte1 & 0xF8) === 0xF0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n const byte4 = bytes[i++] & 0x3F;\n const codePoint = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4;\n const adjusted = codePoint - 0x10000;\n result += String.fromCharCode(0xD800 + (adjusted >> 10), 0xDC00 + (adjusted & 0x3FF));\n }\n }\n\n return result;\n }\n }\n\n globalThis.TextEncoder = TextEncoder;\n globalThis.TextDecoder = TextDecoder;\n})();\n`;\n\n const textEncodingResult = context.evalCode(textEncodingCode);\n if (textEncodingResult.error) {\n console.error(\"Failed to setup TextEncoder/TextDecoder\");\n textEncodingResult.error.dispose();\n } else {\n textEncodingResult.value.dispose();\n }\n\n /**\n * @returns CoreHandle with shared stateMap and dispose method\n *\n * **dispose() behavior:**\n * - Clears internal handle tracking array\n * - Does NOT dispose globals (ReadableStream, Blob, etc.) - they are owned\n * by context.global and cleaned up by context.dispose()\n * - Call before context.dispose() to release internal references\n *\n * @see PATTERNS.md for implementation patterns\n */\n return {\n stateMap,\n dispose() {\n // Note: handles set on global (ReadableStream, Blob, etc.) are NOT disposed here\n // They are owned by the global object and will be cleaned up by context.dispose()\n // Disposing them before context disposal causes QuickJS GC assertion failures\n handles.length = 0;\n },\n };\n}\n\n// Re-export types\nexport type {\n Scope,\n MarshalOptions,\n UnmarshalOptions,\n PropertyDescriptor,\n ClassDefinition,\n StateMap,\n SetupCoreOptions,\n CoreHandle,\n QuickJSContext,\n QuickJSHandle,\n QuickJSRuntime,\n} from \"./types.cjs\";\nexport { INTERNAL_STATE } from \"./types.cjs\";\n\n// Re-export utilities\nexport { withScope, withScopeAsync } from \"./scope.cjs\";\nexport { marshal, isHandle, getHandleType } from \"./marshal.cjs\";\nexport { unmarshal, cleanupUnmarshaledHandles } from \"./unmarshal.cjs\";\nexport {\n defineFunction,\n defineAsyncFunction,\n defineAsyncIteratorFunction,\n cleanupAsyncIterators,\n} from \"./function-builder.cjs\";\nexport {\n defineClass,\n createStateMap,\n getState,\n setState,\n getInstanceState,\n setInstanceState,\n getInstanceStateById,\n cleanupInstanceState,\n clearAllInstanceState,\n} from \"./class-builder.cjs\";\n\n// Re-export class instance helpers for cross-class access\nexport {\n isDefineClassInstance,\n isInstanceOf,\n getClassInstanceState,\n getInstanceId,\n getClassName,\n createClassTypeGuard,\n isUnmarshalledRequest,\n isUnmarshalledResponse,\n isUnmarshalledHeaders,\n isUnmarshalledFormData,\n} from \"./class-helpers.cjs\";\nexport type { DefineClassInstance, TypedClassInstance } from \"./class-helpers.cjs\";\n\n// Re-export instance state management\nexport {\n nextInstanceId,\n registerInstance,\n getInstanceMetadata,\n getInstanceClassName,\n cleanupInstanceState as cleanupInstanceStateById,\n} from \"./instance-state.cjs\";\nexport type { InstanceMetadata } from \"./instance-state.cjs\";\n\n// Re-export stream utilities\nexport {\n createReadableStream,\n consumeReadableStream,\n} from \"./streams/readable-stream.cjs\";\nexport { createWritableStream } from \"./streams/writable-stream.cjs\";\n\n// Re-export Blob/File utilities\nexport { createBlob } from \"./blob.cjs\";\nexport { createFile } from \"./file.cjs\";\n\n// Re-export URL utilities\nexport { createURLSearchParamsClass } from \"./url-search-params.cjs\";\nexport type { URLSearchParamsState } from \"./url-search-params.cjs\";\nexport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.cjs\";\nexport type { URLState } from \"./url.cjs\";\n\n// Re-export coercion utilities\nexport {\n createCoercer,\n classCoercer,\n instanceOrShape,\n coerceURL,\n coerceToURLString,\n coerceHeaders,\n coerceBody,\n coerceRequestInit,\n coerceResponseInit,\n} from \"./coerce.cjs\";\nexport type {\n Coercer,\n CoercionResult,\n URLCoerced,\n HeadersCoerced,\n RequestInitCoerced,\n ResponseInitCoerced,\n} from \"./coerce.cjs\";\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "AAC8B5BEA5BE896D64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "2704213322BFE26C64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-core",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "type": "commonjs"
5
5
  }
@@ -2,6 +2,153 @@
2
2
  // packages/core/src/function-builder.ts
3
3
  import { unmarshal } from "./unmarshal.mjs";
4
4
  import { marshal } from "./marshal.mjs";
5
+ var generatorRegistries = new WeakMap;
6
+ var generatorCounters = new WeakMap;
7
+ var setupContexts = new WeakSet;
8
+ function getGeneratorRegistry(context) {
9
+ let registry = generatorRegistries.get(context);
10
+ if (!registry) {
11
+ registry = new Map;
12
+ generatorRegistries.set(context, registry);
13
+ }
14
+ return registry;
15
+ }
16
+ function nextGeneratorId(context) {
17
+ let counter = generatorCounters.get(context);
18
+ if (!counter) {
19
+ counter = { value: 0 };
20
+ generatorCounters.set(context, counter);
21
+ }
22
+ return ++counter.value;
23
+ }
24
+ function registerGenerator(context, generator) {
25
+ const id = nextGeneratorId(context);
26
+ const registry = getGeneratorRegistry(context);
27
+ registry.set(id, generator);
28
+ return id;
29
+ }
30
+ function setupAsyncIteratorInfrastructure(context) {
31
+ if (setupContexts.has(context)) {
32
+ return;
33
+ }
34
+ setupContexts.add(context);
35
+ const nextFn = context.newFunction("__asyncIteratorNext__", (idHandle) => {
36
+ const id = context.getNumber(idHandle);
37
+ const registry = getGeneratorRegistry(context);
38
+ const generator = registry.get(id);
39
+ if (!generator) {
40
+ const deferred2 = context.newPromise();
41
+ const errorHandle = context.newError(`Generator ${id} not found`);
42
+ deferred2.reject(errorHandle);
43
+ errorHandle.dispose();
44
+ context.runtime.executePendingJobs();
45
+ return deferred2.handle;
46
+ }
47
+ const deferred = context.newPromise();
48
+ generator.next().then((result) => {
49
+ if (!context.alive)
50
+ return;
51
+ const resultHandle = marshal(context, {
52
+ value: result.value,
53
+ done: result.done
54
+ });
55
+ deferred.resolve(resultHandle);
56
+ resultHandle.dispose();
57
+ if (result.done) {
58
+ registry.delete(id);
59
+ }
60
+ context.runtime.executePendingJobs();
61
+ }).catch((error) => {
62
+ if (!context.alive)
63
+ return;
64
+ const errorHandle = context.newError(error instanceof Error ? error.message : String(error));
65
+ deferred.reject(errorHandle);
66
+ errorHandle.dispose();
67
+ registry.delete(id);
68
+ context.runtime.executePendingJobs();
69
+ });
70
+ return deferred.handle;
71
+ });
72
+ context.setProp(context.global, "__asyncIteratorNext__", nextFn);
73
+ nextFn.dispose();
74
+ const returnFn = context.newFunction("__asyncIteratorReturn__", (idHandle, valueHandle) => {
75
+ const id = context.getNumber(idHandle);
76
+ const value = unmarshal(context, valueHandle);
77
+ const registry = getGeneratorRegistry(context);
78
+ const generator = registry.get(id);
79
+ const deferred = context.newPromise();
80
+ if (!generator) {
81
+ const resultHandle = marshal(context, { value, done: true });
82
+ deferred.resolve(resultHandle);
83
+ resultHandle.dispose();
84
+ context.runtime.executePendingJobs();
85
+ return deferred.handle;
86
+ }
87
+ generator.return(value).then((result) => {
88
+ if (!context.alive)
89
+ return;
90
+ const resultHandle = marshal(context, {
91
+ value: result.value,
92
+ done: result.done
93
+ });
94
+ deferred.resolve(resultHandle);
95
+ resultHandle.dispose();
96
+ registry.delete(id);
97
+ context.runtime.executePendingJobs();
98
+ }).catch((error) => {
99
+ if (!context.alive)
100
+ return;
101
+ const errorHandle = context.newError(error instanceof Error ? error.message : String(error));
102
+ deferred.reject(errorHandle);
103
+ errorHandle.dispose();
104
+ registry.delete(id);
105
+ context.runtime.executePendingJobs();
106
+ });
107
+ return deferred.handle;
108
+ });
109
+ context.setProp(context.global, "__asyncIteratorReturn__", returnFn);
110
+ returnFn.dispose();
111
+ const throwFn = context.newFunction("__asyncIteratorThrow__", (idHandle, errorHandle) => {
112
+ const id = context.getNumber(idHandle);
113
+ const errorValue = unmarshal(context, errorHandle);
114
+ const registry = getGeneratorRegistry(context);
115
+ const generator = registry.get(id);
116
+ const deferred = context.newPromise();
117
+ if (!generator) {
118
+ const errHandle = context.newError(errorValue instanceof Error ? errorValue.message : String(errorValue));
119
+ deferred.reject(errHandle);
120
+ errHandle.dispose();
121
+ context.runtime.executePendingJobs();
122
+ return deferred.handle;
123
+ }
124
+ const error = errorValue instanceof Error ? errorValue : new Error(String(errorValue));
125
+ generator.throw(error).then((result) => {
126
+ if (!context.alive)
127
+ return;
128
+ const resultHandle = marshal(context, {
129
+ value: result.value,
130
+ done: result.done
131
+ });
132
+ deferred.resolve(resultHandle);
133
+ resultHandle.dispose();
134
+ if (result.done) {
135
+ registry.delete(id);
136
+ }
137
+ context.runtime.executePendingJobs();
138
+ }).catch((err) => {
139
+ if (!context.alive)
140
+ return;
141
+ const errHandle = context.newError(err instanceof Error ? err.message : String(err));
142
+ deferred.reject(errHandle);
143
+ errHandle.dispose();
144
+ registry.delete(id);
145
+ context.runtime.executePendingJobs();
146
+ });
147
+ return deferred.handle;
148
+ });
149
+ context.setProp(context.global, "__asyncIteratorThrow__", throwFn);
150
+ throwFn.dispose();
151
+ }
5
152
  function defineFunction(context, name, fn) {
6
153
  return context.newFunction(name, (...argHandles) => {
7
154
  const args = argHandles.map((h) => unmarshal(context, h));
@@ -37,9 +184,44 @@ function defineAsyncFunction(context, name, fn) {
37
184
  return deferred.handle;
38
185
  });
39
186
  }
187
+ function defineAsyncIteratorFunction(context, name, fn) {
188
+ setupAsyncIteratorInfrastructure(context);
189
+ return context.newFunction(name, (...argHandles) => {
190
+ const args = argHandles.map((h) => unmarshal(context, h));
191
+ try {
192
+ const generator = fn(...args);
193
+ const generatorId = registerGenerator(context, generator);
194
+ const result = context.evalCode(`({
195
+ [Symbol.asyncIterator]() {
196
+ return {
197
+ next: () => __asyncIteratorNext__(${generatorId}),
198
+ return: (v) => __asyncIteratorReturn__(${generatorId}, v),
199
+ throw: (e) => __asyncIteratorThrow__(${generatorId}, e)
200
+ };
201
+ }
202
+ })`);
203
+ if (result.error) {
204
+ const err = context.dump(result.error);
205
+ result.error.dispose();
206
+ const registry = getGeneratorRegistry(context);
207
+ registry.delete(generatorId);
208
+ throw context.newError(String(err));
209
+ }
210
+ return result.value;
211
+ } catch (error) {
212
+ throw context.newError(error instanceof Error ? error.message : String(error));
213
+ }
214
+ });
215
+ }
216
+ function cleanupAsyncIterators(context) {
217
+ generatorRegistries.delete(context);
218
+ generatorCounters.delete(context);
219
+ }
40
220
  export {
41
221
  defineFunction,
42
- defineAsyncFunction
222
+ defineAsyncIteratorFunction,
223
+ defineAsyncFunction,
224
+ cleanupAsyncIterators
43
225
  };
44
226
 
45
- //# debugId=8B474E0BF8843F0764756E2164756E21
227
+ //# debugId=1A737A5AACCCCD4964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/function-builder.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { unmarshal } from \"./unmarshal.mjs\";\nimport { marshal } from \"./marshal.mjs\";\n\n/**\n * Define a global function in the QuickJS context\n *\n * @returns Handle to the function (caller must manage disposal)\n *\n * @example\n * const logFn = defineFunction(context, \"log\", (...args) => {\n * console.log(\"[QuickJS]\", ...args);\n * });\n * context.setProp(context.global, \"log\", logFn);\n */\nexport function defineFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => unknown\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n try {\n // Call host function\n const result = fn(...args);\n\n // Marshal result\n return marshal(context, result);\n } catch (error) {\n // Throw error in QuickJS\n throw context.newError(\n error instanceof Error ? error.message : String(error)\n );\n }\n });\n}\n\n/**\n * Define an async function that returns a promise to QuickJS\n *\n * @example\n * const fetchFn = defineAsyncFunction(context, \"fetch\", async (url) => {\n * const response = await fetch(String(url));\n * return response.text();\n * });\n */\nexport function defineAsyncFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => Promise<unknown>\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n // Create a promise in QuickJS\n const deferred = context.newPromise();\n\n // Call the async function\n fn(...args)\n .then((result) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const resultHandle = marshal(context, result);\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const errorHandle = marshal(\n context,\n error instanceof Error\n ? { name: error.name, message: error.message }\n : { message: String(error) }\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n });\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { unmarshal } from \"./unmarshal.mjs\";\nimport { marshal } from \"./marshal.mjs\";\n\n/**\n * Registry for async generators, scoped per-context.\n * Uses WeakMap to automatically clean up when context is GC'd.\n */\nconst generatorRegistries = new WeakMap<\n QuickJSContext,\n Map<number, AsyncGenerator<unknown, unknown, unknown>>\n>();\n\n/**\n * Counter for generating unique generator IDs per context.\n */\nconst generatorCounters = new WeakMap<QuickJSContext, { value: number }>();\n\n/**\n * Track which contexts have had async iterator infrastructure set up.\n */\nconst setupContexts = new WeakSet<QuickJSContext>();\n\n/**\n * Get or create the generator registry for a context.\n */\nfunction getGeneratorRegistry(\n context: QuickJSContext\n): Map<number, AsyncGenerator<unknown, unknown, unknown>> {\n let registry = generatorRegistries.get(context);\n if (!registry) {\n registry = new Map();\n generatorRegistries.set(context, registry);\n }\n return registry;\n}\n\n/**\n * Get next generator ID for a context.\n */\nfunction nextGeneratorId(context: QuickJSContext): number {\n let counter = generatorCounters.get(context);\n if (!counter) {\n counter = { value: 0 };\n generatorCounters.set(context, counter);\n }\n return ++counter.value;\n}\n\n/**\n * Register a generator and return its ID.\n */\nfunction registerGenerator(\n context: QuickJSContext,\n generator: AsyncGenerator<unknown, unknown, unknown>\n): number {\n const id = nextGeneratorId(context);\n const registry = getGeneratorRegistry(context);\n registry.set(id, generator);\n return id;\n}\n\n/**\n * Setup async iterator infrastructure helpers in the context.\n * These are global functions that proxy to host-side generators.\n */\nfunction setupAsyncIteratorInfrastructure(context: QuickJSContext): void {\n if (setupContexts.has(context)) {\n return;\n }\n setupContexts.add(context);\n\n // __asyncIteratorNext__(id) - calls generator.next()\n const nextFn = context.newFunction(\n \"__asyncIteratorNext__\",\n (idHandle: QuickJSHandle) => {\n const id = context.getNumber(idHandle);\n const registry = getGeneratorRegistry(context);\n const generator = registry.get(id);\n\n if (!generator) {\n // Generator not found - already cleaned up or invalid ID\n const deferred = context.newPromise();\n const errorHandle = context.newError(`Generator ${id} not found`);\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n return deferred.handle;\n }\n\n const deferred = context.newPromise();\n\n generator\n .next()\n .then((result) => {\n if (!context.alive) return;\n\n const resultHandle = marshal(context, {\n value: result.value,\n done: result.done,\n });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n\n // Clean up if done\n if (result.done) {\n registry.delete(id);\n }\n\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n if (!context.alive) return;\n\n // Create a proper Error object for rejection\n const errorHandle = context.newError(\n error instanceof Error ? error.message : String(error)\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n\n // Clean up on error\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n }\n );\n context.setProp(context.global, \"__asyncIteratorNext__\", nextFn);\n nextFn.dispose();\n\n // __asyncIteratorReturn__(id, value) - calls generator.return(value)\n const returnFn = context.newFunction(\n \"__asyncIteratorReturn__\",\n (idHandle: QuickJSHandle, valueHandle: QuickJSHandle) => {\n const id = context.getNumber(idHandle);\n const value = unmarshal(context, valueHandle);\n const registry = getGeneratorRegistry(context);\n const generator = registry.get(id);\n\n const deferred = context.newPromise();\n\n if (!generator) {\n // Generator not found - return a completed result\n const resultHandle = marshal(context, { value, done: true });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n context.runtime.executePendingJobs();\n return deferred.handle;\n }\n\n generator\n .return(value)\n .then((result) => {\n if (!context.alive) return;\n\n const resultHandle = marshal(context, {\n value: result.value,\n done: result.done,\n });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n\n // Always clean up after return\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n if (!context.alive) return;\n\n const errorHandle = context.newError(\n error instanceof Error ? error.message : String(error)\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n }\n );\n context.setProp(context.global, \"__asyncIteratorReturn__\", returnFn);\n returnFn.dispose();\n\n // __asyncIteratorThrow__(id, error) - calls generator.throw(error)\n const throwFn = context.newFunction(\n \"__asyncIteratorThrow__\",\n (idHandle: QuickJSHandle, errorHandle: QuickJSHandle) => {\n const id = context.getNumber(idHandle);\n const errorValue = unmarshal(context, errorHandle);\n const registry = getGeneratorRegistry(context);\n const generator = registry.get(id);\n\n const deferred = context.newPromise();\n\n if (!generator) {\n // Generator not found - reject with a proper error\n const errHandle = context.newError(\n errorValue instanceof Error ? errorValue.message : String(errorValue)\n );\n deferred.reject(errHandle);\n errHandle.dispose();\n context.runtime.executePendingJobs();\n return deferred.handle;\n }\n\n // Convert to Error if needed\n const error =\n errorValue instanceof Error\n ? errorValue\n : new Error(String(errorValue));\n\n generator\n .throw(error)\n .then((result) => {\n if (!context.alive) return;\n\n const resultHandle = marshal(context, {\n value: result.value,\n done: result.done,\n });\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n\n if (result.done) {\n registry.delete(id);\n }\n\n context.runtime.executePendingJobs();\n })\n .catch((err) => {\n if (!context.alive) return;\n\n const errHandle = context.newError(\n err instanceof Error ? err.message : String(err)\n );\n deferred.reject(errHandle);\n errHandle.dispose();\n\n registry.delete(id);\n\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n }\n );\n context.setProp(context.global, \"__asyncIteratorThrow__\", throwFn);\n throwFn.dispose();\n}\n\n/**\n * Define a global function in the QuickJS context\n *\n * @returns Handle to the function (caller must manage disposal)\n *\n * @example\n * const logFn = defineFunction(context, \"log\", (...args) => {\n * console.log(\"[QuickJS]\", ...args);\n * });\n * context.setProp(context.global, \"log\", logFn);\n */\nexport function defineFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => unknown\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n try {\n // Call host function\n const result = fn(...args);\n\n // Marshal result\n return marshal(context, result);\n } catch (error) {\n // Throw error in QuickJS\n throw context.newError(\n error instanceof Error ? error.message : String(error)\n );\n }\n });\n}\n\n/**\n * Define an async function that returns a promise to QuickJS\n *\n * @example\n * const fetchFn = defineAsyncFunction(context, \"fetch\", async (url) => {\n * const response = await fetch(String(url));\n * return response.text();\n * });\n */\nexport function defineAsyncFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => Promise<unknown>\n): QuickJSHandle {\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n // Create a promise in QuickJS\n const deferred = context.newPromise();\n\n // Call the async function\n fn(...args)\n .then((result) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const resultHandle = marshal(context, result);\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n // Guard: Check if context is still alive\n if (!context.alive) {\n return;\n }\n const errorHandle = marshal(\n context,\n error instanceof Error\n ? { name: error.name, message: error.message }\n : { message: String(error) }\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n });\n}\n\n/**\n * Define an async iterator function that returns an async iterable to QuickJS.\n * The host function should be an async generator.\n *\n * @example\n * const streamFn = defineAsyncIteratorFunction(context, \"stream\", async function* (n) {\n * for (let i = 0; i < n; i++) {\n * yield i;\n * }\n * return \"done\";\n * });\n *\n * // In QuickJS:\n * // for await (const value of stream(3)) { console.log(value); }\n * // Outputs: 0, 1, 2\n */\nexport function defineAsyncIteratorFunction(\n context: QuickJSContext,\n name: string,\n fn: (...args: unknown[]) => AsyncGenerator<unknown, unknown, unknown>\n): QuickJSHandle {\n // Ensure infrastructure is set up\n setupAsyncIteratorInfrastructure(context);\n\n return context.newFunction(name, (...argHandles) => {\n // Unmarshal arguments\n const args = argHandles.map((h) => unmarshal(context, h));\n\n try {\n // Call host function to get generator instance\n const generator = fn(...args);\n\n // Register generator and get ID\n const generatorId = registerGenerator(context, generator);\n\n // Create proxy object that implements async iterator protocol\n // This object when iterated will call our infrastructure helpers\n const result = context.evalCode(`({\n [Symbol.asyncIterator]() {\n return {\n next: () => __asyncIteratorNext__(${generatorId}),\n return: (v) => __asyncIteratorReturn__(${generatorId}, v),\n throw: (e) => __asyncIteratorThrow__(${generatorId}, e)\n };\n }\n })`);\n\n if (result.error) {\n const err = context.dump(result.error);\n result.error.dispose();\n // Clean up the registered generator since we failed\n const registry = getGeneratorRegistry(context);\n registry.delete(generatorId);\n throw context.newError(String(err));\n }\n\n return result.value;\n } catch (error) {\n // Throw error in QuickJS\n throw context.newError(\n error instanceof Error ? error.message : String(error)\n );\n }\n });\n}\n\n/**\n * Clean up all async iterator state for a context.\n * Should be called before context disposal.\n */\nexport function cleanupAsyncIterators(context: QuickJSContext): void {\n generatorRegistries.delete(context);\n generatorCounters.delete(context);\n // Note: setupContexts uses WeakSet, so no need to explicitly delete\n}\n"
6
6
  ],
7
- "mappings": ";;AACA;AACA;AAaO,SAAS,cAAc,CAC5B,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,UAAU,SAAS,CAAC,CAAC;AAAA,IAExD,IAAI;AAAA,MAEF,MAAM,SAAS,GAAG,GAAG,IAAI;AAAA,MAGzB,OAAO,QAAQ,SAAS,MAAM;AAAA,MAC9B,OAAO,OAAO;AAAA,MAEd,MAAM,QAAQ,SACZ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA;AAAA,GAEH;AAAA;AAYI,SAAS,mBAAmB,CACjC,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,UAAU,SAAS,CAAC,CAAC;AAAA,IAGxD,MAAM,WAAW,QAAQ,WAAW;AAAA,IAGpC,GAAG,GAAG,IAAI,EACP,KAAK,CAAC,WAAW;AAAA,MAEhB,IAAI,CAAC,QAAQ,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,MACA,MAAM,eAAe,QAAQ,SAAS,MAAM;AAAA,MAC5C,SAAS,QAAQ,YAAY;AAAA,MAC7B,aAAa,QAAQ;AAAA,MACrB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC,EACA,MAAM,CAAC,UAAU;AAAA,MAEhB,IAAI,CAAC,QAAQ,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,MACA,MAAM,cAAc,QAClB,SACA,iBAAiB,QACb,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ,IAC3C,EAAE,SAAS,OAAO,KAAK,EAAE,CAC/B;AAAA,MACA,SAAS,OAAO,WAAW;AAAA,MAC3B,YAAY,QAAQ;AAAA,MACpB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC;AAAA,IAEH,OAAO,SAAS;AAAA,GACjB;AAAA;",
8
- "debugId": "8B474E0BF8843F0764756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "1A737A5AACCCCD4964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -20,7 +20,12 @@ import { INTERNAL_STATE } from "./types.mjs";
20
20
  import { withScope, withScopeAsync } from "./scope.mjs";
21
21
  import { marshal, isHandle, getHandleType } from "./marshal.mjs";
22
22
  import { unmarshal, cleanupUnmarshaledHandles } from "./unmarshal.mjs";
23
- import { defineFunction, defineAsyncFunction } from "./function-builder.mjs";
23
+ import {
24
+ defineFunction,
25
+ defineAsyncFunction,
26
+ defineAsyncIteratorFunction,
27
+ cleanupAsyncIterators
28
+ } from "./function-builder.mjs";
24
29
  import {
25
30
  defineClass,
26
31
  createStateMap as createStateMap2,
@@ -274,6 +279,7 @@ export {
274
279
  getClassInstanceState,
275
280
  defineFunction,
276
281
  defineClass,
282
+ defineAsyncIteratorFunction,
277
283
  defineAsyncFunction,
278
284
  createWritableStream,
279
285
  createURLSearchParamsClass2 as createURLSearchParamsClass,
@@ -295,10 +301,11 @@ export {
295
301
  cleanupUnmarshaledHandles,
296
302
  cleanupInstanceState2 as cleanupInstanceStateById,
297
303
  cleanupInstanceState,
304
+ cleanupAsyncIterators,
298
305
  classCoercer,
299
306
  addURLSearchParamsLinkage2 as addURLSearchParamsLinkage,
300
307
  addURLSearchParamsGetter2 as addURLSearchParamsGetter,
301
308
  INTERNAL_STATE
302
309
  };
303
310
 
304
- //# debugId=F1D8DE89A0C3E63864756E2164756E21
311
+ //# debugId=0EA35BEDA988897364756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { SetupCoreOptions, CoreHandle, StateMap } from \"./types.mjs\";\nimport { createStateMap } from \"./class-builder.mjs\";\nimport {\n createReadableStreamClass,\n createReadableStreamDefaultReaderClass,\n createReadableStream,\n} from \"./streams/readable-stream.mjs\";\nimport {\n createWritableStreamClass,\n createWritableStreamDefaultWriterClass,\n} from \"./streams/writable-stream.mjs\";\nimport { createTransformStreamClass } from \"./streams/transform-stream.mjs\";\nimport { createBlobClass } from \"./blob.mjs\";\nimport { createFileClass } from \"./file.mjs\";\nimport { createDOMExceptionClass } from \"./dom-exception.mjs\";\nimport { createURLSearchParamsClass } from \"./url-search-params.mjs\";\nimport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.mjs\";\n\n/**\n * Setup core APIs in a QuickJS context\n *\n * Injects the following globals:\n * - ReadableStream, WritableStream, TransformStream\n * - ReadableStreamDefaultReader, WritableStreamDefaultWriter\n * - Blob\n * - File\n * - DOMException\n * - URL, URLSearchParams\n * - TextEncoder, TextDecoder\n *\n * @example\n * const handle = setupCore(context);\n *\n * context.evalCode(`\n * const blob = new Blob([\"hello\", \" \", \"world\"], { type: \"text/plain\" });\n * const text = await blob.text(); // \"hello world\"\n *\n * const stream = new ReadableStream({\n * start(controller) {\n * controller.enqueue(\"chunk1\");\n * controller.enqueue(\"chunk2\");\n * controller.close();\n * }\n * });\n * `);\n */\nexport function setupCore(\n context: QuickJSContext,\n options?: SetupCoreOptions\n): CoreHandle {\n const stateMap = options?.stateMap ?? createStateMap();\n const handles: { name: string; handle: QuickJSHandle }[] = [];\n\n // Create ReadableStreamDefaultReader class first\n const ReadableStreamDefaultReader = createReadableStreamDefaultReaderClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"ReadableStreamDefaultReader\",\n ReadableStreamDefaultReader\n );\n ReadableStreamDefaultReader.dispose();\n\n // Create ReadableStream class\n const readerClassRef = context.getProp(context.global, \"ReadableStreamDefaultReader\");\n const ReadableStream = createReadableStreamClass(\n context,\n stateMap,\n readerClassRef\n );\n readerClassRef.dispose();\n context.setProp(context.global, \"ReadableStream\", ReadableStream);\n ReadableStream.dispose();\n\n // Create WritableStreamDefaultWriter class first\n const WritableStreamDefaultWriter = createWritableStreamDefaultWriterClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"WritableStreamDefaultWriter\",\n WritableStreamDefaultWriter\n );\n WritableStreamDefaultWriter.dispose();\n\n // Create WritableStream class\n const writerClassRef = context.getProp(context.global, \"WritableStreamDefaultWriter\");\n const WritableStream = createWritableStreamClass(\n context,\n stateMap,\n writerClassRef\n );\n writerClassRef.dispose();\n context.setProp(context.global, \"WritableStream\", WritableStream);\n WritableStream.dispose();\n\n // Create TransformStream class\n const TransformStream = createTransformStreamClass(context, stateMap);\n context.setProp(context.global, \"TransformStream\", TransformStream);\n TransformStream.dispose();\n\n // Create Blob class with stream factory\n const BlobClass = createBlobClass(context, stateMap, (source) =>\n createReadableStream(context, stateMap, source)\n );\n context.setProp(context.global, \"Blob\", BlobClass);\n BlobClass.dispose();\n\n // Create File class (extends Blob)\n const blobClassRef = context.getProp(context.global, \"Blob\");\n const FileClass = createFileClass(context, stateMap, blobClassRef);\n blobClassRef.dispose();\n context.setProp(context.global, \"File\", FileClass);\n FileClass.dispose();\n\n // Create DOMException class\n const DOMExceptionClass = createDOMExceptionClass(context, stateMap);\n context.setProp(context.global, \"DOMException\", DOMExceptionClass);\n DOMExceptionClass.dispose();\n\n // Create URLSearchParams class\n const URLSearchParamsClass = createURLSearchParamsClass(context, stateMap);\n context.setProp(context.global, \"URLSearchParams\", URLSearchParamsClass);\n URLSearchParamsClass.dispose();\n\n // Add Symbol.iterator support for URLSearchParams\n const urlSearchParamsIteratorResult = context.evalCode(`\n URLSearchParams.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (urlSearchParamsIteratorResult.error) {\n urlSearchParamsIteratorResult.error.dispose();\n } else {\n urlSearchParamsIteratorResult.value.dispose();\n }\n\n // Create URL class (depends on URLSearchParams)\n const URLClass = createURLClass(context, stateMap);\n context.setProp(context.global, \"URL\", URLClass);\n URLClass.dispose();\n\n // Add searchParams getter to URL that returns URLSearchParams instance\n // Uses JavaScript closures to sync URLSearchParams mutations back to URL\n addURLSearchParamsLinkage(context);\n\n // TextEncoder/TextDecoder - pure JS implementation for UTF-8\n const textEncodingCode = `\n(function() {\n class TextEncoder {\n constructor(encoding = \"utf-8\") {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n }\n\n encode(input = \"\") {\n const str = String(input);\n const bytes = [];\n\n for (let i = 0; i < str.length; i++) {\n let charCode = str.charCodeAt(i);\n\n if (charCode < 0x80) {\n bytes.push(charCode);\n } else if (charCode < 0x800) {\n bytes.push(0xC0 | (charCode >> 6));\n bytes.push(0x80 | (charCode & 0x3F));\n } else if (charCode >= 0xD800 && charCode <= 0xDBFF) {\n const nextCharCode = str.charCodeAt(++i);\n if (nextCharCode >= 0xDC00 && nextCharCode <= 0xDFFF) {\n const codePoint = 0x10000 + ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00);\n bytes.push(0xF0 | (codePoint >> 18));\n bytes.push(0x80 | ((codePoint >> 12) & 0x3F));\n bytes.push(0x80 | ((codePoint >> 6) & 0x3F));\n bytes.push(0x80 | (codePoint & 0x3F));\n }\n } else if (charCode < 0x10000) {\n bytes.push(0xE0 | (charCode >> 12));\n bytes.push(0x80 | ((charCode >> 6) & 0x3F));\n bytes.push(0x80 | (charCode & 0x3F));\n }\n }\n\n return new Uint8Array(bytes);\n }\n\n encodeInto(source, destination) {\n const encoded = this.encode(source);\n const len = Math.min(encoded.length, destination.length);\n destination.set(encoded.subarray(0, len));\n return { read: source.length, written: len };\n }\n }\n\n class TextDecoder {\n constructor(encoding = \"utf-8\", options = {}) {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n this.fatal = Boolean(options.fatal);\n this.ignoreBOM = Boolean(options.ignoreBOM);\n }\n\n decode(input, options = {}) {\n if (!input) return \"\";\n\n let bytes;\n if (input instanceof ArrayBuffer) {\n bytes = new Uint8Array(input);\n } else if (ArrayBuffer.isView(input)) {\n bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);\n } else if (input instanceof Uint8Array) {\n bytes = input;\n } else {\n throw new TypeError(\"The provided value is not of type '(ArrayBuffer or ArrayBufferView)'\");\n }\n\n let offset = 0;\n if (!this.ignoreBOM && bytes.length >= 3 &&\n bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) {\n offset = 3;\n }\n\n let result = \"\";\n for (let i = offset; i < bytes.length;) {\n const byte1 = bytes[i++];\n\n if (byte1 < 0x80) {\n result += String.fromCharCode(byte1);\n } else if ((byte1 & 0xE0) === 0xC0) {\n const byte2 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x1F) << 6) | byte2);\n } else if ((byte1 & 0xF0) === 0xE0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3);\n } else if ((byte1 & 0xF8) === 0xF0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n const byte4 = bytes[i++] & 0x3F;\n const codePoint = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4;\n const adjusted = codePoint - 0x10000;\n result += String.fromCharCode(0xD800 + (adjusted >> 10), 0xDC00 + (adjusted & 0x3FF));\n }\n }\n\n return result;\n }\n }\n\n globalThis.TextEncoder = TextEncoder;\n globalThis.TextDecoder = TextDecoder;\n})();\n`;\n\n const textEncodingResult = context.evalCode(textEncodingCode);\n if (textEncodingResult.error) {\n console.error(\"Failed to setup TextEncoder/TextDecoder\");\n textEncodingResult.error.dispose();\n } else {\n textEncodingResult.value.dispose();\n }\n\n /**\n * @returns CoreHandle with shared stateMap and dispose method\n *\n * **dispose() behavior:**\n * - Clears internal handle tracking array\n * - Does NOT dispose globals (ReadableStream, Blob, etc.) - they are owned\n * by context.global and cleaned up by context.dispose()\n * - Call before context.dispose() to release internal references\n *\n * @see PATTERNS.md for implementation patterns\n */\n return {\n stateMap,\n dispose() {\n // Note: handles set on global (ReadableStream, Blob, etc.) are NOT disposed here\n // They are owned by the global object and will be cleaned up by context.dispose()\n // Disposing them before context disposal causes QuickJS GC assertion failures\n handles.length = 0;\n },\n };\n}\n\n// Re-export types\nexport type {\n Scope,\n MarshalOptions,\n UnmarshalOptions,\n PropertyDescriptor,\n ClassDefinition,\n StateMap,\n SetupCoreOptions,\n CoreHandle,\n QuickJSContext,\n QuickJSHandle,\n QuickJSRuntime,\n} from \"./types.mjs\";\nexport { INTERNAL_STATE } from \"./types.mjs\";\n\n// Re-export utilities\nexport { withScope, withScopeAsync } from \"./scope.mjs\";\nexport { marshal, isHandle, getHandleType } from \"./marshal.mjs\";\nexport { unmarshal, cleanupUnmarshaledHandles } from \"./unmarshal.mjs\";\nexport { defineFunction, defineAsyncFunction } from \"./function-builder.mjs\";\nexport {\n defineClass,\n createStateMap,\n getState,\n setState,\n getInstanceState,\n setInstanceState,\n getInstanceStateById,\n cleanupInstanceState,\n clearAllInstanceState,\n} from \"./class-builder.mjs\";\n\n// Re-export class instance helpers for cross-class access\nexport {\n isDefineClassInstance,\n isInstanceOf,\n getClassInstanceState,\n getInstanceId,\n getClassName,\n createClassTypeGuard,\n isUnmarshalledRequest,\n isUnmarshalledResponse,\n isUnmarshalledHeaders,\n isUnmarshalledFormData,\n} from \"./class-helpers.mjs\";\nexport type { DefineClassInstance, TypedClassInstance } from \"./class-helpers.mjs\";\n\n// Re-export instance state management\nexport {\n nextInstanceId,\n registerInstance,\n getInstanceMetadata,\n getInstanceClassName,\n cleanupInstanceState as cleanupInstanceStateById,\n} from \"./instance-state.mjs\";\nexport type { InstanceMetadata } from \"./instance-state.mjs\";\n\n// Re-export stream utilities\nexport {\n createReadableStream,\n consumeReadableStream,\n} from \"./streams/readable-stream.mjs\";\nexport { createWritableStream } from \"./streams/writable-stream.mjs\";\n\n// Re-export Blob/File utilities\nexport { createBlob } from \"./blob.mjs\";\nexport { createFile } from \"./file.mjs\";\n\n// Re-export URL utilities\nexport { createURLSearchParamsClass } from \"./url-search-params.mjs\";\nexport type { URLSearchParamsState } from \"./url-search-params.mjs\";\nexport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.mjs\";\nexport type { URLState } from \"./url.mjs\";\n\n// Re-export coercion utilities\nexport {\n createCoercer,\n classCoercer,\n instanceOrShape,\n coerceURL,\n coerceToURLString,\n coerceHeaders,\n coerceBody,\n coerceRequestInit,\n coerceResponseInit,\n} from \"./coerce.mjs\";\nexport type {\n Coercer,\n CoercionResult,\n URLCoerced,\n HeadersCoerced,\n RequestInitCoerced,\n ResponseInitCoerced,\n} from \"./coerce.mjs\";\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { SetupCoreOptions, CoreHandle, StateMap } from \"./types.mjs\";\nimport { createStateMap } from \"./class-builder.mjs\";\nimport {\n createReadableStreamClass,\n createReadableStreamDefaultReaderClass,\n createReadableStream,\n} from \"./streams/readable-stream.mjs\";\nimport {\n createWritableStreamClass,\n createWritableStreamDefaultWriterClass,\n} from \"./streams/writable-stream.mjs\";\nimport { createTransformStreamClass } from \"./streams/transform-stream.mjs\";\nimport { createBlobClass } from \"./blob.mjs\";\nimport { createFileClass } from \"./file.mjs\";\nimport { createDOMExceptionClass } from \"./dom-exception.mjs\";\nimport { createURLSearchParamsClass } from \"./url-search-params.mjs\";\nimport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.mjs\";\n\n/**\n * Setup core APIs in a QuickJS context\n *\n * Injects the following globals:\n * - ReadableStream, WritableStream, TransformStream\n * - ReadableStreamDefaultReader, WritableStreamDefaultWriter\n * - Blob\n * - File\n * - DOMException\n * - URL, URLSearchParams\n * - TextEncoder, TextDecoder\n *\n * @example\n * const handle = setupCore(context);\n *\n * context.evalCode(`\n * const blob = new Blob([\"hello\", \" \", \"world\"], { type: \"text/plain\" });\n * const text = await blob.text(); // \"hello world\"\n *\n * const stream = new ReadableStream({\n * start(controller) {\n * controller.enqueue(\"chunk1\");\n * controller.enqueue(\"chunk2\");\n * controller.close();\n * }\n * });\n * `);\n */\nexport function setupCore(\n context: QuickJSContext,\n options?: SetupCoreOptions\n): CoreHandle {\n const stateMap = options?.stateMap ?? createStateMap();\n const handles: { name: string; handle: QuickJSHandle }[] = [];\n\n // Create ReadableStreamDefaultReader class first\n const ReadableStreamDefaultReader = createReadableStreamDefaultReaderClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"ReadableStreamDefaultReader\",\n ReadableStreamDefaultReader\n );\n ReadableStreamDefaultReader.dispose();\n\n // Create ReadableStream class\n const readerClassRef = context.getProp(context.global, \"ReadableStreamDefaultReader\");\n const ReadableStream = createReadableStreamClass(\n context,\n stateMap,\n readerClassRef\n );\n readerClassRef.dispose();\n context.setProp(context.global, \"ReadableStream\", ReadableStream);\n ReadableStream.dispose();\n\n // Create WritableStreamDefaultWriter class first\n const WritableStreamDefaultWriter = createWritableStreamDefaultWriterClass(\n context,\n stateMap\n );\n context.setProp(\n context.global,\n \"WritableStreamDefaultWriter\",\n WritableStreamDefaultWriter\n );\n WritableStreamDefaultWriter.dispose();\n\n // Create WritableStream class\n const writerClassRef = context.getProp(context.global, \"WritableStreamDefaultWriter\");\n const WritableStream = createWritableStreamClass(\n context,\n stateMap,\n writerClassRef\n );\n writerClassRef.dispose();\n context.setProp(context.global, \"WritableStream\", WritableStream);\n WritableStream.dispose();\n\n // Create TransformStream class\n const TransformStream = createTransformStreamClass(context, stateMap);\n context.setProp(context.global, \"TransformStream\", TransformStream);\n TransformStream.dispose();\n\n // Create Blob class with stream factory\n const BlobClass = createBlobClass(context, stateMap, (source) =>\n createReadableStream(context, stateMap, source)\n );\n context.setProp(context.global, \"Blob\", BlobClass);\n BlobClass.dispose();\n\n // Create File class (extends Blob)\n const blobClassRef = context.getProp(context.global, \"Blob\");\n const FileClass = createFileClass(context, stateMap, blobClassRef);\n blobClassRef.dispose();\n context.setProp(context.global, \"File\", FileClass);\n FileClass.dispose();\n\n // Create DOMException class\n const DOMExceptionClass = createDOMExceptionClass(context, stateMap);\n context.setProp(context.global, \"DOMException\", DOMExceptionClass);\n DOMExceptionClass.dispose();\n\n // Create URLSearchParams class\n const URLSearchParamsClass = createURLSearchParamsClass(context, stateMap);\n context.setProp(context.global, \"URLSearchParams\", URLSearchParamsClass);\n URLSearchParamsClass.dispose();\n\n // Add Symbol.iterator support for URLSearchParams\n const urlSearchParamsIteratorResult = context.evalCode(`\n URLSearchParams.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (urlSearchParamsIteratorResult.error) {\n urlSearchParamsIteratorResult.error.dispose();\n } else {\n urlSearchParamsIteratorResult.value.dispose();\n }\n\n // Create URL class (depends on URLSearchParams)\n const URLClass = createURLClass(context, stateMap);\n context.setProp(context.global, \"URL\", URLClass);\n URLClass.dispose();\n\n // Add searchParams getter to URL that returns URLSearchParams instance\n // Uses JavaScript closures to sync URLSearchParams mutations back to URL\n addURLSearchParamsLinkage(context);\n\n // TextEncoder/TextDecoder - pure JS implementation for UTF-8\n const textEncodingCode = `\n(function() {\n class TextEncoder {\n constructor(encoding = \"utf-8\") {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n }\n\n encode(input = \"\") {\n const str = String(input);\n const bytes = [];\n\n for (let i = 0; i < str.length; i++) {\n let charCode = str.charCodeAt(i);\n\n if (charCode < 0x80) {\n bytes.push(charCode);\n } else if (charCode < 0x800) {\n bytes.push(0xC0 | (charCode >> 6));\n bytes.push(0x80 | (charCode & 0x3F));\n } else if (charCode >= 0xD800 && charCode <= 0xDBFF) {\n const nextCharCode = str.charCodeAt(++i);\n if (nextCharCode >= 0xDC00 && nextCharCode <= 0xDFFF) {\n const codePoint = 0x10000 + ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00);\n bytes.push(0xF0 | (codePoint >> 18));\n bytes.push(0x80 | ((codePoint >> 12) & 0x3F));\n bytes.push(0x80 | ((codePoint >> 6) & 0x3F));\n bytes.push(0x80 | (codePoint & 0x3F));\n }\n } else if (charCode < 0x10000) {\n bytes.push(0xE0 | (charCode >> 12));\n bytes.push(0x80 | ((charCode >> 6) & 0x3F));\n bytes.push(0x80 | (charCode & 0x3F));\n }\n }\n\n return new Uint8Array(bytes);\n }\n\n encodeInto(source, destination) {\n const encoded = this.encode(source);\n const len = Math.min(encoded.length, destination.length);\n destination.set(encoded.subarray(0, len));\n return { read: source.length, written: len };\n }\n }\n\n class TextDecoder {\n constructor(encoding = \"utf-8\", options = {}) {\n if (encoding !== \"utf-8\" && encoding !== \"utf8\") {\n throw new RangeError(\"The encoding label provided is invalid.\");\n }\n this.encoding = \"utf-8\";\n this.fatal = Boolean(options.fatal);\n this.ignoreBOM = Boolean(options.ignoreBOM);\n }\n\n decode(input, options = {}) {\n if (!input) return \"\";\n\n let bytes;\n if (input instanceof ArrayBuffer) {\n bytes = new Uint8Array(input);\n } else if (ArrayBuffer.isView(input)) {\n bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);\n } else if (input instanceof Uint8Array) {\n bytes = input;\n } else {\n throw new TypeError(\"The provided value is not of type '(ArrayBuffer or ArrayBufferView)'\");\n }\n\n let offset = 0;\n if (!this.ignoreBOM && bytes.length >= 3 &&\n bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) {\n offset = 3;\n }\n\n let result = \"\";\n for (let i = offset; i < bytes.length;) {\n const byte1 = bytes[i++];\n\n if (byte1 < 0x80) {\n result += String.fromCharCode(byte1);\n } else if ((byte1 & 0xE0) === 0xC0) {\n const byte2 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x1F) << 6) | byte2);\n } else if ((byte1 & 0xF0) === 0xE0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n result += String.fromCharCode(((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3);\n } else if ((byte1 & 0xF8) === 0xF0) {\n const byte2 = bytes[i++] & 0x3F;\n const byte3 = bytes[i++] & 0x3F;\n const byte4 = bytes[i++] & 0x3F;\n const codePoint = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4;\n const adjusted = codePoint - 0x10000;\n result += String.fromCharCode(0xD800 + (adjusted >> 10), 0xDC00 + (adjusted & 0x3FF));\n }\n }\n\n return result;\n }\n }\n\n globalThis.TextEncoder = TextEncoder;\n globalThis.TextDecoder = TextDecoder;\n})();\n`;\n\n const textEncodingResult = context.evalCode(textEncodingCode);\n if (textEncodingResult.error) {\n console.error(\"Failed to setup TextEncoder/TextDecoder\");\n textEncodingResult.error.dispose();\n } else {\n textEncodingResult.value.dispose();\n }\n\n /**\n * @returns CoreHandle with shared stateMap and dispose method\n *\n * **dispose() behavior:**\n * - Clears internal handle tracking array\n * - Does NOT dispose globals (ReadableStream, Blob, etc.) - they are owned\n * by context.global and cleaned up by context.dispose()\n * - Call before context.dispose() to release internal references\n *\n * @see PATTERNS.md for implementation patterns\n */\n return {\n stateMap,\n dispose() {\n // Note: handles set on global (ReadableStream, Blob, etc.) are NOT disposed here\n // They are owned by the global object and will be cleaned up by context.dispose()\n // Disposing them before context disposal causes QuickJS GC assertion failures\n handles.length = 0;\n },\n };\n}\n\n// Re-export types\nexport type {\n Scope,\n MarshalOptions,\n UnmarshalOptions,\n PropertyDescriptor,\n ClassDefinition,\n StateMap,\n SetupCoreOptions,\n CoreHandle,\n QuickJSContext,\n QuickJSHandle,\n QuickJSRuntime,\n} from \"./types.mjs\";\nexport { INTERNAL_STATE } from \"./types.mjs\";\n\n// Re-export utilities\nexport { withScope, withScopeAsync } from \"./scope.mjs\";\nexport { marshal, isHandle, getHandleType } from \"./marshal.mjs\";\nexport { unmarshal, cleanupUnmarshaledHandles } from \"./unmarshal.mjs\";\nexport {\n defineFunction,\n defineAsyncFunction,\n defineAsyncIteratorFunction,\n cleanupAsyncIterators,\n} from \"./function-builder.mjs\";\nexport {\n defineClass,\n createStateMap,\n getState,\n setState,\n getInstanceState,\n setInstanceState,\n getInstanceStateById,\n cleanupInstanceState,\n clearAllInstanceState,\n} from \"./class-builder.mjs\";\n\n// Re-export class instance helpers for cross-class access\nexport {\n isDefineClassInstance,\n isInstanceOf,\n getClassInstanceState,\n getInstanceId,\n getClassName,\n createClassTypeGuard,\n isUnmarshalledRequest,\n isUnmarshalledResponse,\n isUnmarshalledHeaders,\n isUnmarshalledFormData,\n} from \"./class-helpers.mjs\";\nexport type { DefineClassInstance, TypedClassInstance } from \"./class-helpers.mjs\";\n\n// Re-export instance state management\nexport {\n nextInstanceId,\n registerInstance,\n getInstanceMetadata,\n getInstanceClassName,\n cleanupInstanceState as cleanupInstanceStateById,\n} from \"./instance-state.mjs\";\nexport type { InstanceMetadata } from \"./instance-state.mjs\";\n\n// Re-export stream utilities\nexport {\n createReadableStream,\n consumeReadableStream,\n} from \"./streams/readable-stream.mjs\";\nexport { createWritableStream } from \"./streams/writable-stream.mjs\";\n\n// Re-export Blob/File utilities\nexport { createBlob } from \"./blob.mjs\";\nexport { createFile } from \"./file.mjs\";\n\n// Re-export URL utilities\nexport { createURLSearchParamsClass } from \"./url-search-params.mjs\";\nexport type { URLSearchParamsState } from \"./url-search-params.mjs\";\nexport { createURLClass, addURLSearchParamsLinkage, addURLSearchParamsGetter } from \"./url.mjs\";\nexport type { URLState } from \"./url.mjs\";\n\n// Re-export coercion utilities\nexport {\n createCoercer,\n classCoercer,\n instanceOrShape,\n coerceURL,\n coerceToURLString,\n coerceHeaders,\n coerceBody,\n coerceRequestInit,\n coerceResponseInit,\n} from \"./coerce.mjs\";\nexport type {\n Coercer,\n CoercionResult,\n URLCoerced,\n HeadersCoerced,\n RequestInitCoerced,\n ResponseInitCoerced,\n} from \"./coerce.mjs\";\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "F1D8DE89A0C3E63864756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "0EA35BEDA988897364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-core",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "type": "module"
5
5
  }
@@ -21,3 +21,25 @@ export declare function defineFunction(context: QuickJSContext, name: string, fn
21
21
  * });
22
22
  */
23
23
  export declare function defineAsyncFunction(context: QuickJSContext, name: string, fn: (...args: unknown[]) => Promise<unknown>): QuickJSHandle;
24
+ /**
25
+ * Define an async iterator function that returns an async iterable to QuickJS.
26
+ * The host function should be an async generator.
27
+ *
28
+ * @example
29
+ * const streamFn = defineAsyncIteratorFunction(context, "stream", async function* (n) {
30
+ * for (let i = 0; i < n; i++) {
31
+ * yield i;
32
+ * }
33
+ * return "done";
34
+ * });
35
+ *
36
+ * // In QuickJS:
37
+ * // for await (const value of stream(3)) { console.log(value); }
38
+ * // Outputs: 0, 1, 2
39
+ */
40
+ export declare function defineAsyncIteratorFunction(context: QuickJSContext, name: string, fn: (...args: unknown[]) => AsyncGenerator<unknown, unknown, unknown>): QuickJSHandle;
41
+ /**
42
+ * Clean up all async iterator state for a context.
43
+ * Should be called before context disposal.
44
+ */
45
+ export declare function cleanupAsyncIterators(context: QuickJSContext): void;
@@ -34,7 +34,7 @@ export { INTERNAL_STATE } from "./types.ts";
34
34
  export { withScope, withScopeAsync } from "./scope.ts";
35
35
  export { marshal, isHandle, getHandleType } from "./marshal.ts";
36
36
  export { unmarshal, cleanupUnmarshaledHandles } from "./unmarshal.ts";
37
- export { defineFunction, defineAsyncFunction } from "./function-builder.ts";
37
+ export { defineFunction, defineAsyncFunction, defineAsyncIteratorFunction, cleanupAsyncIterators, } from "./function-builder.ts";
38
38
  export { defineClass, createStateMap, getState, setState, getInstanceState, setInstanceState, getInstanceStateById, cleanupInstanceState, clearAllInstanceState, } from "./class-builder.ts";
39
39
  export { isDefineClassInstance, isInstanceOf, getClassInstanceState, getInstanceId, getClassName, createClassTypeGuard, isUnmarshalledRequest, isUnmarshalledResponse, isUnmarshalledHeaders, isUnmarshalledFormData, } from "./class-helpers.ts";
40
40
  export type { DefineClassInstance, TypedClassInstance } from "./class-helpers.ts";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-core",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "main": "./dist/cjs/index.cjs",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "exports": {