@ricsam/quickjs-fetch 0.2.14 → 0.2.16

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.
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/setup.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { setupCore, createStateMap, createReadableStream } from \"@ricsam/quickjs-core\";\nimport type { SetupFetchOptions, FetchHandle, ServeState } from \"./types.cjs\";\nimport { createHeadersClass } from \"./globals/headers.cjs\";\nimport { createRequestClass, addRequestFormDataMethod } from \"./globals/request.cjs\";\nimport { createResponseClass, addResponseStaticMethods } from \"./globals/response.cjs\";\nimport { setupAbortControllerAndSignal } from \"./globals/abort-controller.cjs\";\nimport { createFormDataClass, addFormDataFileMethods } from \"./globals/form-data.cjs\";\nimport { createFetchFunction } from \"./globals/fetch.cjs\";\nimport {\n createServeFunction,\n createServerClass,\n createServerWebSocketClass,\n} from \"./globals/serve.cjs\";\nimport { createFetchHandle } from \"./handle.cjs\";\n\n/**\n * Setup Fetch API in a QuickJS context\n *\n * Injects the following globals:\n * - fetch\n * - Request\n * - Response\n * - Headers\n * - AbortController\n * - AbortSignal\n * - serve\n * - FormData\n *\n * Also sets up Core APIs (Streams, Blob, File) if not already present.\n *\n * **Private globals (internal use):**\n * - `__Server__` - Server class for serve() handler, instantiated via evalCode\n * - `__ServerWebSocket__` - WebSocket class for connection handling\n * - `__scheduleTimeout__` - Host function to schedule AbortSignal.timeout()\n * - `__checkTimeout__` - Host function to check if timeout elapsed\n *\n * These private globals follow the `__Name__` convention and are required for\n * JavaScript code in QuickJS to create class instances via evalCode.\n * See PATTERNS.md section 5 for details.\n *\n * @example\n * const handle = setupFetch(context, {\n * onFetch: async (request) => {\n * // Proxy to real fetch\n * return fetch(request);\n * }\n * });\n *\n * context.evalCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `);\n *\n * const response = await handle.dispatchRequest(\n * new Request(\"http://localhost/\")\n * );\n */\nexport function setupFetch(\n context: QuickJSContext,\n options: SetupFetchOptions = {}\n): FetchHandle {\n // Setup core if not already done\n const coreHandle =\n options.coreHandle ??\n setupCore(context, {\n stateMap: options.stateMap,\n });\n\n const stateMap = options.stateMap ?? coreHandle.stateMap;\n\n // Create serve state\n const serveState: ServeState = {\n fetchHandler: null,\n websocketHandlers: {},\n pendingUpgrade: null,\n activeConnections: new Map(),\n };\n\n // WebSocket command dispatcher\n const wsCommandCallbacks = new Set<\n (cmd: import(\"./types.cjs\").WebSocketCommand) => void\n >();\n const dispatchWsCommand = (cmd: import(\"./types.cjs\").WebSocketCommand) => {\n for (const cb of wsCommandCallbacks) {\n cb(cmd);\n }\n };\n\n // Create stream factory for Request/Response body\n const streamFactory = (source: UnderlyingSource) =>\n createReadableStream(context, stateMap, source);\n\n // Create stream helpers for upload streaming\n const streamHelpers = {\n createStream: streamFactory,\n /**\n * Create an empty ReadableStream for upload streaming.\n *\n * IMPORTANT: We store the stream on a global variable and return the key.\n * This is necessary because __hostCall__ manages and disposes returned handles\n * in its scope. If we cached the handle and returned it multiple times,\n * subsequent calls would return a dead handle.\n *\n * The getter must call getStreamByKey() each time to get a fresh handle.\n */\n createEmptyStream: (): { instanceId: number; globalKey: string } => {\n const globalKey = `__uploadStream_${Date.now()}_${Math.random().toString(36).slice(2)}__`;\n const result = context.evalCode(`\n (function() {\n const stream = new ReadableStream();\n globalThis[\"${globalKey}\"] = stream;\n return stream.__instanceId__;\n })()\n `);\n if (result.error) {\n const error = context.dump(result.error);\n result.error.dispose();\n throw new Error(`Failed to create empty ReadableStream: ${JSON.stringify(error)}`);\n }\n const instanceId = context.getNumber(result.value);\n result.value.dispose();\n\n return { instanceId, globalKey };\n },\n /**\n * Get a fresh handle to the stream stored at globalKey.\n * This must be called each time the body getter is accessed to avoid\n * returning disposed handles.\n */\n getStreamByKey: (globalKey: string): import(\"quickjs-emscripten\").QuickJSHandle | null => {\n const result = context.evalCode(`globalThis[\"${globalKey}\"]`);\n if (result.error) {\n result.error.dispose();\n return null;\n }\n if (context.typeof(result.value) === \"undefined\") {\n result.value.dispose();\n return null;\n }\n return result.value;\n },\n pumpEventLoop: () => {\n context.runtime.executePendingJobs();\n },\n };\n\n // Create Headers class\n const HeadersClass = createHeadersClass(context, stateMap);\n context.setProp(context.global, \"Headers\", HeadersClass);\n HeadersClass.dispose();\n\n // Add Symbol.iterator support for Headers (for...of, Array.from, spread)\n const iteratorResult = context.evalCode(`\n Headers.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (iteratorResult.error) {\n iteratorResult.error.dispose();\n } else {\n iteratorResult.value.dispose();\n }\n\n // Create Request class\n const RequestClass = createRequestClass(context, stateMap, streamHelpers);\n context.setProp(context.global, \"Request\", RequestClass);\n RequestClass.dispose();\n\n // Note: No body getter wrapper needed - handles are returned directly\n // through __hostCall__ because quickjs-emscripten properly duplicates\n // handles via QTS_DupValuePointer before returning to QuickJS.\n\n // Create Response class\n const ResponseClass = createResponseClass(context, stateMap, streamFactory);\n context.setProp(context.global, \"Response\", ResponseClass);\n ResponseClass.dispose();\n\n // Add Response static methods (must be after Response and Headers are on global)\n addResponseStaticMethods(context);\n\n // Create AbortSignal and AbortController classes (pure QuickJS implementation)\n setupAbortControllerAndSignal(context);\n\n // Create FormData class\n const FormDataClass = createFormDataClass(context, stateMap);\n context.setProp(context.global, \"FormData\", FormDataClass);\n FormDataClass.dispose();\n\n // Add Symbol.iterator support for FormData (for...of, Array.from, spread)\n const formDataIteratorResult = context.evalCode(`\n FormData.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (formDataIteratorResult.error) {\n formDataIteratorResult.error.dispose();\n } else {\n formDataIteratorResult.value.dispose();\n }\n\n // Add Request.formData() method that returns a proper FormData instance\n // Must be after both Request and FormData are on global\n addRequestFormDataMethod(context);\n\n // Add FormData.get()/getAll() overrides to reconstruct File instances\n // Must be after both FormData and File are on global\n addFormDataFileMethods(context);\n\n // Create ServerWebSocket class (internal, for WebSocket handling)\n const ServerWebSocketClass = createServerWebSocketClass(\n context,\n stateMap,\n dispatchWsCommand\n );\n // Set on global with internal name so we can use evalCode to instantiate\n context.setProp(context.global, \"__ServerWebSocket__\", ServerWebSocketClass);\n ServerWebSocketClass.dispose();\n // Note: ServerWebSocketClass handle is now owned by global\n\n // Add pure-JS data getter to ServerWebSocket prototype\n // This getter reads from __upgradeRegistry__ using __connectionId__,\n // keeping complex data (like Zod schemas) entirely within QuickJS\n // to avoid marshalling depth limit issues\n const dataGetterResult = context.evalCode(`\n Object.defineProperty(__ServerWebSocket__.prototype, 'data', {\n get: function() {\n return __upgradeRegistry__.get(this.__connectionId__);\n },\n enumerable: true,\n configurable: true\n });\n `);\n if (dataGetterResult.error) {\n dataGetterResult.error.dispose();\n } else {\n dataGetterResult.value.dispose();\n }\n\n // Create Server class (internal, passed to fetch handler)\n const ServerClass = createServerClass(context, stateMap, serveState);\n // Set on global with internal name so we can use evalCode to instantiate\n context.setProp(context.global, \"__Server__\", ServerClass);\n ServerClass.dispose();\n // Note: ServerClass handle is now owned by global\n\n // Setup upgrade registry and helper function for WebSocket upgrades\n // The registry keeps data within QuickJS to avoid marshalling complex objects\n const registryResult = context.evalCode(`\n globalThis.__upgradeRegistry__ = new Map();\n globalThis.__upgradeIdCounter__ = 0;\n `);\n if (registryResult.error) {\n registryResult.error.dispose();\n } else {\n registryResult.value.dispose();\n }\n\n // Host function to set pendingUpgrade - only receives connectionId string\n const setPendingUpgradeFn = context.newFunction(\n \"__setPendingUpgrade__\",\n (connIdHandle) => {\n const connectionId = context.getString(connIdHandle);\n serveState.pendingUpgrade = { requested: true, connectionId };\n return context.undefined;\n }\n );\n context.setProp(context.global, \"__setPendingUpgrade__\", setPendingUpgradeFn);\n setPendingUpgradeFn.dispose();\n\n // Add upgrade method to Server prototype as pure JavaScript\n // This keeps the data within QuickJS and only passes connectionId to host\n const upgradeMethodResult = context.evalCode(`\n __Server__.prototype.upgrade = function(request, options) {\n const data = options && typeof options === 'object' ? options.data : undefined;\n const connectionId = String(++globalThis.__upgradeIdCounter__);\n globalThis.__upgradeRegistry__.set(connectionId, data);\n __setPendingUpgrade__(connectionId);\n return true;\n };\n `);\n if (upgradeMethodResult.error) {\n upgradeMethodResult.error.dispose();\n } else {\n upgradeMethodResult.value.dispose();\n }\n\n // Create fetch function\n const fetchFn = createFetchFunction(context, options.onFetch);\n context.setProp(context.global, \"fetch\", fetchFn);\n fetchFn.dispose();\n\n // Create serve function\n const serveFn = createServeFunction(context, stateMap, serveState);\n context.setProp(context.global, \"serve\", serveFn);\n serveFn.dispose();\n\n // Create and return the handle\n const fetchHandle = createFetchHandle(\n context,\n stateMap,\n serveState\n );\n\n // Wire up WebSocket command callbacks\n const originalOnWebSocketCommand = fetchHandle.onWebSocketCommand;\n fetchHandle.onWebSocketCommand = (callback) => {\n wsCommandCallbacks.add(callback);\n return () => wsCommandCallbacks.delete(callback);\n };\n\n return fetchHandle;\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { setupCore, createStateMap, createReadableStream } from \"@ricsam/quickjs-core\";\nimport type { SetupFetchOptions, FetchHandle, ServeState } from \"./types.cjs\";\nimport { createHeadersClass } from \"./globals/headers.cjs\";\nimport { createRequestClass, addRequestFormDataMethod, addRequestCloneMethod, addRequestHeadersGetter } from \"./globals/request.cjs\";\nimport { createResponseClass, addResponseStaticMethods, addResponseCloneMethod, addResponseHeadersGetter } from \"./globals/response.cjs\";\nimport { setupAbortControllerAndSignal } from \"./globals/abort-controller.cjs\";\nimport { createFormDataClass, addFormDataFileMethods } from \"./globals/form-data.cjs\";\nimport { createFetchFunction } from \"./globals/fetch.cjs\";\nimport {\n createServeFunction,\n createServerClass,\n createServerWebSocketClass,\n} from \"./globals/serve.cjs\";\nimport { createFetchHandle } from \"./handle.cjs\";\n\n/**\n * Setup Fetch API in a QuickJS context\n *\n * Injects the following globals:\n * - fetch\n * - Request\n * - Response\n * - Headers\n * - AbortController\n * - AbortSignal\n * - serve\n * - FormData\n *\n * Also sets up Core APIs (Streams, Blob, File) if not already present.\n *\n * **Private globals (internal use):**\n * - `__Server__` - Server class for serve() handler, instantiated via evalCode\n * - `__ServerWebSocket__` - WebSocket class for connection handling\n * - `__scheduleTimeout__` - Host function to schedule AbortSignal.timeout()\n * - `__checkTimeout__` - Host function to check if timeout elapsed\n *\n * These private globals follow the `__Name__` convention and are required for\n * JavaScript code in QuickJS to create class instances via evalCode.\n * See PATTERNS.md section 5 for details.\n *\n * @example\n * const handle = setupFetch(context, {\n * onFetch: async (request) => {\n * // Proxy to real fetch\n * return fetch(request);\n * }\n * });\n *\n * context.evalCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `);\n *\n * const response = await handle.dispatchRequest(\n * new Request(\"http://localhost/\")\n * );\n */\nexport function setupFetch(\n context: QuickJSContext,\n options: SetupFetchOptions = {}\n): FetchHandle {\n // Setup core if not already done\n const coreHandle =\n options.coreHandle ??\n setupCore(context, {\n stateMap: options.stateMap,\n });\n\n const stateMap = options.stateMap ?? coreHandle.stateMap;\n\n // Create serve state\n const serveState: ServeState = {\n fetchHandler: null,\n websocketHandlers: {},\n pendingUpgrade: null,\n activeConnections: new Map(),\n };\n\n // WebSocket command dispatcher\n const wsCommandCallbacks = new Set<\n (cmd: import(\"./types.cjs\").WebSocketCommand) => void\n >();\n const dispatchWsCommand = (cmd: import(\"./types.cjs\").WebSocketCommand) => {\n for (const cb of wsCommandCallbacks) {\n cb(cmd);\n }\n };\n\n // Create stream factory for Request/Response body\n const streamFactory = (source: UnderlyingSource) =>\n createReadableStream(context, stateMap, source);\n\n // Create stream helpers for upload streaming\n const streamHelpers = {\n createStream: streamFactory,\n /**\n * Create an empty ReadableStream for upload streaming.\n *\n * IMPORTANT: We store the stream on a global variable and return the key.\n * This is necessary because __hostCall__ manages and disposes returned handles\n * in its scope. If we cached the handle and returned it multiple times,\n * subsequent calls would return a dead handle.\n *\n * The getter must call getStreamByKey() each time to get a fresh handle.\n */\n createEmptyStream: (): { instanceId: number; globalKey: string } => {\n const globalKey = `__uploadStream_${Date.now()}_${Math.random().toString(36).slice(2)}__`;\n const result = context.evalCode(`\n (function() {\n const stream = new ReadableStream();\n globalThis[\"${globalKey}\"] = stream;\n return stream.__instanceId__;\n })()\n `);\n if (result.error) {\n const error = context.dump(result.error);\n result.error.dispose();\n throw new Error(`Failed to create empty ReadableStream: ${JSON.stringify(error)}`);\n }\n const instanceId = context.getNumber(result.value);\n result.value.dispose();\n\n return { instanceId, globalKey };\n },\n /**\n * Get a fresh handle to the stream stored at globalKey.\n * This must be called each time the body getter is accessed to avoid\n * returning disposed handles.\n */\n getStreamByKey: (globalKey: string): import(\"quickjs-emscripten\").QuickJSHandle | null => {\n const result = context.evalCode(`globalThis[\"${globalKey}\"]`);\n if (result.error) {\n result.error.dispose();\n return null;\n }\n if (context.typeof(result.value) === \"undefined\") {\n result.value.dispose();\n return null;\n }\n return result.value;\n },\n pumpEventLoop: () => {\n context.runtime.executePendingJobs();\n },\n };\n\n // Create Headers class\n const HeadersClass = createHeadersClass(context, stateMap);\n context.setProp(context.global, \"Headers\", HeadersClass);\n HeadersClass.dispose();\n\n // Add Symbol.iterator support for Headers (for...of, Array.from, spread)\n const iteratorResult = context.evalCode(`\n Headers.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (iteratorResult.error) {\n iteratorResult.error.dispose();\n } else {\n iteratorResult.value.dispose();\n }\n\n // Create Request class\n const RequestClass = createRequestClass(context, stateMap, streamHelpers);\n context.setProp(context.global, \"Request\", RequestClass);\n RequestClass.dispose();\n\n // Note: No body getter wrapper needed - handles are returned directly\n // through __hostCall__ because quickjs-emscripten properly duplicates\n // handles via QTS_DupValuePointer before returning to QuickJS.\n\n // Create Response class\n const ResponseClass = createResponseClass(context, stateMap, streamFactory);\n context.setProp(context.global, \"Response\", ResponseClass);\n ResponseClass.dispose();\n\n // Add Response static methods (must be after Response and Headers are on global)\n addResponseStaticMethods(context);\n\n // Create AbortSignal and AbortController classes (pure QuickJS implementation)\n setupAbortControllerAndSignal(context);\n\n // Create FormData class\n const FormDataClass = createFormDataClass(context, stateMap);\n context.setProp(context.global, \"FormData\", FormDataClass);\n FormDataClass.dispose();\n\n // Add Symbol.iterator support for FormData (for...of, Array.from, spread)\n const formDataIteratorResult = context.evalCode(`\n FormData.prototype[Symbol.iterator] = function() {\n return this.entries()[Symbol.iterator]();\n };\n `);\n if (formDataIteratorResult.error) {\n formDataIteratorResult.error.dispose();\n } else {\n formDataIteratorResult.value.dispose();\n }\n\n // Add Request.formData() method that returns a proper FormData instance\n // Must be after both Request and FormData are on global\n addRequestFormDataMethod(context);\n\n // Add Request.clone() method that returns a proper Request instance\n // Must be after Request and Headers are on global\n addRequestCloneMethod(context);\n\n // Add Response.clone() method that returns a proper Response instance\n // Must be after Response and Headers are on global\n addResponseCloneMethod(context);\n\n // Add Request.headers getter that returns a proper Headers instance\n // Must be after both Request and Headers are on global\n addRequestHeadersGetter(context);\n\n // Add Response.headers getter that returns a proper Headers instance\n // Must be after both Response and Headers are on global\n addResponseHeadersGetter(context);\n\n // Add FormData.get()/getAll() overrides to reconstruct File instances\n // Must be after both FormData and File are on global\n addFormDataFileMethods(context);\n\n // Create ServerWebSocket class (internal, for WebSocket handling)\n const ServerWebSocketClass = createServerWebSocketClass(\n context,\n stateMap,\n dispatchWsCommand\n );\n // Set on global with internal name so we can use evalCode to instantiate\n context.setProp(context.global, \"__ServerWebSocket__\", ServerWebSocketClass);\n ServerWebSocketClass.dispose();\n // Note: ServerWebSocketClass handle is now owned by global\n\n // Add pure-JS data getter to ServerWebSocket prototype\n // This getter reads from __upgradeRegistry__ using __connectionId__,\n // keeping complex data (like Zod schemas) entirely within QuickJS\n // to avoid marshalling depth limit issues\n const dataGetterResult = context.evalCode(`\n Object.defineProperty(__ServerWebSocket__.prototype, 'data', {\n get: function() {\n return __upgradeRegistry__.get(this.__connectionId__);\n },\n enumerable: true,\n configurable: true\n });\n `);\n if (dataGetterResult.error) {\n dataGetterResult.error.dispose();\n } else {\n dataGetterResult.value.dispose();\n }\n\n // Create Server class (internal, passed to fetch handler)\n const ServerClass = createServerClass(context, stateMap, serveState);\n // Set on global with internal name so we can use evalCode to instantiate\n context.setProp(context.global, \"__Server__\", ServerClass);\n ServerClass.dispose();\n // Note: ServerClass handle is now owned by global\n\n // Setup upgrade registry and helper function for WebSocket upgrades\n // The registry keeps data within QuickJS to avoid marshalling complex objects\n const registryResult = context.evalCode(`\n globalThis.__upgradeRegistry__ = new Map();\n globalThis.__upgradeIdCounter__ = 0;\n `);\n if (registryResult.error) {\n registryResult.error.dispose();\n } else {\n registryResult.value.dispose();\n }\n\n // Host function to set pendingUpgrade - only receives connectionId string\n const setPendingUpgradeFn = context.newFunction(\n \"__setPendingUpgrade__\",\n (connIdHandle) => {\n const connectionId = context.getString(connIdHandle);\n serveState.pendingUpgrade = { requested: true, connectionId };\n return context.undefined;\n }\n );\n context.setProp(context.global, \"__setPendingUpgrade__\", setPendingUpgradeFn);\n setPendingUpgradeFn.dispose();\n\n // Add upgrade method to Server prototype as pure JavaScript\n // This keeps the data within QuickJS and only passes connectionId to host\n const upgradeMethodResult = context.evalCode(`\n __Server__.prototype.upgrade = function(request, options) {\n const data = options && typeof options === 'object' ? options.data : undefined;\n const connectionId = String(++globalThis.__upgradeIdCounter__);\n globalThis.__upgradeRegistry__.set(connectionId, data);\n __setPendingUpgrade__(connectionId);\n return true;\n };\n `);\n if (upgradeMethodResult.error) {\n upgradeMethodResult.error.dispose();\n } else {\n upgradeMethodResult.value.dispose();\n }\n\n // Create fetch function\n const fetchFn = createFetchFunction(context, options.onFetch);\n context.setProp(context.global, \"fetch\", fetchFn);\n fetchFn.dispose();\n\n // Create serve function\n const serveFn = createServeFunction(context, stateMap, serveState);\n context.setProp(context.global, \"serve\", serveFn);\n serveFn.dispose();\n\n // Create and return the handle\n const fetchHandle = createFetchHandle(\n context,\n stateMap,\n serveState\n );\n\n // Wire up WebSocket command callbacks\n const originalOnWebSocketCommand = fetchHandle.onWebSocketCommand;\n fetchHandle.onWebSocketCommand = (callback) => {\n wsCommandCallbacks.add(callback);\n return () => wsCommandCallbacks.delete(callback);\n };\n\n return fetchHandle;\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "2354E39DCBC5283664756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "69084328C5578CAD64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -17,10 +17,59 @@ var __toCommonJS = (from) => {
17
17
  __moduleCache.set(from, entry);
