almostnode 0.1.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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +731 -0
  3. package/dist/__sw__.js +394 -0
  4. package/dist/ai-chatbot-demo-entry.d.ts +6 -0
  5. package/dist/ai-chatbot-demo-entry.d.ts.map +1 -0
  6. package/dist/ai-chatbot-demo.d.ts +42 -0
  7. package/dist/ai-chatbot-demo.d.ts.map +1 -0
  8. package/dist/assets/runtime-worker-D9x_Ddwz.js +60543 -0
  9. package/dist/assets/runtime-worker-D9x_Ddwz.js.map +1 -0
  10. package/dist/convex-app-demo-entry.d.ts +6 -0
  11. package/dist/convex-app-demo-entry.d.ts.map +1 -0
  12. package/dist/convex-app-demo.d.ts +68 -0
  13. package/dist/convex-app-demo.d.ts.map +1 -0
  14. package/dist/cors-proxy.d.ts +46 -0
  15. package/dist/cors-proxy.d.ts.map +1 -0
  16. package/dist/create-runtime.d.ts +42 -0
  17. package/dist/create-runtime.d.ts.map +1 -0
  18. package/dist/demo.d.ts +6 -0
  19. package/dist/demo.d.ts.map +1 -0
  20. package/dist/dev-server.d.ts +97 -0
  21. package/dist/dev-server.d.ts.map +1 -0
  22. package/dist/frameworks/next-dev-server.d.ts +202 -0
  23. package/dist/frameworks/next-dev-server.d.ts.map +1 -0
  24. package/dist/frameworks/vite-dev-server.d.ts +85 -0
  25. package/dist/frameworks/vite-dev-server.d.ts.map +1 -0
  26. package/dist/index.cjs +14965 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.d.ts +71 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.mjs +14867 -0
  31. package/dist/index.mjs.map +1 -0
  32. package/dist/next-demo.d.ts +49 -0
  33. package/dist/next-demo.d.ts.map +1 -0
  34. package/dist/npm/index.d.ts +71 -0
  35. package/dist/npm/index.d.ts.map +1 -0
  36. package/dist/npm/registry.d.ts +66 -0
  37. package/dist/npm/registry.d.ts.map +1 -0
  38. package/dist/npm/resolver.d.ts +52 -0
  39. package/dist/npm/resolver.d.ts.map +1 -0
  40. package/dist/npm/tarball.d.ts +29 -0
  41. package/dist/npm/tarball.d.ts.map +1 -0
  42. package/dist/runtime-interface.d.ts +90 -0
  43. package/dist/runtime-interface.d.ts.map +1 -0
  44. package/dist/runtime.d.ts +103 -0
  45. package/dist/runtime.d.ts.map +1 -0
  46. package/dist/sandbox-helpers.d.ts +43 -0
  47. package/dist/sandbox-helpers.d.ts.map +1 -0
  48. package/dist/sandbox-runtime.d.ts +65 -0
  49. package/dist/sandbox-runtime.d.ts.map +1 -0
  50. package/dist/server-bridge.d.ts +89 -0
  51. package/dist/server-bridge.d.ts.map +1 -0
  52. package/dist/shims/assert.d.ts +51 -0
  53. package/dist/shims/assert.d.ts.map +1 -0
  54. package/dist/shims/async_hooks.d.ts +37 -0
  55. package/dist/shims/async_hooks.d.ts.map +1 -0
  56. package/dist/shims/buffer.d.ts +20 -0
  57. package/dist/shims/buffer.d.ts.map +1 -0
  58. package/dist/shims/child_process-browser.d.ts +92 -0
  59. package/dist/shims/child_process-browser.d.ts.map +1 -0
  60. package/dist/shims/child_process.d.ts +93 -0
  61. package/dist/shims/child_process.d.ts.map +1 -0
  62. package/dist/shims/chokidar.d.ts +55 -0
  63. package/dist/shims/chokidar.d.ts.map +1 -0
  64. package/dist/shims/cluster.d.ts +52 -0
  65. package/dist/shims/cluster.d.ts.map +1 -0
  66. package/dist/shims/crypto.d.ts +122 -0
  67. package/dist/shims/crypto.d.ts.map +1 -0
  68. package/dist/shims/dgram.d.ts +34 -0
  69. package/dist/shims/dgram.d.ts.map +1 -0
  70. package/dist/shims/diagnostics_channel.d.ts +80 -0
  71. package/dist/shims/diagnostics_channel.d.ts.map +1 -0
  72. package/dist/shims/dns.d.ts +87 -0
  73. package/dist/shims/dns.d.ts.map +1 -0
  74. package/dist/shims/domain.d.ts +25 -0
  75. package/dist/shims/domain.d.ts.map +1 -0
  76. package/dist/shims/esbuild.d.ts +105 -0
  77. package/dist/shims/esbuild.d.ts.map +1 -0
  78. package/dist/shims/events.d.ts +37 -0
  79. package/dist/shims/events.d.ts.map +1 -0
  80. package/dist/shims/fs.d.ts +115 -0
  81. package/dist/shims/fs.d.ts.map +1 -0
  82. package/dist/shims/fsevents.d.ts +67 -0
  83. package/dist/shims/fsevents.d.ts.map +1 -0
  84. package/dist/shims/http.d.ts +217 -0
  85. package/dist/shims/http.d.ts.map +1 -0
  86. package/dist/shims/http2.d.ts +81 -0
  87. package/dist/shims/http2.d.ts.map +1 -0
  88. package/dist/shims/https.d.ts +36 -0
  89. package/dist/shims/https.d.ts.map +1 -0
  90. package/dist/shims/inspector.d.ts +25 -0
  91. package/dist/shims/inspector.d.ts.map +1 -0
  92. package/dist/shims/module.d.ts +22 -0
  93. package/dist/shims/module.d.ts.map +1 -0
  94. package/dist/shims/net.d.ts +100 -0
  95. package/dist/shims/net.d.ts.map +1 -0
  96. package/dist/shims/os.d.ts +159 -0
  97. package/dist/shims/os.d.ts.map +1 -0
  98. package/dist/shims/path.d.ts +72 -0
  99. package/dist/shims/path.d.ts.map +1 -0
  100. package/dist/shims/perf_hooks.d.ts +50 -0
  101. package/dist/shims/perf_hooks.d.ts.map +1 -0
  102. package/dist/shims/process.d.ts +93 -0
  103. package/dist/shims/process.d.ts.map +1 -0
  104. package/dist/shims/querystring.d.ts +23 -0
  105. package/dist/shims/querystring.d.ts.map +1 -0
  106. package/dist/shims/readdirp.d.ts +52 -0
  107. package/dist/shims/readdirp.d.ts.map +1 -0
  108. package/dist/shims/readline.d.ts +62 -0
  109. package/dist/shims/readline.d.ts.map +1 -0
  110. package/dist/shims/rollup.d.ts +34 -0
  111. package/dist/shims/rollup.d.ts.map +1 -0
  112. package/dist/shims/sentry.d.ts +163 -0
  113. package/dist/shims/sentry.d.ts.map +1 -0
  114. package/dist/shims/stream.d.ts +181 -0
  115. package/dist/shims/stream.d.ts.map +1 -0
  116. package/dist/shims/tls.d.ts +53 -0
  117. package/dist/shims/tls.d.ts.map +1 -0
  118. package/dist/shims/tty.d.ts +30 -0
  119. package/dist/shims/tty.d.ts.map +1 -0
  120. package/dist/shims/url.d.ts +64 -0
  121. package/dist/shims/url.d.ts.map +1 -0
  122. package/dist/shims/util.d.ts +106 -0
  123. package/dist/shims/util.d.ts.map +1 -0
  124. package/dist/shims/v8.d.ts +73 -0
  125. package/dist/shims/v8.d.ts.map +1 -0
  126. package/dist/shims/vfs-adapter.d.ts +126 -0
  127. package/dist/shims/vfs-adapter.d.ts.map +1 -0
  128. package/dist/shims/vm.d.ts +45 -0
  129. package/dist/shims/vm.d.ts.map +1 -0
  130. package/dist/shims/worker_threads.d.ts +66 -0
  131. package/dist/shims/worker_threads.d.ts.map +1 -0
  132. package/dist/shims/ws.d.ts +66 -0
  133. package/dist/shims/ws.d.ts.map +1 -0
  134. package/dist/shims/zlib.d.ts +161 -0
  135. package/dist/shims/zlib.d.ts.map +1 -0
  136. package/dist/transform.d.ts +24 -0
  137. package/dist/transform.d.ts.map +1 -0
  138. package/dist/virtual-fs.d.ts +226 -0
  139. package/dist/virtual-fs.d.ts.map +1 -0
  140. package/dist/vite-demo.d.ts +35 -0
  141. package/dist/vite-demo.d.ts.map +1 -0
  142. package/dist/vite-sw.js +132 -0
  143. package/dist/worker/runtime-worker.d.ts +8 -0
  144. package/dist/worker/runtime-worker.d.ts.map +1 -0
  145. package/dist/worker-runtime.d.ts +50 -0
  146. package/dist/worker-runtime.d.ts.map +1 -0
  147. package/package.json +85 -0
  148. package/src/ai-chatbot-demo-entry.ts +244 -0
  149. package/src/ai-chatbot-demo.ts +509 -0
  150. package/src/convex-app-demo-entry.ts +1107 -0
  151. package/src/convex-app-demo.ts +1316 -0
  152. package/src/cors-proxy.ts +81 -0
  153. package/src/create-runtime.ts +147 -0
  154. package/src/demo.ts +304 -0
  155. package/src/dev-server.ts +274 -0
  156. package/src/frameworks/next-dev-server.ts +2224 -0
  157. package/src/frameworks/vite-dev-server.ts +702 -0
  158. package/src/index.ts +101 -0
  159. package/src/next-demo.ts +1784 -0
  160. package/src/npm/index.ts +347 -0
  161. package/src/npm/registry.ts +152 -0
  162. package/src/npm/resolver.ts +385 -0
  163. package/src/npm/tarball.ts +209 -0
  164. package/src/runtime-interface.ts +103 -0
  165. package/src/runtime.ts +1046 -0
  166. package/src/sandbox-helpers.ts +173 -0
  167. package/src/sandbox-runtime.ts +252 -0
  168. package/src/server-bridge.ts +426 -0
  169. package/src/shims/assert.ts +664 -0
  170. package/src/shims/async_hooks.ts +86 -0
  171. package/src/shims/buffer.ts +75 -0
  172. package/src/shims/child_process-browser.ts +217 -0
  173. package/src/shims/child_process.ts +463 -0
  174. package/src/shims/chokidar.ts +313 -0
  175. package/src/shims/cluster.ts +67 -0
  176. package/src/shims/crypto.ts +830 -0
  177. package/src/shims/dgram.ts +47 -0
  178. package/src/shims/diagnostics_channel.ts +196 -0
  179. package/src/shims/dns.ts +172 -0
  180. package/src/shims/domain.ts +58 -0
  181. package/src/shims/esbuild.ts +805 -0
  182. package/src/shims/events.ts +195 -0
  183. package/src/shims/fs.ts +803 -0
  184. package/src/shims/fsevents.ts +63 -0
  185. package/src/shims/http.ts +904 -0
  186. package/src/shims/http2.ts +96 -0
  187. package/src/shims/https.ts +86 -0
  188. package/src/shims/inspector.ts +30 -0
  189. package/src/shims/module.ts +82 -0
  190. package/src/shims/net.ts +359 -0
  191. package/src/shims/os.ts +195 -0
  192. package/src/shims/path.ts +199 -0
  193. package/src/shims/perf_hooks.ts +92 -0
  194. package/src/shims/process.ts +346 -0
  195. package/src/shims/querystring.ts +97 -0
  196. package/src/shims/readdirp.ts +228 -0
  197. package/src/shims/readline.ts +110 -0
  198. package/src/shims/rollup.ts +80 -0
  199. package/src/shims/sentry.ts +133 -0
  200. package/src/shims/stream.ts +1126 -0
  201. package/src/shims/tls.ts +95 -0
  202. package/src/shims/tty.ts +64 -0
  203. package/src/shims/url.ts +171 -0
  204. package/src/shims/util.ts +312 -0
  205. package/src/shims/v8.ts +113 -0
  206. package/src/shims/vfs-adapter.ts +402 -0
  207. package/src/shims/vm.ts +83 -0
  208. package/src/shims/worker_threads.ts +111 -0
  209. package/src/shims/ws.ts +382 -0
  210. package/src/shims/zlib.ts +289 -0
  211. package/src/transform.ts +313 -0
  212. package/src/types/external.d.ts +67 -0
  213. package/src/virtual-fs.ts +903 -0
  214. package/src/vite-demo.ts +577 -0
  215. package/src/worker/runtime-worker.ts +128 -0
  216. package/src/worker-runtime.ts +145 -0
