@pawells/nestjs-shared 1.0.0-dev.3052c75
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 +21 -0
- package/README.md +802 -0
- package/build/LICENSE +21 -0
- package/build/README.md +802 -0
- package/build/common/common.module.d.ts +49 -0
- package/build/common/common.module.d.ts.map +1 -0
- package/build/common/common.module.js +178 -0
- package/build/common/common.module.js.map +1 -0
- package/build/common/constants/histogram-buckets.constants.d.ts +12 -0
- package/build/common/constants/histogram-buckets.constants.d.ts.map +1 -0
- package/build/common/constants/histogram-buckets.constants.js +51 -0
- package/build/common/constants/histogram-buckets.constants.js.map +1 -0
- package/build/common/constants/http-status.constants.d.ts +27 -0
- package/build/common/constants/http-status.constants.d.ts.map +1 -0
- package/build/common/constants/http-status.constants.js +27 -0
- package/build/common/constants/http-status.constants.js.map +1 -0
- package/build/common/constants/timeout.constants.d.ts +29 -0
- package/build/common/constants/timeout.constants.d.ts.map +1 -0
- package/build/common/constants/timeout.constants.js +45 -0
- package/build/common/constants/timeout.constants.js.map +1 -0
- package/build/common/controllers/metrics.controller.d.ts +23 -0
- package/build/common/controllers/metrics.controller.d.ts.map +1 -0
- package/build/common/controllers/metrics.controller.js +66 -0
- package/build/common/controllers/metrics.controller.js.map +1 -0
- package/build/common/decorators/common-decorators.d.ts +90 -0
- package/build/common/decorators/common-decorators.d.ts.map +1 -0
- package/build/common/decorators/common-decorators.js +101 -0
- package/build/common/decorators/common-decorators.js.map +1 -0
- package/build/common/decorators/decorator-factory.d.ts +108 -0
- package/build/common/decorators/decorator-factory.d.ts.map +1 -0
- package/build/common/decorators/decorator-factory.js +104 -0
- package/build/common/decorators/decorator-factory.js.map +1 -0
- package/build/common/decorators/guard.decorators.d.ts +48 -0
- package/build/common/decorators/guard.decorators.d.ts.map +1 -0
- package/build/common/decorators/guard.decorators.js +49 -0
- package/build/common/decorators/guard.decorators.js.map +1 -0
- package/build/common/decorators/index.d.ts +10 -0
- package/build/common/decorators/index.d.ts.map +1 -0
- package/build/common/decorators/index.js +11 -0
- package/build/common/decorators/index.js.map +1 -0
- package/build/common/decorators/instrument.decorator.d.ts +128 -0
- package/build/common/decorators/instrument.decorator.d.ts.map +1 -0
- package/build/common/decorators/instrument.decorator.js +165 -0
- package/build/common/decorators/instrument.decorator.js.map +1 -0
- package/build/common/decorators/metric.decorators.d.ts +42 -0
- package/build/common/decorators/metric.decorators.d.ts.map +1 -0
- package/build/common/decorators/metric.decorators.js +85 -0
- package/build/common/decorators/metric.decorators.js.map +1 -0
- package/build/common/decorators/request-property.decorator.d.ts +65 -0
- package/build/common/decorators/request-property.decorator.d.ts.map +1 -0
- package/build/common/decorators/request-property.decorator.js +102 -0
- package/build/common/decorators/request-property.decorator.js.map +1 -0
- package/build/common/errors/base-application-error.d.ts +98 -0
- package/build/common/errors/base-application-error.d.ts.map +1 -0
- package/build/common/errors/base-application-error.js +133 -0
- package/build/common/errors/base-application-error.js.map +1 -0
- package/build/common/errors/error-factory.d.ts +93 -0
- package/build/common/errors/error-factory.d.ts.map +1 -0
- package/build/common/errors/error-factory.js +105 -0
- package/build/common/errors/error-factory.js.map +1 -0
- package/build/common/errors/index.d.ts +13 -0
- package/build/common/errors/index.d.ts.map +1 -0
- package/build/common/errors/index.js +15 -0
- package/build/common/errors/index.js.map +1 -0
- package/build/common/factories/index.d.ts +5 -0
- package/build/common/factories/index.d.ts.map +1 -0
- package/build/common/factories/index.js +3 -0
- package/build/common/factories/index.js.map +1 -0
- package/build/common/factories/module-factory.d.ts +178 -0
- package/build/common/factories/module-factory.d.ts.map +1 -0
- package/build/common/factories/module-factory.js +253 -0
- package/build/common/factories/module-factory.js.map +1 -0
- package/build/common/factories/rate-limit-config.factory.d.ts +79 -0
- package/build/common/factories/rate-limit-config.factory.d.ts.map +1 -0
- package/build/common/factories/rate-limit-config.factory.js +115 -0
- package/build/common/factories/rate-limit-config.factory.js.map +1 -0
- package/build/common/factories/security-bootstrap.factory.d.ts +77 -0
- package/build/common/factories/security-bootstrap.factory.d.ts.map +1 -0
- package/build/common/factories/security-bootstrap.factory.js +222 -0
- package/build/common/factories/security-bootstrap.factory.js.map +1 -0
- package/build/common/filters/global-exception.filter.d.ts +78 -0
- package/build/common/filters/global-exception.filter.d.ts.map +1 -0
- package/build/common/filters/global-exception.filter.js +192 -0
- package/build/common/filters/global-exception.filter.js.map +1 -0
- package/build/common/filters/http-exception.filter.d.ts +37 -0
- package/build/common/filters/http-exception.filter.d.ts.map +1 -0
- package/build/common/filters/http-exception.filter.js +91 -0
- package/build/common/filters/http-exception.filter.js.map +1 -0
- package/build/common/guards/csrf.guard.d.ts +53 -0
- package/build/common/guards/csrf.guard.d.ts.map +1 -0
- package/build/common/guards/csrf.guard.js +109 -0
- package/build/common/guards/csrf.guard.js.map +1 -0
- package/build/common/guards/metrics.guard.d.ts +42 -0
- package/build/common/guards/metrics.guard.d.ts.map +1 -0
- package/build/common/guards/metrics.guard.js +124 -0
- package/build/common/guards/metrics.guard.js.map +1 -0
- package/build/common/index.d.ts +43 -0
- package/build/common/index.d.ts.map +1 -0
- package/build/common/index.js +50 -0
- package/build/common/index.js.map +1 -0
- package/build/common/interceptors/http-client.interceptor.d.ts +11 -0
- package/build/common/interceptors/http-client.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/http-client.interceptor.js +69 -0
- package/build/common/interceptors/http-client.interceptor.js.map +1 -0
- package/build/common/interceptors/http-instrumentation.interceptor.d.ts +64 -0
- package/build/common/interceptors/http-instrumentation.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/http-instrumentation.interceptor.js +148 -0
- package/build/common/interceptors/http-instrumentation.interceptor.js.map +1 -0
- package/build/common/interceptors/http-metrics.interceptor.d.ts +46 -0
- package/build/common/interceptors/http-metrics.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/http-metrics.interceptor.js +120 -0
- package/build/common/interceptors/http-metrics.interceptor.js.map +1 -0
- package/build/common/interceptors/logging.interceptor.d.ts +22 -0
- package/build/common/interceptors/logging.interceptor.d.ts.map +1 -0
- package/build/common/interceptors/logging.interceptor.js +67 -0
- package/build/common/interceptors/logging.interceptor.js.map +1 -0
- package/build/common/interfaces/cache-provider.interface.d.ts +54 -0
- package/build/common/interfaces/cache-provider.interface.d.ts.map +1 -0
- package/build/common/interfaces/cache-provider.interface.js +6 -0
- package/build/common/interfaces/cache-provider.interface.js.map +1 -0
- package/build/common/interfaces/index.d.ts +7 -0
- package/build/common/interfaces/index.d.ts.map +1 -0
- package/build/common/interfaces/index.js +3 -0
- package/build/common/interfaces/index.js.map +1 -0
- package/build/common/interfaces/log-context.interface.d.ts +77 -0
- package/build/common/interfaces/log-context.interface.d.ts.map +1 -0
- package/build/common/interfaces/log-context.interface.js +2 -0
- package/build/common/interfaces/log-context.interface.js.map +1 -0
- package/build/common/interfaces/log-entry.interface.d.ts +26 -0
- package/build/common/interfaces/log-entry.interface.d.ts.map +1 -0
- package/build/common/interfaces/log-entry.interface.js +33 -0
- package/build/common/interfaces/log-entry.interface.js.map +1 -0
- package/build/common/interfaces/logger.interface.d.ts +62 -0
- package/build/common/interfaces/logger.interface.d.ts.map +1 -0
- package/build/common/interfaces/logger.interface.js +2 -0
- package/build/common/interfaces/logger.interface.js.map +1 -0
- package/build/common/interfaces/metrics-exporter.interface.d.ts +275 -0
- package/build/common/interfaces/metrics-exporter.interface.d.ts.map +1 -0
- package/build/common/interfaces/metrics-exporter.interface.js +8 -0
- package/build/common/interfaces/metrics-exporter.interface.js.map +1 -0
- package/build/common/metrics/base-metrics-collector.d.ts +81 -0
- package/build/common/metrics/base-metrics-collector.d.ts.map +1 -0
- package/build/common/metrics/base-metrics-collector.js +88 -0
- package/build/common/metrics/base-metrics-collector.js.map +1 -0
- package/build/common/metrics/index.d.ts +2 -0
- package/build/common/metrics/index.d.ts.map +1 -0
- package/build/common/metrics/index.js +2 -0
- package/build/common/metrics/index.js.map +1 -0
- package/build/common/metrics.module.d.ts +50 -0
- package/build/common/metrics.module.d.ts.map +1 -0
- package/build/common/metrics.module.js +77 -0
- package/build/common/metrics.module.js.map +1 -0
- package/build/common/modules/throttler.module.d.ts +69 -0
- package/build/common/modules/throttler.module.d.ts.map +1 -0
- package/build/common/modules/throttler.module.js +117 -0
- package/build/common/modules/throttler.module.js.map +1 -0
- package/build/common/pipes/base-validation.pipe.d.ts +67 -0
- package/build/common/pipes/base-validation.pipe.d.ts.map +1 -0
- package/build/common/pipes/base-validation.pipe.js +95 -0
- package/build/common/pipes/base-validation.pipe.js.map +1 -0
- package/build/common/pipes/validation.pipe.d.ts +32 -0
- package/build/common/pipes/validation.pipe.d.ts.map +1 -0
- package/build/common/pipes/validation.pipe.js +60 -0
- package/build/common/pipes/validation.pipe.js.map +1 -0
- package/build/common/registry/instrumentation-registry.d.ts +227 -0
- package/build/common/registry/instrumentation-registry.d.ts.map +1 -0
- package/build/common/registry/instrumentation-registry.js +414 -0
- package/build/common/registry/instrumentation-registry.js.map +1 -0
- package/build/common/services/audit-logger.service.d.ts +91 -0
- package/build/common/services/audit-logger.service.d.ts.map +1 -0
- package/build/common/services/audit-logger.service.js +180 -0
- package/build/common/services/audit-logger.service.js.map +1 -0
- package/build/common/services/csrf.service.d.ts +202 -0
- package/build/common/services/csrf.service.d.ts.map +1 -0
- package/build/common/services/csrf.service.js +478 -0
- package/build/common/services/csrf.service.js.map +1 -0
- package/build/common/services/error-categorizer.service.d.ts +82 -0
- package/build/common/services/error-categorizer.service.d.ts.map +1 -0
- package/build/common/services/error-categorizer.service.js +339 -0
- package/build/common/services/error-categorizer.service.js.map +1 -0
- package/build/common/services/error-sanitizer.service.d.ts +146 -0
- package/build/common/services/error-sanitizer.service.d.ts.map +1 -0
- package/build/common/services/error-sanitizer.service.js +287 -0
- package/build/common/services/error-sanitizer.service.js.map +1 -0
- package/build/common/services/health-check.service.d.ts +86 -0
- package/build/common/services/health-check.service.d.ts.map +1 -0
- package/build/common/services/health-check.service.js +132 -0
- package/build/common/services/health-check.service.js.map +1 -0
- package/build/common/services/http-client.service.d.ts +113 -0
- package/build/common/services/http-client.service.d.ts.map +1 -0
- package/build/common/services/http-client.service.js +294 -0
- package/build/common/services/http-client.service.js.map +1 -0
- package/build/common/services/logger.service.d.ts +189 -0
- package/build/common/services/logger.service.d.ts.map +1 -0
- package/build/common/services/logger.service.js +423 -0
- package/build/common/services/logger.service.js.map +1 -0
- package/build/common/services/metrics-registry.service.d.ts +98 -0
- package/build/common/services/metrics-registry.service.d.ts.map +1 -0
- package/build/common/services/metrics-registry.service.js +262 -0
- package/build/common/services/metrics-registry.service.js.map +1 -0
- package/build/common/services/nest-logger-adapter.service.d.ts +62 -0
- package/build/common/services/nest-logger-adapter.service.d.ts.map +1 -0
- package/build/common/services/nest-logger-adapter.service.js +120 -0
- package/build/common/services/nest-logger-adapter.service.js.map +1 -0
- package/build/common/utils/error.utils.d.ts +16 -0
- package/build/common/utils/error.utils.d.ts.map +1 -0
- package/build/common/utils/error.utils.js +26 -0
- package/build/common/utils/error.utils.js.map +1 -0
- package/build/common/utils/lazy-getter.types.d.ts +190 -0
- package/build/common/utils/lazy-getter.types.d.ts.map +1 -0
- package/build/common/utils/lazy-getter.types.js +114 -0
- package/build/common/utils/lazy-getter.types.js.map +1 -0
- package/build/common/utils/module.utils.d.ts +33 -0
- package/build/common/utils/module.utils.d.ts.map +1 -0
- package/build/common/utils/module.utils.js +48 -0
- package/build/common/utils/module.utils.js.map +1 -0
- package/build/common/utils/sanitization.utils.d.ts +69 -0
- package/build/common/utils/sanitization.utils.d.ts.map +1 -0
- package/build/common/utils/sanitization.utils.js +141 -0
- package/build/common/utils/sanitization.utils.js.map +1 -0
- package/build/config/config.module.d.ts +30 -0
- package/build/config/config.module.d.ts.map +1 -0
- package/build/config/config.module.js +49 -0
- package/build/config/config.module.js.map +1 -0
- package/build/config/config.service.d.ts +74 -0
- package/build/config/config.service.d.ts.map +1 -0
- package/build/config/config.service.js +145 -0
- package/build/config/config.service.js.map +1 -0
- package/build/config/config.types.d.ts +143 -0
- package/build/config/config.types.d.ts.map +1 -0
- package/build/config/config.types.js +2 -0
- package/build/config/config.types.js.map +1 -0
- package/build/config/decorators/config.decorators.d.ts +43 -0
- package/build/config/decorators/config.decorators.d.ts.map +1 -0
- package/build/config/decorators/config.decorators.js +68 -0
- package/build/config/decorators/config.decorators.js.map +1 -0
- package/build/config/decorators/index.d.ts +2 -0
- package/build/config/decorators/index.d.ts.map +1 -0
- package/build/config/decorators/index.js +2 -0
- package/build/config/decorators/index.js.map +1 -0
- package/build/config/index.d.ts +7 -0
- package/build/config/index.d.ts.map +1 -0
- package/build/config/index.js +9 -0
- package/build/config/index.js.map +1 -0
- package/build/config/validation.utils.d.ts +136 -0
- package/build/config/validation.utils.d.ts.map +1 -0
- package/build/config/validation.utils.js +263 -0
- package/build/config/validation.utils.js.map +1 -0
- package/build/errors/index.d.ts +9 -0
- package/build/errors/index.d.ts.map +1 -0
- package/build/errors/index.js +12 -0
- package/build/errors/index.js.map +1 -0
- package/build/guards/custom-throttle.guard.d.ts +28 -0
- package/build/guards/custom-throttle.guard.d.ts.map +1 -0
- package/build/guards/custom-throttle.guard.js +52 -0
- package/build/guards/custom-throttle.guard.js.map +1 -0
- package/build/guards/index.d.ts +2 -0
- package/build/guards/index.d.ts.map +1 -0
- package/build/guards/index.js +2 -0
- package/build/guards/index.js.map +1 -0
- package/build/index.d.ts +53 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +61 -0
- package/build/index.js.map +1 -0
- package/build/logging/index.d.ts +7 -0
- package/build/logging/index.d.ts.map +1 -0
- package/build/logging/index.js +7 -0
- package/build/logging/index.js.map +1 -0
- package/build/metrics/index.d.ts +6 -0
- package/build/metrics/index.d.ts.map +1 -0
- package/build/metrics/index.js +11 -0
- package/build/metrics/index.js.map +1 -0
- package/build/package.json +72 -0
- package/build/security/index.d.ts +8 -0
- package/build/security/index.d.ts.map +1 -0
- package/build/security/index.js +11 -0
- package/build/security/index.js.map +1 -0
- package/build/test-setup.d.ts +2 -0
- package/build/test-setup.d.ts.map +1 -0
- package/build/test-setup.js +40 -0
- package/build/test-setup.js.map +1 -0
- package/build/validation/index.d.ts +6 -0
- package/build/validation/index.d.ts.map +1 -0
- package/build/validation/index.js +8 -0
- package/build/validation/index.js.map +1 -0
- package/package.json +71 -0
package/build/README.md
ADDED
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
# NestJS Shared Module
|
|
2
|
+
|
|
3
|
+
[](https://github.com/PhillipAWells/nestjs-common/releases)
|
|
4
|
+
[](https://github.com/PhillipAWells/nestjs-common/actions/workflows/ci.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/@pawells/nestjs-shared)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
[](https://github.com/sponsors/PhillipAWells)
|
|
9
|
+
|
|
10
|
+
Foundational NestJS infrastructure library providing filters, guards, interceptors, logging, CSRF protection, error handling, configuration, metrics, and lazy loading utilities.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
yarn add @pawells/nestjs-shared
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- **Node.js**: >= 24.0.0
|
|
21
|
+
- **NestJS**: >= 10.0.0
|
|
22
|
+
|
|
23
|
+
## Peer Dependencies
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"@nestjs/common": ">=10.0.0",
|
|
28
|
+
"@nestjs/config": ">=3.0.0",
|
|
29
|
+
"@nestjs/core": ">=10.0.0",
|
|
30
|
+
"@nestjs/throttler": ">=5.0.0",
|
|
31
|
+
"@opentelemetry/api": ">=1.0.0",
|
|
32
|
+
"class-transformer": ">=0.5.0",
|
|
33
|
+
"class-validator": ">=0.14.0",
|
|
34
|
+
"compression": ">=1.0.0",
|
|
35
|
+
"csrf-csrf": ">=3.0.0",
|
|
36
|
+
"express": ">=4.0.0",
|
|
37
|
+
"helmet": ">=7.0.0",
|
|
38
|
+
"joi": ">=17.0.0",
|
|
39
|
+
"prom-client": ">=15.0.0",
|
|
40
|
+
"rxjs": ">=7.0.0",
|
|
41
|
+
"xss": ">=1.0.0"
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
### 1. Initialize ConfigModule (MUST come first)
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { Module } from '@nestjs/common';
|
|
51
|
+
import { ConfigModule } from '@pawells/nestjs-shared';
|
|
52
|
+
|
|
53
|
+
@Module({
|
|
54
|
+
imports: [
|
|
55
|
+
ConfigModule, // Must be first
|
|
56
|
+
],
|
|
57
|
+
})
|
|
58
|
+
export class AppModule {}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. Import CommonModule
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { Module } from '@nestjs/common';
|
|
65
|
+
import { CommonModule } from '@pawells/nestjs-shared';
|
|
66
|
+
|
|
67
|
+
@Module({
|
|
68
|
+
imports: [
|
|
69
|
+
ConfigModule, // Must be first
|
|
70
|
+
CommonModule, // Depends on ConfigModule
|
|
71
|
+
],
|
|
72
|
+
})
|
|
73
|
+
export class AppModule {}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 3. Use Global Filters and Interceptors
|
|
77
|
+
|
|
78
|
+
Global filters and interceptors are automatically registered by CommonModule:
|
|
79
|
+
- **GlobalExceptionFilter** & **HttpExceptionFilter**: Standardized error responses
|
|
80
|
+
- **LoggingInterceptor**: Request/response logging
|
|
81
|
+
- **HTTPMetricsInterceptor**: HTTP metrics collection
|
|
82
|
+
- **ValidationPipe**: Automatic DTO validation
|
|
83
|
+
|
|
84
|
+
All are applied globally and available for injection in services.
|
|
85
|
+
|
|
86
|
+
## Features
|
|
87
|
+
|
|
88
|
+
### Error Handling
|
|
89
|
+
|
|
90
|
+
Comprehensive error handling with structured responses, categorization, and sanitization.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import {
|
|
94
|
+
BaseApplicationError,
|
|
95
|
+
GlobalExceptionFilter,
|
|
96
|
+
ErrorCategorizerService,
|
|
97
|
+
ErrorSanitizerService,
|
|
98
|
+
} from '@pawells/nestjs-shared';
|
|
99
|
+
|
|
100
|
+
// Create custom error
|
|
101
|
+
export class UserNotFoundError extends BaseApplicationError {
|
|
102
|
+
constructor(userId: string) {
|
|
103
|
+
super(`User ${userId} not found`, {
|
|
104
|
+
code: 'USER_NOT_FOUND',
|
|
105
|
+
statusCode: 404,
|
|
106
|
+
context: { userId }
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Throw it
|
|
112
|
+
throw new UserNotFoundError('123');
|
|
113
|
+
|
|
114
|
+
// Automatically caught by GlobalExceptionFilter
|
|
115
|
+
// Response includes code, message, timestamp, sanitized context, stack (dev only)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Error Categories**: Errors are automatically categorized as transient (retryable) or permanent (fail-fast) with recommended recovery strategies.
|
|
119
|
+
|
|
120
|
+
### Logging
|
|
121
|
+
|
|
122
|
+
Centralized, structured logging with automatic redaction of sensitive data.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { AppLogger } from '@pawells/nestjs-shared';
|
|
126
|
+
|
|
127
|
+
constructor(private logger: AppLogger) {}
|
|
128
|
+
|
|
129
|
+
// Flexible logging methods
|
|
130
|
+
this.logger.info('User created', 'UserService', { userId: '123' });
|
|
131
|
+
this.logger.debug('Cache hit', { metadata: { key: 'users:123' } });
|
|
132
|
+
this.logger.error('Database error', error.stack, { query: '...' });
|
|
133
|
+
this.logger.warn('Rate limit approaching', { context: 'RateLimiter' });
|
|
134
|
+
this.logger.fatal('System shutdown', { context: 'ShutdownService' });
|
|
135
|
+
|
|
136
|
+
// Automatic redaction of sensitive fields: passwords, tokens, API keys, emails, IPs
|
|
137
|
+
this.logger.info('Login attempt', { password: 'secret' });
|
|
138
|
+
// Logs: { password: '[REDACTED]' }
|
|
139
|
+
|
|
140
|
+
// OpenTelemetry integration: traceId and spanId automatically included
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Log Levels**: Controlled by LOG_LEVEL environment variable (debug, info, warn, error, fatal, silent).
|
|
144
|
+
|
|
145
|
+
### Metrics
|
|
146
|
+
|
|
147
|
+
Prometheus metrics for HTTP requests and custom metrics.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { MetricsRegistryService } from '@pawells/nestjs-shared';
|
|
151
|
+
|
|
152
|
+
constructor(private metrics: MetricsRegistryService) {}
|
|
153
|
+
|
|
154
|
+
// Record custom metrics
|
|
155
|
+
const orderCounter = this.metrics.createCounter(
|
|
156
|
+
'orders_total',
|
|
157
|
+
'Total orders processed'
|
|
158
|
+
);
|
|
159
|
+
orderCounter.inc({ status: 'completed' });
|
|
160
|
+
|
|
161
|
+
// HTTP metrics are automatic (duration, count, size)
|
|
162
|
+
// Access at GET /metrics in Prometheus format
|
|
163
|
+
const prometheusMetrics = await this.metrics.getMetrics();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Features**:
|
|
167
|
+
- Automatic HTTP request metrics (duration histogram, request counter, size histogram)
|
|
168
|
+
- Dynamic path normalization (UUIDs, ObjectIDs, numeric IDs → `:id`) to prevent unbounded cardinality
|
|
169
|
+
- Default Node.js metrics collection
|
|
170
|
+
- Custom metric creation (counter, gauge, histogram)
|
|
171
|
+
- Controlled by METRICS_ENABLED environment variable (default: true)
|
|
172
|
+
|
|
173
|
+
### CSRF Protection
|
|
174
|
+
|
|
175
|
+
Double-Submit Cookie pattern with per-IP rate limiting.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import { CSRFGuard, CSRFService } from '@pawells/nestjs-shared';
|
|
179
|
+
|
|
180
|
+
// Globally applied by CommonModule
|
|
181
|
+
// Or manually on specific controller
|
|
182
|
+
@UseGuards(CSRFGuard)
|
|
183
|
+
@Controller('api')
|
|
184
|
+
export class ApiController {
|
|
185
|
+
constructor(private csrf: CSRFService) {}
|
|
186
|
+
|
|
187
|
+
@Post('/form')
|
|
188
|
+
async submitForm(@Req() req: Request, @Res() res: Response) {
|
|
189
|
+
// Generate token
|
|
190
|
+
const token = await this.csrf.generateToken(req, res);
|
|
191
|
+
res.render('form', { csrfToken: token });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@Post('/process')
|
|
195
|
+
async processForm(@Req() req: Request) {
|
|
196
|
+
// Validation done automatically by CSRFGuard
|
|
197
|
+
// Safe methods (GET, HEAD, OPTIONS) bypass validation
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Features**:
|
|
203
|
+
- Token generation with rate limiting (10 per IP per 60s)
|
|
204
|
+
- Session binding or IP-based fallback
|
|
205
|
+
- Automatic pruning of stale timestamps
|
|
206
|
+
- Capacity monitoring with safety margins
|
|
207
|
+
- Configurable proxy trust for X-Forwarded-For header
|
|
208
|
+
- CSRF_SECRET entropy validation at startup
|
|
209
|
+
|
|
210
|
+
### Validation
|
|
211
|
+
|
|
212
|
+
Automatic DTO validation and transformation.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { IsEmail, IsNotEmpty, MinLength } from 'class-validator';
|
|
216
|
+
|
|
217
|
+
export class CreateUserDto {
|
|
218
|
+
@IsNotEmpty()
|
|
219
|
+
@IsEmail()
|
|
220
|
+
email: string;
|
|
221
|
+
|
|
222
|
+
@IsNotEmpty()
|
|
223
|
+
@MinLength(8)
|
|
224
|
+
password: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@Post()
|
|
228
|
+
async createUser(@Body() dto: CreateUserDto) {
|
|
229
|
+
// DTO automatically validated and transformed
|
|
230
|
+
// Validation errors formatted as error array with field paths
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Features**:
|
|
235
|
+
- Automatic DTO validation via ValidationPipe
|
|
236
|
+
- Nested object support with path prefixes
|
|
237
|
+
- Comprehensive error formatting
|
|
238
|
+
- Class transformation with class-transformer
|
|
239
|
+
|
|
240
|
+
### Health Checks
|
|
241
|
+
|
|
242
|
+
Kubernetes-ready health, readiness, and liveness probes.
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { HealthCheckService, HealthStatus } from '@pawells/nestjs-shared';
|
|
246
|
+
|
|
247
|
+
constructor(private health: HealthCheckService) {}
|
|
248
|
+
|
|
249
|
+
@Get('/health')
|
|
250
|
+
getHealth() {
|
|
251
|
+
return this.health.getHealth('my-service', '1.0.0');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@Get('/ready')
|
|
255
|
+
getReadiness() {
|
|
256
|
+
return this.health.getReadiness({
|
|
257
|
+
database: HealthStatus.OK,
|
|
258
|
+
cache: HealthStatus.OK,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@Get('/live')
|
|
263
|
+
getLiveness() {
|
|
264
|
+
return this.health.getLiveness();
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Configuration
|
|
269
|
+
|
|
270
|
+
Type-safe environment variable access with validation.
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
import { ConfigService } from '@pawells/nestjs-shared';
|
|
274
|
+
|
|
275
|
+
constructor(private config: ConfigService) {}
|
|
276
|
+
|
|
277
|
+
// Type-safe getters
|
|
278
|
+
const port = this.config.getNumber('PORT') ?? 3000;
|
|
279
|
+
const nodeEnv = this.config.getString('NODE_ENV') ?? 'development';
|
|
280
|
+
const dbUrl = this.config.getOrThrow('DATABASE_URL');
|
|
281
|
+
|
|
282
|
+
// Validation
|
|
283
|
+
this.config.validate({
|
|
284
|
+
PORT: { required: true },
|
|
285
|
+
DATABASE_URL: { required: true },
|
|
286
|
+
LOG_LEVEL: { required: false },
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Audit Logging
|
|
291
|
+
|
|
292
|
+
Security event logging for compliance and forensics.
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { AuditLoggerService } from '@pawells/nestjs-shared';
|
|
296
|
+
|
|
297
|
+
constructor(private audit: AuditLoggerService) {}
|
|
298
|
+
|
|
299
|
+
// Log authentication
|
|
300
|
+
this.audit.logAuthenticationAttempt('user@example.com', true, '192.168.1.1');
|
|
301
|
+
|
|
302
|
+
// Log authorization failure
|
|
303
|
+
this.audit.logAuthorizationFailure('user-123', 'documents', 'delete', '192.168.1.1');
|
|
304
|
+
|
|
305
|
+
// Log CSRF violations
|
|
306
|
+
this.audit.logCsrfViolation('192.168.1.1', '/api/users');
|
|
307
|
+
|
|
308
|
+
// Log custom security events
|
|
309
|
+
this.audit.logSecurityEvent({
|
|
310
|
+
userId: 'user-123',
|
|
311
|
+
action: 'password_change',
|
|
312
|
+
resource: 'users/123',
|
|
313
|
+
result: 'success',
|
|
314
|
+
ipAddress: '192.168.1.1'
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Lazy Loading
|
|
319
|
+
|
|
320
|
+
Defer dependency resolution to avoid circular dependencies.
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import {
|
|
324
|
+
LazyGetter,
|
|
325
|
+
LazyModuleRefService,
|
|
326
|
+
createMemoizedLazyGetter,
|
|
327
|
+
} from '@pawells/nestjs-shared';
|
|
328
|
+
|
|
329
|
+
@Injectable()
|
|
330
|
+
export class MyService implements LazyModuleRefService {
|
|
331
|
+
private readonly userService: LazyGetter<UserService> = createMemoizedLazyGetter(
|
|
332
|
+
() => this.moduleRef.get(UserService, { strict: false }),
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
constructor(public readonly Module: ModuleRef) {}
|
|
336
|
+
|
|
337
|
+
async getUser(id: string) {
|
|
338
|
+
// UserService resolved lazily on first call
|
|
339
|
+
return this.userService().getById(id);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Features**:
|
|
345
|
+
- LazyGetter<T>: Required dependency getter
|
|
346
|
+
- OptionalLazyGetter<T>: Optional dependency getter
|
|
347
|
+
- CreateMemoizedLazyGetter: Caching factory
|
|
348
|
+
- CreateOptionalLazyGetter: Safe optional resolution
|
|
349
|
+
- IsLazyModuleRefService: Type guard for pattern detection
|
|
350
|
+
|
|
351
|
+
### HTTP Client
|
|
352
|
+
|
|
353
|
+
Robust HTTP client with timeout, SSL/TLS, and sensitive data redaction.
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
import { HttpClientService } from '@pawells/nestjs-shared';
|
|
357
|
+
|
|
358
|
+
constructor(private http: HttpClientService) {}
|
|
359
|
+
|
|
360
|
+
// GET request
|
|
361
|
+
const response = await this.http.get<User>('https://api.example.com/users/123');
|
|
362
|
+
|
|
363
|
+
// POST request with custom timeout
|
|
364
|
+
const response = await this.http.post<User>(
|
|
365
|
+
'https://api.example.com/users',
|
|
366
|
+
{ name: 'John', email: 'john@example.com' },
|
|
367
|
+
{ timeout: 5000, correlationId: 'req-123' }
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
// HTTPS with custom CA certificate
|
|
371
|
+
const cert = fs.readFileSync('/path/to/ca.pem');
|
|
372
|
+
const response = await this.http.get(
|
|
373
|
+
'https://internal-api.local/data',
|
|
374
|
+
{ ca: cert }
|
|
375
|
+
);
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**Features**:
|
|
379
|
+
- Configurable timeouts (default: HTTP_CLIENT_TIMEOUT)
|
|
380
|
+
- SSL/TLS certificate validation (strict by default)
|
|
381
|
+
- Custom CA certificate support
|
|
382
|
+
- Payload size limit (10MB)
|
|
383
|
+
- Automatic content-type parsing
|
|
384
|
+
- Correlation ID support
|
|
385
|
+
- Sensitive data redaction in logs
|
|
386
|
+
- Duration tracking
|
|
387
|
+
|
|
388
|
+
### Decorators
|
|
389
|
+
|
|
390
|
+
Request property extractors for cleaner controller methods.
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import { Query, Params, Body, Headers, Cookies } from '@pawells/nestjs-shared';
|
|
394
|
+
|
|
395
|
+
@Controller('users')
|
|
396
|
+
export class UserController {
|
|
397
|
+
@Get(':id')
|
|
398
|
+
getUser(
|
|
399
|
+
@Params('id') id: string,
|
|
400
|
+
@Query('include') include?: string,
|
|
401
|
+
) {
|
|
402
|
+
// Route params and query params extracted
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
@Post()
|
|
406
|
+
createUser(
|
|
407
|
+
@Body() dto: CreateUserDto,
|
|
408
|
+
@Headers('authorization') auth?: string,
|
|
409
|
+
) {
|
|
410
|
+
// Body and headers extracted
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
@Get()
|
|
414
|
+
listUsers(@Cookies('sessionId') sessionId?: string) {
|
|
415
|
+
// Cookies extracted
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Core Modules
|
|
421
|
+
|
|
422
|
+
### CommonModule
|
|
423
|
+
|
|
424
|
+
Global module providing all shared infrastructure.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
// Automatically applied globally
|
|
428
|
+
@Global()
|
|
429
|
+
@Module({
|
|
430
|
+
providers: [
|
|
431
|
+
// Filters (global)
|
|
432
|
+
GlobalExceptionFilter,
|
|
433
|
+
HttpExceptionFilter,
|
|
434
|
+
|
|
435
|
+
// Interceptors (global)
|
|
436
|
+
LoggingInterceptor,
|
|
437
|
+
HTTPMetricsInterceptor,
|
|
438
|
+
|
|
439
|
+
// Pipe (global)
|
|
440
|
+
ValidationPipe,
|
|
441
|
+
|
|
442
|
+
// Services (injectable)
|
|
443
|
+
AppLogger,
|
|
444
|
+
AuditLoggerService,
|
|
445
|
+
CSRFService,
|
|
446
|
+
ErrorCategorizerService,
|
|
447
|
+
ErrorSanitizerService,
|
|
448
|
+
HttpClientService,
|
|
449
|
+
MetricsRegistryService,
|
|
450
|
+
HealthCheckService,
|
|
451
|
+
],
|
|
452
|
+
exports: [...],
|
|
453
|
+
})
|
|
454
|
+
export class CommonModule {}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### ConfigModule
|
|
458
|
+
|
|
459
|
+
Configuration service with validation.
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
@Module({
|
|
463
|
+
imports: [ConfigModule],
|
|
464
|
+
// ConfigService and ValidationService automatically available
|
|
465
|
+
})
|
|
466
|
+
export class AppModule {}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### MetricsModule
|
|
470
|
+
|
|
471
|
+
Prometheus metrics endpoint and collection.
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
// Automatically imported by CommonModule
|
|
475
|
+
// Provides:
|
|
476
|
+
// - MetricsRegistryService (injectable)
|
|
477
|
+
// - GET /metrics endpoint (Prometheus format)
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## API Reference
|
|
481
|
+
|
|
482
|
+
### Services
|
|
483
|
+
|
|
484
|
+
#### AppLogger
|
|
485
|
+
Structured logging service with context support, metadata, and automatic sensitive data redaction.
|
|
486
|
+
|
|
487
|
+
**Methods**:
|
|
488
|
+
- `debug(message, context?, metadata?)`: Debug level
|
|
489
|
+
- `info(message, context?, metadata?)`: Info level
|
|
490
|
+
- `warn(message, context?, metadata?)`: Warning level
|
|
491
|
+
- `error(message, trace?, context?, metadata?)`: Error level with optional stack trace
|
|
492
|
+
- `fatal(message, trace?, context?, metadata?)`: Fatal level with optional stack trace
|
|
493
|
+
- `createContextualLogger(context)`: Create child logger with context
|
|
494
|
+
|
|
495
|
+
#### ErrorCategorizerService
|
|
496
|
+
Classifies errors as transient/permanent and recommends recovery strategy.
|
|
497
|
+
|
|
498
|
+
**Methods**:
|
|
499
|
+
- `categorizeError(error)`: Returns ErrorCategory with type, retryable, strategy, backoffMs
|
|
500
|
+
- `isRetryable(error)`: Boolean check
|
|
501
|
+
- `logRecoveryAttempt(error, attempt, maxAttempts)`: Log retry attempt
|
|
502
|
+
- `logRecoverySuccess(error, attempts)`: Log successful recovery
|
|
503
|
+
- `logRecoveryFailed(error, attempts)`: Log failed recovery
|
|
504
|
+
|
|
505
|
+
#### ErrorSanitizerService
|
|
506
|
+
Removes sensitive information from error responses and logs.
|
|
507
|
+
|
|
508
|
+
**Methods**:
|
|
509
|
+
- `sanitizeErrorResponse(error, isDevelopment)`: Sanitize error for response
|
|
510
|
+
- `sanitizeMessage(message)`: Sanitize error message string
|
|
511
|
+
|
|
512
|
+
Redactions: File paths, database URIs, API keys, Bearer tokens, email addresses, IP addresses, sensitive field values.
|
|
513
|
+
|
|
514
|
+
#### CSRFService
|
|
515
|
+
CSRF token generation and validation with rate limiting.
|
|
516
|
+
|
|
517
|
+
**Methods**:
|
|
518
|
+
- `generateToken(req, res)`: Generate and set CSRF token (rate limited)
|
|
519
|
+
- `validateToken(req)`: Validate CSRF token
|
|
520
|
+
- `refreshToken(req, res)`: Generate new token after sensitive operation
|
|
521
|
+
- `getMiddleware()`: Get CSRF protection middleware
|
|
522
|
+
|
|
523
|
+
#### MetricsRegistryService
|
|
524
|
+
Prometheus metrics management.
|
|
525
|
+
|
|
526
|
+
**Methods**:
|
|
527
|
+
- `recordHttpRequest(method, route, statusCode, duration, size?)`: Record HTTP metrics
|
|
528
|
+
- `createCounter(name, help, labelNames?)`: Create counter metric
|
|
529
|
+
- `createGauge(name, help, labelNames?)`: Create gauge metric
|
|
530
|
+
- `createHistogram(name, help, labelNames?, buckets?)`: Create histogram metric
|
|
531
|
+
- `recordCounter(name, value?, labels?)`: Record counter value
|
|
532
|
+
- `recordGauge(name, value, labels?)`: Record gauge value
|
|
533
|
+
- `recordHistogram(name, value, labels?)`: Record histogram value
|
|
534
|
+
- `getMetrics()`: Get metrics in Prometheus format
|
|
535
|
+
- `getMetricsAsJSON()`: Get metrics as JSON
|
|
536
|
+
- `clear()`: Clear all metrics (testing)
|
|
537
|
+
|
|
538
|
+
#### HealthCheckService
|
|
539
|
+
Kubernetes health probes.
|
|
540
|
+
|
|
541
|
+
**Methods**:
|
|
542
|
+
- `getHealth(serviceName?, version?)`: General health check
|
|
543
|
+
- `getReadiness(checks?)`: Readiness probe (can receive traffic)
|
|
544
|
+
- `getLiveness()`: Liveness probe (is alive)
|
|
545
|
+
|
|
546
|
+
#### HttpClientService
|
|
547
|
+
HTTP client with timeout and SSL/TLS support.
|
|
548
|
+
|
|
549
|
+
**Methods**:
|
|
550
|
+
- `request<T>(options)`: Make HTTP request
|
|
551
|
+
- `get<T>(url, options?)`: GET request
|
|
552
|
+
- `post<T>(url, data?, options?)`: POST request
|
|
553
|
+
- `put<T>(url, data?, options?)`: PUT request
|
|
554
|
+
- `delete<T>(url, options?)`: DELETE request
|
|
555
|
+
|
|
556
|
+
#### ConfigService
|
|
557
|
+
Type-safe environment variable access.
|
|
558
|
+
|
|
559
|
+
**Methods**:
|
|
560
|
+
- `get<T>(propertyPath, defaultValue?)`: Get config value
|
|
561
|
+
- `getOrThrow<T>(propertyPath)`: Get or throw
|
|
562
|
+
- `getString(propertyPath, defaultValue?)`: Get as string
|
|
563
|
+
- `getNumber(propertyPath, defaultValue?)`: Get as number
|
|
564
|
+
- `validate(schema)`: Validate configuration
|
|
565
|
+
|
|
566
|
+
#### AuditLoggerService
|
|
567
|
+
Security event logging.
|
|
568
|
+
|
|
569
|
+
**Methods**:
|
|
570
|
+
- `logAuthenticationAttempt(email, success, ipAddress?, reason?)`
|
|
571
|
+
- `logAuthorizationFailure(userId, resource, action, ipAddress?)`
|
|
572
|
+
- `logTokenGeneration(userId, tokenType)`
|
|
573
|
+
- `logTokenRevocation(userId, reason)`
|
|
574
|
+
- `logRateLimitViolation(endpoint, ipAddress, limit)`
|
|
575
|
+
- `logCsrfViolation(ipAddress, endpoint)`
|
|
576
|
+
- `logConfigurationChange(userId, config, oldValue, newValue)`
|
|
577
|
+
- `logDataAccess(userId, resource, action)`
|
|
578
|
+
- `logSecurityEvent(entry)`
|
|
579
|
+
|
|
580
|
+
### Filters
|
|
581
|
+
|
|
582
|
+
#### GlobalExceptionFilter
|
|
583
|
+
Catches unhandled exceptions (except HttpException).
|
|
584
|
+
|
|
585
|
+
- Standardizes response format
|
|
586
|
+
- Sanitizes sensitive data
|
|
587
|
+
- Categorizes errors
|
|
588
|
+
- Logs with context
|
|
589
|
+
|
|
590
|
+
#### HttpExceptionFilter
|
|
591
|
+
Handles HTTP exceptions.
|
|
592
|
+
|
|
593
|
+
- Formats NestJS built-in exceptions
|
|
594
|
+
- Sanitizes responses
|
|
595
|
+
- Categorizes for logging
|
|
596
|
+
|
|
597
|
+
### Interceptors
|
|
598
|
+
|
|
599
|
+
#### LoggingInterceptor
|
|
600
|
+
Logs incoming requests and outgoing responses.
|
|
601
|
+
|
|
602
|
+
- Uses DEBUG level for /health and /metrics
|
|
603
|
+
- Uses INFO level for other requests
|
|
604
|
+
- Includes method, URL, IP, duration
|
|
605
|
+
|
|
606
|
+
#### HTTPMetricsInterceptor
|
|
607
|
+
Collects HTTP request metrics.
|
|
608
|
+
|
|
609
|
+
- Duration histogram
|
|
610
|
+
- Request counter
|
|
611
|
+
- Request size histogram
|
|
612
|
+
- Automatic route normalization
|
|
613
|
+
|
|
614
|
+
### Guards
|
|
615
|
+
|
|
616
|
+
#### CSRFGuard
|
|
617
|
+
Validates CSRF tokens on state-changing requests.
|
|
618
|
+
|
|
619
|
+
- Bypasses safe methods (GET, HEAD, OPTIONS)
|
|
620
|
+
- Enforces validation for POST/PUT/DELETE/PATCH
|
|
621
|
+
- Throws 403 on validation failure
|
|
622
|
+
- Logs violations to audit log
|
|
623
|
+
|
|
624
|
+
### Pipes
|
|
625
|
+
|
|
626
|
+
#### ValidationPipe
|
|
627
|
+
Validates DTOs using class-validator.
|
|
628
|
+
|
|
629
|
+
- Automatic transformation via class-transformer
|
|
630
|
+
- Nested object support with path prefixes
|
|
631
|
+
- Comprehensive error formatting
|
|
632
|
+
|
|
633
|
+
## Interfaces & Types
|
|
634
|
+
|
|
635
|
+
### ILogger
|
|
636
|
+
Basic logging interface without contextual logger creation.
|
|
637
|
+
|
|
638
|
+
### IContextualLogger
|
|
639
|
+
Extended logging with contextual logger creation.
|
|
640
|
+
|
|
641
|
+
### LazyModuleRefService
|
|
642
|
+
Interface for services using lazy ModuleRef pattern.
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
interface LazyModuleRefService {
|
|
646
|
+
Module: ModuleRef;
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### LazyGetter<T>
|
|
651
|
+
Function that returns a dependency.
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
type LazyGetter<T> = () => T;
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### OptionalLazyGetter<T>
|
|
658
|
+
Function that returns a dependency or undefined.
|
|
659
|
+
|
|
660
|
+
```typescript
|
|
661
|
+
type OptionalLazyGetter<T> = () => T | undefined;
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### ErrorCategory
|
|
665
|
+
Error classification for recovery strategy.
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
interface ErrorCategory {
|
|
669
|
+
type: 'transient' | 'permanent';
|
|
670
|
+
retryable: boolean;
|
|
671
|
+
strategy: 'retry' | 'fail' | 'backoff';
|
|
672
|
+
backoffMs?: number;
|
|
673
|
+
}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### IHealthCheck
|
|
677
|
+
Health check response structure.
|
|
678
|
+
|
|
679
|
+
```typescript
|
|
680
|
+
interface IHealthCheck {
|
|
681
|
+
status: string;
|
|
682
|
+
timestamp: string;
|
|
683
|
+
service?: string;
|
|
684
|
+
version?: string;
|
|
685
|
+
checks?: Record<string, string>;
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
## Conditional Exports
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
// Main exports (all major classes and utilities)
|
|
693
|
+
import { AppLogger, CSRFService } from '@pawells/nestjs-shared';
|
|
694
|
+
|
|
695
|
+
// Common-only exports (lower-level utilities)
|
|
696
|
+
import { CSRFService } from '@pawells/nestjs-shared/common';
|
|
697
|
+
|
|
698
|
+
// Lazy loader types
|
|
699
|
+
import { LazyGetter } from '@pawells/nestjs-shared/common/utils/lazy-getter.types';
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
## Configuration
|
|
703
|
+
|
|
704
|
+
### Environment Variables
|
|
705
|
+
|
|
706
|
+
- **NODE_ENV**: development, production, etc. (affects error details, logging)
|
|
707
|
+
- **LOG_LEVEL**: debug, info, warn, error, fatal, silent (default: info)
|
|
708
|
+
- **PORT**: Server port (default: 3000)
|
|
709
|
+
- **CSRF_SECRET**: Required for CSRF protection (min 32 chars, high entropy)
|
|
710
|
+
- **METRICS_ENABLED**: Enable metrics (default: true)
|
|
711
|
+
- **SERVICE_NAME**: Service name for logging (default: unknown-service)
|
|
712
|
+
|
|
713
|
+
### CSRF_SECRET Generation
|
|
714
|
+
|
|
715
|
+
```bash
|
|
716
|
+
# Generate secure CSRF_SECRET
|
|
717
|
+
openssl rand -hex 32
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
## Security Defaults
|
|
721
|
+
|
|
722
|
+
- **Token Blacklist** (when implemented): Fails closed — treats unavailable cache as blacklist
|
|
723
|
+
- **CSRF Token Generation**: Per-IP rate limited (10 per 60s)
|
|
724
|
+
- **CSRF Validation**: Signed tokens with session/IP binding
|
|
725
|
+
- **Error Sanitization**: Stack traces only in development; sensitive fields redacted
|
|
726
|
+
- **CORS**: Implemented via security bootstrap (if configured)
|
|
727
|
+
- **HTTP Client**: Strict SSL/TLS certificate validation (rejectUnauthorized: true)
|
|
728
|
+
- **Metrics**: Dynamic path normalization prevents unbounded cardinality
|
|
729
|
+
- **Logging**: Automatic redaction of passwords, tokens, API keys, emails, IPs
|
|
730
|
+
|
|
731
|
+
## Examples
|
|
732
|
+
|
|
733
|
+
### Complete Application Setup
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
import { NestFactory } from '@nestjs/core';
|
|
737
|
+
import { ConfigModule, CommonModule, MetricsModule } from '@pawells/nestjs-shared';
|
|
738
|
+
|
|
739
|
+
@Module({
|
|
740
|
+
imports: [
|
|
741
|
+
ConfigModule, // MUST be first
|
|
742
|
+
CommonModule, // Depends on ConfigModule
|
|
743
|
+
MetricsModule.forRoot(), // Optional: Prometheus metrics
|
|
744
|
+
// ... feature modules
|
|
745
|
+
],
|
|
746
|
+
})
|
|
747
|
+
export class AppModule {}
|
|
748
|
+
|
|
749
|
+
async function bootstrap() {
|
|
750
|
+
const app = await NestFactory.create(AppModule);
|
|
751
|
+
|
|
752
|
+
// All filters, interceptors, pipes already registered globally
|
|
753
|
+
|
|
754
|
+
const port = process.env['PORT'] ?? 3000;
|
|
755
|
+
await app.listen(port);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
bootstrap();
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### Custom Error Handling
|
|
762
|
+
|
|
763
|
+
```typescript
|
|
764
|
+
import { BaseApplicationError, ErrorCategorizerService } from '@pawells/nestjs-shared';
|
|
765
|
+
|
|
766
|
+
export class InsufficientFundsError extends BaseApplicationError {
|
|
767
|
+
constructor(required: number, available: number) {
|
|
768
|
+
super(`Insufficient funds: need ${required}, have ${available}`, {
|
|
769
|
+
code: 'INSUFFICIENT_FUNDS',
|
|
770
|
+
statusCode: 402,
|
|
771
|
+
context: { required, available }
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// In service
|
|
777
|
+
@Catch(InsufficientFundsError)
|
|
778
|
+
export class PaymentService {
|
|
779
|
+
constructor(private errorCategorizer: ErrorCategorizerService) {}
|
|
780
|
+
|
|
781
|
+
async processPayment(amount: number) {
|
|
782
|
+
if (amount > balance) {
|
|
783
|
+
const error = new InsufficientFundsError(amount, balance);
|
|
784
|
+
// Automatically caught by GlobalExceptionFilter
|
|
785
|
+
// Categorized by ErrorCategorizerService (permanent/fail)
|
|
786
|
+
// Sanitized by ErrorSanitizerService
|
|
787
|
+
throw error;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
## Related Packages
|
|
794
|
+
|
|
795
|
+
- **[@pawells/nestjs-auth](https://www.npmjs.com/package/@pawells/nestjs-auth)** - JWT, sessions, OAuth/OIDC, Keycloak
|
|
796
|
+
- **[@pawells/nestjs-graphql](https://www.npmjs.com/package/@pawells/nestjs-graphql)** - GraphQL with caching and subscriptions
|
|
797
|
+
- **[@pawells/nestjs-open-telemetry](https://www.npmjs.com/package/@pawells/nestjs-open-telemetry)** - OpenTelemetry tracing
|
|
798
|
+
- **[@pawells/nestjs-prometheus](https://www.npmjs.com/package/@pawells/nestjs-prometheus)** - Prometheus metrics exporter
|
|
799
|
+
|
|
800
|
+
## License
|
|
801
|
+
|
|
802
|
+
MIT
|