18
18
  return entry;
19
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
+ };
20
29
 
21
30
  // packages/fetch/src/types.ts
22
31
  var exports_types = {};
32
+ __export(exports_types, {
33
+ isUnmarshalledUint8Array: () => isUnmarshalledUint8Array,
34
+ isResponseState: () => isResponseState,
35
+ isRequestState: () => isRequestState,
36
+ isHeadersState: () => isHeadersState,
37
+ isAbortSignalState: () => isAbortSignalState
38
+ });
23
39
  module.exports = __toCommonJS(exports_types);
40
+ function isHeadersState(obj) {
41
+ return obj !== null && typeof obj === "object" && "headers" in obj && obj.headers instanceof Map;
42
+ }
43
+ function isRequestState(obj) {
44
+ if (obj === null || typeof obj !== "object")
45
+ return false;
46
+ const state = obj;
47
+ return typeof state.method === "string" && typeof state.url === "string" && isHeadersState(state.headersState);
48
+ }
49
+ function isResponseState(obj) {
50
+ if (obj === null || typeof obj !== "object")
51
+ return false;
52
+ const state = obj;
53
+ return typeof state.status === "number" && "headersState" in state && isHeadersState(state.headersState) && typeof state.bodyUsed === "boolean";
54
+ }
55
+ function isAbortSignalState(obj) {
56
+ if (obj === null || typeof obj !== "object")
57
+ return false;
58
+ const state = obj;
59
+ return typeof state.aborted === "boolean" && "listeners" in state && state.listeners instanceof Set;
60
+ }
61
+ function isUnmarshalledUint8Array(obj) {
62
+ if (obj === null || typeof obj !== "object")
63
+ return false;
64
+ if (!("0" in obj))
65
+ return false;
66
+ const record = obj;
67
+ for (let i = 0;i < Math.min(3, Object.keys(record).length); i++) {
68
+ if (typeof record[String(i)] !== "number")
69
+ return false;
70
+ }
71
+ return true;
72
+ }
24
73
  })
