shokupan 0.6.1 → 0.9.0

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.
Files changed (81) hide show
  1. package/README.md +55 -2
  2. package/dist/{openapi-analyzer-Bei1sVWp.cjs → analyzer-Bei1sVWp.cjs} +1 -1
  3. package/dist/analyzer-Bei1sVWp.cjs.map +1 -0
  4. package/dist/{openapi-analyzer-Ce_7JxZh.js → analyzer-Ce_7JxZh.js} +1 -1
  5. package/dist/analyzer-Ce_7JxZh.js.map +1 -0
  6. package/dist/cli.cjs +2 -2
  7. package/dist/cli.cjs.map +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/cli.js.map +1 -1
  10. package/dist/context.d.ts +58 -23
  11. package/dist/{server-adapter-DFhwlK8e.cjs → http-server-BEMPIs33.cjs} +4 -2
  12. package/dist/http-server-BEMPIs33.cjs.map +1 -0
  13. package/dist/{server-adapter-0xH174zz.js → http-server-CCeagTyU.js} +4 -2
  14. package/dist/http-server-CCeagTyU.js.map +1 -0
  15. package/dist/index.cjs +1940 -917
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.ts +18 -17
  18. package/dist/index.js +1948 -925
  19. package/dist/index.js.map +1 -1
  20. package/dist/middleware.d.ts +1 -1
  21. package/dist/plugins/{auth.d.ts → application/auth.d.ts} +72 -3
  22. package/dist/plugins/application/cluster.d.ts +33 -0
  23. package/dist/plugins/{failed-request-recorder.d.ts → application/dashboard/failed-request-recorder.d.ts} +1 -1
  24. package/dist/plugins/application/dashboard/metrics-collector.d.ts +12 -0
  25. package/dist/plugins/application/dashboard/plugin.d.ts +42 -0
  26. package/dist/plugins/application/dashboard/static/charts.js +328 -0
  27. package/dist/plugins/application/dashboard/static/failures.js +85 -0
  28. package/dist/plugins/application/dashboard/static/graph.mjs +523 -0
  29. package/dist/plugins/application/dashboard/static/poll.js +146 -0
  30. package/dist/plugins/application/dashboard/static/reactflow.css +18 -0
  31. package/dist/plugins/application/dashboard/static/registry.css +131 -0
  32. package/dist/plugins/application/dashboard/static/registry.js +269 -0
  33. package/dist/plugins/application/dashboard/static/requests.js +118 -0
  34. package/dist/plugins/application/dashboard/static/scrollbar.css +24 -0
  35. package/dist/plugins/application/dashboard/static/styles.css +175 -0
  36. package/dist/plugins/application/dashboard/static/tables.js +92 -0
  37. package/dist/plugins/application/dashboard/static/tabs.js +113 -0
  38. package/dist/plugins/application/dashboard/static/tabulator.css +66 -0
  39. package/dist/plugins/application/dashboard/template.eta +246 -0
  40. package/dist/plugins/{server-adapter.d.ts → application/http-server.d.ts} +1 -1
  41. package/dist/plugins/{idempotency → application/idempotency}/plugin.d.ts +7 -1
  42. package/dist/plugins/{openapi.d.ts → application/openapi/openapi.d.ts} +2 -2
  43. package/dist/plugins/application/scalar.d.ts +36 -0
  44. package/dist/plugins/application/socket-io.d.ts +14 -0
  45. package/dist/plugins/middleware/compression.d.ts +17 -0
  46. package/dist/plugins/middleware/cors.d.ts +34 -0
  47. package/dist/plugins/{express.d.ts → middleware/express.d.ts} +1 -1
  48. package/dist/plugins/{openapi-validator.d.ts → middleware/openapi-validator.d.ts} +2 -2
  49. package/dist/plugins/middleware/proxy.d.ts +37 -0
  50. package/dist/plugins/middleware/rate-limit.d.ts +58 -0
  51. package/dist/plugins/{security-headers.d.ts → middleware/security-headers.d.ts} +51 -1
  52. package/dist/plugins/{serve-static.d.ts → middleware/serve-static.d.ts} +1 -1
  53. package/dist/plugins/{session.d.ts → middleware/session.d.ts} +89 -3
  54. package/dist/plugins/{validation.d.ts → middleware/validation.d.ts} +6 -1
  55. package/dist/router.d.ts +17 -5
  56. package/dist/shokupan.d.ts +31 -5
  57. package/dist/util/async-hooks.d.ts +8 -2
  58. package/dist/util/datastore.d.ts +4 -3
  59. package/dist/{decorators.d.ts → util/decorators.d.ts} +6 -1
  60. package/dist/util/http-error.d.ts +38 -0
  61. package/dist/util/http-status.d.ts +32 -0
  62. package/dist/util/instrumentation.d.ts +1 -1
  63. package/dist/{request.d.ts → util/request.d.ts} +1 -1
  64. package/dist/util/symbol.d.ts +34 -0
  65. package/dist/{router → util}/trie.d.ts +1 -1
  66. package/dist/{types.d.ts → util/types.d.ts} +38 -2
  67. package/package.json +9 -6
  68. package/dist/openapi-analyzer-Bei1sVWp.cjs.map +0 -1
  69. package/dist/openapi-analyzer-Ce_7JxZh.js.map +0 -1
  70. package/dist/plugins/compression.d.ts +0 -5
  71. package/dist/plugins/cors.d.ts +0 -11
  72. package/dist/plugins/debugview/plugin.d.ts +0 -29
  73. package/dist/plugins/proxy.d.ts +0 -11
  74. package/dist/plugins/rate-limit.d.ts +0 -15
  75. package/dist/plugins/scalar.d.ts +0 -15
  76. package/dist/server-adapter-0xH174zz.js.map +0 -1
  77. package/dist/server-adapter-DFhwlK8e.cjs.map +0 -1
  78. package/dist/symbol.d.ts +0 -15
  79. /package/dist/{analysis/openapi-analyzer.d.ts → plugins/application/openapi/analyzer.d.ts} +0 -0
  80. /package/dist/{di.d.ts → util/di.d.ts} +0 -0
  81. /package/dist/{response.d.ts → util/response.d.ts} +0 -0
