elit 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.d.ts +4 -12
- package/dist/build.d.ts.map +1 -0
- package/dist/chokidar.d.ts +7 -9
- package/dist/chokidar.d.ts.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +17 -4
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/dom.d.ts +7 -14
- package/dist/dom.d.ts.map +1 -0
- package/dist/el.d.ts +19 -191
- package/dist/el.d.ts.map +1 -0
- package/dist/fs.d.ts +35 -35
- package/dist/fs.d.ts.map +1 -0
- package/dist/hmr.d.ts +3 -3
- package/dist/hmr.d.ts.map +1 -0
- package/dist/http.d.ts +20 -22
- package/dist/http.d.ts.map +1 -0
- package/dist/https.d.ts +12 -15
- package/dist/https.d.ts.map +1 -0
- package/dist/index.d.ts +10 -629
- package/dist/index.d.ts.map +1 -0
- package/dist/mime-types.d.ts +9 -9
- package/dist/mime-types.d.ts.map +1 -0
- package/dist/path.d.ts +22 -19
- package/dist/path.d.ts.map +1 -0
- package/dist/router.d.ts +10 -17
- package/dist/router.d.ts.map +1 -0
- package/dist/runtime.d.ts +5 -6
- package/dist/runtime.d.ts.map +1 -0
- package/dist/server.d.ts +105 -7
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +14 -2
- package/dist/server.mjs +14 -2
- package/dist/state.d.ts +21 -27
- package/dist/state.d.ts.map +1 -0
- package/dist/style.d.ts +14 -55
- package/dist/style.d.ts.map +1 -0
- package/dist/types.d.ts +26 -240
- package/dist/types.d.ts.map +1 -0
- package/dist/ws.d.ts +14 -17
- package/dist/ws.d.ts.map +1 -0
- package/dist/wss.d.ts +16 -16
- package/dist/wss.d.ts.map +1 -0
- package/package.json +3 -2
- package/src/build.ts +337 -0
- package/src/chokidar.ts +401 -0
- package/src/cli.ts +638 -0
- package/src/config.ts +205 -0
- package/src/dom.ts +817 -0
- package/src/el.ts +164 -0
- package/src/fs.ts +727 -0
- package/src/hmr.ts +137 -0
- package/src/http.ts +775 -0
- package/src/https.ts +411 -0
- package/src/index.ts +14 -0
- package/src/mime-types.ts +222 -0
- package/src/path.ts +493 -0
- package/src/router.ts +237 -0
- package/src/runtime.ts +97 -0
- package/src/server.ts +1290 -0
- package/src/state.ts +468 -0
- package/src/style.ts +524 -0
- package/{dist/types-Du6kfwTm.d.ts → src/types.ts} +58 -141
- package/src/ws.ts +506 -0
- package/src/wss.ts +241 -0
- package/dist/build.d.mts +0 -20
- package/dist/chokidar.d.mts +0 -134
- package/dist/dom.d.mts +0 -87
- package/dist/el.d.mts +0 -207
- package/dist/fs.d.mts +0 -255
- package/dist/hmr.d.mts +0 -38
- package/dist/http.d.mts +0 -163
- package/dist/https.d.mts +0 -108
- package/dist/index.d.mts +0 -629
- package/dist/mime-types.d.mts +0 -48
- package/dist/path.d.mts +0 -163
- package/dist/router.d.mts +0 -47
- package/dist/runtime.d.mts +0 -97
- package/dist/server.d.mts +0 -7
- package/dist/state.d.mts +0 -111
- package/dist/style.d.mts +0 -159
- package/dist/types-C0nGi6MX.d.mts +0 -346
- package/dist/types.d.mts +0 -452
- package/dist/ws.d.mts +0 -195
- package/dist/wss.d.mts +0 -108
package/src/http.ts
ADDED
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP module with unified API across runtimes
|
|
3
|
+
* Ultra-optimized for maximum performance across Node.js, Bun, and Deno
|
|
4
|
+
*
|
|
5
|
+
* Performance optimizations:
|
|
6
|
+
* - Bun fast path: Zero class instantiation (object literals only)
|
|
7
|
+
* - Eliminated EventEmitter overhead for Bun/Deno
|
|
8
|
+
* - Zero-copy headers conversion
|
|
9
|
+
* - Inline response creation
|
|
10
|
+
* - Reduced object allocations
|
|
11
|
+
* - Direct closure capture (no resolver indirection)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { EventEmitter } from 'node:events';
|
|
15
|
+
import { runtime, isBun, isDeno, isNode } from './runtime';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Helper: Check if running on Node.js (eliminates duplication in runtime checks)
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Helper: Queue callback (eliminates duplication in callback handling)
|
|
24
|
+
*/
|
|
25
|
+
function queueCallback(callback?: () => void): void {
|
|
26
|
+
if (callback) queueMicrotask(callback);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Helper: Convert headers to HeadersInit (eliminates duplication in Response creation)
|
|
31
|
+
*/
|
|
32
|
+
function headersToInit(headers: OutgoingHttpHeaders): HeadersInit {
|
|
33
|
+
const result: HeadersInit = {};
|
|
34
|
+
for (const key in headers) {
|
|
35
|
+
const value = headers[key];
|
|
36
|
+
result[key] = Array.isArray(value) ? value.join(', ') : String(value);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Helper: Create address object (eliminates duplication in address() method)
|
|
43
|
+
*/
|
|
44
|
+
function createAddress(port: number, address: string, family = 'IPv4'): { port: number; family: string; address: string } {
|
|
45
|
+
return { port, family, address };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Helper: Create error Response (eliminates duplication in error handling)
|
|
50
|
+
*/
|
|
51
|
+
function createErrorResponse(): Response {
|
|
52
|
+
return new Response('Internal Server Error', { status: 500 });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Helper: Emit listening and queue callback (eliminates duplication in Bun/Deno listen)
|
|
57
|
+
*/
|
|
58
|
+
function emitListeningWithCallback(server: Server, callback?: () => void): void {
|
|
59
|
+
server._listening = true;
|
|
60
|
+
server.emit('listening');
|
|
61
|
+
queueCallback(callback);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Helper: Close server and emit events (eliminates duplication in Bun/Deno close)
|
|
66
|
+
*/
|
|
67
|
+
function closeAndEmit(server: Server, callback?: (err?: Error) => void): void {
|
|
68
|
+
server._listening = false;
|
|
69
|
+
server.emit('close');
|
|
70
|
+
if (callback) queueMicrotask(() => callback());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Lazy-load native modules for Node.js
|
|
74
|
+
let http: any, https: any;
|
|
75
|
+
|
|
76
|
+
// Initialize immediately for Node.js (synchronous require)
|
|
77
|
+
if (isNode && typeof process !== 'undefined') {
|
|
78
|
+
try {
|
|
79
|
+
http = require('node:http');
|
|
80
|
+
https = require('node:https');
|
|
81
|
+
} catch (e) {
|
|
82
|
+
// Fallback for older Node versions
|
|
83
|
+
http = require('http');
|
|
84
|
+
https = require('https');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* HTTP Methods
|
|
90
|
+
*/
|
|
91
|
+
export const METHODS = [
|
|
92
|
+
'GET', 'POST', 'PUT', 'DELETE', 'PATCH',
|
|
93
|
+
'HEAD', 'OPTIONS', 'CONNECT', 'TRACE'
|
|
94
|
+
] as const;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* HTTP Status Codes (compact object)
|
|
98
|
+
*/
|
|
99
|
+
export const STATUS_CODES: Record<number, string> = {
|
|
100
|
+
100: 'Continue', 101: 'Switching Protocols', 102: 'Processing',
|
|
101
|
+
200: 'OK', 201: 'Created', 202: 'Accepted', 203: 'Non-Authoritative Information',
|
|
102
|
+
204: 'No Content', 205: 'Reset Content', 206: 'Partial Content',
|
|
103
|
+
300: 'Multiple Choices', 301: 'Moved Permanently', 302: 'Found',
|
|
104
|
+
303: 'See Other', 304: 'Not Modified', 307: 'Temporary Redirect', 308: 'Permanent Redirect',
|
|
105
|
+
400: 'Bad Request', 401: 'Unauthorized', 402: 'Payment Required', 403: 'Forbidden',
|
|
106
|
+
404: 'Not Found', 405: 'Method Not Allowed', 406: 'Not Acceptable',
|
|
107
|
+
407: 'Proxy Authentication Required', 408: 'Request Timeout', 409: 'Conflict',
|
|
108
|
+
410: 'Gone', 411: 'Length Required', 412: 'Precondition Failed',
|
|
109
|
+
413: 'Payload Too Large', 414: 'URI Too Long', 415: 'Unsupported Media Type',
|
|
110
|
+
416: 'Range Not Satisfiable', 417: 'Expectation Failed', 418: "I'm a teapot",
|
|
111
|
+
422: 'Unprocessable Entity', 425: 'Too Early', 426: 'Upgrade Required',
|
|
112
|
+
428: 'Precondition Required', 429: 'Too Many Requests',
|
|
113
|
+
431: 'Request Header Fields Too Large', 451: 'Unavailable For Legal Reasons',
|
|
114
|
+
500: 'Internal Server Error', 501: 'Not Implemented', 502: 'Bad Gateway',
|
|
115
|
+
503: 'Service Unavailable', 504: 'Gateway Timeout', 505: 'HTTP Version Not Supported',
|
|
116
|
+
506: 'Variant Also Negotiates', 507: 'Insufficient Storage', 508: 'Loop Detected',
|
|
117
|
+
510: 'Not Extended', 511: 'Network Authentication Required',
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* HTTP Headers type
|
|
122
|
+
*/
|
|
123
|
+
export type IncomingHttpHeaders = Record<string, string | string[] | undefined>;
|
|
124
|
+
export type OutgoingHttpHeaders = Record<string, string | string[] | number>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* IncomingMessage - Ultra-optimized for zero-copy operations
|
|
128
|
+
*/
|
|
129
|
+
export class IncomingMessage extends EventEmitter {
|
|
130
|
+
public method: string;
|
|
131
|
+
public url: string;
|
|
132
|
+
public headers: IncomingHttpHeaders;
|
|
133
|
+
public statusCode?: number;
|
|
134
|
+
public statusMessage?: string;
|
|
135
|
+
public httpVersion: string = '1.1';
|
|
136
|
+
public rawHeaders: string[] = [];
|
|
137
|
+
public socket: any;
|
|
138
|
+
|
|
139
|
+
private _req: any;
|
|
140
|
+
|
|
141
|
+
constructor(req: any) {
|
|
142
|
+
super();
|
|
143
|
+
this._req = req;
|
|
144
|
+
|
|
145
|
+
if (isNode) {
|
|
146
|
+
// Direct property access (fastest)
|
|
147
|
+
this.method = req.method;
|
|
148
|
+
this.url = req.url;
|
|
149
|
+
this.headers = req.headers;
|
|
150
|
+
this.statusCode = req.statusCode;
|
|
151
|
+
this.statusMessage = req.statusMessage;
|
|
152
|
+
this.httpVersion = req.httpVersion;
|
|
153
|
+
this.rawHeaders = req.rawHeaders;
|
|
154
|
+
this.socket = req.socket;
|
|
155
|
+
} else {
|
|
156
|
+
// Bun/Deno Request object - zero-copy parsing
|
|
157
|
+
this.method = req.method;
|
|
158
|
+
const urlObj = new URL(req.url);
|
|
159
|
+
this.url = urlObj.pathname + urlObj.search;
|
|
160
|
+
|
|
161
|
+
// Direct headers reference (zero-copy)
|
|
162
|
+
this.headers = req.headers;
|
|
163
|
+
this.rawHeaders = [];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async text(): Promise<string> {
|
|
168
|
+
if (isNode) {
|
|
169
|
+
return new Promise((resolve, reject) => {
|
|
170
|
+
const chunks: Buffer[] = [];
|
|
171
|
+
this._req.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
172
|
+
this._req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
173
|
+
this._req.on('error', reject);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// Bun/Deno - direct text() call
|
|
177
|
+
return this._req.text();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async json(): Promise<any> {
|
|
181
|
+
if (isNode) {
|
|
182
|
+
const text = await this.text();
|
|
183
|
+
return JSON.parse(text);
|
|
184
|
+
}
|
|
185
|
+
// Bun/Deno - optimized json() method
|
|
186
|
+
return this._req.json();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* ServerResponse - Ultra-optimized write operations
|
|
192
|
+
*/
|
|
193
|
+
export class ServerResponse extends EventEmitter {
|
|
194
|
+
public statusCode: number = 200;
|
|
195
|
+
public statusMessage: string = 'OK';
|
|
196
|
+
public headersSent: boolean = false;
|
|
197
|
+
|
|
198
|
+
private _headers: OutgoingHttpHeaders;
|
|
199
|
+
private _body: string = '';
|
|
200
|
+
private _resolve?: (response: Response) => void;
|
|
201
|
+
private _finished: boolean = false;
|
|
202
|
+
private _nodeRes?: any;
|
|
203
|
+
|
|
204
|
+
constructor(_req?: IncomingMessage, nodeRes?: any) {
|
|
205
|
+
super();
|
|
206
|
+
this._nodeRes = nodeRes;
|
|
207
|
+
// Use Object.create(null) for faster property access
|
|
208
|
+
this._headers = Object.create(null);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
setHeader(name: string, value: string | string[] | number): this {
|
|
212
|
+
if (this.headersSent) {
|
|
213
|
+
throw new Error('Cannot set headers after they are sent');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (isNode && this._nodeRes) {
|
|
217
|
+
this._nodeRes.setHeader(name, value);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this._headers[name.toLowerCase()] = value;
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
getHeader(name: string): string | string[] | number | undefined {
|
|
225
|
+
if (isNode && this._nodeRes) {
|
|
226
|
+
return this._nodeRes.getHeader(name);
|
|
227
|
+
}
|
|
228
|
+
return this._headers[name.toLowerCase()];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
getHeaders(): OutgoingHttpHeaders {
|
|
232
|
+
if (isNode && this._nodeRes) {
|
|
233
|
+
return this._nodeRes.getHeaders();
|
|
234
|
+
}
|
|
235
|
+
return { ...this._headers };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
getHeaderNames(): string[] {
|
|
239
|
+
if (isNode && this._nodeRes) {
|
|
240
|
+
return this._nodeRes.getHeaderNames();
|
|
241
|
+
}
|
|
242
|
+
return Object.keys(this._headers);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
hasHeader(name: string): boolean {
|
|
246
|
+
if (isNode && this._nodeRes) {
|
|
247
|
+
return this._nodeRes.hasHeader(name);
|
|
248
|
+
}
|
|
249
|
+
return name.toLowerCase() in this._headers;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
removeHeader(name: string): void {
|
|
253
|
+
if (this.headersSent) {
|
|
254
|
+
throw new Error('Cannot remove headers after they are sent');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (isNode && this._nodeRes) {
|
|
258
|
+
this._nodeRes.removeHeader(name);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
delete this._headers[name.toLowerCase()];
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
writeHead(statusCode: number, statusMessage?: string | OutgoingHttpHeaders, headers?: OutgoingHttpHeaders): this {
|
|
265
|
+
if (this.headersSent) {
|
|
266
|
+
throw new Error('Cannot write headers after they are sent');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.statusCode = statusCode;
|
|
270
|
+
|
|
271
|
+
if (typeof statusMessage === 'string') {
|
|
272
|
+
this.statusMessage = statusMessage;
|
|
273
|
+
if (headers) {
|
|
274
|
+
for (const key in headers) {
|
|
275
|
+
this.setHeader(key, headers[key]!);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} else if (statusMessage) {
|
|
279
|
+
for (const key in statusMessage) {
|
|
280
|
+
this.setHeader(key, statusMessage[key]!);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (isNode && this._nodeRes) {
|
|
285
|
+
if (typeof statusMessage === 'string') {
|
|
286
|
+
this._nodeRes.writeHead(statusCode, statusMessage, headers);
|
|
287
|
+
} else {
|
|
288
|
+
this._nodeRes.writeHead(statusCode, statusMessage);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
this.headersSent = true;
|
|
293
|
+
return this;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
write(chunk: any, encoding?: BufferEncoding | (() => void), callback?: () => void): boolean {
|
|
297
|
+
if (typeof encoding === 'function') {
|
|
298
|
+
callback = encoding;
|
|
299
|
+
encoding = 'utf8';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (!this.headersSent) {
|
|
303
|
+
this.writeHead(this.statusCode);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (isNode && this._nodeRes) {
|
|
307
|
+
return this._nodeRes.write(chunk, encoding, callback);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this._body += chunk;
|
|
311
|
+
queueCallback(callback);
|
|
312
|
+
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
end(chunk?: any, encoding?: BufferEncoding | (() => void), callback?: () => void): this {
|
|
317
|
+
if (this._finished) {
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (typeof chunk === 'function') {
|
|
322
|
+
callback = chunk;
|
|
323
|
+
chunk = undefined;
|
|
324
|
+
} else if (typeof encoding === 'function') {
|
|
325
|
+
callback = encoding;
|
|
326
|
+
encoding = 'utf8';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (chunk !== undefined) {
|
|
330
|
+
this.write(chunk, encoding as BufferEncoding);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (!this.headersSent) {
|
|
334
|
+
this.writeHead(this.statusCode);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
this._finished = true;
|
|
338
|
+
|
|
339
|
+
if (isNode && this._nodeRes) {
|
|
340
|
+
// Don't pass chunk to end() since we already wrote it via this.write() above
|
|
341
|
+
this._nodeRes.end(callback);
|
|
342
|
+
this.emit('finish');
|
|
343
|
+
} else {
|
|
344
|
+
// Bun/Deno - ultra-optimized inline Response creation
|
|
345
|
+
const response = new Response(this._body, {
|
|
346
|
+
status: this.statusCode,
|
|
347
|
+
statusText: this.statusMessage,
|
|
348
|
+
headers: headersToInit(this._headers),
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
if (this._resolve) {
|
|
352
|
+
this._resolve(response);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
queueCallback(callback);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
_setResolver(resolve: (response: Response) => void): void {
|
|
362
|
+
this._resolve = resolve;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Server - Optimized for each runtime
|
|
368
|
+
*/
|
|
369
|
+
export class Server extends EventEmitter {
|
|
370
|
+
private nativeServer?: any;
|
|
371
|
+
private requestListener?: RequestListener;
|
|
372
|
+
public _listening: boolean = false;
|
|
373
|
+
|
|
374
|
+
constructor(requestListener?: RequestListener) {
|
|
375
|
+
super();
|
|
376
|
+
this.requestListener = requestListener;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
listen(port?: number, hostname?: string, backlog?: number, listeningListener?: () => void): this;
|
|
380
|
+
listen(port?: number, hostname?: string, listeningListener?: () => void): this;
|
|
381
|
+
listen(port?: number, listeningListener?: () => void): this;
|
|
382
|
+
listen(options?: { port?: number; hostname?: string; backlog?: number }, listeningListener?: () => void): this;
|
|
383
|
+
listen(...args: any[]): this {
|
|
384
|
+
let port = 3000;
|
|
385
|
+
let hostname = '0.0.0.0';
|
|
386
|
+
let callback: (() => void) | undefined;
|
|
387
|
+
|
|
388
|
+
// Optimized argument parsing
|
|
389
|
+
const firstArg = args[0];
|
|
390
|
+
if (typeof firstArg === 'number') {
|
|
391
|
+
port = firstArg;
|
|
392
|
+
const secondArg = args[1];
|
|
393
|
+
if (typeof secondArg === 'string') {
|
|
394
|
+
hostname = secondArg;
|
|
395
|
+
callback = args[2] || args[3];
|
|
396
|
+
} else if (typeof secondArg === 'function') {
|
|
397
|
+
callback = secondArg;
|
|
398
|
+
}
|
|
399
|
+
} else if (firstArg && typeof firstArg === 'object') {
|
|
400
|
+
port = firstArg.port || 3000;
|
|
401
|
+
hostname = firstArg.hostname || '0.0.0.0';
|
|
402
|
+
callback = args[1];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const self = this;
|
|
406
|
+
|
|
407
|
+
if (isNode) {
|
|
408
|
+
// Node.js - delegate directly to native http
|
|
409
|
+
this.nativeServer = http.createServer((req: any, res: any) => {
|
|
410
|
+
const incomingMessage = new IncomingMessage(req);
|
|
411
|
+
const serverResponse = new ServerResponse(incomingMessage, res);
|
|
412
|
+
|
|
413
|
+
if (self.requestListener) {
|
|
414
|
+
self.requestListener(incomingMessage, serverResponse);
|
|
415
|
+
} else {
|
|
416
|
+
self.emit('request', incomingMessage, serverResponse);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Forward upgrade event for WebSocket support
|
|
421
|
+
this.nativeServer.on('upgrade', (req: any, socket: any, head: any) => {
|
|
422
|
+
self.emit('upgrade', req, socket, head);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
this.nativeServer.listen(port, hostname, () => {
|
|
426
|
+
this._listening = true;
|
|
427
|
+
this.emit('listening');
|
|
428
|
+
if (callback) callback();
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
this.nativeServer.on('error', (err: Error) => this.emit('error', err));
|
|
432
|
+
this.nativeServer.on('close', () => {
|
|
433
|
+
this._listening = false;
|
|
434
|
+
this.emit('close');
|
|
435
|
+
});
|
|
436
|
+
} else if (isBun) {
|
|
437
|
+
// Bun - ULTRA-OPTIMIZED direct fast path (zero wrapper overhead)
|
|
438
|
+
// @ts-ignore
|
|
439
|
+
this.nativeServer = Bun.serve({
|
|
440
|
+
port,
|
|
441
|
+
hostname,
|
|
442
|
+
fetch: (req: Request) => {
|
|
443
|
+
// Fast path: Create minimal context object to avoid wrapper classes
|
|
444
|
+
const urlObj = new URL(req.url);
|
|
445
|
+
const pathname = urlObj.pathname + urlObj.search;
|
|
446
|
+
|
|
447
|
+
// Ultra-lightweight response builder (no class instantiation)
|
|
448
|
+
let statusCode = 200;
|
|
449
|
+
let statusMessage = 'OK';
|
|
450
|
+
let body = '';
|
|
451
|
+
const headers: Record<string, string> = Object.create(null);
|
|
452
|
+
let responseReady = false;
|
|
453
|
+
|
|
454
|
+
// Minimal IncomingMessage-compatible object (object literal is faster than class)
|
|
455
|
+
const incomingMessage: any = {
|
|
456
|
+
method: req.method,
|
|
457
|
+
url: pathname,
|
|
458
|
+
headers: req.headers,
|
|
459
|
+
httpVersion: '1.1',
|
|
460
|
+
rawHeaders: [],
|
|
461
|
+
_req: req,
|
|
462
|
+
text: () => req.text(),
|
|
463
|
+
json: () => req.json(),
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
// Minimal ServerResponse-compatible object (inline methods, no inheritance)
|
|
467
|
+
const serverResponse: any = {
|
|
468
|
+
statusCode: 200,
|
|
469
|
+
statusMessage: 'OK',
|
|
470
|
+
headersSent: false,
|
|
471
|
+
_headers: headers,
|
|
472
|
+
|
|
473
|
+
setHeader(name: string, value: string | string[] | number) {
|
|
474
|
+
headers[name.toLowerCase()] = Array.isArray(value) ? value.join(', ') : String(value);
|
|
475
|
+
return this;
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
getHeader(name: string) {
|
|
479
|
+
return headers[name.toLowerCase()];
|
|
480
|
+
},
|
|
481
|
+
|
|
482
|
+
getHeaders() {
|
|
483
|
+
return { ...headers };
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
writeHead(status: number, arg2?: any, arg3?: any) {
|
|
487
|
+
statusCode = status;
|
|
488
|
+
this.statusCode = status;
|
|
489
|
+
this.headersSent = true;
|
|
490
|
+
|
|
491
|
+
if (typeof arg2 === 'string') {
|
|
492
|
+
statusMessage = arg2;
|
|
493
|
+
this.statusMessage = arg2;
|
|
494
|
+
if (arg3) {
|
|
495
|
+
for (const key in arg3) {
|
|
496
|
+
headers[key.toLowerCase()] = arg3[key];
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
} else if (arg2) {
|
|
500
|
+
for (const key in arg2) {
|
|
501
|
+
headers[key.toLowerCase()] = arg2[key];
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return this;
|
|
505
|
+
},
|
|
506
|
+
|
|
507
|
+
write(chunk: any) {
|
|
508
|
+
if (!this.headersSent) {
|
|
509
|
+
this.writeHead(statusCode);
|
|
510
|
+
}
|
|
511
|
+
body += chunk;
|
|
512
|
+
return true;
|
|
513
|
+
},
|
|
514
|
+
|
|
515
|
+
end(chunk?: any) {
|
|
516
|
+
if (chunk !== undefined) {
|
|
517
|
+
this.write(chunk);
|
|
518
|
+
}
|
|
519
|
+
if (!this.headersSent) {
|
|
520
|
+
this.writeHead(statusCode);
|
|
521
|
+
}
|
|
522
|
+
responseReady = true;
|
|
523
|
+
return this;
|
|
524
|
+
},
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
// Execute handler
|
|
528
|
+
if (self.requestListener) {
|
|
529
|
+
self.requestListener(incomingMessage, serverResponse);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Inline Response creation (fastest path - no function calls)
|
|
533
|
+
if (responseReady) {
|
|
534
|
+
return new Response(body, {
|
|
535
|
+
status: statusCode,
|
|
536
|
+
statusText: statusMessage,
|
|
537
|
+
headers: headers as HeadersInit,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Fallback for async (rare case)
|
|
542
|
+
return new Promise<Response>((resolve) => {
|
|
543
|
+
serverResponse.end = (chunk?: any) => {
|
|
544
|
+
if (chunk !== undefined) {
|
|
545
|
+
body += chunk;
|
|
546
|
+
}
|
|
547
|
+
resolve(new Response(body, {
|
|
548
|
+
status: statusCode,
|
|
549
|
+
statusText: statusMessage,
|
|
550
|
+
headers: headers as HeadersInit,
|
|
551
|
+
}));
|
|
552
|
+
};
|
|
553
|
+
});
|
|
554
|
+
},
|
|
555
|
+
error: createErrorResponse,
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
emitListeningWithCallback(this, callback);
|
|
559
|
+
} else if (isDeno) {
|
|
560
|
+
// Deno - use Deno.serve()
|
|
561
|
+
// @ts-ignore
|
|
562
|
+
this.nativeServer = Deno.serve({
|
|
563
|
+
port,
|
|
564
|
+
hostname,
|
|
565
|
+
handler: (req: Request) => {
|
|
566
|
+
return new Promise<Response>((resolve) => {
|
|
567
|
+
const incomingMessage = new IncomingMessage(req);
|
|
568
|
+
const serverResponse = new ServerResponse();
|
|
569
|
+
|
|
570
|
+
serverResponse._setResolver(resolve);
|
|
571
|
+
|
|
572
|
+
if (self.requestListener) {
|
|
573
|
+
self.requestListener(incomingMessage, serverResponse);
|
|
574
|
+
} else {
|
|
575
|
+
self.emit('request', incomingMessage, serverResponse);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
},
|
|
579
|
+
onError: (error: Error) => {
|
|
580
|
+
this.emit('error', error);
|
|
581
|
+
return createErrorResponse();
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
emitListeningWithCallback(this, callback);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return this;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
close(callback?: (err?: Error) => void): this {
|
|
592
|
+
if (!this.nativeServer) {
|
|
593
|
+
if (callback) queueMicrotask(() => callback());
|
|
594
|
+
return this;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (isNode) {
|
|
598
|
+
this.nativeServer.close(callback);
|
|
599
|
+
} else if (isBun) {
|
|
600
|
+
this.nativeServer.stop();
|
|
601
|
+
closeAndEmit(this, callback);
|
|
602
|
+
} else if (isDeno) {
|
|
603
|
+
// @ts-ignore
|
|
604
|
+
this.nativeServer.shutdown();
|
|
605
|
+
closeAndEmit(this, callback);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return this;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
address(): { port: number; family: string; address: string } | null {
|
|
612
|
+
if (!this.nativeServer) return null;
|
|
613
|
+
|
|
614
|
+
if (isNode) {
|
|
615
|
+
const addr = this.nativeServer.address();
|
|
616
|
+
if (!addr) return null;
|
|
617
|
+
if (typeof addr === 'string') {
|
|
618
|
+
return createAddress(0, addr, 'unix');
|
|
619
|
+
}
|
|
620
|
+
return addr;
|
|
621
|
+
} else if (isBun) {
|
|
622
|
+
return createAddress(this.nativeServer.port, this.nativeServer.hostname);
|
|
623
|
+
} else if (isDeno) {
|
|
624
|
+
// @ts-ignore
|
|
625
|
+
const addr = this.nativeServer.addr;
|
|
626
|
+
return createAddress(addr.port, addr.hostname);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
get listening(): boolean {
|
|
633
|
+
return this._listening;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Request listener type
|
|
639
|
+
*/
|
|
640
|
+
export type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Request options
|
|
644
|
+
*/
|
|
645
|
+
export interface RequestOptions {
|
|
646
|
+
method?: string;
|
|
647
|
+
headers?: OutgoingHttpHeaders;
|
|
648
|
+
timeout?: number;
|
|
649
|
+
signal?: AbortSignal;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Server options
|
|
654
|
+
*/
|
|
655
|
+
export interface ServerOptions {
|
|
656
|
+
IncomingMessage?: typeof IncomingMessage;
|
|
657
|
+
ServerResponse?: typeof ServerResponse;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Client request - lightweight wrapper
|
|
662
|
+
*/
|
|
663
|
+
export class ClientRequest extends EventEmitter {
|
|
664
|
+
constructor(_url: string | URL, _options: RequestOptions = {}) {
|
|
665
|
+
super();
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
write(_chunk: any): boolean {
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
end(callback?: () => void): void {
|
|
673
|
+
queueCallback(callback);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* HTTP Agent
|
|
679
|
+
*/
|
|
680
|
+
export class Agent {
|
|
681
|
+
constructor(public options?: any) { }
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Create HTTP server
|
|
686
|
+
*/
|
|
687
|
+
export function createServer(requestListener?: RequestListener): Server;
|
|
688
|
+
export function createServer(options: ServerOptions, requestListener?: RequestListener): Server;
|
|
689
|
+
export function createServer(
|
|
690
|
+
optionsOrListener?: ServerOptions | RequestListener,
|
|
691
|
+
requestListener?: RequestListener
|
|
692
|
+
): Server {
|
|
693
|
+
return new Server(typeof optionsOrListener === 'function' ? optionsOrListener : requestListener);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Make HTTP request - optimized per runtime
|
|
698
|
+
*/
|
|
699
|
+
export function request(url: string | URL, options?: RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest {
|
|
700
|
+
const urlString = typeof url === 'string' ? url : url.toString();
|
|
701
|
+
const req = new ClientRequest(urlString, options);
|
|
702
|
+
|
|
703
|
+
if (isNode) {
|
|
704
|
+
const urlObj = new URL(urlString);
|
|
705
|
+
const client = urlObj.protocol === 'https:' ? https : http;
|
|
706
|
+
|
|
707
|
+
const nodeReq = client.request(urlString, {
|
|
708
|
+
method: options?.method || 'GET',
|
|
709
|
+
headers: options?.headers,
|
|
710
|
+
timeout: options?.timeout,
|
|
711
|
+
signal: options?.signal,
|
|
712
|
+
}, (res: any) => {
|
|
713
|
+
const incomingMessage = new IncomingMessage(res);
|
|
714
|
+
if (callback) callback(incomingMessage);
|
|
715
|
+
req.emit('response', incomingMessage);
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
nodeReq.on('error', (error: Error) => req.emit('error', error));
|
|
719
|
+
nodeReq.end();
|
|
720
|
+
} else {
|
|
721
|
+
// Bun/Deno - use optimized fetch
|
|
722
|
+
queueMicrotask(async () => {
|
|
723
|
+
try {
|
|
724
|
+
const response = await fetch(urlString, {
|
|
725
|
+
method: options?.method || 'GET',
|
|
726
|
+
headers: options?.headers as HeadersInit,
|
|
727
|
+
signal: options?.signal,
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
const fetchRequest = new Request(urlString);
|
|
731
|
+
const incomingMessage = new IncomingMessage(fetchRequest);
|
|
732
|
+
incomingMessage.statusCode = response.status;
|
|
733
|
+
incomingMessage.statusMessage = response.statusText;
|
|
734
|
+
|
|
735
|
+
if (callback) callback(incomingMessage);
|
|
736
|
+
req.emit('response', incomingMessage);
|
|
737
|
+
} catch (error) {
|
|
738
|
+
req.emit('error', error);
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return req;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Make HTTP GET request
|
|
748
|
+
*/
|
|
749
|
+
export function get(url: string | URL, options?: RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest {
|
|
750
|
+
return request(url, { ...options, method: 'GET' }, callback);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Get current runtime
|
|
755
|
+
*/
|
|
756
|
+
export function getRuntime(): 'node' | 'bun' | 'deno' {
|
|
757
|
+
return runtime;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Default export
|
|
762
|
+
*/
|
|
763
|
+
export default {
|
|
764
|
+
createServer,
|
|
765
|
+
request,
|
|
766
|
+
get,
|
|
767
|
+
Server,
|
|
768
|
+
IncomingMessage,
|
|
769
|
+
ServerResponse,
|
|
770
|
+
Agent,
|
|
771
|
+
ClientRequest,
|
|
772
|
+
METHODS,
|
|
773
|
+
STATUS_CODES,
|
|
774
|
+
getRuntime,
|
|
775
|
+
};
|