@dunx/http 2.5.0 → 3.0.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,253 +1,92 @@
1
1
  // @bun
2
2
  import {
3
- HttpStatusCode,
4
3
  TRACEPARENT_HEADER,
5
4
  TRACESTATE_HEADER,
6
- TraceContext,
5
+ TraceContext
6
+ } from "./chunk-25g22350.js";
7
+ import {
8
+ ApiHidden,
9
+ CompressionEncoding,
10
+ CompressionOptions,
11
+ Controller,
12
+ DEFAULT_RELAY_CHANNEL,
13
+ Delete,
14
+ ErrorFilter,
15
+ Get,
16
+ HEALTH_REPORT_SCHEMA,
17
+ HIDDEN,
18
+ HandlerKind,
19
+ HealthController,
20
+ HealthOptions,
21
+ HealthRegistry,
22
+ HiddenHealthController,
23
+ HttpError,
24
+ HttpStatusCode,
25
+ PUBLIC,
26
+ Patch,
27
+ Post,
28
+ Public,
29
+ Put,
30
+ REQUEST_ID_HEADER,
31
+ ROLES,
32
+ RawBody,
33
+ RedisRelay,
34
+ RequestIds,
35
+ Roles,
36
+ StaticOptions,
37
+ UNMATCHED,
38
+ UseGuards,
39
+ ValidationError,
7
40
  __decorateElement,
8
41
  __decoratorMetadata,
9
42
  __decoratorStart,
10
- __privateAdd,
11
- __privateGet,
12
- __runInitializers
13
- } from "./chunk-jh7jk0bn.js";
14
-
15
- // src/route/marker.ts
16
- var ROUTE = Symbol.for("dunx.route");
17
- var CONTROLLER = Symbol.for("dunx.controller");
18
- var defaultStatusFor = (method) => method === "POST" ? HttpStatusCode.CREATED : HttpStatusCode.OK;
19
- var resolvePath = (path) => typeof path === "function" ? path() : path;
20
- var markRoute = (target, meta) => {
21
- Object.defineProperty(target, ROUTE, { value: meta, configurable: true });
22
- };
23
- var routeMetaOf = (value) => typeof value === "function" ? value[ROUTE] : undefined;
24
- var markController = (target, prefix) => {
25
- Object.defineProperty(target, CONTROLLER, {
26
- value: prefix,
27
- configurable: true
28
- });
29
- };
30
- var prefixOf = (target) => target[CONTROLLER] ?? "";
31
-
32
- // src/route/decorators.ts
33
- var Controller = (prefix = "") => (target) => {
34
- markController(target, prefix);
35
- return target;
36
- };
37
- var verb = (method) => (path = "/", options) => (value, _context) => {
38
- markRoute(value, { method, path, options });
39
- return value;
40
- };
41
- var Get = verb("GET");
42
- var Post = verb("POST");
43
- var Put = verb("PUT");
44
- var Patch = verb("PATCH");
45
- var Delete = verb("DELETE");
46
- // src/route/discover.ts
47
- import { markedMethods } from "@dunx/core";
48
-
49
- // src/route/metadata.ts
50
- var META = Symbol.for("dunx.meta");
51
- var GUARDS = Symbol.for("dunx.guards");
52
- var metaKey = (name) => ({
53
- name,
54
- id: Symbol(name)
55
- });
56
- var write = (target, key, value) => {
57
- const record = new Map(target[META]);
58
- record.set(key.id, value);
59
- Object.defineProperty(target, META, { value: record, configurable: true });
60
- };
61
- var meta = (key, value) => (target) => {
62
- write(target, key, value);
63
- return target;
64
- };
65
- var ROLES = metaKey("roles");
66
- var PUBLIC = metaKey("public");
67
- var HIDDEN = metaKey("hidden");
68
- var UNMATCHED = metaKey("unmatched");
69
- var Roles = (...roles) => meta(ROLES, roles);
70
- var Public = () => meta(PUBLIC, true);
71
- var ApiHidden = () => meta(HIDDEN, true);
72
- var UseGuards = (...guards) => (target) => {
73
- const existing = target[GUARDS] ?? [];
74
- const merged = Object.hasOwn(target, GUARDS) ? [...guards, ...existing] : [...existing, ...guards];
75
- Object.defineProperty(target, GUARDS, {
76
- value: merged,
77
- configurable: true
78
- });
79
- return target;
80
- };
81
- var guardsOf = (target) => target[GUARDS] ?? [];
82
- var metaOf = (target) => target[META];
83
- var mergeMeta = (...targets) => {
84
- const merged = new Map;
85
- for (const target of targets) {
86
- const record = target[META];
87
- if (record)
88
- for (const [id, value] of record)
89
- merged.set(id, value);
90
- }
91
- return merged;
92
- };
93
-
94
- // src/route/discover.ts
95
- var joinPath = (prefix, path) => {
96
- const joined = `/${prefix}/${path}`.replace(/\/{2,}/g, "/");
97
- return joined.length > 1 ? joined.replace(/\/$/, "") : "/";
98
- };
99
- var discoverRoutes = (instance) => {
100
- const klass = instance.constructor;
101
- const prefix = prefixOf(klass);
102
- const classGuards = guardsOf(klass);
103
- const members = instance;
104
- return markedMethods(Object.getPrototypeOf(instance), routeMetaOf).map(({ name, meta: meta2, value: marked }) => ({
105
- method: meta2.method,
106
- path: joinPath(prefix, resolvePath(meta2.path)),
107
- controller: klass.name,
108
- handlerName: name,
109
- handler: members[name].bind(instance),
110
- options: meta2.options,
111
- meta: mergeMeta(klass, marked),
112
- classMeta: metaOf(klass),
113
- guards: [...classGuards, ...guardsOf(marked)]
114
- }));
115
- };
116
- // src/inspect.ts
117
- import {
118
- collectModules,
119
- dependenciesOf,
120
- readControllers
121
- } from "@dunx/core";
122
-
123
- // src/ws/discover.ts
124
- import {
125
- AppError,
126
- classOf,
127
- markedMethods as markedMethods2
128
- } from "@dunx/core";
129
-
130
- // src/ws/marker.ts
131
- var HANDLER = Symbol.for("dunx.ws.handler");
132
- var GATEWAY = Symbol.for("dunx.ws.gateway");
133
- var HandlerKind = Object.freeze({
134
- UPGRADE: "upgrade",
135
- OPEN: "open",
136
- MESSAGE: "message",
137
- CLOSE: "close",
138
- DRAIN: "drain",
139
- PING: "ping",
140
- PONG: "pong"
141
- });
142
- var markHandler = (target, meta2) => {
143
- Object.defineProperty(target, HANDLER, { value: meta2, configurable: true });
144
- };
145
- var handlerMetaOf = (value) => typeof value === "function" ? value[HANDLER] : undefined;
146
- var markGateway = (target, path) => {
147
- Object.defineProperty(target, GATEWAY, { value: path, configurable: true });
148
- };
149
- var gatewayPathOf = (target) => target[GATEWAY] ?? "/";
150
- var isGateway = (target) => target[GATEWAY] !== undefined;
151
-
152
- // src/ws/discover.ts
153
- var normalizePath = (path) => {
154
- const joined = `/${path}`.replace(/\/{2,}/g, "/");
155
- return joined.length > 1 ? joined.replace(/\/$/, "") : "/";
156
- };
157
- var eachHandler = (start) => markedMethods2(start, handlerMetaOf);
158
- var discoverGateway = (instance) => {
159
- const klass = instance.constructor;
160
- const members = instance;
161
- return {
162
- name: klass.name,
163
- path: normalizePath(gatewayPathOf(klass)),
164
- handlers: eachHandler(Object.getPrototypeOf(instance)).map(({ name, meta: meta2 }) => ({
165
- kind: meta2.kind,
166
- event: meta2.event,
167
- method: name,
168
- invoke: members[name].bind(instance)
169
- }))
170
- };
171
- };
172
- var findHandlerMethod = (ctor) => eachHandler(ctor.prototype)[0]?.name;
173
- var discoverGateways = (modules, resolve) => {
174
- const discovered = [];
175
- for (const module of modules) {
176
- for (const entry of module.options.providers ?? []) {
177
- const candidate = classOf(entry);
178
- if (!candidate)
179
- continue;
180
- if (isGateway(candidate.ctor)) {
181
- discovered.push(discoverGateway(resolve(candidate.token)));
182
- continue;
183
- }
184
- const orphan = findHandlerMethod(candidate.ctor);
185
- if (orphan !== undefined) {
186
- throw new AppError(`${candidate.ctor.name}.${orphan}() is a websocket handler, but ` + `${candidate.ctor.name} is not a gateway. Decorate the class with ` + "@Gateway(path), or drop the handler decorator.");
187
- }
188
- }
189
- }
190
- return discovered;
191
- };
192
-
193
- // src/inspect.ts
194
- var vendorOf = (schema) => schema?.["~standard"]?.vendor;
195
- var validatesIn = (options) => {
196
- const body = vendorOf(options?.body);
197
- const query = vendorOf(options?.query);
198
- const params = vendorOf(options?.params);
199
- return {
200
- ...body === undefined ? {} : { body },
201
- ...query === undefined ? {} : { query },
202
- ...params === undefined ? {} : { params }
203
- };
204
- };
205
- var rolesIn = (route) => {
206
- const roles = route.meta?.get(ROLES.id);
207
- if (roles === undefined || roles === null)
208
- return null;
209
- return (Array.isArray(roles) ? roles : [roles]).map(String);
210
- };
211
- var nodeFor = (route, module) => ({
212
- method: route.method,
213
- path: route.path,
214
- controller: route.controller,
215
- handler: route.handlerName,
216
- module,
217
- public: route.meta?.get(PUBLIC.id) === true,
218
- roles: rolesIn(route),
219
- guards: (route.guards ?? []).map((guard) => guard.name),
220
- hidden: route.meta?.get(HIDDEN.id) === true,
221
- validates: validatesIn(route.options),
222
- status: route.options?.status ?? null,
223
- responses: Object.keys(route.options?.response ?? {}).map(Number)
224
- });
225
- var routesOf = (root) => collectModules(root).flatMap((module) => readControllers(module).flatMap((controller) => {
226
- const { prototype } = controller;
227
- return discoverRoutes(Object.create(prototype)).map((route) => nodeFor(route, module.name));
228
- }));
229
- var gatewayFor = (ctor, module) => {
230
- const { name, path, handlers } = discoverGateway(Object.create(ctor.prototype));
231
- return {
232
- name,
233
- path,
234
- module,
235
- dependencies: dependenciesOf(ctor),
236
- handlers: handlers.map((handler) => ({
237
- kind: handler.kind,
238
- event: handler.event ?? null,
239
- method: handler.method
240
- }))
241
- };
242
- };
243
- var classOf2 = (entry) => {
244
- if (typeof entry === "function")
245
- return entry;
246
- return entry.provider.kind === "class" ? entry.provider.ctor : undefined;
247
- };
248
- var gatewaysOf = (root) => collectModules(root).flatMap((module) => (module.options.providers ?? []).map(classOf2).filter((ctor) => ctor !== undefined).filter(isGateway).map((ctor) => gatewayFor(ctor, module.name)));
43
+ __runInitializers,
44
+ assertNoCollisions,
45
+ assertNoGatewayCollisions,
46
+ buildContext,
47
+ buildFallback,
48
+ buildGateways,
49
+ buildRoutes,
50
+ buildRuntime,
51
+ buildWebSocket,
52
+ compose,
53
+ composeSocket,
54
+ decode,
55
+ decodeRelay,
56
+ defaultErrorMapper,
57
+ defaultRelayError,
58
+ defaultRelayUrl,
59
+ defaultStatusFor,
60
+ discoverGateway,
61
+ discoverGateways,
62
+ discoverRoutes,
63
+ encode,
64
+ encodeRelay,
65
+ errorMapper,
66
+ gatewaysOf,
67
+ guardsOf,
68
+ isCompressibleType,
69
+ isErrorFilter,
70
+ isGateway,
71
+ joinPath,
72
+ markGateway,
73
+ markHandler,
74
+ mergeMeta,
75
+ meta,
76
+ metaKey,
77
+ metaOf,
78
+ negotiate,
79
+ normalizePath,
80
+ normalizePrefix,
81
+ observe,
82
+ preflight,
83
+ routesOf,
84
+ toErrorMapper,
85
+ withCors,
86
+ withUpgradeRoutes
87
+ } from "./chunk-ywdpxbkf.js";
249
88
  // src/server/client-address.ts