25
74
 
26
- //# debugId=215C36070677FEE964756E2164756E21
75
+ //# debugId=03E8D870B0ED32C564756E2164756E21
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": [],
3
+ "sources": ["../../src/types.ts"],
4
4
  "sourcesContent": [
5
+ "import type { QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap, CoreHandle } from \"@ricsam/quickjs-core\";\n\nexport type { StateMap, CoreHandle };\n\n/**\n * Options for setting up Fetch APIs\n */\nexport interface SetupFetchOptions {\n /**\n * Handler for outbound fetch() calls from QuickJS\n * If not provided, fetch() will throw an error\n */\n onFetch?: (request: Request) => Promise<Response>;\n\n /** Existing state map (creates new one if not provided) */\n stateMap?: StateMap;\n\n /** Existing core handle (sets up core if not provided) */\n coreHandle?: CoreHandle;\n}\n\n/**\n * Data associated with a WebSocket connection\n */\nexport interface WebSocketData {\n /** User-provided data from server.upgrade() */\n data: unknown;\n\n /** Connection ID assigned by the host */\n connectionId: string;\n}\n\n/**\n * Pending upgrade request info\n */\nexport interface UpgradeRequest {\n /** Whether an upgrade was requested */\n requested: true;\n\n /** Connection ID generated by server.upgrade() - used to look up user data from QuickJS registry */\n connectionId: string;\n}\n\n/**\n * Message to send to a WebSocket\n */\nexport interface WebSocketOutgoingMessage {\n type: \"message\";\n connectionId: string;\n data: string | ArrayBuffer;\n}\n\n/**\n * Close command for a WebSocket\n */\nexport interface WebSocketClose {\n type: \"close\";\n connectionId: string;\n code?: number;\n reason?: string;\n}\n\nexport type WebSocketCommand = WebSocketOutgoingMessage | WebSocketClose;\n\n/**\n * Internal state for serve() handler\n */\nexport interface ServeState {\n fetchHandler: QuickJSHandle | null;\n websocketHandlers: {\n open?: QuickJSHandle;\n message?: QuickJSHandle;\n close?: QuickJSHandle;\n error?: QuickJSHandle;\n };\n pendingUpgrade: UpgradeRequest | null;\n activeConnections: Map<string, ServerWebSocketState>;\n}\n\nexport interface ServerWebSocketState {\n // Note: 'data' is accessed via pure-JS getter that reads from __upgradeRegistry__\n // This avoids marshalling complex objects (like Zod schemas) that exceed depth limits\n readyState: number;\n connectionId: string;\n wsHandle: QuickJSHandle | null;\n}\n\n/**\n * Handle returned from setupFetch\n */\nexport interface FetchHandle {\n /** State map containing all internal states */\n readonly stateMap: StateMap;\n\n /**\n * Dispatch an HTTP request to the serve() handler\n *\n * @returns Response from the QuickJS handler\n * @throws If no serve() handler is registered\n */\n dispatchRequest(request: Request): Promise<Response>;\n\n /**\n * Check if the last request resulted in an upgrade request\n * Must be called immediately after dispatchRequest()\n */\n getUpgradeRequest(): UpgradeRequest | null;\n\n /**\n * Dispatch WebSocket open event\n *\n * @param connectionId The connectionId from getUpgradeRequest() - used to look up data from QuickJS registry\n */\n dispatchWebSocketOpen(connectionId: string): void;\n\n /**\n * Dispatch WebSocket message event\n */\n dispatchWebSocketMessage(\n connectionId: string,\n message: string | ArrayBuffer\n ): void;\n\n /**\n * Dispatch WebSocket close event\n */\n dispatchWebSocketClose(\n connectionId: string,\n code: number,\n reason: string\n ): void;\n\n /**\n * Dispatch WebSocket error event\n */\n dispatchWebSocketError(connectionId: string, error: Error): void;\n\n /**\n * Register a callback for outgoing WebSocket messages/commands\n * Called when QuickJS code calls ws.send() or ws.close()\n */\n onWebSocketCommand(callback: (command: WebSocketCommand) => void): () => void;\n\n /**\n * Check if a serve() handler is registered\n */\n hasServeHandler(): boolean;\n\n /**\n * Check if there are active WebSocket connections\n */\n hasActiveConnections(): boolean;\n\n /**\n * Dispose all handles and cleanup\n */\n dispose(): void;\n}\n\n// Internal state types for the classes\nexport interface HeadersState {\n headers: Map<string, string[]>;\n}\n\n/**\n * What we get when unmarshalling a Request instance from QuickJS.\n * Contains identity markers + enumerable debug properties.\n */\nexport interface UnmarshalledRequest {\n __instanceId__: number;\n __className__: \"Request\";\n __isDefineClassInstance__: true;\n // Debug properties (may be present from unmarshal.ts)\n method?: string;\n url?: string;\n}\n\n/**\n * What we get when unmarshalling a Response instance from QuickJS.\n * Contains identity markers + enumerable debug properties.\n */\nexport interface UnmarshalledResponse {\n __instanceId__: number;\n __className__: \"Response\";\n __isDefineClassInstance__: true;\n // Debug properties (may be present from unmarshal.ts)\n status?: number;\n ok?: boolean;\n url?: string;\n}\n\nexport interface RequestState {\n method: string;\n url: string;\n headersState: HeadersState;\n body: Uint8Array | null;\n bodyUsed: boolean;\n cache: string;\n credentials: string;\n destination: string;\n integrity: string;\n keepalive: boolean;\n mode: string;\n redirect: string;\n referrer: string;\n referrerPolicy: string;\n signal: AbortSignalState | null;\n /** Native ReadableStream for streaming request bodies (upload streaming) */\n nativeBodyStream?: ReadableStream<Uint8Array>;\n /** Instance ID of QuickJS stream created by body getter (for consumption methods) */\n _uploadStreamInstanceId?: number;\n}\n\nexport interface ResponseState {\n status: number;\n statusText: string;\n headersState: HeadersState;\n body: Uint8Array | null;\n bodyUsed: boolean;\n url: string;\n redirected: boolean;\n type: string;\n ok: boolean;\n /** Original body type - used to convert back to string for native Response */\n bodyType?: \"string\" | \"binary\" | \"stream\" | null;\n /** Instance ID of ReadableStream when bodyType is \"stream\" */\n streamInstanceId?: number;\n}\n\nexport interface AbortControllerState {\n signalState: AbortSignalState;\n}\n\nexport interface AbortSignalState {\n aborted: boolean;\n reason: unknown;\n listeners: Set<() => void>;\n}\n\nexport interface FormDataFileValue {\n __formDataFile__: true;\n data: Uint8Array;\n filename: string;\n type: string;\n}\n\nexport interface FormDataEntry {\n name: string;\n value: string | FormDataFileValue;\n}\n\nexport interface FormDataState {\n entries: FormDataEntry[];\n}\n\n/**\n * Host-side queue for upload stream bridging.\n * Native ReadableStream reader pushes chunks here.\n * QuickJS ReadableStream's synchronous pull() reads from here.\n * This avoids async callbacks with QuickJS handles.\n */\nexport interface UploadStreamQueue {\n /** Buffered chunks waiting to be read by QuickJS */\n chunks: Uint8Array[];\n /** Whether the native stream has closed */\n closed: boolean;\n /** Error from native stream if any */\n error?: Error;\n /** Whether the native reader should pause (backpressure) */\n paused: boolean;\n /** Callback to resume native reader when queue is drained */\n resumeCallback?: () => void;\n /** Callback to cancel native reader when QuickJS stream is cancelled */\n cancelCallback?: () => void;\n}\n\n// ============================================\n// Type Guards\n// ============================================\n\n/**\n * Type guard for HeadersState.\n * Validates that the object has the correct structure with a Map.\n */\nexport function isHeadersState(obj: unknown): obj is HeadersState {\n return (\n obj !== null &&\n typeof obj === \"object\" &&\n \"headers\" in obj &&\n (obj as HeadersState).headers instanceof Map\n );\n}\n\n/**\n * Type guard for RequestState.\n * Validates key properties including their types.\n */\nexport function isRequestState(obj: unknown): obj is RequestState {\n if (obj === null || typeof obj !== \"object\") return false;\n const state = obj as Partial<RequestState>;\n return (\n typeof state.method === \"string\" &&\n typeof state.url === \"string\" &&\n isHeadersState(state.headersState)\n );\n}\n\n/**\n * Type guard for ResponseState.\n * Validates key properties including their types.\n */\nexport function isResponseState(obj: unknown): obj is ResponseState {\n if (obj === null || typeof obj !== \"object\") return false;\n const state = obj as Partial<ResponseState>;\n return (\n typeof state.status === \"number\" &&\n \"headersState\" in state &&\n isHeadersState(state.headersState) &&\n typeof state.bodyUsed === \"boolean\"\n );\n}\n\n/**\n * Type guard for AbortSignalState.\n * Validates the aborted flag and listeners set.\n */\nexport function isAbortSignalState(obj: unknown): obj is AbortSignalState {\n if (obj === null || typeof obj !== \"object\") return false;\n const state = obj as Partial<AbortSignalState>;\n return (\n typeof state.aborted === \"boolean\" &&\n \"listeners\" in state &&\n state.listeners instanceof Set\n );\n}\n\n/**\n * Type guard for unmarshalled Uint8Array-like objects.\n * These are objects with numeric keys and number values, created by unmarshal.ts.\n */\nexport function isUnmarshalledUint8Array(obj: unknown): obj is Record<string, number> {\n if (obj === null || typeof obj !== \"object\") return false;\n if (!(\"0\" in obj)) return false;\n // Verify at least the first few numeric keys have number values\n // (checking all keys would be expensive for large arrays)\n const record = obj as Record<string, unknown>;\n for (let i = 0; i < Math.min(3, Object.keys(record).length); i++) {\n if (typeof record[String(i)] !== \"number\") return false;\n }\n return true;\n}\n"
5
6
  ],
