@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.
@@ -41,13 +41,8 @@ export declare class HttpModule {
41
41
  */
42
42
  static forRoot(init?: HttpClientOptionsInit): DynamicModule;
43
43
  /**
44
- * `forRoot` with the options behind a factory, which is the one thing a
45
- * zero-argument `forRoot` cannot do: read the base url or the timeout off
46
- * `ConfigService`.
47
- *
48
- * There is no separate async machinery - the container resolves eagerly and
49
- * awaits factories before any constructor runs, so awaited config is settled by
50
- * the time anything is built.
44
+ * `forRoot` with the options behind a factory, so the base url or the timeout
45
+ * can come off `ConfigService`.
51
46
  *
52
47
  * ```ts
53
48
  * HttpModule.forRootAsync({
@@ -43,18 +43,12 @@ export interface RequestConfig<TRequest = unknown, TResponse = unknown> {
43
43
  type BaseOptions<TRequest, TResponse> = Omit<RequestConfig<TRequest, TResponse>, 'method' | 'url' | 'payload'>;
44
44
  /**
45
45
  * A `fetch` client with a per-request timeout, retry with backoff, request-id
46
- * propagation and one log line per call.
46
+ * propagation and one log line per call. `fetch` and nothing else, so there is no
47
+ * client dependency; what it adds is the parts every caller otherwise
48
+ * reimplements - the timeout, the retry policy, `Retry-After`, url building, and
49
+ * a failure that says which call failed.
47
50
  *
48
- * `fetch` and nothing else: it is a Web standard Bun implements natively, so there
49
- * is no client dependency to justify - which is also why `axios` and `node-fetch`
50
- * are banned repo-wide. What this adds over calling `fetch` yourself is the parts
51
- * every caller otherwise reimplements slightly differently: the timeout, the
52
- * retry policy, `Retry-After`, url building, and a failure that says which call
53
- * failed.
54
- *
55
- * Extends `UrlHelper` from `@arkv/shared`, so `buildUrl` and `interpolate` are
56
- * available on the service, and there is one implementation of them across the
57
- * owner's projects rather than a fork per repo.
51
+ * Extends `UrlHelper` from `@arkv/shared` for `buildUrl` and `interpolate`.
58
52
  */
59
53
  export declare class HttpService extends UrlHelper {
60
54
  private readonly options;
@@ -83,18 +77,13 @@ export declare class HttpService extends UrlHelper {
83
77
  readonly method?: 'GET' | 'POST';
84
78
  }): AsyncGenerator<string>;
85
79
  /**
86
- * Resolves the target, accepting the three forms a caller actually reaches for:
87
- * an absolute url, a path relative to `baseUrl`, or `baseUrl` plus an explicit
88
- * `path`.
89
- *
90
- * `get('/users')` is the one worth calling out. A relative first argument is what
91
- * every HTTP client takes once a base url exists, and passing it straight to
92
- * `buildUrl` throws `ERR_INVALID_URL` from inside `new URL()` - a message naming
93
- * neither the call nor the missing base. So a first argument that is not an
94
- * absolute url is treated as the path, which is what it reads as.
80
+ * Resolves the target: an absolute url, a path relative to `baseUrl`, or
81
+ * `baseUrl` plus an explicit `path`.
95
82
  *
96
- * `URL.canParse` decides, rather than a regex over `//` or `:` - it is the same
97
- * parser `new URL` uses, so the two cannot disagree.
83
+ * A relative first argument reaching `buildUrl` throws `ERR_INVALID_URL` from
84
+ * inside `new URL()`, naming neither the call nor the missing base, so one that
85
+ * is not absolute is treated as the path. `URL.canParse` decides rather than a
86
+ * regex, so it cannot disagree with `new URL`.
98
87
  */
99
88
  private urlFor;
100
89
  /** `serialised` is what a `headerFactory` signs, and is `''` for no body. */
package/dist/client.d.ts CHANGED
@@ -6,8 +6,14 @@
6
6
  * `@dunx/http` does not load any of this.
7
7
  */
8
8
  export { FetchError, FetchTransportError } from './client/errors.js';
9
- export { isJsonBody, isPlainObject, safeStringify } from './client/json.js';
10
9
  export { DEFAULT_REQUEST_ID_HEADER, HttpClientOptions, type HttpClientOptionsInit, } from './client/options.js';
11
- export { backoffDelay, executeWithRetry, isRetryableStatus, retryAfterMs, type BackoffOptions, type RetryOptions, } from './client/retry.js';
10
+ export type { BackoffOptions, RetryOptions } from './client/retry.js';
12
11
  export { httpClient, HttpModule } from './client/module.js';
13
12
  export { HttpService, type HeaderFactory, type RequestConfig, type RequestMethod, } from './client/service.js';
13
+ /**
14
+ * The client's own plumbing, still reachable here and moving out in 4.0.
15
+ * Import it from `@dunx/http/internal`, which carries no stability promise.
16
+ *
17
+ * @deprecated Import from `@dunx/http/internal`. Removed in 4.0.
18
+ */
19
+ export { backoffDelay, executeWithRetry, isJsonBody, isPlainObject, isRetryableStatus, retryAfterMs, safeStringify, } from './internal.js';
package/dist/client.js CHANGED
@@ -1,73 +1,19 @@
1
1
  // @bun
2
2
  import {
3
- HttpStatusCode,
4
3
  TRACEPARENT_HEADER,
5
4
  TraceContext
6
- } from "./chunk-jh7jk0bn.js";
7
-
8
- // src/client/errors.ts
9
- import { AppError } from "@dunx/core";
10
-
11
- class FetchError extends AppError {
12
- status;
13
- statusText;
14
- body;
15
- response;
16
- name = "FetchError";
17
- constructor(status, statusText, body, response) {
18
- super(`HTTP ${status} ${statusText} from ${response.method} ${response.url}`);
19
- this.status = status;
20
- this.statusText = statusText;
21
- this.body = body;
22
- this.response = response;
23
- }
24
- }
25
- Object.defineProperty(FetchError, Symbol.for("dunx.deps"), {
26
- value: () => [{ unresolved: "readonly status: number" }, { unresolved: "readonly statusText: string" }, { unresolved: "readonly body: unknown" }, { unresolved: `readonly response: {
27
- readonly method: string;
28
- readonly url: string;
29
- readonly headers: Headers;
30
- }` }]
31
- });
32
-
33
- class FetchTransportError extends AppError {
34
- response;
35
- aborted;
36
- name = "FetchTransportError";
37
- constructor(response, aborted, options) {
38
- super(`${response.method} ${response.url} failed: ${aborted ? "aborted" : "transport error"}`, options);
39
- this.response = response;
40
- this.aborted = aborted;
41
- }
42
- }
43
- Object.defineProperty(FetchTransportError, Symbol.for("dunx.deps"), {
44
- value: () => [{ unresolved: "readonly response: { readonly method: string; readonly url: string }" }, { unresolved: "readonly aborted: boolean" }, ErrorOptions]
45
- });
46
- // src/client/json.ts
47
- var safeStringify = (value) => {
48
- const seen = new WeakSet;
49
- return JSON.stringify(value, (_key, entry) => {
50
- if (typeof entry === "object" && entry !== null) {
51
- if (seen.has(entry))
52
- return "[Circular]";
53
- seen.add(entry);
54
- }
55
- return entry;
56
- });
57
- };
58
- var isPlainObject = (value) => {
59
- if (typeof value !== "object" || value === null)
60
- return false;
61
- const proto = Object.getPrototypeOf(value);
62
- return proto === Object.prototype || proto === null;
63
- };
64
- var isJsonBody = (payload) => {
65
- if (payload === null || payload === undefined)
66
- return false;
67
- if (typeof payload !== "object")
68
- return typeof payload !== "string";
69
- return !(payload instanceof FormData || payload instanceof URLSearchParams || payload instanceof Blob || payload instanceof ArrayBuffer || payload instanceof ReadableStream || ArrayBuffer.isView(payload));
70
- };
5
+ } from "./chunk-25g22350.js";
6
+ import {
7
+ FetchError,
8
+ FetchTransportError,
9
+ backoffDelay,
10
+ executeWithRetry,
11
+ isJsonBody,
12
+ isPlainObject,
13
+ isRetryableStatus,
14
+ retryAfterMs,
15
+ safeStringify
16
+ } from "./chunk-ywdpxbkf.js";
71
17
  // src/client/options.ts
