@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 +111 -4
- package/dist/cjs/function-builder.cjs +184 -2
- package/dist/cjs/function-builder.cjs.map +3 -3
- package/dist/cjs/index.cjs +3 -1
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/function-builder.mjs +184 -2
- package/dist/mjs/function-builder.mjs.map +3 -3
- package/dist/mjs/index.mjs +9 -2
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/function-builder.d.ts +22 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
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
|
-
|
|
21
|
+
## Injected Globals
|
|
22
|
+
|
|
12
23
|
- `ReadableStream`, `WritableStream`, `TransformStream`
|
|
13
24
|
- `ReadableStreamDefaultReader`, `WritableStreamDefaultWriter`
|
|
14
25
|
- `Blob`, `File`
|
|
15
26
|
|
|
16
|
-
|
|
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
|
-
|
|
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=
|
|
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": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "679B9EDB41D36FF564756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -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=
|
|
290
|
+
//# debugId=2704213322BFE26C64756E2164756E21
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -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": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "2704213322BFE26C64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/cjs/package.json
CHANGED
|
@@ -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
|
-
|
|
222
|
+
defineAsyncIteratorFunction,
|
|
223
|
+
defineAsyncFunction,
|
|
224
|
+
cleanupAsyncIterators
|
|
43
225
|
};
|
|
44
226
|
|
|
45
|
-
//# debugId=
|
|
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;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;AACA;AACA;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,QAAQ,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,UAAU,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,QAAQ,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,QAAQ,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,UAAU,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,QAAQ,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,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;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,UAAU,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": "1A737A5AACCCCD4964756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/index.mjs
CHANGED
|
@@ -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 {
|
|
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=
|
|
311
|
+
//# debugId=0EA35BEDA988897364756E2164756E21
|
package/dist/mjs/index.mjs.map
CHANGED
|
@@ -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": ";;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAiSA;AAGA;AACA;AACA;AACA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "0EA35BEDA988897364756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/package.json
CHANGED
|
@@ -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;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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";
|