250
- import { AppError as AppError2 } from "@dunx/core";
89
+ import { AppError } from "@dunx/core";
251
90
  var trustedHops = (setting) => {
252
91
  if (setting === true)
253
92
  return 1;
@@ -261,7 +100,7 @@ class ClientAddress {
261
100
  of(req) {
262
101
  const source = sources.get(this);
263
102
  if (!source) {
264
- throw new AppError2("ClientAddress has no server yet. The address comes from the live Bun " + "server, so it is only available once listen() has run.");
103
+ throw new AppError("ClientAddress has no server yet. The address comes from the live Bun " + "server, so it is only available once listen() has run.");
265
104
  }
266
105
  const hops = trustedHops(source.trustProxy);
267
106
  if (hops > 0) {
@@ -276,432 +115,17 @@ class ClientAddress {
276
115
  var attachAddressSource = (target, source) => {
277
116
  sources.set(target, source);
278
117
  };
279
- // src/server/context.ts
280
- var EMPTY = new Map;
281
- var buildContext = (route) => {
282
- const record = route.meta ?? EMPTY;
283
- return Object.freeze({
284
- controller: route.controller,
285
- handler: route.handlerName,
286
- method: route.method,
287
- path: route.path,
288
- parsesBody: route.options?.body !== undefined,
289
- get: (key) => record.get(key.id)
290
- });
291
- };
292
- // src/server/cors.ts
293
- var ORIGIN = "access-control-allow-origin";
294
- var allowedOrigin = (options, requested) => {
295
- const origin = options.origin ?? "*";
296
- if (typeof origin === "string") {
297
- if (origin !== "*")
298
- return origin === requested ? origin : undefined;
299
- if (!options.credentials)
300
- return "*";
301
- return requested ?? undefined;
302
- }
303
- if (requested === null)
304
- return;
305
- const allowed = typeof origin === "function" ? origin(requested) : origin.includes(requested);
306
- return allowed ? requested : undefined;
307
- };
308
- var applyCors = (options, req, response) => {
309
- const origin = allowedOrigin(options, req.headers.get("origin"));
310
- if (origin === undefined)
311
- return response;
312
- response.headers.set(ORIGIN, origin);
313
- if (origin !== "*")
314
- response.headers.append("vary", "Origin");
315
- if (options.credentials) {
316
- response.headers.set("access-control-allow-credentials", "true");
317
- }
318
- if (options.exposedHeaders?.length) {
319
- response.headers.set("access-control-expose-headers", options.exposedHeaders.join(", "));
320
- }
321
- return response;
322
- };
323
- var withCors = (options, handler) => {
324
- return async (req) => applyCors(options, req, await handler(req));
325
- };
326
- var preflight = (options, methods) => {
327
- const allowMethods = (options.methods ?? methods).join(", ");
328
- return async (req) => {
329
- const response = applyCors(options, req, new Response(null, { status: HttpStatusCode.NO_CONTENT }));
330
- if (!response.headers.has(ORIGIN))
331
- return response;
332
- response.headers.set("access-control-allow-methods", allowMethods);
333
- const allowHeaders = options.allowedHeaders ?? (req.headers.get("access-control-request-headers") ?? "").split(",").map((header) => header.trim()).filter((header) => header.length > 0);
334
- if (allowHeaders.length > 0) {
335
- response.headers.set("access-control-allow-headers", allowHeaders.join(", "));
336
- }
337
- if (options.maxAge !== undefined) {
338
- response.headers.set("access-control-max-age", String(options.maxAge));
339
- }
340
- return response;
341
- };
342
- };
343
- // src/server/errors.ts
344
- import { AppError as AppError3, ConsoleLogger } from "@dunx/core";
345
- class HttpError extends AppError3 {
346
- status;
347
- name = "HttpError";
348
- headers;
349
- constructor(status, message, options) {
350
- super(message, options);
351
- this.status = status;
352
- this.headers = options?.headers;
353
- }
354
- }
355
- Object.defineProperty(HttpError, Symbol.for("dunx.deps"), {
356
- value: () => [{ unresolved: "readonly status: number" }, { unresolved: "message: string" }, { unresolved: "options?: HttpErrorOptions" }]
357
- });
358
-
359
- class ValidationError extends HttpError {
360
- source;
361
- issues;
362
- name = "ValidationError";
363
- constructor(source, issues) {
364
- super(HttpStatusCode.BAD_REQUEST, `Invalid ${source}`);
365
- this.source = source;
366
- this.issues = issues;
367
- }
368
- }
369
- Object.defineProperty(ValidationError, Symbol.for("dunx.deps"), {
370
- value: () => [{ unresolved: "readonly source: InputSource" }, { unresolved: "readonly issues: readonly ValidationIssue[]" }]
371
- });
372
-
373
- class ErrorFilter {
374
- }
375
- var isErrorFilter = (handler) => typeof handler === "function" && typeof handler.prototype?.catch === "function";
376
- var toErrorMapper = (handler, resolve) => isErrorFilter(handler) ? (error, req) => resolve(handler).catch(error, req) : handler;
377
- var errorMapper = (logger) => (error) => {
378
- if (error instanceof ValidationError) {
379
- return Response.json({ error: error.message, status: error.status, issues: error.issues }, {
380
- status: error.status,
381
- ...error.headers && { headers: error.headers }
382
- });
383
- }
384
- if (error instanceof HttpError) {
385
- return Response.json({ error: error.message, status: error.status }, {
386
- status: error.status,
387
- ...error.headers && { headers: error.headers }
388
- });
389
- }
390
- logger.error("Unhandled error", error);
391
- return Response.json({
392
- error: "Internal Server Error",
393
- status: HttpStatusCode.INTERNAL_SERVER_ERROR
394
- }, { status: HttpStatusCode.INTERNAL_SERVER_ERROR });
395
- };
396
- var defaultErrorMapper = errorMapper(new ConsoleLogger);
397
118
  // src/server/factory.ts
398
119
  import {
399
- collectModules as collectModules2,
400
- AppError as AppError8,
120
+ collectModules,
121
+ AppError as AppError4,
401
122
  AppFactory,
402
123
  Logger as Logger4,
403
124
  provide,
404
- readControllers as readControllers2,
125
+ readControllers,
405
126
  RequestContext as RequestContext3
406
127
  } from "@dunx/core";
407
128
 
408
- // src/ws/envelope.ts
409
- var encode = (event, data) => JSON.stringify({ event, data });
410
- var decode = (message) => {
411
- if (typeof message !== "string")
412
- return;
413
- let parsed;
414
- try {
415
- parsed = JSON.parse(message);
416
- } catch {
417
- return;
418
- }
419
- if (typeof parsed !== "object" || parsed === null)
420
- return;
421
- const { event, data } = parsed;
422
- return typeof event === "string" ? { event, data } : undefined;
423
- };
424
-
425
- // src/ws/middleware.ts
426
- var composeSocket = (middleware, ctx) => middleware.reduceRight((next, current) => (frame, run) => current.handle(frame, ctx, () => next(frame, run)), (_frame, run) => run());
427
- var observe = (next, done) => {
428
- let result;
429
- try {
430
- result = next();
431
- } catch (error) {
432
- done(error, undefined);
433
- throw error;
434
- }
435
- if (result instanceof Promise) {
436
- return result.then((value) => {
437
- done(undefined, value);
438
- return value;
439
- }, (error) => {
440
- done(error, undefined);
441
- throw error;
442
- });
443
- }
444
- done(undefined, result);
445
- return result;
446
- };
447
-
448
- // src/ws/runtime.ts
449
- import { AppError as AppError4 } from "@dunx/core";
450
- var slotOf = (handler) => handler.kind === HandlerKind.MESSAGE && handler.event !== undefined ? `message ${JSON.stringify(handler.event)}` : handler.kind;
451
- var buildRuntime = (gateway) => {
452
- if (gateway.handlers.length === 0) {
453
- throw new AppError4(`${gateway.name} is registered as a gateway but declares no handlers. ` + "Add an @OnMessage/@OnOpen/... method, or drop the @Gateway decorator.");
454
- }
455
- const owners = new Map;
456
- const events = new Map;
457
- for (const handler of gateway.handlers) {
458
- const slot = slotOf(handler);
459
- const existing = owners.get(slot);
460
- if (existing) {
461
- throw new AppError4(`Handler collision in ${gateway.name}: ${slot} is claimed by ` + `${existing.method}() and by ${handler.method}(). One handler per event.`);
462
- }
463
- owners.set(slot, handler);
464
- if (handler.kind === HandlerKind.MESSAGE && handler.event !== undefined) {
465
- events.set(handler.event, handler.invoke);
466
- }
467
- }
468
- const at = (slot) => owners.get(slot)?.invoke;
469
- return {
470
- name: gateway.name,
471
- path: gateway.path,
472
- upgrade: at(HandlerKind.UPGRADE),
473
- open: at(HandlerKind.OPEN),
474
- close: at(HandlerKind.CLOSE),
475
- drain: at(HandlerKind.DRAIN),
476
- ping: at(HandlerKind.PING),
477
- pong: at(HandlerKind.PONG),
478
- raw: at(HandlerKind.MESSAGE),
479
- events
480
- };
481
- };
482
- var buildGateways = (discovered) => {
483
- const byPath = new Map;
484
- for (const gateway of discovered) {
485
- const existing = byPath.get(gateway.path);
486
- if (existing) {
487
- throw new AppError4(`Gateway path collision: ${gateway.path} is served by ${existing.name} ` + `and by ${gateway.name}. One gateway per path.`);
488
- }
489
- byPath.set(gateway.path, buildRuntime(gateway));
490
- }
491
- return byPath;
492
- };
493
- var someHandler = (gateways, pick) => {
494
- for (const gateway of gateways)
495
- if (pick(gateway) !== undefined)
496
- return true;
497
- return false;
498
- };
499
-
500
- // src/ws/adapter.ts
501
- var RUNTIME = Symbol.for("dunx.ws.runtime");
502
- var UNCLAIMED = Symbol.for("dunx.ws.unclaimed");
503
- var defaultOnError = (error, socket) => {
504
- console.error(`[dunx/http] ${socket.data.path} handler failed:`, error);
505
- };
506
- var reportedByMiddleware = () => {
507
- return;
508
- };
509
- 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(", ")}.`;
510
- var runtimeOf = (socket) => socket.data[RUNTIME];
511
- var isBinary = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
512
- var replyRaw = (socket, value) => {
513
- if (value === undefined)
514
- return;
515
- socket.send(typeof value === "string" || isBinary(value) ? value : JSON.stringify(value));
516
- };
517
- var settle = (result, socket, onError, then) => {
518
- if (result instanceof Promise) {
519
- result.then((value) => {
520
- if (!then)
521
- return;
522
- try {
523
- then(value);
524
- } catch (error) {
525
- onError(error, socket);
526
- }
527
- }, (error) => onError(error, socket));
528
- return;
529
- }
530
- if (then)
531
- then(result);
532
- };
533
- var framing = (kind) => {
534
- if (kind === HandlerKind.CLOSE) {
535
- return (args) => ({
536
- socket: args[0],
537
- data: { code: args[1], reason: args[2] }
538
- });
539
- }
540
- if (kind === HandlerKind.OPEN || kind === HandlerKind.DRAIN) {
541
- return (args) => ({ socket: args[0], data: undefined });
542
- }
543
- return (args) => ({ socket: args[1], data: args[0] });
544
- };
545
- var NOTHING = () => {
546
- return;
547
- };
548
- var through = (gateway, middleware, kind, event, invoke) => {
549
- const ctx = {
550
- gateway: gateway.name,
551
- path: gateway.path,
552
- kind,
553
- event
554
- };
555
- const dispatch = composeSocket(middleware, ctx);
556
- const frameOf = framing(kind);
557
- const run = invoke ?? NOTHING;
558
- return (...args) => dispatch(frameOf(args), () => run(...args));
559
- };
560
- var withMiddleware = (gateway, middleware) => {
561
- const wrap = (kind, event, invoke) => through(gateway, middleware, kind, event, invoke);
562
- const optional = (kind, invoke) => invoke === undefined ? undefined : wrap(kind, undefined, invoke);
563
- return {
564
- ...gateway,
565
- open: wrap(HandlerKind.OPEN, undefined, gateway.open),
566
- close: wrap(HandlerKind.CLOSE, undefined, gateway.close),
567
- drain: optional(HandlerKind.DRAIN, gateway.drain),
568
- ping: optional(HandlerKind.PING, gateway.ping),
569
- pong: optional(HandlerKind.PONG, gateway.pong),
570
- raw: optional(HandlerKind.MESSAGE, gateway.raw),
571
- events: new Map([...gateway.events].map(([event, invoke]) => [
572
- event,
573
- wrap(HandlerKind.MESSAGE, event, invoke)
574
- ]))
575
- };
576
- };
577
- var unclaimedDispatch = (gateway, middleware) => (frame, event) => composeSocket(middleware, {
578
- gateway: gateway.name,
579
- path: gateway.path,
580
- kind: HandlerKind.MESSAGE,
581
- event
582
- })(frame, () => {
583
- return;
584
- });
585
- var buildWebSocket = (discovered, options = {}, middleware = []) => {
586
- const byPath = buildGateways(discovered);
587
- const wrapped = middleware.length === 0 ? byPath : new Map([...byPath].map(([path, gateway]) => [
588
- path,
589
- withMiddleware(gateway, middleware)
590
- ]));
591
- const gateways = [...wrapped.values()];
592
- const onError = options.onError ?? (middleware.length === 0 ? defaultOnError : reportedByMiddleware);
593
- const reports = options.onError !== undefined || middleware.some((entry) => entry.reportsErrors === true);
594
- const { onError: _onError, ...socketOptions } = options;
595
- const run = (invoke, args, ws, then) => {
596
- try {
597
- settle(invoke(...args), ws, onError, then);
598
- } catch (error) {
599
- onError(error, ws);
600
- }
601
- };
602
- const websocket = {
603
- ...socketOptions,
604
- message(ws, message) {
605
- const gateway = runtimeOf(ws);
606
- let event;
607
- if (gateway.events.size > 0) {
608
- const envelope = decode(message);
609
- const handler = envelope && gateway.events.get(envelope.event);
610
- if (envelope && handler) {
611
- run(handler, [envelope.data, ws], ws, (value) => {
612
- if (value !== undefined)
613
- ws.send(encode(envelope.event, value));
614
- });
615
- return;
616
- }
617
- event = envelope?.event;
618
- }
619
- if (gateway.raw) {
620
- run(gateway.raw, [message, ws], ws, (value) => replyRaw(ws, value));
621
- return;
622
- }
623
- const unclaimed2 = ws.data[UNCLAIMED];
624
- if (!unclaimed2)
625
- return;
626
- try {
627
- settle(unclaimed2({ socket: ws, data: message }, event), ws, onError, undefined);
628
- } catch (error) {
629
- onError(error, ws);
630
- }
631
- },
632
- ...someHandler(gateways, (g) => g.open) && {
633
- open(ws) {
634
- const { open } = runtimeOf(ws);
635
- if (open)
636
- run(open, [ws], ws, undefined);
637
- }
638
- },
639
- ...someHandler(gateways, (g) => g.close) && {
640
- close(ws, code, reason) {
641
- const { close } = runtimeOf(ws);
642
- if (close)
643
- run(close, [ws, code, reason], ws, undefined);
644
- }
645
- },
646
- ...someHandler(gateways, (g) => g.drain) && {
647
- drain(ws) {
648
- const { drain } = runtimeOf(ws);
649
- if (drain)
650
- run(drain, [ws], ws, undefined);
651
- }
652
- },
653
- ...someHandler(gateways, (g) => g.ping) && {
654
- ping(ws, data) {
655
- const { ping } = runtimeOf(ws);
656
- if (ping)
657
- run(ping, [data, ws], ws, undefined);
658
- }
659
- },
660
- ...someHandler(gateways, (g) => g.pong) && {
661
- pong(ws, data) {
662
- const { pong } = runtimeOf(ws);
663
- if (pong)
664
- run(pong, [data, ws], ws, undefined);
665
- }
666
- }
667
- };
668
- const unclaimed = new Map(middleware.length === 0 ? [] : gateways.map((gateway) => [
669
- gateway,
670
- unclaimedDispatch(gateway, middleware)
671
- ]));
672
- const accept = (req, server, gateway, context) => {
673
- const fallback = unclaimed.get(gateway);
674
- const data = {
675
- path: gateway.path,
676
- context,
677
- id: crypto.randomUUID(),
678
- [RUNTIME]: gateway,
679
- ...fallback === undefined ? {} : { [UNCLAIMED]: fallback }
680
- };
681
- return server.upgrade(req, { data }) ? undefined : new Response("Expected a WebSocket upgrade", { status: 426 });
682
- };
683
- const upgradeHandler = (gateway) => (req, server) => {
684
- if (!gateway.upgrade)
685
- return accept(req, server, gateway, undefined);
686
- const result = gateway.upgrade(req);
687
- if (result instanceof Promise) {
688
- return result.then((value) => value instanceof Response ? value : accept(req, server, gateway, value));
689
- }
690
- return result instanceof Response ? result : accept(req, server, gateway, result);
691
- };
692
- return {
693
- websocket,
694
- routes: new Map(gateways.map((gateway) => [gateway.path, upgradeHandler(gateway)])),
695
- paths: [...byPath.keys()],
696
- warnings: middleware.length > 0 && !reports ? [unreported(middleware)] : [],
697
- gateways: gateways.map((gateway) => ({
698
- name: gateway.name,
699
- path: gateway.path,
700
- events: [...gateway.events.keys()]
701
- }))
702
- };
703
- };
704
-
705
129
  // src/ws/logging.ts
706
130
  import { Logger, LogLevel, RequestContext } from "@dunx/core";
707
131
  var LIFECYCLE_LABEL = {
@@ -746,7 +170,7 @@ class SocketLoggingMiddleware {
746
170
  const label = ctx.event ?? LIFECYCLE_LABEL[ctx.kind] ?? ctx.kind;
747
171
  const connectionId = frame.socket.data.id;
748
172
  const started = Bun.nanoseconds();
749
- const write2 = (error, value) => {
173
+ const write = (error, value) => {
750
174
  const entry = {
751
175
  gateway: ctx.gateway,
752
176
  path: ctx.path,
@@ -760,8 +184,8 @@ class SocketLoggingMiddleware {
760
184
  this.#emit(error === undefined ? level : this.#errorLevel, line, entry);
761
185
  };
762
186
  if (!this.#correlate)
763
- return observe(next, write2);
764
- return this.context.runWithContext({ connectionId, event: label, flow: "ws", context: ctx.gateway }, () => observe(next, write2));
187
+ return observe(next, write);
188
+ return this.context.runWithContext({ connectionId, event: label, flow: "ws", context: ctx.gateway }, () => observe(next, write));
765
189
  }
766
190
  #emit(level, line, entry) {
767
191
  switch (level) {
@@ -797,42 +221,10 @@ class SocketLoggingMiddleware {
797
221
  return text.length > this.#limit ? `[${text.length} chars]` : data;
798
222
  }
799
223
  }
800
- Object.defineProperty(SocketLoggingMiddleware, Symbol.for("dunx.deps"), {
801
- value: () => [Logger, RequestContext, { unresolved: "options: SocketLoggingOptions = {}" }]
802
- });
803
-
804
- // src/ws/pubsub.ts
805
- import { AppError as AppError5 } from "@dunx/core";
806
-
807
- // src/ws/relay.ts
808
- var DEFAULT_RELAY_CHANNEL = "dunx:ws";
809
- var defaultRelayError = (error, phase) => {
810
- console.warn(`[dunx/http] the websocket relay could not ${phase}. Fan-out is local to ` + "this process until it recovers:", error);
811
- };
812
- var toBytes = (data) => ArrayBuffer.isView(data) ? new Uint8Array(data.buffer, data.byteOffset, data.byteLength) : new Uint8Array(data);
813
- var encodeRelay = (origin, topic, data) => typeof data === "string" ? JSON.stringify({ o: origin, t: topic, d: data }) : JSON.stringify({
814
- o: origin,
815
- t: topic,
816
- d: Buffer.from(toBytes(data)).toString("base64"),
817
- b: 1
818
- });
819
- var decodeRelay = (message) => {
820
- let parsed;
821
- try {
822
- parsed = JSON.parse(message);
823
- } catch {
824
- return;
825
- }
826
- if (typeof parsed !== "object" || parsed === null)
827
- return;
828
- const { o, t, d, b } = parsed;
829
- if (typeof o !== "string" || typeof t !== "string" || typeof d !== "string") {
830
- return;
831
- }
832
- return { origin: o, topic: t, data: b ? Buffer.from(d, "base64") : d };
833
- };
224
+ Object.defineProperty(SocketLoggingMiddleware, Symbol.for("dunx.deps"), { value: () => [Logger, RequestContext, { unresolved: "options: SocketLoggingOptions = {}", optional: true }] });
834
225
 
835
226
  // src/ws/pubsub.ts
227
+ import { AppError as AppError2 } from "@dunx/core";
836
228
  class PubSub {
837
229
  #origin = Bun.randomUUIDv7();
838
230
  #server;
@@ -857,7 +249,7 @@ class PubSub {
857
249
  }
858
250
  async relayThrough(relay, options = {}) {
859
251
  if (this.#relay) {
860
- throw new AppError5("PubSub already relays. Two subscriptions on one channel would deliver " + "every relayed message twice - pass HttpOptions.relay or call " + "relayThrough(), not both.");
252
+ throw new AppError2("PubSub already relays. Two subscriptions on one channel would deliver " + "every relayed message twice - pass HttpOptions.relay or call " + "relayThrough(), not both.");
861
253
  }
862
254
  this.#relay = relay;
863
255
  this.#channel = options.channel ?? DEFAULT_RELAY_CHANNEL;
@@ -953,7 +345,7 @@ class PubSub {
953
345
  }
954
346
  #live() {
955
347
  if (!this.#server) {
956
- throw new AppError5("PubSub has no server yet. Publish once the server is listening: " + "HttpApp.listen() is what attaches it.");
348
+ throw new AppError2("PubSub has no server yet. Publish once the server is listening: " + "HttpApp.listen() is what attaches it.");
957
349
  }
958
350
  return this.#server;
959
351
  }
@@ -961,7 +353,7 @@ class PubSub {
961
353
 
962
354
  // src/server/application.ts
963
355
  import {
964
- AppError as AppError7,
356
+ AppError as AppError3,
965
357
  Logger as Logger3,
966
358
  runtimeInfo,
967
359
  ShutdownHooks,
@@ -974,47 +366,6 @@ import {
974
366
  Logger as Logger2,
975
367
  RequestContext as RequestContext2
976
368
  } from "@dunx/core";
977
-
978
- // src/server/raw-body.ts
979
- var WANTED = Symbol.for("dunx.http.rawBody.wanted");
980
- var TEXT = Symbol.for("dunx.http.rawBody.text");
981
-
982
- class RawBody {
983
- static want(req) {
984
- req[WANTED] = true;
985
- }
986
- static wanted(req) {
987
- return req[WANTED] === true;
988
- }
989
- static record(req, text) {
990
- req[TEXT] = text;
991
- }
992
- static read(req) {
993
- return req[TEXT];
994
- }
995
- }
996
-
997
- // src/server/request-id.ts
998
- var REQUEST_ID_HEADER = "x-request-id";
999
- var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1000
- var traceId = (inbound) => inbound !== null && inbound.length === 36 && UUID.test(inbound) ? inbound : crypto.randomUUID();
1001
- var ID = Symbol.for("dunx.http.requestId");
1002
-
1003
- class RequestIds {
1004
- static assign(req) {
1005
- const id = traceId(req.headers.get(REQUEST_ID_HEADER));
1006
- req[ID] = id;
1007
- return id;
1008
- }
1009
- static stamp(response, req) {
1010
- const id = req[ID];
1011
- if (id !== undefined)
1012
- response.headers.set(REQUEST_ID_HEADER, id);
1013
- return response;
1014
- }
1015
- }
1016
-
1017
- // src/server/request-logging.ts
1018
369
  var parse = (text, limit) => {
1019
370
  if (limit === 0)
1020
371
  return;
@@ -1210,248 +561,7 @@ class RequestLoggingMiddleware {
1210
561
  return response.clone().text().then((text) => parse(text, this.#limit));
1211
562
  }
1212
563
  }
1213
- Object.defineProperty(RequestLoggingMiddleware, Symbol.for("dunx.deps"), {
1214
- value: () => [Logger2, RequestContext2, { unresolved: "options: RequestLoggingOptions = {}" }]
1215
- });
1216
-
1217
- // src/server/routes.ts
1218
- import { AppError as AppError6 } from "@dunx/core";
1219
-
1220
- // src/server/input.ts
1221
- var grouped = (entries) => {
1222
- const collected = {};
1223
- entries.forEach((value, key) => {
1224
- const existing = collected[key];
1225
- if (existing === undefined)
1226
- collected[key] = value;
1227
- else if (Array.isArray(existing))
1228
- existing.push(value);
1229
- else
1230
- collected[key] = [existing, value];
1231
- });
1232
- return collected;
1233
- };
1234
- var asJson = (req) => req.json();
1235
- var asUrlEncoded = async (req) => grouped(new URLSearchParams(await req.text()));
1236
- var asMultipart = async (req) => grouped(await req.formData());
1237
- var asText = (req) => req.text();
1238
- var parserFor = (media) => {
1239
- if (media === "application/json" || media.endsWith("+json"))
1240
- return asJson;
1241
- if (media === "application/x-www-form-urlencoded")
1242
- return asUrlEncoded;
1243
- if (media === "multipart/form-data")
1244
- return asMultipart;
1245
- if (media.startsWith("text/"))
1246
- return asText;
1247
- return;
1248
- };
1249
- var JSON_MEDIA = "application/json";
1250
- var mediaTypeOf = (req) => {
1251
- const header = req.headers.get("content-type");
1252
- if (header === JSON_MEDIA || header === null)
1253
- return JSON_MEDIA;
1254
- const end = header.indexOf(";");
1255
- const media = (end === -1 ? header : header.slice(0, end)).trim();
1256
- return media === "" ? JSON_MEDIA : media.toLowerCase();
1257
- };
1258
- var flatten = (issue) => {
1259
- const path = issue.path?.map((segment) => String(typeof segment === "object" ? segment.key : segment)).join(".");
1260
- return path === undefined || path === "" ? { message: issue.message } : { message: issue.message, path };
1261
- };
1262
- var accept = (source, result) => {
1263
- if (result.issues !== undefined) {
1264
- throw new ValidationError(source, result.issues.map(flatten));
1265
- }
1266
- return result.value;
1267
- };
1268
- var fillWith = (draft, source, schema, value) => {
1269
- const result = schema["~standard"].validate(value);
1270
- if (result instanceof Promise) {
1271
- return result.then((settled) => {
1272
- draft[source] = accept(source, settled);
1273
- return draft;
1274
- });
1275
- }
1276
- draft[source] = accept(source, result);
1277
- return draft;
1278
- };
1279
- var bodyFill = (schema) => (draft) => {
1280
- const media = mediaTypeOf(draft.req);
1281
- const parse2 = parserFor(media);
1282
- if (parse2 === undefined) {
1283
- 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/*.");
1284
- }
1285
- const read = parse2 === asJson && RawBody.wanted(draft.req) ? draft.req.text().then((text) => {
1286
- RawBody.record(draft.req, text);
1287
- return JSON.parse(text);
1288
- }) : parse2(draft.req);
1289
- return read.then((value) => fillWith(draft, "body", schema, value), (error) => {
1290
- throw new HttpError(HttpStatusCode.BAD_REQUEST, `Malformed ${media} body`, { cause: error });
1291
- });
1292
- };
1293
- var searchOf = (url) => {
1294
- const start = url.indexOf("?");
1295
- if (start === -1)
1296
- return "";
1297
- const end = url.indexOf("#", start + 1);
1298
- return end === -1 ? url.slice(start + 1) : url.slice(start + 1, end);
1299
- };
1300
- var queryFill = (schema) => (draft) => {
1301
- const params = new URLSearchParams(searchOf(draft.req.url));
1302
- return fillWith(draft, "query", schema, grouped(params));
1303
- };
1304
- var paramsFill = (schema) => (draft) => fillWith(draft, "params", schema, draft.req.params);
1305
- var then = (first, second) => (draft) => {
1306
- const started = first(draft);
1307
- return started instanceof Promise ? started.then(second) : second(started);
1308
- };
1309
- var buildInputReader = (options) => {
1310
- const fills = [];
1311
- if (options?.body !== undefined)
1312
- fills.push(bodyFill(options.body));
1313
- if (options?.query !== undefined)
1314
- fills.push(queryFill(options.query));
1315
- if (options?.params !== undefined)
1316
- fills.push(paramsFill(options.params));
1317
- if (fills.length === 0)
1318
- return (req) => ({ req });
1319
- const fill = fills.reduce(then);
1320
- return (req) => fill({ req });
1321
- };
1322
-
1323
- // src/server/middleware.ts
1324
- var compose = (middleware, ctx, handler) => middleware.reduceRight((next, current) => (req) => current.handle(req, ctx, () => next(req)), handler);
1325
-
1326
- // src/server/routes.ts
1327
- var construct = (guard) => new guard;
1328
- var toResponse = (value, status) => {
1329
- if (value instanceof Response)
1330
- return value;
1331
- if (value === undefined || value === null) {
1332
- return new Response(null, { status: HttpStatusCode.NO_CONTENT });
1333
- }
1334
- return Response.json(value, { status });
1335
- };
1336
- var statusFor = (route) => route.options?.status ?? defaultStatusFor(route.method);
1337
- var assertNoCollisions = (discovered) => {
1338
- const owners = new Map;
1339
- for (const route of discovered) {
1340
- const key = `${route.method} ${route.path}`;
1341
- const owner = `${route.controller}.${route.handlerName}`;
1342
- const existing = owners.get(key);
1343
- if (existing !== undefined) {
1344
- throw new AppError6(`Route collision: ${key} is declared by ${existing} and by ${owner}. ` + "Bun would keep only one of them.");
1345
- }
1346
- owners.set(key, owner);
1347
- }
1348
- };
1349
- var assertNoGatewayCollisions = (discovered, gatewayPaths) => {
1350
- const gateways = new Set(gatewayPaths);
1351
- for (const route of discovered) {
1352
- if (gateways.has(route.path)) {
1353
- throw new AppError6(`Gateway path collision: ${route.path} is served by a gateway and by ` + `${route.controller}.${route.handlerName}(). The upgrade is a route too, ` + "so one of them would be dropped.");
1354
- }
1355
- }
1356
- };
1357
- var withUpgradeRoutes = (routes, gateways) => {
1358
- const merged = { ...routes };
1359
- for (const [path, upgrade] of gateways)
1360
- merged[path] = { GET: upgrade };
1361
- return merged;
1362
- };
1363
- var unmatchedContext = (req, isPublic) => Object.freeze({
1364
- controller: "(unmatched)",
1365
- handler: "(none)",
1366
- method: req.method,
1367
- path: new URL(req.url).pathname,
1368
- parsesBody: false,
1369
- get: (key) => {
1370
- if (key.id === UNMATCHED.id)
1371
- return true;
1372
- if (key.id === PUBLIC.id && isPublic)
1373
- return true;
1374
- return;
1375
- }
1376
- });
1377
- var buildFallback = (middleware = [], onError = defaultErrorMapper, cors, notFound = "guarded") => {
1378
- const miss = () => {
1379
- throw new HttpError(HttpStatusCode.NOT_FOUND, "NOT_FOUND");
1380
- };
1381
- const run = async (req) => {
1382
- try {
1383
- return await compose(middleware, unmatchedContext(req, notFound === "public"), miss)(req);
1384
- } catch (error) {
1385
- return RequestIds.stamp(onError(error, req), req);
1386
- }
1387
- };
1388
- return cors ? withCors(cors, run) : run;
1389
- };
1390
- var directOr = (guarded, route, read, status, onError, noMiddleware) => {
1391
- if (!noMiddleware)
1392
- return guarded;
1393
- const settle2 = (value, req) => {
1394
- try {
1395
- return toResponse(value, status);
1396
- } catch (error) {
1397
- return onError(error, req);
1398
- }
1399
- };
1400
- const invoke = (input, req) => {
1401
- try {
1402
- const value = route.handler(input);
1403
- return value instanceof Promise ? value.then((resolved) => settle2(resolved, req), (error) => onError(error, req)) : settle2(value, req);
1404
- } catch (error) {
1405
- return onError(error, req);
1406
- }
1407
- };
1408
- return (req) => {
1409
- try {
1410
- const input = read(req);
1411
- return input instanceof Promise ? input.then((resolved) => invoke(resolved, req), (error) => onError(error, req)) : invoke(input, req);
1412
- } catch (error) {
1413
- return onError(error, req);
1414
- }
1415
- };
1416
- };
1417
- var buildRoutes = (discovered, middleware = [], onError = defaultErrorMapper, cors, resolve = construct) => {
1418
- assertNoCollisions(discovered);
1419
- const routes = {};
1420
- const instances = new Map;
1421
- const guardOf = (guard, from) => {
1422
- const existing = instances.get(guard);
1423
- if (existing)
1424
- return existing;
1425
- const created = resolve(guard, from);
1426
- instances.set(guard, created);
1427
- return created;
1428
- };
1429
- for (const route of discovered) {
1430
- const read = buildInputReader(route.options);
1431
- const status = statusFor(route);
1432
- const chain = [
1433
- ...middleware,
1434
- ...(route.moduleMiddleware ?? []).map((entry) => guardOf(entry, route.module)),
1435
- ...(route.guards ?? []).map((guard) => guardOf(guard, route.module))
1436
- ];
1437
- const chained = compose(chain, buildContext(route), async (req) => toResponse(await route.handler(await read(req)), status));
1438
- const guarded = async (req) => {
1439
- try {
1440
- return await chained(req);
1441
- } catch (error) {
1442
- return RequestIds.stamp(onError(error, req), req);
1443
- }
1444
- };
1445
- const byMethod = routes[route.path] ??= {};
1446
- byMethod[route.method] = cors ? withCors(cors, guarded) : directOr(guarded, route, read, status, onError, chain.length === 0);
1447
- }
1448
- if (cors) {
1449
- for (const byMethod of Object.values(routes)) {
1450
- byMethod.OPTIONS = preflight(cors, Object.keys(byMethod));
1451
- }
1452
- }
1453
- return routes;
1454
- };
564
+ Object.defineProperty(RequestLoggingMiddleware, Symbol.for("dunx.deps"), { value: () => [Logger2, RequestContext2, { unresolved: "options: RequestLoggingOptions = {}", optional: true }] });
1455
565
 
1456
566
  // src/server/settings.ts
1457
567
  var defaultSettings = () => ({ "trust proxy": false });
@@ -1634,12 +744,10 @@ class HttpApplication {
1634
744
  #assertNotStarted(hook) {
1635
745
  if (!this.#started)
1636
746
  return;
1637
- 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.");
747
+ throw new AppError3(`${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.");
1638
748
  }
1639
749
  }
1640
- Object.defineProperty(HttpApplication, Symbol.for("dunx.deps"), {
1641
- value: () => [{ unresolved: "app: App", typeOnly: "App" }, { unresolved: "discovered: readonly DiscoveredRoute[]" }, { unresolved: "options: HttpOptions" }, { unresolved: "root: ModuleRef", typeOnly: "ModuleRef" }, { unresolved: "websocket?: WebSocketRuntime", typeOnly: "WebSocketRuntime" }]
1642
- });
750
+ 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" }] });
1643
751
 
1644
752
  // src/server/factory.ts
1645
753
  class HttpModule {
@@ -1669,14 +777,14 @@ class HttpFactory {
1669
777
  exports: providers.map((entry) => typeof entry === "function" ? entry : entry.token)
1670
778
  };
1671
779
  const app = await AppFactory.create(scope, options.overrides ? { overrides: options.overrides } : {});
1672
- const modules = collectModules2(scope);
780
+ const modules = collectModules(scope);
1673
781
  const discovered = [];
1674
782
  for (const module of modules) {
1675
783
  const moduleMiddleware = module.options.middleware ?? [];
1676
- for (const controller of readControllers2(module)) {
784
+ for (const controller of readControllers(module)) {
1677
785
  const routes = discoverRoutes(app.get(controller, module.ref));
1678
786
  if (routes.length === 0) {
1679
- throw new AppError8(`${controller.name} is registered as a controller but declares no routes. ` + "Add a @Get/@Post/... method, or move it to providers.");
787
+ throw new AppError4(`${controller.name} is registered as a controller but declares no routes. ` + "Add a @Get/@Post/... method, or move it to providers.");
1680
788
  }
1681
789
  discovered.push(...routes.map((route) => ({
1682
790
  ...route,
@@ -1703,29 +811,6 @@ class HttpFactory {
1703
811
  }
1704
812
  // src/static/files.ts
1705
813
  import { join, normalize, resolve } from "path";
1706
-
1707
- // src/static/options.ts
1708
- class StaticOptions {
1709
- root;
1710
- path;
1711
- maxAge;
1712
- immutable;
1713
- constructor(init) {
1714
- this.root = init.root;
1715
- this.path = normalizePrefix(init.path ?? "/");
1716
- this.maxAge = init.maxAge ?? 60;
1717
- this.immutable = init.immutable ?? (() => false);
1718
- }
1719
- }
1720
- Object.defineProperty(StaticOptions, Symbol.for("dunx.deps"), {
1721
- value: () => [{ unresolved: "init: StaticOptionsInit" }]
1722
- });
1723
- var normalizePrefix = (path) => {
1724
- const trimmed = path.split("/").filter(Boolean).join("/");
1725
- return trimmed === "" ? "/" : `/${trimmed}`;
1726
- };
1727
-
1728
- // src/static/files.ts
1729
814
  class StaticFiles {
1730
815
  #options;
1731
816
  #root;
@@ -1777,9 +862,7 @@ class StaticFiles {
1777
862
  });
1778
863
  }
1779
864
  }
1780
- Object.defineProperty(StaticFiles, Symbol.for("dunx.deps"), {
1781
- value: () => [StaticOptions]
1782
- });
865
+ Object.defineProperty(StaticFiles, Symbol.for("dunx.deps"), { value: () => [StaticOptions] });
1783
866
  // src/static/module.ts
1784
867
  import {
1785
868
  Module,
@@ -1824,101 +907,6 @@ StaticModule = __decorateElement(_init, 0, "StaticModule", _dec, StaticModule);
1824
907
  __runInitializers(_init, 1, StaticModule);
1825
908
  __decoratorMetadata(_init, StaticModule);
1826
909
  let _StaticModule = StaticModule;
1827
- // src/compression/negotiate.ts
1828
- var quality = (params) => {
1829
- for (const param of params) {
1830
- const [key, value] = param.split("=");
1831
- if (key?.trim().toLowerCase() !== "q")
1832
- continue;
1833
- const q = Number.parseFloat(value ?? "");
1834
- return Number.isFinite(q) && q >= 0 && q <= 1 ? q : 1;
1835
- }
1836
- return 1;
1837
- };
1838
- var negotiate = (header, offered) => {
1839
- if (header === null)
1840
- return;
1841
- const accepted = new Map;
1842
- for (const element of header.split(",")) {
1843
- const [name, ...params] = element.split(";");
1844
- const token = name?.trim().toLowerCase();
1845
- if (token === undefined || token === "")
1846
- continue;
1847
- accepted.set(token, quality(params));
1848
- }
1849
- const wildcard = accepted.get("*");
1850
- let best;
1851
- let bestQuality = 0;
1852
- for (const encoding of offered) {
1853
- const q = accepted.get(encoding) ?? wildcard ?? 0;
1854
- if (q > bestQuality) {
1855
- best = encoding;
1856
- bestQuality = q;
1857
- }
1858
- }
1859
- return best;
1860
- };
1861
-
1862
- // src/compression/options.ts
1863
- var CompressionEncoding = Object.freeze({
1864
- ZSTD: "zstd",
1865
- GZIP: "gzip"
1866
- });
1867
- var COMPRESSIBLE = new Set([
1868
- "application/graphql",
1869
- "application/graphql-response+json",
1870
- "application/javascript",
1871
- "application/json",
1872
- "application/manifest+json",
1873
- "application/wasm",
1874
- "application/x-javascript",
1875
- "application/x-ndjson",
1876
- "application/xml",
1877
- "image/svg+xml"
1878
- ]);
1879
- var isCompressibleType = (contentType) => {
1880
- if (contentType === null)
1881
- return false;
1882
- const type = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
1883
- if (type.startsWith("text/"))
1884
- return true;
1885
- if (type.endsWith("+json") || type.endsWith("+xml"))
1886
- return true;
1887
- return COMPRESSIBLE.has(type);
1888
- };
1889
- var encodable = (encoding) => {
1890
- const sync = encoding === CompressionEncoding.ZSTD ? Bun.zstdCompressSync : Bun.gzipSync;
1891
- if (typeof sync !== "function")
1892
- return false;
1893
- try {
1894
- new CompressionStream(encoding);
1895
- return true;
1896
- } catch {
1897
- return false;
1898
- }
1899
- };
1900
-
1901
- class CompressionOptions {
1902
- encodings;
1903
- threshold;
1904
- filter;
1905
- constructor(init = {}) {
1906
- this.encodings = init.encodings ?? [
1907
- CompressionEncoding.ZSTD,
1908
- CompressionEncoding.GZIP
1909
- ];
1910
- const missing = this.encodings.filter((encoding) => !encodable(encoding));
1911
- if (missing.length > 0) {
1912
- throw new Error(`Bun ${Bun.version} cannot encode ${missing.join(", ")}. ` + "Pass `encodings` without it, or upgrade Bun.");
1913
- }
1914
- this.threshold = init.threshold ?? 1024;
1915
- this.filter = init.filter ?? isCompressibleType;
1916
- }
1917
- }
1918
- Object.defineProperty(CompressionOptions, Symbol.for("dunx.deps"), {
1919
- value: () => [{ unresolved: "init: CompressionOptionsInit = {}" }]
1920
- });
1921
-
1922
910
  // src/compression/compression.ts
1923
911
  var BODYLESS = new Set([204, 205, 304]);
1924
912
  var BUFFER_LIMIT = 1024 * 1024;
@@ -2045,9 +1033,7 @@ class Compression {
2045
1033
  });
2046
1034
  }
2047
1035
  }
2048
- Object.defineProperty(Compression, Symbol.for("dunx.deps"), {
2049
- value: () => [CompressionOptions]
2050
- });
1036
+ Object.defineProperty(Compression, Symbol.for("dunx.deps"), { value: () => [CompressionOptions] });
2051
1037
  // src/compression/module.ts
2052
1038
  import {
2053
1039
  Module as Module2,
@@ -2101,7 +1087,7 @@ var SkipThrottle = () => meta(SKIP_THROTTLE, true);
2101
1087
  import { Logger as Logger5 } from "@dunx/core";
2102
1088
 
2103
1089
  // src/throttle/options.ts
2104
- import { AppError as AppError9 } from "@dunx/core";
1090
+ import { AppError as AppError5 } from "@dunx/core";
2105
1091
 
2106
1092
  class ThrottleOptions {
2107
1093
  limit;
@@ -2112,13 +1098,13 @@ class ThrottleOptions {
2112
1098
  store;
2113
1099
  constructor(init) {
2114
1100
  if (init.prefix.trim() === "") {
2115
- throw new AppError9("ThrottleModule needs a prefix naming this application, and it has no " + "default: two apps sharing one Redis with one throttle namespace each " + "spend the other's budget. Pass something like { prefix: 'orders-api' }.");
1101
+ throw new AppError5("ThrottleModule needs a prefix naming this application, and it has no " + "default: two apps sharing one Redis with one throttle namespace each " + "spend the other's budget. Pass something like { prefix: 'orders-api' }.");
2116
1102
  }
2117
1103
  if (!Number.isInteger(init.limit) || init.limit < 1) {
2118
- throw new AppError9(`ThrottleModule needs a limit of at least 1; got ${init.limit}.`);
1104
+ throw new AppError5(`ThrottleModule needs a limit of at least 1; got ${init.limit}.`);
2119
1105
  }
2120
1106
  if (!Number.isInteger(init.windowSeconds) || init.windowSeconds < 1) {
2121
- throw new AppError9("ThrottleModule needs a windowSeconds of at least 1; got " + `${init.windowSeconds}.`);
1107
+ throw new AppError5("ThrottleModule needs a windowSeconds of at least 1; got " + `${init.windowSeconds}.`);
2122
1108
  }
2123
1109
  this.limit = init.limit;
2124
1110
  this.windowSeconds = init.windowSeconds;
@@ -2128,17 +1114,15 @@ class ThrottleOptions {
2128
1114
  this.store = init.store;
2129
1115
  }
2130
1116
  }
2131
- Object.defineProperty(ThrottleOptions, Symbol.for("dunx.deps"), {
2132
- value: () => [{ unresolved: "init: ThrottleOptionsInit" }]
2133
- });
1117
+ Object.defineProperty(ThrottleOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: ThrottleOptionsInit" }] });
2134
1118
 
2135
1119
  // src/throttle/store.ts
2136
- import { AppError as AppError10 } from "@dunx/core";
1120
+ import { AppError as AppError6 } from "@dunx/core";
2137
1121
 
2138
1122
  class ThrottleStore {
2139
1123
  constructor() {
2140
1124
  if (new.target === ThrottleStore) {
2141
- throw new AppError10("ThrottleStore is a contract, not an implementation. Bind one with " + "ThrottleModule.forRoot({ store: new RedisThrottleStore(redis) }), or " + "leave it out for the in-process MemoryThrottleStore.");
1125
+ throw new AppError6("ThrottleStore is a contract, not an implementation. Bind one with " + "ThrottleModule.forRoot({ store: new RedisThrottleStore(redis) }), or " + "leave it out for the in-process MemoryThrottleStore.");
2142
1126
  }
2143
1127
  }
2144
1128
  }
@@ -2160,9 +1144,7 @@ class RedisThrottleStore extends ThrottleStore {
2160
1144
  return left > 0 ? left : undefined;
2161
1145
  }
2162
1146
  }
2163
- Object.defineProperty(RedisThrottleStore, Symbol.for("dunx.deps"), {
2164
- value: () => [{ unresolved: "private readonly redis: ThrottleRedis" }]
2165
- });
1147
+ Object.defineProperty(RedisThrottleStore, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "private readonly redis: ThrottleRedis" }] });
2166
1148
 
2167
1149
  class MemoryThrottleStore extends ThrottleStore {
2168
1150
  #windows = new Map;
@@ -2199,9 +1181,7 @@ class MemoryThrottleStore extends ThrottleStore {
2199
1181
  this.#windows.clear();
2200
1182
  }
2201
1183
  }
2202
- Object.defineProperty(MemoryThrottleStore, Symbol.for("dunx.deps"), {
2203
- value: () => [{ unresolved: "maxKeys = 10_000" }]
2204
- });
1184
+ Object.defineProperty(MemoryThrottleStore, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "maxKeys = 10_000", optional: true }] });
2205
1185
 
2206
1186
  // src/throttle/guard.ts
2207
1187
  class ThrottleGuard {
@@ -2271,9 +1251,7 @@ class ThrottleGuard {
2271
1251
  this.logger.warn("The rate limiter is unreachable, so requests are not being counted.", { reason: error.message });
2272
1252
  }
2273
1253
  }
2274
- Object.defineProperty(ThrottleGuard, Symbol.for("dunx.deps"), {
2275
- value: () => [ThrottleOptions, ThrottleStore, ClientAddress, Logger5]
2276
- });
1254
+ Object.defineProperty(ThrottleGuard, Symbol.for("dunx.deps"), { value: () => [ThrottleOptions, ThrottleStore, ClientAddress, Logger5] });
2277
1255
  // src/throttle/module.ts
2278
1256
  import {
2279
1257
  Logger as Logger6,
@@ -2347,99 +1325,6 @@ var OnMessage = (event) => (value) => {
2347
1325
  markHandler(value, { kind: HandlerKind.MESSAGE, event });
2348
1326
  return value;
2349
1327
  };
2350
- // src/ws/redis-relay.ts
2351
- import { AppError as AppError11 } from "@dunx/core";
2352
- var PROTOCOLS = [
2353
- "redis:",
2354
- "rediss:",
2355
- "valkey:",
2356
- "valkeys:",
2357
- "redis+tls:",
2358
- "redis+unix:",
2359
- "redis+tls+unix:"
2360
- ];
2361
- var defaultRelayUrl = () => process.env["VALKEY_URL"] ?? process.env["REDIS_URL"] ?? "redis://localhost:6379";
2362
- var assertUrl = (url) => {
2363
- let parsed;
2364
- try {
2365
- parsed = new URL(url);
2366
- } catch {
2367
- throw new AppError11(`${JSON.stringify(url)} is not a valid URL for the websocket relay. ` + "Expected something like redis://localhost:6379.");
2368
- }
2369
- if (!PROTOCOLS.includes(parsed.protocol)) {
2370
- throw new AppError11(`Unsupported protocol ${JSON.stringify(parsed.protocol)} in ` + `${JSON.stringify(url)}. Expected one of ${PROTOCOLS.join(", ")}.`);
2371
- }
2372
- return url;
2373
- };
2374
-
2375
- class RedisRelay {
2376
- #url;
2377
- #options;
2378
- #pub;
2379
- #sub;
2380
- #channel;
2381
- constructor(options = {}) {
2382
- this.#url = assertUrl(options.url ?? defaultRelayUrl());
2383
- this.#options = {
2384
- maxRetries: options.maxRetries ?? 0,
2385
- ...options.connectionTimeout !== undefined && {
2386
- connectionTimeout: options.connectionTimeout
2387
- },
2388
- ...options.tls !== undefined && { tls: options.tls }
2389
- };
2390
- }
2391
- get url() {
2392
- const parsed = new URL(this.#url);
2393
- if (parsed.password)
2394
- parsed.password = "***";
2395
- return parsed.toString();
2396
- }
2397
- async publish(channel, message) {
2398
- const client = this.#pub ??= new Bun.RedisClient(this.#url, this.#options);
2399
- try {
2400
- return await client.publish(channel, message);
2401
- } catch (error) {
2402
- if (this.#pub === client) {
2403
- this.#pub = undefined;
2404
- client.close();
2405
- }
2406
- throw error;
2407
- }
2408
- }
2409
- async subscribe(channel, listener) {
2410
- const client = this.#sub ??= new Bun.RedisClient(this.#url, this.#options);
2411
- try {
2412
- await client.connect();
2413
- await client.subscribe(channel, listener);
2414
- this.#channel = channel;
2415
- } catch (error) {
2416
- if (this.#sub === client) {
2417
- this.#sub = undefined;
2418
- client.close();
2419
- }
2420
- throw error;
2421
- }
2422
- }
2423
- async close() {
2424
- const sub = this.#sub;
2425
- const channel = this.#channel;
2426
- this.#pub?.close();
2427
- this.#pub = undefined;
2428
- this.#sub = undefined;
2429
- this.#channel = undefined;
2430
- if (!sub)
2431
- return;
2432
- if (channel !== undefined) {
2433
- try {
2434
- await sub.unsubscribe(channel);
2435
- } catch {}
2436
- }
2437
- sub.close();
2438
- }
2439
- }
2440
- Object.defineProperty(RedisRelay, Symbol.for("dunx.deps"), {
2441
- value: () => [{ unresolved: "options: RedisRelayOptions = {}" }]
2442
- });
2443
1328
  // src/health/contracts.ts
2444
1329
  class HealthIndicator {
2445
1330
  critical = true;
@@ -2450,205 +1335,6 @@ class PingProbe {
2450
1335
 
2451
1336
  class QueryProbe {
2452
1337
  }
2453
- // src/health/controller.ts
2454
- import { inject } from "@dunx/core";
2455
-
2456
- // src/health/report-schema.ts
2457
- var state = {
2458
- type: "string",
2459
- enum: ["up", "down", "unknown"],
2460
- description: "`unknown` is not `down`: a probe that timed out has told you nothing."
2461
- };
2462
- var HEALTH_REPORT_SCHEMA = Object.freeze({
2463
- $id: "HealthReport",
2464
- type: "object",
2465
- description: "What the probe found. `up` answers 200 and anything else answers 503.",
2466
- properties: {
2467
- status: state,
2468
- draining: {
2469
- type: "boolean",
2470
- description: "The process is shutting down, or something holds it out."
2471
- },
2472
- uptimeMs: {
2473
- type: "integer",
2474
- description: "Measured on a monotonic clock, so it never goes backwards."
2475
- },
2476
- checks: {
2477
- type: "array",
2478
- items: {
2479
- type: "object",
2480
- properties: {
2481
- name: { type: "string" },
2482
- state,
2483
- critical: {
2484
- type: "boolean",
2485
- description: "A failure here sheds traffic. Memory and disk do not."
2486
- },
2487
- ms: { type: "integer", description: "How long the check took." },
2488
- detail: {
2489
- type: "string",
2490
- description: "A latency, a version, or a failure message."
2491
- }
2492
- },
2493
- required: ["name", "state", "critical", "ms"]
2494
- }
2495
- }
2496
- },
2497
- required: ["status", "draining", "uptimeMs", "checks"]
2498
- });
2499
-
2500
- // src/health/registry.ts
2501
- var bounded = async (indicator, timeoutMs) => {
2502
- let timer;
2503
- const timeout = new Promise((resolve2) => {
2504
- timer = setTimeout(() => resolve2({ state: "unknown", detail: `no answer in ${timeoutMs} ms` }), timeoutMs);
2505
- timer.unref?.();
2506
- });
2507
- try {
2508
- return await Promise.race([
2509
- Promise.resolve().then(() => indicator.check()).catch((error) => ({
2510
- state: "down",
2511
- detail: error instanceof Error ? error.message : String(error)
2512
- })),
2513
- timeout
2514
- ]);
2515
- } finally {
2516
- if (timer)
2517
- clearTimeout(timer);
2518
- }
2519
- };
2520
- var worst = (checks) => {
2521
- const critical = checks.filter((check) => check.critical);
2522
- if (critical.some((check) => check.state === "down"))
2523
- return "down";
2524
- if (critical.some((check) => check.state === "unknown"))
2525
- return "unknown";
2526
- return "up";
2527
- };
2528
-
2529
- class HealthOptions {
2530
- liveness;
2531
- readiness;
2532
- timeoutMs;
2533
- routes;
2534
- documented;
2535
- drainDelayMs;
2536
- constructor(init = {}) {
2537
- this.liveness = init.liveness ?? [];
2538
- this.readiness = init.readiness ?? [];
2539
- this.timeoutMs = init.timeoutMs ?? 2000;
2540
- this.routes = init.routes ?? true;
2541
- this.documented = init.documented ?? true;
2542
- this.drainDelayMs = Math.max(0, init.drainDelayMs ?? 0);
2543
- }
2544
- }
2545
- Object.defineProperty(HealthOptions, Symbol.for("dunx.deps"), {
2546
- value: () => [{ unresolved: "init: HealthOptionsInit = {}" }]
2547
- });
2548
-
2549
- class HealthRegistry {
2550
- options;
2551
- readiness_;
2552
- #startedAt = performance.now();
2553
- constructor(options, readiness_) {
2554
- this.options = options;
2555
- this.readiness_ = readiness_;
2556
- }
2557
- async report(indicators) {
2558
- const checks = await Promise.all(indicators.map(async (indicator) => {
2559
- const started = performance.now();
2560
- const result = await bounded(indicator, this.options.timeoutMs);
2561
- return {
2562
- name: indicator.name,
2563
- state: result.state,
2564
- critical: indicator.critical,
2565
- ms: Math.round(performance.now() - started),
2566
- ...result.detail === undefined ? {} : { detail: result.detail }
2567
- };
2568
- }));
2569
- return {
2570
- status: worst(checks),
2571
- draining: this.readiness_.draining,
2572
- uptimeMs: Math.round(performance.now() - this.#startedAt),
2573
- checks
2574
- };
2575
- }
2576
- liveness() {
2577
- return this.report(this.options.liveness);
2578
- }
2579
- async readiness() {
2580
- const report = await this.report(this.options.readiness);
2581
- if (!this.readiness_.draining)
2582
- return report;
2583
- return {
2584
- ...report,
2585
- status: "down",
2586
- checks: [
2587
- {
2588
- name: "readiness",
2589
- state: "down",
2590
- critical: true,
2591
- ms: 0,
2592
- detail: this.readiness_.reason ?? "not accepting traffic"
2593
- },
2594
- ...report.checks
2595
- ]
2596
- };
2597
- }
2598
- }
2599
- Object.defineProperty(HealthRegistry, Symbol.for("dunx.deps"), {
2600
- value: () => [HealthOptions, { unresolved: "private readonly readiness_: Readiness", typeOnly: "Readiness" }]
2601
- });
2602
-
2603
- // src/health/controller.ts
2604
- var probeResponses = {
2605
- response: { 200: HEALTH_REPORT_SCHEMA, 503: HEALTH_REPORT_SCHEMA }
2606
- };
2607
- var answer = (report) => Response.json(report, { status: report.status === "up" ? 200 : 503 });
2608
- var _dec = [
2609
- Controller("health")
2610
- ];
2611
- var _dec2 = [
2612
- Public(),
2613
- Get("/live", probeResponses)
2614
- ];
2615
- var _dec3 = [
2616
- Public(),
2617
- Get("/ready", probeResponses)
2618
- ];
2619
- var _health = new WeakMap;
2620
- var _init = __decoratorStart(undefined);
2621
-
2622
- class HealthController {
2623
- constructor() {
2624
- __privateAdd(this, _health, inject(HealthRegistry));
2625
- __runInitializers(_init, 5, this);
2626
- }
2627
- async live() {
2628
- return answer(await __privateGet(this, _health).liveness());
2629
- }
2630
- async ready() {
2631
- return answer(await __privateGet(this, _health).readiness());
2632
- }
2633
- }
2634
- __decorateElement(_init, 1, "live", _dec2, HealthController);
2635
- __decorateElement(_init, 1, "ready", _dec3, HealthController);
2636
- HealthController = __decorateElement(_init, 0, "HealthController", _dec, HealthController);
2637
- __runInitializers(_init, 1, HealthController);
2638
- __decoratorMetadata(_init, HealthController);
2639
- let _HealthController = HealthController;
2640
- var _dec = [
2641
- ApiHidden()
2642
- ];
2643
- var _base = HealthController;
2644
- var _init = __decoratorStart(_base);
2645
-
2646
- class HiddenHealthController extends _base {
2647
- }
2648
- HiddenHealthController = __decorateElement(_init, 0, "HiddenHealthController", _dec, HiddenHealthController);
2649
- __runInitializers(_init, 1, HiddenHealthController);
2650
- __decoratorMetadata(_init, HiddenHealthController);
2651
- let _HiddenHealthController = HiddenHealthController;
2652
1338
  // src/health/indicators.ts
2653
1339
  import { statfs } from "fs/promises";
2654
1340
  var ms = (started) => Math.round(performance.now() - started);
@@ -2666,9 +1352,7 @@ class RedisIndicator extends HealthIndicator {
2666
1352
  return { state: "up", detail: `${ms(started)} ms` };
2667
1353
  }
2668
1354
  }
2669
- Object.defineProperty(RedisIndicator, Symbol.for("dunx.deps"), {
2670
- value: () => [{ unresolved: "private readonly redis: PingProbe", typeOnly: "PingProbe" }]
2671
- });
1355
+ Object.defineProperty(RedisIndicator, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "private readonly redis: PingProbe", typeOnly: "PingProbe" }] });
2672
1356
 
2673
1357
  class DatabaseIndicator extends HealthIndicator {
2674
1358
  db;
@@ -2683,9 +1367,7 @@ class DatabaseIndicator extends HealthIndicator {
2683
1367
  return { state: "up", detail: `${ms(started)} ms` };
2684
1368
  }
2685
1369
  }
2686
- Object.defineProperty(DatabaseIndicator, Symbol.for("dunx.deps"), {
2687
- value: () => [{ unresolved: "private readonly db: QueryProbe", typeOnly: "QueryProbe" }]
2688
- });
1370
+ Object.defineProperty(DatabaseIndicator, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "private readonly db: QueryProbe", typeOnly: "QueryProbe" }] });
2689
1371
 
2690
1372
  class MemoryOptions {
2691
1373
  maxRssBytes;
@@ -2693,9 +1375,7 @@ class MemoryOptions {
2693
1375
  this.maxRssBytes = init.maxRssBytes;
2694
1376
  }
2695
1377
  }
2696
- Object.defineProperty(MemoryOptions, Symbol.for("dunx.deps"), {
2697
- value: () => [{ unresolved: "init: MemoryOptionsInit" }]
2698
- });
1378
+ Object.defineProperty(MemoryOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: MemoryOptionsInit" }] });
2699
1379
  var MIB = 1024 * 1024;
2700
1380
  var mib = (bytes) => `${Math.round(bytes / MIB)} MiB`;
2701
1381
 
@@ -2713,9 +1393,7 @@ class MemoryIndicator extends HealthIndicator {
2713
1393
  return rss > this.options.maxRssBytes ? { state: "down", detail } : { state: "up", detail };
2714
1394
  }
2715
1395
  }
2716
- Object.defineProperty(MemoryIndicator, Symbol.for("dunx.deps"), {
2717
- value: () => [MemoryOptions]
2718
- });
1396
+ Object.defineProperty(MemoryIndicator, Symbol.for("dunx.deps"), { value: () => [MemoryOptions] });
2719
1397
 
2720
1398
  class DiskOptions {
2721
1399
  path;
@@ -2725,9 +1403,7 @@ class DiskOptions {
2725
1403
  this.maxUsedFraction = init.maxUsedFraction;
2726
1404
  }
2727
1405
  }
2728
- Object.defineProperty(DiskOptions, Symbol.for("dunx.deps"), {
2729
- value: () => [{ unresolved: "init: DiskOptionsInit" }]
2730
- });
1406
+ Object.defineProperty(DiskOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: DiskOptionsInit" }] });
2731
1407
 
2732
1408
  class DiskIndicator extends HealthIndicator {
2733
1409
  options;
@@ -2748,9 +1424,7 @@ class DiskIndicator extends HealthIndicator {
2748
1424
  return used > this.options.maxUsedFraction ? { state: "down", detail } : { state: "up", detail };
2749
1425
  }
2750
1426
  }
2751
- Object.defineProperty(DiskIndicator, Symbol.for("dunx.deps"), {
2752
- value: () => [DiskOptions]
2753
- });
1427
+ Object.defineProperty(DiskIndicator, Symbol.for("dunx.deps"), { value: () => [DiskOptions] });
2754
1428
  // src/health/module.ts
2755
1429
  import {
2756
1430
  Module as Module4,
@@ -2764,9 +1438,7 @@ class ReadinessOptions {
2764
1438
  this.drainDelayMs = Math.max(0, init.drainDelayMs ?? 0);
2765
1439
  }
2766
1440
  }
2767
- Object.defineProperty(ReadinessOptions, Symbol.for("dunx.deps"), {
2768
- value: () => [{ unresolved: "init: ReadinessOptionsInit = {}" }]
2769
- });
1441
+ Object.defineProperty(ReadinessOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: ReadinessOptionsInit = {}", optional: true }] });
2770
1442
 
2771
1443
  class Readiness {
2772
1444
  options;
@@ -2794,9 +1466,7 @@ class Readiness {
2794
1466
  }
2795
1467
  }
2796
1468
  }
2797
- Object.defineProperty(Readiness, Symbol.for("dunx.deps"), {
2798
- value: () => [ReadinessOptions]
2799
- });
1469
+ Object.defineProperty(Readiness, Symbol.for("dunx.deps"), { value: () => [ReadinessOptions] });
2800
1470
 
2801
1471
  // src/health/module.ts
2802
1472
  var wiring = (options) => [