72
18
  var DEFAULT_REQUEST_ID_HEADER = "x-request-id";
73
19
 
@@ -98,71 +44,7 @@ class HttpClientOptions {
98
44
  ].filter(([, value]) => value !== undefined));
99
45
  }
100
46
  }
101
- Object.defineProperty(HttpClientOptions, Symbol.for("dunx.deps"), {
102
- value: () => [{ unresolved: "init: HttpClientOptionsInit = {}" }]
103
- });
104
- // src/client/retry.ts
105
- var uniform = () => {
106
- const buffer = new Uint32Array(1);
107
- crypto.getRandomValues(buffer);
108
- return (buffer[0] ?? 0) / 2 ** 32;
109
- };
110
- var backoffDelay = (attempt, { baseMs, power = 2, jitterMs = 1000, maxMs = 30000 }) => Math.min(baseMs * power ** attempt + uniform() * jitterMs, maxMs);
111
- var retryAfterMs = (headers, now = Date.now()) => {
112
- const header = headers.get("retry-after");
113
- if (header === null)
114
- return;
115
- const seconds = Number(header);
116
- if (Number.isFinite(seconds))
117
- return Math.max(0, seconds * 1000);
118
- const at = Date.parse(header);
119
- return Number.isNaN(at) ? undefined : Math.max(0, at - now);
120
- };
121
- var isRetryableStatus = (status) => status >= HttpStatusCode.INTERNAL_SERVER_ERROR || status === HttpStatusCode.REQUEST_TIMEOUT || status === HttpStatusCode.TOO_MANY_REQUESTS;
122
- var decide = (error, attempt, options) => {
123
- const {
124
- retryDelayMs = 1000,
125
- backoff,
126
- shouldRetryOnStatus = isRetryableStatus,
127
- respectRetryAfter = true
128
- } = options;
129
- const computed = backoffDelay(attempt, { baseMs: retryDelayMs, ...backoff });
130
- if (error instanceof FetchTransportError) {
131
- return { retry: !error.aborted, delayMs: computed };
132
- }
133
- if (error instanceof FetchError) {
134
- if (!shouldRetryOnStatus(error.status))
135
- return { retry: false, delayMs: 0 };
136
- const asked = respectRetryAfter ? retryAfterMs(error.response.headers) : undefined;
137
- const maxMs = backoff?.maxMs ?? 30000;
138
- return {
139
- retry: true,
140
- delayMs: asked === undefined ? computed : Math.min(asked, maxMs)
141
- };
142
- }
143
- return { retry: true, delayMs: computed };
144
- };
145
- var executeWithRetry = async (operation, options = {}) => {
146
- const { maxRetries = 3, onAttempt, onError, onSuccess } = options;
147
- let lastError;
148
- for (let attempt = 0;attempt <= maxRetries; attempt += 1) {
149
- onAttempt?.(attempt + 1, attempt > 0);
150
- try {
151
- const result = await operation();
152
- onSuccess?.(result, attempt + 1);
153
- return result;
154
- } catch (error) {
155
- lastError = error;
156
- const { retry, delayMs } = decide(error, attempt, options);
157
- const willRetry = retry && attempt < maxRetries;
158
- onError?.(error, attempt + 1, willRetry);
159
- if (!willRetry)
160
- throw error;
161
- await Bun.sleep(delayMs);
162
- }
163
- }
164
- throw lastError;
165
- };
47
+ Object.defineProperty(HttpClientOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: HttpClientOptionsInit = {}", optional: true }] });
166
48
  // src/client/module.ts
167
49
  import {
168
50
  Logger as Logger2,
@@ -372,9 +254,7 @@ class HttpService extends UrlHelper {
372
254
  }
373
255
  }
374
256
  }
