@bymax-one/nest-core 1.0.0 → 1.1.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/CHANGELOG.md +157 -1
- package/README.md +387 -64
- package/dist/health/index.cjs +10 -0
- package/dist/health/index.d.cts +33 -1
- package/dist/health/index.d.ts +33 -1
- package/dist/health/index.mjs +8 -0
- package/dist/index.cjs +422 -37
- package/dist/index.d.cts +237 -11
- package/dist/index.d.ts +237 -11
- package/dist/index.mjs +424 -40
- package/dist/metrics/index.cjs +12 -0
- package/dist/metrics/index.d.cts +57 -0
- package/dist/metrics/index.d.ts +57 -0
- package/dist/metrics/index.mjs +9 -0
- package/dist/openapi/index.cjs +268 -0
- package/dist/openapi/index.d.cts +44 -0
- package/dist/openapi/index.d.ts +44 -0
- package/dist/openapi/index.mjs +266 -0
- package/package.json +70 -27
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,160 @@ heading here.
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [1.1.0] - 2026-08-05
|
|
15
|
+
|
|
16
|
+
Four optional integrations, each off by default and each loading nothing until it
|
|
17
|
+
is turned on: OpenAPI documents in development, health-indicator discovery, a
|
|
18
|
+
metrics contribution contract, and OpenTelemetry trace correlation.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **OpenAPI documents, development only.** A new `openapi` option block and a new
|
|
23
|
+
`./openapi` subpath exporting `applyBymaxOpenApi`. Enabling the block and calling
|
|
24
|
+
the helper once during bootstrap serves an interactive UI and the raw document,
|
|
25
|
+
carrying the schemas this package already owns — the error envelope and its code
|
|
26
|
+
catalog, the health response, and the offset and cursor page shapes with their
|
|
27
|
+
query parameters.
|
|
28
|
+
|
|
29
|
+
`@nestjs/swagger` is an optional peer, reached only through a lazy dynamic import,
|
|
30
|
+
exactly like `prom-client`: an application that leaves the feature off never loads
|
|
31
|
+
it, and enabling the feature without installing it fails at boot with a message
|
|
32
|
+
naming the package and the install command.
|
|
33
|
+
|
|
34
|
+
The schemas are contributed as plain specification objects rather than decorated
|
|
35
|
+
classes. A decorator runs when its class is defined, so describing these contracts
|
|
36
|
+
with `@ApiProperty` would load the peer in every application that imports this
|
|
37
|
+
package, including the ones that never enable the feature.
|
|
38
|
+
|
|
39
|
+
A contributed entry never overwrites one the document already defines.
|
|
40
|
+
|
|
41
|
+
- **Health-indicator discovery.** A new `health.autoDiscover` option and a
|
|
42
|
+
`@BymaxHealthIndicator()` marker, exported from the `./health` subpath alongside
|
|
43
|
+
the contract it belongs to. With discovery enabled, every marked provider in the
|
|
44
|
+
application joins readiness — so a library an application merely imports can
|
|
45
|
+
contribute its own check without the application registering anything.
|
|
46
|
+
|
|
47
|
+
Discovery matches the marker, never the shape of an object: a provider that
|
|
48
|
+
happens to expose a `name` and a `check` is not a readiness probe, and scraping
|
|
49
|
+
one in would let an unrelated failure take an application out of rotation. A
|
|
50
|
+
provider that is marked but does not implement `IHealthIndicator` fails the boot
|
|
51
|
+
naming the class, rather than being skipped silently.
|
|
52
|
+
|
|
53
|
+
Explicit registration still wins: an indicator bound under
|
|
54
|
+
`BYMAX_HEALTH_INDICATORS` keeps its name and its position, and a discovered one
|
|
55
|
+
with the same name is dropped. Discovered indicators are sorted by name, so the
|
|
56
|
+
`checks` array is stable across restarts. The provider graph is walked once, at
|
|
57
|
+
bootstrap.
|
|
58
|
+
|
|
59
|
+
Off by default. It changes which failures can fail a readiness probe, which is
|
|
60
|
+
a decision an application makes rather than one it inherits from its imports.
|
|
61
|
+
|
|
62
|
+
- **A metrics contribution contract.** A new `./metrics` subpath exporting
|
|
63
|
+
`IMetricsContributor` and a `@BymaxMetricsContributor()` marker. A marked provider
|
|
64
|
+
is handed the registry once at bootstrap and registers its own collectors, so a
|
|
65
|
+
library's metrics appear on the application's existing scrape endpoint with
|
|
66
|
+
nothing wired.
|
|
67
|
+
|
|
68
|
+
Contributors receive the registry rather than injecting `BYMAX_METRICS_REGISTRY`:
|
|
69
|
+
a library that injected the token would depend on this package's DI tokens, and
|
|
70
|
+
therefore on the module. Receiving it as an argument means the only thing a
|
|
71
|
+
contributing library imports is the contract and the marker.
|
|
72
|
+
|
|
73
|
+
Registration failures are rethrown with the contributor named and the original
|
|
74
|
+
error chained. `prom-client` reports a duplicate metric name but not who
|
|
75
|
+
registered it, which in an application composing several libraries is the hard
|
|
76
|
+
half of the question. Contributors run sorted by class name, so a collision fails
|
|
77
|
+
the same way on every boot.
|
|
78
|
+
|
|
79
|
+
No separate flag: contribution rides on the metrics feature. With metrics
|
|
80
|
+
disabled no contributor runs and `prom-client` is still never loaded.
|
|
81
|
+
|
|
82
|
+
This is the one subpath whose types name `prom-client`. Implementing the contract
|
|
83
|
+
means constructing `prom-client` collectors, so anyone importing it already
|
|
84
|
+
depends on the peer; every other subpath stays free of it.
|
|
85
|
+
|
|
86
|
+
- **Trace correlation.** A new `telemetry` option block reads the active OpenTelemetry
|
|
87
|
+
span and carries its identifiers into the request-timing sample, into the exception
|
|
88
|
+
filter's observability seam, and — behind `telemetry.exposeTraceId` — into the error
|
|
89
|
+
envelope served to the client.
|
|
90
|
+
|
|
91
|
+
`@opentelemetry/api` is an optional peer. Unlike the other two it is read on every
|
|
92
|
+
request, so it is loaded once at bootstrap rather than at the point of use, and only
|
|
93
|
+
when the feature is enabled.
|
|
94
|
+
|
|
95
|
+
This package reads; it never traces. No span is created, no SDK configured, no
|
|
96
|
+
exporter registered: all of that belongs to the instrumentation an operator already
|
|
97
|
+
runs, and duplicating it would produce two spans per request.
|
|
98
|
+
|
|
99
|
+
A request with nothing recording, or an all-zero span context, resolves to no trace:
|
|
100
|
+
the fields are absent rather than set to a sentinel. Trace identifiers are never used
|
|
101
|
+
as metric labels — a trace id is unbounded, and one unbounded label is enough to make
|
|
102
|
+
a scrape endpoint the most expensive route in a service.
|
|
103
|
+
|
|
104
|
+
### Changed
|
|
105
|
+
|
|
106
|
+
- **The marker-based provider scan is now shared.** Readiness discovery and metrics
|
|
107
|
+
contribution use one scan, which reads Nest's provider graph, matches a literal
|
|
108
|
+
metadata key, and labels each match by class name — falling back to the provider
|
|
109
|
+
token for an anonymous class. Behavior is unchanged for readiness.
|
|
110
|
+
|
|
111
|
+
### Security
|
|
112
|
+
|
|
113
|
+
- **A trace id is not published in a response body by default.** `telemetry.exposeTraceId`
|
|
114
|
+
is off: a trace id is not a secret, but in a response it tells a caller that a tracing
|
|
115
|
+
backend exists and hands them the identifier correlating their request with everything
|
|
116
|
+
else in that trace. With the option off the identifiers still reach the timing sample and
|
|
117
|
+
the logging seam.
|
|
118
|
+
- **The OpenAPI document is never served in production.** `NODE_ENV` decides, and
|
|
119
|
+
the decision is fail-closed: only `development` and `test` are non-production, so
|
|
120
|
+
an unset or unrecognized value is production. The guard runs in two independent
|
|
121
|
+
layers — the option resolver forces the feature off, and the bootstrap helper
|
|
122
|
+
refuses again without trusting that resolution — and there is no override. Asking
|
|
123
|
+
for the document in production is a no-op with a warning, not an error, so one
|
|
124
|
+
configuration can be shared across environments.
|
|
125
|
+
|
|
126
|
+
### Notes
|
|
127
|
+
|
|
128
|
+
- `applyBymaxOpenApi` must be called **before** `app.listen()`. Mounting the document
|
|
129
|
+
re-registers routes on the HTTP adapter, and doing that against an
|
|
130
|
+
already-initialized Express 5 application replaces the router: every other route,
|
|
131
|
+
including this package's health endpoints, stops resolving.
|
|
132
|
+
|
|
133
|
+
## [1.0.1] - 2026-08-04
|
|
134
|
+
|
|
135
|
+
**Behaviour change on the readiness endpoint.** A failing indicator's message no
|
|
136
|
+
longer appears in the HTTP response by default; it goes to the logger instead.
|
|
137
|
+
|
|
138
|
+
### Security
|
|
139
|
+
|
|
140
|
+
- **The readiness response no longer publishes an indicator's failure message.**
|
|
141
|
+
`GET /health/ready` returned `details.error` carrying the rejecting indicator's
|
|
142
|
+
`Error#message`. That endpoint is typically unauthenticated and reachable by
|
|
143
|
+
whatever probes it — and an indicator rarely authors its own failure text: it
|
|
144
|
+
writes `await this.redis.ping()` and lets the driver's error propagate. Driver
|
|
145
|
+
errors carry hosts, ports and, for a connection string, credentials. An
|
|
146
|
+
indicator failing with `connection refused: postgres://user:PASSWORD@db:5432`
|
|
147
|
+
served that string to anyone who could reach the probe.
|
|
148
|
+
|
|
149
|
+
A failing check is now `{ name, status: 'down' }` and nothing more. The message
|
|
150
|
+
is written to Nest's `Logger` instead, so the diagnostic survives in a channel
|
|
151
|
+
that already has access control rather than being lost.
|
|
152
|
+
|
|
153
|
+
`health.exposeIndicatorErrors` (default `false`) puts it back in the response
|
|
154
|
+
for local debugging — the same shape, and the same warning, as
|
|
155
|
+
`envelope.exposeInternals`. The library made opposite choices about the same
|
|
156
|
+
risk in two places; they now agree.
|
|
157
|
+
|
|
158
|
+
`timedOutAfterMs` is unaffected: that number is one this library chose, not text
|
|
159
|
+
an indicator produced.
|
|
160
|
+
|
|
161
|
+
### Changed
|
|
162
|
+
|
|
163
|
+
- **The Health and Security Model sections describe the split**, and the
|
|
164
|
+
configuration table documents the new option. The previous text said an
|
|
165
|
+
indicator "cannot leak more than it already chose to put in a message", which
|
|
166
|
+
assigned a choice the indicator's author usually never makes.
|
|
167
|
+
|
|
14
168
|
## [1.0.0] - 2026-08-03
|
|
15
169
|
|
|
16
170
|
First published release. Everything below ships in it.
|
|
@@ -73,5 +227,7 @@ have regressed from. They are kept because the reasoning is worth having.
|
|
|
73
227
|
cleanly and silently. Corrected before the first publish, so no released version
|
|
74
228
|
ever carried the permissive range. No runtime behaviour changed.
|
|
75
229
|
|
|
230
|
+
[1.1.0]: https://github.com/bymaxone/nest-core/compare/v1.0.1...v1.1.0
|
|
231
|
+
[1.0.1]: https://github.com/bymaxone/nest-core/compare/v1.0.0...v1.0.1
|
|
76
232
|
[1.0.0]: https://github.com/bymaxone/nest-core/releases/tag/v1.0.0
|
|
77
|
-
[Unreleased]: https://github.com/bymaxone/nest-core/compare/v1.
|
|
233
|
+
[Unreleased]: https://github.com/bymaxone/nest-core/compare/v1.1.0...HEAD
|