@nest-toolbox/request-context 1.8.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 bogdanlupu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,301 @@
1
+ # @nest-toolbox/request-context
2
+
3
+ Lightweight AsyncLocalStorage-based request context for NestJS with auto-generated request IDs.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40nest-toolbox%2Frequest-context.svg)](https://www.npmjs.com/package/@nest-toolbox/request-context)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - ðŸŠķ **Zero dependencies** — uses Node.js built-in `AsyncLocalStorage`, nothing else
11
+ - 🚀 **Zero config** — import the module and every request gets a unique ID
12
+ - 🆔 **Auto-generated request IDs** — UUIDv4 by default, or reads from an incoming header
13
+ - ðŸ“Ī **Response header** — sets `x-request-id` on every response automatically
14
+ - ðŸŽŊ **Static API** — no DI needed, read context from anywhere with `RequestContext.get()`
15
+ - 🔀 **Express & Fastify** — works with both adapters out of the box
16
+ - 🔒 **Type-safe** — generic `get<T>(key)` for typed access
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @nest-toolbox/request-context
22
+ ```
23
+
24
+ **Peer dependencies:** `@nestjs/common` and `@nestjs/core` (^10.0.0)
25
+
26
+ ## Quick Start
27
+
28
+ ```typescript
29
+ // app.module.ts
30
+ import { Module } from '@nestjs/common';
31
+ import { RequestContextModule } from '@nest-toolbox/request-context';
32
+
33
+ @Module({
34
+ imports: [RequestContextModule.forRoot()],
35
+ })
36
+ export class AppModule {}
37
+ ```
38
+
39
+ That's it! Every HTTP request now has a unique context. Access it from anywhere:
40
+
41
+ ```typescript
42
+ import { RequestContext } from '@nest-toolbox/request-context';
43
+
44
+ // In any service, repository, pipe, or helper — no injection needed
45
+ const requestId = RequestContext.requestId;
46
+ const userId = RequestContext.get<string>('userId');
47
+ ```
48
+
49
+ ## API Reference
50
+
51
+ ### `RequestContextModule.forRoot(options?)`
52
+
53
+ Register the module globally with static options.
54
+
55
+ ```typescript
56
+ RequestContextModule.forRoot({
57
+ requestIdHeader: 'x-correlation-id',
58
+ generateId: () => nanoid(),
59
+ setResponseHeader: true,
60
+ responseIdHeader: 'x-correlation-id',
61
+ });
62
+ ```
63
+
64
+ | Option | Type | Default | Description |
65
+ |--------|------|---------|-------------|
66
+ | `requestIdHeader` | `string` | `'x-request-id'` | Header to read the incoming request ID from |
67
+ | `generateId` | `() => string` | `crypto.randomUUID` | Custom ID generator when no header is present |
68
+ | `setResponseHeader` | `boolean` | `true` | Whether to set the request ID on the response |
69
+ | `responseIdHeader` | `string` | `'x-request-id'` | Response header name for the request ID |
70
+
71
+ ### `RequestContextModule.forRootAsync(options)`
72
+
73
+ Register the module with async factory injection.
74
+
75
+ ```typescript
76
+ RequestContextModule.forRootAsync({
77
+ imports: [ConfigModule],
78
+ useFactory: (config: ConfigService) => ({
79
+ requestIdHeader: config.get('CORRELATION_HEADER', 'x-request-id'),
80
+ setResponseHeader: config.get('SET_RESPONSE_HEADER') !== 'false',
81
+ }),
82
+ inject: [ConfigService],
83
+ });
84
+ ```
85
+
86
+ ### `RequestContext.requestId`
87
+
88
+ Get the current request ID. Returns `undefined` if called outside a request context.
89
+
90
+ ```typescript
91
+ import { RequestContext } from '@nest-toolbox/request-context';
92
+
93
+ const id = RequestContext.requestId;
94
+ // → "550e8400-e29b-41d4-a716-446655440000"
95
+ ```
96
+
97
+ ### `RequestContext.get<T>(key)`
98
+
99
+ Get a typed value from the context store.
100
+
101
+ ```typescript
102
+ const userId = RequestContext.get<number>('userId');
103
+ // → 42 (typed as number | undefined)
104
+ ```
105
+
106
+ ### `RequestContext.set(key, value)`
107
+
108
+ Set a value in the context store. No-op if called outside a context.
109
+
110
+ ```typescript
111
+ RequestContext.set('userId', 42);
112
+ RequestContext.set('tenantId', 'acme-corp');
113
+ ```
114
+
115
+ ### `RequestContext.has(key)`
116
+
117
+ Check whether a key exists in the context store.
118
+
119
+ ```typescript
120
+ if (RequestContext.has('userId')) {
121
+ // user is authenticated
122
+ }
123
+ ```
124
+
125
+ ### `RequestContext.delete(key)`
126
+
127
+ Remove a key from the context store. Returns `true` if the key existed.
128
+
129
+ ```typescript
130
+ RequestContext.delete('tempToken');
131
+ ```
132
+
133
+ ### `RequestContext.getAll()`
134
+
135
+ Get all key-value pairs as a `ReadonlyMap<string, unknown>`.
136
+
137
+ ```typescript
138
+ const entries = RequestContext.getAll();
139
+ // → Map { 'userId' => 42, 'tenantId' => 'acme-corp' }
140
+ ```
141
+
142
+ ### `RequestContext.run(requestId, fn)`
143
+
144
+ Run a function within a manually created request context. Useful for testing, WebSocket handlers, message queue consumers, and CRON jobs.
145
+
146
+ ```typescript
147
+ const result = await RequestContext.run('test-request-1', async () => {
148
+ RequestContext.set('userId', 1);
149
+ return await myService.doSomething();
150
+ });
151
+ ```
152
+
153
+ ## Common Patterns
154
+
155
+ ### Setting user info in a guard
156
+
157
+ ```typescript
158
+ import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
159
+ import { RequestContext } from '@nest-toolbox/request-context';
160
+
161
+ @Injectable()
162
+ export class AuthGuard implements CanActivate {
163
+ async canActivate(context: ExecutionContext): Promise<boolean> {
164
+ const request = context.switchToHttp().getRequest();
165
+ const user = await this.authService.validate(request.headers.authorization);
166
+
167
+ // Store user info — available everywhere downstream
168
+ RequestContext.set('userId', user.id);
169
+ RequestContext.set('userRole', user.role);
170
+
171
+ return true;
172
+ }
173
+ }
174
+ ```
175
+
176
+ ### Reading tenant ID in a service
177
+
178
+ ```typescript
179
+ import { Injectable } from '@nestjs/common';
180
+ import { RequestContext } from '@nest-toolbox/request-context';
181
+
182
+ @Injectable()
183
+ export class InvoiceService {
184
+ async findAll() {
185
+ const tenantId = RequestContext.get<string>('tenantId');
186
+
187
+ return this.invoiceRepo.find({
188
+ where: { tenantId },
189
+ });
190
+ }
191
+ }
192
+ ```
193
+
194
+ ### Using with loggers (injecting request ID)
195
+
196
+ ```typescript
197
+ import { LoggerService } from '@nestjs/common';
198
+ import { RequestContext } from '@nest-toolbox/request-context';
199
+
200
+ export class AppLogger implements LoggerService {
201
+ log(message: string) {
202
+ const requestId = RequestContext.requestId ?? 'no-context';
203
+ console.log(`[${requestId}] ${message}`);
204
+ }
205
+
206
+ error(message: string, trace?: string) {
207
+ const requestId = RequestContext.requestId ?? 'no-context';
208
+ console.error(`[${requestId}] ${message}`, trace);
209
+ }
210
+
211
+ warn(message: string) {
212
+ const requestId = RequestContext.requestId ?? 'no-context';
213
+ console.warn(`[${requestId}] ${message}`);
214
+ }
215
+ }
216
+ ```
217
+
218
+ ### Testing with `RequestContext.run()`
219
+
220
+ ```typescript
221
+ import { RequestContext } from '@nest-toolbox/request-context';
222
+
223
+ describe('InvoiceService', () => {
224
+ it('should filter by tenant', async () => {
225
+ const result = await RequestContext.run('test-req-1', async () => {
226
+ RequestContext.set('tenantId', 'acme-corp');
227
+ return invoiceService.findAll();
228
+ });
229
+
230
+ expect(result).toEqual(
231
+ expect.arrayContaining([
232
+ expect.objectContaining({ tenantId: 'acme-corp' }),
233
+ ]),
234
+ );
235
+ });
236
+ });
237
+ ```
238
+
239
+ ## Integration with Other Toolbox Packages
240
+
241
+ ### @nest-toolbox/http-logger-middleware
242
+
243
+ The HTTP logger automatically picks up the request ID to correlate log entries:
244
+
245
+ ```typescript
246
+ import { RequestContextModule } from '@nest-toolbox/request-context';
247
+ import { HttpLoggerMiddleware } from '@nest-toolbox/http-logger-middleware';
248
+
249
+ @Module({
250
+ imports: [RequestContextModule.forRoot()],
251
+ })
252
+ export class AppModule implements NestModule {
253
+ configure(consumer: MiddlewareConsumer) {
254
+ consumer.apply(HttpLoggerMiddleware).forRoutes('*');
255
+ }
256
+ }
257
+ // Every log line now includes the request ID for tracing.
258
+ ```
259
+
260
+ ### @nest-toolbox/typeorm-audit-log
261
+
262
+ Store the current user in context so audit logs automatically record who made each change:
263
+
264
+ ```typescript
265
+ // In your auth guard
266
+ RequestContext.set('userId', user.id);
267
+
268
+ // The audit log subscriber reads from the same context
269
+ // to attribute every INSERT, UPDATE, and DELETE.
270
+ ```
271
+
272
+ ## Comparison with nestjs-cls
273
+
274
+ [`nestjs-cls`](https://github.com/Papooch/nestjs-cls) is a popular, feature-rich CLS library. If you need middleware hooks, proxy providers, or plugin extensibility, it's a great choice.
275
+
276
+ **`@nest-toolbox/request-context` is intentionally simpler:**
277
+
278
+ | | `request-context` | `nestjs-cls` |
279
+ |---|---|---|
280
+ | Dependencies | **0** (Node.js built-in) | 1+ |
281
+ | API surface | Static class, 7 methods | Service + decorators + plugins |
282
+ | Setup | `forRoot()`, done | `forRoot()` + configure enhancer |
283
+ | Access pattern | `RequestContext.get()` anywhere | Inject `ClsService` via DI |
284
+ | Request IDs | Built-in, auto-generated | Manual setup |
285
+ | Best for | Simple context + request IDs | Complex CLS with plugins |
286
+
287
+ If all you need is request IDs and a lightweight key-value store per request, this package gets out of your way.
288
+
289
+ ## Types
290
+
291
+ All types are exported from the package:
292
+
293
+ | Type | Description |
294
+ |------|-------------|
295
+ | `ContextStore` | Internal store shape (`requestId` + `values` map) |
296
+ | `RequestContextOptions` | Static options for `forRoot()` |
297
+ | `RequestContextAsyncOptions` | Async options for `forRootAsync()` |
298
+
299
+ ## License
300
+
301
+ MIT ÂĐ [Bogdan Lupu](https://github.com/lupu60)
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Constants for @nest-toolbox/request-context
3
+ */
4
+ /** Injection token for module options */
5
+ export declare const REQUEST_CONTEXT_OPTIONS = "REQUEST_CONTEXT_OPTIONS";
6
+ /** Default request ID header name */
7
+ export declare const DEFAULT_REQUEST_ID_HEADER = "x-request-id";
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * Constants for @nest-toolbox/request-context
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_REQUEST_ID_HEADER = exports.REQUEST_CONTEXT_OPTIONS = void 0;
7
+ /** Injection token for module options */
8
+ exports.REQUEST_CONTEXT_OPTIONS = 'REQUEST_CONTEXT_OPTIONS';
9
+ /** Default request ID header name */
10
+ exports.DEFAULT_REQUEST_ID_HEADER = 'x-request-id';
11
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,yCAAyC;AAC5B,QAAA,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE,qCAAqC;AACxB,QAAA,yBAAyB,GAAG,cAAc,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @nest-toolbox/request-context
3
+ *
4
+ * Lightweight AsyncLocalStorage-based request context for NestJS
5
+ * with auto-generated request IDs.
6
+ */
7
+ export * from './constants';
8
+ export * from './request-context';
9
+ export * from './request-context.middleware';
10
+ export * from './request-context.module';
11
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * @nest-toolbox/request-context
4
+ *
5
+ * Lightweight AsyncLocalStorage-based request context for NestJS
6
+ * with auto-generated request IDs.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ __exportStar(require("./constants"), exports);
24
+ __exportStar(require("./request-context"), exports);
25
+ __exportStar(require("./request-context.middleware"), exports);
26
+ __exportStar(require("./request-context.module"), exports);
27
+ __exportStar(require("./types"), exports);
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;AAEH,8CAA4B;AAC5B,oDAAkC;AAClC,+DAA6C;AAC7C,2DAAyC;AACzC,0CAAwB"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Core request context store using AsyncLocalStorage.
3
+ *
4
+ * Provides a static API to get/set values anywhere in the request lifecycle
5
+ * without injecting services or passing context through function arguments.
6
+ */
7
+ import type { ContextStore } from './types';
8
+ /**
9
+ * Run a function within a request context.
10
+ * All code executed within fn (including async operations) will have access
11
+ * to the context store.
12
+ *
13
+ * @param store - The context store for this request
14
+ * @param fn - The function to run within the context
15
+ * @returns The return value of fn
16
+ */
17
+ export declare function runWithContext<T>(store: ContextStore, fn: () => T): T;
18
+ /**
19
+ * Get the current context store, or undefined if outside a context.
20
+ */
21
+ export declare function getStore(): ContextStore | undefined;
22
+ /**
23
+ * Static API for accessing request context from anywhere.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { RequestContext } from '@nest-toolbox/request-context';
28
+ *
29
+ * // In any service, repository, or helper
30
+ * const reqId = RequestContext.requestId;
31
+ * const userId = RequestContext.get<string>('userId');
32
+ * RequestContext.set('tenantId', 'acme-corp');
33
+ * ```
34
+ */
35
+ export declare class RequestContext {
36
+ /**
37
+ * Get the current request ID.
38
+ * Returns undefined if called outside a request context.
39
+ */
40
+ static get requestId(): string | undefined;
41
+ /**
42
+ * Get a typed value from the context store.
43
+ *
44
+ * @param key - The key to look up
45
+ * @returns The value cast to T, or undefined if not found
46
+ */
47
+ static get<T = unknown>(key: string): T | undefined;
48
+ /**
49
+ * Set a value in the context store.
50
+ * No-op if called outside a request context.
51
+ *
52
+ * @param key - The key to set
53
+ * @param value - The value to store
54
+ */
55
+ static set(key: string, value: unknown): void;
56
+ /**
57
+ * Check if a key exists in the context store.
58
+ */
59
+ static has(key: string): boolean;
60
+ /**
61
+ * Delete a key from the context store.
62
+ */
63
+ static delete(key: string): boolean;
64
+ /**
65
+ * Get all key-value pairs from the context store.
66
+ * Returns an empty map if called outside a request context.
67
+ */
68
+ static getAll(): ReadonlyMap<string, unknown>;
69
+ /**
70
+ * Run a function within a request context.
71
+ * Useful for testing or non-HTTP contexts (WebSockets, queues).
72
+ *
73
+ * @param requestId - The request ID for this context
74
+ * @param fn - The function to run
75
+ * @returns The return value of fn
76
+ */
77
+ static run<T>(requestId: string, fn: () => T): T;
78
+ }
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * Core request context store using AsyncLocalStorage.
4
+ *
5
+ * Provides a static API to get/set values anywhere in the request lifecycle
6
+ * without injecting services or passing context through function arguments.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.RequestContext = void 0;
10
+ exports.runWithContext = runWithContext;
11
+ exports.getStore = getStore;
12
+ const node_async_hooks_1 = require("node:async_hooks");
13
+ const storage = new node_async_hooks_1.AsyncLocalStorage();
14
+ /**
15
+ * Run a function within a request context.
16
+ * All code executed within fn (including async operations) will have access
17
+ * to the context store.
18
+ *
19
+ * @param store - The context store for this request
20
+ * @param fn - The function to run within the context
21
+ * @returns The return value of fn
22
+ */
23
+ function runWithContext(store, fn) {
24
+ return storage.run(store, fn);
25
+ }
26
+ /**
27
+ * Get the current context store, or undefined if outside a context.
28
+ */
29
+ function getStore() {
30
+ return storage.getStore();
31
+ }
32
+ /**
33
+ * Static API for accessing request context from anywhere.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * import { RequestContext } from '@nest-toolbox/request-context';
38
+ *
39
+ * // In any service, repository, or helper
40
+ * const reqId = RequestContext.requestId;
41
+ * const userId = RequestContext.get<string>('userId');
42
+ * RequestContext.set('tenantId', 'acme-corp');
43
+ * ```
44
+ */
45
+ // biome-ignore lint/complexity/noStaticOnlyClass: class provides clean namespaced API for static access pattern
46
+ class RequestContext {
47
+ /**
48
+ * Get the current request ID.
49
+ * Returns undefined if called outside a request context.
50
+ */
51
+ static get requestId() {
52
+ var _a;
53
+ return (_a = storage.getStore()) === null || _a === void 0 ? void 0 : _a.requestId;
54
+ }
55
+ /**
56
+ * Get a typed value from the context store.
57
+ *
58
+ * @param key - The key to look up
59
+ * @returns The value cast to T, or undefined if not found
60
+ */
61
+ static get(key) {
62
+ var _a;
63
+ return (_a = storage.getStore()) === null || _a === void 0 ? void 0 : _a.values.get(key);
64
+ }
65
+ /**
66
+ * Set a value in the context store.
67
+ * No-op if called outside a request context.
68
+ *
69
+ * @param key - The key to set
70
+ * @param value - The value to store
71
+ */
72
+ static set(key, value) {
73
+ var _a;
74
+ (_a = storage.getStore()) === null || _a === void 0 ? void 0 : _a.values.set(key, value);
75
+ }
76
+ /**
77
+ * Check if a key exists in the context store.
78
+ */
79
+ static has(key) {
80
+ var _a, _b;
81
+ return (_b = (_a = storage.getStore()) === null || _a === void 0 ? void 0 : _a.values.has(key)) !== null && _b !== void 0 ? _b : false;
82
+ }
83
+ /**
84
+ * Delete a key from the context store.
85
+ */
86
+ static delete(key) {
87
+ var _a, _b;
88
+ return (_b = (_a = storage.getStore()) === null || _a === void 0 ? void 0 : _a.values.delete(key)) !== null && _b !== void 0 ? _b : false;
89
+ }
90
+ /**
91
+ * Get all key-value pairs from the context store.
92
+ * Returns an empty map if called outside a request context.
93
+ */
94
+ static getAll() {
95
+ var _a, _b;
96
+ return (_b = (_a = storage.getStore()) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : new Map();
97
+ }
98
+ /**
99
+ * Run a function within a request context.
100
+ * Useful for testing or non-HTTP contexts (WebSockets, queues).
101
+ *
102
+ * @param requestId - The request ID for this context
103
+ * @param fn - The function to run
104
+ * @returns The return value of fn
105
+ */
106
+ static run(requestId, fn) {
107
+ const store = { requestId, values: new Map() };
108
+ return runWithContext(store, fn);
109
+ }
110
+ }
111
+ exports.RequestContext = RequestContext;
112
+ //# sourceMappingURL=request-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.js","sourceRoot":"","sources":["../src/request-context.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAgBH,wCAEC;AAKD,4BAEC;AAvBD,uDAAqD;AAGrD,MAAM,OAAO,GAAG,IAAI,oCAAiB,EAAgB,CAAC;AAEtD;;;;;;;;GAQG;AACH,SAAgB,cAAc,CAAI,KAAmB,EAAE,EAAW;IAChE,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ;IACtB,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,gHAAgH;AAChH,MAAa,cAAc;IACzB;;;OAGG;IACH,MAAM,KAAK,SAAS;;QAClB,OAAO,MAAA,OAAO,CAAC,QAAQ,EAAE,0CAAE,SAAS,CAAC;IACvC,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,GAAG,CAAc,GAAW;;QACjC,OAAO,MAAA,OAAO,CAAC,QAAQ,EAAE,0CAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAkB,CAAC;IAC9D,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,KAAc;;QACpC,MAAA,OAAO,CAAC,QAAQ,EAAE,0CAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,GAAG,CAAC,GAAW;;QACpB,OAAO,MAAA,MAAA,OAAO,CAAC,QAAQ,EAAE,0CAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,mCAAI,KAAK,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,GAAW;;QACvB,OAAO,MAAA,MAAA,OAAO,CAAC,QAAQ,EAAE,0CAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,mCAAI,KAAK,CAAC;IACzD,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAM;;QACX,OAAO,MAAA,MAAA,OAAO,CAAC,QAAQ,EAAE,0CAAE,MAAM,mCAAI,IAAI,GAAG,EAAE,CAAC;IACjD,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,GAAG,CAAI,SAAiB,EAAE,EAAW;QAC1C,MAAM,KAAK,GAAiB,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;QAC7D,OAAO,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACnC,CAAC;CACF;AAhED,wCAgEC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * NestJS middleware that initializes the request context for each HTTP request.
3
+ *
4
+ * Extracts or generates a request ID and wraps the request lifecycle
5
+ * in AsyncLocalStorage so context is available everywhere.
6
+ */
7
+ import { type NestMiddleware } from '@nestjs/common';
8
+ import type { RequestContextOptions } from './types';
9
+ export declare class RequestContextMiddleware implements NestMiddleware {
10
+ private readonly requestIdHeader;
11
+ private readonly generateId;
12
+ private readonly setResponseHeader;
13
+ private readonly responseIdHeader;
14
+ constructor(options?: RequestContextOptions);
15
+ use(req: any, res: any, next: () => void): void;
16
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * NestJS middleware that initializes the request context for each HTTP request.
4
+ *
5
+ * Extracts or generates a request ID and wraps the request lifecycle
6
+ * in AsyncLocalStorage so context is available everywhere.
7
+ */
8
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
9
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
10
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
11
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
12
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
13
+ };
14
+ var __metadata = (this && this.__metadata) || function (k, v) {
15
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
16
+ };
17
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
18
+ return function (target, key) { decorator(target, key, paramIndex); }
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.RequestContextMiddleware = void 0;
22
+ const node_crypto_1 = require("node:crypto");
23
+ const common_1 = require("@nestjs/common");
24
+ const constants_1 = require("./constants");
25
+ const request_context_1 = require("./request-context");
26
+ let RequestContextMiddleware = class RequestContextMiddleware {
27
+ constructor(options) {
28
+ var _a, _b, _c, _d;
29
+ this.requestIdHeader = (_a = options === null || options === void 0 ? void 0 : options.requestIdHeader) !== null && _a !== void 0 ? _a : constants_1.DEFAULT_REQUEST_ID_HEADER;
30
+ this.generateId = (_b = options === null || options === void 0 ? void 0 : options.generateId) !== null && _b !== void 0 ? _b : node_crypto_1.randomUUID;
31
+ this.setResponseHeader = (_c = options === null || options === void 0 ? void 0 : options.setResponseHeader) !== null && _c !== void 0 ? _c : true;
32
+ this.responseIdHeader = (_d = options === null || options === void 0 ? void 0 : options.responseIdHeader) !== null && _d !== void 0 ? _d : constants_1.DEFAULT_REQUEST_ID_HEADER;
33
+ }
34
+ // biome-ignore lint/suspicious/noExplicitAny: Express/Fastify request/response types vary
35
+ use(req, res, next) {
36
+ var _a;
37
+ const headerValue = (_a = req.headers) === null || _a === void 0 ? void 0 : _a[this.requestIdHeader];
38
+ const requestId = typeof headerValue === 'string' && headerValue.length > 0 ? headerValue : this.generateId();
39
+ if (this.setResponseHeader && typeof res.setHeader === 'function') {
40
+ res.setHeader(this.responseIdHeader, requestId);
41
+ }
42
+ const store = { requestId, values: new Map() };
43
+ (0, request_context_1.runWithContext)(store, () => next());
44
+ }
45
+ };
46
+ exports.RequestContextMiddleware = RequestContextMiddleware;
47
+ exports.RequestContextMiddleware = RequestContextMiddleware = __decorate([
48
+ (0, common_1.Injectable)(),
49
+ __param(0, (0, common_1.Optional)()),
50
+ __param(0, (0, common_1.Inject)(constants_1.REQUEST_CONTEXT_OPTIONS)),
51
+ __metadata("design:paramtypes", [Object])
52
+ ], RequestContextMiddleware);
53
+ //# sourceMappingURL=request-context.middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.middleware.js","sourceRoot":"","sources":["../src/request-context.middleware.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;AAEH,6CAAyC;AACzC,2CAAmF;AACnF,2CAAiF;AACjF,uDAAmD;AAI5C,IAAM,wBAAwB,GAA9B,MAAM,wBAAwB;IAMnC,YAGE,OAA+B;;QAE/B,IAAI,CAAC,eAAe,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,eAAe,mCAAI,qCAAyB,CAAC;QAC7E,IAAI,CAAC,UAAU,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,UAAU,mCAAI,wBAAU,CAAC;QACpD,IAAI,CAAC,iBAAiB,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,iBAAiB,mCAAI,IAAI,CAAC;QAC5D,IAAI,CAAC,gBAAgB,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,mCAAI,qCAAyB,CAAC;IACjF,CAAC;IAED,0FAA0F;IAC1F,GAAG,CAAC,GAAQ,EAAE,GAAQ,EAAE,IAAgB;;QACtC,MAAM,WAAW,GAAG,MAAA,GAAG,CAAC,OAAO,0CAAG,IAAI,CAAC,eAAe,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAE9G,IAAI,IAAI,CAAC,iBAAiB,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YAClE,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,KAAK,GAAiB,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;QAC7D,IAAA,gCAAc,EAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;CACF,CAAA;AA7BY,4DAAwB;mCAAxB,wBAAwB;IADpC,IAAA,mBAAU,GAAE;IAQR,WAAA,IAAA,iBAAQ,GAAE,CAAA;IACV,WAAA,IAAA,eAAM,EAAC,mCAAuB,CAAC,CAAA;;GARvB,wBAAwB,CA6BpC"}