375
- Object.defineProperty(HttpService, Symbol.for("dunx.deps"), {
376
- value: () => [HttpClientOptions, Logger, RequestContext]
377
- });
257
+ Object.defineProperty(HttpService, Symbol.for("dunx.deps"), { value: () => [HttpClientOptions, Logger, RequestContext] });
378
258
  var urlOf = (url) => url === undefined ? {} : { url };
379
259
  var readBody = async (response) => {
380
260
  const text = await response.text().catch(() => "");
@@ -3,25 +3,20 @@ import type { RouteContext } from '../server/context.js';
3
3
  import type { Middleware, Next } from '../server/middleware.js';
4
4
  import { CompressionOptions } from './options.js';
5
5
  /**
6
- * Response compression, on Bun's own compressors.
7
- *
8
- * **Not installed by default, and registered by the app rather than by a module:**
6
+ * Response compression, on Bun's own compressors. Not installed by default, and
7
+ * registered by the app rather than a module:
9
8
  *
10
9
  * ```ts
11
10
  * const app = await HttpFactory.create(AppModule, { imports: [CompressionModule.forRoot()] });
12
11
  * app.use(Compression);
13
12
  * ```
14
13
  *
15
- * An app that never registers it pays nothing - there is no branch in the request
16
- * path to skip. Position is the app's decision for the same reason `StaticFiles`
17
- * leaves it open: compression belongs inside request logging, so the logged status
18
- * is the real one, and outside anything that wants to read the body it produced.
14
+ * An app that never registers it pays nothing. Position is the app's: compression
15
+ * belongs inside request logging and outside anything reading the body it made.
19
16
  *
20
- * Two encoders rather than one. A body whose `content-length` is known and under
21
- * `BUFFER_LIMIT` goes through `Bun.zstdCompressSync`/`gzipSync`, which is faster
22
- * than the stream and leaves an accurate `content-length` on the response; a
23
- * streamed or oversized body goes through `CompressionStream` and loses the header,
24
- * as it must.
17
+ * Two encoders. A known length under `BUFFER_LIMIT` goes through the sync
18
+ * compressors, which keep an accurate `content-length`; anything larger or
19
+ * streamed goes through `CompressionStream` and loses the header.
25
20
  */
26
21
  export declare class Compression implements Middleware {
27
22
  #private;
@@ -1,23 +1,14 @@
1
1
  /**
2
2
  * The content codings this package produces.
3
3
  *
4
- * **Brotli is absent, and that is a measurement rather than an oversight.** Bun
5
- * implements it - `new CompressionStream('brotli')` works - but at 6,344 us to
6
- * encode a 6.4 KB JSON body against gzip's 23 us and zstd's 24 us, roughly 275x.
7
- * The `level` argument that would fix it is accepted and ignored: `{ level: 4 }`
8
- * encodes in 6,345 us and produces the same 339 bytes as the default. Brotli
9
- * belongs on a build artefact compressed once, not on a response encoded per
10
- * request. Note also that the `CompressionStream` format is spelled `brotli`
11
- * while the HTTP token is `br`, so the two never lined up anyway.
4
+ * Brotli is absent on measurement: 6,344 us to encode a 6.4 KB JSON body against
5
+ * gzip's 23 us, and the `level` argument that would fix it is accepted and
6
+ * ignored. It belongs on a build artefact, not a per-request response.
12
7
  *
13
- * **`deflate` is absent for a second and worse reason: Bun's two encoders disagree
14
- * about what it means.** `Bun.deflateSync` emits raw DEFLATE (first bytes
15
- * `cb 48`), while `CompressionStream('deflate')` emits zlib (`78 9c`), which is
16
- * what `Content-Encoding: deflate` is defined as. No option reconciles them -
17
- * `library`, `windowBits` and `level` all leave `deflateSync` raw - so offering
18
- * the coding would flip wire format at the buffering threshold and serve bytes a
19
- * strict client rejects. `gzip` is taken by everything that would have accepted
20
- * `deflate`. Measured on Bun 1.4.0; see docs/bun-apis.md.
8
+ * `deflate` is absent because Bun's two encoders disagree: `Bun.deflateSync` emits
9
+ * raw DEFLATE while `CompressionStream('deflate')` emits zlib, which is what the
10
+ * header is defined as. Nothing reconciles them, so offering it would flip wire
11
+ * format at the buffering threshold. Measured on Bun 1.4.0; see docs/bun-apis.md.
21
12
  */
22
13
  export declare const CompressionEncoding: Readonly<{
23
14
  readonly ZSTD: 'zstd';
@@ -36,14 +27,11 @@ export declare const isCompressibleType: (contentType: string | null) => boolean
36
27
  export interface CompressionOptionsInit {
37
28
  /**
38
29
  * The codings offered, most preferred first. A tie in the client's q-values is
39
- * broken by this order, so it is a real preference and not just a filter.
30
+ * broken by this order.
40
31
  *
41
- * The default puts `zstd` first for speed. On a 6.4 KB JSON body zstd encodes to
42
- * 372 bytes in 7.7 us where gzip takes 16.1 us to reach 576; on a 116 KB OpenAPI
43
- * document the two land within 0.2% of each other (9,603 against 9,587), so the
44
- * size advantage narrows with the body while the time one does not. A client
45
- * that does not send `zstd` in `accept-encoding` gets gzip, so the order costs
46
- * nothing to state.
32
+ * `zstd` leads for speed: 7.7 us to 372 bytes on a 6.4 KB JSON body where gzip
33
+ * takes 16.1 us to reach 576. On a 116 KB document the sizes land within 0.2%,
34
+ * so the size advantage narrows with the body while the time one does not.
47
35
  *
48
36
  * @default ['zstd', 'gzip']
49
37
  */
@@ -22,17 +22,12 @@ export declare class MemoryOptions {
22
22
  constructor(init: MemoryOptionsInit);
23
23
  }
24
24
  /**
25
- * Resident set size against a ceiling.
25
+ * Resident set size against a ceiling. `process.memoryUsage()` costs 5.96 us,
26
+ * which is what makes it safe on an endpoint scraped every two seconds;
27
+ * `jsc.heapStats()` is 2.2 ms and up and `v8.getHeapStatistics()` 1 to 7.6 ms.
26
28
  *
27
- * `process.memoryUsage()` costs 5.96 us, which is what makes it safe on an endpoint
28
- * scraped every two seconds. The alternatives were measured and rejected:
29
- * `jsc.heapStats()` walks every live object at 2.2 ms and up,
30
- * `v8.getHeapStatistics()` is 1 to 7.6 ms, and `Bun.generateHeapSnapshot()` is
31
- * hundreds of milliseconds and megabytes. None belongs on this path.
32
- *
33
- * Not critical: a process near its ceiling is worth seeing, and shedding traffic
34
- * from it does not make it use less memory. Liveness is where a ceiling belongs, so
35
- * the orchestrator restarts it.
29
+ * Not critical: shedding traffic from a process near its ceiling does not make it
30
+ * use less memory. A ceiling belongs on liveness, where it restarts.
36
31
  */
37
32
  export declare class MemoryIndicator extends HealthIndicator {
38
33
  private readonly options;
package/dist/index.d.ts CHANGED
@@ -1,49 +1,48 @@
1
1
  export { Controller, Delete, Get, Patch, Post, Put, } from './route/decorators.js';
2
- export { discoverRoutes, joinPath, type DiscoveredRoute, } from './route/discover.js';
3
- export { defaultStatusFor, type DefaultStatus, type HttpMethod, type RouteMeta, type RoutePath, } from './route/marker.js';
4
- export { ApiHidden, guardsOf, HIDDEN, meta, metaKey, metaOf, mergeMeta, Public, PUBLIC, Roles, ROLES, UNMATCHED, UseGuards, type MetaKey, type MetaRecord, } from './route/metadata.js';
2
+ export type { HttpMethod, RoutePath } from './route/marker.js';
3
+ export { ApiHidden, HIDDEN, meta, metaKey, metaOf, mergeMeta, Public, PUBLIC, Roles, ROLES, UNMATCHED, UseGuards, type MetaKey, type MetaRecord, } from './route/metadata.js';
5
4
  export type { InferOutput, Input, JsonSchema, ResponseMap, Returns, RouteInput, RouteSchemas, StandardSchemaIssue, StandardSchemaResult, StandardSchemaV1, } from './route/schema.js';
6
- export { gatewaysOf, routesOf, type GatewayHandler, type GatewayNode, type RouteInputs, type RouteNode, } from './inspect.js';
7
5
  export { ClientAddress } from './server/client-address.js';
8
- export { buildContext, type RouteContext } from './server/context.js';
9
- export { preflight, withCors, type CorsOptions, type CorsOrigin, } from './server/cors.js';
10
- export { defaultErrorMapper, ErrorFilter, errorMapper, HttpError, isErrorFilter, toErrorMapper, ValidationError, type ErrorHandler, type ErrorMapper, type HttpErrorOptions, type InputSource, type ValidationIssue, } from './server/errors.js';
6
+ export type { RouteContext } from './server/context.js';
7
+ export type { CorsOptions, CorsOrigin } from './server/cors.js';
8
+ export { defaultErrorMapper, ErrorFilter, errorMapper, HttpError, ValidationError, type ErrorHandler, type ErrorMapper, type HttpErrorOptions, type InputSource, type ValidationIssue, } from './server/errors.js';
11
9
  export { HttpFactory, type HttpApp, type HttpOptions, } from './server/factory.js';
12
10
  export { REQUEST_ID_HEADER } from './server/request-id.js';
13
11
  export { TRACEPARENT_HEADER, TRACESTATE_HEADER, TraceContext, type Trace, } from './server/trace-context.js';
14
12
  export { RequestLoggingMiddleware, type RequestLoggingOptions, } from './server/request-logging.js';
15
- export { compose, type Middleware, type Next, type RouteHandler, } from './server/middleware.js';
16
- export { assertNoCollisions, assertNoGatewayCollisions, buildRoutes, withUpgradeRoutes, type BunRoutes, type GuardResolver, type RouteMethod, type ServeRoutes, } from './server/routes.js';
13
+ export type { Middleware, Next, RouteHandler } from './server/middleware.js';
17
14
  export type { AppSettings } from './server/settings.js';
18
15
  export { StaticFiles } from './static/files.js';
19
16
  export { StaticModule } from './static/module.js';
20
- export { normalizePrefix, StaticOptions, type StaticOptionsInit, } from './static/options.js';
17
+ export { StaticOptions, type StaticOptionsInit } from './static/options.js';
21
18
  export { Compression } from './compression/compression.js';
22
19
  export { CompressionModule } from './compression/module.js';
23
- export { negotiate } from './compression/negotiate.js';
24
- export { CompressionEncoding, CompressionOptions, isCompressibleType, type CompressionOptionsInit, } from './compression/options.js';
20
+ export { CompressionEncoding, CompressionOptions, type CompressionOptionsInit, } from './compression/options.js';
25
21
  export { SKIP_THROTTLE, SkipThrottle, THROTTLE, Throttle, type ThrottleLimit, } from './throttle/decorators.js';
26
22
  export { ThrottleGuard } from './throttle/guard.js';
27
23
  export { ThrottleModule } from './throttle/module.js';
28
24
  export { ThrottleOptions, type ThrottleOptionsInit, } from './throttle/options.js';
29
25
  export { MemoryThrottleStore, RedisThrottleStore, ThrottleStore, type ThrottleRedis, } from './throttle/store.js';
30
26
  export { HttpStatusCode, type HttpStatusName } from './server/status.js';
31
- export { buildWebSocket, type UpgradeHandler, type WebSocketRuntime, } from './ws/adapter.js';
32
27
  export { Gateway, OnClose, OnDrain, OnMessage, OnOpen, OnPing, OnPong, OnUpgrade, } from './ws/decorators.js';
33
- export { discoverGateway, discoverGateways, normalizePath, type DiscoveredGateway, type DiscoveredHandler, type Invoke, } from './ws/discover.js';
34
- export { decode, encode, type Envelope } from './ws/envelope.js';
35
- export { composeSocket, observe, type SocketContext, type SocketDispatch, type SocketFrame, type SocketMiddleware, type SocketNext, } from './ws/middleware.js';
28
+ export type { Envelope } from './ws/envelope.js';
29
+ export type { SocketContext, SocketDispatch, SocketFrame, SocketMiddleware, SocketNext, } from './ws/middleware.js';
36
30
  export { SocketLoggingMiddleware, type SocketLoggingOptions, } from './ws/logging.js';
37
- export { HandlerKind, isGateway, type HandlerMeta } from './ws/marker.js';
38
31
  export { PubSub } from './ws/pubsub.js';
39
- export { defaultRelayUrl, RedisRelay, type RedisRelayOptions, } from './ws/redis-relay.js';
40
- export { decodeRelay, DEFAULT_RELAY_CHANNEL, encodeRelay, type PubSubRelay, type RelayFrame, type RelayOptions, type RelayPhase, } from './ws/relay.js';
41
- export { buildGateways, buildRuntime, type GatewayRuntime, } from './ws/runtime.js';
32
+ export { RedisRelay, type RedisRelayOptions } from './ws/redis-relay.js';
33
+ export { DEFAULT_RELAY_CHANNEL, type PubSubRelay, type RelayOptions, } from './ws/relay.js';
42
34
  export type { Socket, SocketData, SocketErrorHandler, SocketOptions, } from './ws/socket.js';
43
35
  export { HealthIndicator, PingProbe, QueryProbe, type ProbeResult, type ProbeState, } from './health/contracts.js';
44
- export { HealthController, HiddenHealthController, } from './health/controller.js';
36
+ export { HealthController } from './health/controller.js';
45
37
  export { DatabaseIndicator, DiskIndicator, DiskOptions, MemoryIndicator, MemoryOptions, RedisIndicator, type DiskOptionsInit, type MemoryOptionsInit, } from './health/indicators.js';
46
38
  export { HealthModule } from './health/module.js';
47
39
  export { HEALTH_REPORT_SCHEMA } from './health/report-schema.js';
48
40
  export { Readiness, ReadinessOptions } from './health/readiness.js';
49
41
  export { HealthOptions, HealthRegistry, type HealthCheckReport, type HealthOptionsInit, type HealthReport, } from './health/registry.js';
42
+ /**
43
+ * The framework's own plumbing, still reachable here and moving out in 4.0.
44
+ * Import it from `@dunx/http/internal`, which carries no stability promise.
45
+ *
46
+ * @deprecated Import from `@dunx/http/internal`. Removed in 4.0.
47
+ */
48
+ export { assertNoCollisions, assertNoGatewayCollisions, buildContext, buildGateways, buildRoutes, buildRuntime, buildWebSocket, compose, composeSocket, decode, decodeRelay, defaultRelayUrl, defaultStatusFor, discoverGateway, discoverGateways, discoverRoutes, encode, encodeRelay, gatewaysOf, guardsOf, HandlerKind, HiddenHealthController, isCompressibleType, isErrorFilter, isGateway, joinPath, negotiate, normalizePath, normalizePrefix, observe, preflight, routesOf, toErrorMapper, withCors, withUpgradeRoutes, type BunRoutes, type DefaultStatus, type DiscoveredGateway, type DiscoveredHandler, type DiscoveredRoute, type GatewayHandler, type GatewayNode, type GatewayRuntime, type GuardResolver, type HandlerMeta, type Invoke, type RelayFrame, type RelayPhase, type RouteInputs, type RouteMeta, type RouteMethod, type RouteNode, type ServeRoutes, type UpgradeHandler, type WebSocketRuntime, } from './internal.js';