@biorate/nestjs-tools 2.2.1 → 2.2.3

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.
Files changed (2) hide show
  1. package/README.md +274 -5
  2. package/package.json +9 -9
package/README.md CHANGED
@@ -1,10 +1,279 @@
1
- # NestJS Tools
1
+ # @biorate/nestjs-tools
2
2
 
3
- This module provides an middlewares, providers, filters ans decorators for NestJS.
3
+ Production‑grade middleware, guards, interceptors, filters, decorators, and HTTP controllers for NestJS applications built on `@biorate/inversion` and `@biorate/prometheus`.
4
+
5
+ ## Features
6
+
7
+ - **Request counting** — Prometheus‑backed counter per method + route + status.
8
+ - **Response time** — Prometheus histogram + `x-response-time` header.
9
+ - **HTTP proxy** — Prometheus‑instrumented `http-proxy-middleware` wrapper.
10
+ - **Tracing** — OpenTelemetry span attributes for incoming requests.
11
+ - **Exception filter** — structured JSON error responses for HTTP, WS, and RPC.
12
+ - **Auth** — `@AuthBasic()` decorator + `AuthGuardProvider`.
13
+ - **Roles** — `@Roles()` decorator + `RolesGuardProvider`.
14
+ - **CORS** — config‑driven origin validation.
15
+ - **Built‑in controllers** — `/metrics`, `/probe`, `/locales`.
16
+ - **Hexagonal app template** — domain/application/infrastructure layers.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pnpm add @biorate/nestjs-tools
22
+ ```
23
+
24
+ Peer dependencies: `@nestjs/common`, `@nestjs/core`, `@nestjs/swagger`, `class-validator`, `express`, `http-proxy`, `http-proxy-middleware`, `lodash-es`, `rxjs`, `ws`.
25
+
26
+ ## Quick start
4
27
 
5
- #### Example:
6
28
  ```ts
