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