@dunx/http 3.2.1 → 3.3.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/dist/index.js CHANGED
@@ -1,43 +1,107 @@
1
1
  // @bun
2
2
  import {
3
- TRACEPARENT_HEADER,
4
- TRACERESPONSE_HEADER,
5
- TRACESTATE_HEADER,
6
- TraceContext
7
- } from "./chunk-3j2n1n11.js";
3
+ HttpStatusCode2
4
+ } from "./chunk-bg0dr54z.js";
8
5
  import {
9
- ApiHidden,
10
- HIDDEN,
11
- HandlerKind,
12
- PUBLIC,
13
- Public,
14
- ROLES,
15
- Roles,
16
- UNMATCHED,
17
- UseGuards,
18
- buildContext,
19
- defaultStatusFor,
20
- discoverGateways,
21
- discoverRoutes,
22
- joinPath,
6
+ defaultStatusFor2,
7
+ markRoute,
23
8
  markController,
24
- markGateway,
9
+ metaKey2,
10
+ meta2,
11
+ ROLES2,
12
+ PUBLIC2,
13
+ HIDDEN2,
14
+ UNMATCHED2,
15
+ Roles2,
16
+ Public2,
17
+ ApiHidden2,
18
+ UseGuards2,
19
+ metaOf2,
20
+ mergeMeta2,
21
+ joinPath2,
22
+ discoverRoutes2,
23
+ HandlerKind,
25
24
  markHandler,
26
- markRoute,
27
- mergeMeta,
28
- meta,
29
- metaKey,
30
- metaOf
31
- } from "./chunk-3nbj06q8.js";
25
+ markGateway,
26
+ discoverGateways,
27
+ buildContext2
28
+ } from "./chunk-8939brh2.js";
32
29
  import {
33
- HttpStatusCode,
34
- __decorateElement,
35
- __decoratorMetadata,
36
- __decoratorStart,
37
- __privateAdd,
38
- __privateGet,
39
- __runInitializers
40
- } from "./chunk-sz4pvqxy.js";
30
+ TRACEPARENT_HEADER2,
31
+ TRACESTATE_HEADER2,
32
+ TRACERESPONSE_HEADER2,
33
+ TraceContext2
34
+ } from "./chunk-gmtwad7f.js";
35
+ var __create = Object.create;
36
+ var __defProp = Object.defineProperty;
37
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
38
+ var __name = (target, name) => {
39
+ Object.defineProperty(target, "name", {
40
+ value: name,
41
+ enumerable: false,
42
+ configurable: true
43
+ });
44
+ return target;
45
+ };
46
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
47
+ var __typeError = (msg) => {
48
+ throw TypeError(msg);
49
+ };
50
+ var __defNormalProp = (obj, key, value) => (key in obj) ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
51
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
52
+ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
53
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
54
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
55
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
56
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
57
+ var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
58
+ var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
59
+ var __expectFn = (fn) => fn !== undefined && typeof fn !== "function" ? __typeError("Function expected") : fn;
60
+ var __decoratorContext = (kind, name, done, metadata, fns) => ({
61
+ kind: __decoratorStrings[kind],
62
+ name,
63
+ metadata,
64
+ addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null))
65
+ });
66
+ var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
67
+ var __runInitializers = (array, flags, self, value) => {
68
+ for (var i = 0, fns = array[flags >> 1], n = fns && fns.length;i < n; i++)
69
+ flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
70
+ return value;
71
+ };
72
+ var __decorateElement = (array, flags, name, decorators, target, extra) => {
73
+ var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
74
+ var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
75
+ var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
76
+ var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : {
77
+ get [name]() {
78
+ return __privateGet(this, extra);
79
+ },
80
+ set [name](x) {
81
+ __privateSet(this, extra, x);
82
+ }
83
+ }, name));
84
+ k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
85
+ for (var i = decorators.length - 1;i >= 0; i--) {
86
+ ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
87
+ if (k) {
88
+ ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => (name in x) };
89
+ if (k ^ 3)
90
+ access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
91
+ if (k > 2)
92
+ access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
93
+ }
94
+ it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? undefined : { get: desc.get, set: desc.set } : target, ctx);
95
+ done._ = 1;
96
+ if (k ^ 4 || it === undefined)
97
+ __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
98
+ else if (typeof it !== "object" || it === null)
99
+ __typeError("Object expected");
100
+ else
101
+ __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
102
+ }
103
+ return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
104
+ };
41
105
 
42
106
  // src/route/decorators.ts
