@ricsam/quickjs-fetch 0.2.8 → 0.2.10

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.
@@ -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
- function createRequestClass(context, stateMap, createStream) {
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,34 @@ 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._uploadStreamGlobalKey) {
138
+ return streamHelpers?.getStreamByKey(this._uploadStreamGlobalKey) || null;
139
+ }
140
+ if (this._cachedBodyStream !== undefined) {
141
+ return this._cachedBodyStream;
142
+ }
143
+ if (this.nativeBodyStream) {
144
+ if (!streamHelpers?.createEmptyStream || !streamHelpers?.getStreamByKey) {
145
+ return null;
146
+ }
147
+ const { instanceId: streamInstanceId, globalKey } = streamHelpers.createEmptyStream();
148
+ const cleanup = startNativeStreamReader(this.nativeBodyStream, streamInstanceId, streamHelpers.pumpEventLoop);
149
+ this._uploadStreamCleanup = cleanup;
150
+ this._uploadStreamGlobalKey = globalKey;
151
+ this.nativeBodyStream = undefined;
152
+ return streamHelpers.getStreamByKey(globalKey);
153
+ }
154
+ if (!this.body) {
155
+ this._cachedBodyStream = null;
156
+ return null;
157
+ }
119
158
  const bodyData = this.body;
120
159
  let offset = 0;
121
160
  const chunkSize = 65536;
