@ricsam/quickjs-fetch 0.2.8 → 0.2.9
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/globals/request.cjs +80 -12
- package/dist/cjs/globals/request.cjs.map +3 -3
- package/dist/cjs/handle.cjs +2 -2
- package/dist/cjs/handle.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/setup.cjs +56 -2
- package/dist/cjs/setup.cjs.map +3 -3
- package/dist/cjs/upload-stream-queue.cjs +171 -0
- package/dist/cjs/upload-stream-queue.cjs.map +10 -0
- package/dist/mjs/globals/request.mjs +80 -12
- package/dist/mjs/globals/request.mjs.map +3 -3
- package/dist/mjs/handle.mjs +2 -2
- package/dist/mjs/handle.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/setup.mjs +56 -2
- package/dist/mjs/setup.mjs.map +3 -3
- package/dist/mjs/upload-stream-queue.mjs +145 -0
- package/dist/mjs/upload-stream-queue.mjs.map +10 -0
- package/dist/types/globals/request.d.ts +21 -3
- package/dist/types/types.d.ts +22 -0
- package/dist/types/upload-stream-queue.d.ts +69 -0
- package/package.json +2 -2
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// @bun @bun-cjs
|
|
2
|
+
(function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// packages/fetch/src/upload-stream-queue.ts
|
|
31
|
+
var exports_upload_stream_queue = {};
|
|
32
|
+
__export(exports_upload_stream_queue, {
|
|
33
|
+
startNativeStreamReader: () => startNativeStreamReader,
|
|
34
|
+
pushToQuickJSStream: () => pushToQuickJSStream,
|
|
35
|
+
isQuickJSStreamQueueFull: () => isQuickJSStreamQueueFull,
|
|
36
|
+
getUploadQueue: () => getUploadQueue,
|
|
37
|
+
errorQuickJSStream: () => errorQuickJSStream,
|
|
38
|
+
createUploadQueue: () => createUploadQueue,
|
|
39
|
+
closeQuickJSStream: () => closeQuickJSStream,
|
|
40
|
+
cleanupUploadQueue: () => cleanupUploadQueue
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(exports_upload_stream_queue);
|
|
43
|
+
var import_quickjs_core = require("@ricsam/quickjs-core");
|
|
44
|
+
var MAX_QUEUE_CHUNKS = 10;
|
|
45
|
+
var CHUNK_SIZE = 64 * 1024;
|
|
46
|
+
function createUploadQueue() {
|
|
47
|
+
const instanceId = import_quickjs_core.nextInstanceId();
|
|
48
|
+
const queue = {
|
|
49
|
+
chunks: [],
|
|
50
|
+
closed: false,
|
|
51
|
+
error: undefined,
|
|
52
|
+
paused: false,
|
|
53
|
+
resumeCallback: undefined,
|
|
54
|
+
cancelCallback: undefined
|
|
55
|
+
};
|
|
56
|
+
import_quickjs_core.registerInstance(instanceId, "UploadStreamQueue", queue);
|
|
57
|
+
return instanceId;
|
|
58
|
+
}
|
|
59
|
+
function getUploadQueue(instanceId) {
|
|
60
|
+
return import_quickjs_core.getInstanceStateById(instanceId);
|
|
61
|
+
}
|
|
62
|
+
function cleanupUploadQueue(instanceId) {
|
|
63
|
+
import_quickjs_core.cleanupInstanceStateById(instanceId);
|
|
64
|
+
}
|
|
65
|
+
function pushToQuickJSStream(streamInstanceId, chunk) {
|
|
66
|
+
const state = import_quickjs_core.getInstanceStateById(streamInstanceId);
|
|
67
|
+
if (!state) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (state.closeRequested || state.closed || state.errored) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
state.queue.push(chunk);
|
|
74
|
+
if (state.reader && state.reader.readRequests.length > 0) {
|
|
75
|
+
const request = state.reader.readRequests.shift();
|
|
76
|
+
const value = state.queue.shift();
|
|
77
|
+
request.resolve({ value, done: false });
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
function closeQuickJSStream(streamInstanceId) {
|
|
82
|
+
const state = import_quickjs_core.getInstanceStateById(streamInstanceId);
|
|
83
|
+
if (!state) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (state.closeRequested || state.closed) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
state.closeRequested = true;
|
|
90
|
+
if (state.queue.length === 0) {
|
|
91
|
+
state.closed = true;
|
|
92
|
+
if (state.reader) {
|
|
93
|
+
state.reader.closedPromiseResolvers.resolve();
|
|
94
|
+
for (const request of state.reader.readRequests) {
|
|
95
|
+
request.resolve({ value: undefined, done: true });
|
|
96
|
+
}
|
|
97
|
+
state.reader.readRequests = [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function errorQuickJSStream(streamInstanceId, error) {
|
|
102
|
+
const state = import_quickjs_core.getInstanceStateById(streamInstanceId);
|
|
103
|
+
if (!state) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (state.errored || state.closed) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
state.errored = true;
|
|
110
|
+
state.errorValue = { name: error.name, message: error.message };
|
|
111
|
+
if (state.reader) {
|
|
112
|
+
state.reader.closedPromiseResolvers.reject(state.errorValue);
|
|
113
|
+
for (const request of state.reader.readRequests) {
|
|
114
|
+
request.reject(state.errorValue);
|
|
115
|
+
}
|
|
116
|
+
state.reader.readRequests = [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function isQuickJSStreamQueueFull(streamInstanceId) {
|
|
120
|
+
const state = import_quickjs_core.getInstanceStateById(streamInstanceId);
|
|
121
|
+
if (!state) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return state.queue.length >= MAX_QUEUE_CHUNKS;
|
|
125
|
+
}
|
|
126
|
+
function startNativeStreamReader(nativeStream, quickjsStreamInstanceId, onChunkPushed) {
|
|
127
|
+
const reader = nativeStream.getReader();
|
|
128
|
+
let cancelled = false;
|
|
129
|
+
(async () => {
|
|
130
|
+
try {
|
|
131
|
+
while (!cancelled) {
|
|
132
|
+
if (isQuickJSStreamQueueFull(quickjsStreamInstanceId)) {
|
|
133
|
+
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const { done, value } = await reader.read();
|
|
137
|
+
if (done) {
|
|
138
|
+
closeQuickJSStream(quickjsStreamInstanceId);
|
|
139
|
+
onChunkPushed?.();
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
if (value) {
|
|
143
|
+
if (value.length > CHUNK_SIZE) {
|
|
144
|
+
let offset = 0;
|
|
145
|
+
while (offset < value.length) {
|
|
146
|
+
const chunk = value.slice(offset, offset + CHUNK_SIZE);
|
|
147
|
+
pushToQuickJSStream(quickjsStreamInstanceId, chunk);
|
|
148
|
+
offset += chunk.length;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
pushToQuickJSStream(quickjsStreamInstanceId, value);
|
|
152
|
+
}
|
|
153
|
+
onChunkPushed?.();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (!cancelled) {
|
|
158
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
159
|
+
errorQuickJSStream(quickjsStreamInstanceId, err);
|
|
160
|
+
onChunkPushed?.();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
})();
|
|
164
|
+
return () => {
|
|
165
|
+
cancelled = true;
|
|
166
|
+
reader.cancel().catch(() => {});
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
//# debugId=8FFB3F18BA1BDE2C64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/upload-stream-queue.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Upload stream queue management for bridging native ReadableStreams to QuickJS.\n *\n * This module implements the \"Inverted Direct State Access\" pattern:\n * - Native stream reader reads data and pushes directly to QuickJS stream's internal queue\n * - QuickJS stream's read() method reads from the queue\n * - No async callbacks with QuickJS handles, avoiding handle lifetime issues\n *\n * The pattern is the reverse of download streaming (handle.ts:createNativeStreamFromState):\n * - Download: QuickJS enqueues → host polls queue\n * - Upload: Host pushes to queue → QuickJS reads\n */\n\nimport type { UploadStreamQueue } from \"./types.cjs\";\nimport {\n nextInstanceId,\n registerInstance,\n getInstanceStateById,\n cleanupInstanceStateById,\n} from \"@ricsam/quickjs-core\";\n\n/** Maximum chunks to buffer before applying backpressure */\nconst MAX_QUEUE_CHUNKS = 10;\n/** Chunk size for reading from native stream (64KB, consistent with FS streaming) */\nconst CHUNK_SIZE = 64 * 1024;\n\n/**\n * Internal state of a QuickJS ReadableStream.\n * This mirrors the structure in core/streams/readable-stream.ts.\n */\ninterface ReadableStreamInternalState {\n locked: boolean;\n queue: unknown[];\n closeRequested: boolean;\n closed: boolean;\n errored: boolean;\n errorValue: unknown;\n reader: ReadableStreamReaderState | null;\n}\n\ninterface ReadableStreamReaderState {\n readRequests: Array<{\n resolve: (result: { value: unknown; done: boolean }) => void;\n reject: (e: unknown) => void;\n }>;\n closedPromiseResolvers: {\n resolve: () => void;\n reject: (e: unknown) => void;\n };\n}\n\n/**\n * Create a new upload queue and register it in instance state.\n * Returns the instance ID for accessing the queue via getUploadQueue().\n */\nexport function createUploadQueue(): number {\n const instanceId = nextInstanceId();\n const queue: UploadStreamQueue = {\n chunks: [],\n closed: false,\n error: undefined,\n paused: false,\n resumeCallback: undefined,\n cancelCallback: undefined,\n };\n\n registerInstance(instanceId, \"UploadStreamQueue\", queue);\n return instanceId;\n}\n\n/**\n * Get an upload queue by its instance ID.\n */\nexport function getUploadQueue(instanceId: number): UploadStreamQueue | undefined {\n return getInstanceStateById<UploadStreamQueue>(instanceId);\n}\n\n/**\n * Clean up an upload queue when no longer needed.\n */\nexport function cleanupUploadQueue(instanceId: number): void {\n cleanupInstanceStateById(instanceId);\n}\n\n/**\n * Push a chunk to a QuickJS ReadableStream's internal queue.\n * If there are pending read requests, fulfills the first one immediately.\n *\n * @param streamInstanceId The instance ID of the QuickJS ReadableStream\n * @param chunk The data chunk to enqueue\n * @returns true if the chunk was successfully enqueued\n */\nexport function pushToQuickJSStream(\n streamInstanceId: number,\n chunk: Uint8Array\n): boolean {\n const state = getInstanceStateById<ReadableStreamInternalState>(streamInstanceId);\n if (!state) {\n return false;\n }\n\n if (state.closeRequested || state.closed || state.errored) {\n return false;\n }\n\n // Push chunk to queue\n state.queue.push(chunk);\n\n // If there are pending read requests, fulfill the first one\n if (state.reader && state.reader.readRequests.length > 0) {\n const request = state.reader.readRequests.shift()!;\n const value = state.queue.shift();\n request.resolve({ value, done: false });\n }\n\n return true;\n}\n\n/**\n * Close a QuickJS ReadableStream.\n * If there are pending read requests, fulfills them with done: true.\n *\n * @param streamInstanceId The instance ID of the QuickJS ReadableStream\n */\nexport function closeQuickJSStream(streamInstanceId: number): void {\n const state = getInstanceStateById<ReadableStreamInternalState>(streamInstanceId);\n if (!state) {\n return;\n }\n\n if (state.closeRequested || state.closed) {\n return;\n }\n\n state.closeRequested = true;\n\n if (state.queue.length === 0) {\n state.closed = true;\n if (state.reader) {\n state.reader.closedPromiseResolvers.resolve();\n // Resolve any pending reads with done: true\n for (const request of state.reader.readRequests) {\n request.resolve({ value: undefined, done: true });\n }\n state.reader.readRequests = [];\n }\n }\n}\n\n/**\n * Error a QuickJS ReadableStream.\n *\n * @param streamInstanceId The instance ID of the QuickJS ReadableStream\n * @param error The error to propagate\n */\nexport function errorQuickJSStream(streamInstanceId: number, error: Error): void {\n const state = getInstanceStateById<ReadableStreamInternalState>(streamInstanceId);\n if (!state) {\n return;\n }\n\n if (state.errored || state.closed) {\n return;\n }\n\n state.errored = true;\n state.errorValue = { name: error.name, message: error.message };\n\n if (state.reader) {\n state.reader.closedPromiseResolvers.reject(state.errorValue);\n for (const request of state.reader.readRequests) {\n request.reject(state.errorValue);\n }\n state.reader.readRequests = [];\n }\n}\n\n/**\n * Check if a QuickJS ReadableStream's queue is full (for backpressure).\n *\n * @param streamInstanceId The instance ID of the QuickJS ReadableStream\n * @returns true if the queue has reached capacity\n */\nexport function isQuickJSStreamQueueFull(streamInstanceId: number): boolean {\n const state = getInstanceStateById<ReadableStreamInternalState>(streamInstanceId);\n if (!state) {\n return true; // Treat missing stream as full\n }\n return state.queue.length >= MAX_QUEUE_CHUNKS;\n}\n\n/**\n * Start a background reader that reads from a native ReadableStream\n * and pushes chunks directly to a QuickJS ReadableStream.\n *\n * The reader respects backpressure by pausing when the QuickJS queue is full\n * (10+ chunks) and resuming when QuickJS consumes chunks.\n *\n * @param nativeStream The native ReadableStream to read from\n * @param quickjsStreamInstanceId The instance ID of the QuickJS ReadableStream\n * @param onChunkPushed Optional callback called after each chunk is pushed\n * @returns A cleanup function to cancel the reader\n */\nexport function startNativeStreamReader(\n nativeStream: ReadableStream<Uint8Array>,\n quickjsStreamInstanceId: number,\n onChunkPushed?: () => void\n): () => void {\n const reader = nativeStream.getReader();\n let cancelled = false;\n\n // Start reading in background\n (async () => {\n try {\n while (!cancelled) {\n // Check for backpressure\n if (isQuickJSStreamQueueFull(quickjsStreamInstanceId)) {\n // Wait a bit for the queue to drain\n await new Promise<void>((resolve) => setTimeout(resolve, 1));\n continue;\n }\n\n const { done, value } = await reader.read();\n\n if (done) {\n closeQuickJSStream(quickjsStreamInstanceId);\n onChunkPushed?.();\n break;\n }\n\n if (value) {\n // Split large chunks into CHUNK_SIZE pieces for consistent streaming\n if (value.length > CHUNK_SIZE) {\n let offset = 0;\n while (offset < value.length) {\n const chunk = value.slice(offset, offset + CHUNK_SIZE);\n pushToQuickJSStream(quickjsStreamInstanceId, chunk);\n offset += chunk.length;\n }\n } else {\n pushToQuickJSStream(quickjsStreamInstanceId, value);\n }\n onChunkPushed?.();\n }\n }\n } catch (error) {\n if (!cancelled) {\n const err = error instanceof Error ? error : new Error(String(error));\n errorQuickJSStream(quickjsStreamInstanceId, err);\n onChunkPushed?.();\n }\n }\n })();\n\n // Return cleanup function\n return () => {\n cancelled = true;\n reader.cancel().catch(() => {\n // Ignore cancel errors\n });\n };\n}\n\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "8FFB3F18BA1BDE2C64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -3,7 +3,27 @@
|
|
|
3
3
|
import { defineClass, getInstanceStateById } from "@ricsam/quickjs-core";
|
|
4
4
|
import { createHeadersStateFromNative, createHeadersLike } from "./headers.mjs";
|
|
5
5
|
import { parseMultipartFormData, parseUrlEncodedFormData } from "./form-data.mjs";
|
|
6
|
-
|
|
6
|
+
import { startNativeStreamReader } from "../upload-stream-queue.mjs";
|
|
7
|
+
async function consumeNativeStream(stream) {
|
|
8
|
+
const chunks = [];
|
|
9
|
+
const reader = stream.getReader();
|
|
10
|
+
while (true) {
|
|
11
|
+
const { done, value } = await reader.read();
|
|
12
|
+
if (done)
|
|
13
|
+
break;
|
|
14
|
+
chunks.push(value);
|
|
15
|
+
}
|
|
16
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
17
|
+
const result = new Uint8Array(totalLength);
|
|
18
|
+
let offset = 0;
|
|
19
|
+
for (const chunk of chunks) {
|
|
20
|
+
result.set(chunk, offset);
|
|
21
|
+
offset += chunk.length;
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
function createRequestClass(context, stateMap, streamHelpers) {
|
|
26
|
+
const createStream = streamHelpers?.createStream;
|
|
7
27
|
return defineClass(context, stateMap, {
|
|
8
28
|
name: "Request",
|
|
9
29
|
construct: (args) => {
|
|
@@ -111,15 +131,31 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
111
131
|
},
|
|
112
132
|
body: {
|
|
113
133
|
get() {
|
|
114
|
-
if (!this.body)
|
|
115
|
-
return null;
|
|
116
134
|
if (!createStream) {
|
|
117
135
|
return this.body;
|
|
118
136
|
}
|
|
137
|
+
if (this._cachedBodyStream !== undefined) {
|
|
138
|
+
return this._cachedBodyStream;
|
|
139
|
+
}
|
|
140
|
+
if (this.nativeBodyStream) {
|
|
141
|
+
if (!streamHelpers?.createEmptyStream) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const { instanceId: streamInstanceId, globalKey } = streamHelpers.createEmptyStream();
|
|
145
|
+
const cleanup = startNativeStreamReader(this.nativeBodyStream, streamInstanceId, streamHelpers.pumpEventLoop);
|
|
146
|
+
this._uploadStreamCleanup = cleanup;
|
|
147
|
+
this._cachedBodyStream = `__UPLOAD_STREAM_KEY__:${globalKey}`;
|
|
148
|
+
this.nativeBodyStream = undefined;
|
|
149
|
+
return this._cachedBodyStream;
|
|
150
|
+
}
|
|
151
|
+
if (!this.body) {
|
|
152
|
+
this._cachedBodyStream = null;
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
119
155
|
const bodyData = this.body;
|
|
120
156
|
let offset = 0;
|
|
121
157
|
const chunkSize = 65536;
|
|
122
|
-
|
|
158
|
+
const stream = createStream({
|
|
123
159
|
pull(controller) {
|
|
124
160
|
if (offset >= bodyData.length) {
|
|
125
161
|
controller.close();
|
|
@@ -130,6 +166,8 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
130
166
|
controller.enqueue(chunk);
|
|
131
167
|
}
|
|
132
168
|
});
|
|
169
|
+
this._cachedBodyStream = stream;
|
|
170
|
+
return stream;
|
|
133
171
|
}
|
|
134
172
|
},
|
|
135
173
|
bodyUsed: {
|
|
@@ -194,6 +232,10 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
194
232
|
throw new TypeError("Body has already been consumed");
|
|
195
233
|
}
|
|
196
234
|
this.bodyUsed = true;
|
|
235
|
+
if (this.nativeBodyStream) {
|
|
236
|
+
const buffer = await consumeNativeStream(this.nativeBodyStream);
|
|
237
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
238
|
+
}
|
|
197
239
|
if (!this.body) {
|
|
198
240
|
return new ArrayBuffer(0);
|
|
199
241
|
}
|
|
@@ -205,6 +247,14 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
205
247
|
}
|
|
206
248
|
this.bodyUsed = true;
|
|
207
249
|
const contentType = this.headersState.headers.get("content-type")?.[0] || "";
|
|
250
|
+
if (this.nativeBodyStream) {
|
|
251
|
+
const buffer = await consumeNativeStream(this.nativeBodyStream);
|
|
252
|
+
return {
|
|
253
|
+
parts: [buffer],
|
|
254
|
+
type: contentType,
|
|
255
|
+
size: buffer.length
|
|
256
|
+
};
|
|
257
|
+
}
|
|
208
258
|
return {
|
|
209
259
|
parts: this.body ? [this.body] : [],
|
|
210
260
|
type: contentType,
|
|
@@ -215,6 +265,9 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
215
265
|
if (this.bodyUsed) {
|
|
216
266
|
throw new TypeError("Body has already been consumed");
|
|
217
267
|
}
|
|
268
|
+
if (this.nativeBodyStream) {
|
|
269
|
+
throw new TypeError("Cannot clone Request with streaming body");
|
|
270
|
+
}
|
|
218
271
|
return {
|
|
219
272
|
...this,
|
|
220
273
|
headersState: {
|
|
@@ -229,6 +282,11 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
229
282
|
throw new TypeError("Body has already been consumed");
|
|
230
283
|
}
|
|
231
284
|
this.bodyUsed = true;
|
|
285
|
+
if (this.nativeBodyStream) {
|
|
286
|
+
const buffer = await consumeNativeStream(this.nativeBodyStream);
|
|
287
|
+
const text2 = new TextDecoder().decode(buffer);
|
|
288
|
+
return JSON.parse(text2);
|
|
289
|
+
}
|
|
232
290
|
if (!this.body) {
|
|
233
291
|
return JSON.parse("");
|
|
234
292
|
}
|
|
@@ -240,6 +298,10 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
240
298
|
throw new TypeError("Body has already been consumed");
|
|
241
299
|
}
|
|
242
300
|
this.bodyUsed = true;
|
|
301
|
+
if (this.nativeBodyStream) {
|
|
302
|
+
const buffer = await consumeNativeStream(this.nativeBodyStream);
|
|
303
|
+
return new TextDecoder().decode(buffer);
|
|
304
|
+
}
|
|
243
305
|
if (!this.body) {
|
|
244
306
|
return "";
|
|
245
307
|
}
|
|
@@ -250,15 +312,21 @@ function createRequestClass(context, stateMap, createStream) {
|
|
|
250
312
|
throw new TypeError("Body has already been consumed");
|
|
251
313
|
}
|
|
252
314
|
this.bodyUsed = true;
|
|
253
|
-
|
|
315
|
+
let bodyData = null;
|
|
316
|
+
if (this.nativeBodyStream) {
|
|
317
|
+
bodyData = await consumeNativeStream(this.nativeBodyStream);
|
|
318
|
+
} else {
|
|
319
|
+
bodyData = this.body;
|
|
320
|
+
}
|
|
321
|
+
if (!bodyData) {
|
|
254
322
|
return { entries: [] };
|
|
255
323
|
}
|
|
256
324
|
const contentType = this.headersState.headers.get("content-type")?.[0] || "";
|
|
257
325
|
let formDataState;
|
|
258
326
|
if (contentType.includes("multipart/form-data")) {
|
|
259
|
-
formDataState = parseMultipartFormData(
|
|
327
|
+
formDataState = parseMultipartFormData(bodyData, contentType);
|
|
260
328
|
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
261
|
-
formDataState = parseUrlEncodedFormData(
|
|
329
|
+
formDataState = parseUrlEncodedFormData(bodyData);
|
|
262
330
|
} else {
|
|
263
331
|
throw new TypeError("Could not parse content as FormData");
|
|
264
332
|
}
|
|
@@ -308,13 +376,12 @@ function addRequestFormDataMethod(context) {
|
|
|
308
376
|
result.value.dispose();
|
|
309
377
|
}
|
|
310
378
|
}
|
|
311
|
-
|
|
312
|
-
const body = request.body ? new Uint8Array(await request.arrayBuffer()) : null;
|
|
379
|
+
function createRequestStateFromNative(request) {
|
|
313
380
|
return {
|
|
314
381
|
method: request.method,
|
|
315
382
|
url: request.url,
|
|
316
383
|
headersState: createHeadersStateFromNative(request.headers),
|
|
317
|
-
body,
|
|
384
|
+
body: null,
|
|
318
385
|
bodyUsed: false,
|
|
319
386
|
cache: request.cache,
|
|
320
387
|
credentials: request.credentials,
|
|
@@ -325,7 +392,8 @@ async function createRequestStateFromNative(request) {
|
|
|
325
392
|
redirect: request.redirect,
|
|
326
393
|
referrer: request.referrer,
|
|
327
394
|
referrerPolicy: request.referrerPolicy,
|
|
328
|
-
signal: null
|
|
395
|
+
signal: null,
|
|
396
|
+
nativeBodyStream: request.body ?? undefined
|
|
329
397
|
};
|
|
330
398
|
}
|
|
331
399
|
export {
|
|
@@ -334,4 +402,4 @@ export {
|
|
|
334
402
|
addRequestFormDataMethod
|
|
335
403
|
};
|
|
336
404
|
|
|
337
|
-
//# debugId=
|
|
405
|
+
//# debugId=3969E7C807E073F664756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/globals/request.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap } from \"@ricsam/quickjs-core\";\nimport { defineClass, getInstanceStateById } from \"@ricsam/quickjs-core\";\nimport type { RequestState, HeadersState, AbortSignalState, FormDataState } from \"../types.mjs\";\nimport { createHeadersStateFromNative, createHeadersLike } from \"./headers.mjs\";\nimport { parseMultipartFormData, parseUrlEncodedFormData } from \"./form-data.mjs\";\n\n/**\n * Type for the stream factory function\n */\ntype StreamFactory = (source: UnderlyingSource) => QuickJSHandle;\n\n/**\n * Create the Request class for QuickJS\n */\nexport function createRequestClass(\n context: QuickJSContext,\n stateMap: StateMap,\n createStream?: StreamFactory\n): QuickJSHandle {\n return defineClass<RequestState>(context, stateMap, {\n name: \"Request\",\n construct: (args) => {\n const input = args[0];\n const init = args[1] as {\n method?: string;\n headers?: object;\n body?: unknown;\n cache?: string;\n credentials?: string;\n integrity?: string;\n keepalive?: boolean;\n mode?: string;\n redirect?: string;\n referrer?: string;\n referrerPolicy?: string;\n signal?: AbortSignalState;\n } | undefined;\n\n let url = \"\";\n let method = \"GET\";\n let headersState: HeadersState = { headers: new Map() };\n let body: Uint8Array | null = null;\n let signal: AbortSignalState | null = null;\n\n // Handle input\n if (typeof input === \"string\") {\n url = input;\n } else if (input && typeof input === \"object\") {\n // Could be URL or Request-like\n if (\"url\" in input) {\n url = String((input as { url: string }).url);\n }\n if (\"method\" in input) {\n method = String((input as { method: string }).method);\n }\n if (\"headersState\" in input) {\n const inputHeaders = (input as RequestState).headersState;\n headersState = {\n headers: new Map(inputHeaders.headers),\n };\n }\n if (\"body\" in input && (input as RequestState).body) {\n body = (input as RequestState).body;\n }\n if (\"signal\" in input) {\n signal = (input as RequestState).signal;\n }\n }\n\n // Apply init options\n if (init) {\n if (init.method) {\n method = init.method.toUpperCase();\n }\n if (init.headers) {\n if (init.headers && typeof init.headers === \"object\") {\n if (\"headers\" in init.headers && init.headers.headers instanceof Map) {\n headersState = {\n headers: new Map((init.headers as HeadersState).headers),\n };\n } else if (\n \"__isDefineClassInstance__\" in init.headers &&\n (init.headers as { __isDefineClassInstance__?: boolean }).__isDefineClassInstance__ === true &&\n \"__instanceId__\" in init.headers\n ) {\n // Unmarshalled Headers instance from defineClass\n const instanceId = (init.headers as { __instanceId__: number }).__instanceId__;\n const state = getInstanceStateById<HeadersState>(instanceId);\n if (state && state.headers instanceof Map) {\n headersState = {\n headers: new Map(state.headers),\n };\n }\n } else {\n headersState = { headers: new Map() };\n for (const [key, value] of Object.entries(init.headers)) {\n headersState.headers.set(key.toLowerCase(), [String(value)]);\n }\n }\n }\n }\n if (init.body !== undefined && init.body !== null) {\n if (typeof init.body === \"string\") {\n body = new TextEncoder().encode(init.body);\n } else if (init.body instanceof ArrayBuffer) {\n body = new Uint8Array(init.body);\n } else if (init.body instanceof Uint8Array) {\n body = init.body;\n }\n }\n if (init.signal) {\n signal = init.signal;\n }\n }\n\n return {\n method,\n url,\n headersState,\n body,\n bodyUsed: false,\n cache: init?.cache || \"default\",\n credentials: init?.credentials || \"same-origin\",\n destination: \"\",\n integrity: init?.integrity || \"\",\n keepalive: init?.keepalive || false,\n mode: init?.mode || \"cors\",\n redirect: init?.redirect || \"follow\",\n referrer: init?.referrer || \"about:client\",\n referrerPolicy: init?.referrerPolicy || \"\",\n signal,\n };\n },\n properties: {\n method: {\n get(this: RequestState) {\n return this.method;\n },\n },\n url: {\n get(this: RequestState) {\n return this.url;\n },\n },\n headers: {\n get(this: RequestState) {\n return createHeadersLike(this.headersState);\n },\n },\n body: {\n get(this: RequestState) {\n if (!this.body) return null;\n if (!createStream) {\n // Fallback: return raw body if no stream factory\n return this.body;\n }\n // Create a ReadableStream from the body data\n const bodyData = this.body;\n let offset = 0;\n const chunkSize = 65536; // 64KB chunks\n return createStream({\n pull(controller) {\n if (offset >= bodyData.length) {\n controller.close();\n return;\n }\n const chunk = bodyData.slice(offset, Math.min(offset + chunkSize, bodyData.length));\n offset += chunk.length;\n controller.enqueue(chunk);\n },\n });\n },\n },\n bodyUsed: {\n get(this: RequestState) {\n return this.bodyUsed;\n },\n },\n cache: {\n get(this: RequestState) {\n return this.cache;\n },\n },\n credentials: {\n get(this: RequestState) {\n return this.credentials;\n },\n },\n destination: {\n get(this: RequestState) {\n return this.destination;\n },\n },\n integrity: {\n get(this: RequestState) {\n return this.integrity;\n },\n },\n keepalive: {\n get(this: RequestState) {\n return this.keepalive;\n },\n },\n mode: {\n get(this: RequestState) {\n return this.mode;\n },\n },\n redirect: {\n get(this: RequestState) {\n return this.redirect;\n },\n },\n referrer: {\n get(this: RequestState) {\n return this.referrer;\n },\n },\n referrerPolicy: {\n get(this: RequestState) {\n return this.referrerPolicy;\n },\n },\n signal: {\n get(this: RequestState) {\n return this.signal;\n },\n },\n },\n methods: {\n async arrayBuffer(this: RequestState): Promise<ArrayBuffer> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n if (!this.body) {\n return new ArrayBuffer(0);\n }\n return this.body.buffer.slice(\n this.body.byteOffset,\n this.body.byteOffset + this.body.byteLength\n ) as ArrayBuffer;\n },\n async blob(this: RequestState): Promise<object> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n const contentType = this.headersState.headers.get(\"content-type\")?.[0] || \"\";\n return {\n parts: this.body ? [this.body] : [],\n type: contentType,\n size: this.body?.length || 0,\n };\n },\n clone(this: RequestState): RequestState {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n return {\n ...this,\n headersState: {\n headers: new Map(this.headersState.headers),\n },\n body: this.body ? new Uint8Array(this.body) : null,\n bodyUsed: false,\n };\n },\n async json(this: RequestState): Promise<unknown> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n if (!this.body) {\n return JSON.parse(\"\");\n }\n const text = new TextDecoder().decode(this.body);\n return JSON.parse(text);\n },\n async text(this: RequestState): Promise<string> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n if (!this.body) {\n return \"\";\n }\n return new TextDecoder().decode(this.body);\n },\n /**\n * Private method that returns raw FormData entries.\n * Used by the formData() method added via evalCode (see addRequestFormDataMethod).\n *\n * Note: File data is converted to plain number arrays to avoid memory issues\n * when marshalling Uint8Array between host and QuickJS contexts.\n */\n async __getFormDataEntries__(this: RequestState): Promise<{\n entries: Array<{\n name: string;\n value: string | { __formDataFile__: true; data: number[]; filename: string; type: string };\n }>;\n }> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n if (!this.body) {\n return { entries: [] };\n }\n\n const contentType = this.headersState.headers.get(\"content-type\")?.[0] || \"\";\n\n let formDataState: FormDataState;\n if (contentType.includes(\"multipart/form-data\")) {\n formDataState = parseMultipartFormData(this.body, contentType);\n } else if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n formDataState = parseUrlEncodedFormData(this.body);\n } else {\n throw new TypeError(\"Could not parse content as FormData\");\n }\n\n // Convert Uint8Array data to plain number arrays for safe marshalling\n // Include marker so FormData.get() can reconstruct File instances\n type SerializedFileValue = { __formDataFile__: true; data: number[]; filename: string; type: string };\n type SerializedEntry = { name: string; value: string | SerializedFileValue };\n return {\n entries: formDataState.entries.map((entry): SerializedEntry => {\n if (typeof entry.value === \"string\") {\n return { name: entry.name, value: entry.value };\n }\n // Convert Uint8Array to number array and include marker\n return {\n name: entry.name,\n value: {\n __formDataFile__: true,\n data: Array.from(entry.value.data),\n filename: entry.value.filename,\n type: entry.value.type,\n },\n };\n }),\n };\n },\n },\n });\n}\n\n/**\n * Add the formData() method to Request.prototype via evalCode.\n *\n * This must be called AFTER both Request and FormData classes are on global.\n * The method creates a proper FormData instance with all entries.\n *\n * @see PATTERNS.md section 2 (Class Methods That Return Instances)\n */\nexport function addRequestFormDataMethod(context: QuickJSContext): void {\n const result = context.evalCode(`\n Request.prototype.formData = async function() {\n // Get raw entries from private method\n // Note: File data comes as plain number arrays (converted in host side)\n const rawData = await this.__getFormDataEntries__();\n\n // Create a proper FormData instance\n const formData = new FormData();\n\n // Populate with entries\n // FormData.append handles both string values and file-like objects\n // with number arrays (converted to Uint8Array on the host side)\n for (const entry of rawData.entries) {\n formData.append(entry.name, entry.value);\n }\n\n return formData;\n };\n `);\n\n if (result.error) {\n result.error.dispose();\n } else {\n result.value.dispose();\n }\n}\n\n/**\n * Create a RequestState from a native Request object\n */\nexport async function createRequestStateFromNative(\n request: Request\n): Promise<RequestState> {\n const body = request.body\n ? new Uint8Array(await request.arrayBuffer())\n : null;\n\n return {\n method: request.method,\n url: request.url,\n headersState: createHeadersStateFromNative(request.headers),\n body,\n bodyUsed: false,\n cache: request.cache,\n credentials: request.credentials,\n destination: request.destination,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: null, // Signal handling is complex, simplified here\n };\n}\n"
|
|
5
|
+
"import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap } from \"@ricsam/quickjs-core\";\nimport { defineClass, getInstanceStateById } from \"@ricsam/quickjs-core\";\nimport type { RequestState, HeadersState, AbortSignalState, FormDataState } from \"../types.mjs\";\nimport { createHeadersStateFromNative, createHeadersLike } from \"./headers.mjs\";\nimport { parseMultipartFormData, parseUrlEncodedFormData } from \"./form-data.mjs\";\nimport { startNativeStreamReader } from \"../upload-stream-queue.mjs\";\n\n/**\n * Type for the stream factory function\n */\ntype StreamFactory = (source: UnderlyingSource) => QuickJSHandle;\n\n/**\n * Stream helpers passed to the body getter for upload streaming\n */\ninterface StreamHelpers {\n createStream: StreamFactory;\n /** Creates an empty ReadableStream, stores on global, returns instanceId and globalKey */\n createEmptyStream: () => { instanceId: number; globalKey: string };\n pumpEventLoop: () => void;\n}\n\n/**\n * Helper to consume a native ReadableStream into a Uint8Array.\n * Used by text(), json(), arrayBuffer(), blob() methods.\n */\nasync function consumeNativeStream(\n stream: ReadableStream<Uint8Array>\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n const reader = stream.getReader();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n\n // Concatenate chunks into single Uint8Array\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n\n return result;\n}\n\n/**\n * Create the Request class for QuickJS\n */\nexport function createRequestClass(\n context: QuickJSContext,\n stateMap: StateMap,\n streamHelpers?: StreamHelpers\n): QuickJSHandle {\n const createStream = streamHelpers?.createStream;\n return defineClass<RequestState>(context, stateMap, {\n name: \"Request\",\n construct: (args) => {\n const input = args[0];\n const init = args[1] as {\n method?: string;\n headers?: object;\n body?: unknown;\n cache?: string;\n credentials?: string;\n integrity?: string;\n keepalive?: boolean;\n mode?: string;\n redirect?: string;\n referrer?: string;\n referrerPolicy?: string;\n signal?: AbortSignalState;\n } | undefined;\n\n let url = \"\";\n let method = \"GET\";\n let headersState: HeadersState = { headers: new Map() };\n let body: Uint8Array | null = null;\n let signal: AbortSignalState | null = null;\n\n // Handle input\n if (typeof input === \"string\") {\n url = input;\n } else if (input && typeof input === \"object\") {\n // Could be URL or Request-like\n if (\"url\" in input) {\n url = String((input as { url: string }).url);\n }\n if (\"method\" in input) {\n method = String((input as { method: string }).method);\n }\n if (\"headersState\" in input) {\n const inputHeaders = (input as RequestState).headersState;\n headersState = {\n headers: new Map(inputHeaders.headers),\n };\n }\n if (\"body\" in input && (input as RequestState).body) {\n body = (input as RequestState).body;\n }\n if (\"signal\" in input) {\n signal = (input as RequestState).signal;\n }\n }\n\n // Apply init options\n if (init) {\n if (init.method) {\n method = init.method.toUpperCase();\n }\n if (init.headers) {\n if (init.headers && typeof init.headers === \"object\") {\n if (\"headers\" in init.headers && init.headers.headers instanceof Map) {\n headersState = {\n headers: new Map((init.headers as HeadersState).headers),\n };\n } else if (\n \"__isDefineClassInstance__\" in init.headers &&\n (init.headers as { __isDefineClassInstance__?: boolean }).__isDefineClassInstance__ === true &&\n \"__instanceId__\" in init.headers\n ) {\n // Unmarshalled Headers instance from defineClass\n const instanceId = (init.headers as { __instanceId__: number }).__instanceId__;\n const state = getInstanceStateById<HeadersState>(instanceId);\n if (state && state.headers instanceof Map) {\n headersState = {\n headers: new Map(state.headers),\n };\n }\n } else {\n headersState = { headers: new Map() };\n for (const [key, value] of Object.entries(init.headers)) {\n headersState.headers.set(key.toLowerCase(), [String(value)]);\n }\n }\n }\n }\n if (init.body !== undefined && init.body !== null) {\n if (typeof init.body === \"string\") {\n body = new TextEncoder().encode(init.body);\n } else if (init.body instanceof ArrayBuffer) {\n body = new Uint8Array(init.body);\n } else if (init.body instanceof Uint8Array) {\n body = init.body;\n }\n }\n if (init.signal) {\n signal = init.signal;\n }\n }\n\n return {\n method,\n url,\n headersState,\n body,\n bodyUsed: false,\n cache: init?.cache || \"default\",\n credentials: init?.credentials || \"same-origin\",\n destination: \"\",\n integrity: init?.integrity || \"\",\n keepalive: init?.keepalive || false,\n mode: init?.mode || \"cors\",\n redirect: init?.redirect || \"follow\",\n referrer: init?.referrer || \"about:client\",\n referrerPolicy: init?.referrerPolicy || \"\",\n signal,\n };\n },\n properties: {\n method: {\n get(this: RequestState) {\n return this.method;\n },\n },\n url: {\n get(this: RequestState) {\n return this.url;\n },\n },\n headers: {\n get(this: RequestState) {\n return createHeadersLike(this.headersState);\n },\n },\n body: {\n get(this: RequestState & { _cachedBodyStream?: object | string | null; _uploadStreamCleanup?: () => void }) {\n if (!createStream) {\n // Fallback: return raw body if no stream factory\n return this.body;\n }\n\n // Return cached stream if already created\n if (this._cachedBodyStream !== undefined) {\n return this._cachedBodyStream;\n }\n\n // Streaming native body - create a QuickJS ReadableStream that bridges to the native stream\n // Uses the \"Inverted Direct State Access\" pattern: host pushes to QuickJS stream's queue\n if (this.nativeBodyStream) {\n if (!streamHelpers?.createEmptyStream) {\n // No helpers available - fall back to null (legacy behavior)\n return null;\n }\n\n // Create a QuickJS ReadableStream with no source callbacks via evalCode\n // The stream is stored on a global key - we return a marker string that\n // the JavaScript wrapper will use to retrieve the actual stream.\n // This avoids returning a QuickJSHandle through __hostCall__ which causes lifetime issues.\n const { instanceId: streamInstanceId, globalKey } = streamHelpers.createEmptyStream();\n\n // Start background reader that pushes to the QuickJS stream\n // The onChunkPushed callback pumps the event loop to process pending reads\n const cleanup = startNativeStreamReader(\n this.nativeBodyStream,\n streamInstanceId,\n streamHelpers.pumpEventLoop\n );\n\n // Store cleanup function for potential cancellation\n this._uploadStreamCleanup = cleanup;\n // Cache the global key so subsequent calls return the same stream\n this._cachedBodyStream = `__UPLOAD_STREAM_KEY__:${globalKey}`;\n\n // Clear nativeBodyStream to prevent double-consumption\n // This ensures text()/json()/arrayBuffer() don't try to read from it\n this.nativeBodyStream = undefined;\n\n return this._cachedBodyStream;\n }\n\n // Fallback: buffered body (backwards compatibility)\n if (!this.body) {\n this._cachedBodyStream = null;\n return null;\n }\n const bodyData = this.body;\n let offset = 0;\n const chunkSize = 65536; // 64KB chunks\n const stream = createStream({\n pull(controller) {\n if (offset >= bodyData.length) {\n controller.close();\n return;\n }\n const chunk = bodyData.slice(offset, Math.min(offset + chunkSize, bodyData.length));\n offset += chunk.length;\n controller.enqueue(chunk);\n },\n });\n this._cachedBodyStream = stream;\n return stream;\n },\n },\n bodyUsed: {\n get(this: RequestState) {\n return this.bodyUsed;\n },\n },\n cache: {\n get(this: RequestState) {\n return this.cache;\n },\n },\n credentials: {\n get(this: RequestState) {\n return this.credentials;\n },\n },\n destination: {\n get(this: RequestState) {\n return this.destination;\n },\n },\n integrity: {\n get(this: RequestState) {\n return this.integrity;\n },\n },\n keepalive: {\n get(this: RequestState) {\n return this.keepalive;\n },\n },\n mode: {\n get(this: RequestState) {\n return this.mode;\n },\n },\n redirect: {\n get(this: RequestState) {\n return this.redirect;\n },\n },\n referrer: {\n get(this: RequestState) {\n return this.referrer;\n },\n },\n referrerPolicy: {\n get(this: RequestState) {\n return this.referrerPolicy;\n },\n },\n signal: {\n get(this: RequestState) {\n return this.signal;\n },\n },\n },\n methods: {\n async arrayBuffer(this: RequestState): Promise<ArrayBuffer> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n\n // Consume native stream if present\n if (this.nativeBodyStream) {\n const buffer = await consumeNativeStream(this.nativeBodyStream);\n return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer;\n }\n\n // Fallback: buffered body\n if (!this.body) {\n return new ArrayBuffer(0);\n }\n return this.body.buffer.slice(\n this.body.byteOffset,\n this.body.byteOffset + this.body.byteLength\n ) as ArrayBuffer;\n },\n async blob(this: RequestState): Promise<object> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n const contentType = this.headersState.headers.get(\"content-type\")?.[0] || \"\";\n\n // Consume native stream if present\n if (this.nativeBodyStream) {\n const buffer = await consumeNativeStream(this.nativeBodyStream);\n return {\n parts: [buffer],\n type: contentType,\n size: buffer.length,\n };\n }\n\n // Fallback: buffered body\n return {\n parts: this.body ? [this.body] : [],\n type: contentType,\n size: this.body?.length || 0,\n };\n },\n clone(this: RequestState): RequestState {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n // Note: Cannot clone streaming body - would need to tee the stream\n if (this.nativeBodyStream) {\n throw new TypeError(\"Cannot clone Request with streaming body\");\n }\n return {\n ...this,\n headersState: {\n headers: new Map(this.headersState.headers),\n },\n body: this.body ? new Uint8Array(this.body) : null,\n bodyUsed: false,\n };\n },\n async json(this: RequestState): Promise<unknown> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n\n // Consume native stream if present\n if (this.nativeBodyStream) {\n const buffer = await consumeNativeStream(this.nativeBodyStream);\n const text = new TextDecoder().decode(buffer);\n return JSON.parse(text);\n }\n\n // Fallback: buffered body\n if (!this.body) {\n return JSON.parse(\"\");\n }\n const text = new TextDecoder().decode(this.body);\n return JSON.parse(text);\n },\n async text(this: RequestState): Promise<string> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n\n // Consume native stream if present\n if (this.nativeBodyStream) {\n const buffer = await consumeNativeStream(this.nativeBodyStream);\n return new TextDecoder().decode(buffer);\n }\n\n // Fallback: buffered body\n if (!this.body) {\n return \"\";\n }\n return new TextDecoder().decode(this.body);\n },\n /**\n * Private method that returns raw FormData entries.\n * Used by the formData() method added via evalCode (see addRequestFormDataMethod).\n *\n * Note: File data is converted to plain number arrays to avoid memory issues\n * when marshalling Uint8Array between host and QuickJS contexts.\n */\n async __getFormDataEntries__(this: RequestState): Promise<{\n entries: Array<{\n name: string;\n value: string | { __formDataFile__: true; data: number[]; filename: string; type: string };\n }>;\n }> {\n if (this.bodyUsed) {\n throw new TypeError(\"Body has already been consumed\");\n }\n this.bodyUsed = true;\n\n // Get body data from native stream or buffered body\n let bodyData: Uint8Array | null = null;\n if (this.nativeBodyStream) {\n bodyData = await consumeNativeStream(this.nativeBodyStream);\n } else {\n bodyData = this.body;\n }\n\n if (!bodyData) {\n return { entries: [] };\n }\n\n const contentType = this.headersState.headers.get(\"content-type\")?.[0] || \"\";\n\n let formDataState: FormDataState;\n if (contentType.includes(\"multipart/form-data\")) {\n formDataState = parseMultipartFormData(bodyData, contentType);\n } else if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n formDataState = parseUrlEncodedFormData(bodyData);\n } else {\n throw new TypeError(\"Could not parse content as FormData\");\n }\n\n // Convert Uint8Array data to plain number arrays for safe marshalling\n // Include marker so FormData.get() can reconstruct File instances\n type SerializedFileValue = { __formDataFile__: true; data: number[]; filename: string; type: string };\n type SerializedEntry = { name: string; value: string | SerializedFileValue };\n return {\n entries: formDataState.entries.map((entry): SerializedEntry => {\n if (typeof entry.value === \"string\") {\n return { name: entry.name, value: entry.value };\n }\n // Convert Uint8Array to number array and include marker\n return {\n name: entry.name,\n value: {\n __formDataFile__: true,\n data: Array.from(entry.value.data),\n filename: entry.value.filename,\n type: entry.value.type,\n },\n };\n }),\n };\n },\n },\n });\n}\n\n/**\n * Add the formData() method to Request.prototype via evalCode.\n *\n * This must be called AFTER both Request and FormData classes are on global.\n * The method creates a proper FormData instance with all entries.\n *\n * @see PATTERNS.md section 2 (Class Methods That Return Instances)\n */\nexport function addRequestFormDataMethod(context: QuickJSContext): void {\n const result = context.evalCode(`\n Request.prototype.formData = async function() {\n // Get raw entries from private method\n // Note: File data comes as plain number arrays (converted in host side)\n const rawData = await this.__getFormDataEntries__();\n\n // Create a proper FormData instance\n const formData = new FormData();\n\n // Populate with entries\n // FormData.append handles both string values and file-like objects\n // with number arrays (converted to Uint8Array on the host side)\n for (const entry of rawData.entries) {\n formData.append(entry.name, entry.value);\n }\n\n return formData;\n };\n `);\n\n if (result.error) {\n result.error.dispose();\n } else {\n result.value.dispose();\n }\n}\n\n/**\n * Create a RequestState from a native Request object.\n *\n * This is now synchronous - we preserve the native ReadableStream instead of\n * buffering it. The stream is consumed lazily when QuickJS code accesses\n * request.body or calls request.text()/json()/arrayBuffer().\n *\n * This enables streaming large uploads (1GB+) without buffering.\n */\nexport function createRequestStateFromNative(\n request: Request\n): RequestState {\n return {\n method: request.method,\n url: request.url,\n headersState: createHeadersStateFromNative(request.headers),\n body: null, // Not buffered upfront - use nativeBodyStream instead\n bodyUsed: false,\n cache: request.cache,\n credentials: request.credentials,\n destination: request.destination,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: null, // Signal handling is complex, simplified here\n nativeBodyStream: request.body ?? undefined,\n };\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;AAEA;AAEA;AACA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "3969E7C807E073F664756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/handle.mjs
CHANGED
|
@@ -76,7 +76,7 @@ function createFetchHandle(context, stateMap, serveState) {
|
|
|
76
76
|
throw new Error("No serve() handler registered");
|
|
77
77
|
}
|
|
78
78
|
serveState.pendingUpgrade = null;
|
|
79
|
-
const requestState =
|
|
79
|
+
const requestState = createRequestStateFromNative(request);
|
|
80
80
|
const requestHandle = createRequestInstance(context, stateMap, requestState);
|
|
81
81
|
const serverResult = context.evalCode(`new __Server__()`);
|
|
82
82
|
if (serverResult.error) {
|
|
@@ -281,4 +281,4 @@ export {
|
|
|
281
281
|
createFetchHandle
|
|
282
282
|
};
|
|
283
283
|
|
|
284
|
-
//# debugId=
|
|
284
|
+
//# debugId=802249127874F14F64756E2164756E21
|