@forklaunch/express 0.7.12 → 0.8.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.
- package/lib/index.d.mts +111 -120
- package/lib/index.d.ts +111 -120
- package/lib/index.js +2105 -134
- package/lib/index.mjs +2101 -129
- package/package.json +12 -10
package/lib/index.js
CHANGED
@@ -37,7 +37,7 @@ __export(index_exports, {
|
|
37
37
|
module.exports = __toCommonJS(index_exports);
|
38
38
|
|
39
39
|
// src/expressApplication.ts
|
40
|
-
var
|
40
|
+
var import_common4 = require("@forklaunch/common");
|
41
41
|
var import_http3 = require("@forklaunch/core/http");
|
42
42
|
var import_zod = require("@forklaunch/validator/zod");
|
43
43
|
var import_express_api_reference = require("@scalar/express-api-reference");
|
@@ -45,8 +45,1878 @@ var import_crypto = __toESM(require("crypto"));
|
|
45
45
|
var import_express2 = __toESM(require("express"));
|
46
46
|
var import_swagger_ui_express = __toESM(require("swagger-ui-express"));
|
47
47
|
|
48
|
-
// src/
|
48
|
+
// src/cluster/bun.cluster.ts
|
49
|
+
var import_node_cluster = __toESM(require("cluster"));
|
50
|
+
var import_node_os = __toESM(require("os"));
|
51
|
+
|
52
|
+
// src/cluster/bun.serve.shim.ts
|
53
|
+
var crypto = __toESM(require("crypto"));
|
54
|
+
var import_node_events = require("events");
|
55
|
+
var path = __toESM(require("path"));
|
56
|
+
var import_node_stream = require("stream");
|
57
|
+
var import_range_parser = __toESM(require("range-parser"));
|
58
|
+
|
59
|
+
// src/cluster/bun.socket.shim.ts
|
60
|
+
var import_stream = require("stream");
|
61
|
+
var BunSocketShim = class extends import_stream.Duplex {
|
62
|
+
remoteAddress;
|
63
|
+
remotePort;
|
64
|
+
remoteFamily;
|
65
|
+
localAddress;
|
66
|
+
localPort;
|
67
|
+
localFamily;
|
68
|
+
bytesRead = 0;
|
69
|
+
bytesWritten = 0;
|
70
|
+
connecting = false;
|
71
|
+
pending = false;
|
72
|
+
timeout;
|
73
|
+
readyState = "closed";
|
74
|
+
bufferSize = 0;
|
75
|
+
autoSelectFamilyAttemptedAddresses = [];
|
76
|
+
_destroyed = false;
|
77
|
+
_socketTimeoutId;
|
78
|
+
_abortController;
|
79
|
+
_request;
|
80
|
+
_responseWriter;
|
81
|
+
constructor(options2 = {}) {
|
82
|
+
super({
|
83
|
+
allowHalfOpen: false,
|
84
|
+
objectMode: false
|
85
|
+
});
|
86
|
+
this.remoteAddress = options2.remoteAddress || "127.0.0.1";
|
87
|
+
this.remotePort = options2.remotePort || 0;
|
88
|
+
this.remoteFamily = "IPv4";
|
89
|
+
this.localAddress = options2.localAddress || "localhost";
|
90
|
+
this.localPort = options2.localPort || 0;
|
91
|
+
this.localFamily = "IPv4";
|
92
|
+
this._abortController = options2.abortController || new AbortController();
|
93
|
+
this._request = options2.request;
|
94
|
+
this._responseWriter = options2.responseWriter;
|
95
|
+
this.readyState = "open";
|
96
|
+
this._setupAbortHandling();
|
97
|
+
this._setupRequestReading();
|
98
|
+
}
|
99
|
+
_setupAbortHandling() {
|
100
|
+
if (this._abortController?.signal) {
|
101
|
+
this._abortController.signal.addEventListener("abort", () => {
|
102
|
+
if (!this._destroyed) {
|
103
|
+
this.destroy(new Error("Socket aborted"));
|
104
|
+
}
|
105
|
+
});
|
106
|
+
}
|
107
|
+
}
|
108
|
+
_setupRequestReading() {
|
109
|
+
if (this._request?.body) {
|
110
|
+
const reader = this._request.body.getReader();
|
111
|
+
const pump = async () => {
|
112
|
+
try {
|
113
|
+
while (!this._destroyed) {
|
114
|
+
const { done, value } = await reader.read();
|
115
|
+
if (done) break;
|
116
|
+
this.bytesRead += value.length;
|
117
|
+
this.push(Buffer.from(value));
|
118
|
+
}
|
119
|
+
this.push(null);
|
120
|
+
} catch (error) {
|
121
|
+
if (!this._destroyed) {
|
122
|
+
this.destroy(
|
123
|
+
error instanceof Error ? error : new Error(String(error))
|
124
|
+
);
|
125
|
+
}
|
126
|
+
}
|
127
|
+
};
|
128
|
+
pump();
|
129
|
+
}
|
130
|
+
}
|
131
|
+
_read(_size) {
|
132
|
+
}
|
133
|
+
_write(chunk, encoding, callback) {
|
134
|
+
try {
|
135
|
+
if (this._destroyed || !this.writable) {
|
136
|
+
callback(new Error("Socket is not writable"));
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
let buffer;
|
140
|
+
if (Buffer.isBuffer(chunk)) {
|
141
|
+
buffer = chunk;
|
142
|
+
} else if (chunk instanceof Uint8Array) {
|
143
|
+
buffer = Buffer.from(chunk);
|
144
|
+
} else {
|
145
|
+
buffer = Buffer.from(chunk, encoding);
|
146
|
+
}
|
147
|
+
this.bytesWritten += buffer.length;
|
148
|
+
if (this._responseWriter) {
|
149
|
+
this._responseWriter.write(new Uint8Array(buffer)).then(() => callback()).catch(callback);
|
150
|
+
} else {
|
151
|
+
queueMicrotask(() => callback());
|
152
|
+
}
|
153
|
+
} catch (error) {
|
154
|
+
callback(error instanceof Error ? error : new Error(String(error)));
|
155
|
+
}
|
156
|
+
}
|
157
|
+
_final(callback) {
|
158
|
+
if (this._responseWriter) {
|
159
|
+
this._responseWriter.close().then(() => callback()).catch(callback);
|
160
|
+
} else {
|
161
|
+
callback();
|
162
|
+
}
|
163
|
+
}
|
164
|
+
_destroy(error, callback) {
|
165
|
+
this._destroyed = true;
|
166
|
+
this.readyState = "closed";
|
167
|
+
this.connecting = false;
|
168
|
+
this.pending = false;
|
169
|
+
if (this._socketTimeoutId) {
|
170
|
+
clearTimeout(this._socketTimeoutId);
|
171
|
+
this._socketTimeoutId = void 0;
|
172
|
+
}
|
173
|
+
if (this._responseWriter && !this._responseWriter.closed) {
|
174
|
+
this._responseWriter.abort().catch(() => {
|
175
|
+
});
|
176
|
+
}
|
177
|
+
if (this._abortController && !this._abortController.signal.aborted) {
|
178
|
+
this._abortController.abort();
|
179
|
+
}
|
180
|
+
callback(error);
|
181
|
+
}
|
182
|
+
destroyed = this._destroyed;
|
183
|
+
destroy(error) {
|
184
|
+
if (this._destroyed) return this;
|
185
|
+
super.destroy(error);
|
186
|
+
return this;
|
187
|
+
}
|
188
|
+
destroySoon() {
|
189
|
+
this.end();
|
190
|
+
}
|
191
|
+
connect(optionsPortOrPath, hostOrConnectionListener, connectionListener) {
|
192
|
+
let port;
|
193
|
+
let host;
|
194
|
+
let listener;
|
195
|
+
if (typeof optionsPortOrPath === "number") {
|
196
|
+
port = optionsPortOrPath;
|
197
|
+
if (typeof hostOrConnectionListener === "string") {
|
198
|
+
host = hostOrConnectionListener;
|
199
|
+
listener = connectionListener;
|
200
|
+
} else if (typeof hostOrConnectionListener === "function") {
|
201
|
+
host = "localhost";
|
202
|
+
listener = hostOrConnectionListener;
|
203
|
+
} else {
|
204
|
+
host = "localhost";
|
205
|
+
}
|
206
|
+
this.remoteAddress = host;
|
207
|
+
this.remotePort = port;
|
208
|
+
this.localAddress = "localhost";
|
209
|
+
this.localPort = 0;
|
210
|
+
this.remoteFamily = "IPv4";
|
211
|
+
this.localFamily = "IPv4";
|
212
|
+
} else if (typeof optionsPortOrPath === "string") {
|
213
|
+
this.remoteAddress = optionsPortOrPath;
|
214
|
+
this.remotePort = void 0;
|
215
|
+
this.localAddress = optionsPortOrPath;
|
216
|
+
this.localPort = void 0;
|
217
|
+
this.remoteFamily = "Unix";
|
218
|
+
this.localFamily = "Unix";
|
219
|
+
listener = typeof hostOrConnectionListener === "function" ? hostOrConnectionListener : connectionListener;
|
220
|
+
} else {
|
221
|
+
const options2 = optionsPortOrPath;
|
222
|
+
if ("path" in options2) {
|
223
|
+
this.remoteAddress = options2.path;
|
224
|
+
this.remotePort = void 0;
|
225
|
+
this.localAddress = options2.path;
|
226
|
+
this.localPort = void 0;
|
227
|
+
this.remoteFamily = "Unix";
|
228
|
+
this.localFamily = "Unix";
|
229
|
+
} else {
|
230
|
+
port = options2.port;
|
231
|
+
host = options2.host || "localhost";
|
232
|
+
this.remoteAddress = host;
|
233
|
+
this.remotePort = port;
|
234
|
+
this.localAddress = options2.localAddress || "localhost";
|
235
|
+
this.localPort = options2.localPort || 0;
|
236
|
+
this.remoteFamily = typeof options2.family === "number" ? "IPv4" : options2.family || "IPv4";
|
237
|
+
this.localFamily = typeof options2.family === "number" ? "IPv4" : options2.family || "IPv4";
|
238
|
+
}
|
239
|
+
listener = typeof hostOrConnectionListener === "function" ? hostOrConnectionListener : connectionListener;
|
240
|
+
}
|
241
|
+
this.connecting = true;
|
242
|
+
this.pending = true;
|
243
|
+
this.readyState = "opening";
|
244
|
+
if (listener) {
|
245
|
+
this.once("connect", listener);
|
246
|
+
}
|
247
|
+
queueMicrotask(() => {
|
248
|
+
if (this._destroyed) return;
|
249
|
+
this.connecting = false;
|
250
|
+
this.pending = false;
|
251
|
+
this.readyState = "open";
|
252
|
+
this.remotePort = port;
|
253
|
+
this.remoteAddress = host;
|
254
|
+
this.emit("connect");
|
255
|
+
});
|
256
|
+
return this;
|
257
|
+
}
|
258
|
+
setTimeout(timeout, callback) {
|
259
|
+
if (this._socketTimeoutId) {
|
260
|
+
clearTimeout(this._socketTimeoutId);
|
261
|
+
}
|
262
|
+
this.timeout = timeout;
|
263
|
+
if (timeout > 0) {
|
264
|
+
this._socketTimeoutId = setTimeout(() => {
|
265
|
+
if (this._destroyed) return;
|
266
|
+
this.emit("timeout");
|
267
|
+
if (callback) {
|
268
|
+
try {
|
269
|
+
callback();
|
270
|
+
} catch (error) {
|
271
|
+
this.emit("error", error);
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}, timeout);
|
275
|
+
}
|
276
|
+
return this;
|
277
|
+
}
|
278
|
+
setNoDelay(_noDelay = true) {
|
279
|
+
return this;
|
280
|
+
}
|
281
|
+
setKeepAlive(enable = false, initialDelay = 0) {
|
282
|
+
return this;
|
283
|
+
}
|
284
|
+
address() {
|
285
|
+
if (!this.localAddress || !this.localPort) {
|
286
|
+
return {};
|
287
|
+
}
|
288
|
+
return {
|
289
|
+
address: this.localAddress,
|
290
|
+
family: this.localFamily || "IPv4",
|
291
|
+
port: this.localPort
|
292
|
+
};
|
293
|
+
}
|
294
|
+
unref() {
|
295
|
+
if (this._socketTimeoutId && typeof this._socketTimeoutId === "object" && "unref" in this._socketTimeoutId) {
|
296
|
+
this._socketTimeoutId.unref();
|
297
|
+
}
|
298
|
+
return this;
|
299
|
+
}
|
300
|
+
ref() {
|
301
|
+
if (this._socketTimeoutId && typeof this._socketTimeoutId === "object" && "ref" in this._socketTimeoutId) {
|
302
|
+
this._socketTimeoutId.ref();
|
303
|
+
}
|
304
|
+
return this;
|
305
|
+
}
|
306
|
+
setEncoding(encoding) {
|
307
|
+
super.setEncoding(encoding || "utf-8");
|
308
|
+
return this;
|
309
|
+
}
|
310
|
+
resetAndDestroy() {
|
311
|
+
this.destroy();
|
312
|
+
return this;
|
313
|
+
}
|
314
|
+
end(chunkOrCb, encodingOrCb, cb) {
|
315
|
+
let chunk;
|
316
|
+
let encoding;
|
317
|
+
let callback;
|
318
|
+
if (typeof chunkOrCb === "function") {
|
319
|
+
callback = chunkOrCb;
|
320
|
+
} else {
|
321
|
+
chunk = chunkOrCb;
|
322
|
+
if (typeof encodingOrCb === "function") {
|
323
|
+
callback = encodingOrCb;
|
324
|
+
} else {
|
325
|
+
encoding = encodingOrCb;
|
326
|
+
callback = cb;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
if (callback) {
|
330
|
+
this.once("finish", callback);
|
331
|
+
}
|
332
|
+
super.end(chunk, encoding || "utf-8");
|
333
|
+
return this;
|
334
|
+
}
|
335
|
+
write(chunk, encodingOrCb, cb) {
|
336
|
+
let encoding;
|
337
|
+
let callback;
|
338
|
+
if (typeof encodingOrCb === "function") {
|
339
|
+
callback = encodingOrCb;
|
340
|
+
} else {
|
341
|
+
encoding = encodingOrCb;
|
342
|
+
callback = cb;
|
343
|
+
}
|
344
|
+
return super.write(chunk, encoding || "utf-8", callback);
|
345
|
+
}
|
346
|
+
};
|
347
|
+
function createBunSocket(options2 = {}) {
|
348
|
+
return new BunSocketShim(options2);
|
349
|
+
}
|
350
|
+
function createSocketFromBunRequest(request, serverInfo) {
|
351
|
+
const url = new URL(request.url);
|
352
|
+
const forwardedFor = request.headers.get("x-forwarded-for");
|
353
|
+
const realIP = request.headers.get("x-real-ip");
|
354
|
+
const cfConnectingIP = request.headers.get("cf-connecting-ip");
|
355
|
+
const remoteAddress = forwardedFor?.split(",")[0]?.trim() || realIP || cfConnectingIP || "127.0.0.1";
|
356
|
+
return createBunSocket({
|
357
|
+
remoteAddress,
|
358
|
+
remotePort: 0,
|
359
|
+
localAddress: serverInfo.hostname,
|
360
|
+
localPort: serverInfo.port,
|
361
|
+
request
|
362
|
+
});
|
363
|
+
}
|
364
|
+
|
365
|
+
// src/cluster/bun.serve.shim.ts
|
366
|
+
function toNodeReadable(stream, signal) {
|
367
|
+
const out = new import_node_stream.PassThrough();
|
368
|
+
(async () => {
|
369
|
+
try {
|
370
|
+
if (!stream) {
|
371
|
+
out.end();
|
372
|
+
return;
|
373
|
+
}
|
374
|
+
if (signal?.aborted) {
|
375
|
+
out.destroy(new Error("Request aborted"));
|
376
|
+
return;
|
377
|
+
}
|
378
|
+
const reader = stream.getReader();
|
379
|
+
if (signal) {
|
380
|
+
signal.addEventListener("abort", () => {
|
381
|
+
reader.cancel();
|
382
|
+
out.destroy(new Error("Request aborted"));
|
383
|
+
});
|
384
|
+
}
|
385
|
+
while (true) {
|
386
|
+
const { done, value } = await reader.read();
|
387
|
+
if (done) break;
|
388
|
+
if (value) out.write(Buffer.from(value));
|
389
|
+
}
|
390
|
+
out.end();
|
391
|
+
} catch (e) {
|
392
|
+
out.destroy(e);
|
393
|
+
}
|
394
|
+
})();
|
395
|
+
return out;
|
396
|
+
}
|
397
|
+
function extMime(filePath) {
|
398
|
+
const i = filePath.lastIndexOf(".");
|
399
|
+
const ext = i >= 0 ? filePath.slice(i + 1).toLowerCase() : "";
|
400
|
+
const mimeTypes = {
|
401
|
+
html: "text/html; charset=utf-8",
|
402
|
+
htm: "text/html; charset=utf-8",
|
403
|
+
css: "text/css; charset=utf-8",
|
404
|
+
js: "text/javascript; charset=utf-8",
|
405
|
+
mjs: "text/javascript; charset=utf-8",
|
406
|
+
json: "application/json; charset=utf-8",
|
407
|
+
txt: "text/plain; charset=utf-8",
|
408
|
+
md: "text/markdown; charset=utf-8",
|
409
|
+
xml: "application/xml; charset=utf-8",
|
410
|
+
png: "image/png",
|
411
|
+
jpg: "image/jpeg",
|
412
|
+
jpeg: "image/jpeg",
|
413
|
+
gif: "image/gif",
|
414
|
+
svg: "image/svg+xml; charset=utf-8",
|
415
|
+
ico: "image/x-icon",
|
416
|
+
webp: "image/webp",
|
417
|
+
pdf: "application/pdf",
|
418
|
+
zip: "application/zip",
|
419
|
+
mp3: "audio/mpeg",
|
420
|
+
mp4: "video/mp4",
|
421
|
+
woff: "font/woff",
|
422
|
+
woff2: "font/woff2",
|
423
|
+
ttf: "font/ttf",
|
424
|
+
eot: "application/vnd.ms-fontobject"
|
425
|
+
};
|
426
|
+
return mimeTypes[ext];
|
427
|
+
}
|
428
|
+
function serializeCookie(name, value, opts = {}) {
|
429
|
+
const enc = (v) => encodeURIComponent(v);
|
430
|
+
let str = `${name}=${enc(value)}`;
|
431
|
+
if (opts.maxAge != null) str += `; Max-Age=${Math.floor(opts.maxAge)}`;
|
432
|
+
if (opts.domain) str += `; Domain=${opts.domain}`;
|
433
|
+
str += `; Path=${opts.path || "/"}`;
|
434
|
+
if (opts.expires) str += `; Expires=${opts.expires.toUTCString()}`;
|
435
|
+
if (opts.httpOnly) str += `; HttpOnly`;
|
436
|
+
if (opts.secure) str += `; Secure`;
|
437
|
+
if (opts.sameSite) {
|
438
|
+
if (typeof opts.sameSite === "boolean") {
|
439
|
+
str += `; SameSite=Strict`;
|
440
|
+
} else {
|
441
|
+
str += `; SameSite=${opts.sameSite}`;
|
442
|
+
}
|
443
|
+
}
|
444
|
+
return str;
|
445
|
+
}
|
446
|
+
function signCookie(value, secret) {
|
447
|
+
return value + "." + crypto.createHmac("sha256", secret).update(value).digest("base64url");
|
448
|
+
}
|
449
|
+
function unsignCookie(signedValue, secret) {
|
450
|
+
const lastDot = signedValue.lastIndexOf(".");
|
451
|
+
if (lastDot === -1) return false;
|
452
|
+
const value = signedValue.slice(0, lastDot);
|
453
|
+
const signature = signedValue.slice(lastDot + 1);
|
454
|
+
const expected = crypto.createHmac("sha256", secret).update(value).digest("base64url");
|
455
|
+
return signature === expected ? value : false;
|
456
|
+
}
|
457
|
+
function parseCookies(request) {
|
458
|
+
const cookieHeader = request.headers.get("cookie");
|
459
|
+
const cookies = {};
|
460
|
+
if (cookieHeader) {
|
461
|
+
cookieHeader.split(";").forEach((cookie) => {
|
462
|
+
const [name, value] = cookie.trim().split("=");
|
463
|
+
if (name && value) {
|
464
|
+
cookies[decodeURIComponent(name)] = decodeURIComponent(value);
|
465
|
+
}
|
466
|
+
});
|
467
|
+
}
|
468
|
+
return cookies;
|
469
|
+
}
|
470
|
+
function parseSignedCookies(request, secret) {
|
471
|
+
const cookies = parseCookies(request);
|
472
|
+
const signedCookies = {};
|
473
|
+
Object.entries(cookies).forEach(([name, value]) => {
|
474
|
+
if (name.startsWith("s:")) {
|
475
|
+
const cookieName = name.slice(2);
|
476
|
+
const unsigned = unsignCookie(value, secret);
|
477
|
+
if (unsigned !== false) {
|
478
|
+
signedCookies[cookieName] = unsigned;
|
479
|
+
}
|
480
|
+
}
|
481
|
+
});
|
482
|
+
return signedCookies;
|
483
|
+
}
|
484
|
+
function serveExpress(app, openTelemetryCollector, opts = {}) {
|
485
|
+
const {
|
486
|
+
port = Number(process.env.PORT || 3e3),
|
487
|
+
host = "0.0.0.0",
|
488
|
+
reusePort = false,
|
489
|
+
development = process.env.NODE_ENV !== "production",
|
490
|
+
idleTimeout,
|
491
|
+
tls: tls2,
|
492
|
+
cookieSecret = process.env.COOKIE_SECRET || "default-secret"
|
493
|
+
} = opts;
|
494
|
+
let serverClosed = false;
|
495
|
+
const server = Bun.serve({
|
496
|
+
port,
|
497
|
+
hostname: host,
|
498
|
+
reusePort,
|
499
|
+
development,
|
500
|
+
...idleTimeout ? { idleTimeout } : {},
|
501
|
+
...tls2 ? { tls: tls2 } : {},
|
502
|
+
async fetch(request) {
|
503
|
+
const url = new URL(request.url);
|
504
|
+
const headers = {};
|
505
|
+
Object.entries(request.headers).forEach(([k, v]) => {
|
506
|
+
headers[k.toLowerCase()] = v;
|
507
|
+
});
|
508
|
+
const forwardedFor = headers["x-forwarded-for"];
|
509
|
+
const ip = (forwardedFor ? Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor.split(",")[0].trim() : void 0) || headers["x-real-ip"] || headers["x-client-ip"] || "127.0.0.1";
|
510
|
+
const proto = headers["x-forwarded-proto"] || (url.protocol === "https:" ? "https" : "http");
|
511
|
+
const nodeReq = toNodeReadable(request.body);
|
512
|
+
let reqTimeoutId;
|
513
|
+
let resTimeoutId;
|
514
|
+
let socketTimeoutId;
|
515
|
+
const socket = createSocketFromBunRequest(request, {
|
516
|
+
hostname: host,
|
517
|
+
port
|
518
|
+
});
|
519
|
+
let ended = false;
|
520
|
+
const headerMap = new Headers();
|
521
|
+
let statusCode = 200;
|
522
|
+
let headersSent = false;
|
523
|
+
const resEE = new import_node_events.EventEmitter();
|
524
|
+
const pathname = url.pathname;
|
525
|
+
const searchParams = url.searchParams;
|
526
|
+
const query = Object.fromEntries(searchParams.entries());
|
527
|
+
const cookies = parseCookies(request);
|
528
|
+
const signedCookies = parseSignedCookies(request, cookieSecret);
|
529
|
+
const abort = new AbortController();
|
530
|
+
const ts = new TransformStream();
|
531
|
+
const writer = ts.writable.getWriter();
|
532
|
+
let responded = false;
|
533
|
+
let resolveResponse;
|
534
|
+
const responsePromise = new Promise(
|
535
|
+
(r) => resolveResponse = r
|
536
|
+
);
|
537
|
+
function ensureResponse() {
|
538
|
+
if (responded) return;
|
539
|
+
responded = true;
|
540
|
+
const finalHeaders = new Headers(headerMap);
|
541
|
+
if (!finalHeaders.has("X-Powered-By")) {
|
542
|
+
finalHeaders.set("X-Powered-By", "Express");
|
543
|
+
}
|
544
|
+
resolveResponse(
|
545
|
+
new Response(ts.readable, {
|
546
|
+
status: statusCode,
|
547
|
+
statusText: res.statusMessage || void 0,
|
548
|
+
headers: finalHeaders
|
549
|
+
})
|
550
|
+
);
|
551
|
+
}
|
552
|
+
function cleanup() {
|
553
|
+
Object.assign(req, {
|
554
|
+
complete: true,
|
555
|
+
destroyed: true,
|
556
|
+
closed: true
|
557
|
+
});
|
558
|
+
Object.assign(res, {
|
559
|
+
finished: true,
|
560
|
+
writableEnded: true
|
561
|
+
});
|
562
|
+
if (reqTimeoutId) {
|
563
|
+
clearTimeout(reqTimeoutId);
|
564
|
+
reqTimeoutId = void 0;
|
565
|
+
}
|
566
|
+
if (resTimeoutId) {
|
567
|
+
clearTimeout(resTimeoutId);
|
568
|
+
resTimeoutId = void 0;
|
569
|
+
}
|
570
|
+
if (socketTimeoutId) {
|
571
|
+
clearTimeout(socketTimeoutId);
|
572
|
+
socketTimeoutId = void 0;
|
573
|
+
}
|
574
|
+
if (writer && !ended) {
|
575
|
+
writer.close();
|
576
|
+
}
|
577
|
+
req.emit("end");
|
578
|
+
req.emit("close");
|
579
|
+
res.emit("close");
|
580
|
+
}
|
581
|
+
const res = Object.assign(resEE, {
|
582
|
+
statusCode,
|
583
|
+
statusMessage: "",
|
584
|
+
headersSent,
|
585
|
+
finished: false,
|
586
|
+
locals: {},
|
587
|
+
charset: "utf-8",
|
588
|
+
strictContentLength: false,
|
589
|
+
writeProcessing: () => {
|
590
|
+
},
|
591
|
+
chunkedEncoding: false,
|
592
|
+
shouldKeepAlive: true,
|
593
|
+
useChunkedEncodingByDefault: true,
|
594
|
+
sendDate: true,
|
595
|
+
connection: socket,
|
596
|
+
socket,
|
597
|
+
writableCorked: 0,
|
598
|
+
writableEnded: false,
|
599
|
+
writableFinished: false,
|
600
|
+
writableHighWaterMark: 16384,
|
601
|
+
writableLength: 0,
|
602
|
+
writableObjectMode: false,
|
603
|
+
destroyed: false,
|
604
|
+
closed: false,
|
605
|
+
errored: null,
|
606
|
+
writableNeedDrain: false,
|
607
|
+
_header: null,
|
608
|
+
_headerSent: false,
|
609
|
+
_headers: {},
|
610
|
+
_headerNames: {},
|
611
|
+
_hasBody: true,
|
612
|
+
_trailer: "",
|
613
|
+
_keepAliveTimeout: 5e3,
|
614
|
+
_last: false,
|
615
|
+
_onPendingData: () => {
|
616
|
+
},
|
617
|
+
_sent100: false,
|
618
|
+
_expect_continue: false,
|
619
|
+
_maxRequestsPerSocket: 0,
|
620
|
+
req: void 0,
|
621
|
+
writable: true,
|
622
|
+
writableAborted: false,
|
623
|
+
setDefaultEncoding: (encoding) => {
|
624
|
+
socket.setEncoding(encoding);
|
625
|
+
return res;
|
626
|
+
},
|
627
|
+
[Symbol.asyncDispose]: async () => {
|
628
|
+
cleanup();
|
629
|
+
},
|
630
|
+
compose: ((stream) => {
|
631
|
+
if (stream && typeof stream === "object" && "pipe" in stream) {
|
632
|
+
return stream;
|
633
|
+
}
|
634
|
+
if (typeof stream === "function") {
|
635
|
+
const transform = new import_node_stream.Transform({
|
636
|
+
objectMode: true,
|
637
|
+
transform(chunk, encoding, callback) {
|
638
|
+
try {
|
639
|
+
stream(chunk);
|
640
|
+
callback(null, chunk);
|
641
|
+
} catch (error) {
|
642
|
+
callback(error);
|
643
|
+
}
|
644
|
+
}
|
645
|
+
});
|
646
|
+
return transform;
|
647
|
+
}
|
648
|
+
if (stream && typeof stream === "object" && Symbol.iterator in stream) {
|
649
|
+
const iterator = stream[Symbol.iterator]();
|
650
|
+
const first = iterator.next();
|
651
|
+
if (!first.done && first.value && typeof first.value === "object" && "pipe" in first.value) {
|
652
|
+
return first.value;
|
653
|
+
}
|
654
|
+
}
|
655
|
+
if (stream && typeof stream === "object" && Symbol.asyncIterator in stream) {
|
656
|
+
const readable = new import_node_stream.Readable({
|
657
|
+
objectMode: true,
|
658
|
+
read() {
|
659
|
+
this.push(null);
|
660
|
+
}
|
661
|
+
});
|
662
|
+
return readable;
|
663
|
+
}
|
664
|
+
const emptyStream = new import_node_stream.Readable({
|
665
|
+
read() {
|
666
|
+
this.push(null);
|
667
|
+
}
|
668
|
+
});
|
669
|
+
return emptyStream;
|
670
|
+
}),
|
671
|
+
setTimeout: (msecs, callback) => {
|
672
|
+
setTimeout(callback || (() => {
|
673
|
+
}), msecs);
|
674
|
+
return res;
|
675
|
+
},
|
676
|
+
setHeaders: (headers2) => {
|
677
|
+
for (const [name, value] of Object.entries(headers2)) {
|
678
|
+
res.setHeader(name, value);
|
679
|
+
}
|
680
|
+
return res;
|
681
|
+
},
|
682
|
+
appendHeader: (name, value) => {
|
683
|
+
return res.append(name, value);
|
684
|
+
},
|
685
|
+
addTrailers: (headers2) => {
|
686
|
+
return res;
|
687
|
+
},
|
688
|
+
flushHeaders: () => {
|
689
|
+
headersSent = true;
|
690
|
+
res.headersSent = true;
|
691
|
+
ensureResponse();
|
692
|
+
},
|
693
|
+
setHeader(name, value) {
|
694
|
+
if (Array.isArray(value)) {
|
695
|
+
headerMap.delete(name);
|
696
|
+
value.forEach((v) => headerMap.append(name, String(v)));
|
697
|
+
} else {
|
698
|
+
headerMap.set(name, String(value));
|
699
|
+
}
|
700
|
+
return res;
|
701
|
+
},
|
702
|
+
getHeader(name) {
|
703
|
+
return headerMap.get(name) ?? void 0;
|
704
|
+
},
|
705
|
+
getHeaders() {
|
706
|
+
const obj = {};
|
707
|
+
headerMap.forEach((v, k) => obj[k] = v);
|
708
|
+
return obj;
|
709
|
+
},
|
710
|
+
getHeaderNames() {
|
711
|
+
const names = [];
|
712
|
+
headerMap.forEach((_, name) => names.push(name));
|
713
|
+
return names;
|
714
|
+
},
|
715
|
+
hasHeader(name) {
|
716
|
+
return headerMap.has(name);
|
717
|
+
},
|
718
|
+
removeHeader(name) {
|
719
|
+
headerMap.delete(name);
|
720
|
+
return res;
|
721
|
+
},
|
722
|
+
writeHead(code, reason, headers2) {
|
723
|
+
if (typeof reason === "object") {
|
724
|
+
headers2 = reason;
|
725
|
+
reason = void 0;
|
726
|
+
}
|
727
|
+
statusCode = code;
|
728
|
+
res.statusCode = statusCode;
|
729
|
+
if (reason) res.statusMessage = reason;
|
730
|
+
if (headers2) {
|
731
|
+
for (const [k, v] of Object.entries(headers2))
|
732
|
+
if (v) res.setHeader(k, v);
|
733
|
+
}
|
734
|
+
headersSent = true;
|
735
|
+
res.headersSent = true;
|
736
|
+
ensureResponse();
|
737
|
+
return res;
|
738
|
+
},
|
739
|
+
write(chunk, encoding, callback) {
|
740
|
+
if (typeof encoding === "function") {
|
741
|
+
callback = encoding;
|
742
|
+
encoding = void 0;
|
743
|
+
}
|
744
|
+
if (ended) {
|
745
|
+
if (callback) callback(new Error("Cannot write after end"));
|
746
|
+
return false;
|
747
|
+
}
|
748
|
+
headersSent = true;
|
749
|
+
res.headersSent = true;
|
750
|
+
ensureResponse();
|
751
|
+
if (chunk == null) {
|
752
|
+
if (callback) callback();
|
753
|
+
return true;
|
754
|
+
}
|
755
|
+
try {
|
756
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk), encoding || "utf8");
|
757
|
+
writer.write(buf);
|
758
|
+
if (callback) callback();
|
759
|
+
return true;
|
760
|
+
} catch (error) {
|
761
|
+
if (callback) callback(error);
|
762
|
+
return false;
|
763
|
+
}
|
764
|
+
},
|
765
|
+
end(chunk, encoding, callback) {
|
766
|
+
if (typeof chunk === "function") {
|
767
|
+
callback = chunk;
|
768
|
+
chunk = void 0;
|
769
|
+
}
|
770
|
+
if (typeof encoding === "function") {
|
771
|
+
callback = encoding;
|
772
|
+
encoding = void 0;
|
773
|
+
}
|
774
|
+
if (ended) {
|
775
|
+
if (callback) callback();
|
776
|
+
return res;
|
777
|
+
}
|
778
|
+
if (chunk) res.write(chunk, encoding || "utf8");
|
779
|
+
ended = true;
|
780
|
+
Object.assign(res, {
|
781
|
+
writableEnded: true
|
782
|
+
});
|
783
|
+
ensureResponse();
|
784
|
+
writer.close().then(() => {
|
785
|
+
resEE.emit("finish");
|
786
|
+
if (callback) callback();
|
787
|
+
});
|
788
|
+
return res;
|
789
|
+
},
|
790
|
+
cork: () => {
|
791
|
+
},
|
792
|
+
uncork: () => {
|
793
|
+
},
|
794
|
+
destroy: (error) => {
|
795
|
+
res.destroyed = true;
|
796
|
+
cleanup();
|
797
|
+
return res;
|
798
|
+
},
|
799
|
+
_destroy: (error, callback) => {
|
800
|
+
callback(error);
|
801
|
+
},
|
802
|
+
_final: (callback) => {
|
803
|
+
callback();
|
804
|
+
},
|
805
|
+
_write: (chunk, encoding, callback) => {
|
806
|
+
callback();
|
807
|
+
},
|
808
|
+
_writev: (chunks, callback) => {
|
809
|
+
callback();
|
810
|
+
},
|
811
|
+
pipe: (destination, options2) => {
|
812
|
+
return destination;
|
813
|
+
},
|
814
|
+
unpipe: (destination) => {
|
815
|
+
return res;
|
816
|
+
},
|
817
|
+
addListener: resEE.addListener.bind(resEE),
|
818
|
+
removeListener: resEE.removeListener.bind(resEE),
|
819
|
+
prependListener: resEE.prependListener.bind(resEE),
|
820
|
+
prependOnceListener: resEE.prependOnceListener.bind(resEE),
|
821
|
+
removeAllListeners: resEE.removeAllListeners.bind(resEE),
|
822
|
+
setMaxListeners: resEE.setMaxListeners.bind(resEE),
|
823
|
+
getMaxListeners: resEE.getMaxListeners.bind(resEE),
|
824
|
+
listeners: resEE.listeners.bind(resEE),
|
825
|
+
rawListeners: resEE.rawListeners.bind(resEE),
|
826
|
+
listenerCount: resEE.listenerCount.bind(resEE),
|
827
|
+
eventNames: resEE.eventNames.bind(resEE),
|
828
|
+
status(code) {
|
829
|
+
statusCode = code;
|
830
|
+
res.statusCode = code;
|
831
|
+
return res;
|
832
|
+
},
|
833
|
+
sendStatus(code) {
|
834
|
+
const statusTexts = {
|
835
|
+
100: "Continue",
|
836
|
+
101: "Switching Protocols",
|
837
|
+
200: "OK",
|
838
|
+
201: "Created",
|
839
|
+
202: "Accepted",
|
840
|
+
203: "Non-Authoritative Information",
|
841
|
+
204: "No Content",
|
842
|
+
205: "Reset Content",
|
843
|
+
206: "Partial Content",
|
844
|
+
300: "Multiple Choices",
|
845
|
+
301: "Moved Permanently",
|
846
|
+
302: "Found",
|
847
|
+
303: "See Other",
|
848
|
+
304: "Not Modified",
|
849
|
+
307: "Temporary Redirect",
|
850
|
+
308: "Permanent Redirect",
|
851
|
+
400: "Bad Request",
|
852
|
+
401: "Unauthorized",
|
853
|
+
402: "Payment Required",
|
854
|
+
403: "Forbidden",
|
855
|
+
404: "Not Found",
|
856
|
+
405: "Method Not Allowed",
|
857
|
+
406: "Not Acceptable",
|
858
|
+
407: "Proxy Authentication Required",
|
859
|
+
408: "Request Timeout",
|
860
|
+
409: "Conflict",
|
861
|
+
410: "Gone",
|
862
|
+
411: "Length Required",
|
863
|
+
412: "Precondition Failed",
|
864
|
+
413: "Payload Too Large",
|
865
|
+
414: "URI Too Long",
|
866
|
+
415: "Unsupported Media Type",
|
867
|
+
416: "Range Not Satisfiable",
|
868
|
+
417: "Expectation Failed",
|
869
|
+
418: "I'm a teapot",
|
870
|
+
422: "Unprocessable Entity",
|
871
|
+
425: "Too Early",
|
872
|
+
426: "Upgrade Required",
|
873
|
+
428: "Precondition Required",
|
874
|
+
429: "Too Many Requests",
|
875
|
+
431: "Request Header Fields Too Large",
|
876
|
+
451: "Unavailable For Legal Reasons",
|
877
|
+
500: "Internal Server Error",
|
878
|
+
501: "Not Implemented",
|
879
|
+
502: "Bad Gateway",
|
880
|
+
503: "Service Unavailable",
|
881
|
+
504: "Gateway Timeout",
|
882
|
+
505: "HTTP Version Not Supported",
|
883
|
+
507: "Insufficient Storage",
|
884
|
+
508: "Loop Detected",
|
885
|
+
510: "Not Extended",
|
886
|
+
511: "Network Authentication Required"
|
887
|
+
};
|
888
|
+
const statusText = statusTexts[code] || "Unknown Status";
|
889
|
+
res.status(code).send(statusText);
|
890
|
+
return res;
|
891
|
+
},
|
892
|
+
set(field, value) {
|
893
|
+
if (typeof field === "string" && value !== void 0) {
|
894
|
+
res.setHeader(field, value);
|
895
|
+
} else if (typeof field === "object") {
|
896
|
+
for (const [k, v] of Object.entries(field)) res.setHeader(k, v);
|
897
|
+
}
|
898
|
+
return res;
|
899
|
+
},
|
900
|
+
header(name, value) {
|
901
|
+
if (value !== void 0) {
|
902
|
+
res.setHeader(name, value);
|
903
|
+
return res;
|
904
|
+
}
|
905
|
+
return res;
|
906
|
+
},
|
907
|
+
get(name) {
|
908
|
+
return res.getHeader(name);
|
909
|
+
},
|
910
|
+
type(contentType) {
|
911
|
+
if (contentType.includes("/")) {
|
912
|
+
res.setHeader("Content-Type", contentType);
|
913
|
+
} else {
|
914
|
+
const mime = extMime(`file.${contentType}`);
|
915
|
+
if (mime) res.setHeader("Content-Type", mime);
|
916
|
+
}
|
917
|
+
return res;
|
918
|
+
},
|
919
|
+
contentType(type) {
|
920
|
+
return res.type(type);
|
921
|
+
},
|
922
|
+
location(url2) {
|
923
|
+
res.setHeader("Location", url2);
|
924
|
+
return res;
|
925
|
+
},
|
926
|
+
redirect(arg1, arg2) {
|
927
|
+
let code = 302;
|
928
|
+
let location = "";
|
929
|
+
if (typeof arg1 === "number") {
|
930
|
+
code = arg1;
|
931
|
+
location = String(arg2);
|
932
|
+
} else {
|
933
|
+
location = String(arg1);
|
934
|
+
}
|
935
|
+
res.status(code);
|
936
|
+
res.setHeader("Location", location);
|
937
|
+
if (req.accepts("html")) {
|
938
|
+
return res.type("html").end(
|
939
|
+
`<p>Redirecting to <a href="${location}">${location}</a></p>`
|
940
|
+
);
|
941
|
+
} else {
|
942
|
+
return res.type("txt").end(`Redirecting to ${location}`);
|
943
|
+
}
|
944
|
+
},
|
945
|
+
json(obj) {
|
946
|
+
if (!headerMap.has("content-type"))
|
947
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
948
|
+
return res.end(JSON.stringify(obj));
|
949
|
+
},
|
950
|
+
jsonp(obj) {
|
951
|
+
const callback = req.query.callback || req.query.jsonp;
|
952
|
+
if (callback && typeof callback === "string") {
|
953
|
+
res.setHeader("Content-Type", "text/javascript; charset=utf-8");
|
954
|
+
const callbackName = callback.replace(/[^\w$]/g, "");
|
955
|
+
return res.end(
|
956
|
+
`/**/ typeof ${callbackName} === 'function' && ${callbackName}(${JSON.stringify(obj)});`
|
957
|
+
);
|
958
|
+
}
|
959
|
+
return res.json(obj);
|
960
|
+
},
|
961
|
+
send(body) {
|
962
|
+
if (body == null) return res.end();
|
963
|
+
if (Buffer.isBuffer(body)) return res.end(body);
|
964
|
+
if (typeof body === "object") {
|
965
|
+
if (!headerMap.has("content-type"))
|
966
|
+
res.type("application/json; charset=utf-8");
|
967
|
+
return res.end(JSON.stringify(body));
|
968
|
+
}
|
969
|
+
if (typeof body === "number") {
|
970
|
+
return res.sendStatus(body);
|
971
|
+
}
|
972
|
+
if (!headerMap.has("content-type"))
|
973
|
+
res.type("text/plain; charset=utf-8");
|
974
|
+
return res.end(String(body));
|
975
|
+
},
|
976
|
+
cookie(name, value, options2) {
|
977
|
+
const opts2 = options2 || {};
|
978
|
+
let cookieValue = value;
|
979
|
+
if (opts2.signed) {
|
980
|
+
cookieValue = signCookie(value, cookieSecret);
|
981
|
+
name = `s:${name}`;
|
982
|
+
}
|
983
|
+
headerMap.append(
|
984
|
+
"Set-Cookie",
|
985
|
+
serializeCookie(name, cookieValue, opts2)
|
986
|
+
);
|
987
|
+
return res;
|
988
|
+
},
|
989
|
+
clearCookie(name, options2) {
|
990
|
+
const opts2 = { ...options2 || {}, expires: /* @__PURE__ */ new Date(0), maxAge: 0 };
|
991
|
+
headerMap.append("Set-Cookie", serializeCookie(name, "", opts2));
|
992
|
+
return res;
|
993
|
+
},
|
994
|
+
sendFile: function(filePath, optionsOrFn, fn) {
|
995
|
+
let options2 = {};
|
996
|
+
let callback;
|
997
|
+
if (typeof optionsOrFn === "function") {
|
998
|
+
callback = optionsOrFn;
|
999
|
+
} else {
|
1000
|
+
options2 = optionsOrFn || {};
|
1001
|
+
callback = fn;
|
1002
|
+
}
|
1003
|
+
(async () => {
|
1004
|
+
try {
|
1005
|
+
const fullPath = options2.root ? path.join(options2.root, filePath) : filePath;
|
1006
|
+
if (options2.dotfiles === "deny" && path.basename(fullPath).startsWith(".")) {
|
1007
|
+
res.status(403);
|
1008
|
+
res.end("Forbidden");
|
1009
|
+
if (callback) callback(new Error("Forbidden"));
|
1010
|
+
return;
|
1011
|
+
}
|
1012
|
+
const file = Bun.file(fullPath);
|
1013
|
+
if (!await file.exists()) {
|
1014
|
+
res.status(404);
|
1015
|
+
res.end("Not Found");
|
1016
|
+
if (callback) callback(new Error("Not Found"));
|
1017
|
+
return;
|
1018
|
+
}
|
1019
|
+
const stats = await file.size;
|
1020
|
+
const lastModified = new Date(file.lastModified);
|
1021
|
+
if (options2.cacheControl !== false) {
|
1022
|
+
const maxAge = options2.maxAge || 0;
|
1023
|
+
res.setHeader("Cache-Control", `public, max-age=${maxAge}`);
|
1024
|
+
}
|
1025
|
+
if (options2.lastModified !== false) {
|
1026
|
+
res.setHeader("Last-Modified", lastModified.toUTCString());
|
1027
|
+
}
|
1028
|
+
if (options2.etag !== false) {
|
1029
|
+
const etag = `"${stats}-${lastModified.getTime()}"`;
|
1030
|
+
res.setHeader("ETag", etag);
|
1031
|
+
}
|
1032
|
+
const ifModifiedSince = req.get("if-modified-since");
|
1033
|
+
const ifNoneMatch = req.get("if-none-match");
|
1034
|
+
if (ifModifiedSince && new Date(ifModifiedSince) >= lastModified) {
|
1035
|
+
res.status(304).end();
|
1036
|
+
if (callback) callback(void 0);
|
1037
|
+
return;
|
1038
|
+
}
|
1039
|
+
if (ifNoneMatch && ifNoneMatch === res.getHeader("ETag")) {
|
1040
|
+
res.status(304).end();
|
1041
|
+
if (callback) callback(void 0);
|
1042
|
+
return;
|
1043
|
+
}
|
1044
|
+
const mime = extMime(fullPath);
|
1045
|
+
if (mime) res.setHeader("Content-Type", mime);
|
1046
|
+
res.setHeader("Content-Length", stats.toString());
|
1047
|
+
if (options2.headers) {
|
1048
|
+
for (const [k, v] of Object.entries(options2.headers))
|
1049
|
+
if (v) res.setHeader(k, v);
|
1050
|
+
}
|
1051
|
+
headersSent = true;
|
1052
|
+
res.headersSent = true;
|
1053
|
+
ensureResponse();
|
1054
|
+
const reader = file.stream().getReader();
|
1055
|
+
try {
|
1056
|
+
while (true) {
|
1057
|
+
const { done, value } = await reader.read();
|
1058
|
+
if (done) break;
|
1059
|
+
if (value) await writer.write(value);
|
1060
|
+
}
|
1061
|
+
} finally {
|
1062
|
+
await writer.close();
|
1063
|
+
resEE.emit("finish");
|
1064
|
+
if (callback) callback(void 0);
|
1065
|
+
}
|
1066
|
+
} catch (error) {
|
1067
|
+
if (callback) callback(error);
|
1068
|
+
}
|
1069
|
+
})();
|
1070
|
+
},
|
1071
|
+
download(filePath, filename, options2, callback) {
|
1072
|
+
const downloadFilename = filename || path.basename(filePath);
|
1073
|
+
res.setHeader(
|
1074
|
+
"Content-Disposition",
|
1075
|
+
`attachment; filename="${downloadFilename}"`
|
1076
|
+
);
|
1077
|
+
if (typeof options2 === "function") {
|
1078
|
+
callback = options2;
|
1079
|
+
options2 = {};
|
1080
|
+
}
|
1081
|
+
res.sendFile(filePath, options2 || {});
|
1082
|
+
return res;
|
1083
|
+
},
|
1084
|
+
render: (view, locals, callback) => {
|
1085
|
+
const errback = typeof locals === "function" ? locals : callback;
|
1086
|
+
try {
|
1087
|
+
const templateLocals = {
|
1088
|
+
...res.locals,
|
1089
|
+
...typeof locals === "function" ? {} : locals
|
1090
|
+
};
|
1091
|
+
let html = `<!DOCTYPE html><html><head><title>${view}</title></head><body>`;
|
1092
|
+
html += `<h1>View: ${view}</h1>`;
|
1093
|
+
html += `<pre>${JSON.stringify(templateLocals, null, 2)}</pre>`;
|
1094
|
+
html += `</body></html>`;
|
1095
|
+
if (errback) {
|
1096
|
+
errback(new Error("Template rendering error"), html);
|
1097
|
+
} else {
|
1098
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
1099
|
+
res.send(html);
|
1100
|
+
}
|
1101
|
+
} catch (error) {
|
1102
|
+
if (errback) {
|
1103
|
+
errback(error, "");
|
1104
|
+
} else {
|
1105
|
+
res.status(500).send("Template rendering error");
|
1106
|
+
}
|
1107
|
+
}
|
1108
|
+
return res;
|
1109
|
+
},
|
1110
|
+
links(links) {
|
1111
|
+
const existing = res.getHeader("Link");
|
1112
|
+
const linkHeader = Object.entries(links).map(([rel, url2]) => `<${url2}>; rel="${rel}"`).join(", ");
|
1113
|
+
if (existing) {
|
1114
|
+
res.setHeader("Link", `${existing}, ${linkHeader}`);
|
1115
|
+
} else {
|
1116
|
+
res.setHeader("Link", linkHeader);
|
1117
|
+
}
|
1118
|
+
return res;
|
1119
|
+
},
|
1120
|
+
sendfile: function(path2, options2, callback) {
|
1121
|
+
if (!callback && !options2) {
|
1122
|
+
return res.sendFile(path2);
|
1123
|
+
} else if (!callback && options2) {
|
1124
|
+
return res.sendFile(path2, options2);
|
1125
|
+
} else if (callback && options2) {
|
1126
|
+
return res.sendFile(path2, options2, callback);
|
1127
|
+
}
|
1128
|
+
},
|
1129
|
+
attachment(filename) {
|
1130
|
+
if (filename) {
|
1131
|
+
res.setHeader(
|
1132
|
+
"Content-Disposition",
|
1133
|
+
`attachment; filename="${filename}"`
|
1134
|
+
);
|
1135
|
+
const mime = extMime(filename);
|
1136
|
+
if (mime) res.type(mime);
|
1137
|
+
} else {
|
1138
|
+
res.setHeader("Content-Disposition", "attachment");
|
1139
|
+
}
|
1140
|
+
return res;
|
1141
|
+
},
|
1142
|
+
format(obj) {
|
1143
|
+
const accepted = req.accepts(Object.keys(obj));
|
1144
|
+
if (accepted && obj[accepted]) {
|
1145
|
+
return obj[accepted]();
|
1146
|
+
}
|
1147
|
+
const defaultHandler = obj.default;
|
1148
|
+
if (defaultHandler) {
|
1149
|
+
return defaultHandler();
|
1150
|
+
}
|
1151
|
+
return res.status(406).send("Not Acceptable");
|
1152
|
+
},
|
1153
|
+
vary(field) {
|
1154
|
+
const fields = Array.isArray(field) ? field : [field];
|
1155
|
+
const existing = res.getHeader("Vary");
|
1156
|
+
const varyHeader = existing ? `${existing}, ${fields.join(", ")}` : fields.join(", ");
|
1157
|
+
res.setHeader("Vary", varyHeader);
|
1158
|
+
return res;
|
1159
|
+
},
|
1160
|
+
append(field, value) {
|
1161
|
+
const existing = res.getHeader(field);
|
1162
|
+
if (existing) {
|
1163
|
+
const newValue = Array.isArray(value) ? value.join(", ") : value;
|
1164
|
+
res.setHeader(field, `${existing}, ${newValue}`);
|
1165
|
+
} else {
|
1166
|
+
res.setHeader(field, value);
|
1167
|
+
}
|
1168
|
+
return res;
|
1169
|
+
},
|
1170
|
+
writeContinue: () => {
|
1171
|
+
return res;
|
1172
|
+
},
|
1173
|
+
writeEarlyHints: (hints) => {
|
1174
|
+
return res;
|
1175
|
+
},
|
1176
|
+
assignSocket: (socket2) => {
|
1177
|
+
Object.defineProperty(res, "socket", {
|
1178
|
+
value: socket2,
|
1179
|
+
writable: true,
|
1180
|
+
enumerable: false,
|
1181
|
+
configurable: true
|
1182
|
+
});
|
1183
|
+
return res;
|
1184
|
+
},
|
1185
|
+
detachSocket: (socket2) => {
|
1186
|
+
Object.defineProperty(res, "socket", {
|
1187
|
+
value: void 0,
|
1188
|
+
writable: true,
|
1189
|
+
enumerable: false,
|
1190
|
+
configurable: true
|
1191
|
+
});
|
1192
|
+
return res;
|
1193
|
+
},
|
1194
|
+
app
|
1195
|
+
});
|
1196
|
+
const reqEE = new import_node_events.EventEmitter();
|
1197
|
+
Object.getOwnPropertyNames(nodeReq).forEach((key) => {
|
1198
|
+
if (key !== "constructor") {
|
1199
|
+
try {
|
1200
|
+
const descriptor = Object.getOwnPropertyDescriptor(nodeReq, key);
|
1201
|
+
if (descriptor && descriptor.configurable !== false && descriptor.writable !== false) {
|
1202
|
+
Object.defineProperty(reqEE, key, descriptor);
|
1203
|
+
} else {
|
1204
|
+
openTelemetryCollector.info(
|
1205
|
+
"Property not configurable or writable:",
|
1206
|
+
key
|
1207
|
+
);
|
1208
|
+
}
|
1209
|
+
} catch (e) {
|
1210
|
+
openTelemetryCollector.error("Error defining property:", e);
|
1211
|
+
}
|
1212
|
+
}
|
1213
|
+
});
|
1214
|
+
const req = Object.assign(reqEE, {
|
1215
|
+
method: request.method,
|
1216
|
+
url: url.pathname + url.search,
|
1217
|
+
originalUrl: url.pathname + url.search,
|
1218
|
+
headers,
|
1219
|
+
httpVersion: "1.1",
|
1220
|
+
httpVersionMajor: 1,
|
1221
|
+
httpVersionMinor: 1,
|
1222
|
+
complete: false,
|
1223
|
+
socket,
|
1224
|
+
connection: socket,
|
1225
|
+
protocol: proto,
|
1226
|
+
secure: proto === "https",
|
1227
|
+
ip,
|
1228
|
+
ips: forwardedFor ? Array.isArray(forwardedFor) ? forwardedFor : forwardedFor.split(",").map((s) => s.trim()) : [],
|
1229
|
+
hostname: Array.isArray(headers["x-forwarded-host"] || headers["host"]) ? (headers["x-forwarded-host"] || headers["host"])[0].split(":")[0] : (headers["x-forwarded-host"] || headers["host"] || "").split(
|
1230
|
+
":"
|
1231
|
+
)[0],
|
1232
|
+
host: Array.isArray(headers["x-forwarded-host"] || headers["host"]) ? (headers["x-forwarded-host"] || headers["host"])[0] : headers["x-forwarded-host"] || headers["host"] || "",
|
1233
|
+
path: url.pathname,
|
1234
|
+
query,
|
1235
|
+
params: {},
|
1236
|
+
// Will be populated by route matching
|
1237
|
+
body: void 0,
|
1238
|
+
// Will be populated by body parsing middleware
|
1239
|
+
cookies,
|
1240
|
+
signedCookies,
|
1241
|
+
secret: cookieSecret,
|
1242
|
+
accepted: [],
|
1243
|
+
subdomains: (() => {
|
1244
|
+
const hostname = Array.isArray(
|
1245
|
+
headers["x-forwarded-host"] || headers["host"]
|
1246
|
+
) ? (headers["x-forwarded-host"] || headers["host"])[0].split(":")[0] : (headers["x-forwarded-host"] || headers["host"] || "").split(
|
1247
|
+
":"
|
1248
|
+
)[0];
|
1249
|
+
if (!hostname) return [];
|
1250
|
+
const parts = hostname.split(".");
|
1251
|
+
return parts.length > 2 ? parts.slice(0, -2).reverse() : [];
|
1252
|
+
})(),
|
1253
|
+
get fresh() {
|
1254
|
+
const method = request.method;
|
1255
|
+
const status = res.statusCode;
|
1256
|
+
if (method !== "GET" && method !== "HEAD") return false;
|
1257
|
+
if (status >= 200 && status < 300 || status === 304) {
|
1258
|
+
const modifiedSince = headers["if-modified-since"];
|
1259
|
+
const noneMatch = headers["if-none-match"];
|
1260
|
+
const lastModified = res.get("last-modified");
|
1261
|
+
const etag = res.get("etag");
|
1262
|
+
if (noneMatch && etag) {
|
1263
|
+
return noneMatch.includes(etag);
|
1264
|
+
}
|
1265
|
+
if (modifiedSince && lastModified) {
|
1266
|
+
return new Date(modifiedSince) >= new Date(lastModified);
|
1267
|
+
}
|
1268
|
+
}
|
1269
|
+
return false;
|
1270
|
+
},
|
1271
|
+
get stale() {
|
1272
|
+
return !this.fresh;
|
1273
|
+
},
|
1274
|
+
xhr: (() => {
|
1275
|
+
const requestedWith = headers["x-requested-with"];
|
1276
|
+
return requestedWith === "XMLHttpRequest";
|
1277
|
+
})(),
|
1278
|
+
get: ((name) => {
|
1279
|
+
const value = headers[name.toLowerCase()];
|
1280
|
+
if (!value) return void 0;
|
1281
|
+
return Array.isArray(value) ? value[0] : value;
|
1282
|
+
}),
|
1283
|
+
header: ((name) => {
|
1284
|
+
const value = headers[name.toLowerCase()];
|
1285
|
+
if (!value) return void 0;
|
1286
|
+
return Array.isArray(value) ? value[0] : value;
|
1287
|
+
}),
|
1288
|
+
is(types) {
|
1289
|
+
const contentType = headers["content-type"] || "";
|
1290
|
+
if (!contentType) return false;
|
1291
|
+
const typesToCheck = Array.isArray(types) ? types : [types];
|
1292
|
+
for (const type of typesToCheck) {
|
1293
|
+
if (type === "json" && contentType.includes("application/json"))
|
1294
|
+
return "json";
|
1295
|
+
if (type === "html" && contentType.includes("text/html"))
|
1296
|
+
return "html";
|
1297
|
+
if (type === "xml" && contentType.includes("application/xml"))
|
1298
|
+
return "xml";
|
1299
|
+
if (type === "text" && contentType.includes("text/")) return "text";
|
1300
|
+
if (contentType.includes(type)) return type;
|
1301
|
+
}
|
1302
|
+
return false;
|
1303
|
+
},
|
1304
|
+
accepts: ((types) => {
|
1305
|
+
const accept = headers.accept || "*/*";
|
1306
|
+
if (!types) {
|
1307
|
+
const acceptStr2 = Array.isArray(accept) ? accept.join(",") : accept;
|
1308
|
+
return acceptStr2.split(",").map((t) => t.trim().split(";")[0]);
|
1309
|
+
}
|
1310
|
+
const typesToCheck = Array.isArray(types) ? types : [types];
|
1311
|
+
const acceptStr = Array.isArray(accept) ? accept.join(",") : accept;
|
1312
|
+
const result = [];
|
1313
|
+
for (const type of typesToCheck) {
|
1314
|
+
if (acceptStr.includes(type) || acceptStr.includes("*/*")) {
|
1315
|
+
result.push(type);
|
1316
|
+
}
|
1317
|
+
if (type === "json" && acceptStr.includes("application/json"))
|
1318
|
+
result.push("json");
|
1319
|
+
if (type === "html" && acceptStr.includes("text/html"))
|
1320
|
+
result.push("html");
|
1321
|
+
if (type === "xml" && acceptStr.includes("application/xml"))
|
1322
|
+
result.push("xml");
|
1323
|
+
}
|
1324
|
+
return result;
|
1325
|
+
}),
|
1326
|
+
acceptsCharsets: ((charsets) => {
|
1327
|
+
const acceptCharset = headers["accept-charset"] || "*";
|
1328
|
+
const acceptCharsetStr = Array.isArray(acceptCharset) ? acceptCharset.join(",") : acceptCharset;
|
1329
|
+
if (!charsets)
|
1330
|
+
return acceptCharsetStr.split(",").map((c) => c.trim());
|
1331
|
+
const charsetsToCheck = Array.isArray(charsets) ? charsets : [charsets];
|
1332
|
+
const result = [];
|
1333
|
+
for (const charset of charsetsToCheck) {
|
1334
|
+
if (acceptCharsetStr.includes(charset) || acceptCharsetStr.includes("*")) {
|
1335
|
+
result.push(charset);
|
1336
|
+
}
|
1337
|
+
}
|
1338
|
+
return result;
|
1339
|
+
}),
|
1340
|
+
acceptsEncodings: ((encodings) => {
|
1341
|
+
const acceptEncoding = headers["accept-encoding"] || "identity";
|
1342
|
+
const acceptEncodingStr = Array.isArray(acceptEncoding) ? acceptEncoding.join(",") : acceptEncoding;
|
1343
|
+
if (!encodings)
|
1344
|
+
return acceptEncodingStr.split(",").map((e) => e.trim());
|
1345
|
+
const encodingsToCheck = Array.isArray(encodings) ? encodings : [encodings];
|
1346
|
+
const result = [];
|
1347
|
+
for (const encoding of encodingsToCheck) {
|
1348
|
+
if (acceptEncodingStr.includes(encoding) || acceptEncodingStr.includes("*")) {
|
1349
|
+
result.push(encoding);
|
1350
|
+
}
|
1351
|
+
}
|
1352
|
+
return result;
|
1353
|
+
}),
|
1354
|
+
acceptsLanguages: ((languages) => {
|
1355
|
+
const acceptLanguage = headers["accept-language"] || "*";
|
1356
|
+
const acceptLanguageStr = Array.isArray(acceptLanguage) ? acceptLanguage.join(",") : acceptLanguage;
|
1357
|
+
if (!languages)
|
1358
|
+
return acceptLanguageStr.split(",").map((l) => l.trim());
|
1359
|
+
const languagesToCheck = Array.isArray(languages) ? languages : [languages];
|
1360
|
+
const result = [];
|
1361
|
+
for (const language of languagesToCheck) {
|
1362
|
+
if (acceptLanguageStr.includes(language) || acceptLanguageStr.includes("*")) {
|
1363
|
+
result.push(language);
|
1364
|
+
}
|
1365
|
+
}
|
1366
|
+
return result;
|
1367
|
+
}),
|
1368
|
+
range(size, options2) {
|
1369
|
+
const rangeHeader = headers.range;
|
1370
|
+
if (!rangeHeader) return void 0;
|
1371
|
+
const rangeStr = Array.isArray(rangeHeader) ? rangeHeader[0] : rangeHeader;
|
1372
|
+
return (0, import_range_parser.default)(size, rangeStr, options2);
|
1373
|
+
},
|
1374
|
+
param(name, defaultValue) {
|
1375
|
+
if (this.params && this.params[name] !== void 0) {
|
1376
|
+
return this.params[name];
|
1377
|
+
}
|
1378
|
+
if (this.query && this.query[name] !== void 0) {
|
1379
|
+
return this.query[name];
|
1380
|
+
}
|
1381
|
+
if (this.body && typeof this.body === "object" && this.body[name] !== void 0) {
|
1382
|
+
return this.body[name];
|
1383
|
+
}
|
1384
|
+
return defaultValue;
|
1385
|
+
},
|
1386
|
+
app,
|
1387
|
+
baseUrl: app.basePath || "",
|
1388
|
+
route: {
|
1389
|
+
path: pathname,
|
1390
|
+
stack: [],
|
1391
|
+
methods: { [request.method.toLowerCase()]: true }
|
1392
|
+
},
|
1393
|
+
res,
|
1394
|
+
next: (() => {
|
1395
|
+
}),
|
1396
|
+
rawHeaders: Object.entries(headers).flat(),
|
1397
|
+
trailers: {},
|
1398
|
+
rawTrailers: [],
|
1399
|
+
aborted: false,
|
1400
|
+
upgrade: false,
|
1401
|
+
readable: true,
|
1402
|
+
readableHighWaterMark: 16384,
|
1403
|
+
readableLength: 0,
|
1404
|
+
destroyed: false,
|
1405
|
+
closed: false,
|
1406
|
+
clearCookie: (name, options2) => {
|
1407
|
+
const opts2 = Object.assign({}, options2);
|
1408
|
+
opts2.expires = /* @__PURE__ */ new Date(1);
|
1409
|
+
opts2.path = opts2.path || "/";
|
1410
|
+
return res.cookie(name, "", opts2);
|
1411
|
+
},
|
1412
|
+
setTimeout: (msecs, callback) => {
|
1413
|
+
setTimeout(callback || (() => {
|
1414
|
+
}), msecs);
|
1415
|
+
return req;
|
1416
|
+
},
|
1417
|
+
headersDistinct: Object.fromEntries(
|
1418
|
+
Object.entries(headers).map(([key, value]) => [
|
1419
|
+
key,
|
1420
|
+
Array.isArray(value) ? value : [value]
|
1421
|
+
])
|
1422
|
+
),
|
1423
|
+
trailersDistinct: {}
|
1424
|
+
});
|
1425
|
+
Object.assign(req, {
|
1426
|
+
res,
|
1427
|
+
req
|
1428
|
+
});
|
1429
|
+
Object.assign(res, {
|
1430
|
+
req,
|
1431
|
+
res
|
1432
|
+
});
|
1433
|
+
const onAbort = () => {
|
1434
|
+
cleanup();
|
1435
|
+
Object.assign(req, {
|
1436
|
+
aborted: true,
|
1437
|
+
destroyed: true
|
1438
|
+
});
|
1439
|
+
resEE.emit("close");
|
1440
|
+
req.emit("close");
|
1441
|
+
req.emit("aborted");
|
1442
|
+
writer.abort("client aborted");
|
1443
|
+
};
|
1444
|
+
abort.signal.addEventListener("abort", onAbort);
|
1445
|
+
res.once("finish", cleanup);
|
1446
|
+
res.once("close", cleanup);
|
1447
|
+
res.once("finish", () => {
|
1448
|
+
abort.signal.removeEventListener("abort", onAbort);
|
1449
|
+
});
|
1450
|
+
res.once("close", () => {
|
1451
|
+
abort.signal.removeEventListener("abort", onAbort);
|
1452
|
+
});
|
1453
|
+
try {
|
1454
|
+
req.on("error", (error) => {
|
1455
|
+
openTelemetryCollector.error("Request error:", error);
|
1456
|
+
req.emit("aborted");
|
1457
|
+
if (!res.headersSent) {
|
1458
|
+
res.status(400).send("Bad Request: aborted");
|
1459
|
+
}
|
1460
|
+
});
|
1461
|
+
req.on("timeout", () => {
|
1462
|
+
openTelemetryCollector.warn("Request timeout:", req.method, req.path);
|
1463
|
+
if (!res.headersSent) {
|
1464
|
+
res.status(408).send("Request Timeout");
|
1465
|
+
}
|
1466
|
+
});
|
1467
|
+
res.on("error", (error) => {
|
1468
|
+
openTelemetryCollector.error("Response error:", error);
|
1469
|
+
res.emit("close");
|
1470
|
+
});
|
1471
|
+
const next = (error) => {
|
1472
|
+
if (error) {
|
1473
|
+
openTelemetryCollector.error("Express middleware error:", error);
|
1474
|
+
if (!res.headersSent) {
|
1475
|
+
const status = error?.status || error?.statusCode || 500;
|
1476
|
+
res.status(status);
|
1477
|
+
if (development) {
|
1478
|
+
const message = error?.message || String(error);
|
1479
|
+
res.send(`${status} ${message}`);
|
1480
|
+
} else {
|
1481
|
+
const message = status === 404 ? "Not Found" : status === 401 ? "Unauthorized" : status === 403 ? "Forbidden" : status === 400 ? "Bad Request" : "Internal Server Error";
|
1482
|
+
res.send(message);
|
1483
|
+
}
|
1484
|
+
}
|
1485
|
+
return;
|
1486
|
+
}
|
1487
|
+
};
|
1488
|
+
if (development) {
|
1489
|
+
openTelemetryCollector.info(
|
1490
|
+
`${request.method} ${pathname} - Started`
|
1491
|
+
);
|
1492
|
+
}
|
1493
|
+
try {
|
1494
|
+
app(req, res, next);
|
1495
|
+
} catch (syncError) {
|
1496
|
+
openTelemetryCollector.error(
|
1497
|
+
"Synchronous Express application error:",
|
1498
|
+
syncError
|
1499
|
+
);
|
1500
|
+
next(syncError);
|
1501
|
+
}
|
1502
|
+
} catch (error) {
|
1503
|
+
openTelemetryCollector.error("Request processing error:", error);
|
1504
|
+
const message = development ? error.message || String(error) : "Internal Server Error";
|
1505
|
+
return new Response(message, {
|
1506
|
+
status: 500,
|
1507
|
+
headers: { "content-type": "text/plain" }
|
1508
|
+
});
|
1509
|
+
}
|
1510
|
+
queueMicrotask(() => {
|
1511
|
+
if (!responded && (res.headersSent || res.statusCode !== 200)) {
|
1512
|
+
ensureResponse();
|
1513
|
+
}
|
1514
|
+
});
|
1515
|
+
if (development) {
|
1516
|
+
setTimeout(() => {
|
1517
|
+
if (!responded && !serverClosed) {
|
1518
|
+
try {
|
1519
|
+
openTelemetryCollector.warn(
|
1520
|
+
`Request timeout: ${request.method} ${pathname} - No response after 30s`
|
1521
|
+
);
|
1522
|
+
openTelemetryCollector.warn(
|
1523
|
+
`Headers sent: ${res.headersSent}, Status: ${res.statusCode}`
|
1524
|
+
);
|
1525
|
+
if (!res.headersSent) {
|
1526
|
+
res.status(504).send("Gateway Timeout");
|
1527
|
+
} else {
|
1528
|
+
writer.close();
|
1529
|
+
ensureResponse();
|
1530
|
+
}
|
1531
|
+
} catch (error) {
|
1532
|
+
openTelemetryCollector.error(
|
1533
|
+
"Error sending timeout response:",
|
1534
|
+
error
|
1535
|
+
);
|
1536
|
+
if (!responded) {
|
1537
|
+
ensureResponse();
|
1538
|
+
}
|
1539
|
+
}
|
1540
|
+
}
|
1541
|
+
}, 3e4);
|
1542
|
+
}
|
1543
|
+
return await responsePromise;
|
1544
|
+
}
|
1545
|
+
});
|
1546
|
+
const serverObj = {
|
1547
|
+
port: server.port,
|
1548
|
+
hostname: server.hostname,
|
1549
|
+
url: `${tls2 ? "https" : "http"}://${host === "0.0.0.0" ? "localhost" : host}:${server.port}`,
|
1550
|
+
stop(force = false) {
|
1551
|
+
serverClosed = true;
|
1552
|
+
openTelemetryCollector.info(`Stopping server on port ${server.port}...`);
|
1553
|
+
server.stop(force);
|
1554
|
+
},
|
1555
|
+
reload() {
|
1556
|
+
if (development) {
|
1557
|
+
openTelemetryCollector.info(
|
1558
|
+
"Server reload requested - restart server to apply changes"
|
1559
|
+
);
|
1560
|
+
}
|
1561
|
+
},
|
1562
|
+
address() {
|
1563
|
+
return {
|
1564
|
+
port: server.port,
|
1565
|
+
family: "IPv4",
|
1566
|
+
address: host
|
1567
|
+
};
|
1568
|
+
},
|
1569
|
+
listening: true,
|
1570
|
+
connections: 0,
|
1571
|
+
maxConnections: void 0,
|
1572
|
+
on: (event, listener) => {
|
1573
|
+
if (event === "listening") {
|
1574
|
+
process.nextTick(listener);
|
1575
|
+
}
|
1576
|
+
return serverObj;
|
1577
|
+
},
|
1578
|
+
once: (event, listener) => {
|
1579
|
+
if (event === "listening") {
|
1580
|
+
process.nextTick(listener);
|
1581
|
+
}
|
1582
|
+
return serverObj;
|
1583
|
+
},
|
1584
|
+
emit: (event, ...args) => {
|
1585
|
+
return true;
|
1586
|
+
},
|
1587
|
+
async close(callback) {
|
1588
|
+
try {
|
1589
|
+
serverClosed = true;
|
1590
|
+
server.stop(true);
|
1591
|
+
if (callback) callback();
|
1592
|
+
} catch (error) {
|
1593
|
+
if (callback) callback(error);
|
1594
|
+
}
|
1595
|
+
},
|
1596
|
+
getConnections(callback) {
|
1597
|
+
process.nextTick(() => callback(null, serverObj.connections));
|
1598
|
+
}
|
1599
|
+
};
|
1600
|
+
if (development) {
|
1601
|
+
openTelemetryCollector.info(
|
1602
|
+
`\u{1F680} Express server running on ${serverObj.url}`
|
1603
|
+
);
|
1604
|
+
openTelemetryCollector.info(
|
1605
|
+
`\u{1F4C1} Environment: ${development ? "development" : "production"}`
|
1606
|
+
);
|
1607
|
+
}
|
1608
|
+
return serverObj;
|
1609
|
+
}
|
1610
|
+
|
1611
|
+
// src/cluster/bun.cluster.ts
|
1612
|
+
function startBunCluster(config) {
|
1613
|
+
const WORKERS = config.workerCount;
|
1614
|
+
const PORT = config.port;
|
1615
|
+
const HOST = config.host;
|
1616
|
+
const openTelemetryCollector = config.openTelemetryCollector;
|
1617
|
+
if (WORKERS > import_node_os.default.cpus().length) {
|
1618
|
+
throw new Error("Worker count cannot be greater than the number of CPUs");
|
1619
|
+
}
|
1620
|
+
if (import_node_cluster.default.isPrimary) {
|
1621
|
+
let startWorker2 = function(i) {
|
1622
|
+
if (isShuttingDown) return;
|
1623
|
+
const worker = import_node_cluster.default.fork({
|
1624
|
+
WORKER_INDEX: String(i),
|
1625
|
+
PORT: String(PORT)
|
1626
|
+
});
|
1627
|
+
workers.set(worker.id, worker);
|
1628
|
+
worker.on("exit", () => {
|
1629
|
+
if (isShuttingDown) {
|
1630
|
+
return;
|
1631
|
+
}
|
1632
|
+
workers.delete(worker.id);
|
1633
|
+
openTelemetryCollector.warn(
|
1634
|
+
`worker ${worker.process.pid} died; restarting in 2s`
|
1635
|
+
);
|
1636
|
+
setTimeout(() => {
|
1637
|
+
if (!isShuttingDown) {
|
1638
|
+
startWorker2(i);
|
1639
|
+
}
|
1640
|
+
}, 2e3);
|
1641
|
+
});
|
1642
|
+
worker.on("message", (message) => {
|
1643
|
+
if (message && message.type === "worker-ready") {
|
1644
|
+
openTelemetryCollector.info(
|
1645
|
+
`Worker ${i} (PID: ${worker.process.pid}) ready`
|
1646
|
+
);
|
1647
|
+
}
|
1648
|
+
});
|
1649
|
+
};
|
1650
|
+
var startWorker = startWorker2;
|
1651
|
+
const workers = /* @__PURE__ */ new Map();
|
1652
|
+
let isShuttingDown = false;
|
1653
|
+
openTelemetryCollector.info(
|
1654
|
+
`[primary ${process.pid}] starting ${WORKERS} workers on :${PORT}. Ignoring routing strategy due to SO_REUSEPORT kernel level routing.`
|
1655
|
+
);
|
1656
|
+
for (let i = 0; i < WORKERS; i++) {
|
1657
|
+
startWorker2(i);
|
1658
|
+
}
|
1659
|
+
process.on("SIGINT", () => {
|
1660
|
+
isShuttingDown = true;
|
1661
|
+
openTelemetryCollector.info(
|
1662
|
+
"Received SIGINT, shutting down gracefully..."
|
1663
|
+
);
|
1664
|
+
workers.forEach((worker) => {
|
1665
|
+
worker.send({ type: "shutdown" });
|
1666
|
+
worker.kill("SIGTERM");
|
1667
|
+
});
|
1668
|
+
setTimeout(() => {
|
1669
|
+
workers.forEach((worker) => worker.kill("SIGKILL"));
|
1670
|
+
process.exit(0);
|
1671
|
+
}, 5e3);
|
1672
|
+
});
|
1673
|
+
} else {
|
1674
|
+
const PORT2 = Number(process.env.PORT || 6935);
|
1675
|
+
const IDX = process.env.WORKER_INDEX ?? "0";
|
1676
|
+
const server = serveExpress(
|
1677
|
+
config.expressApp,
|
1678
|
+
config.openTelemetryCollector,
|
1679
|
+
{
|
1680
|
+
port: PORT2,
|
1681
|
+
host: HOST,
|
1682
|
+
reusePort: true,
|
1683
|
+
development: false,
|
1684
|
+
tls: config.ssl
|
1685
|
+
}
|
1686
|
+
);
|
1687
|
+
if (process.send) {
|
1688
|
+
process.send({ type: "worker-ready", port: server.port, index: IDX });
|
1689
|
+
}
|
1690
|
+
setInterval(() => {
|
1691
|
+
const memUsage = process.memoryUsage();
|
1692
|
+
const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024);
|
1693
|
+
if (heapUsedMB > 100) {
|
1694
|
+
openTelemetryCollector.warn(
|
1695
|
+
`High memory usage on worker ${process.pid}: ${heapUsedMB} MB`
|
1696
|
+
);
|
1697
|
+
}
|
1698
|
+
}, 3e4);
|
1699
|
+
process.on("SIGINT", () => {
|
1700
|
+
openTelemetryCollector.info(
|
1701
|
+
`[worker ${process.pid}] shutting down gracefully...`
|
1702
|
+
);
|
1703
|
+
server.stop();
|
1704
|
+
process.exit(0);
|
1705
|
+
});
|
1706
|
+
process.on("message", (message) => {
|
1707
|
+
if (message?.type === "shutdown") {
|
1708
|
+
openTelemetryCollector.info(
|
1709
|
+
`[worker ${process.pid}] received shutdown signal from primary`
|
1710
|
+
);
|
1711
|
+
server.stop();
|
1712
|
+
process.exit(0);
|
1713
|
+
}
|
1714
|
+
});
|
1715
|
+
process.on("uncaughtException", (err) => {
|
1716
|
+
openTelemetryCollector.error(
|
1717
|
+
`Uncaught exception on worker ${process.pid}:`,
|
1718
|
+
err
|
1719
|
+
);
|
1720
|
+
process.exit(1);
|
1721
|
+
});
|
1722
|
+
process.on("unhandledRejection", (reason) => {
|
1723
|
+
openTelemetryCollector.error(
|
1724
|
+
`Unhandled rejection on worker ${process.pid}:`,
|
1725
|
+
reason
|
1726
|
+
);
|
1727
|
+
process.exit(1);
|
1728
|
+
});
|
1729
|
+
}
|
1730
|
+
}
|
1731
|
+
|
1732
|
+
// src/cluster/node.cluster.ts
|
49
1733
|
var import_common = require("@forklaunch/common");
|
1734
|
+
var import_node_cluster2 = __toESM(require("cluster"));
|
1735
|
+
var import_node_fs = __toESM(require("fs"));
|
1736
|
+
var import_node_http = __toESM(require("http"));
|
1737
|
+
var import_node_https = __toESM(require("https"));
|
1738
|
+
var import_node_net = __toESM(require("net"));
|
1739
|
+
var import_node_os2 = __toESM(require("os"));
|
1740
|
+
var import_node_tls = __toESM(require("tls"));
|
1741
|
+
function startNodeCluster(config) {
|
1742
|
+
const PORT = config.port;
|
1743
|
+
const HOST = config.host;
|
1744
|
+
const WORKERS = config.workerCount;
|
1745
|
+
const ROUTING_STRATEGY = config.routingStrategy || "round-robin";
|
1746
|
+
const app = config.expressApp;
|
1747
|
+
const openTelemetryCollector = config.openTelemetryCollector;
|
1748
|
+
const SSL_CONFIG = config.ssl;
|
1749
|
+
if (WORKERS > import_node_os2.default.cpus().length) {
|
1750
|
+
throw new Error("Worker count cannot be greater than the number of CPUs");
|
1751
|
+
}
|
1752
|
+
let sslOptions;
|
1753
|
+
if (SSL_CONFIG) {
|
1754
|
+
try {
|
1755
|
+
sslOptions = {
|
1756
|
+
key: import_node_fs.default.readFileSync(SSL_CONFIG.keyFile),
|
1757
|
+
cert: import_node_fs.default.readFileSync(SSL_CONFIG.certFile),
|
1758
|
+
ca: import_node_fs.default.readFileSync(SSL_CONFIG.caFile)
|
1759
|
+
};
|
1760
|
+
openTelemetryCollector.info(`SSL/TLS configuration loaded from files`);
|
1761
|
+
} catch (error) {
|
1762
|
+
openTelemetryCollector.error(
|
1763
|
+
"Failed to load SSL/TLS certificates:",
|
1764
|
+
error
|
1765
|
+
);
|
1766
|
+
throw new Error("SSL/TLS configuration failed");
|
1767
|
+
}
|
1768
|
+
}
|
1769
|
+
if (import_node_cluster2.default.isPrimary) {
|
1770
|
+
let getWorker2 = function(remoteAddress) {
|
1771
|
+
switch (ROUTING_STRATEGY) {
|
1772
|
+
case "sticky": {
|
1773
|
+
const ip = remoteAddress ?? "";
|
1774
|
+
const idx = (0, import_common.hashString)(ip) % workers.length;
|
1775
|
+
return workers[idx];
|
1776
|
+
}
|
1777
|
+
case "random": {
|
1778
|
+
return workers[Math.floor(Math.random() * workers.length)];
|
1779
|
+
}
|
1780
|
+
case "round-robin":
|
1781
|
+
default: {
|
1782
|
+
const worker = workers[currentWorkerIndex];
|
1783
|
+
currentWorkerIndex = (currentWorkerIndex + 1) % workers.length;
|
1784
|
+
return worker;
|
1785
|
+
}
|
1786
|
+
}
|
1787
|
+
};
|
1788
|
+
var getWorker = getWorker2;
|
1789
|
+
import_node_cluster2.default.setupPrimary({ execArgv: process.execArgv });
|
1790
|
+
const protocol = SSL_CONFIG ? "https" : "http";
|
1791
|
+
openTelemetryCollector.info(
|
1792
|
+
`[primary ${process.pid}] starting ${WORKERS} workers with ${ROUTING_STRATEGY} routing on ${protocol}://${HOST}:${PORT}`
|
1793
|
+
);
|
1794
|
+
const workers = Array.from({ length: WORKERS }, (_, i) => {
|
1795
|
+
const worker = import_node_cluster2.default.fork();
|
1796
|
+
worker.on(
|
1797
|
+
"message",
|
1798
|
+
(message) => {
|
1799
|
+
if (message && message.type === "worker-ready") {
|
1800
|
+
openTelemetryCollector.info(
|
1801
|
+
`Worker ${message.index || i} (PID: ${worker.process.pid}) ready`
|
1802
|
+
);
|
1803
|
+
}
|
1804
|
+
}
|
1805
|
+
);
|
1806
|
+
return worker;
|
1807
|
+
});
|
1808
|
+
let currentWorkerIndex = 0;
|
1809
|
+
const server = SSL_CONFIG ? import_node_tls.default.createServer(sslOptions, (socket) => {
|
1810
|
+
const w = getWorker2(socket.remoteAddress);
|
1811
|
+
w.send({ type: "sticky-connection" }, socket);
|
1812
|
+
}) : import_node_net.default.createServer({ pauseOnConnect: true }, (socket) => {
|
1813
|
+
const w = getWorker2(socket.remoteAddress);
|
1814
|
+
w.send({ type: "sticky-connection" }, socket);
|
1815
|
+
});
|
1816
|
+
server.on("error", (err) => {
|
1817
|
+
openTelemetryCollector.error("primary net server error:", err);
|
1818
|
+
});
|
1819
|
+
server.listen(PORT, HOST, () => {
|
1820
|
+
const protocol2 = SSL_CONFIG ? "https" : "http";
|
1821
|
+
openTelemetryCollector.info(
|
1822
|
+
`[primary ${process.pid}] listening on ${protocol2}://${HOST}:${PORT}`
|
1823
|
+
);
|
1824
|
+
});
|
1825
|
+
import_node_cluster2.default.on("exit", (worker) => {
|
1826
|
+
openTelemetryCollector.warn(
|
1827
|
+
`worker ${worker.process.pid} died; restarting`
|
1828
|
+
);
|
1829
|
+
const i = workers.findIndex((w) => w.id === worker.id);
|
1830
|
+
const replacement = import_node_cluster2.default.fork();
|
1831
|
+
replacement.on(
|
1832
|
+
"message",
|
1833
|
+
(message) => {
|
1834
|
+
if (message && message.type === "worker-ready") {
|
1835
|
+
openTelemetryCollector.info(
|
1836
|
+
`Worker ${message.index || i} (PID: ${replacement.process.pid}) ready`
|
1837
|
+
);
|
1838
|
+
}
|
1839
|
+
}
|
1840
|
+
);
|
1841
|
+
if (i !== -1) workers[i] = replacement;
|
1842
|
+
});
|
1843
|
+
let isShuttingDown = false;
|
1844
|
+
process.on("SIGINT", () => {
|
1845
|
+
if (isShuttingDown) return;
|
1846
|
+
isShuttingDown = true;
|
1847
|
+
openTelemetryCollector.info(
|
1848
|
+
"Received SIGINT, shutting down gracefully..."
|
1849
|
+
);
|
1850
|
+
workers.forEach((worker) => {
|
1851
|
+
worker.send({ type: "shutdown" });
|
1852
|
+
worker.kill("SIGTERM");
|
1853
|
+
});
|
1854
|
+
setTimeout(() => {
|
1855
|
+
workers.forEach((worker) => worker.kill("SIGKILL"));
|
1856
|
+
process.exit(0);
|
1857
|
+
}, 5e3);
|
1858
|
+
});
|
1859
|
+
} else {
|
1860
|
+
const server = SSL_CONFIG ? import_node_https.default.createServer(sslOptions, app) : import_node_http.default.createServer(app);
|
1861
|
+
const IDX = process.env.WORKER_INDEX ?? import_node_cluster2.default.worker?.id ?? "0";
|
1862
|
+
process.on("message", (msg, socket) => {
|
1863
|
+
if (msg?.type === "sticky-connection" && socket) {
|
1864
|
+
server.emit("connection", socket);
|
1865
|
+
socket.resume();
|
1866
|
+
} else if (msg?.type === "shutdown") {
|
1867
|
+
openTelemetryCollector.info(
|
1868
|
+
`[worker ${process.pid}] received shutdown signal from primary`
|
1869
|
+
);
|
1870
|
+
server.close(() => {
|
1871
|
+
process.exit(0);
|
1872
|
+
});
|
1873
|
+
}
|
1874
|
+
});
|
1875
|
+
server.on("clientError", (err, socket) => {
|
1876
|
+
try {
|
1877
|
+
const response = SSL_CONFIG ? "HTTP/1.1 400 Bad Request\r\n\r\n" : "HTTP/1.1 400 Bad Request\r\n\r\n";
|
1878
|
+
socket.end(response);
|
1879
|
+
} catch {
|
1880
|
+
openTelemetryCollector.error("clientError", err);
|
1881
|
+
}
|
1882
|
+
});
|
1883
|
+
server.listen(0, () => {
|
1884
|
+
if (process.send) {
|
1885
|
+
process.send({ type: "worker-ready", port: PORT, index: IDX });
|
1886
|
+
}
|
1887
|
+
});
|
1888
|
+
setInterval(() => {
|
1889
|
+
const memUsage = process.memoryUsage();
|
1890
|
+
const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024);
|
1891
|
+
if (heapUsedMB > 100) {
|
1892
|
+
openTelemetryCollector.warn(
|
1893
|
+
`High memory usage on worker ${process.pid}: ${heapUsedMB} MB`
|
1894
|
+
);
|
1895
|
+
}
|
1896
|
+
}, 3e4);
|
1897
|
+
process.on("uncaughtException", (err) => {
|
1898
|
+
openTelemetryCollector.error(
|
1899
|
+
`Uncaught exception on worker ${process.pid}:`,
|
1900
|
+
err
|
1901
|
+
);
|
1902
|
+
process.exit(1);
|
1903
|
+
});
|
1904
|
+
process.on("unhandledRejection", (reason) => {
|
1905
|
+
openTelemetryCollector.error(
|
1906
|
+
`Unhandled rejection on worker ${process.pid}:`,
|
1907
|
+
reason
|
1908
|
+
);
|
1909
|
+
process.exit(1);
|
1910
|
+
});
|
1911
|
+
const protocol = SSL_CONFIG ? "https" : "http";
|
1912
|
+
openTelemetryCollector.info(
|
1913
|
+
`[worker ${process.pid}] ready (awaiting sockets from primary) - ${protocol}`
|
1914
|
+
);
|
1915
|
+
}
|
1916
|
+
}
|
1917
|
+
|
1918
|
+
// src/middleware/content.parse.middleware.ts
|
1919
|
+
var import_common2 = require("@forklaunch/common");
|
50
1920
|
var import_http = require("@forklaunch/core/http");
|
51
1921
|
var import_busboy = __toESM(require("busboy"));
|
52
1922
|
var import_express = __toESM(require("express"));
|
@@ -121,7 +1991,7 @@ function contentParse(options2) {
|
|
121
1991
|
break;
|
122
1992
|
}
|
123
1993
|
default:
|
124
|
-
(0,
|
1994
|
+
(0, import_common2.isNever)(discriminatedBody.parserType);
|
125
1995
|
throw new Error(
|
126
1996
|
"Unsupported parser type for body: " + discriminatedBody.parserType
|
127
1997
|
);
|
@@ -133,7 +2003,7 @@ function contentParse(options2) {
|
|
133
2003
|
}
|
134
2004
|
|
135
2005
|
// src/middleware/enrichResponseTransmission.middleware.ts
|
136
|
-
var
|
2006
|
+
var import_common3 = require("@forklaunch/common");
|
137
2007
|
var import_http2 = require("@forklaunch/core/http");
|
138
2008
|
function enrichResponseTransmission(req, res, next) {
|
139
2009
|
const originalSend = res.send;
|
@@ -155,9 +2025,9 @@ function enrichResponseTransmission(req, res, next) {
|
|
155
2025
|
res.setHeader = function(name, value) {
|
156
2026
|
let stringifiedValue;
|
157
2027
|
if (Array.isArray(value)) {
|
158
|
-
stringifiedValue = value.map((v) => (0,
|
2028
|
+
stringifiedValue = value.map((v) => (0, import_common3.safeStringify)(v)).join("\n");
|
159
2029
|
} else {
|
160
|
-
stringifiedValue = (0,
|
2030
|
+
stringifiedValue = (0, import_common3.safeStringify)(value);
|
161
2031
|
}
|
162
2032
|
return originalSetHeader.call(this, name, stringifiedValue);
|
163
2033
|
};
|
@@ -171,6 +2041,9 @@ function enrichResponseTransmission(req, res, next) {
|
|
171
2041
|
// src/expressApplication.ts
|
172
2042
|
var Application = class extends import_http3.ForklaunchExpressLikeApplication {
|
173
2043
|
docsConfiguration;
|
2044
|
+
mcpConfiguration;
|
2045
|
+
openapiConfiguration;
|
2046
|
+
hostingConfiguration;
|
174
2047
|
/**
|
175
2048
|
* Creates an instance of Application.
|
176
2049
|
*
|
@@ -189,90 +2062,153 @@ var Application = class extends import_http3.ForklaunchExpressLikeApplication {
|
|
189
2062
|
openTelemetryCollector,
|
190
2063
|
options2
|
191
2064
|
);
|
2065
|
+
console.log("this.routerOptions offa", this.routerOptions);
|
2066
|
+
this.hostingConfiguration = options2?.hosting;
|
192
2067
|
this.docsConfiguration = options2?.docs;
|
2068
|
+
this.mcpConfiguration = options2?.mcp;
|
2069
|
+
this.openapiConfiguration = options2?.openapi;
|
193
2070
|
}
|
194
2071
|
listen(...args) {
|
195
2072
|
const port = typeof args[0] === "number" ? args[0] : Number(process.env.PORT);
|
196
2073
|
const host = typeof args[1] === "string" ? args[1] : process.env.HOST ?? "localhost";
|
197
2074
|
const protocol = process.env.PROTOCOL ?? "http";
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
openApiServerDescriptions,
|
208
|
-
this
|
209
|
-
);
|
210
|
-
if (this.schemaValidator instanceof import_zod.ZodSchemaValidator) {
|
2075
|
+
if (this.schemaValidator instanceof import_zod.ZodSchemaValidator && this.mcpConfiguration !== false) {
|
2076
|
+
const {
|
2077
|
+
port: mcpPort,
|
2078
|
+
options: options2,
|
2079
|
+
path: mcpPath,
|
2080
|
+
version,
|
2081
|
+
additionalTools,
|
2082
|
+
contentTypeMapping
|
2083
|
+
} = this.mcpConfiguration ?? {};
|
211
2084
|
const zodSchemaValidator = this.schemaValidator;
|
2085
|
+
const finalMcpPort = mcpPort ?? port + 2e3;
|
212
2086
|
const mcpServer = (0, import_http3.generateMcpServer)(
|
213
2087
|
zodSchemaValidator,
|
214
2088
|
protocol,
|
215
2089
|
host,
|
216
|
-
|
217
|
-
"1.0.0",
|
218
|
-
this
|
2090
|
+
finalMcpPort,
|
2091
|
+
version ?? "1.0.0",
|
2092
|
+
this,
|
2093
|
+
this.mcpConfiguration,
|
2094
|
+
options2,
|
2095
|
+
contentTypeMapping
|
219
2096
|
);
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
2097
|
+
if (additionalTools) {
|
2098
|
+
additionalTools(mcpServer);
|
2099
|
+
}
|
2100
|
+
if (this.hostingConfiguration?.workerCount && this.hostingConfiguration.workerCount > 1) {
|
2101
|
+
(0, import_http3.isPortBound)(finalMcpPort, host).then((isBound) => {
|
2102
|
+
if (!isBound) {
|
2103
|
+
mcpServer.start({
|
2104
|
+
httpStream: {
|
2105
|
+
host,
|
2106
|
+
endpoint: mcpPath ?? "/mcp",
|
2107
|
+
port: finalMcpPort
|
2108
|
+
},
|
2109
|
+
transportType: "httpStream"
|
2110
|
+
});
|
2111
|
+
}
|
2112
|
+
});
|
2113
|
+
} else {
|
2114
|
+
mcpServer.start({
|
2115
|
+
httpStream: {
|
2116
|
+
host,
|
2117
|
+
endpoint: mcpPath ?? "/mcp",
|
2118
|
+
port: finalMcpPort
|
2119
|
+
},
|
2120
|
+
transportType: "httpStream"
|
2121
|
+
});
|
2122
|
+
}
|
228
2123
|
}
|
229
|
-
if (this.
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
2124
|
+
if (this.openapiConfiguration !== false) {
|
2125
|
+
const openApiServerUrls = (0, import_common4.getEnvVar)("DOCS_SERVER_URLS")?.split(",") ?? [
|
2126
|
+
`${protocol}://${host}:${port}`
|
2127
|
+
];
|
2128
|
+
const openApiServerDescriptions = (0, import_common4.getEnvVar)(
|
2129
|
+
"DOCS_SERVER_DESCRIPTIONS"
|
2130
|
+
)?.split(",") ?? ["Main Server"];
|
2131
|
+
const openApi = (0, import_http3.generateOpenApiSpecs)(
|
2132
|
+
this.schemaValidator,
|
2133
|
+
openApiServerUrls,
|
2134
|
+
openApiServerDescriptions,
|
2135
|
+
this,
|
2136
|
+
this.openapiConfiguration
|
2137
|
+
);
|
2138
|
+
if (this.docsConfiguration == null || this.docsConfiguration.type === "scalar") {
|
2139
|
+
this.internal.use(
|
2140
|
+
`/api${process.env.VERSION ? `/${process.env.VERSION}` : ""}${process.env.DOCS_PATH ?? "/docs"}`,
|
2141
|
+
(0, import_express_api_reference.apiReference)({
|
2142
|
+
...this.docsConfiguration,
|
2143
|
+
sources: [
|
2144
|
+
{
|
2145
|
+
content: openApi[import_http3.OPENAPI_DEFAULT_VERSION],
|
2146
|
+
title: "API Reference"
|
2147
|
+
},
|
2148
|
+
...Object.entries(openApi).map(([version, spec]) => ({
|
2149
|
+
content: typeof this.openapiConfiguration === "boolean" ? spec : this.openapiConfiguration?.discreteVersions === false ? {
|
2150
|
+
...openApi[import_http3.OPENAPI_DEFAULT_VERSION],
|
2151
|
+
...spec
|
2152
|
+
} : spec,
|
2153
|
+
title: `API Reference - ${version}`
|
2154
|
+
})),
|
2155
|
+
...this.docsConfiguration?.sources ?? []
|
2156
|
+
]
|
2157
|
+
})
|
2158
|
+
);
|
2159
|
+
} else if (this.docsConfiguration.type === "swagger") {
|
2160
|
+
this.internal.use(
|
2161
|
+
`/api${process.env.VERSION ? `/${process.env.VERSION}` : ""}${process.env.DOCS_PATH ?? "/docs"}`,
|
2162
|
+
import_swagger_ui_express.default.serveFiles(openApi),
|
2163
|
+
import_swagger_ui_express.default.setup(openApi)
|
2164
|
+
);
|
2165
|
+
}
|
2166
|
+
this.internal.get(
|
2167
|
+
`/api${process.env.VERSION ? `/${process.env.VERSION}` : ""}/openapi`,
|
2168
|
+
(_, res) => {
|
2169
|
+
res.type("application/json");
|
2170
|
+
res.json({
|
2171
|
+
latest: openApi[import_http3.OPENAPI_DEFAULT_VERSION],
|
2172
|
+
...Object.fromEntries(
|
2173
|
+
Object.entries(openApi).map(([version, spec]) => [
|
2174
|
+
`v${version}`,
|
2175
|
+
typeof this.openapiConfiguration === "boolean" ? spec : this.openapiConfiguration?.discreteVersions === false ? {
|
2176
|
+
...openApi[import_http3.OPENAPI_DEFAULT_VERSION],
|
2177
|
+
...spec
|
2178
|
+
} : spec
|
2179
|
+
])
|
2180
|
+
)
|
2181
|
+
});
|
2182
|
+
}
|
2183
|
+
);
|
2184
|
+
this.internal.get(
|
2185
|
+
`/api${process.env.VERSION ? `/${process.env.VERSION}` : ""}/openapi/:id`,
|
2186
|
+
async (req, res) => {
|
2187
|
+
res.type("application/json");
|
2188
|
+
if (req.params.id === "latest") {
|
2189
|
+
res.json(openApi[import_http3.OPENAPI_DEFAULT_VERSION]);
|
2190
|
+
} else {
|
2191
|
+
if (openApi[req.params.id] == null) {
|
2192
|
+
res.status(404).send("Not Found");
|
2193
|
+
return;
|
2194
|
+
}
|
2195
|
+
res.json(
|
2196
|
+
typeof this.openapiConfiguration === "boolean" ? openApi[req.params.id] : this.openapiConfiguration?.discreteVersions === false ? {
|
2197
|
+
...openApi[import_http3.OPENAPI_DEFAULT_VERSION],
|
2198
|
+
...openApi[req.params.id]
|
2199
|
+
} : openApi[req.params.id]
|
2200
|
+
);
|
2201
|
+
}
|
2202
|
+
}
|
246
2203
|
);
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
2204
|
+
this.internal.get(
|
2205
|
+
`/api/${process.env.VERSION ?? "v1"}/openapi-hash`,
|
2206
|
+
async (_, res) => {
|
2207
|
+
const hash = await import_crypto.default.createHash("sha256").update((0, import_common4.safeStringify)(openApi)).digest("hex");
|
2208
|
+
res.send(hash);
|
2209
|
+
}
|
252
2210
|
);
|
253
2211
|
}
|
254
|
-
this.internal.get(
|
255
|
-
`/api${process.env.VERSION ? `/${process.env.VERSION}` : ""}/openapi`,
|
256
|
-
(_, res) => {
|
257
|
-
res.type("application/json");
|
258
|
-
res.json({
|
259
|
-
latest: openApi[import_http3.OPENAPI_DEFAULT_VERSION],
|
260
|
-
...Object.fromEntries(
|
261
|
-
Object.entries(openApi).map(([version, spec]) => [
|
262
|
-
`v${version}`,
|
263
|
-
spec
|
264
|
-
])
|
265
|
-
)
|
266
|
-
});
|
267
|
-
}
|
268
|
-
);
|
269
|
-
this.internal.get(
|
270
|
-
`/api/${process.env.VERSION ?? "v1"}/openapi-hash`,
|
271
|
-
async (_, res) => {
|
272
|
-
const hash = await import_crypto.default.createHash("sha256").update((0, import_common3.safeStringify)(openApi)).digest("hex");
|
273
|
-
res.send(hash);
|
274
|
-
}
|
275
|
-
);
|
276
2212
|
this.internal.get("/health", (_, res) => {
|
277
2213
|
res.send("OK");
|
278
2214
|
});
|
@@ -294,6 +2230,36 @@ Correlation id: ${(0, import_http3.isForklaunchRequest)(req) ? req.context.corre
|
|
294
2230
|
);
|
295
2231
|
};
|
296
2232
|
this.internal.use(errorHandler);
|
2233
|
+
const { workerCount, ssl, routingStrategy } = this.hostingConfiguration ?? {};
|
2234
|
+
if (workerCount != null && workerCount > 1) {
|
2235
|
+
if (typeof Bun !== "undefined") {
|
2236
|
+
this.openTelemetryCollector.warn(
|
2237
|
+
`Note: bun clustering is experimental, shimmed, and only works on linux. You may have an inconsistent experience, consider creating multiple hosts.`
|
2238
|
+
);
|
2239
|
+
Object.assign(this.internal, {
|
2240
|
+
basePath: this.basePath
|
2241
|
+
});
|
2242
|
+
startBunCluster({
|
2243
|
+
expressApp: this.internal,
|
2244
|
+
openTelemetryCollector: this.openTelemetryCollector,
|
2245
|
+
port,
|
2246
|
+
host,
|
2247
|
+
workerCount,
|
2248
|
+
routingStrategy,
|
2249
|
+
ssl
|
2250
|
+
});
|
2251
|
+
} else {
|
2252
|
+
startNodeCluster({
|
2253
|
+
expressApp: this.internal,
|
2254
|
+
openTelemetryCollector: this.openTelemetryCollector,
|
2255
|
+
port,
|
2256
|
+
host,
|
2257
|
+
workerCount,
|
2258
|
+
routingStrategy,
|
2259
|
+
ssl
|
2260
|
+
});
|
2261
|
+
}
|
2262
|
+
}
|
297
2263
|
return this.internal.listen(...args);
|
298
2264
|
}
|
299
2265
|
};
|
@@ -317,14 +2283,15 @@ var Router = class _Router extends import_http4.ForklaunchExpressLikeRouter {
|
|
317
2283
|
contentParse(options2),
|
318
2284
|
enrichResponseTransmission
|
319
2285
|
],
|
320
|
-
openTelemetryCollector
|
2286
|
+
openTelemetryCollector,
|
2287
|
+
options2
|
321
2288
|
);
|
322
2289
|
this.basePath = basePath;
|
323
2290
|
this.configOptions = options2;
|
324
2291
|
}
|
325
2292
|
configOptions;
|
326
|
-
route(
|
327
|
-
this.internal.route(
|
2293
|
+
route(path2) {
|
2294
|
+
this.internal.route(path2);
|
328
2295
|
return this;
|
329
2296
|
}
|
330
2297
|
param(name, _types, handler) {
|
@@ -505,175 +2472,179 @@ var Router = class _Router extends import_http4.ForklaunchExpressLikeRouter {
|
|
505
2472
|
|
506
2473
|
// src/handlers/checkout.ts
|
507
2474
|
var import_http5 = require("@forklaunch/core/http");
|
508
|
-
var checkout = (schemaValidator,
|
509
|
-
return (0, import_http5.middleware)(schemaValidator,
|
2475
|
+
var checkout = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2476
|
+
return (0, import_http5.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
510
2477
|
};
|
511
2478
|
|
512
2479
|
// src/handlers/copy.ts
|
513
2480
|
var import_http6 = require("@forklaunch/core/http");
|
514
|
-
var copy = (schemaValidator,
|
515
|
-
return (0, import_http6.middleware)(schemaValidator,
|
2481
|
+
var copy = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2482
|
+
return (0, import_http6.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
516
2483
|
};
|
517
2484
|
|
518
2485
|
// src/handlers/delete.ts
|
519
2486
|
var import_http7 = require("@forklaunch/core/http");
|
520
|
-
var delete_ = (schemaValidator,
|
521
|
-
return (0, import_http7.delete_)(schemaValidator,
|
2487
|
+
var delete_ = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2488
|
+
return (0, import_http7.delete_)(schemaValidator, path2, contractDetails, ...handlers2);
|
522
2489
|
};
|
523
2490
|
|
524
2491
|
// src/handlers/get.ts
|
525
2492
|
var import_http8 = require("@forklaunch/core/http");
|
526
|
-
var get = (schemaValidator,
|
527
|
-
return (0, import_http8.get)(schemaValidator,
|
2493
|
+
var get = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2494
|
+
return (0, import_http8.get)(schemaValidator, path2, contractDetails, ...handlers2);
|
528
2495
|
};
|
529
2496
|
|
530
2497
|
// src/handlers/head.ts
|
531
2498
|
var import_http9 = require("@forklaunch/core/http");
|
532
|
-
var head = (schemaValidator,
|
533
|
-
return (0, import_http9.head)(schemaValidator,
|
2499
|
+
var head = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2500
|
+
return (0, import_http9.head)(schemaValidator, path2, contractDetails, ...handlers2);
|
534
2501
|
};
|
535
2502
|
|
536
2503
|
// src/handlers/link.ts
|
537
2504
|
var import_http10 = require("@forklaunch/core/http");
|
538
|
-
var link = (schemaValidator,
|
539
|
-
return (0, import_http10.middleware)(schemaValidator,
|
2505
|
+
var link = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2506
|
+
return (0, import_http10.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
540
2507
|
};
|
541
2508
|
|
542
2509
|
// src/handlers/lock.ts
|
543
2510
|
var import_http11 = require("@forklaunch/core/http");
|
544
|
-
var lock = (schemaValidator,
|
545
|
-
return (0, import_http11.middleware)(schemaValidator,
|
2511
|
+
var lock = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2512
|
+
return (0, import_http11.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
546
2513
|
};
|
547
2514
|
|
548
2515
|
// src/handlers/m-search.ts
|
549
2516
|
var import_http12 = require("@forklaunch/core/http");
|
550
|
-
var mSearch = (schemaValidator,
|
551
|
-
return (0, import_http12.middleware)(schemaValidator,
|
2517
|
+
var mSearch = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2518
|
+
return (0, import_http12.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
552
2519
|
};
|
553
2520
|
|
554
2521
|
// src/handlers/merge.ts
|
555
2522
|
var import_http13 = require("@forklaunch/core/http");
|
556
|
-
var merge = (schemaValidator,
|
557
|
-
return (0, import_http13.middleware)(schemaValidator,
|
2523
|
+
var merge = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2524
|
+
return (0, import_http13.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
558
2525
|
};
|
559
2526
|
|
560
2527
|
// src/handlers/middleware.ts
|
561
2528
|
var import_http14 = require("@forklaunch/core/http");
|
562
|
-
var middleware7 = (schemaValidator,
|
563
|
-
return (0, import_http14.middleware)(schemaValidator,
|
2529
|
+
var middleware7 = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2530
|
+
return (0, import_http14.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
564
2531
|
};
|
565
2532
|
|
566
2533
|
// src/handlers/mkcactivity.ts
|
567
2534
|
var import_http15 = require("@forklaunch/core/http");
|
568
|
-
var mkcActivity = (schemaValidator,
|
569
|
-
return (0, import_http15.middleware)(schemaValidator,
|
2535
|
+
var mkcActivity = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2536
|
+
return (0, import_http15.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
570
2537
|
};
|
571
2538
|
|
572
2539
|
// src/handlers/mkcol.ts
|
573
2540
|
var import_http16 = require("@forklaunch/core/http");
|
574
|
-
var mkcol = (schemaValidator,
|
575
|
-
return (0, import_http16.middleware)(schemaValidator,
|
2541
|
+
var mkcol = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2542
|
+
return (0, import_http16.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
576
2543
|
};
|
577
2544
|
|
578
2545
|
// src/handlers/move.ts
|
579
2546
|
var import_http17 = require("@forklaunch/core/http");
|
580
|
-
var move = (schemaValidator,
|
581
|
-
return (0, import_http17.middleware)(schemaValidator,
|
2547
|
+
var move = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2548
|
+
return (0, import_http17.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
582
2549
|
};
|
583
2550
|
|
584
2551
|
// src/handlers/notify.ts
|
585
2552
|
var import_http18 = require("@forklaunch/core/http");
|
586
|
-
var notify = (schemaValidator,
|
587
|
-
return (0, import_http18.middleware)(schemaValidator,
|
2553
|
+
var notify = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2554
|
+
return (0, import_http18.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
588
2555
|
};
|
589
2556
|
|
590
2557
|
// src/handlers/options.ts
|
591
2558
|
var import_http19 = require("@forklaunch/core/http");
|
592
|
-
var options = (schemaValidator,
|
593
|
-
return (0, import_http19.options)(schemaValidator,
|
2559
|
+
var options = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2560
|
+
return (0, import_http19.options)(schemaValidator, path2, contractDetails, ...handlers2);
|
594
2561
|
};
|
595
2562
|
|
596
2563
|
// src/handlers/patch.ts
|
597
2564
|
var import_http20 = require("@forklaunch/core/http");
|
598
|
-
var patch = (schemaValidator,
|
599
|
-
return (0, import_http20.patch)(schemaValidator,
|
2565
|
+
var patch = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2566
|
+
return (0, import_http20.patch)(schemaValidator, path2, contractDetails, ...handlers2);
|
600
2567
|
};
|
601
2568
|
|
602
2569
|
// src/handlers/post.ts
|
603
2570
|
var import_http21 = require("@forklaunch/core/http");
|
604
|
-
var post = (schemaValidator,
|
605
|
-
return (0, import_http21.post)(schemaValidator,
|
2571
|
+
var post = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2572
|
+
return (0, import_http21.post)(schemaValidator, path2, contractDetails, ...handlers2);
|
606
2573
|
};
|
607
2574
|
|
608
2575
|
// src/handlers/propfind.ts
|
609
2576
|
var import_http22 = require("@forklaunch/core/http");
|
610
|
-
var propfind = (schemaValidator,
|
611
|
-
return (0, import_http22.middleware)(schemaValidator,
|
2577
|
+
var propfind = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2578
|
+
return (0, import_http22.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
612
2579
|
};
|
613
2580
|
|
614
2581
|
// src/handlers/proppatch.ts
|
615
2582
|
var import_http23 = require("@forklaunch/core/http");
|
616
|
-
var proppatch = (schemaValidator,
|
617
|
-
return (0, import_http23.middleware)(schemaValidator,
|
2583
|
+
var proppatch = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2584
|
+
return (0, import_http23.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
618
2585
|
};
|
619
2586
|
|
620
2587
|
// src/handlers/purge.ts
|
621
2588
|
var import_http24 = require("@forklaunch/core/http");
|
622
|
-
var purge = (schemaValidator,
|
623
|
-
return (0, import_http24.middleware)(schemaValidator,
|
2589
|
+
var purge = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2590
|
+
return (0, import_http24.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
624
2591
|
};
|
625
2592
|
|
626
2593
|
// src/handlers/put.ts
|
627
2594
|
var import_http25 = require("@forklaunch/core/http");
|
628
|
-
var put = (schemaValidator,
|
629
|
-
return (0, import_http25.put)(schemaValidator,
|
2595
|
+
var put = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2596
|
+
return (0, import_http25.put)(schemaValidator, path2, contractDetails, ...handlers2);
|
630
2597
|
};
|
631
2598
|
|
632
2599
|
// src/handlers/report.ts
|
633
2600
|
var import_http26 = require("@forklaunch/core/http");
|
634
|
-
var report = (schemaValidator,
|
635
|
-
return (0, import_http26.middleware)(schemaValidator,
|
2601
|
+
var report = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2602
|
+
return (0, import_http26.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
636
2603
|
};
|
637
2604
|
|
638
2605
|
// src/handlers/search.ts
|
639
2606
|
var import_http27 = require("@forklaunch/core/http");
|
640
|
-
var search = (schemaValidator,
|
641
|
-
return (0, import_http27.middleware)(schemaValidator,
|
2607
|
+
var search = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2608
|
+
return (0, import_http27.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
642
2609
|
};
|
643
2610
|
|
644
2611
|
// src/handlers/subscribe.ts
|
645
2612
|
var import_http28 = require("@forklaunch/core/http");
|
646
|
-
var subscribe = (schemaValidator,
|
647
|
-
return (0, import_http28.middleware)(schemaValidator,
|
2613
|
+
var subscribe = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2614
|
+
return (0, import_http28.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
648
2615
|
};
|
649
2616
|
|
650
2617
|
// src/handlers/trace.ts
|
651
2618
|
var import_http29 = require("@forklaunch/core/http");
|
652
|
-
var trace = (schemaValidator,
|
653
|
-
return (0, import_http29.trace)(schemaValidator,
|
2619
|
+
var trace = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2620
|
+
return (0, import_http29.trace)(schemaValidator, path2, contractDetails, ...handlers2);
|
654
2621
|
};
|
655
2622
|
|
656
2623
|
// src/handlers/unlink.ts
|
657
2624
|
var import_http30 = require("@forklaunch/core/http");
|
658
|
-
var unlink = (schemaValidator,
|
659
|
-
return (0, import_http30.middleware)(schemaValidator,
|
2625
|
+
var unlink = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2626
|
+
return (0, import_http30.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
660
2627
|
};
|
661
2628
|
|
662
2629
|
// src/handlers/unlock.ts
|
663
2630
|
var import_http31 = require("@forklaunch/core/http");
|
664
|
-
var unlock = (schemaValidator,
|
665
|
-
return (0, import_http31.middleware)(schemaValidator,
|
2631
|
+
var unlock = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2632
|
+
return (0, import_http31.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
666
2633
|
};
|
667
2634
|
|
668
2635
|
// src/handlers/unsubscribe.ts
|
669
2636
|
var import_http32 = require("@forklaunch/core/http");
|
670
|
-
var unsubscribe = (schemaValidator,
|
671
|
-
return (0, import_http32.middleware)(schemaValidator,
|
2637
|
+
var unsubscribe = (schemaValidator, path2, contractDetails, ...handlers2) => {
|
2638
|
+
return (0, import_http32.middleware)(schemaValidator, path2, contractDetails, ...handlers2);
|
672
2639
|
};
|
673
2640
|
|
674
2641
|
// index.ts
|
675
2642
|
function forklaunchExpress(schemaValidator, openTelemetryCollector, options2) {
|
676
|
-
return new Application(
|
2643
|
+
return new Application(
|
2644
|
+
schemaValidator,
|
2645
|
+
openTelemetryCollector,
|
2646
|
+
options2
|
2647
|
+
);
|
677
2648
|
}
|
678
2649
|
function forklaunchRouter(basePath, schemaValidator, openTelemetryCollector, options2) {
|
679
2650
|
const router = new Router(
|