6
- "mappings": "",
7
- "debugId": "215C36070677FEE964756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6RO,SAAS,cAAc,CAAC,KAAmC;AAAA,EAChE,OACE,QAAQ,QACR,OAAO,QAAQ,YACf,aAAa,OACZ,IAAqB,mBAAmB;AAAA;AAQtC,SAAS,cAAc,CAAC,KAAmC;AAAA,EAChE,IAAI,QAAQ,QAAQ,OAAO,QAAQ;AAAA,IAAU,OAAO;AAAA,EACpD,MAAM,QAAQ;AAAA,EACd,OACE,OAAO,MAAM,WAAW,YACxB,OAAO,MAAM,QAAQ,YACrB,eAAe,MAAM,YAAY;AAAA;AAQ9B,SAAS,eAAe,CAAC,KAAoC;AAAA,EAClE,IAAI,QAAQ,QAAQ,OAAO,QAAQ;AAAA,IAAU,OAAO;AAAA,EACpD,MAAM,QAAQ;AAAA,EACd,OACE,OAAO,MAAM,WAAW,YACxB,kBAAkB,SAClB,eAAe,MAAM,YAAY,KACjC,OAAO,MAAM,aAAa;AAAA;AAQvB,SAAS,kBAAkB,CAAC,KAAuC;AAAA,EACxE,IAAI,QAAQ,QAAQ,OAAO,QAAQ;AAAA,IAAU,OAAO;AAAA,EACpD,MAAM,QAAQ;AAAA,EACd,OACE,OAAO,MAAM,YAAY,aACzB,eAAe,SACf,MAAM,qBAAqB;AAAA;AAQxB,SAAS,wBAAwB,CAAC,KAA6C;AAAA,EACpF,IAAI,QAAQ,QAAQ,OAAO,QAAQ;AAAA,IAAU,OAAO;AAAA,EACpD,IAAI,EAAE,OAAO;AAAA,IAAM,OAAO;AAAA,EAG1B,MAAM,SAAS;AAAA,EACf,SAAS,IAAI,EAAG,IAAI,KAAK,IAAI,GAAG,OAAO,KAAK,MAAM,EAAE,MAAM,GAAG,KAAK;AAAA,IAChE,IAAI,OAAO,OAAO,OAAO,CAAC,OAAO;AAAA,MAAU,OAAO;AAAA,EACpD;AAAA,EACA,OAAO;AAAA;",
8
+ "debugId": "03E8D870B0ED32C564756E2164756E21",
8
9
  "names": []
