@dunx/http 3.3.2 → 3.4.1
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/{chunk-8939brh2.js → chunk-p9hdmkm6.js} +15 -1
- package/dist/index.js +24 -8
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +3 -1
- package/dist/route/prefix.d.ts +16 -0
- package/dist/server/application.d.ts +1 -1
- package/dist/server/options-provider.d.ts +5 -0
- package/dist/server/options.d.ts +11 -0
- package/dist/server/routes.d.ts +16 -0
- package/package.json +2 -2
|
@@ -89,6 +89,20 @@ var discoverRoutes2 = (instance) => {
|
|
|
89
89
|
}));
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
+
// src/route/prefix.ts
|
|
93
|
+
class RoutePrefix2 {
|
|
94
|
+
#value = "";
|
|
95
|
+
get value() {
|
|
96
|
+
return this.#value;
|
|
97
|
+
}
|
|
98
|
+
attach(prefix) {
|
|
99
|
+
this.#value = prefix;
|
|
100
|
+
}
|
|
101
|
+
apply(path) {
|
|
102
|
+
return this.#value === "" ? path : joinPath2(this.#value, path);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
92
106
|
// src/ws/marker.ts
|
|
93
107
|
var HANDLER = Symbol.for("dunx.ws.handler");
|
|
94
108
|
var GATEWAY = Symbol.for("dunx.ws.gateway");
|
|
@@ -171,4 +185,4 @@ var discoverGateways = (modules, resolve) => {
|
|
|
171
185
|
return discovered;
|
|
172
186
|
};
|
|
173
187
|
|
|
174
|
-
export { defaultStatusFor2, markRoute, markController, metaKey2, meta2, ROLES2, PUBLIC2, HIDDEN2, UNMATCHED2, Roles2, Public2, ApiHidden2, UseGuards2, metaOf2, mergeMeta2, joinPath2, discoverRoutes2, HandlerKind, markHandler, markGateway, isGateway2, discoverGateway, discoverGateways, buildContext2 };
|
|
188
|
+
export { defaultStatusFor2, markRoute, markController, metaKey2, meta2, ROLES2, PUBLIC2, HIDDEN2, UNMATCHED2, Roles2, Public2, ApiHidden2, UseGuards2, metaOf2, mergeMeta2, joinPath2, discoverRoutes2, RoutePrefix2, HandlerKind, markHandler, markGateway, isGateway2, discoverGateway, discoverGateways, buildContext2 };
|
package/dist/index.js
CHANGED
|
@@ -18,14 +18,14 @@ import {
|
|
|
18
18
|
UseGuards2,
|
|
19
19
|
metaOf2,
|
|
20
20
|
mergeMeta2,
|
|
21
|
-
joinPath2,
|
|
22
21
|
discoverRoutes2,
|
|
22
|
+
RoutePrefix2,
|
|
23
23
|
HandlerKind,
|
|
24
24
|
markHandler,
|
|
25
25
|
markGateway,
|
|
26
26
|
discoverGateways,
|
|
27
27
|
buildContext2
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-p9hdmkm6.js";
|
|
29
29
|
import {
|
|
30
30
|
TRACEPARENT_HEADER2,
|
|
31
31
|
TRACESTATE_HEADER2,
|
|
@@ -1468,6 +1468,15 @@ var buildRoutes = (discovered, middleware = [], onError = defaultErrorMapper, co
|
|
|
1468
1468
|
}
|
|
1469
1469
|
return routes;
|
|
1470
1470
|
};
|
|
1471
|
+
var withTrailingSlashAliases = (routes) => {
|
|
1472
|
+
const aliased = { ...routes };
|
|
1473
|
+
for (const [path, byMethod] of Object.entries(routes)) {
|
|
1474
|
+
if (path.endsWith("/") || path.includes("*"))
|
|
1475
|
+
continue;
|
|
1476
|
+
aliased[`${path}/`] ??= byMethod;
|
|
1477
|
+
}
|
|
1478
|
+
return aliased;
|
|
1479
|
+
};
|
|
1471
1480
|
|
|
1472
1481
|
// src/server/binding.ts
|
|
1473
1482
|
class ServerBinding {
|
|
@@ -1557,6 +1566,7 @@ class HttpApplication extends ShutdownAware {
|
|
|
1557
1566
|
#relayChannel;
|
|
1558
1567
|
#relayResubscribe;
|
|
1559
1568
|
#notFound;
|
|
1569
|
+
#strict;
|
|
1560
1570
|
#bootLogging;
|
|
1561
1571
|
#binding;
|
|
1562
1572
|
#split;
|
|
@@ -1583,6 +1593,7 @@ class HttpApplication extends ShutdownAware {
|
|
|
1583
1593
|
this.#relayChannel = options.relayChannel;
|
|
1584
1594
|
this.#relayResubscribe = options.relayResubscribe;
|
|
1585
1595
|
this.#notFound = options.notFound ?? "public";
|
|
1596
|
+
this.#strict = options.strict ?? true;
|
|
1586
1597
|
this.#bootLogging = options.bootLogging ?? true;
|
|
1587
1598
|
this.#binding = new ServerBinding({
|
|
1588
1599
|
http2: options.http2,
|
|
@@ -1645,8 +1656,11 @@ class HttpApplication extends ShutdownAware {
|
|
|
1645
1656
|
this.#assertNotStarted("listen()");
|
|
1646
1657
|
this.#started = true;
|
|
1647
1658
|
const middleware = this.#middleware.map((entry) => this.#app.get(entry, this.#root));
|
|
1648
|
-
const
|
|
1649
|
-
|
|
1659
|
+
const prefix = this.#app.get(RoutePrefix2);
|
|
1660
|
+
prefix.attach(this.#globalPrefix);
|
|
1661
|
+
const prefixed = this.#prefixed(prefix);
|
|
1662
|
+
const built = buildRoutes(prefixed, middleware, this.#onError, this.#cors, (guard, from) => from === undefined ? this.#app.get(guard) : this.#app.get(guard, from));
|
|
1663
|
+
const routes = this.#strict ? built : withTrailingSlashAliases(built);
|
|
1650
1664
|
const ws = this.#websocket;
|
|
1651
1665
|
if (ws && !this.#split)
|
|
1652
1666
|
assertNoGatewayCollisions(prefixed, ws.paths);
|
|
@@ -1726,12 +1740,12 @@ class HttpApplication extends ShutdownAware {
|
|
|
1726
1740
|
})();
|
|
1727
1741
|
return this.#shuttingDown;
|
|
1728
1742
|
}
|
|
1729
|
-
#prefixed() {
|
|
1730
|
-
if (
|
|
1743
|
+
#prefixed(prefix) {
|
|
1744
|
+
if (prefix.value === "")
|
|
1731
1745
|
return this.#discovered;
|
|
1732
1746
|
return this.#discovered.map((route) => ({
|
|
1733
1747
|
...route,
|
|
1734
|
-
path:
|
|
1748
|
+
path: prefix.apply(route.path)
|
|
1735
1749
|
}));
|
|
1736
1750
|
}
|
|
1737
1751
|
#assertNotStarted(hook) {
|
|
@@ -1749,6 +1763,7 @@ class HttpOptionsProvider {
|
|
|
1749
1763
|
notFound = "public";
|
|
1750
1764
|
bootLogging = true;
|
|
1751
1765
|
trustProxy = false;
|
|
1766
|
+
strict = true;
|
|
1752
1767
|
shutdownHooks = false;
|
|
1753
1768
|
relayChannel = "dunx:ws";
|
|
1754
1769
|
get prefix() {
|
|
@@ -1801,6 +1816,7 @@ function resolveHttpOptions(settings, given) {
|
|
|
1801
1816
|
notFound: settings.notFound,
|
|
1802
1817
|
bootLogging: settings.bootLogging,
|
|
1803
1818
|
trustProxy: settings.trustProxy,
|
|
1819
|
+
strict: settings.strict,
|
|
1804
1820
|
shutdownHooks: settings.shutdownHooks,
|
|
1805
1821
|
relayChannel: settings.relayChannel,
|
|
1806
1822
|
prefix: settings.prefix,
|
|
@@ -1850,7 +1866,7 @@ class HttpFactory {
|
|
|
1850
1866
|
useFactory: (logger, context, settings) => new SocketLoggingMiddleware(logger, context, pick(options.socketLogging, settings.socketLogging)),
|
|
1851
1867
|
inject: [Logger4, RequestContext3, HttpOptionsProvider]
|
|
1852
1868
|
});
|
|
1853
|
-
const services = [PubSub, ClientAddress, RequestMetrics];
|
|
1869
|
+
const services = [PubSub, ClientAddress, RequestMetrics, RoutePrefix2];
|
|
1854
1870
|
const providers = [...services, logging, metricsMiddleware, socketLogging];
|
|
1855
1871
|
const scope = {
|
|
1856
1872
|
module: HttpModule,
|
package/dist/internal.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* No stability promise attaches to this subpath.
|
|
13
13
|
*/
|
|
14
14
|
export { discoverRoutes, joinPath, type DiscoveredRoute, } from './route/discover.js';
|
|
15
|
+
export { RoutePrefix } from './route/prefix.js';
|
|
15
16
|
export { defaultStatusFor } from './route/marker.js';
|
|
16
17
|
export { gatewaysOf, routesOf, type GatewayHandler, type GatewayNode, type RouteInputs, type RouteNode, } from './inspect.js';
|
|
17
18
|
export { buildContext } from './server/context.js';
|
package/dist/internal.js
CHANGED
|
@@ -7,10 +7,11 @@ import {
|
|
|
7
7
|
HIDDEN2,
|
|
8
8
|
joinPath2,
|
|
9
9
|
discoverRoutes2,
|
|
10
|
+
RoutePrefix2,
|
|
10
11
|
isGateway2,
|
|
11
12
|
discoverGateway,
|
|
12
13
|
buildContext2
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-p9hdmkm6.js";
|
|
14
15
|
// src/inspect.ts
|
|
15
16
|
import {
|
|
16
17
|
classOf,
|
|
@@ -71,6 +72,7 @@ var gatewaysOf = (root) => collectModules(root).flatMap((module) => (module.opti
|
|
|
71
72
|
// src/server/html.ts
|
|
72
73
|
var embedJson = (value) => JSON.stringify(value).replaceAll("<", "\\u003c");
|
|
73
74
|
export {
|
|
75
|
+
RoutePrefix2 as RoutePrefix,
|
|
74
76
|
buildContext2 as buildContext,
|
|
75
77
|
defaultStatusFor2 as defaultStatusFor,
|
|
76
78
|
discoverRoutes2 as discoverRoutes,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The global prefix, as `listen()` resolved it.
|
|
3
|
+
*
|
|
4
|
+
* Bound by `HttpFactory`'s global wrapper next to `ClientAddress`, and attached
|
|
5
|
+
* the same way: a second instance reads an empty prefix, which is a plausible
|
|
6
|
+
* answer and a wrong one. Routes only, never gateways.
|
|
7
|
+
* See docs/architecture/http.md, "Who knows the global prefix".
|
|
8
|
+
*/
|
|
9
|
+
export declare class RoutePrefix {
|
|
10
|
+
#private;
|
|
11
|
+
/** Empty when the app set none. */
|
|
12
|
+
get value(): string;
|
|
13
|
+
attach(prefix: string): void;
|
|
14
|
+
/** Where a discovered route is served. The one place that answers it. */
|
|
15
|
+
apply(path: string): string;
|
|
16
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BunRequest } from 'bun';
|
|
2
2
|
import { ShutdownAware, type App, type Ctor, type InjectionToken, type ModuleRef } from '@dunx/core';
|
|
3
|
-
import {
|
|
3
|
+
import type { DiscoveredRoute } from '../route/discover.js';
|
|
4
4
|
import type { WebSocketRuntime } from '../ws/adapter.js';
|
|
5
5
|
import type { CorsOptions } from './cors.js';
|
|
6
6
|
import type { Middleware } from './middleware.js';
|
|
@@ -54,6 +54,11 @@ export declare abstract class HttpOptionsProvider {
|
|
|
54
54
|
* nothing lets any caller choose its own address.
|
|
55
55
|
*/
|
|
56
56
|
readonly trustProxy: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Match a path exactly as declared, so `/users/1/` is not `/users/1`. On by
|
|
59
|
+
* default, which is `Bun.serve`'s own behaviour and hono's.
|
|
60
|
+
*/
|
|
61
|
+
readonly strict: boolean;
|
|
57
62
|
/**
|
|
58
63
|
* Install `SIGTERM`/`SIGINT` handlers that shut the app down. Off by default,
|
|
59
64
|
* because installing a signal handler changes how the process terminates and
|
package/dist/server/options.d.ts
CHANGED
|
@@ -33,6 +33,17 @@ export interface HttpOptions extends AppOptions {
|
|
|
33
33
|
readonly cors?: CorsOptions;
|
|
34
34
|
/** `app.set('trust proxy', ...)` as a field. */
|
|
35
35
|
readonly trustProxy?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Match a path exactly as declared, so `/users/1/` is not `/users/1`.
|
|
38
|
+
*
|
|
39
|
+
* **`true` by default**, which is what `Bun.serve({ routes })` matches on its
|
|
40
|
+
* own, and hono's name and default for the same switch. `false` serves both
|
|
41
|
+
* spellings, as Nest, express and elysia do - every route but `/` and a
|
|
42
|
+
* wildcard mount, which already matches its own trailing slash.
|
|
43
|
+
*
|
|
44
|
+
* Not an `app.set()` setting: the route table is built once, at `listen()`.
|
|
45
|
+
*/
|
|
46
|
+
readonly strict?: boolean;
|
|
36
47
|
/**
|
|
37
48
|
* Calls `enableShutdownHooks` at construction. `true` takes the default signals;
|
|
38
49
|
* an object names them and tunes the force-exit.
|
package/dist/server/routes.d.ts
CHANGED
|
@@ -60,3 +60,19 @@ export declare const withUpgradeRoutes: (routes: BunRoutes, gateways: ReadonlyMa
|
|
|
60
60
|
*/
|
|
61
61
|
export declare const buildFallback: (middleware?: readonly Middleware[], onError?: ErrorMapper, cors?: CorsOptions, notFound?: 'guarded' | 'public') => RouteHandler;
|
|
62
62
|
export declare const buildRoutes: (discovered: readonly DiscoveredRoute[], middleware?: readonly Middleware[], onError?: ErrorMapper, cors?: CorsOptions, resolve?: GuardResolver) => BunRoutes;
|
|
63
|
+
/**
|
|
64
|
+
* A second key per route ending in `/`, holding the handlers the first one has.
|
|
65
|
+
*
|
|
66
|
+
* `Bun.serve({ routes })` matches the literal path, so `/users/1/` misses when
|
|
67
|
+
* `/users/:id` is what was registered. Opt in with `strict: false`. The
|
|
68
|
+
* measurements, and what the other frameworks do, are in
|
|
69
|
+
* docs/architecture/http.md.
|
|
70
|
+
*
|
|
71
|
+
* A key rather than a copy: one per-method object under two names, so the
|
|
72
|
+
* pattern `buildContext` froze still labels the metrics series and the log line.
|
|
73
|
+
* It runs after the CORS preflight is mounted, so the alias carries `OPTIONS`.
|
|
74
|
+
*
|
|
75
|
+
* `/` and any `*` path are skipped - `//` is neither, and a wildcard already
|
|
76
|
+
* matches its own trailing slash.
|
|
77
|
+
*/
|
|
78
|
+
export declare const withTrailingSlashAliases: (routes: BunRoutes) => BunRoutes;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dunx/http",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "Bun.serve adapter for the dunx framework: controllers, middleware and WebSocket gateways",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@opentelemetry/sdk-trace-node": "2.11.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
|
-
"@dunx/core": "^3.
|
|
68
|
+
"@dunx/core": "^3.4.1",
|
|
69
69
|
"@types/bun": ">=1.4.1"
|
|
70
70
|
},
|
|
71
71
|
"peerDependenciesMeta": {
|