@ricsam/quickjs-core 0.2.0 → 0.2.1
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/dist/cjs/blob.cjs +197 -0
- package/dist/cjs/blob.cjs.map +10 -0
- package/dist/cjs/class-builder.cjs +244 -0
- package/dist/cjs/class-builder.cjs.map +10 -0
- package/dist/cjs/dom-exception.cjs +95 -0
- package/dist/cjs/dom-exception.cjs.map +10 -0
- package/dist/cjs/file.cjs +234 -0
- package/dist/cjs/file.cjs.map +10 -0
- package/dist/cjs/function-builder.cjs +70 -0
- package/dist/cjs/function-builder.cjs.map +10 -0
- package/dist/cjs/marshal.cjs +191 -0
- package/dist/cjs/marshal.cjs.map +10 -0
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/readable-stream.cjs +588 -0
- package/dist/cjs/readable-stream.cjs.map +10 -0
- package/dist/cjs/scope.cjs +76 -0
- package/dist/cjs/scope.cjs.map +10 -0
- package/dist/cjs/transform-stream.cjs +152 -0
- package/dist/cjs/transform-stream.cjs.map +10 -0
- package/dist/cjs/types.cjs +39 -0
- package/dist/cjs/types.cjs.map +10 -0
- package/dist/cjs/unmarshal.cjs +254 -0
- package/dist/cjs/unmarshal.cjs.map +10 -0
- package/dist/cjs/url-search-params.cjs +165 -0
- package/dist/cjs/url-search-params.cjs.map +10 -0
- package/dist/cjs/url.cjs +183 -0
- package/dist/cjs/url.cjs.map +10 -0
- package/dist/cjs/writable-stream.cjs +513 -0
- package/dist/cjs/writable-stream.cjs.map +10 -0
- package/dist/mjs/blob.mjs +166 -0
- package/dist/mjs/blob.mjs.map +10 -0
- package/dist/mjs/class-builder.mjs +213 -0
- package/dist/mjs/class-builder.mjs.map +10 -0
- package/dist/mjs/dom-exception.mjs +64 -0
- package/dist/mjs/dom-exception.mjs.map +10 -0
- package/dist/mjs/file.mjs +203 -0
- package/dist/mjs/file.mjs.map +10 -0
- package/dist/mjs/function-builder.mjs +39 -0
- package/dist/mjs/function-builder.mjs.map +10 -0
- package/dist/mjs/marshal.mjs +160 -0
- package/dist/mjs/marshal.mjs.map +10 -0
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/readable-stream.mjs +557 -0
- package/dist/mjs/readable-stream.mjs.map +10 -0
- package/dist/mjs/scope.mjs +45 -0
- package/dist/mjs/scope.mjs.map +10 -0
- package/dist/mjs/transform-stream.mjs +121 -0
- package/dist/mjs/transform-stream.mjs.map +10 -0
- package/dist/mjs/types.mjs +8 -0
- package/dist/mjs/types.mjs.map +10 -0
- package/dist/mjs/unmarshal.mjs +223 -0
- package/dist/mjs/unmarshal.mjs.map +10 -0
- package/dist/mjs/url-search-params.mjs +134 -0
- package/dist/mjs/url-search-params.mjs.map +10 -0
- package/dist/mjs/url.mjs +152 -0
- package/dist/mjs/url.mjs.map +10 -0
- package/dist/mjs/writable-stream.mjs +482 -0
- package/dist/mjs/writable-stream.mjs.map +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/core/src/file.ts
|
|
3
|
+
import { defineClass } from "./class-builder.ts";
|
|
4
|
+
function normalizeParts(parts) {
|
|
5
|
+
const result = [];
|
|
6
|
+
for (const part of parts) {
|
|
7
|
+
if (typeof part === "string") {
|
|
8
|
+
result.push(new TextEncoder().encode(part));
|
|
9
|
+
} else if (part instanceof Uint8Array) {
|
|
10
|
+
result.push(part);
|
|
11
|
+
} else if (part instanceof ArrayBuffer) {
|
|
12
|
+
result.push(new Uint8Array(part));
|
|
13
|
+
} else if (ArrayBuffer.isView(part)) {
|
|
14
|
+
result.push(new Uint8Array(part.buffer, part.byteOffset, part.byteLength));
|
|
15
|
+
} else if (part && typeof part === "object") {
|
|
16
|
+
if ("byteLength" in part && typeof part.byteLength === "number") {
|
|
17
|
+
try {
|
|
18
|
+
result.push(new Uint8Array(part));
|
|
19
|
+
} catch {
|
|
20
|
+
if ("buffer" in part && "byteOffset" in part) {
|
|
21
|
+
const view = part;
|
|
22
|
+
try {
|
|
23
|
+
result.push(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
|
|
24
|
+
} catch {}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} else if ("parts" in part) {
|
|
28
|
+
const blobParts = part.parts;
|
|
29
|
+
result.push(...blobParts);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function concatenateParts(parts) {
|
|
36
|
+
const totalLength = parts.reduce((sum, part) => sum + part.length, 0);
|
|
37
|
+
const result = new Uint8Array(totalLength);
|
|
38
|
+
let offset = 0;
|
|
39
|
+
for (const part of parts) {
|
|
40
|
+
result.set(part, offset);
|
|
41
|
+
offset += part.length;
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
function createFileClass(context, stateMap, _blobClass) {
|
|
46
|
+
return defineClass(context, stateMap, {
|
|
47
|
+
name: "File",
|
|
48
|
+
construct: (args) => {
|
|
49
|
+
const fileBits = args[0];
|
|
50
|
+
const fileName = args[1];
|
|
51
|
+
const options = args[2];
|
|
52
|
+
const parts = fileBits ? normalizeParts(fileBits) : [];
|
|
53
|
+
const size = parts.reduce((sum, part) => sum + part.length, 0);
|
|
54
|
+
const type = options?.type ?? "";
|
|
55
|
+
const lastModified = options?.lastModified ?? Date.now();
|
|
56
|
+
return {
|
|
57
|
+
parts,
|
|
58
|
+
type,
|
|
59
|
+
size,
|
|
60
|
+
name: String(fileName),
|
|
61
|
+
lastModified,
|
|
62
|
+
webkitRelativePath: ""
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
properties: {
|
|
66
|
+
size: {
|
|
67
|
+
get() {
|
|
68
|
+
return this.size;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
type: {
|
|
72
|
+
get() {
|
|
73
|
+
return this.type;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
name: {
|
|
77
|
+
get() {
|
|
78
|
+
return this.name;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
lastModified: {
|
|
82
|
+
get() {
|
|
83
|
+
return this.lastModified;
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
webkitRelativePath: {
|
|
87
|
+
get() {
|
|
88
|
+
return this.webkitRelativePath;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
methods: {
|
|
93
|
+
async text() {
|
|
94
|
+
const data = concatenateParts(this.parts);
|
|
95
|
+
return new TextDecoder().decode(data);
|
|
96
|
+
},
|
|
97
|
+
async arrayBuffer() {
|
|
98
|
+
const data = concatenateParts(this.parts);
|
|
99
|
+
return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
100
|
+
},
|
|
101
|
+
async bytes() {
|
|
102
|
+
return concatenateParts(this.parts);
|
|
103
|
+
},
|
|
104
|
+
slice(start, end, contentType) {
|
|
105
|
+
const data = concatenateParts(this.parts);
|
|
106
|
+
const startIndex = typeof start === "number" ? start : 0;
|
|
107
|
+
const endIndex = typeof end === "number" ? end : data.length;
|
|
108
|
+
const sliced = data.slice(startIndex, endIndex);
|
|
109
|
+
return {
|
|
110
|
+
parts: [sliced],
|
|
111
|
+
type: typeof contentType === "string" ? contentType : this.type,
|
|
112
|
+
size: sliced.length
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
stream() {
|
|
116
|
+
const data = concatenateParts(this.parts);
|
|
117
|
+
let offset = 0;
|
|
118
|
+
const chunkSize = 65536;
|
|
119
|
+
return {
|
|
120
|
+
pull: (controller) => {
|
|
121
|
+
if (offset >= data.length) {
|
|
122
|
+
controller.close();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const chunk = data.slice(offset, Math.min(offset + chunkSize, data.length));
|
|
126
|
+
offset += chunk.length;
|
|
127
|
+
controller.enqueue(chunk);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function createFile(context, stateMap, parts, name, options) {
|
|
135
|
+
const FileConstructor = context.getProp(context.global, "File");
|
|
136
|
+
const partsHandle = context.newArray();
|
|
137
|
+
for (let i = 0;i < parts.length; i++) {
|
|
138
|
+
const part = parts[i];
|
|
139
|
+
let partHandle;
|
|
140
|
+
if (typeof part === "string") {
|
|
141
|
+
partHandle = context.newString(part);
|
|
142
|
+
} else if (part instanceof ArrayBuffer) {
|
|
143
|
+
partHandle = context.newArrayBuffer(part);
|
|
144
|
+
} else if (part instanceof Uint8Array) {
|
|
145
|
+
partHandle = context.newArrayBuffer(part.buffer.slice(part.byteOffset, part.byteOffset + part.byteLength));
|
|
146
|
+
} else if (part instanceof Blob) {
|
|
147
|
+
partHandle = context.newString("[Blob]");
|
|
148
|
+
} else {
|
|
149
|
+
partHandle = context.newString(String(part));
|
|
150
|
+
}
|
|
151
|
+
context.setProp(partsHandle, i, partHandle);
|
|
152
|
+
partHandle.dispose();
|
|
153
|
+
}
|
|
154
|
+
const nameHandle = context.newString(name);
|
|
155
|
+
const optionsHandle = context.newObject();
|
|
156
|
+
if (options?.type) {
|
|
157
|
+
const typeHandle = context.newString(options.type);
|
|
158
|
+
context.setProp(optionsHandle, "type", typeHandle);
|
|
159
|
+
typeHandle.dispose();
|
|
160
|
+
}
|
|
161
|
+
if (options?.lastModified !== undefined) {
|
|
162
|
+
const lastModifiedHandle = context.newNumber(options.lastModified);
|
|
163
|
+
context.setProp(optionsHandle, "lastModified", lastModifiedHandle);
|
|
164
|
+
lastModifiedHandle.dispose();
|
|
165
|
+
}
|
|
166
|
+
FileConstructor.dispose();
|
|
167
|
+
context.setProp(context.global, "__tempFileParts__", partsHandle);
|
|
168
|
+
context.setProp(context.global, "__tempFileName__", nameHandle);
|
|
169
|
+
context.setProp(context.global, "__tempFileOptions__", optionsHandle);
|
|
170
|
+
partsHandle.dispose();
|
|
171
|
+
nameHandle.dispose();
|
|
172
|
+
optionsHandle.dispose();
|
|
173
|
+
const result = context.evalCode("new File(__tempFileParts__, __tempFileName__, __tempFileOptions__)");
|
|
174
|
+
const cleanup1 = context.evalCode("delete globalThis.__tempFileParts__");
|
|
175
|
+
const cleanup2 = context.evalCode("delete globalThis.__tempFileName__");
|
|
176
|
+
const cleanup3 = context.evalCode("delete globalThis.__tempFileOptions__");
|
|
177
|
+
if (cleanup1.error)
|
|
178
|
+
cleanup1.error.dispose();
|
|
179
|
+
else
|
|
180
|
+
cleanup1.value.dispose();
|
|
181
|
+
if (cleanup2.error)
|
|
182
|
+
cleanup2.error.dispose();
|
|
183
|
+
else
|
|
184
|
+
cleanup2.value.dispose();
|
|
185
|
+
if (cleanup3.error)
|
|
186
|
+
cleanup3.error.dispose();
|
|
187
|
+
else
|
|
188
|
+
cleanup3.value.dispose();
|
|
189
|
+
if (result.error) {
|
|
190
|
+
const msgHandle = context.getProp(result.error, "message");
|
|
191
|
+
const errorMsg = context.dump(msgHandle);
|
|
192
|
+
msgHandle.dispose();
|
|
193
|
+
result.error.dispose();
|
|
194
|
+
throw new Error(`Failed to create File: ${errorMsg}`);
|
|
195
|
+
}
|
|
196
|
+
return result.value;
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
createFileClass,
|
|
200
|
+
createFile
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
//# debugId=387C3080E0064C9B64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/file.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap } from \"./types.ts\";\nimport { defineClass } from \"./class-builder.ts\";\n\ninterface FileInternalState {\n parts: Uint8Array[];\n type: string;\n size: number;\n name: string;\n lastModified: number;\n webkitRelativePath: string;\n}\n\n/**\n * Normalize file parts to Uint8Array\n * Handles various input types including cross-realm ArrayBuffer/Uint8Array\n */\nfunction normalizeParts(parts: unknown[]): Uint8Array[] {\n const result: Uint8Array[] = [];\n\n for (const part of parts) {\n if (typeof part === \"string\") {\n result.push(new TextEncoder().encode(part));\n } else if (part instanceof Uint8Array) {\n result.push(part);\n } else if (part instanceof ArrayBuffer) {\n result.push(new Uint8Array(part));\n } else if (ArrayBuffer.isView(part)) {\n result.push(new Uint8Array(part.buffer, part.byteOffset, part.byteLength));\n } else if (part && typeof part === \"object\") {\n // Handle cross-realm or duck-typed ArrayBuffer-like objects\n if (\"byteLength\" in part && typeof (part as ArrayBuffer).byteLength === \"number\") {\n try {\n // Try as ArrayBuffer\n result.push(new Uint8Array(part as ArrayBuffer));\n } catch {\n // If that fails, try as TypedArray-like with buffer property\n if (\"buffer\" in part && \"byteOffset\" in part) {\n const view = part as ArrayBufferView;\n try {\n result.push(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));\n } catch {\n // Skip invalid parts\n }\n }\n }\n } else if (\"parts\" in part) {\n // Another Blob-like object\n const blobParts = (part as { parts: Uint8Array[] }).parts;\n result.push(...blobParts);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Concatenate Uint8Arrays into a single Uint8Array\n */\nfunction concatenateParts(parts: Uint8Array[]): Uint8Array {\n const totalLength = parts.reduce((sum, part) => sum + part.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const part of parts) {\n result.set(part, offset);\n offset += part.length;\n }\n return result;\n}\n\n/**\n * Create the File class for QuickJS (extends Blob)\n */\nexport function createFileClass(\n context: QuickJSContext,\n stateMap: StateMap,\n _blobClass: QuickJSHandle\n): QuickJSHandle {\n return defineClass<FileInternalState>(context, stateMap, {\n name: \"File\",\n construct: (args) => {\n const fileBits = args[0] as unknown[] | undefined;\n const fileName = args[1] as string;\n const options = args[2] as { type?: string; lastModified?: number } | undefined;\n\n const parts = fileBits ? normalizeParts(fileBits) : [];\n const size = parts.reduce((sum, part) => sum + part.length, 0);\n const type = options?.type ?? \"\";\n const lastModified = options?.lastModified ?? Date.now();\n\n return {\n parts,\n type,\n size,\n name: String(fileName),\n lastModified,\n webkitRelativePath: \"\",\n };\n },\n properties: {\n size: {\n get(this: FileInternalState) {\n return this.size;\n },\n },\n type: {\n get(this: FileInternalState) {\n return this.type;\n },\n },\n name: {\n get(this: FileInternalState) {\n return this.name;\n },\n },\n lastModified: {\n get(this: FileInternalState) {\n return this.lastModified;\n },\n },\n webkitRelativePath: {\n get(this: FileInternalState) {\n return this.webkitRelativePath;\n },\n },\n },\n methods: {\n async text(this: FileInternalState): Promise<string> {\n const data = concatenateParts(this.parts);\n return new TextDecoder().decode(data);\n },\n async arrayBuffer(this: FileInternalState): Promise<ArrayBuffer> {\n const data = concatenateParts(this.parts);\n return data.buffer.slice(\n data.byteOffset,\n data.byteOffset + data.byteLength\n ) as ArrayBuffer;\n },\n async bytes(this: FileInternalState): Promise<Uint8Array> {\n return concatenateParts(this.parts);\n },\n slice(\n this: FileInternalState,\n start?: unknown,\n end?: unknown,\n contentType?: unknown\n ): object {\n const data = concatenateParts(this.parts);\n const startIndex = typeof start === \"number\" ? start : 0;\n const endIndex = typeof end === \"number\" ? end : data.length;\n const sliced = data.slice(startIndex, endIndex);\n\n // Return a Blob-like state (not a File, as per spec)\n return {\n parts: [sliced],\n type: typeof contentType === \"string\" ? contentType : this.type,\n size: sliced.length,\n };\n },\n stream(this: FileInternalState): object {\n const data = concatenateParts(this.parts);\n let offset = 0;\n const chunkSize = 65536; // 64KB chunks\n\n return {\n pull: (controller: { enqueue: (chunk: unknown) => void; close: () => void }) => {\n if (offset >= data.length) {\n controller.close();\n return;\n }\n\n const chunk = data.slice(offset, Math.min(offset + chunkSize, data.length));\n offset += chunk.length;\n controller.enqueue(chunk);\n },\n };\n },\n },\n });\n}\n\n/**\n * Create a File in QuickJS from host data\n */\nexport function createFile(\n context: QuickJSContext,\n stateMap: StateMap,\n parts: BlobPart[],\n name: string,\n options?: FilePropertyBag\n): QuickJSHandle {\n // Get the File constructor from global\n const FileConstructor = context.getProp(context.global, \"File\");\n\n // Marshal the parts\n const partsHandle = context.newArray();\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n let partHandle: QuickJSHandle;\n\n if (typeof part === \"string\") {\n partHandle = context.newString(part);\n } else if (part instanceof ArrayBuffer) {\n partHandle = context.newArrayBuffer(part);\n } else if (part instanceof Uint8Array) {\n partHandle = context.newArrayBuffer(\n part.buffer.slice(part.byteOffset, part.byteOffset + part.byteLength)\n );\n } else if (part instanceof Blob) {\n partHandle = context.newString(\"[Blob]\");\n } else {\n partHandle = context.newString(String(part));\n }\n\n context.setProp(partsHandle, i, partHandle);\n partHandle.dispose();\n }\n\n // Marshal name\n const nameHandle = context.newString(name);\n\n // Marshal options\n const optionsHandle = context.newObject();\n if (options?.type) {\n const typeHandle = context.newString(options.type);\n context.setProp(optionsHandle, \"type\", typeHandle);\n typeHandle.dispose();\n }\n if (options?.lastModified !== undefined) {\n const lastModifiedHandle = context.newNumber(options.lastModified);\n context.setProp(optionsHandle, \"lastModified\", lastModifiedHandle);\n lastModifiedHandle.dispose();\n }\n\n FileConstructor.dispose();\n\n // Set temporary globals for evalCode\n context.setProp(context.global, \"__tempFileParts__\", partsHandle);\n context.setProp(context.global, \"__tempFileName__\", nameHandle);\n context.setProp(context.global, \"__tempFileOptions__\", optionsHandle);\n partsHandle.dispose();\n nameHandle.dispose();\n optionsHandle.dispose();\n\n // Create File using evalCode with 'new' (callFunction doesn't work with constructors)\n const result = context.evalCode(\n \"new File(__tempFileParts__, __tempFileName__, __tempFileOptions__)\"\n );\n\n // Clean up temporary globals\n const cleanup1 = context.evalCode(\"delete globalThis.__tempFileParts__\");\n const cleanup2 = context.evalCode(\"delete globalThis.__tempFileName__\");\n const cleanup3 = context.evalCode(\"delete globalThis.__tempFileOptions__\");\n if (cleanup1.error) cleanup1.error.dispose();\n else cleanup1.value.dispose();\n if (cleanup2.error) cleanup2.error.dispose();\n else cleanup2.value.dispose();\n if (cleanup3.error) cleanup3.error.dispose();\n else cleanup3.value.dispose();\n\n if (result.error) {\n const msgHandle = context.getProp(result.error, \"message\");\n const errorMsg = context.dump(msgHandle);\n msgHandle.dispose();\n result.error.dispose();\n throw new Error(`Failed to create File: ${errorMsg}`);\n }\n\n return result.value;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;AAEA;AAeA,SAAS,cAAc,CAAC,OAAgC;AAAA,EACtD,MAAM,SAAuB,CAAC;AAAA,EAE9B,WAAW,QAAQ,OAAO;AAAA,IACxB,IAAI,OAAO,SAAS,UAAU;AAAA,MAC5B,OAAO,KAAK,IAAI,YAAY,EAAE,OAAO,IAAI,CAAC;AAAA,IAC5C,EAAO,SAAI,gBAAgB,YAAY;AAAA,MACrC,OAAO,KAAK,IAAI;AAAA,IAClB,EAAO,SAAI,gBAAgB,aAAa;AAAA,MACtC,OAAO,KAAK,IAAI,WAAW,IAAI,CAAC;AAAA,IAClC,EAAO,SAAI,YAAY,OAAO,IAAI,GAAG;AAAA,MACnC,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC;AAAA,IAC3E,EAAO,SAAI,QAAQ,OAAO,SAAS,UAAU;AAAA,MAE3C,IAAI,gBAAgB,QAAQ,OAAQ,KAAqB,eAAe,UAAU;AAAA,QAChF,IAAI;AAAA,UAEF,OAAO,KAAK,IAAI,WAAW,IAAmB,CAAC;AAAA,UAC/C,MAAM;AAAA,UAEN,IAAI,YAAY,QAAQ,gBAAgB,MAAM;AAAA,YAC5C,MAAM,OAAO;AAAA,YACb,IAAI;AAAA,cACF,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC;AAAA,cACzE,MAAM;AAAA,UAGV;AAAA;AAAA,MAEJ,EAAO,SAAI,WAAW,MAAM;AAAA,QAE1B,MAAM,YAAa,KAAiC;AAAA,QACpD,OAAO,KAAK,GAAG,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;AAMT,SAAS,gBAAgB,CAAC,OAAiC;AAAA,EACzD,MAAM,cAAc,MAAM,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,QAAQ,CAAC;AAAA,EACpE,MAAM,SAAS,IAAI,WAAW,WAAW;AAAA,EACzC,IAAI,SAAS;AAAA,EACb,WAAW,QAAQ,OAAO;AAAA,IACxB,OAAO,IAAI,MAAM,MAAM;AAAA,IACvB,UAAU,KAAK;AAAA,EACjB;AAAA,EACA,OAAO;AAAA;AAMF,SAAS,eAAe,CAC7B,SACA,UACA,YACe;AAAA,EACf,OAAO,YAA+B,SAAS,UAAU;AAAA,IACvD,MAAM;AAAA,IACN,WAAW,CAAC,SAAS;AAAA,MACnB,MAAM,WAAW,KAAK;AAAA,MACtB,MAAM,WAAW,KAAK;AAAA,MACtB,MAAM,UAAU,KAAK;AAAA,MAErB,MAAM,QAAQ,WAAW,eAAe,QAAQ,IAAI,CAAC;AAAA,MACrD,MAAM,OAAO,MAAM,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,QAAQ,CAAC;AAAA,MAC7D,MAAM,OAAO,SAAS,QAAQ;AAAA,MAC9B,MAAM,eAAe,SAAS,gBAAgB,KAAK,IAAI;AAAA,MAEvD,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM,OAAO,QAAQ;AAAA,QACrB;AAAA,QACA,oBAAoB;AAAA,MACtB;AAAA;AAAA,IAEF,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,GAAG,GAA0B;AAAA,UAC3B,OAAO,KAAK;AAAA;AAAA,MAEhB;AAAA,MACA,MAAM;AAAA,QACJ,GAAG,GAA0B;AAAA,UAC3B,OAAO,KAAK;AAAA;AAAA,MAEhB;AAAA,MACA,MAAM;AAAA,QACJ,GAAG,GAA0B;AAAA,UAC3B,OAAO,KAAK;AAAA;AAAA,MAEhB;AAAA,MACA,cAAc;AAAA,QACZ,GAAG,GAA0B;AAAA,UAC3B,OAAO,KAAK;AAAA;AAAA,MAEhB;AAAA,MACA,oBAAoB;AAAA,QAClB,GAAG,GAA0B;AAAA,UAC3B,OAAO,KAAK;AAAA;AAAA,MAEhB;AAAA,IACF;AAAA,IACA,SAAS;AAAA,WACD,KAAI,GAA2C;AAAA,QACnD,MAAM,OAAO,iBAAiB,KAAK,KAAK;AAAA,QACxC,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AAAA;AAAA,WAEhC,YAAW,GAAgD;AAAA,QAC/D,MAAM,OAAO,iBAAiB,KAAK,KAAK;AAAA,QACxC,OAAO,KAAK,OAAO,MACjB,KAAK,YACL,KAAK,aAAa,KAAK,UACzB;AAAA;AAAA,WAEI,MAAK,GAA+C;AAAA,QACxD,OAAO,iBAAiB,KAAK,KAAK;AAAA;AAAA,MAEpC,KAAK,CAEH,OACA,KACA,aACQ;AAAA,QACR,MAAM,OAAO,iBAAiB,KAAK,KAAK;AAAA,QACxC,MAAM,aAAa,OAAO,UAAU,WAAW,QAAQ;AAAA,QACvD,MAAM,WAAW,OAAO,QAAQ,WAAW,MAAM,KAAK;AAAA,QACtD,MAAM,SAAS,KAAK,MAAM,YAAY,QAAQ;AAAA,QAG9C,OAAO;AAAA,UACL,OAAO,CAAC,MAAM;AAAA,UACd,MAAM,OAAO,gBAAgB,WAAW,cAAc,KAAK;AAAA,UAC3D,MAAM,OAAO;AAAA,QACf;AAAA;AAAA,MAEF,MAAM,GAAkC;AAAA,QACtC,MAAM,OAAO,iBAAiB,KAAK,KAAK;AAAA,QACxC,IAAI,SAAS;AAAA,QACb,MAAM,YAAY;AAAA,QAElB,OAAO;AAAA,UACL,MAAM,CAAC,eAAyE;AAAA,YAC9E,IAAI,UAAU,KAAK,QAAQ;AAAA,cACzB,WAAW,MAAM;AAAA,cACjB;AAAA,YACF;AAAA,YAEA,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK,IAAI,SAAS,WAAW,KAAK,MAAM,CAAC;AAAA,YAC1E,UAAU,MAAM;AAAA,YAChB,WAAW,QAAQ,KAAK;AAAA;AAAA,QAE5B;AAAA;AAAA,IAEJ;AAAA,EACF,CAAC;AAAA;AAMI,SAAS,UAAU,CACxB,SACA,UACA,OACA,MACA,SACe;AAAA,EAEf,MAAM,kBAAkB,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;AAAA,EAG9D,MAAM,cAAc,QAAQ,SAAS;AAAA,EACrC,SAAS,IAAI,EAAG,IAAI,MAAM,QAAQ,KAAK;AAAA,IACrC,MAAM,OAAO,MAAM;AAAA,IACnB,IAAI;AAAA,IAEJ,IAAI,OAAO,SAAS,UAAU;AAAA,MAC5B,aAAa,QAAQ,UAAU,IAAI;AAAA,IACrC,EAAO,SAAI,gBAAgB,aAAa;AAAA,MACtC,aAAa,QAAQ,eAAe,IAAI;AAAA,IAC1C,EAAO,SAAI,gBAAgB,YAAY;AAAA,MACrC,aAAa,QAAQ,eACnB,KAAK,OAAO,MAAM,KAAK,YAAY,KAAK,aAAa,KAAK,UAAU,CACtE;AAAA,IACF,EAAO,SAAI,gBAAgB,MAAM;AAAA,MAC/B,aAAa,QAAQ,UAAU,QAAQ;AAAA,IACzC,EAAO;AAAA,MACL,aAAa,QAAQ,UAAU,OAAO,IAAI,CAAC;AAAA;AAAA,IAG7C,QAAQ,QAAQ,aAAa,GAAG,UAAU;AAAA,IAC1C,WAAW,QAAQ;AAAA,EACrB;AAAA,EAGA,MAAM,aAAa,QAAQ,UAAU,IAAI;AAAA,EAGzC,MAAM,gBAAgB,QAAQ,UAAU;AAAA,EACxC,IAAI,SAAS,MAAM;AAAA,IACjB,MAAM,aAAa,QAAQ,UAAU,QAAQ,IAAI;AAAA,IACjD,QAAQ,QAAQ,eAAe,QAAQ,UAAU;AAAA,IACjD,WAAW,QAAQ;AAAA,EACrB;AAAA,EACA,IAAI,SAAS,iBAAiB,WAAW;AAAA,IACvC,MAAM,qBAAqB,QAAQ,UAAU,QAAQ,YAAY;AAAA,IACjE,QAAQ,QAAQ,eAAe,gBAAgB,kBAAkB;AAAA,IACjE,mBAAmB,QAAQ;AAAA,EAC7B;AAAA,EAEA,gBAAgB,QAAQ;AAAA,EAGxB,QAAQ,QAAQ,QAAQ,QAAQ,qBAAqB,WAAW;AAAA,EAChE,QAAQ,QAAQ,QAAQ,QAAQ,oBAAoB,UAAU;AAAA,EAC9D,QAAQ,QAAQ,QAAQ,QAAQ,uBAAuB,aAAa;AAAA,EACpE,YAAY,QAAQ;AAAA,EACpB,WAAW,QAAQ;AAAA,EACnB,cAAc,QAAQ;AAAA,EAGtB,MAAM,SAAS,QAAQ,SACrB,oEACF;AAAA,EAGA,MAAM,WAAW,QAAQ,SAAS,qCAAqC;AAAA,EACvE,MAAM,WAAW,QAAQ,SAAS,oCAAoC;AAAA,EACtE,MAAM,WAAW,QAAQ,SAAS,uCAAuC;AAAA,EACzE,IAAI,SAAS;AAAA,IAAO,SAAS,MAAM,QAAQ;AAAA,EACtC;AAAA,aAAS,MAAM,QAAQ;AAAA,EAC5B,IAAI,SAAS;AAAA,IAAO,SAAS,MAAM,QAAQ;AAAA,EACtC;AAAA,aAAS,MAAM,QAAQ;AAAA,EAC5B,IAAI,SAAS;AAAA,IAAO,SAAS,MAAM,QAAQ;AAAA,EACtC;AAAA,aAAS,MAAM,QAAQ;AAAA,EAE5B,IAAI,OAAO,OAAO;AAAA,IAChB,MAAM,YAAY,QAAQ,QAAQ,OAAO,OAAO,SAAS;AAAA,IACzD,MAAM,WAAW,QAAQ,KAAK,SAAS;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,OAAO,MAAM,QAAQ;AAAA,IACrB,MAAM,IAAI,MAAM,0BAA0B,UAAU;AAAA,EACtD;AAAA,EAEA,OAAO,OAAO;AAAA;",
|
|
8
|
+
"debugId": "387C3080E0064C9B64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/core/src/function-builder.ts
|
|
3
|
+
import { unmarshal } from "./unmarshal.ts";
|
|
4
|
+
import { marshal } from "./marshal.ts";
|
|
5
|
+
function defineFunction(context, name, fn) {
|
|
6
|
+
return context.newFunction(name, (...argHandles) => {
|
|
7
|
+
const args = argHandles.map((h) => unmarshal(context, h));
|
|
8
|
+
try {
|
|
9
|
+
const result = fn(...args);
|
|
10
|
+
return marshal(context, result);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
throw context.newError(error instanceof Error ? error.message : String(error));
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function defineAsyncFunction(context, name, fn) {
|
|
17
|
+
return context.newFunction(name, (...argHandles) => {
|
|
18
|
+
const args = argHandles.map((h) => unmarshal(context, h));
|
|
19
|
+
const deferred = context.newPromise();
|
|
20
|
+
fn(...args).then((result) => {
|
|
21
|
+
const resultHandle = marshal(context, result);
|
|
22
|
+
deferred.resolve(resultHandle);
|
|
23
|
+
resultHandle.dispose();
|
|
24
|
+
context.runtime.executePendingJobs();
|
|
25
|
+
}).catch((error) => {
|
|
26
|
+
const errorHandle = marshal(context, error instanceof Error ? { name: error.name, message: error.message } : { message: String(error) });
|
|
27
|
+
deferred.reject(errorHandle);
|
|
28
|
+
errorHandle.dispose();
|
|
29
|
+
context.runtime.executePendingJobs();
|
|
30
|
+
});
|
|
31
|
+
return deferred.handle;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
defineFunction,
|
|
36
|
+
defineAsyncFunction
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
//# debugId=420324452008D1FF64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/function-builder.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { unmarshal } from \"./unmarshal.ts\";\nimport { marshal } from \"./marshal.ts\";\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 const resultHandle = marshal(context, result);\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\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"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;AACA;AACA;AAaO,SAAS,cAAc,CAC5B,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,UAAU,SAAS,CAAC,CAAC;AAAA,IAExD,IAAI;AAAA,MAEF,MAAM,SAAS,GAAG,GAAG,IAAI;AAAA,MAGzB,OAAO,QAAQ,SAAS,MAAM;AAAA,MAC9B,OAAO,OAAO;AAAA,MAEd,MAAM,QAAQ,SACZ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CACvD;AAAA;AAAA,GAEH;AAAA;AAYI,SAAS,mBAAmB,CACjC,SACA,MACA,IACe;AAAA,EACf,OAAO,QAAQ,YAAY,MAAM,IAAI,eAAe;AAAA,IAElD,MAAM,OAAO,WAAW,IAAI,CAAC,MAAM,UAAU,SAAS,CAAC,CAAC;AAAA,IAGxD,MAAM,WAAW,QAAQ,WAAW;AAAA,IAGpC,GAAG,GAAG,IAAI,EACP,KAAK,CAAC,WAAW;AAAA,MAChB,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,MAChB,MAAM,cAAc,QAClB,SACA,iBAAiB,QACb,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ,IAC3C,EAAE,SAAS,OAAO,KAAK,EAAE,CAC/B;AAAA,MACA,SAAS,OAAO,WAAW;AAAA,MAC3B,YAAY,QAAQ;AAAA,MACpB,QAAQ,QAAQ,mBAAmB;AAAA,KACpC;AAAA,IAEH,OAAO,SAAS;AAAA,GACjB;AAAA;",
|
|
8
|
+
"debugId": "420324452008D1FF64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/core/src/marshal.ts
|
|
3
|
+
function isHandle(value) {
|
|
4
|
+
return value !== null && typeof value === "object" && "alive" in value && "dispose" in value && typeof value.dispose === "function";
|
|
5
|
+
}
|
|
6
|
+
function getHandleType(context, handle) {
|
|
7
|
+
return context.typeof(handle);
|
|
8
|
+
}
|
|
9
|
+
function marshal(context, value, options = {}) {
|
|
10
|
+
const maxDepth = options.maxDepth ?? 10;
|
|
11
|
+
const seen = new WeakSet;
|
|
12
|
+
function marshalValue(val, depth) {
|
|
13
|
+
if (depth > maxDepth) {
|
|
14
|
+
throw new Error(`Maximum marshalling depth of ${maxDepth} exceeded`);
|
|
15
|
+
}
|
|
16
|
+
if (isHandle(val)) {
|
|
17
|
+
return val;
|
|
18
|
+
}
|
|
19
|
+
if (options.custom) {
|
|
20
|
+
const customResult = options.custom(val, context);
|
|
21
|
+
if (customResult !== undefined) {
|
|
22
|
+
return customResult;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (val === undefined) {
|
|
26
|
+
return context.undefined;
|
|
27
|
+
}
|
|
28
|
+
if (val === null) {
|
|
29
|
+
return context.null;
|
|
30
|
+
}
|
|
31
|
+
if (typeof val === "boolean") {
|
|
32
|
+
return val ? context.true : context.false;
|
|
33
|
+
}
|
|
34
|
+
if (typeof val === "number") {
|
|
35
|
+
return context.newNumber(val);
|
|
36
|
+
}
|
|
37
|
+
if (typeof val === "string") {
|
|
38
|
+
return context.newString(val);
|
|
39
|
+
}
|
|
40
|
+
if (typeof val === "bigint") {
|
|
41
|
+
return context.newBigInt(val);
|
|
42
|
+
}
|
|
43
|
+
if (typeof val === "symbol") {
|
|
44
|
+
return context.newString(val.toString());
|
|
45
|
+
}
|
|
46
|
+
if (typeof val === "object") {
|
|
47
|
+
if (seen.has(val)) {
|
|
48
|
+
throw new Error("Circular reference detected during marshalling");
|
|
49
|
+
}
|
|
50
|
+
seen.add(val);
|
|
51
|
+
try {
|
|
52
|
+
if (val instanceof ArrayBuffer) {
|
|
53
|
+
return context.newArrayBuffer(val);
|
|
54
|
+
}
|
|
55
|
+
if (val instanceof Uint8Array) {
|
|
56
|
+
const buffer = val.buffer.slice(val.byteOffset, val.byteOffset + val.byteLength);
|
|
57
|
+
const bufferHandle = context.newArrayBuffer(buffer);
|
|
58
|
+
context.setProp(context.global, "__tempMarshalBuffer__", bufferHandle);
|
|
59
|
+
bufferHandle.dispose();
|
|
60
|
+
const result = context.evalCode("new Uint8Array(__tempMarshalBuffer__)");
|
|
61
|
+
const cleanup = context.evalCode("delete globalThis.__tempMarshalBuffer__");
|
|
62
|
+
if (cleanup.error)
|
|
63
|
+
cleanup.error.dispose();
|
|
64
|
+
else
|
|
65
|
+
cleanup.value.dispose();
|
|
66
|
+
if (result.error) {
|
|
67
|
+
result.error.dispose();
|
|
68
|
+
return context.newArrayBuffer(buffer);
|
|
69
|
+
}
|
|
70
|
+
return result.value;
|
|
71
|
+
}
|
|
72
|
+
if (ArrayBuffer.isView(val)) {
|
|
73
|
+
const buffer = val.buffer.slice(val.byteOffset, val.byteOffset + val.byteLength);
|
|
74
|
+
return context.newArrayBuffer(buffer);
|
|
75
|
+
}
|
|
76
|
+
if (val instanceof Date) {
|
|
77
|
+
const dateConstructor = context.getProp(context.global, "Date");
|
|
78
|
+
const timestamp = context.newNumber(val.getTime());
|
|
79
|
+
const result = context.callFunction(dateConstructor, context.undefined, timestamp);
|
|
80
|
+
dateConstructor.dispose();
|
|
81
|
+
timestamp.dispose();
|
|
82
|
+
if (result.error) {
|
|
83
|
+
const error = result.error;
|
|
84
|
+
result.error.dispose();
|
|
85
|
+
throw new Error(`Failed to create Date: ${context.dump(error)}`);
|
|
86
|
+
}
|
|
87
|
+
return result.value;
|
|
88
|
+
}
|
|
89
|
+
if (val instanceof Promise) {
|
|
90
|
+
const deferred = context.newPromise();
|
|
91
|
+
val.then((resolved) => {
|
|
92
|
+
const resolvedHandle = marshalValue(resolved, depth + 1);
|
|
93
|
+
deferred.resolve(resolvedHandle);
|
|
94
|
+
resolvedHandle.dispose();
|
|
95
|
+
context.runtime.executePendingJobs();
|
|
96
|
+
}).catch((error) => {
|
|
97
|
+
const errorHandle = marshalValue(error instanceof Error ? { name: error.name, message: error.message } : error, depth + 1);
|
|
98
|
+
deferred.reject(errorHandle);
|
|
99
|
+
errorHandle.dispose();
|
|
100
|
+
context.runtime.executePendingJobs();
|
|
101
|
+
});
|
|
102
|
+
return deferred.handle;
|
|
103
|
+
}
|
|
104
|
+
if (Array.isArray(val)) {
|
|
105
|
+
const arr = context.newArray();
|
|
106
|
+
for (let i = 0;i < val.length; i++) {
|
|
107
|
+
const elementHandle = marshalValue(val[i], depth + 1);
|
|
108
|
+
context.setProp(arr, i, elementHandle);
|
|
109
|
+
elementHandle.dispose();
|
|
110
|
+
}
|
|
111
|
+
return arr;
|
|
112
|
+
}
|
|
113
|
+
const obj = context.newObject();
|
|
114
|
+
for (const [key, propVal] of Object.entries(val)) {
|
|
115
|
+
const propHandle = marshalValue(propVal, depth + 1);
|
|
116
|
+
context.setProp(obj, key, propHandle);
|
|
117
|
+
propHandle.dispose();
|
|
118
|
+
}
|
|
119
|
+
return obj;
|
|
120
|
+
} finally {
|
|
121
|
+
seen.delete(val);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (typeof val === "function") {
|
|
125
|
+
return context.newFunction(val.name || "anonymous", (...argHandles) => {
|
|
126
|
+
const args = argHandles.map((h) => context.dump(h));
|
|
127
|
+
try {
|
|
128
|
+
const result = val(...args);
|
|
129
|
+
if (result instanceof Promise) {
|
|
130
|
+
const deferred = context.newPromise();
|
|
131
|
+
result.then((resolved) => {
|
|
132
|
+
const resolvedHandle = marshalValue(resolved, depth + 1);
|
|
133
|
+
deferred.resolve(resolvedHandle);
|
|
134
|
+
resolvedHandle.dispose();
|
|
135
|
+
context.runtime.executePendingJobs();
|
|
136
|
+
}).catch((error) => {
|
|
137
|
+
const errorHandle = marshalValue(error instanceof Error ? { name: error.name, message: error.message } : error, depth + 1);
|
|
138
|
+
deferred.reject(errorHandle);
|
|
139
|
+
errorHandle.dispose();
|
|
140
|
+
context.runtime.executePendingJobs();
|
|
141
|
+
});
|
|
142
|
+
return deferred.handle;
|
|
143
|
+
}
|
|
144
|
+
return marshalValue(result, depth + 1);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw context.newError(error instanceof Error ? error.message : String(error));
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
throw new Error(`Cannot marshal value of type ${typeof val}`);
|
|
151
|
+
}
|
|
152
|
+
return marshalValue(value, 0);
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
marshal,
|
|
156
|
+
isHandle,
|
|
157
|
+
getHandleType
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
//# debugId=D3A382CD5B7A763864756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/marshal.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { MarshalOptions } from \"./types.ts\";\n\n/**\n * Check if a value is a QuickJS handle\n */\nexport function isHandle(value: unknown): value is QuickJSHandle {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"alive\" in value &&\n \"dispose\" in value &&\n typeof (value as QuickJSHandle).dispose === \"function\"\n );\n}\n\n/**\n * Get the type of a QuickJS handle as a string\n */\nexport function getHandleType(\n context: QuickJSContext,\n handle: QuickJSHandle\n): \"undefined\" | \"null\" | \"boolean\" | \"number\" | \"string\" | \"symbol\" | \"object\" | \"function\" {\n return context.typeof(handle) as \"undefined\" | \"null\" | \"boolean\" | \"number\" | \"string\" | \"symbol\" | \"object\" | \"function\";\n}\n\n/**\n * Marshal a JavaScript value to a QuickJS handle\n *\n * Supports:\n * - Primitives (string, number, boolean, null, undefined, bigint)\n * - Arrays\n * - Plain objects\n * - ArrayBuffer / Uint8Array\n * - Date (converted to Date object in QuickJS)\n * - Functions (wrapped as host functions)\n * - Promises (wrapped with context.newPromise)\n *\n * @example\n * const handle = marshal(context, {\n * name: \"test\",\n * values: [1, 2, 3],\n * callback: (x) => x * 2\n * });\n */\nexport function marshal(\n context: QuickJSContext,\n value: unknown,\n options: MarshalOptions = {}\n): QuickJSHandle {\n const maxDepth = options.maxDepth ?? 10;\n const seen = new WeakSet<object>();\n\n function marshalValue(val: unknown, depth: number): QuickJSHandle {\n if (depth > maxDepth) {\n throw new Error(`Maximum marshalling depth of ${maxDepth} exceeded`);\n }\n\n // Pass through existing QuickJS handles\n if (isHandle(val)) {\n return val;\n }\n\n // Try custom marshaller first\n if (options.custom) {\n const customResult = options.custom(val, context);\n if (customResult !== undefined) {\n return customResult;\n }\n }\n\n // Handle primitives\n if (val === undefined) {\n return context.undefined;\n }\n if (val === null) {\n return context.null;\n }\n if (typeof val === \"boolean\") {\n return val ? context.true : context.false;\n }\n if (typeof val === \"number\") {\n return context.newNumber(val);\n }\n if (typeof val === \"string\") {\n return context.newString(val);\n }\n if (typeof val === \"bigint\") {\n return context.newBigInt(val);\n }\n\n // Handle symbols (convert to string representation)\n if (typeof val === \"symbol\") {\n return context.newString(val.toString());\n }\n\n // Handle objects\n if (typeof val === \"object\") {\n // Check for circular references\n if (seen.has(val)) {\n throw new Error(\"Circular reference detected during marshalling\");\n }\n seen.add(val);\n\n try {\n // Handle ArrayBuffer\n if (val instanceof ArrayBuffer) {\n return context.newArrayBuffer(val);\n }\n\n // Handle Uint8Array - create proper Uint8Array in QuickJS (has .length property)\n if (val instanceof Uint8Array) {\n const buffer = val.buffer.slice(\n val.byteOffset,\n val.byteOffset + val.byteLength\n );\n const bufferHandle = context.newArrayBuffer(buffer);\n context.setProp(context.global, \"__tempMarshalBuffer__\", bufferHandle);\n bufferHandle.dispose();\n const result = context.evalCode(\"new Uint8Array(__tempMarshalBuffer__)\");\n const cleanup = context.evalCode(\"delete globalThis.__tempMarshalBuffer__\");\n if (cleanup.error) cleanup.error.dispose();\n else cleanup.value.dispose();\n if (result.error) {\n result.error.dispose();\n // Fallback to ArrayBuffer if Uint8Array creation fails\n return context.newArrayBuffer(buffer);\n }\n return result.value;\n }\n\n // Handle other TypedArrays (Int8Array, Float32Array, etc.) - convert to ArrayBuffer\n if (ArrayBuffer.isView(val)) {\n const buffer = val.buffer.slice(\n val.byteOffset,\n val.byteOffset + val.byteLength\n );\n return context.newArrayBuffer(buffer);\n }\n\n // Handle Date\n if (val instanceof Date) {\n const dateConstructor = context.getProp(context.global, \"Date\");\n const timestamp = context.newNumber(val.getTime());\n const result = context.callFunction(\n dateConstructor,\n context.undefined,\n timestamp\n );\n dateConstructor.dispose();\n timestamp.dispose();\n\n if (result.error) {\n const error = result.error;\n result.error.dispose();\n throw new Error(`Failed to create Date: ${context.dump(error)}`);\n }\n return result.value;\n }\n\n // Handle Promise\n if (val instanceof Promise) {\n const deferred = context.newPromise();\n val\n .then((resolved) => {\n const resolvedHandle = marshalValue(resolved, depth + 1);\n deferred.resolve(resolvedHandle);\n resolvedHandle.dispose();\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n const errorHandle = marshalValue(\n error instanceof Error\n ? { name: error.name, message: error.message }\n : error,\n depth + 1\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n });\n return deferred.handle;\n }\n\n // Handle Array\n if (Array.isArray(val)) {\n const arr = context.newArray();\n for (let i = 0; i < val.length; i++) {\n const elementHandle = marshalValue(val[i], depth + 1);\n context.setProp(arr, i, elementHandle);\n elementHandle.dispose();\n }\n return arr;\n }\n\n // Handle plain objects\n const obj = context.newObject();\n for (const [key, propVal] of Object.entries(val)) {\n const propHandle = marshalValue(propVal, depth + 1);\n context.setProp(obj, key, propHandle);\n propHandle.dispose();\n }\n return obj;\n } finally {\n seen.delete(val);\n }\n }\n\n // Handle functions\n if (typeof val === \"function\") {\n return context.newFunction(val.name || \"anonymous\", (...argHandles) => {\n const args = argHandles.map((h) => context.dump(h));\n try {\n const result = val(...args);\n if (result instanceof Promise) {\n const deferred = context.newPromise();\n result\n .then((resolved) => {\n const resolvedHandle = marshalValue(resolved, depth + 1);\n deferred.resolve(resolvedHandle);\n resolvedHandle.dispose();\n context.runtime.executePendingJobs();\n })\n .catch((error) => {\n const errorHandle = marshalValue(\n error instanceof Error\n ? { name: error.name, message: error.message }\n : error,\n depth + 1\n );\n deferred.reject(errorHandle);\n errorHandle.dispose();\n context.runtime.executePendingJobs();\n });\n return deferred.handle;\n }\n return marshalValue(result, depth + 1);\n } catch (error) {\n throw context.newError(\n error instanceof Error ? error.message : String(error)\n );\n }\n });\n }\n\n throw new Error(`Cannot marshal value of type ${typeof val}`);\n }\n\n return marshalValue(value, 0);\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "D3A382CD5B7A763864756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/mjs/package.json
CHANGED