9
10
  }
@@ -1,6 +1,7 @@
1
1
  // @bun
2
2
  // packages/fetch/src/globals/fetch.ts
3
- import { unmarshal, marshal } from "@ricsam/quickjs-core";
3
+ import { unmarshal, marshal, coerceHeaders, coerceBody } from "@ricsam/quickjs-core";
4
+ import { isRequestState } from "../types.mjs";
4
5
  import { headersStateToNative } from "./headers.mjs";
5
6
  import { createResponseStateFromNative } from "./response.mjs";
6
7
  function createFetchFunction(context, onFetch) {
@@ -75,13 +76,17 @@ function createFetchFunction(context, onFetch) {
75
76
  let body = null;
76
77
  if (typeof input === "string") {
77
78
  url = input;
79
+ } else if (isRequestState(input)) {
80
+ url = input.url;
81
+ method = input.method;
82
+ headers = headersStateToNative(input.headersState);
83
+ if (input.body) {
84
+ body = input.body.buffer.slice(input.body.byteOffset, input.body.byteOffset + input.body.byteLength);
85
+ }
78
86
  } else if (input && typeof input === "object" && "url" in input) {
79
- const reqState = input;
80
- url = reqState.url;
81
- method = reqState.method;
82
- headers = headersStateToNative(reqState.headersState);
83
- if (reqState.body) {
84
- body = reqState.body;
87
+ url = String(input.url);
88
+ if ("method" in input && typeof input.method === "string") {
89
+ method = input.method;
85
90
  }
86
91
  }
87
92
  if (init) {
@@ -89,8 +94,9 @@ function createFetchFunction(context, onFetch) {
89
94
  method = init.method;
90
95
  }
91
96
  if (init.headers) {
92
- if (init.headers && typeof init.headers === "object" && "headers" in init.headers) {
93
- headers = headersStateToNative(init.headers);
97
+ const coerced = coerceHeaders.safeParse(init.headers);
98
+ if (coerced.success) {
99
+ headers = headersStateToNative(coerced.value);
94
100
  } else {
95
101
  headers = new Headers;
96
102
  for (const [key, value] of Object.entries(init.headers)) {
@@ -99,22 +105,13 @@ function createFetchFunction(context, onFetch) {
99
105
  }
100
106
  }
101
107
  if (init.body !== undefined) {
102
- if (typeof init.body === "string") {
108
+ const coercedBody = coerceBody(init.body);
109
+ if (coercedBody) {
110
+ body = coercedBody.buffer.slice(coercedBody.byteOffset, coercedBody.byteOffset + coercedBody.byteLength);
111
+ } else if (typeof init.body === "string") {
103
112
  body = init.body;
104
113
  } else if (init.body instanceof ArrayBuffer) {
105
114
  body = init.body;
106
- } else if (init.body instanceof Uint8Array) {
107
- body = init.body;
108
- } else if (init.body && typeof init.body === "object" && "parts" in init.body) {
109
- const parts = init.body.parts;
110
- const totalLength = parts.reduce((sum, p) => sum + p.length, 0);
111
- const combined = new Uint8Array(totalLength);
112
- let offset = 0;
113
- for (const part of parts) {
114
- combined.set(part, offset);
115
- offset += part.length;
116
- }
117
- body = combined;
118
115
  }
119
116
  }
120
117
  }
@@ -165,4 +162,4 @@ export {
165
162
  createFetchFunction
166
163
  };
167
164
 
168
- //# debugId=2A2E6AB453CC3F9B64756E2164756E21
165
+ //# debugId=960321ED419AEC7A64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/globals/fetch.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { unmarshal, marshal } from \"@ricsam/quickjs-core\";\nimport type { RequestState, HeadersState } from \"../types.mjs\";\nimport { headersStateToNative } from \"./headers.mjs\";\nimport { createResponseStateFromNative } from \"./response.mjs\";\n\n/**\n * Create the fetch function for QuickJS\n */\nexport function createFetchFunction(\n context: QuickJSContext,\n onFetch?: (request: Request) => Promise<Response>\n): QuickJSHandle {\n return context.newFunction(\"fetch\", (...argHandles) => {\n // Create promise first\n const deferred = context.newPromise();\n\n const inputHandle = argHandles[0];\n const initHandle = argHandles[1];\n\n // Extract signal BEFORE unmarshalling (keep as handle)\n let signalHandle: QuickJSHandle | null = null;\n // Check if initHandle exists and is a valid QuickJS handle (not JS undefined)\n if (initHandle !== undefined) {\n const initType = context.typeof(initHandle);\n if (initType === \"object\") {\n const tempSignal = context.getProp(initHandle, \"signal\");\n const signalType = context.typeof(tempSignal);\n if (signalType !== \"undefined\" && signalType !== \"null\") {\n signalHandle = tempSignal;\n } else {\n tempSignal.dispose();\n }\n }\n }\n\n // Check if signal is pre-aborted\n let isPreAborted = false;\n let abortReason: { message?: string } | undefined;\n if (signalHandle) {\n const abortedHandle = context.getProp(signalHandle, \"aborted\");\n isPreAborted = Boolean(context.dump(abortedHandle));\n abortedHandle.dispose();\n\n if (isPreAborted) {\n const reasonHandle = context.getProp(signalHandle, \"reason\");\n abortReason = context.dump(reasonHandle) as { message?: string } | undefined;\n reasonHandle.dispose();\n signalHandle.dispose();\n signalHandle = null;\n }\n }\n\n // If pre-aborted, reject immediately in a microtask\n if (isPreAborted) {\n Promise.resolve().then(() => {\n // Create DOMException and reject\n const errorMessage = abortReason?.message || \"signal is aborted without reason\";\n // Escape quotes in the message for safety\n const safeMessage = errorMessage.replace(/\"/g, '\\\\\"');\n const errorResult = context.evalCode(\n `new DOMException(\"${safeMessage}\", \"AbortError\")`\n );\n if (\"value\" in errorResult) {\n deferred.reject(errorResult.value);\n errorResult.value.dispose();\n } else {\n // If evalCode failed, create a plain error\n const fallbackError = marshal(context, { name: \"AbortError\", message: errorMessage });\n deferred.reject(fallbackError);\n fallbackError.dispose();\n errorResult.error.dispose();\n }\n context.runtime.executePendingJobs();\n });\n return deferred.handle;\n }\n\n // Create native AbortController\n const nativeController = new AbortController();\n\n // Wire QuickJS signal to native controller\n if (signalHandle) {\n // Create callback that aborts native controller when QuickJS signal aborts\n const abortCallback = context.newFunction(\"__fetchAbortCallback__\", () => {\n nativeController.abort();\n return context.undefined;\n });\n\n // Call addEventListener on the QuickJS signal\n const addEventListenerHandle = context.getProp(signalHandle, \"addEventListener\");\n const typeHandle = context.newString(\"abort\");\n\n context.callFunction(addEventListenerHandle, signalHandle, typeHandle, abortCallback);\n\n typeHandle.dispose();\n addEventListenerHandle.dispose();\n abortCallback.dispose();\n signalHandle.dispose();\n }\n\n // Unmarshal arguments\n const input = inputHandle ? unmarshal(context, inputHandle) : undefined;\n const init = initHandle ? unmarshal(context, initHandle) as {\n method?: string;\n headers?: object;\n body?: unknown;\n } | undefined : undefined;\n\n // Build the request\n let url = \"\";\n let method = \"GET\";\n let headers = new Headers();\n let body: BodyInit | null = null;\n\n if (typeof input === \"string\") {\n url = input;\n } else if (input && typeof input === \"object\" && \"url\" in input) {\n // Request-like object from QuickJS\n const reqState = input as RequestState;\n url = reqState.url;\n method = reqState.method;\n headers = headersStateToNative(reqState.headersState);\n if (reqState.body) {\n body = reqState.body as BodyInit;\n }\n }\n\n // Apply init overrides\n if (init) {\n if (init.method) {\n method = init.method;\n }\n if (init.headers) {\n if (\n init.headers &&\n typeof init.headers === \"object\" &&\n \"headers\" in init.headers\n ) {\n headers = headersStateToNative(init.headers as HeadersState);\n } else {\n headers = new Headers();\n for (const [key, value] of Object.entries(init.headers)) {\n headers.set(key, String(value));\n }\n }\n }\n if (init.body !== undefined) {\n if (typeof init.body === \"string\") {\n body = init.body;\n } else if (init.body instanceof ArrayBuffer) {\n body = init.body;\n } else if (init.body instanceof Uint8Array) {\n body = init.body as BodyInit;\n } else if (\n init.body &&\n typeof init.body === \"object\" &&\n \"parts\" in init.body\n ) {\n // Blob-like\n const parts = (init.body as { parts: Uint8Array[] }).parts;\n const totalLength = parts.reduce((sum, p) => sum + p.length, 0);\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const part of parts) {\n combined.set(part, offset);\n offset += part.length;\n }\n body = combined as BodyInit;\n }\n }\n }\n\n // Run the async fetch operation in a microtask to ensure proper promise settling\n Promise.resolve().then(async () => {\n try {\n if (!onFetch) {\n throw new Error(\n \"fetch is not configured - no onFetch handler provided to setupFetch\"\n );\n }\n\n // Create native Request with signal\n const nativeRequest = new Request(url, {\n method,\n headers,\n body: method !== \"GET\" && method !== \"HEAD\" ? body : undefined,\n signal: nativeController.signal,\n });\n\n // Call the host fetch handler\n const nativeResponse = await onFetch(nativeRequest);\n\n // Convert to ResponseState for QuickJS\n const responseState = await createResponseStateFromNative(nativeResponse);\n const resultHandle = marshal(context, responseState);\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n } catch (error) {\n // Handle abort errors specially\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const safeMessage = error.message.replace(/\"/g, '\\\\\"');\n const errorResult = context.evalCode(\n `new DOMException(\"${safeMessage}\", \"AbortError\")`\n );\n if (\"value\" in errorResult) {\n deferred.reject(errorResult.value);\n errorResult.value.dispose();\n } else {\n const fallbackError = marshal(context, { name: \"AbortError\", message: error.message });\n deferred.reject(fallbackError);\n fallbackError.dispose();\n errorResult.error.dispose();\n }\n } else {\n const errorHandle = marshal(context, {\n name: error instanceof Error ? error.name : \"Error\",\n message: error instanceof Error ? error.message : String(error),\n });\n deferred.reject(errorHandle);\n errorHandle.dispose();\n }\n }\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n });\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { unmarshal, marshal, coerceHeaders, coerceBody } from \"@ricsam/quickjs-core\";\nimport type { RequestState, HeadersState } from \"../types.mjs\";\nimport { isRequestState } from \"../types.mjs\";\nimport { headersStateToNative } from \"./headers.mjs\";\nimport { createResponseStateFromNative } from \"./response.mjs\";\n\n/**\n * Create the fetch function for QuickJS\n */\nexport function createFetchFunction(\n context: QuickJSContext,\n onFetch?: (request: Request) => Promise<Response>\n): QuickJSHandle {\n return context.newFunction(\"fetch\", (...argHandles) => {\n // Create promise first\n const deferred = context.newPromise();\n\n const inputHandle = argHandles[0];\n const initHandle = argHandles[1];\n\n // Extract signal BEFORE unmarshalling (keep as handle)\n let signalHandle: QuickJSHandle | null = null;\n // Check if initHandle exists and is a valid QuickJS handle (not JS undefined)\n if (initHandle !== undefined) {\n const initType = context.typeof(initHandle);\n if (initType === \"object\") {\n const tempSignal = context.getProp(initHandle, \"signal\");\n const signalType = context.typeof(tempSignal);\n if (signalType !== \"undefined\" && signalType !== \"null\") {\n signalHandle = tempSignal;\n } else {\n tempSignal.dispose();\n }\n }\n }\n\n // Check if signal is pre-aborted\n let isPreAborted = false;\n let abortReason: { message?: string } | undefined;\n if (signalHandle) {\n const abortedHandle = context.getProp(signalHandle, \"aborted\");\n isPreAborted = Boolean(context.dump(abortedHandle));\n abortedHandle.dispose();\n\n if (isPreAborted) {\n const reasonHandle = context.getProp(signalHandle, \"reason\");\n abortReason = context.dump(reasonHandle) as { message?: string } | undefined;\n reasonHandle.dispose();\n signalHandle.dispose();\n signalHandle = null;\n }\n }\n\n // If pre-aborted, reject immediately in a microtask\n if (isPreAborted) {\n Promise.resolve().then(() => {\n // Create DOMException and reject\n const errorMessage = abortReason?.message || \"signal is aborted without reason\";\n // Escape quotes in the message for safety\n const safeMessage = errorMessage.replace(/\"/g, '\\\\\"');\n const errorResult = context.evalCode(\n `new DOMException(\"${safeMessage}\", \"AbortError\")`\n );\n if (\"value\" in errorResult) {\n deferred.reject(errorResult.value);\n errorResult.value.dispose();\n } else {\n // If evalCode failed, create a plain error\n const fallbackError = marshal(context, { name: \"AbortError\", message: errorMessage });\n deferred.reject(fallbackError);\n fallbackError.dispose();\n errorResult.error.dispose();\n }\n context.runtime.executePendingJobs();\n });\n return deferred.handle;\n }\n\n // Create native AbortController\n const nativeController = new AbortController();\n\n // Wire QuickJS signal to native controller\n if (signalHandle) {\n // Create callback that aborts native controller when QuickJS signal aborts\n const abortCallback = context.newFunction(\"__fetchAbortCallback__\", () => {\n nativeController.abort();\n return context.undefined;\n });\n\n // Call addEventListener on the QuickJS signal\n const addEventListenerHandle = context.getProp(signalHandle, \"addEventListener\");\n const typeHandle = context.newString(\"abort\");\n\n context.callFunction(addEventListenerHandle, signalHandle, typeHandle, abortCallback);\n\n typeHandle.dispose();\n addEventListenerHandle.dispose();\n abortCallback.dispose();\n signalHandle.dispose();\n }\n\n // Unmarshal arguments\n const input = inputHandle ? unmarshal(context, inputHandle) : undefined;\n const init = initHandle ? unmarshal(context, initHandle) as {\n method?: string;\n headers?: object;\n body?: unknown;\n } | undefined : undefined;\n\n // Build the request\n let url = \"\";\n let method = \"GET\";\n let headers = new Headers();\n let body: BodyInit | null = null;\n\n if (typeof input === \"string\") {\n url = input;\n } else if (isRequestState(input)) {\n // Full RequestState object - extract properties with type safety\n url = input.url;\n method = input.method;\n headers = headersStateToNative(input.headersState);\n if (input.body) {\n // Convert Uint8Array to ArrayBuffer for BodyInit compatibility\n body = input.body.buffer.slice(\n input.body.byteOffset,\n input.body.byteOffset + input.body.byteLength\n ) as ArrayBuffer;\n }\n } else if (input && typeof input === \"object\" && \"url\" in input) {\n // Partial object with url property - extract what we can\n url = String((input as Record<string, unknown>).url);\n if (\"method\" in input && typeof (input as Record<string, unknown>).method === \"string\") {\n method = (input as Record<string, unknown>).method as string;\n }\n }\n\n // Apply init overrides\n if (init) {\n if (init.method) {\n method = init.method;\n }\n if (init.headers) {\n // Use coercion system for type-safe headers handling\n const coerced = coerceHeaders.safeParse(init.headers);\n if (coerced.success) {\n headers = headersStateToNative(coerced.value);\n } else {\n // Fallback for plain objects\n headers = new Headers();\n for (const [key, value] of Object.entries(init.headers)) {\n headers.set(key, String(value));\n }\n }\n }\n if (init.body !== undefined) {\n // Use coerceBody for type-safe body handling\n const coercedBody = coerceBody(init.body);\n if (coercedBody) {\n // Convert Uint8Array to ArrayBuffer for BodyInit compatibility\n body = coercedBody.buffer.slice(\n coercedBody.byteOffset,\n coercedBody.byteOffset + coercedBody.byteLength\n ) as ArrayBuffer;\n } else if (typeof init.body === \"string\") {\n body = init.body;\n } else if (init.body instanceof ArrayBuffer) {\n body = init.body;\n }\n }\n }\n\n // Run the async fetch operation in a microtask to ensure proper promise settling\n Promise.resolve().then(async () => {\n try {\n if (!onFetch) {\n throw new Error(\n \"fetch is not configured - no onFetch handler provided to setupFetch\"\n );\n }\n\n // Create native Request with signal\n const nativeRequest = new Request(url, {\n method,\n headers,\n body: method !== \"GET\" && method !== \"HEAD\" ? body : undefined,\n signal: nativeController.signal,\n });\n\n // Call the host fetch handler\n const nativeResponse = await onFetch(nativeRequest);\n\n // Convert to ResponseState for QuickJS\n const responseState = await createResponseStateFromNative(nativeResponse);\n const resultHandle = marshal(context, responseState);\n deferred.resolve(resultHandle);\n resultHandle.dispose();\n } catch (error) {\n // Handle abort errors specially\n if (error instanceof DOMException && error.name === \"AbortError\") {\n const safeMessage = error.message.replace(/\"/g, '\\\\\"');\n const errorResult = context.evalCode(\n `new DOMException(\"${safeMessage}\", \"AbortError\")`\n );\n if (\"value\" in errorResult) {\n deferred.reject(errorResult.value);\n errorResult.value.dispose();\n } else {\n const fallbackError = marshal(context, { name: \"AbortError\", message: error.message });\n deferred.reject(fallbackError);\n fallbackError.dispose();\n errorResult.error.dispose();\n }\n } else {\n const errorHandle = marshal(context, {\n name: error instanceof Error ? error.name : \"Error\",\n message: error instanceof Error ? error.message : String(error),\n });\n deferred.reject(errorHandle);\n errorHandle.dispose();\n }\n }\n context.runtime.executePendingJobs();\n });\n\n return deferred.handle;\n });\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "2A2E6AB453CC3F9B64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "960321ED419AEC7A64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,41 +1,16 @@
1
1
  // @bun
2
2
  // packages/fetch/src/globals/headers.ts
3
- import { defineClass } from "@ricsam/quickjs-core";
3
+ import { defineClass, coerceHeaders, getInstanceStateById } from "@ricsam/quickjs-core";
4
4
  function createHeadersClass(context, stateMap) {
5
5
  return defineClass(context, stateMap, {
6
6
  name: "Headers",
7
7
  construct: (args) => {
8
8
  const init = args[0];
9
- const headers = new Map;
10
- if (init) {
11
- if (Array.isArray(init)) {
12
- for (const pair of init) {
13
- if (Array.isArray(pair) && pair.length >= 2) {
14
- const key = String(pair[0]).toLowerCase();
15
- const value = String(pair[1]);
16
- const existing = headers.get(key) || [];
17
- existing.push(value);
18
- headers.set(key, existing);
19
- }
20
- }
21
- } else if (typeof init === "object" && init !== null) {
22
- if ("headers" in init && init.headers instanceof Map) {
23
- for (const [key, values] of init.headers) {
24
- headers.set(key, [...values]);
25
- }
26
- } else {
27
- for (const [key, value] of Object.entries(init)) {
28
- const normalizedKey = key.toLowerCase();
29
- if (Array.isArray(value)) {
30
- headers.set(normalizedKey, value.map(String));
31
- } else {
32
- headers.set(normalizedKey, [String(value)]);
33
- }
34
- }
35
- }
36
- }
9
+ const coerced = coerceHeaders.safeParse(init);
10
+ if (coerced.success) {
11
+ return coerced.value;
37
12
  }
38
- return { headers };
13
+ return { headers: new Map };
39
14
  },
40
15
  methods: {
41
16
  append(name, value) {
@@ -84,6 +59,13 @@ function createHeadersClass(context, stateMap) {
84
59
  },
85
60
  getSetCookie() {
86
61
  return this.headers.get("set-cookie") || [];
62
+ },
63
+ __linkToParent__(parentInstanceId) {
64
+ const id = typeof parentInstanceId === "number" ? parentInstanceId : 0;
65
+ const parentState = getInstanceStateById(id);
66
+ if (parentState?.headersState) {
67
+ this.headers = parentState.headersState.headers;
68
+ }
87
69
  }
88
70
  }
89
71
  });
@@ -106,60 +88,10 @@ function headersStateToNative(state) {
106
88
  }
107
89
  return headers;
108
90
  }
109
- function createHeadersLike(state) {
110
- return {
111
- headers: state.headers,
112
- append(name, value) {
113
- const key = name.toLowerCase();
114
- const existing = state.headers.get(key) || [];
115
- existing.push(value);
116
- state.headers.set(key, existing);
117
- },
118
- delete(name) {
119
- state.headers.delete(name.toLowerCase());
120
- },
121
- get(name) {
122
- const values = state.headers.get(name.toLowerCase());
123
- return values ? values.join(", ") : null;
124
- },
125
- has(name) {
126
- return state.headers.has(name.toLowerCase());
127
- },
128
- set(name, value) {
129
- state.headers.set(name.toLowerCase(), [value]);
130
- },
131
- entries() {
132
- const result = [];
133
- for (const [key, values] of state.headers) {
134
- result.push([key, values.join(", ")]);
135
- }
136
- return result;
137
- },
138
- keys() {
139
- return Array.from(state.headers.keys());
140
- },
141
- values() {
142
- const result = [];
143
- for (const values of state.headers.values()) {
144
- result.push(values.join(", "));
145
- }
146
- return result;
147
- },
148
- forEach(callback) {
149
- for (const [key, values] of state.headers) {
150
- callback(values.join(", "), key);
151
- }
152
- },
153
- getSetCookie() {
154
- return state.headers.get("set-cookie") || [];
155
- }
156
- };
157
- }
158
91
  export {
159
92
  headersStateToNative,
160
93
  createHeadersStateFromNative,
161
- createHeadersLike,
162
94
  createHeadersClass
163
95
  };
164
96
 
165
- //# debugId=55519B963E4BBD8E64756E2164756E21
97
+ //# debugId=314BF006BE58B50F64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/globals/headers.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 { HeadersState } from \"../types.mjs\";\n\n/**\n * Create the Headers class for QuickJS\n */\nexport function createHeadersClass(\n context: QuickJSContext,\n stateMap: StateMap\n): QuickJSHandle {\n return defineClass<HeadersState>(context, stateMap, {\n name: \"Headers\",\n construct: (args) => {\n const init = args[0];\n const headers = new Map<string, string[]>();\n\n if (init) {\n if (Array.isArray(init)) {\n // Array of [key, value] pairs\n for (const pair of init) {\n if (Array.isArray(pair) && pair.length >= 2) {\n const key = String(pair[0]).toLowerCase();\n const value = String(pair[1]);\n const existing = headers.get(key) || [];\n existing.push(value);\n headers.set(key, existing);\n }\n }\n } else if (typeof init === \"object\" && init !== null) {\n // Check if it's another Headers-like object with entries method\n if (\"headers\" in init && init.headers instanceof Map) {\n // HeadersState\n for (const [key, values] of (init as HeadersState).headers) {\n headers.set(key, [...values]);\n }\n } else {\n // Plain object\n for (const [key, value] of Object.entries(init)) {\n const normalizedKey = key.toLowerCase();\n if (Array.isArray(value)) {\n headers.set(normalizedKey, value.map(String));\n } else {\n headers.set(normalizedKey, [String(value)]);\n }\n }\n }\n }\n }\n\n return { headers };\n },\n methods: {\n append(this: HeadersState, name: unknown, value: unknown) {\n const key = String(name).toLowerCase();\n const existing = this.headers.get(key) || [];\n existing.push(String(value));\n this.headers.set(key, existing);\n },\n delete(this: HeadersState, name: unknown) {\n this.headers.delete(String(name).toLowerCase());\n },\n get(this: HeadersState, name: unknown): string | null {\n const values = this.headers.get(String(name).toLowerCase());\n return values ? values.join(\", \") : null;\n },\n has(this: HeadersState, name: unknown): boolean {\n return this.headers.has(String(name).toLowerCase());\n },\n set(this: HeadersState, name: unknown, value: unknown) {\n this.headers.set(String(name).toLowerCase(), [String(value)]);\n },\n entries(this: HeadersState): Array<[string, string]> {\n const result: Array<[string, string]> = [];\n for (const [key, values] of this.headers) {\n result.push([key, values.join(\", \")]);\n }\n return result;\n },\n keys(this: HeadersState): string[] {\n return Array.from(this.headers.keys());\n },\n values(this: HeadersState): string[] {\n const result: string[] = [];\n for (const values of this.headers.values()) {\n result.push(values.join(\", \"));\n }\n return result;\n },\n forEach(this: HeadersState, callback: unknown) {\n if (typeof callback !== \"function\") {\n throw new TypeError(\"callback must be a function\");\n }\n for (const [key, values] of this.headers) {\n (callback as (value: string, key: string, parent: HeadersState) => void)(\n values.join(\", \"),\n key,\n this\n );\n }\n },\n getSetCookie(this: HeadersState): string[] {\n return this.headers.get(\"set-cookie\") || [];\n },\n },\n });\n}\n\n/**\n * Create a HeadersState from a native Headers object\n */\nexport function createHeadersStateFromNative(headers: Headers): HeadersState {\n const map = new Map<string, string[]>();\n headers.forEach((value, key) => {\n const existing = map.get(key.toLowerCase()) || [];\n existing.push(value);\n map.set(key.toLowerCase(), existing);\n });\n return { headers: map };\n}\n\n/**\n * Convert HeadersState to native Headers\n */\nexport function headersStateToNative(state: HeadersState): Headers {\n const headers = new Headers();\n for (const [key, values] of state.headers) {\n for (const value of values) {\n headers.append(key, value);\n }\n }\n return headers;\n}\n\n/**\n * Interface for a Headers-like object that can be returned from getters\n */\nexport interface HeadersLike {\n headers: Map<string, string[]>;\n append(name: string, value: string): void;\n delete(name: string): void;\n get(name: string): string | null;\n has(name: string): boolean;\n set(name: string, value: string): void;\n entries(): Array<[string, string]>;\n keys(): string[];\n values(): string[];\n forEach(callback: (value: string, key: string) => void): void;\n getSetCookie(): string[];\n}\n\n/**\n * Create a Headers-like object from HeadersState that has all the Headers methods\n * This is used for getters that need to return an object with Headers API\n */\nexport function createHeadersLike(state: HeadersState): HeadersLike {\n return {\n headers: state.headers,\n append(name: string, value: string) {\n const key = name.toLowerCase();\n const existing = state.headers.get(key) || [];\n existing.push(value);\n state.headers.set(key, existing);\n },\n delete(name: string) {\n state.headers.delete(name.toLowerCase());\n },\n get(name: string): string | null {\n const values = state.headers.get(name.toLowerCase());\n return values ? values.join(\", \") : null;\n },\n has(name: string): boolean {\n return state.headers.has(name.toLowerCase());\n },\n set(name: string, value: string) {\n state.headers.set(name.toLowerCase(), [value]);\n },\n entries(): Array<[string, string]> {\n const result: Array<[string, string]> = [];\n for (const [key, values] of state.headers) {\n result.push([key, values.join(\", \")]);\n }\n return result;\n },\n keys(): string[] {\n return Array.from(state.headers.keys());\n },\n values(): string[] {\n const result: string[] = [];\n for (const values of state.headers.values()) {\n result.push(values.join(\", \"));\n }\n return result;\n },\n forEach(callback: (value: string, key: string) => void) {\n for (const [key, values] of state.headers) {\n callback(values.join(\", \"), key);\n }\n },\n getSetCookie(): string[] {\n return state.headers.get(\"set-cookie\") || [];\n },\n };\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap } from \"@ricsam/quickjs-core\";\nimport { defineClass, coerceHeaders, getInstanceStateById } from \"@ricsam/quickjs-core\";\nimport type { HeadersState } from \"../types.mjs\";\n\n/**\n * Create the Headers class for QuickJS\n */\nexport function createHeadersClass(\n context: QuickJSContext,\n stateMap: StateMap\n): QuickJSHandle {\n return defineClass<HeadersState>(context, stateMap, {\n name: \"Headers\",\n construct: (args) => {\n const init = args[0];\n // Use coercion to handle all input types consistently\n const coerced = coerceHeaders.safeParse(init);\n if (coerced.success) {\n return coerced.value;\n }\n // Fallback to empty headers if coercion fails\n return { headers: new Map<string, string[]>() };\n },\n methods: {\n append(this: HeadersState, name: unknown, value: unknown) {\n const key = String(name).toLowerCase();\n const existing = this.headers.get(key) || [];\n existing.push(String(value));\n this.headers.set(key, existing);\n },\n delete(this: HeadersState, name: unknown) {\n this.headers.delete(String(name).toLowerCase());\n },\n get(this: HeadersState, name: unknown): string | null {\n const values = this.headers.get(String(name).toLowerCase());\n return values ? values.join(\", \") : null;\n },\n has(this: HeadersState, name: unknown): boolean {\n return this.headers.has(String(name).toLowerCase());\n },\n set(this: HeadersState, name: unknown, value: unknown) {\n this.headers.set(String(name).toLowerCase(), [String(value)]);\n },\n entries(this: HeadersState): Array<[string, string]> {\n const result: Array<[string, string]> = [];\n for (const [key, values] of this.headers) {\n result.push([key, values.join(\", \")]);\n }\n return result;\n },\n keys(this: HeadersState): string[] {\n return Array.from(this.headers.keys());\n },\n values(this: HeadersState): string[] {\n const result: string[] = [];\n for (const values of this.headers.values()) {\n result.push(values.join(\", \"));\n }\n return result;\n },\n forEach(this: HeadersState, callback: unknown) {\n if (typeof callback !== \"function\") {\n throw new TypeError(\"callback must be a function\");\n }\n for (const [key, values] of this.headers) {\n (callback as (value: string, key: string, parent: HeadersState) => void)(\n values.join(\", \"),\n key,\n this\n );\n }\n },\n getSetCookie(this: HeadersState): string[] {\n return this.headers.get(\"set-cookie\") || [];\n },\n /**\n * Private method to link this Headers instance to a parent Request/Response.\n * Called from the cached headers getter to share state.\n */\n __linkToParent__(this: HeadersState, parentInstanceId: unknown) {\n const id = typeof parentInstanceId === \"number\" ? parentInstanceId : 0;\n const parentState = getInstanceStateById<{ headersState: HeadersState }>(id);\n if (parentState?.headersState) {\n this.headers = parentState.headersState.headers;\n }\n },\n },\n });\n}\n\n/**\n * Create a HeadersState from a native Headers object\n */\nexport function createHeadersStateFromNative(headers: Headers): HeadersState {\n const map = new Map<string, string[]>();\n headers.forEach((value, key) => {\n const existing = map.get(key.toLowerCase()) || [];\n existing.push(value);\n map.set(key.toLowerCase(), existing);\n });\n return { headers: map };\n}\n\n/**\n * Convert HeadersState to native Headers\n */\nexport function headersStateToNative(state: HeadersState): Headers {\n const headers = new Headers();\n for (const [key, values] of state.headers) {\n for (const value of values) {\n headers.append(key, value);\n }\n }\n return headers;\n}\n\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "55519B963E4BBD8E64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "314BF006BE58B50F64756E2164756E21",
9
9
  "names": []
10
10
  }