7
- //TODO:
29
+ import { NestFactory } from '@nestjs/core';
30
+ import { AppModule } from './app.module';
31
+ import {
32
+ AllExceptionsFilter,
33
+ BootstrapProvider,
34
+ RequestCountMiddleware,
35
+ ResponseTimeMiddleware,
36
+ TracingInterceptor,
37
+ } from '@biorate/nestjs-tools';
38
+
39
+ async function bootstrap() {
40
+ const app = await NestFactory.create(AppModule, { bufferLogs: true });
41
+
42
+ app.useGlobalFilters(new AllExceptionsFilter());
43
+ app.useGlobalInterceptors(new TracingInterceptor());
44
+
45
+ // Middleware
46
+ app.use(BootstrapProvider.create());
47
+ app.use(RequestCountMiddleware.create());
48
+ app.use(ResponseTimeMiddleware.create());
49
+
50
+ await app.listen(3000);
51
+ }
52
+ ```
53
+
54
+ ## Middlewares
55
+
56
+ ### `RequestCountMiddleware`
57
+
58
+ Prometheus counter `http_server_requests_seconds_count` with labels `method`, `uri`, `status`.
59
+
60
+ ```ts
61
+ consumer.apply(RequestCountMiddleware).forRoutes('*');
62
+ // or via BootstrapProvider
63
+ app.use(RequestCountMiddleware.create());
64
+ ```
65
+
66
+ Uses `RoutesInterceptor` to resolve the actual route path (e.g. `/api/users/:id` instead of `/api/users/123`).
67
+
68
+ Config option: `app.middleware.RequestCountMiddleware.log-base-url` (boolean, default `false`).
69
+
70
+ ### `ResponseTimeMiddleware`
71
+
72
+ Prometheus histogram `http_server_requests_seconds` + `x-response-time` header.
73
+
74
+ ```ts
75
+ app.use(ResponseTimeMiddleware.create());
76
+ ```
77
+
78
+ Config options:
79
+
80
+ | Path | Default |
81
+ |-----------------------------------------------------|-------------|
82
+ | `app.middleware.ResponseTimeMiddleware.suffix` | `true` |
83
+ | `app.middleware.ResponseTimeMiddleware.header` | `x-response-time` |
84
+ | `app.middleware.ResponseTimeMiddleware.digits` | `3` |
85
+ | `app.middleware.ResponseTimeMiddleware.log-base-url` | `false` |
86
+ | `ResponseTimeMiddleware.histogram.buckets` | `[0.005, 0.01, … , 10]` |
87
+
88
+ ### `ProxyPrometheusMiddleware`
89
+
90
+ Prometheus‑instrumented HTTP proxy via `http-proxy-middleware`.
91
+
92
+ ```ts
93
+ import { ProxyPrometheusMiddleware } from '@biorate/nestjs-tools';
94
+
95
+ consumer.apply(ProxyPrometheusMiddleware.create({
96
+ target: 'http://upstream.service:8080',
97
+ changeOrigin: true,
98
+ })).forRoutes('/api/v2/legacy');
99
+ ```
100
+
101
+ Creates two metrics:
102
+ - `http_proxy_server_requests_seconds_count` (counter)
103
+ - `http_proxy_server_requests_seconds` (histogram)
104
+
105
+ Config: `ProxyPrometheusMiddleware.histogram.buckets`.
106
+
107
+ ## Filters
108
+
109
+ ### `AllExceptionsFilter`
110
+
111
+ Catches all exceptions and returns a structured JSON response:
112
+
113
+ ```json
114
+ {
115
+ "status": 402,
116
+ "code": "PaymentError",
117
+ "hint": "Insufficient funds",
118
+ "path": "/api/orders",
119
+ "meta": {}
120
+ }
121
+ ```
122
+
123
+ Supports HTTP, WebSocket, and RPC transport types. Maps `meta.status` from `@biorate/errors` to HTTP status codes.
124
+
125
+ ```ts
126
+ app.useGlobalFilters(new AllExceptionsFilter());
127
+ ```
128
+
129
+ ## Interceptors
130
+
131
+ ### `TracingInterceptor`
132
+
133
+ Adds OpenTelemetry span attributes for incoming requests:
134
+
135
+ ```
136
+ incoming.request.url
137
+ incoming.request.body
138
+ incoming.request.headers
139
+ incoming.request.method
140
+ incoming.request.params
141
+ incoming.request.query
142
+ incoming.response.headers
143
+ incoming.response.statusCode
144
+ incoming.response.data
145
+ incoming.response.errorCode
146
+ ```
147
+
148
+ Config: `TracingInterceptor.excluded` — array of strings or RegExp to skip URLs.
149
+
150
+ ### `RoutesInterceptor`
151
+
152
+ Resolves the full route path (controller + handler) and stores it in a `WeakMap<Request, { path }>` for use by `RequestCountMiddleware` and `ResponseTimeMiddleware`.
153
+
154
+ Applied automatically when using the count/time middlewares.
155
+
156
+ ## Providers (Guards)
157
+
158
+ ### `AuthGuardProvider`
159
+
160
+ HTTP Basic Authentication guard. Validates `Authorization: Basic …` against config `app.auth.basic` (map of `username: password`). If config is absent, access is granted.
161
+
162
+ ```ts
163
+ @Injectable()
164
+ export class MyController {
165
+ @Get('/admin')
166
+ @AuthBasic()
167
+ public admin() { return 'secret data'; }
168
+ }
169
+ ```
170
+
171
+ ### `RolesGuardProvider`
172
+
173
+ Bitmask‑based role guard. Use with `@Roles()` decorator:
174
+
175
+ ```ts
176
+ import { Roles, UserRoles } from '@biorate/nestjs-tools';
177
+
178
+ @Roles(UserRoles.Admin | UserRoles.Manager)
179
+ @Get('/admin')
180
+ public admin() { return 'ok'; }
181
+ ```
182
+
183
+ Override `getUser()` to load the user from your database:
184
+
185
+ ```ts
186
+ export class CustomRolesGuard extends RolesGuardProvider {
187
+ protected async getUser(context: ExecutionContext) {
188
+ const request = context.switchToHttp().getRequest();
189
+ const user = await myDb.findUser(request.cookies.sessionId);
190
+ return user;
191
+ }
192
+ }
193
+ ```
194
+
195
+ ### `BootstrapProvider`
196
+
197
+ Convenience middleware that initializes the `@biorate/inversion` container lifecycle:
198
+
199
+ ```ts
200
+ app.use(BootstrapProvider.create());
201
+ ```
202
+
203
+ ## Decorators
204
+
205
+ | Decorator | Composition |
206
+ |---------------|--------------------------------------------------|
207
+ | `@Roles(...)` | `SetMetadata(ROLES_KEY, bitmask)` |
208
+ | `@AuthBasic()`| `ApiBasicAuth()` + `UseGuards(AuthGuardProvider)` |
209
+
210
+ ## CORS
211
+
212
+ ```ts
213
+ import { corsOriginHandler } from '@biorate/nestjs-tools';
214
+
215
+ app.enableCors({ origin: corsOriginHandler });
216
+ ```
217
+
218
+ In non‑debug environments, validates the origin against `ALLOWED_ORIGIN` config regexp (defaults to `package.name` without `-server` suffix). In `debug` env, all origins are allowed.
219
+
220
+ ## HTTP controllers
221
+
222
+ ### `MetricsController`
223
+
224
+ Exposes `GET /metrics` with Prometheus metrics from the shared registry.
225
+
226
+ ### `ProbeController`
227
+
228
+ | Route | Purpose |
229
+ |-----------------|---------------------|
230
+ | `GET /probe` | Liveness/readiness |
231
+
232
+ ### `LocalesController`
233
+
234
+ Serves locale files for internationalization.
235
+
236
+ ## App structure (hexagonal)
237
+
238
+ ```
239
+ src/app/
240
+ ├── application/
241
+ │ ├── ports/ ← Use‑case interfaces (inbound ports)
242
+ │ └── service/ ← Use‑case implementations
243
+ ├── domain/
244
+ │ └── .keep ← Domain models, entities, value objects
245
+ └── infrastructure/
246
+ ├── adapters/ ← Outbound port implementations
247
+ └── controllers/ ← NestJS controllers
248
+ ```
249
+
250
+ ## Architecture
251
+
252
+ ```
253
+ ┌──────────────────────────────────────────────────────┐
254
+ │ Incoming HTTP │
255
+ └──────────┬───────────────────────────────────────────┘
256
+ │
257
+ ┌──────────▼───────────────────────────────────────────┐
258
+ │ BootstrapProvider (DI lifecycle init) │
259
+ ├──────────────────────────────────────────────────────┤
260
+ │ RequestCountMiddleware (counter) │
261
+ ├──────────────────────────────────────────────────────┤
262
+ │ ResponseTimeMiddleware (histogram + header) │
263
+ ├──────────────────────────────────────────────────────┤
264
+ │ RoutesInterceptor (path resolution) │
265
+ ├──────────────────────────────────────────────────────┤
266
+ │ TracingInterceptor (OpenTelemetry span attrs) │
267
+ ├──────────────────────────────────────────────────────┤
268
+ │ AllExceptionsFilter (structured error JSON) │
269
+ ├──────────────────────────────────────────────────────┤
270
+ │ AuthGuardProvider / RolesGuardProvider │
271
+ ├──────────────────────────────────────────────────────┤
272
+ │ ┌──────────────────────┐ │
273
+ │ │ ProxyMiddleware │ (optional) │
274
+ │ │ │ │
275
+ │ └──────────────────────┘ │
276
+ └──────────────────────────────────────────────────────┘
8
277
  ```
9
278
 
10
279
  ### Learn
@@ -15,7 +284,7 @@ This module provides an middlewares, providers, filters ans decorators for NestJ
15
284
 
16
285
  See the [CHANGELOG](https://github.com/biorate/core/blob/master/packages/%40biorate/nestjs-tools/CHANGELOG.md)
17
286
 
18
- ### License
287
+ ## License
19
288
 
20
289
  [MIT](https://github.com/biorate/core/blob/master/packages/%40biorate/nestjs-tools/LICENSE)
21
290
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biorate/nestjs-tools",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "NestJS tools",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -45,7 +45,7 @@
45
45
  "keywords": [],
46
46
  "author": "llevkin",
47
47
  "license": "MIT",
48
- "gitHead": "4ec073f69a7fc223e802ced6a632e7a45fa324d9",
48
+ "gitHead": "ff1dcf14a733ce8004ca582d2c421a2154ce97cb",
49
49
  "peerDependencies": {
50
50
  "@nestjs/common": ">=10.4.15",
51
51
  "@nestjs/core": ">=10.4.15",
@@ -59,13 +59,13 @@
59
59
  "ws": ">=8.18.0"
60
60
  },
61
61
  "dependencies": {
62
- "@biorate/axios": "^3.3.0",
63
- "@biorate/config": "^3.2.0",
64
- "@biorate/errors": "^3.1.0",
65
- "@biorate/inversion": "^3.1.0",
66
- "@biorate/opentelemetry": "^2.1.0",
67
- "@biorate/prometheus": "^3.1.0",
68
- "@biorate/tools": "^3.1.0",
62
+ "@biorate/axios": "^3.3.1",
63
+ "@biorate/config": "^3.2.1",
64
+ "@biorate/errors": "^3.1.1",
65
+ "@biorate/inversion": "^3.1.1",
66
+ "@biorate/opentelemetry": "^2.2.1",
67
+ "@biorate/prometheus": "^3.1.1",
68
+ "@biorate/tools": "^3.1.1",
69
69
  "http-proxy": "1.18.1",
70
70
  "http-proxy-middleware": "2.0.6",
71
71
  "json-stringify-safe": "5.0.1",