43
107
  var Controller = (prefix = "") => (target) => {
@@ -74,7 +138,7 @@ class ClientAddress {
74
138
  }
75
139
  const hops = trustedHops(source.trustProxy);
76
140
  if (hops > 0) {
77
- const entries = (req.headers.get("x-forwarded-for") ?? "").split(",").map((entry2) => entry2.trim()).filter((entry2) => entry2.length > 0);
141
+ const entries = (req.headers.get("x-forwarded-for") ?? "").split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
78
142
  const entry = entries[Math.max(0, entries.length - hops)];
79
143
  if (entry)
80
144
  return unmap(entry);
@@ -104,7 +168,7 @@ class ValidationError extends HttpError {
104
168
  issues;
105
169
  name = "ValidationError";
106
170
  constructor(source, issues) {
107
- super(HttpStatusCode.BAD_REQUEST, `Invalid ${source}`);
171
+ super(HttpStatusCode2.BAD_REQUEST, `Invalid ${source}`);
108
172
  this.source = source;
109
173
  this.issues = issues;
110
174
  }
@@ -129,7 +193,7 @@ var errorMapper = (logger) => (error) => {
129
193
  });
130
194
  }
131
195
  if (error instanceof AppError2 && isStatus(error.status)) {
132
- if (error.status >= HttpStatusCode.INTERNAL_SERVER_ERROR) {
196
+ if (error.status >= HttpStatusCode2.INTERNAL_SERVER_ERROR) {
133
197
  logger.error("Unhandled error", error);
134
198
  }
135
199
  return Response.json({ error: error.message, status: error.status }, { status: error.status });
@@ -137,8 +201,8 @@ var errorMapper = (logger) => (error) => {
137
201
  logger.error("Unhandled error", error);
138
202
  return Response.json({
139
203
  error: "Internal Server Error",
140
- status: HttpStatusCode.INTERNAL_SERVER_ERROR
141
- }, { status: HttpStatusCode.INTERNAL_SERVER_ERROR });
204
+ status: HttpStatusCode2.INTERNAL_SERVER_ERROR
205
+ }, { status: HttpStatusCode2.INTERNAL_SERVER_ERROR });
142
206
  };
143
207
  var isStatus = (value) => value !== undefined && Number.isInteger(value) && value >= 200 && value <= 599;
144
208
  var defaultErrorMapper = errorMapper(new ConsoleLogger);
@@ -174,7 +238,7 @@ class RequestMetrics {
174
238
  observe(ctx, status, durationNs, traceId) {
175
239
  let series = this.#series.get(ctx);
176
240
  if (series === undefined) {
177
- if (ctx.get(UNMATCHED) === true) {
241
+ if (ctx.get(UNMATCHED2) === true) {
178
242
  series = this.#unmatched.get(ctx.method);
179
243
  if (series === undefined) {
180
244
  series = seriesFor(UNMATCHED_ROUTE, ctx.method);
@@ -238,7 +302,7 @@ class MetricsMiddleware {
238
302
  this.metrics.observe(ctx, response.status, Bun.nanoseconds() - started);
239
303
  return response;
240
304
  }, (error) => {
241
- this.metrics.observe(ctx, error instanceof HttpError ? error.status : HttpStatusCode.INTERNAL_SERVER_ERROR, Bun.nanoseconds() - started);
305
+ this.metrics.observe(ctx, error instanceof HttpError ? error.status : HttpStatusCode2.INTERNAL_SERVER_ERROR, Bun.nanoseconds() - started);
242
306
  throw error;
243
307
  });
244
308
  }
@@ -348,7 +412,7 @@ var reportedByMiddleware = () => {
348
412
  };
349
413
  var unreported = (middleware) => "Socket middleware is installed and none of it sets reportsErrors, so a " + "throwing gateway handler is reported nowhere: the console fallback is off " + "whenever middleware wraps the handler. Set reportsErrors on the one that " + "records a failure, or pass websocket.onError. Installed: " + `${middleware.map((entry) => entry.constructor.name).join(", ")}.`;
350
414
  var runtimeOf = (socket) => socket.data[RUNTIME];
351
- var isBinary = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
415
+ var isBinary = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value) || value instanceof Blob;
352
416
  var replyRaw = (socket, value) => {
353
417
  if (value === undefined)
354
418
  return;
@@ -431,7 +495,27 @@ var buildWebSocket = (discovered, options = {}, middleware = []) => {
431
495
  const gateways = [...wrapped.values()];
432
496
  const onError = options.onError ?? (middleware.length === 0 ? defaultOnError : reportedByMiddleware);
433
497
  const reports = options.onError !== undefined || middleware.some((entry) => entry.reportsErrors === true);
434
- const { onError: _onError, ...socketOptions } = options;
498
+ const {
499
+ onError: _onError,
500
+ binaryType,
501
+ backpressureLimit,
502
+ closeOnBackpressureLimit,
503
+ idleTimeout,
504
+ maxPayloadLength,
505
+ perMessageDeflate,
506
+ publishToSelf,
507
+ sendPings,
508
+ ...rest
509
+ } = options;
510
+ const handlerOptions = {
511
+ ...backpressureLimit !== undefined && { backpressureLimit },
512
+ ...closeOnBackpressureLimit !== undefined && { closeOnBackpressureLimit },
513
+ ...idleTimeout !== undefined && { idleTimeout },
514
+ ...maxPayloadLength !== undefined && { maxPayloadLength },
515
+ ...perMessageDeflate !== undefined && { perMessageDeflate },
516
+ ...publishToSelf !== undefined && { publishToSelf },
517
+ ...sendPings !== undefined && { sendPings }
518
+ };
435
519
  const run = (invoke, args, ws, then) => {
436
520
  try {
437
521
  settle(invoke(...args), ws, onError, then);
@@ -440,7 +524,7 @@ var buildWebSocket = (discovered, options = {}, middleware = []) => {
440
524
  }
441
525
  };
442
526
  const websocket = {
443
- ...socketOptions,
527
+ ...handlerOptions,
444
528
  message(ws, message) {
445
529
  const gateway = runtimeOf(ws);
446
530
  let event;
@@ -460,17 +544,19 @@ var buildWebSocket = (discovered, options = {}, middleware = []) => {
460
544
  run(gateway.raw, [message, ws], ws, (value) => replyRaw(ws, value));
461
545
  return;
462
546
  }
463
- const unclaimed2 = ws.data[UNCLAIMED];
464
- if (!unclaimed2)
547
+ const unclaimed = ws.data[UNCLAIMED];
548
+ if (!unclaimed)
465
549
  return;
466
550
  try {
467
- settle(unclaimed2({ socket: ws, data: message }, event), ws, onError, undefined);
551
+ settle(unclaimed({ socket: ws, data: message }, event), ws, onError, undefined);
468
552
  } catch (error) {
469
553
  onError(error, ws);
470
554
  }
471
555
  },
472
- ...someHandler(gateways, (g) => g.open) && {
556
+ ...(someHandler(gateways, (g) => g.open) || binaryType !== undefined) && {
473
557
  open(ws) {
558
+ if (binaryType !== undefined)
559
+ ws.binaryType = binaryType;
474
560
  const { open } = runtimeOf(ws);
475
561
  if (open)
476
562
  run(open, [ws], ws, undefined);
@@ -633,6 +719,8 @@ class SocketLoggingMiddleware {
633
719
  if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
634
720
  return `[${data.byteLength} bytes]`;
635
721
  }
722
+ if (data instanceof Blob)
723
+ return `[${data.size} bytes]`;
636
724
  const text = JSON.stringify(data) ?? "";
637
725
  return text.length > this.#limit ? `[${text.length} chars]` : data;
638
726
  }
@@ -928,7 +1016,7 @@ class RequestLoggingMiddleware {
928
1016
  context: `${ctx.controller}.${ctx.handler}`
929
1017
  };
930
1018
  if (this.#trace) {
931
- const trace = TraceContext.adopt(req, this.#traceResponse);
1019
+ const trace = TraceContext2.adopt(req, this.#traceResponse);
932
1020
  scope.traceId = trace.traceId;
933
1021
  scope.spanId = trace.spanId;
934
1022
  scope.traceFlags = trace.flags;
@@ -972,7 +1060,7 @@ class RequestLoggingMiddleware {
972
1060
  #ignoredWithMetrics(req, ctx, path, next) {
973
1061
  const started = Bun.nanoseconds();
974
1062
  const failed = (error) => {
975
- this.#observe(req, ctx, error instanceof HttpError ? error.status : HttpStatusCode.INTERNAL_SERVER_ERROR, started);
1063
+ this.#observe(req, ctx, error instanceof HttpError ? error.status : HttpStatusCode2.INTERNAL_SERVER_ERROR, started);
976
1064
  throw error;
977
1065
  };
978
1066
  let settled;
@@ -987,8 +1075,8 @@ class RequestLoggingMiddleware {
987
1075
  }, failed);
988
1076
  }
989
1077
  #correlated(req, ctx, path, next) {
990
- const trace = this.#trace ? TraceContext.adopt(req, this.#traceResponse) : undefined;
991
- const stamp = (response) => trace === undefined ? response : TraceContext.stamp(response, req);
1078
+ const trace = this.#trace ? TraceContext2.adopt(req, this.#traceResponse) : undefined;
1079
+ const stamp = (response) => trace === undefined ? response : TraceContext2.stamp(response, req);
992
1080
  if (!this.#correlate)
993
1081
  return next().then(stamp);
994
1082
  return this.context.runWithContext({
@@ -1020,7 +1108,7 @@ class RequestLoggingMiddleware {
1020
1108
  }
1021
1109
  #failed(req, ctx, path, started, request, error, scope) {
1022
1110
  this.#shared(req, request);
1023
- const status = error instanceof HttpError ? error.status : HttpStatusCode.INTERNAL_SERVER_ERROR;
1111
+ const status = error instanceof HttpError ? error.status : HttpStatusCode2.INTERNAL_SERVER_ERROR;
1024
1112
  const entry = {
1025
1113
  ...scope,
1026
1114
  request,
@@ -1030,7 +1118,7 @@ class RequestLoggingMiddleware {
1030
1118
  };
1031
1119
  this.#observe(req, ctx, status, started);
1032
1120
  const line = `${req.method} ${path} ${status}`;
1033
- if (status < HttpStatusCode.INTERNAL_SERVER_ERROR) {
1121
+ if (status < HttpStatusCode2.INTERNAL_SERVER_ERROR) {
1034
1122
  this.logger.warn(line, entry);
1035
1123
  } else {
1036
1124
  this.logger.error(line, entry);
@@ -1047,7 +1135,7 @@ class RequestLoggingMiddleware {
1047
1135
  statusCode: response.status,
1048
1136
  elapsedMs: elapsedMs2(started)
1049
1137
  });
1050
- return TraceContext.stamp(response, req);
1138
+ return TraceContext2.stamp(response, req);
1051
1139
  }
1052
1140
  return body.then((value) => {
1053
1141
  this.logger.info(`${req.method} ${path} ${response.status}`, {
@@ -1057,13 +1145,13 @@ class RequestLoggingMiddleware {
1057
1145
  ...value === undefined ? {} : { responseBody: value },
1058
1146
  elapsedMs: elapsedMs2(started)
1059
1147
  });
1060
- return TraceContext.stamp(response, req);
1148
+ return TraceContext2.stamp(response, req);
1061
1149
  });
1062
1150
  }
1063
1151
  #observe(req, ctx, status, started) {
1064
1152
  if (this.#metrics === undefined)
1065
1153
  return;
1066
- this.#metrics.observe(ctx, status, Bun.nanoseconds() - started, TraceContext.of(req)?.traceId);
1154
+ this.#metrics.observe(ctx, status, Bun.nanoseconds() - started, TraceContext2.of(req)?.traceId);
1067
1155
  }
1068
1156
  #body(req, ctx) {
1069
1157
  if (!this.#requestBody)
@@ -1130,7 +1218,7 @@ var withCors = (options, handler) => {
1130
1218
  var preflight = (options, methods) => {
1131
1219
  const allowMethods = (options.methods ?? methods).join(", ");
1132
1220
  return async (req) => {
1133
- const response = applyCors(options, req, new Response(null, { status: HttpStatusCode.NO_CONTENT }));
1221
+ const response = applyCors(options, req, new Response(null, { status: HttpStatusCode2.NO_CONTENT }));
1134
1222
  if (!response.headers.has(ORIGIN))
1135
1223
  return response;
1136
1224
  response.headers.set("access-control-allow-methods", allowMethods);
@@ -1206,16 +1294,16 @@ var fillWith = (draft, source, schema, value) => {
1206
1294
  };
1207
1295
  var bodyFill = (schema) => (draft) => {
1208
1296
  const media = mediaTypeOf(draft.req);
1209
- const parse2 = parserFor(media);
1210
- if (parse2 === undefined) {
1211
- throw new HttpError(HttpStatusCode.UNSUPPORTED_MEDIA_TYPE, `Unsupported content type "${media}". Declared bodies accept ` + "application/json, application/x-www-form-urlencoded, multipart/form-data or text/*.");
1297
+ const parse = parserFor(media);
1298
+ if (parse === undefined) {
1299
+ throw new HttpError(HttpStatusCode2.UNSUPPORTED_MEDIA_TYPE, `Unsupported content type "${media}". Declared bodies accept ` + "application/json, application/x-www-form-urlencoded, multipart/form-data or text/*.");
1212
1300
  }
1213
- const read = parse2 === asJson && RawBody.wanted(draft.req) ? draft.req.text().then((text) => {
1301
+ const read = parse === asJson && RawBody.wanted(draft.req) ? draft.req.text().then((text) => {
1214
1302
  RawBody.record(draft.req, text);
1215
1303
  return JSON.parse(text);
1216
- }) : parse2(draft.req);
1304
+ }) : parse(draft.req);
1217
1305
  return read.then((value) => fillWith(draft, "body", schema, value), (error) => {
1218
- throw new HttpError(HttpStatusCode.BAD_REQUEST, `Malformed ${media} body`, { cause: error });
1306
+ throw new HttpError(HttpStatusCode2.BAD_REQUEST, `Malformed ${media} body`, { cause: error });
1219
1307
  });
1220
1308
  };
1221
1309
  var searchOf = (url) => {
@@ -1257,11 +1345,11 @@ var toResponse = (value, status) => {
1257
1345
  if (value instanceof Response)
1258
1346
  return value;
1259
1347
  if (value === undefined || value === null) {
1260
- return new Response(null, { status: HttpStatusCode.NO_CONTENT });
1348
+ return new Response(null, { status: HttpStatusCode2.NO_CONTENT });
1261
1349
  }
1262
1350
  return Response.json(value, { status });
1263
1351
  };
1264
- var statusFor = (route) => route.options?.status ?? defaultStatusFor(route.method);
1352
+ var statusFor = (route) => route.options?.status ?? defaultStatusFor2(route.method);
1265
1353
  var assertNoCollisions = (discovered) => {
1266
1354
  const owners = new Map;
1267
1355
  for (const route of discovered) {
@@ -1295,22 +1383,22 @@ var unmatchedContext = (req, isPublic) => Object.freeze({
1295
1383
  path: new URL(req.url).pathname,
1296
1384
  parsesBody: false,
1297
1385
  get: (key) => {
1298
- if (key.id === UNMATCHED.id)
1386
+ if (key.id === UNMATCHED2.id)
1299
1387
  return true;
1300
- if (key.id === PUBLIC.id && isPublic)
1388
+ if (key.id === PUBLIC2.id && isPublic)
1301
1389
  return true;
1302
1390
  return;
1303
1391
  }
1304
1392
  });
1305
1393
  var buildFallback = (middleware = [], onError = defaultErrorMapper, cors, notFound = "guarded") => {
1306
1394
  const miss = () => {
1307
- throw new HttpError(HttpStatusCode.NOT_FOUND, "NOT_FOUND");
1395
+ throw new HttpError(HttpStatusCode2.NOT_FOUND, "NOT_FOUND");
1308
1396
  };
1309
1397
  const run = async (req) => {
1310
1398
  try {
1311
1399
  return await compose(middleware, unmatchedContext(req, notFound === "public"), miss)(req);
1312
1400
  } catch (error) {
1313
- return TraceContext.stamp(onError(error, req), req);
1401
+ return TraceContext2.stamp(onError(error, req), req);
1314
1402
  }
1315
1403
  };
1316
1404
  return cors ? withCors(cors, run) : run;
@@ -1318,7 +1406,7 @@ var buildFallback = (middleware = [], onError = defaultErrorMapper, cors, notFou
1318
1406
  var directOr = (guarded, route, read, status, onError, noMiddleware) => {
1319
1407
  if (!noMiddleware)
1320
1408
  return guarded;
1321
- const settle2 = (value, req) => {
1409
+ const settle = (value, req) => {
1322
1410
  try {
1323
1411
  return toResponse(value, status);
1324
1412
  } catch (error) {
@@ -1328,7 +1416,7 @@ var directOr = (guarded, route, read, status, onError, noMiddleware) => {
1328
1416
  const invoke = (input, req) => {
1329
1417
  try {
1330
1418
  const value = route.handler(input);
1331
- return value instanceof Promise ? value.then((resolved) => settle2(resolved, req), (error) => onError(error, req)) : settle2(value, req);
1419
+ return value instanceof Promise ? value.then((resolved) => settle(resolved, req), (error) => onError(error, req)) : settle(value, req);
1332
1420
  } catch (error) {
1333
1421
  return onError(error, req);
1334
1422
  }
@@ -1362,12 +1450,12 @@ var buildRoutes = (discovered, middleware = [], onError = defaultErrorMapper, co
1362
1450
  ...(route.moduleMiddleware ?? []).map((entry) => guardOf(entry, route.module)),
1363
1451
  ...(route.guards ?? []).map((guard) => guardOf(guard, route.module))
1364
1452
  ];
1365
- const chained = compose(chain, buildContext(route), async (req) => toResponse(await route.handler(await read(req)), status));
1453
+ const chained = compose(chain, buildContext2(route), async (req) => toResponse(await route.handler(await read(req)), status));
1366
1454
  const guarded = async (req) => {
1367
1455
  try {
1368
1456
  return await chained(req);
1369
1457
  } catch (error) {
1370
- return TraceContext.stamp(onError(error, req), req);
1458
+ return TraceContext2.stamp(onError(error, req), req);
1371
1459
  }
1372
1460
  };
1373
1461
  const byMethod = routes[route.path] ??= {};
@@ -1381,6 +1469,74 @@ var buildRoutes = (discovered, middleware = [], onError = defaultErrorMapper, co
1381
1469
  return routes;
1382
1470
  };
1383
1471
 
1472
+ // src/server/binding.ts
1473
+ class ServerBinding {
1474
+ #protocols;
1475
+ #main;
1476
+ #gateways;
1477
+ constructor(protocols) {
1478
+ this.#protocols = protocols;
1479
+ }
1480
+ bind(plan) {
1481
+ const { websocket: ws } = plan;
1482
+ const { http2, http1, gatewayPort } = this.#protocols;
1483
+ const split = ws !== undefined && gatewayPort !== undefined;
1484
+ const table = ws && !split ? {
1485
+ routes: withUpgradeRoutes(plan.routes, ws.routes),
1486
+ websocket: ws.websocket
1487
+ } : { routes: plan.routes };
1488
+ this.#main = Bun.serve({
1489
+ port: plan.port,
1490
+ fetch: plan.fetch,
1491
+ ...http2 !== undefined && { http2 },
1492
+ ...http1 !== undefined && { http1 },
1493
+ ...table
1494
+ });
1495
+ if (split) {
1496
+ try {
1497
+ this.#gateways = Bun.serve({
1498
+ port: gatewayPort,
1499
+ fetch: plan.fetch,
1500
+ routes: withUpgradeRoutes({}, ws.routes),
1501
+ websocket: ws.websocket
1502
+ });
1503
+ } catch (error) {
1504
+ this.#main.stop(true);
1505
+ this.#main = undefined;
1506
+ throw error;
1507
+ }
1508
+ }
1509
+ const main = this.#main;
1510
+ const gateways = this.#gateways;
1511
+ return {
1512
+ main,
1513
+ sockets: gateways ?? main,
1514
+ gauges: {
1515
+ get pendingRequests() {
1516
+ return main.pendingRequests + (gateways?.pendingRequests ?? 0);
1517
+ },
1518
+ get pendingWebSockets() {
1519
+ return main.pendingWebSockets + (gateways?.pendingWebSockets ?? 0);
1520
+ }
1521
+ }
1522
+ };
1523
+ }
1524
+ get gatewayUrl() {
1525
+ return this.#gateways?.url.href;
1526
+ }
1527
+ async stop(force) {
1528
+ const main = this.#main;
1529
+ const gateways = this.#gateways;
1530
+ this.#main = undefined;
1531
+ this.#gateways = undefined;
1532
+ await Promise.all([
1533
+ main?.stop(gateways === undefined && force),
1534
+ gateways?.stop(force)
1535
+ ]);
1536
+ }
1537
+ }
1538
+ Object.defineProperty(ServerBinding, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "protocols: BindingProtocols" }] });
1539
+
1384
1540
  // src/server/settings.ts
1385
1541
  var defaultSettings = () => ({ "trust proxy": false });
1386
1542
 
@@ -1402,10 +1558,11 @@ class HttpApplication extends ShutdownAware {
1402
1558
  #relayResubscribe;
1403
1559
  #notFound;
1404
1560
  #bootLogging;
1561
+ #binding;
1562
+ #split;
1405
1563
  #globalPrefix = "";
1406
1564
  #cors;
1407
1565
  #started = false;
1408
- #server;
1409
1566
  #resolveClosed;
1410
1567
  #shuttingDown;
1411
1568
  constructor(app, discovered, options, root, websocket) {
@@ -1427,6 +1584,12 @@ class HttpApplication extends ShutdownAware {
1427
1584
  this.#relayResubscribe = options.relayResubscribe;
1428
1585
  this.#notFound = options.notFound ?? "public";
1429
1586
  this.#bootLogging = options.bootLogging ?? true;
1587
+ this.#binding = new ServerBinding({
1588
+ http2: options.http2,
1589
+ http1: options.http1,
1590
+ gatewayPort: options.gatewayPort
1591
+ });
1592
+ this.#split = options.gatewayPort !== undefined && websocket !== undefined;
1430
1593
  this.gatewayPaths = websocket?.paths ?? [];
1431
1594
  this.closed = new Promise((resolve) => {
1432
1595
  this.#resolveClosed = resolve;
@@ -1485,23 +1648,17 @@ class HttpApplication extends ShutdownAware {
1485
1648
  const prefixed = this.#prefixed();
1486
1649
  const routes = buildRoutes(prefixed, middleware, this.#onError, this.#cors, (guard, from) => from === undefined ? this.#app.get(guard) : this.#app.get(guard, from));
1487
1650
  const ws = this.#websocket;
1488
- if (ws)
1651
+ if (ws && !this.#split)
1489
1652
  assertNoGatewayCollisions(prefixed, ws.paths);
1490
1653
  const fetch = buildFallback(middleware, this.#onError, this.#cors, this.#notFound);
1491
- const options = ws ? {
1492
- port,
1493
- fetch,
1494
- routes: withUpgradeRoutes(routes, ws.routes),
1495
- websocket: ws.websocket
1496
- } : { port, fetch, routes };
1497
- this.#server = Bun.serve(options);
1654
+ const bound = this.#binding.bind({ port, routes, fetch, websocket: ws });
1498
1655
  attachAddressSource(this.#app.get(ClientAddress), {
1499
- server: this.#server,
1656
+ server: bound.main,
1500
1657
  trustProxy: this.#settings["trust proxy"]
1501
1658
  });
1502
- this.#app.get(RequestMetrics).attach(this.#server);
1659
+ this.#app.get(RequestMetrics).attach(bound.gauges);
1503
1660
  const pubsub = this.#app.get(PubSub);
1504
- pubsub.attach(this.#server);
1661
+ pubsub.attach(bound.sockets);
1505
1662
  if (this.#relay) {
1506
1663
  const logger = this.#app.get(Logger3);
1507
1664
  await pubsub.relayThrough(this.#relay, {
@@ -1517,7 +1674,10 @@ class HttpApplication extends ShutdownAware {
1517
1674
  });
1518
1675
  }
1519
1676
  this.#logServed(prefixed, ws);
1520
- return this.#server.url.href;
1677
+ return bound.main.url.href;
1678
+ }
1679
+ get gatewayUrl() {
1680
+ return this.#binding.gatewayUrl;
1521
1681
  }
1522
1682
  #logServed(routes, ws) {
1523
1683
  if (!this.#bootLogging)
@@ -1529,6 +1689,7 @@ class HttpApplication extends ShutdownAware {
1529
1689
  ].join(" and ");
1530
1690
  this.#app.get(Logger3).info(`Serving ${subject}`, {
1531
1691
  ...runtimeInfo(),
1692
+ ...this.#binding.gatewayUrl === undefined ? {} : { gatewayUrl: this.#binding.gatewayUrl },
1532
1693
  routes: routes.map((route) => `${route.method} ${route.path}`),
1533
1694
  ...gateways.length === 0 ? {} : {
1534
1695
  gateways: gateways.map((gateway) => ({
@@ -1553,8 +1714,7 @@ class HttpApplication extends ShutdownAware {
1553
1714
  }
1554
1715
  };
1555
1716
  await step(() => this.#app.drain());
1556
- await step(async () => this.#server?.stop(this.#websocket !== undefined));
1557
- this.#server = undefined;
1717
+ await step(() => this.#binding.stop(this.#websocket !== undefined));
1558
1718
  await step(() => this.#app.get(PubSub).close());
1559
1719
  try {
1560
1720
  await step(() => this.#app.shutdown());
@@ -1571,7 +1731,7 @@ class HttpApplication extends ShutdownAware {
1571
1731
  return this.#discovered;
1572
1732
  return this.#discovered.map((route) => ({
1573
1733
  ...route,
1574
- path: joinPath(this.#globalPrefix, route.path)
1734
+ path: joinPath2(this.#globalPrefix, route.path)
1575
1735
  }));
1576
1736
  }
1577
1737
  #assertNotStarted(hook) {
@@ -1580,7 +1740,7 @@ class HttpApplication extends ShutdownAware {
1580
1740
  throw new AppError7(`${hook} must be called before listen(). The route table and the middleware ` + "chain are folded into one closure per route when the server binds, so " + "this call could not take effect.");
1581
1741
  }
1582
1742
  }
1583
- Object.defineProperty(HttpApplication, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "app: App", typeOnly: "App" }, { unresolved: "discovered: readonly DiscoveredRoute[]" }, { unresolved: "options: HttpOptions" }, { unresolved: "root: ModuleRef", typeOnly: "ModuleRef" }, { unresolved: "websocket?: WebSocketRuntime", typeOnly: "WebSocketRuntime" }] });
1743
+ Object.defineProperty(HttpApplication, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "app: App", typeOnly: "App" }, { unresolved: "discovered: readonly DiscoveredRoute[]" }, { unresolved: "options: HttpOptions", typeOnly: "HttpOptions" }, { unresolved: "root: ModuleRef", typeOnly: "ModuleRef" }, { unresolved: "websocket?: WebSocketRuntime", typeOnly: "WebSocketRuntime" }] });
1584
1744
 
1585
1745
  // src/server/options-provider.ts
1586
1746
  class HttpOptionsProvider {
@@ -1621,6 +1781,15 @@ class HttpOptionsProvider {
1621
1781
  get relayResubscribe() {
1622
1782
  return;
1623
1783
  }
1784
+ get http2() {
1785
+ return;
1786
+ }
1787
+ get http1() {
1788
+ return;
1789
+ }
1790
+ get gatewayPort() {
1791
+ return;
1792
+ }
1624
1793
  }
1625
1794
 
1626
1795
  class DefaultHttpOptions extends HttpOptionsProvider {
@@ -1643,7 +1812,10 @@ function resolveHttpOptions(settings, given) {
1643
1812
  onError: settings.onError,
1644
1813
  websocket: settings.websocket,
1645
1814
  relay: settings.relay,
1646
- relayResubscribe: settings.relayResubscribe
1815
+ relayResubscribe: settings.relayResubscribe,
1816
+ http2: settings.http2,
1817
+ http1: settings.http1,
1818
+ gatewayPort: settings.gatewayPort
1647
1819
  };
1648
1820
  for (const key of Object.keys(given)) {
1649
1821
  merged[key] = given[key];
@@ -1697,7 +1869,7 @@ class HttpFactory {
1697
1869
  for (const module of modules) {
1698
1870
  const moduleMiddleware = module.options.middleware ?? [];
1699
1871
  for (const controller of readControllers(module)) {
1700
- const routes = discoverRoutes(app.get(controller, module.ref));
1872
+ const routes = discoverRoutes2(app.get(controller, module.ref));
1701
1873
  if (routes.length === 0) {
1702
1874
  throw new AppError8(`${controller.name} is registered as a controller but declares no routes. ` + "Add a @Get/@Post/... method, or move it to providers.");
1703
1875
  }
@@ -1716,6 +1888,15 @@ class HttpFactory {
1716
1888
  for (const warning of websocket?.warnings ?? []) {
1717
1889
  app.get(Logger4).warn(warning);
1718
1890
  }
1891
+ if (resolved.gatewayPort !== undefined && resolved.gatewayPort !== 0 && websocket === undefined) {
1892
+ app.get(Logger4).warn(`gatewayPort is set and no gateway is declared, so no second server ` + `binds and gatewayUrl stays undefined. Declare a @Gateway in a ` + `module's providers, or drop gatewayPort.`);
1893
+ }
1894
+ if (resolved.http1 === false && websocket !== undefined && resolved.gatewayPort === undefined) {
1895
+ await app.shutdown().catch(() => {
1896
+ return;
1897
+ });
1898
+ throw new AppError8(`http1: false refuses HTTP/1.x with a 505, and a websocket upgrade is an ` + `HTTP/1.1 request - so nothing could ever connect to ` + `${websocket.paths.join(", ")}. Set gatewayPort to serve the gateways ` + "from a second port that keeps HTTP/1.1, or drop http1: false.");
1899
+ }
1719
1900
  return new HttpApplication(app, discovered, resolved, root, websocket);
1720
1901
  }
1721
1902
  static #socketMiddleware(app, root, options) {
@@ -2108,10 +2289,10 @@ __runInitializers(_init, 1, CompressionModule);
2108
2289
  __decoratorMetadata(_init, CompressionModule);
2109
2290
  let _CompressionModule = CompressionModule;
2110
2291
  // src/throttle/decorators.ts
2111
- var THROTTLE = metaKey("throttle");
2112
- var SKIP_THROTTLE = metaKey("skip-throttle");
2113
- var Throttle = (limit) => meta(THROTTLE, limit);
2114
- var SkipThrottle = () => meta(SKIP_THROTTLE, true);
2292
+ var THROTTLE = metaKey2("throttle");
2293
+ var SKIP_THROTTLE = metaKey2("skip-throttle");
2294
+ var Throttle = (limit) => meta2(THROTTLE, limit);
2295
+ var SkipThrottle = () => meta2(SKIP_THROTTLE, true);
2115
2296
  // src/throttle/guard.ts
2116
2297
  import { Logger as Logger5 } from "@dunx/core";
2117
2298
 
@@ -2226,7 +2407,7 @@ class ThrottleGuard {
2226
2407
  this.logger = logger;
2227
2408
  }
2228
2409
  async handle(req, ctx, next) {
2229
- if (ctx.get(UNMATCHED) === true)
2410
+ if (ctx.get(UNMATCHED2) === true)
2230
2411
  return next();
2231
2412
  if (ctx.get(SKIP_THROTTLE) === true)
2232
2413
  return next();
@@ -2237,7 +2418,7 @@ class ThrottleGuard {
2237
2418
  return next();
2238
2419
  if (used > limit.limit) {
2239
2420
  const after = await this.#ttl(key) ?? limit.windowSeconds;
2240
- throw new HttpError(HttpStatusCode.TOO_MANY_REQUESTS, `Rate limit exceeded: ${limit.limit} requests per ` + `${limit.windowSeconds}s`, this.options.headers ? {
2421
+ throw new HttpError(HttpStatusCode2.TOO_MANY_REQUESTS, `Rate limit exceeded: ${limit.limit} requests per ` + `${limit.windowSeconds}s`, this.options.headers ? {
2241
2422
  headers: {
2242
2423
  "retry-after": String(after),
2243
2424
  "ratelimit-limit": String(limit.limit),
@@ -2670,8 +2851,8 @@ var HEALTH_REPORT_SCHEMA = Object.freeze({
2670
2851
  // src/health/registry.ts
2671
2852
  var bounded = async (indicator, timeoutMs) => {
2672
2853
  let timer;
2673
- const timeout = new Promise((resolve2) => {
2674
- timer = setTimeout(() => resolve2({ state: "unknown", detail: `no answer in ${timeoutMs} ms` }), timeoutMs);
2854
+ const timeout = new Promise((resolve) => {
2855
+ timer = setTimeout(() => resolve({ state: "unknown", detail: `no answer in ${timeoutMs} ms` }), timeoutMs);
2675
2856
  timer.unref?.();
2676
2857
  });
2677
2858
  try {
@@ -2775,11 +2956,11 @@ var _dec = [
2775
2956
  Controller("health")
2776
2957
  ];
2777
2958
  var _dec2 = [
2778
- Public(),
2959
+ Public2(),
2779
2960
  Get("/live", probeResponses)
2780
2961
  ];
2781
2962
  var _dec3 = [
2782
- Public(),
2963
+ Public2(),
2783
2964
  Get("/ready", probeResponses)
2784
2965
  ];
2785
2966
  var _health = new WeakMap;
@@ -2804,7 +2985,7 @@ __runInitializers(_init, 1, HealthController);
2804
2985
  __decoratorMetadata(_init, HealthController);
2805
2986
  let _HealthController = HealthController;
2806
2987
  var _dec = [
2807
- ApiHidden()
2988
+ ApiHidden2()
2808
2989
  ];
2809
2990
  var _base = HealthController;
2810
2991
  var _init = __decoratorStart(_base);
@@ -3001,7 +3182,7 @@ __runInitializers(_init, 1, HealthModule);
3001
3182
  __decoratorMetadata(_init, HealthModule);
3002
3183
  let _HealthModule = HealthModule;
3003
3184
  export {
3004
- ApiHidden,
3185
+ ApiHidden2 as ApiHidden,
3005
3186
  ClientAddress,
3006
3187
  Compression,
3007
3188
  CompressionEncoding,
@@ -3018,7 +3199,7 @@ export {
3018
3199
  Gateway,
3019
3200
  Get,
3020
3201
  HEALTH_REPORT_SCHEMA,
3021
- HIDDEN,
3202
+ HIDDEN2 as HIDDEN,
3022
3203
  HealthController,
3023
3204
  HealthIndicator,
3024
3205
  HealthModule,
@@ -3027,7 +3208,7 @@ export {
3027
3208
  HttpError,
3028
3209
  HttpFactory,
3029
3210
  HttpOptionsProvider,
3030
- HttpStatusCode,
3211
+ HttpStatusCode2 as HttpStatusCode,
3031
3212
  MemoryIndicator,
3032
3213
  MemoryOptions,
3033
3214
  MemoryThrottleStore,
@@ -3039,17 +3220,17 @@ export {
3039
3220
  OnPing,
3040
3221
  OnPong,
3041
3222
  OnUpgrade,
3042
- PUBLIC,
3223
+ PUBLIC2 as PUBLIC,
3043
3224
  Patch,
3044
3225
  PingProbe,
3045
3226
  Post,
3046
3227
  PostgresRelay,
3047
3228
  PostgresRelayConnectionOptions,
3048
3229
  PubSub,
3049
- Public,
3230
+ Public2 as Public,
3050
3231
  Put,
3051
3232
  QueryProbe,
3052
- ROLES,
3233
+ ROLES2 as ROLES,
3053
3234
  Readiness,
3054
3235
  ReadinessOptions,
3055
3236
  RedisIndicator,
@@ -3058,7 +3239,7 @@ export {
3058
3239
  RelayConnectionOptions,
3059
3240
  RequestLoggingMiddleware,
3060
3241
  RequestMetrics,
3061
- Roles,
3242
+ Roles2 as Roles,
3062
3243
  SKIP_THROTTLE,
3063
3244
  SkipThrottle,
3064
3245
  SocketLoggingMiddleware,
@@ -3066,25 +3247,25 @@ export {
3066
3247
  StaticModule,
3067
3248
  StaticOptions,
3068
3249
  THROTTLE,
3069
- TRACEPARENT_HEADER,
3070
- TRACERESPONSE_HEADER,
3071
- TRACESTATE_HEADER,
3250
+ TRACEPARENT_HEADER2 as TRACEPARENT_HEADER,
3251
+ TRACERESPONSE_HEADER2 as TRACERESPONSE_HEADER,
3252
+ TRACESTATE_HEADER2 as TRACESTATE_HEADER,
3072
3253
  Throttle,
3073
3254
  ThrottleGuard,
3074
3255
  ThrottleModule,
3075
3256
  ThrottleOptions,
3076
3257
  ThrottleStore,
3077
- TraceContext,
3078
- UNMATCHED,
3258
+ TraceContext2 as TraceContext,
3259
+ UNMATCHED2 as UNMATCHED,
3079
3260
  UNMATCHED_ROUTE,
3080
- UseGuards,
3261
+ UseGuards2 as UseGuards,
3081
3262
  ValidationError,
3082
3263
  WsRelay,
3083
3264
  WsRelayModule,
3084
3265
  defaultErrorMapper,
3085
3266
  errorMapper,
3086
- mergeMeta,
3087
- meta,
3088
- metaKey,
3089
- metaOf
3267
+ mergeMeta2 as mergeMeta,
3268
+ meta2 as meta,
3269
+ metaKey2 as metaKey,
3270
+ metaOf2 as metaOf
3090
3271
  };