@dunx/http 2.2.0 → 2.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/client.js CHANGED
@@ -445,21 +445,21 @@ class HttpModule {
445
445
  }
446
446
  }
447
447
  export {
448
- safeStringify,
449
- retryAfterMs,
450
- isRetryableStatus,
451
- isPlainObject,
452
- isJsonBody,
453
- httpClient,
454
- executeWithRetry,
455
- backoffDelay,
456
- HttpService,
457
- HttpModule,
458
- HttpClientOptions,
459
- FetchTransportError,
448
+ DEFAULT_REQUEST_ID_HEADER,
460
449
  FetchError,
461
- DEFAULT_REQUEST_ID_HEADER
450
+ FetchTransportError,
451
+ HttpClientOptions,
452
+ HttpModule,
453
+ HttpService,
454
+ backoffDelay,
455
+ executeWithRetry,
456
+ httpClient,
457
+ isJsonBody,
458
+ isPlainObject,
459
+ isRetryableStatus,
460
+ retryAfterMs,
461
+ safeStringify
462
462
  };
463
463
 
464
- //# debugId=67E96F658C57D72264756E2164756E21
464
+ //# debugId=9448CCC7AF6FC82264756E2164756E21
465
465
  //# sourceMappingURL=client.js.map
@@ -10,6 +10,6 @@
10
10
  "import { Logger, RequestContext } from '@dunx/core';\nimport { UrlHelper, type ParamsType } from '@arkv/shared';\nimport type { HttpMethod } from '../route/marker.js';\nimport { FetchError, FetchTransportError } from './errors.js';\nimport { isJsonBody, safeStringify } from './json.js';\nimport { HttpClientOptions } from './options.js';\nimport { executeWithRetry, type RetryOptions } from './retry.js';\n\n/** The client speaks two more verbs than a route can declare. */\nexport type RequestMethod = HttpMethod | 'HEAD' | 'OPTIONS';\n\n/**\n * `@arkv/shared`'s own param type, imported rather than restated - a local copy\n * would drift from what `buildUrl` actually accepts, which is how `null` ended up\n * in the first draft of this file and `interpolate` would never have seen it.\n */\ntype Params = ParamsType;\n\n/**\n * `fetch`'s own body type, derived from its signature. `BodyInit` is not a global\n * here: the root tsconfig sets `lib: [\"ESNext\"]` with no DOM, so the name does not\n * exist even though the value does. Reading it off `typeof fetch` needs no lib and\n * cannot disagree with the runtime.\n */\ntype FetchBody = NonNullable<NonNullable<Parameters<typeof fetch>[1]>['body']>;\n\nexport type HeaderFactory = (params: {\n /** Unix seconds, which is what every HMAC scheme signs. */\n readonly timestamp: number;\n readonly method: RequestMethod;\n /** `pathname + search`, the part such schemes sign. */\n readonly requestPath: string;\n /** The serialised body, or `''`. */\n readonly body: string;\n}) => Record<string, string>;\n\nexport interface RequestConfig<TRequest = unknown, TResponse = unknown> {\n readonly method: RequestMethod;\n /** Absolute, or relative to `baseUrl`. Omit when `baseUrl` plus `path` is enough. */\n readonly url?: string | URL;\n readonly payload?: TRequest;\n readonly headers?: Readonly<Record<string, string>>;\n /** Appended to the base, with `{param}` interpolated from `pathParams`. */\n readonly path?: string;\n readonly pathParams?: Params;\n readonly queryParams?: Params;\n /** Overrides the client's default budget. */\n readonly timeoutMs?: number;\n /** Called once per attempt, so a signature covers the body it is sent with. */\n readonly headerFactory?: HeaderFactory;\n /** Merged into the async context for this call, so its logs carry it. */\n readonly flow?: string;\n readonly retry?: RetryOptions<TResponse>;\n /** Cancels the call. Combined with the timeout, whichever fires first. */\n readonly signal?: AbortSignal;\n}\n\ntype BaseOptions<TRequest, TResponse> = Omit<\n RequestConfig<TRequest, TResponse>,\n 'method' | 'url' | 'payload'\n>;\n\n/**\n * What `send` reads. Narrower than `RequestConfig` on purpose: `RetryOptions<T>` is\n * invariant in `T` - its `onSuccess` takes a `T` and its callbacks return one - so a\n * `RequestConfig<_, TResponse>` is not assignable to a `RequestConfig<_, unknown>`.\n * `send` never touches `retry`, so leaving it out is both true and assignable.\n */\ninterface SendConfig {\n readonly method: RequestMethod;\n readonly headers?: Readonly<Record<string, string>>;\n readonly timeoutMs?: number;\n readonly headerFactory?: HeaderFactory;\n readonly signal?: AbortSignal;\n}\n\n/**\n * A `fetch` client with a per-request timeout, retry with backoff, request-id\n * propagation and one log line per call.\n *\n * `fetch` and nothing else: it is a Web standard Bun implements natively, so there\n * is no client dependency to justify - which is also why `axios` and `node-fetch`\n * are banned repo-wide. What this adds over calling `fetch` yourself is the parts\n * every caller otherwise reimplements slightly differently: the timeout, the\n * retry policy, `Retry-After`, url building, and a failure that says which call\n * failed.\n *\n * Extends `UrlHelper` from `@arkv/shared`, so `buildUrl` and `interpolate` are\n * available on the service, and there is one implementation of them across the\n * owner's projects rather than a fork per repo.\n */\nexport class HttpService extends UrlHelper {\n constructor(\n private readonly options: HttpClientOptions,\n private readonly logger: Logger,\n private readonly requestContext: RequestContext,\n ) {\n super();\n }\n\n async request<TRequest = unknown, TResponse = unknown>(\n config: RequestConfig<TRequest, TResponse>,\n ): Promise<TResponse> {\n const url = this.urlFor(config);\n const startedAt = Date.now();\n let attempts = 0;\n let status: number | undefined;\n\n /**\n * Serialised **once**, outside the retry loop. A body does not change between\n * attempts - only the signature over it does, and `headerFactory` gets a fresh\n * timestamp per attempt from `send`.\n *\n * Doing it inside meant a caller's own `JSON.stringify` failure, a circular\n * payload, was treated as a retryable error: three attempts and eight seconds of\n * backoff before surfacing a bug that no amount of retrying could fix. It also\n * re-serialised a large body on every attempt.\n */\n const { body, serialised } = this.bodyFor(config.payload);\n\n /**\n * A stream body is consumed by the first attempt, so a second would send an\n * empty one. Retrying is switched off rather than left to fail as a confusing\n * \"body already used\" on the retry.\n */\n const replayable = !(config.payload instanceof ReadableStream);\n\n const attempt = async (): Promise<TResponse> => {\n attempts += 1;\n const response = await this.send(config, url, body, serialised);\n status = response.status;\n\n if (!response.ok) {\n throw new FetchError(\n response.status,\n response.statusText,\n await readBody(response),\n {\n method: config.method,\n url: url.href,\n headers: response.headers,\n },\n );\n }\n\n return (await readBody(response)) as TResponse;\n };\n\n const describe = (): string => `${config.method} ${url.href}`;\n\n try {\n const result = await this.requestContext.runWithContext(\n {\n ...(config.flow === undefined ? {} : { flow: config.flow }),\n event: config.path ?? url.pathname,\n },\n () =>\n executeWithRetry(attempt, {\n ...this.options.retry,\n ...config.retry,\n ...(replayable ? {} : { maxRetries: 0 }),\n } as RetryOptions<TResponse>),\n );\n\n this.logger.debug(`${describe()} succeeded`, {\n status,\n attempts,\n elapsedMs: Date.now() - startedAt,\n });\n return result;\n } catch (error) {\n this.logger.error(`${describe()} failed`, {\n // `safeStringify`, not the error object: an upstream body can carry a cycle\n // and this is the one place that must not throw while reporting a throw.\n err: safeStringify(describeError(error)),\n attempts,\n elapsedMs: Date.now() - startedAt,\n });\n throw error;\n }\n }\n\n get<TResponse = unknown>(\n url?: string | URL,\n options?: BaseOptions<never, TResponse>,\n ): Promise<TResponse> {\n return this.request<never, TResponse>({\n method: 'GET',\n ...options,\n ...urlOf(url),\n });\n }\n\n post<TRequest = unknown, TResponse = unknown>(\n url?: string | URL,\n payload?: TRequest,\n options?: BaseOptions<TRequest, TResponse>,\n ): Promise<TResponse> {\n return this.request<TRequest, TResponse>({\n method: 'POST',\n ...options,\n ...urlOf(url),\n ...(payload === undefined ? {} : { payload }),\n });\n }\n\n put<TRequest = unknown, TResponse = unknown>(\n url?: string | URL,\n payload?: TRequest,\n options?: BaseOptions<TRequest, TResponse>,\n ): Promise<TResponse> {\n return this.request<TRequest, TResponse>({\n method: 'PUT',\n ...options,\n ...urlOf(url),\n ...(payload === undefined ? {} : { payload }),\n });\n }\n\n patch<TRequest = unknown, TResponse = unknown>(\n url?: string | URL,\n payload?: TRequest,\n options?: BaseOptions<TRequest, TResponse>,\n ): Promise<TResponse> {\n return this.request<TRequest, TResponse>({\n method: 'PATCH',\n ...options,\n ...urlOf(url),\n ...(payload === undefined ? {} : { payload }),\n });\n }\n\n delete<TResponse = unknown>(\n url?: string | URL,\n options?: BaseOptions<never, TResponse>,\n ): Promise<TResponse> {\n return this.request<never, TResponse>({\n method: 'DELETE',\n ...options,\n ...urlOf(url),\n });\n }\n\n /**\n * Yields each `data:` payload of a Server-Sent-Events response, consuming the\n * terminating `[DONE]` sentinel rather than yielding it.\n *\n * **No retry**, deliberately: a partially consumed stream cannot be replayed, so\n * retrying would re-deliver events the caller has already seen. The timeout\n * covers the connect only - it is dropped once headers arrive, or a long-lived\n * stream would be cut off mid-flight.\n *\n * Hand-rolled rather than delegated: Bun exposes no `EventSource` global and no\n * SSE parser, which was measured rather than assumed.\n */\n async *streamSse<TRequest = unknown>(\n config: Omit<RequestConfig<TRequest>, 'method' | 'retry'> & {\n readonly method?: 'GET' | 'POST';\n },\n ): AsyncGenerator<string> {\n const url = this.urlFor(config);\n const method = config.method ?? 'POST';\n const startedAt = Date.now();\n const { body, serialised } = this.bodyFor(config.payload);\n\n const response = await this.send(\n { ...config, method },\n url,\n body,\n serialised,\n 'text/event-stream',\n );\n\n if (!response.ok || response.body === null) {\n throw new FetchError(\n response.status,\n response.statusText,\n await readBody(response),\n { method, url: url.href, headers: response.headers },\n );\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n // Async iteration, not `getReader()`: it acquires the reader and releases it\n // on completion, on `break`, and on the `return` below when `[DONE]` arrives -\n // which is the case the manual form needed `releaseLock()` in a `finally` for.\n for await (const chunk of response.body) {\n buffer += decoder.decode(chunk, { stream: true });\n\n let newline = buffer.indexOf('\\n');\n while (newline !== -1) {\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n newline = buffer.indexOf('\\n');\n\n if (!line.startsWith('data:')) continue;\n const data = line.slice(5).trim();\n if (data === '[DONE]') return;\n yield data;\n }\n }\n } finally {\n this.logger.debug(`SSE ${method} ${url.href} closed`, {\n elapsedMs: Date.now() - startedAt,\n });\n }\n }\n\n /**\n * Resolves the target, accepting the three forms a caller actually reaches for:\n * an absolute url, a path relative to `baseUrl`, or `baseUrl` plus an explicit\n * `path`.\n *\n * `get('/users')` is the one worth calling out. A relative first argument is what\n * every HTTP client takes once a base url exists, and passing it straight to\n * `buildUrl` throws `ERR_INVALID_URL` from inside `new URL()` - a message naming\n * neither the call nor the missing base. So a first argument that is not an\n * absolute url is treated as the path, which is what it reads as.\n *\n * `URL.canParse` decides, rather than a regex over `//` or `:` - it is the same\n * parser `new URL` uses, so the two cannot disagree.\n */\n private urlFor(config: {\n readonly url?: string | URL;\n readonly path?: string;\n readonly pathParams?: Params;\n readonly queryParams?: Params;\n }): URL {\n const given = config.url === undefined ? undefined : String(config.url);\n const absolute =\n given !== undefined && given !== '' && URL.canParse(given)\n ? given\n : undefined;\n const relative = given === '' || absolute !== undefined ? undefined : given;\n const base = absolute ?? this.options.baseUrl;\n\n if (base === undefined) {\n throw new FetchTransportError(\n { method: 'GET', url: given ?? config.path ?? '(none)' },\n false,\n {\n cause: new Error(\n 'No url to call. Pass an absolute url, or set baseUrl on ' +\n 'HttpModule.forRoot and pass a path.',\n ),\n },\n );\n }\n\n // An explicit `path` wins over a relative first argument, so a call cannot\n // silently request two different paths.\n const path = config.path ?? relative;\n\n return this.buildUrl({\n base,\n ...(path === undefined ? {} : { path }),\n ...(config.pathParams === undefined\n ? {}\n : { pathParams: config.pathParams }),\n ...(config.queryParams === undefined\n ? {}\n : { queryParams: config.queryParams }),\n });\n }\n\n /** `serialised` is what a `headerFactory` signs, and is `''` for no body. */\n private bodyFor(payload: unknown): {\n body: FetchBody | undefined;\n serialised: string;\n json: boolean;\n } {\n if (payload === undefined || payload === null) {\n return { body: undefined, serialised: '', json: false };\n }\n if (!isJsonBody(payload)) {\n return { body: payload as FetchBody, serialised: '', json: false };\n }\n // Plain `JSON.stringify`, deliberately not `safeStringify`: a cycle here must\n // throw rather than be sent upstream as \"[Circular]\".\n const serialised = JSON.stringify(payload);\n return { body: serialised, serialised, json: true };\n }\n\n private async send(\n config: SendConfig,\n url: URL,\n body: FetchBody | undefined,\n serialised: string,\n accept = 'application/json',\n ): Promise<Response> {\n const requestId =\n this.options.requestIdHeader === undefined\n ? undefined\n : this.requestContext.getContext().requestId;\n\n const headers: Record<string, string> = {\n accept,\n ...(serialised === '' ? {} : { 'content-type': 'application/json' }),\n ...this.options.headers,\n ...(requestId === undefined || this.options.requestIdHeader === undefined\n ? {}\n : { [this.options.requestIdHeader]: requestId }),\n ...config.headerFactory?.({\n timestamp: Math.floor(Date.now() / 1000),\n method: config.method,\n requestPath: url.pathname + url.search,\n body: serialised,\n }),\n ...config.headers,\n };\n\n /**\n * `AbortSignal.timeout` plus `AbortSignal.any`, rather than an\n * `AbortController` with a `setTimeout` and a `clearTimeout` in a `finally`.\n * Both are Web standards Bun implements, the timer is the runtime's to cancel,\n * and combining the caller's signal with the budget is one call instead of a\n * second listener that has to be removed.\n */\n const timeoutMs = config.timeoutMs ?? this.options.timeoutMs;\n const signals = [\n ...(timeoutMs > 0 ? [AbortSignal.timeout(timeoutMs)] : []),\n ...(config.signal === undefined ? [] : [config.signal]),\n ];\n\n try {\n return await fetch(url.href, {\n method: config.method,\n headers,\n ...(body === undefined ? {} : { body }),\n ...(signals.length === 0 ? {} : { signal: AbortSignal.any(signals) }),\n ...this.options.fetchOptions,\n });\n } catch (error) {\n // `fetch` reports a refused connection, a DNS failure and an abort all as\n // exceptions with nothing naming the call. Wrapped so the message does.\n const aborted =\n error instanceof Error &&\n (error.name === 'AbortError' || error.name === 'TimeoutError');\n throw new FetchTransportError(\n { method: config.method, url: url.href },\n aborted,\n { cause: error },\n );\n }\n }\n}\nObject.defineProperty(HttpService, Symbol.for('dunx.deps'), {\n value: () => [HttpClientOptions, Logger, RequestContext],\n});\n\nconst urlOf = (url?: string | URL): { url?: string | URL } =>\n url === undefined ? {} : { url };\n\n/** JSON when the upstream said so or the body parses; text otherwise; undefined for empty. */\nconst readBody = async (response: Response): Promise<unknown> => {\n const text = await response.text().catch(() => '');\n if (text === '') return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return text;\n }\n};\n\nconst describeError = (error: unknown): Record<string, unknown> => {\n if (error instanceof FetchError) {\n return {\n name: error.name,\n message: error.message,\n status: error.status,\n body: error.body,\n };\n }\n if (error instanceof Error) {\n return { name: error.name, message: error.message };\n }\n return { message: String(error) };\n};\n"