122
- return createStream({
161
+ const stream = createStream({
123
162
  pull(controller) {
124
163
  if (offset >= bodyData.length) {
125
164
  controller.close();
@@ -130,6 +169,8 @@ function createRequestClass(context, stateMap, createStream) {
130
169
  controller.enqueue(chunk);
131
170
  }
132
171
  });
172
+ this._cachedBodyStream = stream;
173
+ return stream;
133
174
  }
134
175
  },
135
176
  bodyUsed: {
@@ -194,6 +235,10 @@ function createRequestClass(context, stateMap, createStream) {
194
235
  throw new TypeError("Body has already been consumed");
195
236
  }
196
237
  this.bodyUsed = true;
238
+ if (this.nativeBodyStream) {
239
+ const buffer = await consumeNativeStream(this.nativeBodyStream);
240
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
241
+ }
197
242
  if (!this.body) {
198
243
  return new ArrayBuffer(0);
199
244
  }
@@ -205,6 +250,14 @@ function createRequestClass(context, stateMap, createStream) {
205
250
  }
206
251
  this.bodyUsed = true;
207
252
  const contentType = this.headersState.headers.get("content-type")?.[0] || "";
253
+ if (this.nativeBodyStream) {
254
+ const buffer = await consumeNativeStream(this.nativeBodyStream);
255
+ return {
256
+ parts: [buffer],
257
+ type: contentType,
258
+ size: buffer.length
259
+ };
260
+ }
208
261
  return {
209
262
  parts: this.body ? [this.body] : [],
210
263
  type: contentType,
@@ -215,6 +268,9 @@ function createRequestClass(context, stateMap, createStream) {
215
268
  if (this.bodyUsed) {
216
269
  throw new TypeError("Body has already been consumed");
217
270
  }
271
+ if (this.nativeBodyStream) {
272
+ throw new TypeError("Cannot clone Request with streaming body");
273
+ }
218
274
  return {
219
275
  ...this,
220
276
  headersState: {
@@ -229,6 +285,11 @@ function createRequestClass(context, stateMap, createStream) {
229
285
  throw new TypeError("Body has already been consumed");
230
286
  }
231
287
  this.bodyUsed = true;
288
+ if (this.nativeBodyStream) {
289
+ const buffer = await consumeNativeStream(this.nativeBodyStream);
290
+ const text2 = new TextDecoder().decode(buffer);
291
+ return JSON.parse(text2);
292
+ }
232
293
  if (!this.body) {
233
294
  return JSON.parse("");
234
295
  }
@@ -240,6 +301,10 @@ function createRequestClass(context, stateMap, createStream) {
240
301
  throw new TypeError("Body has already been consumed");
241
302
  }
242
303
  this.bodyUsed = true;
304
+ if (this.nativeBodyStream) {
305
+ const buffer = await consumeNativeStream(this.nativeBodyStream);
306
+ return new TextDecoder().decode(buffer);
307
+ }
243
308
  if (!this.body) {
244
309
  return "";
245
310
  }
@@ -250,15 +315,21 @@ function createRequestClass(context, stateMap, createStream) {
250
315
  throw new TypeError("Body has already been consumed");
251
316
  }
252
317
  this.bodyUsed = true;
253
- if (!this.body) {
318
+ let bodyData = null;
319
+ if (this.nativeBodyStream) {
320
+ bodyData = await consumeNativeStream(this.nativeBodyStream);
321
+ } else {
322
+ bodyData = this.body;
323
+ }
324
+ if (!bodyData) {
254
325
  return { entries: [] };
255
326
  }
256
327
  const contentType = this.headersState.headers.get("content-type")?.[0] || "";
257
328
  let formDataState;
258
329
  if (contentType.includes("multipart/form-data")) {
259
- formDataState = parseMultipartFormData(this.body, contentType);
330
+ formDataState = parseMultipartFormData(bodyData, contentType);
260
331
  } else if (contentType.includes("application/x-www-form-urlencoded")) {
261
- formDataState = parseUrlEncodedFormData(this.body);
332
+ formDataState = parseUrlEncodedFormData(bodyData);
262
333
  } else {
263
334
  throw new TypeError("Could not parse content as FormData");
264
335
  }
@@ -308,13 +379,12 @@ function addRequestFormDataMethod(context) {
308
379
  result.value.dispose();
309
380
  }
310
381
  }
311
- async function createRequestStateFromNative(request) {
312
- const body = request.body ? new Uint8Array(await request.arrayBuffer()) : null;
382
+ function createRequestStateFromNative(request) {
313
383
  return {
314
384
  method: request.method,
315
385
  url: request.url,
316
386
  headersState: createHeadersStateFromNative(request.headers),
317
- body,
387
+ body: null,
318
388
  bodyUsed: false,
319
389
  cache: request.cache,
320
390
  credentials: request.credentials,
@@ -325,7 +395,8 @@ async function createRequestStateFromNative(request) {
325
395
  redirect: request.redirect,
326
396
  referrer: request.referrer,
327
397
  referrerPolicy: request.referrerPolicy,
328
- signal: null
398
+ signal: null,
399
+ nativeBodyStream: request.body ?? undefined
329
400
  };
330
401
  }
331
402
  export {
@@ -334,4 +405,4 @@ export {
334
405
  addRequestFormDataMethod
335
406
  };
336
407
 
337
- //# debugId=5790EB732C5A0C5964756E2164756E21
408
+ //# debugId=1AB30F476B52ACC364756E2164756E21
@@ -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 /** Gets a fresh handle to the stream stored at globalKey */\n getStreamByKey: (globalKey: string) => QuickJSHandle | null;\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 & { _uploadStreamGlobalKey?: string; _uploadStreamCleanup?: () => void; _cachedBodyStream?: object | null }) {\n if (!createStream) {\n // Fallback: return raw body if no stream factory\n return this.body;\n }\n\n // If we have an upload stream, get a fresh handle each time\n // (Can't cache handles because __hostCall__ disposes them after each call)\n if (this._uploadStreamGlobalKey) {\n return streamHelpers?.getStreamByKey(this._uploadStreamGlobalKey) || null;\n }\n\n // Return cached buffered body 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 || !streamHelpers?.getStreamByKey) {\n // No helpers available - fall back to null (legacy behavior)\n return null;\n }\n\n // Create a QuickJS ReadableStream with no source callbacks.\n // The stream is stored on a global because __hostCall__ disposes returned\n // handles after each call. We cache the globalKey and get a fresh handle\n // on each access via getStreamByKey().\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 can get the same stream\n this._uploadStreamGlobalKey = 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 // Get fresh handle to return\n return streamHelpers.getStreamByKey(globalKey);\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": "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",
8
- "debugId": "5790EB732C5A0C5964756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "1AB30F476B52ACC364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -6,20 +6,13 @@ function createServerWebSocketClass(context, stateMap, onWebSocketCommand) {
6
6
  name: "ServerWebSocket",
7
7
  construct: (args) => {
8
8
  const connectionId = String(args[0]);
9
- const data = args[1];
10
9
  return {
11
- data,
12
10
  readyState: 1,
13
11
  connectionId,
14
12
  wsHandle: null
15
13
  };
16
14
  },
17
15
  properties: {
18
- data: {
19
- get() {
20
- return this.data;
21
- }
22
- },
23
16
  readyState: {
24
17
  get() {
25
18
  return this.readyState;
@@ -62,22 +55,13 @@ function createServerWebSocketClass(context, stateMap, onWebSocketCommand) {
62
55
  }
63
56
  });
64
57
  }
65
- function createServerClass(context, stateMap, serveState) {
58
+ function createServerClass(context, stateMap, _serveState) {
66
59
  return defineClass(context, stateMap, {
67
60
  name: "Server",
68
61
  construct: () => {
69
- return { serveState };
62
+ return {};
70
63
  },
71
- methods: {
72
- upgrade(_request, options) {
73
- const data = options && typeof options === "object" && "data" in options ? options.data : undefined;
74
- this.serveState.pendingUpgrade = {
75
- requested: true,
76
- data
77
- };
78
- return true;
79
- }
80
- }
64
+ methods: {}
81
65
  });
82
66
  }
83
67
  function createServeFunction(context, stateMap, serveState) {
@@ -148,4 +132,4 @@ export {
148
132
  createServeFunction
149
133
  };
150
134
 
151
- //# debugId=273172F2CE17BE7964756E2164756E21
135
+ //# debugId=168A2F1F5C5FC26C64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/globals/serve.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap } from \"@ricsam/quickjs-core\";\nimport { defineClass } from \"@ricsam/quickjs-core\";\nimport type { ServeState, ServerWebSocketState, WebSocketCommand } from \"../types.mjs\";\n\ninterface ServerState {\n serveState: ServeState;\n}\n\n/**\n * Create the ServerWebSocket class for QuickJS\n */\nexport function createServerWebSocketClass(\n context: QuickJSContext,\n stateMap: StateMap,\n onWebSocketCommand: (cmd: WebSocketCommand) => void\n): QuickJSHandle {\n return defineClass<ServerWebSocketState>(context, stateMap, {\n name: \"ServerWebSocket\",\n construct: (args) => {\n const connectionId = String(args[0]);\n const data = args[1];\n\n return {\n data,\n readyState: 1, // OPEN\n connectionId,\n wsHandle: null,\n };\n },\n properties: {\n data: {\n get(this: ServerWebSocketState) {\n return this.data;\n },\n },\n readyState: {\n get(this: ServerWebSocketState) {\n return this.readyState;\n },\n },\n },\n methods: {\n send(this: ServerWebSocketState, message: unknown) {\n if (this.readyState !== 1) {\n throw new Error(\"WebSocket is not open\");\n }\n\n let data: string | ArrayBuffer;\n if (typeof message === \"string\") {\n data = message;\n } else if (message instanceof ArrayBuffer) {\n data = message;\n } else if (message instanceof Uint8Array) {\n data = message.buffer.slice(\n message.byteOffset,\n message.byteOffset + message.byteLength\n ) as ArrayBuffer;\n } else {\n data = String(message);\n }\n\n onWebSocketCommand({\n type: \"message\",\n connectionId: this.connectionId,\n data,\n });\n },\n close(this: ServerWebSocketState, code?: unknown, reason?: unknown) {\n if (this.readyState === 3) {\n return; // Already closed\n }\n\n this.readyState = 2; // CLOSING\n\n onWebSocketCommand({\n type: \"close\",\n connectionId: this.connectionId,\n code: typeof code === \"number\" ? code : undefined,\n reason: typeof reason === \"string\" ? reason : undefined,\n });\n },\n },\n });\n}\n\n/**\n * Create the Server class for QuickJS\n */\nexport function createServerClass(\n context: QuickJSContext,\n stateMap: StateMap,\n serveState: ServeState\n): QuickJSHandle {\n return defineClass<ServerState>(context, stateMap, {\n name: \"Server\",\n construct: () => {\n return { serveState };\n },\n methods: {\n upgrade(\n this: ServerState,\n _request: unknown,\n options?: unknown\n ): boolean {\n const data =\n options && typeof options === \"object\" && \"data\" in options\n ? (options as { data: unknown }).data\n : undefined;\n\n this.serveState.pendingUpgrade = {\n requested: true,\n data,\n };\n\n return true;\n },\n },\n });\n}\n\n/**\n * Create the serve function for QuickJS\n * Uses context.newFunction instead of defineFunction to properly manage handle lifetimes\n */\nexport function createServeFunction(\n context: QuickJSContext,\n stateMap: StateMap,\n serveState: ServeState\n): QuickJSHandle {\n return context.newFunction(\"serve\", (optionsHandle) => {\n if (context.typeof(optionsHandle) !== \"object\") {\n throw context.newError(\"serve requires an options object\");\n }\n\n // Dispose previous handlers if any\n if (serveState.fetchHandler) {\n serveState.fetchHandler.dispose();\n serveState.fetchHandler = null;\n }\n\n // Get and store fetch handler - don't dispose, keep alive for later calls\n const fetchHandle = context.getProp(optionsHandle, \"fetch\");\n if (context.typeof(fetchHandle) === \"function\") {\n serveState.fetchHandler = fetchHandle;\n } else {\n fetchHandle.dispose();\n }\n\n // Get and store websocket handlers\n const websocketHandle = context.getProp(optionsHandle, \"websocket\");\n if (context.typeof(websocketHandle) === \"object\") {\n // Dispose previous handlers\n if (serveState.websocketHandlers.open) {\n serveState.websocketHandlers.open.dispose();\n serveState.websocketHandlers.open = undefined;\n }\n if (serveState.websocketHandlers.message) {\n serveState.websocketHandlers.message.dispose();\n serveState.websocketHandlers.message = undefined;\n }\n if (serveState.websocketHandlers.close) {\n serveState.websocketHandlers.close.dispose();\n serveState.websocketHandlers.close = undefined;\n }\n if (serveState.websocketHandlers.error) {\n serveState.websocketHandlers.error.dispose();\n serveState.websocketHandlers.error = undefined;\n }\n\n const openHandle = context.getProp(websocketHandle, \"open\");\n if (context.typeof(openHandle) === \"function\") {\n serveState.websocketHandlers.open = openHandle;\n } else {\n openHandle.dispose();\n }\n\n const messageHandle = context.getProp(websocketHandle, \"message\");\n if (context.typeof(messageHandle) === \"function\") {\n serveState.websocketHandlers.message = messageHandle;\n } else {\n messageHandle.dispose();\n }\n\n const closeHandle = context.getProp(websocketHandle, \"close\");\n if (context.typeof(closeHandle) === \"function\") {\n serveState.websocketHandlers.close = closeHandle;\n } else {\n closeHandle.dispose();\n }\n\n const errorHandle = context.getProp(websocketHandle, \"error\");\n if (context.typeof(errorHandle) === \"function\") {\n serveState.websocketHandlers.error = errorHandle;\n } else {\n errorHandle.dispose();\n }\n }\n websocketHandle.dispose();\n\n return context.undefined;\n });\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap } from \"@ricsam/quickjs-core\";\nimport { defineClass } from \"@ricsam/quickjs-core\";\nimport type { ServeState, ServerWebSocketState, WebSocketCommand } from \"../types.mjs\";\n\n// Server state is empty - upgrade method is pure JavaScript and stores data in a global registry\ntype ServerState = Record<string, never>;\n\n/**\n * Create the ServerWebSocket class for QuickJS\n */\nexport function createServerWebSocketClass(\n context: QuickJSContext,\n stateMap: StateMap,\n onWebSocketCommand: (cmd: WebSocketCommand) => void\n): QuickJSHandle {\n return defineClass<ServerWebSocketState>(context, stateMap, {\n name: \"ServerWebSocket\",\n construct: (args) => {\n const connectionId = String(args[0]);\n // Note: 'data' is accessed via a pure-JS getter that reads from __upgradeRegistry__\n // This avoids unmarshalling complex objects (like Zod schemas) that would exceed depth limit\n return {\n readyState: 1, // OPEN\n connectionId,\n wsHandle: null,\n };\n },\n properties: {\n // Note: 'data' is NOT defined here - it's a pure-JS getter added in setup.ts\n // that reads from __upgradeRegistry__ to avoid marshalling complex objects\n readyState: {\n get(this: ServerWebSocketState) {\n return this.readyState;\n },\n },\n },\n methods: {\n send(this: ServerWebSocketState, message: unknown) {\n if (this.readyState !== 1) {\n throw new Error(\"WebSocket is not open\");\n }\n\n let data: string | ArrayBuffer;\n if (typeof message === \"string\") {\n data = message;\n } else if (message instanceof ArrayBuffer) {\n data = message;\n } else if (message instanceof Uint8Array) {\n data = message.buffer.slice(\n message.byteOffset,\n message.byteOffset + message.byteLength\n ) as ArrayBuffer;\n } else {\n data = String(message);\n }\n\n onWebSocketCommand({\n type: \"message\",\n connectionId: this.connectionId,\n data,\n });\n },\n close(this: ServerWebSocketState, code?: unknown, reason?: unknown) {\n if (this.readyState === 3) {\n return; // Already closed\n }\n\n this.readyState = 2; // CLOSING\n\n onWebSocketCommand({\n type: \"close\",\n connectionId: this.connectionId,\n code: typeof code === \"number\" ? code : undefined,\n reason: typeof reason === \"string\" ? reason : undefined,\n });\n },\n },\n });\n}\n\n/**\n * Create the Server class for QuickJS\n */\nexport function createServerClass(\n context: QuickJSContext,\n stateMap: StateMap,\n _serveState: ServeState\n): QuickJSHandle {\n // Note: The upgrade method is added as pure JavaScript in setup.ts\n // to avoid marshalling data across the QuickJS/host boundary.\n // This keeps complex objects (like Zod schemas) within QuickJS.\n return defineClass<ServerState>(context, stateMap, {\n name: \"Server\",\n construct: () => {\n return {};\n },\n methods: {},\n });\n}\n\n/**\n * Create the serve function for QuickJS\n * Uses context.newFunction instead of defineFunction to properly manage handle lifetimes\n */\nexport function createServeFunction(\n context: QuickJSContext,\n stateMap: StateMap,\n serveState: ServeState\n): QuickJSHandle {\n return context.newFunction(\"serve\", (optionsHandle) => {\n if (context.typeof(optionsHandle) !== \"object\") {\n throw context.newError(\"serve requires an options object\");\n }\n\n // Dispose previous handlers if any\n if (serveState.fetchHandler) {\n serveState.fetchHandler.dispose();\n serveState.fetchHandler = null;\n }\n\n // Get and store fetch handler - don't dispose, keep alive for later calls\n const fetchHandle = context.getProp(optionsHandle, \"fetch\");\n if (context.typeof(fetchHandle) === \"function\") {\n serveState.fetchHandler = fetchHandle;\n } else {\n fetchHandle.dispose();\n }\n\n // Get and store websocket handlers\n const websocketHandle = context.getProp(optionsHandle, \"websocket\");\n if (context.typeof(websocketHandle) === \"object\") {\n // Dispose previous handlers\n if (serveState.websocketHandlers.open) {\n serveState.websocketHandlers.open.dispose();\n serveState.websocketHandlers.open = undefined;\n }\n if (serveState.websocketHandlers.message) {\n serveState.websocketHandlers.message.dispose();\n serveState.websocketHandlers.message = undefined;\n }\n if (serveState.websocketHandlers.close) {\n serveState.websocketHandlers.close.dispose();\n serveState.websocketHandlers.close = undefined;\n }\n if (serveState.websocketHandlers.error) {\n serveState.websocketHandlers.error.dispose();\n serveState.websocketHandlers.error = undefined;\n }\n\n const openHandle = context.getProp(websocketHandle, \"open\");\n if (context.typeof(openHandle) === \"function\") {\n serveState.websocketHandlers.open = openHandle;\n } else {\n openHandle.dispose();\n }\n\n const messageHandle = context.getProp(websocketHandle, \"message\");\n if (context.typeof(messageHandle) === \"function\") {\n serveState.websocketHandlers.message = messageHandle;\n } else {\n messageHandle.dispose();\n }\n\n const closeHandle = context.getProp(websocketHandle, \"close\");\n if (context.typeof(closeHandle) === \"function\") {\n serveState.websocketHandlers.close = closeHandle;\n } else {\n closeHandle.dispose();\n }\n\n const errorHandle = context.getProp(websocketHandle, \"error\");\n if (context.typeof(errorHandle) === \"function\") {\n serveState.websocketHandlers.error = errorHandle;\n } else {\n errorHandle.dispose();\n }\n }\n websocketHandle.dispose();\n\n return context.undefined;\n });\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "273172F2CE17BE7964756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "168A2F1F5C5FC26C64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -75,8 +75,19 @@ function createFetchHandle(context, stateMap, serveState) {
75
75
  if (!serveState.fetchHandler) {
76
76
  throw new Error("No serve() handler registered");
77
77
  }
78
+ if (serveState.pendingUpgrade?.connectionId) {
79
+ const connId = serveState.pendingUpgrade.connectionId;
80
+ if (!serveState.activeConnections.has(connId)) {
81
+ const deleteResult = context.evalCode(`__upgradeRegistry__.delete("${connId}")`);
82
+ if (deleteResult.error) {
83
+ deleteResult.error.dispose();
84
+ } else {
85
+ deleteResult.value.dispose();
86
+ }
87
+ }
88
+ }
78
89
  serveState.pendingUpgrade = null;
79
- const requestState = await createRequestStateFromNative(request);
90
+ const requestState = createRequestStateFromNative(request);
80
91
  const requestHandle = createRequestInstance(context, stateMap, requestState);
81
92
  const serverResult = context.evalCode(`new __Server__()`);
82
93
  if (serverResult.error) {
@@ -143,26 +154,24 @@ function createFetchHandle(context, stateMap, serveState) {
143
154
  getUpgradeRequest() {
144
155
  return serveState.pendingUpgrade;
145
156
  },
146
- dispatchWebSocketOpen(connectionId, data) {
157
+ dispatchWebSocketOpen(connectionId) {
147
158
  if (!serveState.websocketHandlers.open) {
148
159
  return;
149
160
  }
150
161
  const connectionIdHandle = context.newString(connectionId);
151
- const dataHandle = marshal(context, data);
152
162
  context.setProp(context.global, "__wsConnectionId__", connectionIdHandle);
153
- context.setProp(context.global, "__wsData__", dataHandle);
154
163
  connectionIdHandle.dispose();
155
- dataHandle.dispose();
156
- const wsResult = context.evalCode(`new __ServerWebSocket__(__wsConnectionId__, __wsData__)`);
164
+ const wsResult = context.evalCode(`new __ServerWebSocket__(__wsConnectionId__)`);
157
165
  context.setProp(context.global, "__wsConnectionId__", context.undefined);
158
- context.setProp(context.global, "__wsData__", context.undefined);
159
166
  if (wsResult.error) {
160
167
  wsResult.error.dispose();
161
168
  return;
162
169
  }
163
170
  const wsHandle = wsResult.value;
171
+ const connIdForGetter = context.newString(connectionId);
172
+ context.setProp(wsHandle, "__connectionId__", connIdForGetter);
173
+ connIdForGetter.dispose();
164
174
  serveState.activeConnections.set(connectionId, {
165
- data,
166
175
  readyState: 1,
167
176
  connectionId,
168
177
  wsHandle
@@ -194,14 +203,24 @@ function createFetchHandle(context, stateMap, serveState) {
194
203
  context.runtime.executePendingJobs();
195
204
  },
196
205
  dispatchWebSocketClose(connectionId, code, reason) {
206
+ const cleanupRegistry = () => {
207
+ const deleteResult = context.evalCode(`__upgradeRegistry__.delete("${connectionId}")`);
208
+ if (deleteResult.error) {
209
+ deleteResult.error.dispose();
210
+ } else {
211
+ deleteResult.value.dispose();
212
+ }
213
+ };
197
214
  const connection = serveState.activeConnections.get(connectionId);
198
215
  if (!connection || !connection.wsHandle) {
199
216
  serveState.activeConnections.delete(connectionId);
217
+ cleanupRegistry();
200
218
  return;
201
219
  }
202
220
  if (!serveState.websocketHandlers.close) {
203
221
  connection.wsHandle.dispose();
204
222
  serveState.activeConnections.delete(connectionId);
223
+ cleanupRegistry();
205
224
  return;
206
225
  }
207
226
  connection.readyState = 3;
@@ -217,6 +236,7 @@ function createFetchHandle(context, stateMap, serveState) {
217
236
  }
218
237
  connection.wsHandle.dispose();
219
238
  serveState.activeConnections.delete(connectionId);
239
+ cleanupRegistry();
220
240
  context.runtime.executePendingJobs();
221
241
  },
222
242
  dispatchWebSocketError(connectionId, error) {
@@ -248,6 +268,12 @@ function createFetchHandle(context, stateMap, serveState) {
248
268
  return serveState.fetchHandler !== null;
249
269
  },
250
270
  dispose() {
271
+ const clearResult = context.evalCode(`__upgradeRegistry__.clear()`);
272
+ if (clearResult.error) {
273
+ clearResult.error.dispose();
274
+ } else {
275
+ clearResult.value.dispose();
276
+ }
251
277
  if (serveState.websocketHandlers.open) {
252
278
  serveState.websocketHandlers.open.dispose();
253
279
  serveState.websocketHandlers.open = undefined;
@@ -281,4 +307,4 @@ export {
281
307
  createFetchHandle
282
308
  };
283
309
 
284
- //# debugId=ED91E5C4CED38FC864756E2164756E21
310
+ //# debugId=56BFD315339C6DE564756E2164756E21