package/dist/context.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { BodyInit, Server } from 'bun';
2
- import { ShokupanRequest } from './request';
3
- import { ShokupanResponse } from './response';
1
+ import { BodyInit, Server, ServerWebSocket } from 'bun';
2
+ import { Socket, Server as SocketServer } from 'socket.io';
4
3
  import { Shokupan } from './shokupan';
5
- import { CookieOptions, JSXRenderer } from './types';
6
- type HeadersInit = Headers | Record<string, string> | [string, string][];
4
+ import { ShokupanRequest } from './util/request';
5
+ import { ShokupanResponse } from './util/response';
6
+ import { $bodyParsed, $bodyParseError, $bodyType, $cachedBody, $cachedHost, $cachedHostname, $cachedOrigin, $cachedProtocol, $cachedQuery, $debug, $finalResponse, $io, $rawBody, $requestId, $routeMatched, $socket, $url, $ws } from './util/symbol';
7
+ import { CookieOptions, HeadersInit, JSXRenderer } from './util/types';
7
8
  export interface HandlerStackItem {
8
9
  name: string;
9
10
  file: string;
@@ -88,19 +89,30 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
88
89
  state: State;
89
90
  handlerStack: HandlerStackItem[];
90
91
  readonly response: ShokupanResponse;
91
- _debug?: DebugCollector;
92
- _finalResponse?: Response;
93
- _rawBody?: string | ArrayBuffer | Uint8Array;
94
- private _url?;
95
- private _cachedBody?;
96
- private _bodyType?;
97
- private _bodyParsed;
98
- _bodyParseError?: Error;
99
- private _cachedHostname?;
100
- private _cachedProtocol?;
101
- private _cachedHost?;
102
- private _cachedOrigin?;
103
- private _cachedQuery?;
92
+ [$debug]?: DebugCollector;
93
+ [$finalResponse]?: Response;
94
+ [$rawBody]?: string | ArrayBuffer | Uint8Array;
95
+ private [$url]?;
96
+ private [$cachedBody]?;
97
+ private [$bodyType]?;
98
+ private [$bodyParsed];
99
+ private [$bodyParseError]?;
100
+ [$routeMatched]: boolean;
101
+ private [$cachedHostname]?;
102
+ private [$cachedProtocol]?;
103
+ private [$cachedHost]?;
104
+ private [$cachedOrigin]?;
105
+ private [$cachedQuery]?;
106
+ private [$ws]?;
107
+ private [$socket]?;
108
+ private [$io]?;
109
+ /**
110
+ * JSX Rendering Function
111
+ */
112
+ private renderer?;
113
+ setRenderer(renderer: JSXRenderer): void;
114
+ private [$requestId];
115
+ get requestId(): string;
104
116
  constructor(request: ShokupanRequest<any>, server?: Server, state?: State, app?: Shokupan, signal?: AbortSignal, // Optional as it might not be provided in tests or simple creates
105
117
  enableMiddlewareTracking?: boolean);
106
118
  get url(): URL;
@@ -157,12 +169,34 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
157
169
  * Base response object
158
170
  */
159
171
  get res(): ShokupanResponse;
172
+ /**
173
+ * Raw WebSocket connection
174
+ */
175
+ get ws(): ServerWebSocket<undefined>;
176
+ /**
177
+ * Socket.io socket
178
+ */
179
+ get socket(): Socket<import('socket.io').DefaultEventsMap, import('socket.io').DefaultEventsMap, import('socket.io').DefaultEventsMap, any>;
180
+ /**
181
+ * Socket.io server
182
+ */
183
+ get io(): SocketServer<import('socket.io').DefaultEventsMap, import('socket.io').DefaultEventsMap, import('socket.io').DefaultEventsMap, any>;
160
184
  /**
161
185
  * Helper to set a header on the response
162
186
  * @param key Header key
163
187
  * @param value Header value
164
188
  */
165
189
  set(key: string, value: string): this;
190
+ isUpgraded: boolean;
191
+ /**
192
+ * Upgrades the request to a WebSocket connection.
193
+ * @param options Upgrade options
194
+ * @returns true if upgraded, false otherwise
195
+ */
196
+ upgrade(options?: {
197
+ data?: any;
198
+ headers?: HeadersInit;
199
+ }): boolean;
166
200
  /**
167
201
  * Set a cookie
168
202
  * @param name Cookie name
@@ -195,6 +229,12 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
195
229
  * @returns Response
196
230
  */
197
231
  send(body?: BodyInit, options?: ResponseInit): Response;
232
+ /**
233
+ * Emit an event to the client (WebSocket only)
234
+ * @param event Event name
235
+ * @param data Event data (Must be JSON serializable)
236
+ */
237
+ emit(event: string, data?: any): void;
198
238
  /**
199
239
  * Respond with a JSON object
200
240
  */
@@ -220,10 +260,6 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
220
260
  * Respond with a file
221
261
  */
222
262
  file(path: string, fileOptions?: BlobPropertyBag, responseOptions?: ResponseInit): Promise<Response>;
223
- /**
224
- * JSX Rendering Function
225
- */
226
- renderer?: JSXRenderer;
227
263
  /**
228
264
  * Render a JSX element
229
265
  * @param element JSX Element
@@ -232,4 +268,3 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
232
268
  */
233
269
  jsx(element: any, args?: Parameters<JSXRenderer>[1], status?: number, headers?: HeadersInit): Promise<Response>;
234
270
  }