11
11
  ],
12
12
  "mappings": "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",
13
- "debugId": "67E96F658C57D72264756E2164756E21",
13
+ "debugId": "9448CCC7AF6FC82264756E2164756E21",
14
14
  "names": []
15
15
  }
@@ -18,6 +18,7 @@ export interface HealthCheckReport {
18
18
  export interface HealthReport {
19
19
  readonly status: ProbeState;
20
20
  readonly draining: boolean;
21
+ /** Measured on a monotonic clock, so it never goes backwards. */
21
22
  readonly uptimeMs: number;
22
23
  readonly checks: readonly HealthCheckReport[];
23
24
  }
package/dist/index.d.ts CHANGED
@@ -9,7 +9,8 @@ export { buildContext, type RouteContext } from './server/context.js';
9
9
  export { preflight, withCors, type CorsOptions, type CorsOrigin, } from './server/cors.js';
10
10
  export { defaultErrorMapper, ErrorFilter, errorMapper, HttpError, isErrorFilter, toErrorMapper, ValidationError, type ErrorHandler, type ErrorMapper, type HttpErrorOptions, type InputSource, type ValidationIssue, } from './server/errors.js';
11
11
  export { HttpFactory, type HttpApp, type HttpOptions, } from './server/factory.js';
12
- export { REQUEST_ID_HEADER, RequestLoggingMiddleware, type RequestLoggingOptions, } from './server/request-logging.js';
12
+ export { REQUEST_ID_HEADER } from './server/request-id.js';
13
+ export { RequestLoggingMiddleware, type RequestLoggingOptions, } from './server/request-logging.js';
13
14
  export { compose, type Middleware, type Next, type RouteHandler, } from './server/middleware.js';
14
15
  export { assertNoCollisions, assertNoGatewayCollisions, buildRoutes, withUpgradeRoutes, type BunRoutes, type GuardResolver, type RouteMethod, type ServeRoutes, } from './server/routes.js';
15
16
  export type { AppSettings } from './server/settings.js';
package/dist/index.js CHANGED
@@ -501,6 +501,7 @@ var defaultOnError = (error, socket) => {
501
501
  var reportedByMiddleware = () => {
502
502
  return;
503
503
  };
504
+ 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(", ")}.`;
504
505
  var runtimeOf = (socket) => socket.data[RUNTIME];
505
506
  var isBinary = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
506
507
  var replyRaw = (socket, value) => {
@@ -584,6 +585,7 @@ var buildWebSocket = (discovered, options = {}, middleware = []) => {
584
585
  ]));
585
586
  const gateways = [...wrapped.values()];
586
587
  const onError = options.onError ?? (middleware.length === 0 ? defaultOnError : reportedByMiddleware);
588
+ const reports = options.onError !== undefined || middleware.some((entry) => entry.reportsErrors === true);
587
589
  const { onError: _onError, ...socketOptions } = options;
588
590
  const run = (invoke, args, ws, then) => {
589
591
  try {
@@ -686,6 +688,7 @@ var buildWebSocket = (discovered, options = {}, middleware = []) => {
686
688
  websocket,
687
689
  routes: new Map(gateways.map((gateway) => [gateway.path, upgradeHandler(gateway)])),
688
690
  paths: [...byPath.keys()],
691
+ warnings: middleware.length > 0 && !reports ? [unreported(middleware)] : [],
689
692
  gateways: gateways.map((gateway) => ({
690
693
  name: gateway.name,
691
694
  path: gateway.path,
@@ -705,6 +708,7 @@ var elapsedMs = (started) => Math.round((Bun.nanoseconds() - started) / 1e6);
705
708
  class SocketLoggingMiddleware {
706
709
  logger;
707
710
  context;
711
+ reportsErrors = true;
708
712
  #level;
709
713
  #errorLevel;
710
714
  #events;
@@ -965,9 +969,28 @@ import {
965
969
  Logger as Logger2,
966
970
  RequestContext as RequestContext2
967
971
  } from "@dunx/core";
972
+
973
+ // src/server/request-id.ts
968
974
  var REQUEST_ID_HEADER = "x-request-id";
969
975
  var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
970
976
  var traceId = (inbound) => inbound !== null && inbound.length === 36 && UUID.test(inbound) ? inbound : crypto.randomUUID();
977
+ var ID = Symbol.for("dunx.http.requestId");
978
+
979
+ class RequestIds {
980
+ static assign(req) {
981
+ const id = traceId(req.headers.get(REQUEST_ID_HEADER));
982
+ req[ID] = id;
983
+ return id;
984
+ }
985
+ static stamp(response, req) {
986
+ const id = req[ID];
987
+ if (id !== undefined)
988
+ response.headers.set(REQUEST_ID_HEADER, id);
989
+ return response;
990
+ }
991
+ }
992
+
993
+ // src/server/request-logging.ts
971
994
  var parse = (text, limit) => {
972
995
  if (limit === 0)
973
996
  return;
@@ -1020,7 +1043,7 @@ class RequestLoggingMiddleware {
1020
1043
  return this.#correlateIgnored ? this.#correlated(req, ctx, path, next) : next();
1021
1044
  }
1022
1045
  const started = Bun.nanoseconds();
1023
- const requestId = traceId(req.headers.get(REQUEST_ID_HEADER));
1046
+ const requestId = RequestIds.assign(req);
1024
1047
  const scope = {
1025
1048
  requestId,
1026
1049
  method: ctx.method,
@@ -1048,7 +1071,7 @@ class RequestLoggingMiddleware {
1048
1071
  });
1049
1072
  }
1050
1073
  #correlated(req, ctx, path, next) {
1051
- const requestId = traceId(req.headers.get(REQUEST_ID_HEADER));
1074
+ const requestId = RequestIds.assign(req);
1052
1075
  const stamp = (response) => {
1053
1076
  response.headers.set(REQUEST_ID_HEADER, requestId);
1054
1077
  return response;
@@ -1302,7 +1325,7 @@ var buildFallback = (middleware = [], onError = defaultErrorMapper, cors, notFou
1302
1325
  try {
1303
1326
  return await compose(middleware, unmatchedContext(req, notFound === "public"), miss)(req);
1304
1327
  } catch (error) {
1305
- return onError(error, req);
1328
+ return RequestIds.stamp(onError(error, req), req);
1306
1329
  }
1307
1330
  };
1308
1331
  return cors ? withCors(cors, run) : run;
@@ -1359,7 +1382,7 @@ var buildRoutes = (discovered, middleware = [], onError = defaultErrorMapper, co
1359
1382
  try {
1360
1383
  return await chained(req);
1361
1384
  } catch (error) {
1362
- return onError(error, req);
1385
+ return RequestIds.stamp(onError(error, req), req);
1363
1386
  }
1364
1387
  };
1365
1388
  const byMethod = routes[route.path] ??= {};
@@ -1610,6 +1633,9 @@ class HttpFactory {
1610
1633
  assertNoCollisions(discovered);
1611
1634
  const gateways = discoverGateways(modules, (token) => app.get(token));
1612
1635
  const websocket = gateways.length > 0 ? buildWebSocket(gateways, options.websocket, HttpFactory.#socketMiddleware(app, root, options)) : undefined;
1636
+ for (const warning of websocket?.warnings ?? []) {
1637
+ app.get(Logger4).warn(warning);
1638
+ }
1613
1639
  return new HttpApplication(app, discovered, options, root, websocket);
1614
1640
  }
1615
1641
  static #socketMiddleware(app, root, options) {
@@ -2152,7 +2178,7 @@ Object.defineProperty(HealthOptions, Symbol.for("dunx.deps"), {
2152
2178
  class HealthRegistry {
2153
2179
  options;
2154
2180
  readiness_;
2155
- #startedAt = Date.now();
2181
+ #startedAt = performance.now();
2156
2182
  constructor(options, readiness_) {
2157
2183
  this.options = options;
2158
2184
  this.readiness_ = readiness_;
@@ -2172,7 +2198,7 @@ class HealthRegistry {
2172
2198
  return {
2173
2199
  status: worst(checks),
2174
2200
  draining: this.readiness_.draining,
2175
- uptimeMs: Date.now() - this.#startedAt,
2201
+ uptimeMs: Math.round(performance.now() - this.#startedAt),
2176
2202
  checks
2177
2203
  };
2178
2204
  }
@@ -2439,106 +2465,106 @@ __runInitializers(_init, 1, HealthModule);
2439
2465
  __decoratorMetadata(_init, HealthModule);
2440
2466
  let _HealthModule = HealthModule;
2441
2467
  export {
2442
- withUpgradeRoutes,
2443
- withCors,
2444
- toErrorMapper,
2445
- routesOf,
2446
- preflight,
2447
- observe,
2448
- normalizePrefix,
2449
- normalizePath,
2450
- metaOf,
2451
- metaKey,
2452
- meta,
2453
- mergeMeta,
2454
- joinPath,
2455
- isGateway,
2456
- isErrorFilter,
2457
- guardsOf,
2458
- gatewaysOf,
2459
- errorMapper,
2460
- encodeRelay,
2461
- encode,
2462
- discoverRoutes,
2463
- discoverGateways,
2464
- discoverGateway,
2465
- defaultRelayUrl,
2466
- defaultErrorMapper,
2467
- decodeRelay,
2468
- decode,
2469
- composeSocket,
2470
- compose,
2471
- buildWebSocket,
2472
- buildRuntime,
2473
- buildRoutes,
2474
- buildGateways,
2475
- buildContext,
2476
- assertNoGatewayCollisions,
2477
- assertNoCollisions,
2478
- ValidationError,
2479
- UseGuards,
2480
- UNMATCHED,
2481
- ThrottleStore,
2482
- ThrottleOptions,
2483
- ThrottleModule,
2484
- ThrottleGuard,
2485
- Throttle,
2486
- THROTTLE,
2487
- StaticOptions,
2488
- StaticModule,
2489
- StaticFiles,
2490
- SocketLoggingMiddleware,
2491
- SkipThrottle,
2492
- SKIP_THROTTLE,
2493
- Roles,
2494
- RequestLoggingMiddleware,
2495
- RedisThrottleStore,
2496
- RedisRelay,
2497
- RedisIndicator,
2498
- ReadinessOptions,
2499
- Readiness,
2500
- ROLES,
2501
- REQUEST_ID_HEADER,
2502
- QueryProbe,
2503
- Put,
2504
- Public,
2505
- PubSub,
2506
- Post,
2507
- PingProbe,
2508
- Patch,
2509
- PUBLIC,
2510
- OnUpgrade,
2511
- OnPong,
2512
- OnPing,
2513
- OnOpen,
2514
- OnMessage,
2515
- OnDrain,
2516
- OnClose,
2517
- MemoryThrottleStore,
2518
- MemoryOptions,
2519
- MemoryIndicator,
2520
- HttpStatusCode,
2521
- HttpFactory,
2522
- HttpError,
2523
- HealthRegistry,
2524
- HealthOptions,
2525
- HealthModule,
2526
- HealthIndicator,
2527
- HealthController,
2528
- HandlerKind,
2529
- HIDDEN,
2530
- Get,
2531
- Gateway,
2532
- ErrorFilter,
2533
- DiskOptions,
2534
- DiskIndicator,
2535
- Delete,
2536
- DatabaseIndicator,
2537
- DEFAULT_RELAY_CHANNEL,
2538
- Controller,
2468
+ ApiHidden,
2539
2469
  ClientAddress,
2540
- ApiHidden
2470
+ Controller,
2471
+ DEFAULT_RELAY_CHANNEL,
2472
+ DatabaseIndicator,
2473
+ Delete,
2474
+ DiskIndicator,
2475
+ DiskOptions,
2476
+ ErrorFilter,
2477
+ Gateway,
2478
+ Get,
2479
+ HIDDEN,
2480
+ HandlerKind,
2481
+ HealthController,
2482
+ HealthIndicator,
2483
+ HealthModule,
2484
+ HealthOptions,
2485
+ HealthRegistry,
2486
+ HttpError,
2487
+ HttpFactory,
2488
+ HttpStatusCode,
2489
+ MemoryIndicator,
2490
+ MemoryOptions,
2491
+ MemoryThrottleStore,
2492
+ OnClose,
2493
+ OnDrain,
2494
+ OnMessage,
2495
+ OnOpen,
2496
+ OnPing,
2497
+ OnPong,
2498
+ OnUpgrade,
2499
+ PUBLIC,
2500
+ Patch,
2501
+ PingProbe,
2502
+ Post,
2503
+ PubSub,
2504
+ Public,
2505
+ Put,
2506
+ QueryProbe,
2507
+ REQUEST_ID_HEADER,
2508
+ ROLES,
2509
+ Readiness,
2510
+ ReadinessOptions,
2511
+ RedisIndicator,
2512
+ RedisRelay,
2513
+ RedisThrottleStore,
2514
+ RequestLoggingMiddleware,
2515
+ Roles,
2516
+ SKIP_THROTTLE,
2517
+ SkipThrottle,
2518
+ SocketLoggingMiddleware,
2519
+ StaticFiles,
2520
+ StaticModule,
2521
+ StaticOptions,
2522
+ THROTTLE,
2523
+ Throttle,
2524
+ ThrottleGuard,
2525
+ ThrottleModule,
2526
+ ThrottleOptions,
2527
+ ThrottleStore,
2528
+ UNMATCHED,
2529
+ UseGuards,
2530
+ ValidationError,
2531
+ assertNoCollisions,
2532
+ assertNoGatewayCollisions,
2533
+ buildContext,
2534
+ buildGateways,
2535
+ buildRoutes,
2536
+ buildRuntime,
2537
+ buildWebSocket,
2538
+ compose,
2539
+ composeSocket,
2540
+ decode,
2541
+ decodeRelay,
2542
+ defaultErrorMapper,
2543
+ defaultRelayUrl,
2544
+ discoverGateway,
2545
+ discoverGateways,
2546
+ discoverRoutes,
2547
+ encode,
2548
+ encodeRelay,
2549
+ errorMapper,
2550
+ gatewaysOf,
2551
+ guardsOf,
2552
+ isErrorFilter,
2553
+ isGateway,
2554
+ joinPath,
2555
+ mergeMeta,
2556
+ meta,
2557
+ metaKey,
2558
+ metaOf,
2559
+ normalizePath,
2560
+ normalizePrefix,
2561
+ observe,
2562
+ preflight,
2563
+ routesOf,
2564
+ toErrorMapper,
2565
+ withCors,
2566
+ withUpgradeRoutes
2541
2567
  };
2542
2568
 
2543
- //# debugId=80302AC7A1BB24E664756E2164756E21
2569
+ //# debugId=30A653C61AAD581564756E2164756E21
2544
2570
  //# sourceMappingURL=index.js.map