@@ -0,0 +1,904 @@
1
+ /**
2
+ * Node.js http module shim
3
+ * Provides IncomingMessage, ServerResponse, and Server for virtual HTTP handling
4
+ */
5
+
6
+ import { EventEmitter, type EventListener } from './events';
7
+ import { Readable, Writable, Buffer } from './stream';
8
+ import { Socket, Server as NetServer, AddressInfo } from './net';
9
+
10
+ export type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;
11
+
12
+ export interface RequestOptions {
13
+ method?: string;
14
+ path?: string;
15
+ headers?: Record<string, string | string[]>;
16
+ hostname?: string;
17
+ port?: number;
18
+ }
19
+
20
+ /**
21
+ * Incoming HTTP request (Node.js compatible)
22
+ */
23
+ export class IncomingMessage extends Readable {
24
+ httpVersion: string = '1.1';
25
+ httpVersionMajor: number = 1;
26
+ httpVersionMinor: number = 1;
27
+ complete: boolean = false;
28
+ headers: Record<string, string | string[] | undefined> = {};
29
+ rawHeaders: string[] = [];
30
+ trailers: Record<string, string | undefined> = {};
31
+ rawTrailers: string[] = [];
32
+ method?: string;
33
+ url?: string;
34
+ statusCode?: number;
35
+ statusMessage?: string;
36
+ socket: Socket;
37
+
38
+ private _body: Buffer | null = null;
39
+
40
+ constructor(socket?: Socket) {
41
+ super();
42
+ this.socket = socket || new Socket();
43
+ }
44
+
45
+ setTimeout(msecs: number, callback?: () => void): this {
46
+ if (callback) {
47
+ this.once('timeout', callback);
48
+ }
49
+ return this;
50
+ }
51
+
52
+ destroy(error?: Error): this {
53
+ super.destroy(error);
54
+ return this;
55
+ }
56
+
57
+ // Internal: set body data
58
+ _setBody(body: Buffer | string | null): void {
59
+ if (body === null) {
60
+ this._body = null;
61
+ } else {
62
+ this._body = typeof body === 'string' ? Buffer.from(body) : body;
63
+ }
64
+
65
+ if (this._body) {
66
+ this.push(this._body);
67
+ }
68
+ this.push(null);
69
+ this.complete = true;
70
+ }
71
+
72
+ // Internal: initialize from raw request
73
+ static fromRequest(
74
+ method: string,
75
+ url: string,
76
+ headers: Record<string, string>,
77
+ body?: Buffer | string
78
+ ): IncomingMessage {
79
+ const msg = new IncomingMessage();
80
+ msg.method = method;
81
+ msg.url = url;
82
+ msg.headers = { ...headers };
83
+
84
+ // Build raw headers
85
+ for (const [key, value] of Object.entries(headers)) {
86
+ msg.rawHeaders.push(key, value);
87
+ }
88
+
89
+ if (body) {
90
+ msg._setBody(body);
91
+ } else {
92
+ msg.push(null);
93
+ msg.complete = true;
94
+ }
95
+
96
+ return msg;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Outgoing HTTP response (Node.js compatible)
102
+ */
103
+ export class ServerResponse extends Writable {
104
+ statusCode: number = 200;
105
+ statusMessage: string = 'OK';
106
+ headersSent: boolean = false;
107
+ finished: boolean = false;
108
+ sendDate: boolean = true;
109
+ socket: Socket | null;
110
+
111
+ private _headers: Map<string, string | string[]> = new Map();
112
+ private _body: Uint8Array[] = [];
113
+ private _resolve?: (response: ResponseData) => void;
114
+
115
+ constructor(req: IncomingMessage) {
116
+ super();
117
+ this.socket = req.socket;
118
+ }
119
+
120
+ // Internal: set resolver for async response handling
121
+ _setResolver(resolve: (response: ResponseData) => void): void {
122
+ this._resolve = resolve;
123
+ }
124
+
125
+ setHeader(name: string, value: string | string[] | number): this {
126
+ if (this.headersSent) {
127
+ throw new Error('Cannot set headers after they are sent');
128
+ }
129
+ this._headers.set(name.toLowerCase(), String(value));
130
+ return this;
131
+ }
132
+
133
+ getHeader(name: string): string | string[] | undefined {
134
+ return this._headers.get(name.toLowerCase());
135
+ }
136
+
137
+ getHeaders(): Record<string, string | string[]> {
138
+ const headers: Record<string, string | string[]> = {};
139
+ for (const [key, value] of this._headers) {
140
+ headers[key] = value;
141
+ }
142
+ return headers;
143
+ }
144
+
145
+ getHeaderNames(): string[] {
146
+ return [...this._headers.keys()];
147
+ }
148
+
149
+ hasHeader(name: string): boolean {
150
+ return this._headers.has(name.toLowerCase());
151
+ }
152
+
153
+ removeHeader(name: string): void {
154
+ if (this.headersSent) {
155
+ throw new Error('Cannot remove headers after they are sent');
156
+ }
157
+ this._headers.delete(name.toLowerCase());
158
+ }
159
+
160
+ writeHead(
161
+ statusCode: number,
162
+ statusMessageOrHeaders?: string | Record<string, string | string[] | number>,
163
+ headers?: Record<string, string | string[] | number>
164
+ ): this {
165
+ this.statusCode = statusCode;
166
+
167
+ if (typeof statusMessageOrHeaders === 'string') {
168
+ this.statusMessage = statusMessageOrHeaders;
169
+ if (headers) {
170
+ for (const [key, value] of Object.entries(headers)) {
171
+ this.setHeader(key, value);
172
+ }
173
+ }
174
+ } else if (statusMessageOrHeaders) {
175
+ for (const [key, value] of Object.entries(statusMessageOrHeaders)) {
176
+ this.setHeader(key, value);
177
+ }
178
+ }
179
+
180
+ return this;
181
+ }
182
+
183
+ write(
184
+ chunk: Uint8Array | string,
185
+ encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void),
186
+ callback?: (error?: Error | null) => void
187
+ ): boolean {
188
+ this.headersSent = true;
189
+ const buffer = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
190
+ this._body.push(buffer);
191
+
192
+ const cb = typeof encodingOrCallback === 'function' ? encodingOrCallback : callback;
193
+ if (cb) {
194
+ queueMicrotask(() => cb(null));
195
+ }
196
+
197
+ return true;
198
+ }
199
+
200
+ end(
201
+ chunkOrCallback?: Uint8Array | string | (() => void),
202
+ encodingOrCallback?: BufferEncoding | (() => void),
203
+ callback?: () => void
204
+ ): this {
205
+ if (typeof chunkOrCallback === 'function') {
206
+ callback = chunkOrCallback;
207
+ } else if (chunkOrCallback !== undefined) {
208
+ this.write(chunkOrCallback as Uint8Array | string);
209
+ }
210
+
211
+ if (typeof encodingOrCallback === 'function') {
212
+ callback = encodingOrCallback;
213
+ }
214
+
215
+ this.headersSent = true;
216
+ this.finished = true;
217
+
218
+ // Resolve with response data
219
+ if (this._resolve) {
220
+ const headers: Record<string, string> = {};
221
+ for (const [key, value] of this._headers) {
222
+ headers[key] = Array.isArray(value) ? value.join(', ') : value;
223
+ }
224
+
225
+ this._resolve({
226
+ statusCode: this.statusCode,
227
+ statusMessage: this.statusMessage,
228
+ headers,
229
+ body: Buffer.concat(this._body),
230
+ });
231
+ }
232
+
233
+ queueMicrotask(() => {
234
+ this.emit('finish');
235
+ if (callback) callback();
236
+ });
237
+
238
+ return this;
239
+ }
240
+
241
+ // Convenience method for simple responses
242
+ send(data: string | Buffer | object): this {
243
+ if (typeof data === 'object' && !Buffer.isBuffer(data)) {
244
+ this.setHeader('Content-Type', 'application/json');
245
+ data = JSON.stringify(data);
246
+ }
247
+
248
+ if (!this.hasHeader('Content-Type')) {
249
+ this.setHeader('Content-Type', 'text/html');
250
+ }
251
+
252
+ this.write(typeof data === 'string' ? data : data);
253
+ return this.end();
254
+ }
255
+
256
+ // Express compatibility
257
+ json(data: unknown): this {
258
+ this.setHeader('Content-Type', 'application/json');
259
+ return this.end(JSON.stringify(data));
260
+ }
261
+
262
+ status(code: number): this {
263
+ this.statusCode = code;
264
+ return this;
265
+ }
266
+
267
+ redirect(urlOrStatus: string | number, url?: string): void {
268
+ if (typeof urlOrStatus === 'number') {
269
+ this.statusCode = urlOrStatus;
270
+ this.setHeader('Location', url!);
271
+ } else {
272
+ this.statusCode = 302;
273
+ this.setHeader('Location', urlOrStatus);
274
+ }
275
+ this.end();
276
+ }
277
+
278
+ // Get body for testing/debugging
279
+ _getBody(): Buffer {
280
+ return Buffer.concat(this._body);
281
+ }
282
+
283
+ _getBodyAsString(): string {
284
+ return this._getBody().toString('utf8');
285
+ }
286
+ }
287
+
288
+ export interface ResponseData {
289
+ statusCode: number;
290
+ statusMessage: string;
291
+ headers: Record<string, string>;
292
+ body: Buffer;
293
+ }
294
+
295
+ /**
296
+ * HTTP Server (Node.js compatible)
297
+ */
298
+ export class Server extends EventEmitter {
299
+ private _netServer: NetServer;
300
+ private _requestListener?: RequestListener;
301
+ private _pendingRequests: Map<string, {
302
+ resolve: (response: ResponseData) => void;
303
+ reject: (error: Error) => void;
304
+ }> = new Map();
305
+
306
+ listening: boolean = false;
307
+ maxHeadersCount: number | null = null;
308
+ timeout: number = 0;
309
+ keepAliveTimeout: number = 5000;
310
+ headersTimeout: number = 60000;
311
+ requestTimeout: number = 0;
312
+
313
+ constructor(requestListener?: RequestListener) {
314
+ super();
315
+ this._requestListener = requestListener;
316
+ this._netServer = new NetServer();
317
+
318
+ this._netServer.on('listening', () => {
319
+ this.listening = true;
320
+ this.emit('listening');
321
+ });
322
+
323
+ this._netServer.on('close', () => {
324
+ this.listening = false;
325
+ this.emit('close');
326
+ });
327
+
328
+ this._netServer.on('error', (err) => {
329
+ this.emit('error', err);
330
+ });
331
+ }
332
+
333
+ listen(
334
+ portOrOptions?: number | { port?: number; host?: string },
335
+ hostOrCallback?: string | (() => void),
336
+ callback?: () => void
337
+ ): this {
338
+ let port: number | undefined;
339
+ let host: string | undefined;
340
+ let cb: (() => void) | undefined;
341
+
342
+ if (typeof portOrOptions === 'number') {
343
+ port = portOrOptions;
344
+ if (typeof hostOrCallback === 'string') {
345
+ host = hostOrCallback;
346
+ cb = callback;
347
+ } else {
348
+ cb = hostOrCallback;
349
+ }
350
+ } else if (portOrOptions) {
351
+ port = portOrOptions.port;
352
+ host = portOrOptions.host;
353
+ cb = typeof hostOrCallback === 'function' ? hostOrCallback : callback;
354
+ }
355
+
356
+ // Wrap callback to register server after listening
357
+ const originalCb = cb;
358
+ const self = this;
359
+ cb = function() {
360
+ const addr = self._netServer.address();
361
+ if (addr) {
362
+ _registerServer(addr.port, self);
363
+ }
364
+ if (originalCb) originalCb();
365
+ };
366
+
367
+ this._netServer.listen(port, host, cb);
368
+
369
+ return this;
370
+ }
371
+
372
+ close(callback?: (err?: Error) => void): this {
373
+ const addr = this._netServer.address();
374
+ if (addr) {
375
+ _unregisterServer(addr.port);
376
+ }
377
+ this._netServer.close(callback);
378
+ return this;
379
+ }
380
+
381
+ address(): AddressInfo | null {
382
+ return this._netServer.address();
383
+ }
384
+
385
+ setTimeout(msecs?: number, callback?: () => void): this {
386
+ this.timeout = msecs || 0;
387
+ if (callback) {
388
+ this.on('timeout', callback);
389
+ }
390
+ return this;
391
+ }
392
+
393
+ ref(): this {
394
+ this._netServer.ref();
395
+ return this;
396
+ }
397
+
398
+ unref(): this {
399
+ this._netServer.unref();
400
+ return this;
401
+ }
402
+
403
+ /**
404
+ * Handle an incoming request (used by server bridge)
405
+ */
406
+ async handleRequest(
407
+ method: string,
408
+ url: string,
409
+ headers: Record<string, string>,
410
+ body?: Buffer | string
411
+ ): Promise<ResponseData> {
412
+ return new Promise((resolve, reject) => {
413
+ const req = IncomingMessage.fromRequest(method, url, headers, body);
414
+ const res = new ServerResponse(req);
415
+
416
+ res._setResolver(resolve);
417
+
418
+ // Set timeout
419
+ const timeoutId = this.timeout
420
+ ? setTimeout(() => {
421
+ reject(new Error('Request timeout'));
422
+ }, this.timeout)
423
+ : null;
424
+
425
+ res.on('finish', () => {
426
+ if (timeoutId) clearTimeout(timeoutId);
427
+ });
428
+
429
+ try {
430
+ this.emit('request', req, res);
431
+
432
+ if (this._requestListener) {
433
+ this._requestListener(req, res);
434
+ }
435
+ } catch (error) {
436
+ if (timeoutId) clearTimeout(timeoutId);
437
+ reject(error);
438
+ }
439
+ });
440
+ }
441
+ }
442
+
443
+ /**
444
+ * Create an HTTP server
445
+ */
446
+ export function createServer(requestListener?: RequestListener): Server {
447
+ return new Server(requestListener);
448
+ }
449
+
450
+ /**
451
+ * HTTP status codes
452
+ */
453
+ export const STATUS_CODES: Record<number, string> = {
454
+ 100: 'Continue',
455
+ 101: 'Switching Protocols',
456
+ 200: 'OK',
457
+ 201: 'Created',
458
+ 202: 'Accepted',
459
+ 204: 'No Content',
460
+ 301: 'Moved Permanently',
461
+ 302: 'Found',
462
+ 304: 'Not Modified',
463
+ 400: 'Bad Request',
464
+ 401: 'Unauthorized',
465
+ 403: 'Forbidden',
466
+ 404: 'Not Found',
467
+ 405: 'Method Not Allowed',
468
+ 408: 'Request Timeout',
469
+ 500: 'Internal Server Error',
470
+ 501: 'Not Implemented',
471
+ 502: 'Bad Gateway',
472
+ 503: 'Service Unavailable',
473
+ };
474
+
475
+ /**
476
+ * HTTP methods
477
+ */
478
+ export const METHODS = [
479
+ 'GET',
480
+ 'POST',
481
+ 'PUT',
482
+ 'DELETE',
483
+ 'PATCH',
484
+ 'HEAD',
485
+ 'OPTIONS',
486
+ 'CONNECT',
487
+ 'TRACE',
488
+ ];
489
+
490
+ // CORS proxy getter - checks localStorage for configured proxy
491
+ function getCorsProxy(): string | null {
492
+ if (typeof localStorage !== 'undefined') {
493
+ return localStorage.getItem('__corsProxyUrl') || null;
494
+ }
495
+ return null;
496
+ }
497
+
498
+ /**
499
+ * HTTP Client Request - makes real HTTP requests using fetch()
500
+ */
501
+ export class ClientRequest extends Writable {
502
+ method: string;
503
+ path: string;
504
+ headers: Record<string, string>;
505
+
506
+ private _options: RequestOptions;
507
+ private _protocol: 'http' | 'https';
508
+ private _bodyChunks: Uint8Array[] = [];
509
+ private _aborted: boolean = false;
510
+ private _timeout: number | null = null;
511
+ private _timeoutId: ReturnType<typeof setTimeout> | null = null;
512
+ private _requestEnded: boolean = false;
513
+
514
+ constructor(options: RequestOptions, protocol: 'http' | 'https' = 'http') {
515
+ super();
516
+ this._options = options;
517
+ this._protocol = protocol;
518
+ this.method = options.method || 'GET';
519
+ this.path = options.path || '/';
520
+ this.headers = {};
521
+
522
+ if (options.headers) {
523
+ for (const [key, value] of Object.entries(options.headers)) {
524
+ this.headers[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value;
525
+ }
526
+ }
527
+ }
528
+
529
+ setHeader(name: string, value: string): void {
530
+ this.headers[name.toLowerCase()] = value;
531
+ }
532
+
533
+ getHeader(name: string): string | undefined {
534
+ return this.headers[name.toLowerCase()];
535
+ }
536
+
537
+ removeHeader(name: string): void {
538
+ delete this.headers[name.toLowerCase()];
539
+ }
540
+
541
+ write(
542
+ chunk: Uint8Array | string,
543
+ encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void),
544
+ callback?: (error?: Error | null) => void
545
+ ): boolean {
546
+ const buffer = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
547
+ this._bodyChunks.push(buffer);
548
+
549
+ const cb = typeof encodingOrCallback === 'function' ? encodingOrCallback : callback;
550
+ if (cb) {
551
+ queueMicrotask(() => cb(null));
552
+ }
553
+
554
+ return true;
555
+ }
556
+
557
+ end(
558
+ dataOrCallback?: Uint8Array | string | (() => void),
559
+ encodingOrCallback?: BufferEncoding | (() => void),
560
+ callback?: () => void
561
+ ): this {
562
+ if (this._requestEnded) return this;
563
+ this._requestEnded = true;
564
+
565
+ // Handle overloaded arguments
566
+ let finalCallback = callback;
567
+ if (typeof dataOrCallback === 'function') {
568
+ finalCallback = dataOrCallback;
569
+ } else if (dataOrCallback !== undefined) {
570
+ this.write(dataOrCallback as Uint8Array | string);
571
+ }
572
+
573
+ if (typeof encodingOrCallback === 'function') {
574
+ finalCallback = encodingOrCallback;
575
+ }
576
+
577
+ // Perform the actual request
578
+ this._performRequest().then(() => {
579
+ if (finalCallback) finalCallback();
580
+ }).catch((error) => {
581
+ this.emit('error', error);
582
+ });
583
+
584
+ return this;
585
+ }
586
+
587
+ abort(): void {
588
+ this._aborted = true;
589
+ if (this._timeoutId) {
590
+ clearTimeout(this._timeoutId);
591
+ }
592
+ this.emit('abort');
593
+ }
594
+
595
+ setTimeout(ms: number, callback?: () => void): this {
596
+ this._timeout = ms;
597
+ if (callback) {
598
+ this.once('timeout', callback);
599
+ }
600
+ return this;
601
+ }
602
+
603
+ private async _performRequest(): Promise<void> {
604
+ if (this._aborted) return;
605
+
606
+ try {
607
+ // Build URL
608
+ const protocol = this._protocol === 'https' ? 'https:' : 'http:';
609
+ const hostname = this._options.hostname || 'localhost';
610
+ const port = this._options.port ? `:${this._options.port}` : '';
611
+ const path = this._options.path || '/';
612
+ const url = `${protocol}//${hostname}${port}${path}`;
613
+
614
+ // Use CORS proxy if configured
615
+ const corsProxy = getCorsProxy();
616
+ const fetchUrl = corsProxy
617
+ ? corsProxy + encodeURIComponent(url)
618
+ : url;
619
+
620
+ // Build fetch options
621
+ const fetchOptions: RequestInit = {
622
+ method: this.method,
623
+ headers: this.headers,
624
+ };
625
+
626
+ // Add body if we have one (not for GET/HEAD)
627
+ if (this._bodyChunks.length > 0 && this.method !== 'GET' && this.method !== 'HEAD') {
628
+ fetchOptions.body = Buffer.concat(this._bodyChunks);
629
+ }
630
+
631
+ // Set up timeout with AbortController
632
+ const controller = new AbortController();
633
+ fetchOptions.signal = controller.signal;
634
+
635
+ if (this._timeout) {
636
+ this._timeoutId = setTimeout(() => {
637
+ controller.abort();
638
+ this.emit('timeout');
639
+ }, this._timeout);
640
+ }
641
+
642
+ // Make the request
643
+ const response = await fetch(fetchUrl, fetchOptions);
644
+
645
+ // Clear timeout
646
+ if (this._timeoutId) {
647
+ clearTimeout(this._timeoutId);
648
+ this._timeoutId = null;
649
+ }
650
+
651
+ if (this._aborted) return;
652
+
653
+ // Convert response to IncomingMessage
654
+ const incomingMessage = await this._responseToIncomingMessage(response);
655
+
656
+ // Emit response event
657
+ this.emit('response', incomingMessage);
658
+
659
+ } catch (error) {
660
+ if (this._timeoutId) {
661
+ clearTimeout(this._timeoutId);
662
+ }
663
+ if (this._aborted) return;
664
+
665
+ // Wrap abort errors
666
+ if (error instanceof Error && error.name === 'AbortError') {
667
+ // Already emitted timeout event
668
+ return;
669
+ }
670
+
671
+ this.emit('error', error);
672
+ }
673
+ }
674
+
675
+ private async _responseToIncomingMessage(response: Response): Promise<IncomingMessage> {
676
+ const msg = new IncomingMessage();
677
+
678
+ // Set status
679
+ msg.statusCode = response.status;
680
+ msg.statusMessage = response.statusText || STATUS_CODES[response.status] || '';
681
+
682
+ // Copy headers
683
+ response.headers.forEach((value, key) => {
684
+ msg.headers[key.toLowerCase()] = value;
685
+ msg.rawHeaders.push(key, value);
686
+ });
687
+
688
+ // Read body and push to stream
689
+ const body = await response.arrayBuffer();
690
+ msg._setBody(Buffer.from(body));
691
+
692
+ return msg;
693
+ }
694
+ }
695
+
696
+ /**
697
+ * Helper to parse URL/options arguments for request()
698
+ */
699
+ function parseRequestArgs(
700
+ urlOrOptions: string | URL | RequestOptions,
701
+ optionsOrCallback?: RequestOptions | ((res: IncomingMessage) => void),
702
+ callback?: (res: IncomingMessage) => void
703
+ ): { options: RequestOptions; callback?: (res: IncomingMessage) => void } {
704
+ let options: RequestOptions;
705
+ let cb = callback;
706
+
707
+ if (typeof urlOrOptions === 'string' || urlOrOptions instanceof URL) {
708
+ const parsed = new URL(urlOrOptions.toString());
709
+ options = {
710
+ hostname: parsed.hostname,
711
+ port: parsed.port ? parseInt(parsed.port) : undefined,
712
+ path: parsed.pathname + parsed.search,
713
+ method: 'GET',
714
+ };
715
+ if (typeof optionsOrCallback === 'function') {
716
+ cb = optionsOrCallback;
717
+ } else if (optionsOrCallback) {
718
+ options = { ...options, ...optionsOrCallback };
719
+ }
720
+ } else {
721
+ options = urlOrOptions;
722
+ if (typeof optionsOrCallback === 'function') {
723
+ cb = optionsOrCallback;
724
+ }
725
+ }
726
+
727
+ return { options, callback: cb };
728
+ }
729
+
730
+ /**
731
+ * Create an HTTP client request
732
+ */
733
+ export function request(
734
+ urlOrOptions: string | URL | RequestOptions,
735
+ optionsOrCallback?: RequestOptions | ((res: IncomingMessage) => void),
736
+ callback?: (res: IncomingMessage) => void
737
+ ): ClientRequest {
738
+ const { options, callback: cb } = parseRequestArgs(urlOrOptions, optionsOrCallback, callback);
739
+ const req = new ClientRequest(options, 'http');
740
+ if (cb) {
741
+ req.once('response', cb as unknown as EventListener);
742
+ }
743
+ return req;
744
+ }
745
+
746
+ /**
747
+ * Make an HTTP GET request
748
+ */
749
+ export function get(
750
+ urlOrOptions: string | URL | RequestOptions,
751
+ optionsOrCallback?: RequestOptions | ((res: IncomingMessage) => void),
752
+ callback?: (res: IncomingMessage) => void
753
+ ): ClientRequest {
754
+ const { options, callback: cb } = parseRequestArgs(urlOrOptions, optionsOrCallback, callback);
755
+ const req = new ClientRequest({ ...options, method: 'GET' }, 'http');
756
+ if (cb) {
757
+ req.once('response', cb as unknown as EventListener);
758
+ }
759
+ req.end();
760
+ return req;
761
+ }
762
+
763
+ /**
764
+ * Internal: create client request with specified protocol
765
+ * Used by https module
766
+ */
767
+ export function _createClientRequest(
768
+ urlOrOptions: string | URL | RequestOptions,
769
+ optionsOrCallback: RequestOptions | ((res: IncomingMessage) => void) | undefined,
770
+ callback: ((res: IncomingMessage) => void) | undefined,
771
+ protocol: 'http' | 'https'
772
+ ): ClientRequest {
773
+ const { options, callback: cb } = parseRequestArgs(urlOrOptions, optionsOrCallback, callback);
774
+ const req = new ClientRequest(options, protocol);
775
+ if (cb) {
776
+ req.once('response', cb as unknown as EventListener);
777
+ }
778
+ return req;
779
+ }
780
+
781
+ /**
782
+ * Server registry for tracking listening servers
783
+ * Used by server bridge to route requests
784
+ */
785
+ export type ServerRegistryCallback = (port: number, server: Server) => void;
786
+
787
+ const serverRegistry = new Map<number, Server>();
788
+ let onServerListenCallback: ServerRegistryCallback | null = null;
789
+ let onServerCloseCallback: ((port: number) => void) | null = null;
790
+
791
+ export function _registerServer(port: number, server: Server): void {
792
+ serverRegistry.set(port, server);
793
+ if (onServerListenCallback) {
794
+ onServerListenCallback(port, server);
795
+ }
796
+ }
797
+
798
+ export function _unregisterServer(port: number): void {
799
+ serverRegistry.delete(port);
800
+ if (onServerCloseCallback) {
801
+ onServerCloseCallback(port);
802
+ }
803
+ }
804
+
805
+ export function getServer(port: number): Server | undefined {
806
+ return serverRegistry.get(port);
807
+ }
808
+
809
+ export function getAllServers(): Map<number, Server> {
810
+ return new Map(serverRegistry);
811
+ }
812
+
813
+ export function setServerListenCallback(callback: ServerRegistryCallback | null): void {
814
+ onServerListenCallback = callback;
815
+ }
816
+
817
+ export function setServerCloseCallback(callback: ((port: number) => void) | null): void {
818
+ onServerCloseCallback = callback;
819
+ }
820
+
821
+ /**
822
+ * HTTP Agent - manages connection persistence and reuse
823
+ * This is a stub implementation for browser environment
824
+ */
825
+ export interface AgentOptions {
826
+ keepAlive?: boolean;
827
+ keepAliveMsecs?: number;
828
+ maxSockets?: number;
829
+ maxTotalSockets?: number;
830
+ maxFreeSockets?: number;
831
+ scheduling?: 'fifo' | 'lifo';
832
+ timeout?: number;
833
+ }
834
+
835
+ export class Agent extends EventEmitter {
836
+ maxSockets: number;
837
+ maxFreeSockets: number;
838
+ maxTotalSockets: number;
839
+ sockets: Record<string, Socket[]>;
840
+ freeSockets: Record<string, Socket[]>;
841
+ requests: Record<string, IncomingMessage[]>;
842
+ options: AgentOptions;
843
+
844
+ constructor(opts?: AgentOptions) {
845
+ super();
846
+ this.options = opts || {};
847
+ this.maxSockets = opts?.maxSockets ?? Infinity;
848
+ this.maxFreeSockets = opts?.maxFreeSockets ?? 256;
849
+ this.maxTotalSockets = opts?.maxTotalSockets ?? Infinity;
850
+ this.sockets = {};
851
+ this.freeSockets = {};
852
+ this.requests = {};
853
+ }
854
+
855
+ createConnection(
856
+ _options: Record<string, unknown>,
857
+ callback?: (err: Error | null, socket: Socket) => void
858
+ ): Socket {
859
+ const socket = new Socket();
860
+ if (callback) {
861
+ callback(null, socket);
862
+ }
863
+ return socket;
864
+ }
865
+
866
+ getName(options: { host?: string; port?: number; localAddress?: string }): string {
867
+ const host = options.host || 'localhost';
868
+ const port = options.port || 80;
869
+ return `${host}:${port}:${options.localAddress || ''}`;
870
+ }
871
+
872
+ addRequest(_req: ClientRequest, _options: Record<string, unknown>): void {
873
+ // Stub - in browser we use fetch instead
874
+ }
875
+
876
+ destroy(): void {
877
+ // Clean up - stub
878
+ this.sockets = {};
879
+ this.freeSockets = {};
880
+ this.requests = {};
881
+ }
882
+ }
883
+
884
+ // Global agent instance
885
+ export const globalAgent = new Agent();
886
+
887
+ export default {
888
+ Server,
889
+ IncomingMessage,
890
+ ServerResponse,
891
+ ClientRequest,
892
+ createServer,
893
+ request,
894
+ get,
895
+ STATUS_CODES,
896
+ METHODS,
897
+ getServer,
898
+ getAllServers,
899
+ setServerListenCallback,
900
+ setServerCloseCallback,
901
+ _createClientRequest,
902
+ Agent,
903
+ globalAgent,
904
+ };