235
- export {};
@@ -70,7 +70,9 @@ function createHttpServer() {
70
70
  requestIP: (req) => null,
71
71
  publish: () => 0,
72
72
  subscriberCount: () => 0,
73
- url: new URL(`http://${options.hostname}:${options.port}`)
73
+ url: new URL(`http://${options.hostname}:${options.port}`),
74
+ // Expose the raw Node.js server for generic socket/websocket support (e.g. Socket.IO)
75
+ nodeServer: server
74
76
  };
75
77
  return new Promise((resolve) => {
76
78
  server.listen(options.port, options.hostname, () => {
@@ -80,4 +82,4 @@ function createHttpServer() {
80
82
  };
81
83
  }
82
84
  exports.createHttpServer = createHttpServer;
83
- //# sourceMappingURL=server-adapter-DFhwlK8e.cjs.map
85
+ //# sourceMappingURL=http-server-BEMPIs33.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server-BEMPIs33.cjs","sources":["../src/plugins/application/http-server.ts"],"sourcesContent":["import type { Server } from \"bun\";\nimport * as http from \"node:http\";\nimport * as https from \"node:https\";\nimport type { ServerFactory } from \"../../util/types\";\n\n/**\n * Creates a server factory that uses the standard Node.js `http` module.\n * @returns A ServerFactory compatible with Shokupan.\n */\nexport function createHttpServer(): ServerFactory {\n return async (options: any): Promise<Server> => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url!, `http://${req.headers.host}`);\n const request = new Request(url.toString(), {\n method: req.method,\n headers: req.headers as any,\n body: ['GET', 'HEAD'].includes(req.method!) ? undefined : new ReadableStream({\n start(controller) {\n req.on('data', chunk => controller.enqueue(chunk));\n req.on('end', () => controller.close());\n req.on('error', err => controller.error(err));\n }\n }) as any,\n // Required for Node.js undici when sending a body\n duplex: 'half'\n } as any);\n\n const response = await options.fetch(request, fauxServer);\n\n res.statusCode = response.status;\n response.headers.forEach((v, k) => res.setHeader(k, v));\n\n if (response.body) {\n // Optimize: Use arrayBuffer for direct conversion instead of async iteration\n const buffer = await response.arrayBuffer();\n res.end(Buffer.from(buffer));\n } else {\n res.end();\n }\n });\n\n const fauxServer: Server = {\n stop: () => {\n server.close();\n return Promise.resolve(); // Bun.Server stop usually returns void but in type definition it might vary.\n },\n upgrade(req, options) {\n return false;\n },\n reload(options) {\n return fauxServer as any;\n },\n get port() {\n const addr = server.address();\n if (typeof addr === 'object' && addr !== null) {\n return addr.port;\n }\n return options.port;\n },\n hostname: options.hostname,\n development: options.development,\n pendingRequests: 0,\n requestIP: (req) => null,\n publish: () => 0,\n subscriberCount: () => 0,\n url: new URL(`http://${options.hostname}:${options.port}`),\n // Expose the raw Node.js server for generic socket/websocket support (e.g. Socket.IO)\n nodeServer: server\n } as unknown as Server;\n\n return new Promise((resolve) => {\n server.listen(options.port, options.hostname, () => {\n resolve(fauxServer);\n });\n });\n };\n}\n\n/**\n * Creates a server factory that uses the standard Node.js `https` module.\n * @param sslOptions - Node.js HTTPS options (key, cert, etc.)\n * @returns A ServerFactory compatible with Shokupan.\n */\nexport function createHttpsServer(sslOptions: https.ServerOptions): ServerFactory {\n return async (options: any): Promise<Server> => {\n const server = https.createServer(sslOptions, async (req, res) => {\n const url = new URL(req.url!, `https://${req.headers.host}`);\n const request = new Request(url.toString(), {\n method: req.method,\n headers: req.headers as any,\n body: ['GET', 'HEAD'].includes(req.method!) ? undefined : new ReadableStream({\n start(controller) {\n req.on('data', chunk => controller.enqueue(chunk));\n req.on('end', () => controller.close());\n req.on('error', err => controller.error(err));\n }\n }) as any,\n // Required for Node.js undici when sending a body\n duplex: 'half'\n } as any);\n\n const response = await options.fetch(request, fauxServer);\n\n res.statusCode = response.status;\n response.headers.forEach((v, k) => res.setHeader(k, v));\n\n if (response.body) {\n // Optimize: Use arrayBuffer for direct conversion instead of async iteration\n const buffer = await response.arrayBuffer();\n res.end(Buffer.from(buffer));\n } else {\n res.end();\n }\n });\n\n const fauxServer: Server = {\n stop: () => {\n server.close();\n },\n upgrade(req, options) {\n return false;\n },\n reload(options) {\n return fauxServer as any;\n },\n get port() {\n const addr = server.address();\n if (typeof addr === 'object' && addr !== null) {\n return addr.port;\n }\n return options.port;\n },\n hostname: options.hostname,\n development: options.development,\n pendingRequests: 0,\n requestIP: (req) => null,\n publish: () => 0,\n subscriberCount: () => 0,\n url: new URL(`https://${options.hostname}:${options.port}`),\n // Expose the raw Node.js server for generic socket/websocket support\n nodeServer: server\n } as unknown as Server;\n\n return new Promise((resolve) => {\n server.listen(options.port, options.hostname, () => {\n resolve(fauxServer);\n });\n });\n };\n}\n"],"names":["http","options"],"mappings":";;;;;;;;;;;;;;;;;;;;;AASO,SAAS,mBAAkC;AAC9C,SAAO,OAAO,YAAkC;AAC5C,UAAM,SAASA,gBAAK,aAAa,OAAO,KAAK,QAAQ;AACjD,YAAM,MAAM,IAAI,IAAI,IAAI,KAAM,UAAU,IAAI,QAAQ,IAAI,EAAE;AAC1D,YAAM,UAAU,IAAI,QAAQ,IAAI,YAAY;AAAA,QACxC,QAAQ,IAAI;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,MAAM,CAAC,OAAO,MAAM,EAAE,SAAS,IAAI,MAAO,IAAI,SAAY,IAAI,eAAe;AAAA,UACzE,MAAM,YAAY;AACd,gBAAI,GAAG,QAAQ,CAAA,UAAS,WAAW,QAAQ,KAAK,CAAC;AACjD,gBAAI,GAAG,OAAO,MAAM,WAAW,OAAO;AACtC,gBAAI,GAAG,SAAS,CAAA,QAAO,WAAW,MAAM,GAAG,CAAC;AAAA,UAChD;AAAA,QAAA,CACH;AAAA;AAAA,QAED,QAAQ;AAAA,MAAA,CACJ;AAER,YAAM,WAAW,MAAM,QAAQ,MAAM,SAAS,UAAU;AAExD,UAAI,aAAa,SAAS;AAC1B,eAAS,QAAQ,QAAQ,CAAC,GAAG,MAAM,IAAI,UAAU,GAAG,CAAC,CAAC;AAEtD,UAAI,SAAS,MAAM;AAEf,cAAM,SAAS,MAAM,SAAS,YAAA;AAC9B,YAAI,IAAI,OAAO,KAAK,MAAM,CAAC;AAAA,MAC/B,OAAO;AACH,YAAI,IAAA;AAAA,MACR;AAAA,IACJ,CAAC;AAED,UAAM,aAAqB;AAAA,MACvB,MAAM,MAAM;AACR,eAAO,MAAA;AACP,eAAO,QAAQ,QAAA;AAAA,MACnB;AAAA,MACA,QAAQ,KAAKC,UAAS;AAClB,eAAO;AAAA,MACX;AAAA,MACA,OAAOA,UAAS;AACZ,eAAO;AAAA,MACX;AAAA,MACA,IAAI,OAAO;AACP,cAAM,OAAO,OAAO,QAAA;AACpB,YAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC3C,iBAAO,KAAK;AAAA,QAChB;AACA,eAAO,QAAQ;AAAA,MACnB;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB,aAAa,QAAQ;AAAA,MACrB,iBAAiB;AAAA,MACjB,WAAW,CAAC,QAAQ;AAAA,MACpB,SAAS,MAAM;AAAA,MACf,iBAAiB,MAAM;AAAA,MACvB,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ,IAAI,QAAQ,IAAI,EAAE;AAAA;AAAA,MAEzD,YAAY;AAAA,IAAA;AAGhB,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC5B,aAAO,OAAO,QAAQ,MAAM,QAAQ,UAAU,MAAM;AAChD,gBAAQ,UAAU;AAAA,MACtB,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AACJ;;"}
@@ -51,7 +51,9 @@ function createHttpServer() {
51
51
  requestIP: (req) => null,
52
52
  publish: () => 0,
53
53
  subscriberCount: () => 0,
54
- url: new URL(`http://${options.hostname}:${options.port}`)
54
+ url: new URL(`http://${options.hostname}:${options.port}`),
55
+ // Expose the raw Node.js server for generic socket/websocket support (e.g. Socket.IO)
56
+ nodeServer: server
55
57
  };
56
58
  return new Promise((resolve) => {
57
59
  server.listen(options.port, options.hostname, () => {
@@ -63,4 +65,4 @@ function createHttpServer() {
63
65
  export {
64
66
  createHttpServer
65
67
  };
66
- //# sourceMappingURL=server-adapter-0xH174zz.js.map
68
+ //# sourceMappingURL=http-server-CCeagTyU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server-CCeagTyU.js","sources":["../src/plugins/application/http-server.ts"],"sourcesContent":["import type { Server } from \"bun\";\nimport * as http from \"node:http\";\nimport * as https from \"node:https\";\nimport type { ServerFactory } from \"../../util/types\";\n\n/**\n * Creates a server factory that uses the standard Node.js `http` module.\n * @returns A ServerFactory compatible with Shokupan.\n */\nexport function createHttpServer(): ServerFactory {\n return async (options: any): Promise<Server> => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url!, `http://${req.headers.host}`);\n const request = new Request(url.toString(), {\n method: req.method,\n headers: req.headers as any,\n body: ['GET', 'HEAD'].includes(req.method!) ? undefined : new ReadableStream({\n start(controller) {\n req.on('data', chunk => controller.enqueue(chunk));\n req.on('end', () => controller.close());\n req.on('error', err => controller.error(err));\n }\n }) as any,\n // Required for Node.js undici when sending a body\n duplex: 'half'\n } as any);\n\n const response = await options.fetch(request, fauxServer);\n\n res.statusCode = response.status;\n response.headers.forEach((v, k) => res.setHeader(k, v));\n\n if (response.body) {\n // Optimize: Use arrayBuffer for direct conversion instead of async iteration\n const buffer = await response.arrayBuffer();\n res.end(Buffer.from(buffer));\n } else {\n res.end();\n }\n });\n\n const fauxServer: Server = {\n stop: () => {\n server.close();\n return Promise.resolve(); // Bun.Server stop usually returns void but in type definition it might vary.\n },\n upgrade(req, options) {\n return false;\n },\n reload(options) {\n return fauxServer as any;\n },\n get port() {\n const addr = server.address();\n if (typeof addr === 'object' && addr !== null) {\n return addr.port;\n }\n return options.port;\n },\n hostname: options.hostname,\n development: options.development,\n pendingRequests: 0,\n requestIP: (req) => null,\n publish: () => 0,\n subscriberCount: () => 0,\n url: new URL(`http://${options.hostname}:${options.port}`),\n // Expose the raw Node.js server for generic socket/websocket support (e.g. Socket.IO)\n nodeServer: server\n } as unknown as Server;\n\n return new Promise((resolve) => {\n server.listen(options.port, options.hostname, () => {\n resolve(fauxServer);\n });\n });\n };\n}\n\n/**\n * Creates a server factory that uses the standard Node.js `https` module.\n * @param sslOptions - Node.js HTTPS options (key, cert, etc.)\n * @returns A ServerFactory compatible with Shokupan.\n */\nexport function createHttpsServer(sslOptions: https.ServerOptions): ServerFactory {\n return async (options: any): Promise<Server> => {\n const server = https.createServer(sslOptions, async (req, res) => {\n const url = new URL(req.url!, `https://${req.headers.host}`);\n const request = new Request(url.toString(), {\n method: req.method,\n headers: req.headers as any,\n body: ['GET', 'HEAD'].includes(req.method!) ? undefined : new ReadableStream({\n start(controller) {\n req.on('data', chunk => controller.enqueue(chunk));\n req.on('end', () => controller.close());\n req.on('error', err => controller.error(err));\n }\n }) as any,\n // Required for Node.js undici when sending a body\n duplex: 'half'\n } as any);\n\n const response = await options.fetch(request, fauxServer);\n\n res.statusCode = response.status;\n response.headers.forEach((v, k) => res.setHeader(k, v));\n\n if (response.body) {\n // Optimize: Use arrayBuffer for direct conversion instead of async iteration\n const buffer = await response.arrayBuffer();\n res.end(Buffer.from(buffer));\n } else {\n res.end();\n }\n });\n\n const fauxServer: Server = {\n stop: () => {\n server.close();\n },\n upgrade(req, options) {\n return false;\n },\n reload(options) {\n return fauxServer as any;\n },\n get port() {\n const addr = server.address();\n if (typeof addr === 'object' && addr !== null) {\n return addr.port;\n }\n return options.port;\n },\n hostname: options.hostname,\n development: options.development,\n pendingRequests: 0,\n requestIP: (req) => null,\n publish: () => 0,\n subscriberCount: () => 0,\n url: new URL(`https://${options.hostname}:${options.port}`),\n // Expose the raw Node.js server for generic socket/websocket support\n nodeServer: server\n } as unknown as Server;\n\n return new Promise((resolve) => {\n server.listen(options.port, options.hostname, () => {\n resolve(fauxServer);\n });\n });\n };\n}\n"],"names":["options"],"mappings":";;AASO,SAAS,mBAAkC;AAC9C,SAAO,OAAO,YAAkC;AAC5C,UAAM,SAAS,KAAK,aAAa,OAAO,KAAK,QAAQ;AACjD,YAAM,MAAM,IAAI,IAAI,IAAI,KAAM,UAAU,IAAI,QAAQ,IAAI,EAAE;AAC1D,YAAM,UAAU,IAAI,QAAQ,IAAI,YAAY;AAAA,QACxC,QAAQ,IAAI;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,MAAM,CAAC,OAAO,MAAM,EAAE,SAAS,IAAI,MAAO,IAAI,SAAY,IAAI,eAAe;AAAA,UACzE,MAAM,YAAY;AACd,gBAAI,GAAG,QAAQ,CAAA,UAAS,WAAW,QAAQ,KAAK,CAAC;AACjD,gBAAI,GAAG,OAAO,MAAM,WAAW,OAAO;AACtC,gBAAI,GAAG,SAAS,CAAA,QAAO,WAAW,MAAM,GAAG,CAAC;AAAA,UAChD;AAAA,QAAA,CACH;AAAA;AAAA,QAED,QAAQ;AAAA,MAAA,CACJ;AAER,YAAM,WAAW,MAAM,QAAQ,MAAM,SAAS,UAAU;AAExD,UAAI,aAAa,SAAS;AAC1B,eAAS,QAAQ,QAAQ,CAAC,GAAG,MAAM,IAAI,UAAU,GAAG,CAAC,CAAC;AAEtD,UAAI,SAAS,MAAM;AAEf,cAAM,SAAS,MAAM,SAAS,YAAA;AAC9B,YAAI,IAAI,OAAO,KAAK,MAAM,CAAC;AAAA,MAC/B,OAAO;AACH,YAAI,IAAA;AAAA,MACR;AAAA,IACJ,CAAC;AAED,UAAM,aAAqB;AAAA,MACvB,MAAM,MAAM;AACR,eAAO,MAAA;AACP,eAAO,QAAQ,QAAA;AAAA,MACnB;AAAA,MACA,QAAQ,KAAKA,UAAS;AAClB,eAAO;AAAA,MACX;AAAA,MACA,OAAOA,UAAS;AACZ,eAAO;AAAA,MACX;AAAA,MACA,IAAI,OAAO;AACP,cAAM,OAAO,OAAO,QAAA;AACpB,YAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC3C,iBAAO,KAAK;AAAA,QAChB;AACA,eAAO,QAAQ;AAAA,MACnB;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB,aAAa,QAAQ;AAAA,MACrB,iBAAiB;AAAA,MACjB,WAAW,CAAC,QAAQ;AAAA,MACpB,SAAS,MAAM;AAAA,MACf,iBAAiB,MAAM;AAAA,MACvB,KAAK,IAAI,IAAI,UAAU,QAAQ,QAAQ,IAAI,QAAQ,IAAI,EAAE;AAAA;AAAA,MAEzD,YAAY;AAAA,IAAA;AAGhB,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC5B,aAAO,OAAO,QAAQ,MAAM,QAAQ,UAAU,MAAM;AAChD,gBAAQ,UAAU;AAAA,MACtB,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AACJ;"}