@dyanet/nestjs-config-aws 1.0.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 +21 -0
- package/README.md +1183 -0
- package/dist/cjs/config.module.js +178 -0
- package/dist/cjs/config.module.js.map +1 -0
- package/dist/cjs/index.js +47 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/integration/index.js +23 -0
- package/dist/cjs/integration/index.js.map +1 -0
- package/dist/cjs/integration/interfaces/configuration-factory.interface.js +3 -0
- package/dist/cjs/integration/interfaces/configuration-factory.interface.js.map +1 -0
- package/dist/cjs/integration/interfaces/configuration-source.interface.js +3 -0
- package/dist/cjs/integration/interfaces/configuration-source.interface.js.map +1 -0
- package/dist/cjs/integration/interfaces/index.js +26 -0
- package/dist/cjs/integration/interfaces/index.js.map +1 -0
- package/dist/cjs/integration/interfaces/integration-options.interface.js +3 -0
- package/dist/cjs/integration/interfaces/integration-options.interface.js.map +1 -0
- package/dist/cjs/integration/interfaces/integration-state.interface.js +3 -0
- package/dist/cjs/integration/interfaces/integration-state.interface.js.map +1 -0
- package/dist/cjs/integration/interfaces/nestjs-config-compatibility.interface.js +73 -0
- package/dist/cjs/integration/interfaces/nestjs-config-compatibility.interface.js.map +1 -0
- package/dist/cjs/integration/interfaces/nestjs-config-integration.interface.js +3 -0
- package/dist/cjs/integration/interfaces/nestjs-config-integration.interface.js.map +1 -0
- package/dist/cjs/integration/interfaces/typed-configuration.interface.js +4 -0
- package/dist/cjs/integration/interfaces/typed-configuration.interface.js.map +1 -0
- package/dist/cjs/integration/interfaces/utility-types.interface.js +52 -0
- package/dist/cjs/integration/interfaces/utility-types.interface.js.map +1 -0
- package/dist/cjs/integration/nestjs-config-integration.module.js +124 -0
- package/dist/cjs/integration/nestjs-config-integration.module.js.map +1 -0
- package/dist/cjs/integration/providers/aws-configuration-loader.service.js +591 -0
- package/dist/cjs/integration/providers/aws-configuration-loader.service.js.map +1 -0
- package/dist/cjs/integration/providers/configuration-factory.provider.js +383 -0
- package/dist/cjs/integration/providers/configuration-factory.provider.js.map +1 -0
- package/dist/cjs/integration/providers/index.js +20 -0
- package/dist/cjs/integration/providers/index.js.map +1 -0
- package/dist/cjs/integration/services/async-config-helper.service.js +356 -0
- package/dist/cjs/integration/services/async-config-helper.service.js.map +1 -0
- package/dist/cjs/integration/services/error-handler.service.js +265 -0
- package/dist/cjs/integration/services/error-handler.service.js.map +1 -0
- package/dist/cjs/integration/services/factory-registration.service.js +512 -0
- package/dist/cjs/integration/services/factory-registration.service.js.map +1 -0
- package/dist/cjs/integration/services/index.js +26 -0
- package/dist/cjs/integration/services/index.js.map +1 -0
- package/dist/cjs/integration/services/integration-state.service.js +83 -0
- package/dist/cjs/integration/services/integration-state.service.js.map +1 -0
- package/dist/cjs/integration/services/namespace-handler.service.js +467 -0
- package/dist/cjs/integration/services/namespace-handler.service.js.map +1 -0
- package/dist/cjs/integration/services/nestjs-config-integration.service.js +316 -0
- package/dist/cjs/integration/services/nestjs-config-integration.service.js.map +1 -0
- package/dist/cjs/integration/services/precedence-handler.service.js +294 -0
- package/dist/cjs/integration/services/precedence-handler.service.js.map +1 -0
- package/dist/cjs/integration/services/validation-integration.service.js +591 -0
- package/dist/cjs/integration/services/validation-integration.service.js.map +1 -0
- package/dist/cjs/integration/utils/config-integration.util.js +283 -0
- package/dist/cjs/integration/utils/config-integration.util.js.map +1 -0
- package/dist/cjs/integration/utils/index.js +19 -0
- package/dist/cjs/integration/utils/index.js.map +1 -0
- package/dist/cjs/interfaces/config-loader.interface.js +3 -0
- package/dist/cjs/interfaces/config-loader.interface.js.map +1 -0
- package/dist/cjs/interfaces/config-service.interface.js +11 -0
- package/dist/cjs/interfaces/config-service.interface.js.map +1 -0
- package/dist/cjs/interfaces/default-schema.interface.js +63 -0
- package/dist/cjs/interfaces/default-schema.interface.js.map +1 -0
- package/dist/cjs/interfaces/errors.interface.js +77 -0
- package/dist/cjs/interfaces/errors.interface.js.map +1 -0
- package/dist/cjs/interfaces/index.js +25 -0
- package/dist/cjs/interfaces/index.js.map +1 -0
- package/dist/cjs/interfaces/module-options.interface.js +3 -0
- package/dist/cjs/interfaces/module-options.interface.js.map +1 -0
- package/dist/cjs/loaders/environment.loader.js +59 -0
- package/dist/cjs/loaders/environment.loader.js.map +1 -0
- package/dist/cjs/loaders/secrets-manager.loader.js +122 -0
- package/dist/cjs/loaders/secrets-manager.loader.js.map +1 -0
- package/dist/cjs/loaders/ssm-parameter-store.loader.js +146 -0
- package/dist/cjs/loaders/ssm-parameter-store.loader.js.map +1 -0
- package/dist/cjs/services/config.service.js +297 -0
- package/dist/cjs/services/config.service.js.map +1 -0
- package/dist/cjs/utils/validation.util.js +114 -0
- package/dist/cjs/utils/validation.util.js.map +1 -0
- package/dist/esm/config.module.js +175 -0
- package/dist/esm/config.module.js.map +1 -0
- package/dist/esm/index.js +18 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/integration/index.js +7 -0
- package/dist/esm/integration/index.js.map +1 -0
- package/dist/esm/integration/interfaces/configuration-factory.interface.js +2 -0
- package/dist/esm/integration/interfaces/configuration-factory.interface.js.map +1 -0
- package/dist/esm/integration/interfaces/configuration-source.interface.js +2 -0
- package/dist/esm/integration/interfaces/configuration-source.interface.js.map +1 -0
- package/dist/esm/integration/interfaces/index.js +10 -0
- package/dist/esm/integration/interfaces/index.js.map +1 -0
- package/dist/esm/integration/interfaces/integration-options.interface.js +2 -0
- package/dist/esm/integration/interfaces/integration-options.interface.js.map +1 -0
- package/dist/esm/integration/interfaces/integration-state.interface.js +2 -0
- package/dist/esm/integration/interfaces/integration-state.interface.js.map +1 -0
- package/dist/esm/integration/interfaces/nestjs-config-compatibility.interface.js +64 -0
- package/dist/esm/integration/interfaces/nestjs-config-compatibility.interface.js.map +1 -0
- package/dist/esm/integration/interfaces/nestjs-config-integration.interface.js +2 -0
- package/dist/esm/integration/interfaces/nestjs-config-integration.interface.js.map +1 -0
- package/dist/esm/integration/interfaces/typed-configuration.interface.js +3 -0
- package/dist/esm/integration/interfaces/typed-configuration.interface.js.map +1 -0
- package/dist/esm/integration/interfaces/utility-types.interface.js +44 -0
- package/dist/esm/integration/interfaces/utility-types.interface.js.map +1 -0
- package/dist/esm/integration/nestjs-config-integration.module.js +121 -0
- package/dist/esm/integration/nestjs-config-integration.module.js.map +1 -0
- package/dist/esm/integration/providers/aws-configuration-loader.service.js +588 -0
- package/dist/esm/integration/providers/aws-configuration-loader.service.js.map +1 -0
- package/dist/esm/integration/providers/configuration-factory.provider.js +380 -0
- package/dist/esm/integration/providers/configuration-factory.provider.js.map +1 -0
- package/dist/esm/integration/providers/index.js +4 -0
- package/dist/esm/integration/providers/index.js.map +1 -0
- package/dist/esm/integration/services/async-config-helper.service.js +353 -0
- package/dist/esm/integration/services/async-config-helper.service.js.map +1 -0
- package/dist/esm/integration/services/error-handler.service.js +262 -0
- package/dist/esm/integration/services/error-handler.service.js.map +1 -0
- package/dist/esm/integration/services/factory-registration.service.js +509 -0
- package/dist/esm/integration/services/factory-registration.service.js.map +1 -0
- package/dist/esm/integration/services/index.js +10 -0
- package/dist/esm/integration/services/index.js.map +1 -0
- package/dist/esm/integration/services/integration-state.service.js +80 -0
- package/dist/esm/integration/services/integration-state.service.js.map +1 -0
- package/dist/esm/integration/services/namespace-handler.service.js +464 -0
- package/dist/esm/integration/services/namespace-handler.service.js.map +1 -0
- package/dist/esm/integration/services/nestjs-config-integration.service.js +313 -0
- package/dist/esm/integration/services/nestjs-config-integration.service.js.map +1 -0
- package/dist/esm/integration/services/precedence-handler.service.js +291 -0
- package/dist/esm/integration/services/precedence-handler.service.js.map +1 -0
- package/dist/esm/integration/services/validation-integration.service.js +585 -0
- package/dist/esm/integration/services/validation-integration.service.js.map +1 -0
- package/dist/esm/integration/utils/config-integration.util.js +240 -0
- package/dist/esm/integration/utils/config-integration.util.js.map +1 -0
- package/dist/esm/integration/utils/index.js +3 -0
- package/dist/esm/integration/utils/index.js.map +1 -0
- package/dist/esm/interfaces/config-loader.interface.js +2 -0
- package/dist/esm/interfaces/config-loader.interface.js.map +1 -0
- package/dist/esm/interfaces/config-service.interface.js +7 -0
- package/dist/esm/interfaces/config-service.interface.js.map +1 -0
- package/dist/esm/interfaces/default-schema.interface.js +59 -0
- package/dist/esm/interfaces/default-schema.interface.js.map +1 -0
- package/dist/esm/interfaces/errors.interface.js +69 -0
- package/dist/esm/interfaces/errors.interface.js.map +1 -0
- package/dist/esm/interfaces/index.js +9 -0
- package/dist/esm/interfaces/index.js.map +1 -0
- package/dist/esm/interfaces/module-options.interface.js +2 -0
- package/dist/esm/interfaces/module-options.interface.js.map +1 -0
- package/dist/esm/loaders/environment.loader.js +55 -0
- package/dist/esm/loaders/environment.loader.js.map +1 -0
- package/dist/esm/loaders/secrets-manager.loader.js +118 -0
- package/dist/esm/loaders/secrets-manager.loader.js.map +1 -0
- package/dist/esm/loaders/ssm-parameter-store.loader.js +142 -0
- package/dist/esm/loaders/ssm-parameter-store.loader.js.map +1 -0
- package/dist/esm/services/config.service.js +261 -0
- package/dist/esm/services/config.service.js.map +1 -0
- package/dist/esm/utils/validation.util.js +110 -0
- package/dist/esm/utils/validation.util.js.map +1 -0
- package/dist/types/config.module.d.ts +46 -0
- package/dist/types/config.module.d.ts.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/integration/index.d.ts +6 -0
- package/dist/types/integration/index.d.ts.map +1 -0
- package/dist/types/integration/interfaces/configuration-factory.interface.d.ts +71 -0
- package/dist/types/integration/interfaces/configuration-factory.interface.d.ts.map +1 -0
- package/dist/types/integration/interfaces/configuration-source.interface.d.ts +24 -0
- package/dist/types/integration/interfaces/configuration-source.interface.d.ts.map +1 -0
- package/dist/types/integration/interfaces/index.d.ts +9 -0
- package/dist/types/integration/interfaces/index.d.ts.map +1 -0
- package/dist/types/integration/interfaces/integration-options.interface.d.ts +66 -0
- package/dist/types/integration/interfaces/integration-options.interface.d.ts.map +1 -0
- package/dist/types/integration/interfaces/integration-state.interface.d.ts +17 -0
- package/dist/types/integration/interfaces/integration-state.interface.d.ts.map +1 -0
- package/dist/types/integration/interfaces/nestjs-config-compatibility.interface.d.ts +332 -0
- package/dist/types/integration/interfaces/nestjs-config-compatibility.interface.d.ts.map +1 -0
- package/dist/types/integration/interfaces/nestjs-config-integration.interface.d.ts +259 -0
- package/dist/types/integration/interfaces/nestjs-config-integration.interface.d.ts.map +1 -0
- package/dist/types/integration/interfaces/typed-configuration.interface.d.ts +209 -0
- package/dist/types/integration/interfaces/typed-configuration.interface.d.ts.map +1 -0
- package/dist/types/integration/interfaces/utility-types.interface.d.ts +249 -0
- package/dist/types/integration/interfaces/utility-types.interface.d.ts.map +1 -0
- package/dist/types/integration/nestjs-config-integration.module.d.ts +36 -0
- package/dist/types/integration/nestjs-config-integration.module.d.ts.map +1 -0
- package/dist/types/integration/providers/aws-configuration-loader.service.d.ts +134 -0
- package/dist/types/integration/providers/aws-configuration-loader.service.d.ts.map +1 -0
- package/dist/types/integration/providers/configuration-factory.provider.d.ts +119 -0
- package/dist/types/integration/providers/configuration-factory.provider.d.ts.map +1 -0
- package/dist/types/integration/providers/index.d.ts +3 -0
- package/dist/types/integration/providers/index.d.ts.map +1 -0
- package/dist/types/integration/services/async-config-helper.service.d.ts +84 -0
- package/dist/types/integration/services/async-config-helper.service.d.ts.map +1 -0
- package/dist/types/integration/services/error-handler.service.d.ts +84 -0
- package/dist/types/integration/services/error-handler.service.d.ts.map +1 -0
- package/dist/types/integration/services/factory-registration.service.d.ts +158 -0
- package/dist/types/integration/services/factory-registration.service.d.ts.map +1 -0
- package/dist/types/integration/services/index.d.ts +9 -0
- package/dist/types/integration/services/index.d.ts.map +1 -0
- package/dist/types/integration/services/integration-state.service.d.ts +41 -0
- package/dist/types/integration/services/integration-state.service.d.ts.map +1 -0
- package/dist/types/integration/services/namespace-handler.service.d.ts +192 -0
- package/dist/types/integration/services/namespace-handler.service.d.ts.map +1 -0
- package/dist/types/integration/services/nestjs-config-integration.service.d.ts +87 -0
- package/dist/types/integration/services/nestjs-config-integration.service.d.ts.map +1 -0
- package/dist/types/integration/services/precedence-handler.service.d.ts +103 -0
- package/dist/types/integration/services/precedence-handler.service.d.ts.map +1 -0
- package/dist/types/integration/services/validation-integration.service.d.ts +222 -0
- package/dist/types/integration/services/validation-integration.service.d.ts.map +1 -0
- package/dist/types/integration/utils/config-integration.util.d.ts +81 -0
- package/dist/types/integration/utils/config-integration.util.d.ts.map +1 -0
- package/dist/types/integration/utils/index.d.ts +2 -0
- package/dist/types/integration/utils/index.d.ts.map +1 -0
- package/dist/types/interfaces/config-loader.interface.d.ts +22 -0
- package/dist/types/interfaces/config-loader.interface.d.ts.map +1 -0
- package/dist/types/interfaces/config-service.interface.d.ts +23 -0
- package/dist/types/interfaces/config-service.interface.d.ts.map +1 -0
- package/dist/types/interfaces/default-schema.interface.d.ts +195 -0
- package/dist/types/interfaces/default-schema.interface.d.ts.map +1 -0
- package/dist/types/interfaces/errors.interface.d.ts +38 -0
- package/dist/types/interfaces/errors.interface.d.ts.map +1 -0
- package/dist/types/interfaces/index.d.ts +6 -0
- package/dist/types/interfaces/index.d.ts.map +1 -0
- package/dist/types/interfaces/module-options.interface.d.ts +64 -0
- package/dist/types/interfaces/module-options.interface.d.ts.map +1 -0
- package/dist/types/loaders/environment.loader.d.ts +26 -0
- package/dist/types/loaders/environment.loader.d.ts.map +1 -0
- package/dist/types/loaders/secrets-manager.loader.d.ts +52 -0
- package/dist/types/loaders/secrets-manager.loader.d.ts.map +1 -0
- package/dist/types/loaders/ssm-parameter-store.loader.d.ts +68 -0
- package/dist/types/loaders/ssm-parameter-store.loader.d.ts.map +1 -0
- package/dist/types/services/config.service.d.ts +94 -0
- package/dist/types/services/config.service.d.ts.map +1 -0
- package/dist/types/utils/validation.util.d.ts +53 -0
- package/dist/types/utils/validation.util.d.ts.map +1 -0
- package/package.json +102 -0
package/README.md
ADDED
|
@@ -0,0 +1,1183 @@
|
|
|
1
|
+
# nestjs-config-aws
|
|
2
|
+
|
|
3
|
+
AWS-integrated configuration management for NestJS applications with support for environment variables, AWS Secrets Manager, and AWS Systems Manager Parameter Store. **Includes seamless @nestjs/config integration for maximum compatibility.**
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔧 **Environment Variable Loading**: Automatic loading from `process.env`
|
|
8
|
+
- 🔐 **AWS Secrets Manager Integration**: Secure secret management with environment-aware paths
|
|
9
|
+
- 📋 **AWS Systems Manager Parameter Store**: Hierarchical parameter management
|
|
10
|
+
- 🛡️ **Type-Safe Configuration**: Full TypeScript support with Zod validation
|
|
11
|
+
- 🌍 **Environment-Aware Loading**: Automatic configuration based on `APP_ENV`
|
|
12
|
+
- 📦 **Zero-Configuration Setup**: Works out of the box with sensible defaults
|
|
13
|
+
- 🔄 **Configuration Merging**: Intelligent precedence handling across sources
|
|
14
|
+
- ⚡ **Performance Optimized**: Efficient loading with caching and pagination support
|
|
15
|
+
- 🤝 **@nestjs/config Integration**: Use AWS-sourced values through standard @nestjs/config patterns
|
|
16
|
+
- 🔀 **Flexible Precedence Rules**: aws-first, local-first, or merge strategies for configuration conflicts
|
|
17
|
+
|
|
18
|
+
## Table of Contents
|
|
19
|
+
|
|
20
|
+
- [Installation](#installation)
|
|
21
|
+
- [Quick Start](#quick-start)
|
|
22
|
+
- [Configuration](#configuration)
|
|
23
|
+
- [Environment Variables](#environment-variables)
|
|
24
|
+
- [Usage Examples](#usage-examples)
|
|
25
|
+
- [@nestjs/config Integration](#nestjsconfig-integration)
|
|
26
|
+
- [API Reference](#api-reference)
|
|
27
|
+
- [Troubleshooting](#troubleshooting)
|
|
28
|
+
- [Examples](#examples)
|
|
29
|
+
- [Contributing](#contributing)
|
|
30
|
+
- [License](#license)
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
### Standalone Usage
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install nestjs-config-aws
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### @nestjs/config Integration
|
|
41
|
+
|
|
42
|
+
For seamless integration with the standard @nestjs/config module:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install nestjs-config-aws @nestjs/config
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Peer Dependencies
|
|
49
|
+
|
|
50
|
+
Make sure you have the following peer dependencies installed:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install @nestjs/common @nestjs/core zod
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For @nestjs/config integration, `@nestjs/config` is also required as a peer dependency.
|
|
57
|
+
|
|
58
|
+
### AWS Dependencies
|
|
59
|
+
|
|
60
|
+
The module automatically includes the necessary AWS SDK dependencies:
|
|
61
|
+
- `@aws-sdk/client-secrets-manager`
|
|
62
|
+
- `@aws-sdk/client-ssm`
|
|
63
|
+
- `@aws-sdk/credential-providers`
|
|
64
|
+
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
Choose your preferred integration approach:
|
|
68
|
+
|
|
69
|
+
### Option 1: Standalone Usage
|
|
70
|
+
|
|
71
|
+
Use nestjs-config-aws as your primary configuration module:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { Module } from '@nestjs/common';
|
|
75
|
+
import { ConfigModule } from 'nestjs-config-aws';
|
|
76
|
+
|
|
77
|
+
@Module({
|
|
78
|
+
imports: [
|
|
79
|
+
ConfigModule.forRoot(), // Uses default configuration
|
|
80
|
+
],
|
|
81
|
+
})
|
|
82
|
+
export class AppModule {}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Option 2: @nestjs/config Integration (Recommended)
|
|
86
|
+
|
|
87
|
+
Integrate with the standard @nestjs/config for maximum compatibility:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { Module } from '@nestjs/common';
|
|
91
|
+
import { ConfigModule } from '@nestjs/config';
|
|
92
|
+
import { NestConfigAwsIntegrationModule } from 'nestjs-config-aws';
|
|
93
|
+
|
|
94
|
+
@Module({
|
|
95
|
+
imports: [
|
|
96
|
+
// Step 1: AWS Integration (must be first)
|
|
97
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
98
|
+
secretsManagerConfig: { enabled: true },
|
|
99
|
+
precedence: 'aws-first'
|
|
100
|
+
}),
|
|
101
|
+
|
|
102
|
+
// Step 2: Standard @nestjs/config (must be after)
|
|
103
|
+
ConfigModule.forRoot({ isGlobal: true })
|
|
104
|
+
],
|
|
105
|
+
})
|
|
106
|
+
export class AppModule {}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### With Custom Schema (Standalone)
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { Module } from '@nestjs/common';
|
|
113
|
+
import { ConfigModule } from 'nestjs-config-aws';
|
|
114
|
+
import { z } from 'zod';
|
|
115
|
+
|
|
116
|
+
const configSchema = z.object({
|
|
117
|
+
PORT: z.coerce.number().default(3000),
|
|
118
|
+
DATABASE_URL: z.string(),
|
|
119
|
+
API_KEY: z.string(),
|
|
120
|
+
DEBUG: z.coerce.boolean().default(false),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
@Module({
|
|
124
|
+
imports: [
|
|
125
|
+
ConfigModule.forRoot({
|
|
126
|
+
schema: configSchema,
|
|
127
|
+
}),
|
|
128
|
+
],
|
|
129
|
+
})
|
|
130
|
+
export class AppModule {}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Service Usage
|
|
134
|
+
|
|
135
|
+
Both approaches use the same service patterns:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { Injectable } from '@nestjs/common';
|
|
139
|
+
// For standalone: import { ConfigService } from 'nestjs-config-aws';
|
|
140
|
+
// For integration: import { ConfigService } from '@nestjs/config';
|
|
141
|
+
import { ConfigService } from '@nestjs/config';
|
|
142
|
+
|
|
143
|
+
@Injectable()
|
|
144
|
+
export class AppService {
|
|
145
|
+
constructor(private configService: ConfigService) {}
|
|
146
|
+
|
|
147
|
+
getPort(): number {
|
|
148
|
+
return this.configService.get('PORT'); // Values can come from AWS
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
getDatabaseUrl(): string {
|
|
152
|
+
// This value can come from AWS Secrets Manager
|
|
153
|
+
return this.configService.get('DATABASE_URL');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Configuration
|
|
159
|
+
|
|
160
|
+
### Module Options
|
|
161
|
+
|
|
162
|
+
The `ConfigModule.forRoot()` method accepts the following options:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
interface NestConfigAwsModuleOptions<T = any> {
|
|
166
|
+
schema?: ZodType<T>;
|
|
167
|
+
secretsManagerConfig?: SecretsManagerConfig;
|
|
168
|
+
ssmConfig?: SSMConfig;
|
|
169
|
+
envPrefix?: string;
|
|
170
|
+
ignoreValidationErrors?: boolean;
|
|
171
|
+
appEnvVariable?: string;
|
|
172
|
+
loadSync?: boolean;
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### AWS Secrets Manager Configuration
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
interface SecretsManagerConfig {
|
|
180
|
+
region?: string;
|
|
181
|
+
paths?: {
|
|
182
|
+
development?: string;
|
|
183
|
+
test?: string;
|
|
184
|
+
production?: string;
|
|
185
|
+
};
|
|
186
|
+
enabled?: boolean;
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### AWS SSM Parameter Store Configuration
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
interface SSMConfig {
|
|
194
|
+
region?: string;
|
|
195
|
+
paths?: {
|
|
196
|
+
development?: string;
|
|
197
|
+
test?: string;
|
|
198
|
+
production?: string;
|
|
199
|
+
};
|
|
200
|
+
enabled?: boolean;
|
|
201
|
+
decrypt?: boolean;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Environment Variables
|
|
206
|
+
|
|
207
|
+
### Core Environment Variables
|
|
208
|
+
|
|
209
|
+
| Variable | Description | Default | Required |
|
|
210
|
+
|----------|-------------|---------|----------|
|
|
211
|
+
| `APP_ENV` | Application environment | `local` | No |
|
|
212
|
+
| `NODE_ENV` | Node.js environment | - | No |
|
|
213
|
+
| `AWS_REGION` | AWS region for services | Auto-detected | No |
|
|
214
|
+
| `AWS_PROFILE` | AWS profile for local development | - | No |
|
|
215
|
+
|
|
216
|
+
### APP_ENV Behavior
|
|
217
|
+
|
|
218
|
+
The `APP_ENV` variable controls configuration loading behavior:
|
|
219
|
+
|
|
220
|
+
- **`local`**: Only loads environment variables. AWS services are used only if valid AWS credentials are found.
|
|
221
|
+
- **`development`**: Loads from environment variables, AWS Secrets Manager, and SSM Parameter Store using development paths.
|
|
222
|
+
- **`test`**: Loads from environment variables, AWS Secrets Manager, and SSM Parameter Store using test paths.
|
|
223
|
+
- **`production`**: Loads from environment variables, AWS Secrets Manager, and SSM Parameter Store using production paths.
|
|
224
|
+
|
|
225
|
+
### Environment Variable Precedence
|
|
226
|
+
|
|
227
|
+
Configuration values are loaded in the following order (later sources override earlier ones):
|
|
228
|
+
|
|
229
|
+
1. **Environment Variables** (`process.env`)
|
|
230
|
+
2. **AWS Secrets Manager** (if enabled and not in local mode)
|
|
231
|
+
3. **AWS SSM Parameter Store** (if enabled and not in local mode)
|
|
232
|
+
4. **Local .env file** (in local mode only, overrides AWS sources)
|
|
233
|
+
|
|
234
|
+
### AWS Path Construction
|
|
235
|
+
|
|
236
|
+
By default, the module constructs AWS resource paths using the following patterns:
|
|
237
|
+
|
|
238
|
+
**Secrets Manager:**
|
|
239
|
+
- Development: `/myapp/development/secrets`
|
|
240
|
+
- Test: `/myapp/test/secrets`
|
|
241
|
+
- Production: `/myapp/production/secrets`
|
|
242
|
+
|
|
243
|
+
**SSM Parameter Store:**
|
|
244
|
+
- Development: `/myapp/development/`
|
|
245
|
+
- Test: `/myapp/test/`
|
|
246
|
+
- Production: `/myapp/production/`
|
|
247
|
+
|
|
248
|
+
## Usage Examples
|
|
249
|
+
|
|
250
|
+
### Basic Configuration
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// app.module.ts
|
|
254
|
+
import { Module } from '@nestjs/common';
|
|
255
|
+
import { ConfigModule } from 'nestjs-config-aws';
|
|
256
|
+
|
|
257
|
+
@Module({
|
|
258
|
+
imports: [ConfigModule.forRoot()],
|
|
259
|
+
})
|
|
260
|
+
export class AppModule {}
|
|
261
|
+
|
|
262
|
+
// app.service.ts
|
|
263
|
+
import { Injectable } from '@nestjs/common';
|
|
264
|
+
import { ConfigService } from 'nestjs-config-aws';
|
|
265
|
+
|
|
266
|
+
@Injectable()
|
|
267
|
+
export class AppService {
|
|
268
|
+
constructor(private configService: ConfigService) {}
|
|
269
|
+
|
|
270
|
+
getDatabaseUrl(): string {
|
|
271
|
+
return this.configService.get('DATABASE_URL');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Custom Schema with Validation
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { z } from 'zod';
|
|
280
|
+
|
|
281
|
+
const appConfigSchema = z.object({
|
|
282
|
+
// Server configuration
|
|
283
|
+
PORT: z.coerce.number().min(1).max(65535).default(3000),
|
|
284
|
+
HOST: z.string().default('localhost'),
|
|
285
|
+
|
|
286
|
+
// Database configuration
|
|
287
|
+
DATABASE_URL: z.string().url(),
|
|
288
|
+
DATABASE_POOL_SIZE: z.coerce.number().min(1).default(10),
|
|
289
|
+
|
|
290
|
+
// External services
|
|
291
|
+
REDIS_URL: z.string().url().optional(),
|
|
292
|
+
API_KEY: z.string().min(1),
|
|
293
|
+
|
|
294
|
+
// Feature flags
|
|
295
|
+
ENABLE_LOGGING: z.coerce.boolean().default(true),
|
|
296
|
+
DEBUG_MODE: z.coerce.boolean().default(false),
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
type AppConfig = z.infer<typeof appConfigSchema>;
|
|
300
|
+
|
|
301
|
+
@Module({
|
|
302
|
+
imports: [
|
|
303
|
+
ConfigModule.forRoot({
|
|
304
|
+
schema: appConfigSchema,
|
|
305
|
+
}),
|
|
306
|
+
],
|
|
307
|
+
})
|
|
308
|
+
export class AppModule {}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Advanced AWS Configuration
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
@Module({
|
|
315
|
+
imports: [
|
|
316
|
+
ConfigModule.forRoot({
|
|
317
|
+
schema: appConfigSchema,
|
|
318
|
+
secretsManagerConfig: {
|
|
319
|
+
region: 'us-east-1',
|
|
320
|
+
paths: {
|
|
321
|
+
development: '/myapp/dev/secrets',
|
|
322
|
+
test: '/myapp/test/secrets',
|
|
323
|
+
production: '/myapp/prod/secrets',
|
|
324
|
+
},
|
|
325
|
+
enabled: true,
|
|
326
|
+
},
|
|
327
|
+
ssmConfig: {
|
|
328
|
+
region: 'us-east-1',
|
|
329
|
+
paths: {
|
|
330
|
+
development: '/myapp/dev/config/',
|
|
331
|
+
test: '/myapp/test/config/',
|
|
332
|
+
production: '/myapp/prod/config/',
|
|
333
|
+
},
|
|
334
|
+
enabled: true,
|
|
335
|
+
decrypt: true,
|
|
336
|
+
},
|
|
337
|
+
envPrefix: 'MYAPP_',
|
|
338
|
+
}),
|
|
339
|
+
],
|
|
340
|
+
})
|
|
341
|
+
export class AppModule {}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Async Configuration
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
@Module({
|
|
348
|
+
imports: [
|
|
349
|
+
ConfigModule.forRootAsync({
|
|
350
|
+
useFactory: async () => {
|
|
351
|
+
// Load schema or configuration dynamically
|
|
352
|
+
const schema = await loadSchemaFromFile();
|
|
353
|
+
return {
|
|
354
|
+
schema,
|
|
355
|
+
secretsManagerConfig: {
|
|
356
|
+
enabled: process.env.NODE_ENV !== 'test',
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
},
|
|
360
|
+
}),
|
|
361
|
+
],
|
|
362
|
+
})
|
|
363
|
+
export class AppModule {}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Environment-Specific Configuration
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
// Different configurations based on APP_ENV
|
|
370
|
+
const getConfigForEnvironment = () => {
|
|
371
|
+
const baseConfig = {
|
|
372
|
+
schema: appConfigSchema,
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
switch (process.env.APP_ENV) {
|
|
376
|
+
case 'local':
|
|
377
|
+
return {
|
|
378
|
+
...baseConfig,
|
|
379
|
+
secretsManagerConfig: { enabled: false },
|
|
380
|
+
ssmConfig: { enabled: false },
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
case 'development':
|
|
384
|
+
return {
|
|
385
|
+
...baseConfig,
|
|
386
|
+
secretsManagerConfig: {
|
|
387
|
+
enabled: true,
|
|
388
|
+
paths: { development: '/myapp/dev/secrets' },
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
case 'production':
|
|
393
|
+
return {
|
|
394
|
+
...baseConfig,
|
|
395
|
+
secretsManagerConfig: {
|
|
396
|
+
enabled: true,
|
|
397
|
+
paths: { production: '/myapp/prod/secrets' },
|
|
398
|
+
},
|
|
399
|
+
ssmConfig: {
|
|
400
|
+
enabled: true,
|
|
401
|
+
decrypt: true,
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
default:
|
|
406
|
+
return baseConfig;
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
@Module({
|
|
411
|
+
imports: [ConfigModule.forRoot(getConfigForEnvironment())],
|
|
412
|
+
})
|
|
413
|
+
export class AppModule {}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## @nestjs/config Integration
|
|
417
|
+
|
|
418
|
+
nestjs-config-aws provides seamless integration with the standard `@nestjs/config` module, allowing you to use AWS-sourced configuration values through the familiar `@nestjs/config` patterns. This integration maintains backward compatibility while adding AWS capabilities.
|
|
419
|
+
|
|
420
|
+
### Installation for Integration
|
|
421
|
+
|
|
422
|
+
When using the integration, install both packages:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
npm install nestjs-config-aws @nestjs/config
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Basic Integration Setup
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { Module } from '@nestjs/common';
|
|
432
|
+
import { ConfigModule } from '@nestjs/config';
|
|
433
|
+
import { NestConfigAwsIntegrationModule } from 'nestjs-config-aws';
|
|
434
|
+
|
|
435
|
+
@Module({
|
|
436
|
+
imports: [
|
|
437
|
+
// Initialize AWS integration first
|
|
438
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
439
|
+
secretsManagerConfig: {
|
|
440
|
+
enabled: true,
|
|
441
|
+
paths: {
|
|
442
|
+
production: '/myapp/prod/secrets'
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
precedence: 'aws-first'
|
|
446
|
+
}),
|
|
447
|
+
|
|
448
|
+
// Standard @nestjs/config setup
|
|
449
|
+
ConfigModule.forRoot({
|
|
450
|
+
isGlobal: true,
|
|
451
|
+
cache: true
|
|
452
|
+
})
|
|
453
|
+
]
|
|
454
|
+
})
|
|
455
|
+
export class AppModule {}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Using Standard ConfigService
|
|
459
|
+
|
|
460
|
+
With the integration, you can use the standard `@nestjs/config` `ConfigService` to access AWS-sourced values:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { Injectable } from '@nestjs/common';
|
|
464
|
+
import { ConfigService } from '@nestjs/config';
|
|
465
|
+
|
|
466
|
+
@Injectable()
|
|
467
|
+
export class AppService {
|
|
468
|
+
constructor(private configService: ConfigService) {}
|
|
469
|
+
|
|
470
|
+
getDatabaseUrl(): string {
|
|
471
|
+
// This value can come from AWS Secrets Manager
|
|
472
|
+
return this.configService.get<string>('DATABASE_URL');
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
getPort(): number {
|
|
476
|
+
// This value can come from SSM Parameter Store
|
|
477
|
+
return this.configService.get<number>('PORT', 3000);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Integration Configuration Options
|
|
483
|
+
|
|
484
|
+
The `NestConfigAwsIntegrationModule` accepts the following options:
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
interface IntegrationOptions {
|
|
488
|
+
// AWS Configuration
|
|
489
|
+
secretsManagerConfig?: SecretsManagerConfig;
|
|
490
|
+
ssmConfig?: SSMConfig;
|
|
491
|
+
|
|
492
|
+
// Integration Settings
|
|
493
|
+
precedence?: 'aws-first' | 'local-first' | 'merge';
|
|
494
|
+
namespaces?: string[];
|
|
495
|
+
enableLogging?: boolean;
|
|
496
|
+
|
|
497
|
+
// @nestjs/config compatibility
|
|
498
|
+
registerGlobally?: boolean;
|
|
499
|
+
factoryOptions?: {
|
|
500
|
+
cache?: boolean;
|
|
501
|
+
expandVariables?: boolean;
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
// Error handling
|
|
505
|
+
failOnAwsError?: boolean;
|
|
506
|
+
fallbackToLocal?: boolean;
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Precedence Rules
|
|
511
|
+
|
|
512
|
+
The integration supports three precedence strategies:
|
|
513
|
+
|
|
514
|
+
#### 1. AWS-First (Default)
|
|
515
|
+
AWS values override local values when both exist:
|
|
516
|
+
```typescript
|
|
517
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
518
|
+
precedence: 'aws-first' // AWS values take priority
|
|
519
|
+
})
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### 2. Local-First
|
|
523
|
+
Local values override AWS values when both exist:
|
|
524
|
+
```typescript
|
|
525
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
526
|
+
precedence: 'local-first' // Local .env values take priority
|
|
527
|
+
})
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
#### 3. Merge
|
|
531
|
+
Combines values from all sources intelligently:
|
|
532
|
+
```typescript
|
|
533
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
534
|
+
precedence: 'merge' // Merge all sources with smart conflict resolution
|
|
535
|
+
})
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### Async Configuration Integration
|
|
539
|
+
|
|
540
|
+
For complex setups, use async configuration:
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
import { Module } from '@nestjs/common';
|
|
544
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
545
|
+
import { NestConfigAwsIntegrationModule } from 'nestjs-config-aws';
|
|
546
|
+
|
|
547
|
+
@Module({
|
|
548
|
+
imports: [
|
|
549
|
+
NestConfigAwsIntegrationModule.forRootAsync({
|
|
550
|
+
useFactory: async () => ({
|
|
551
|
+
secretsManagerConfig: {
|
|
552
|
+
enabled: process.env.NODE_ENV === 'production',
|
|
553
|
+
region: process.env.AWS_REGION,
|
|
554
|
+
paths: {
|
|
555
|
+
production: `/myapp/${process.env.DEPLOYMENT_STAGE}/secrets`
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
precedence: 'aws-first',
|
|
559
|
+
failOnAwsError: false
|
|
560
|
+
})
|
|
561
|
+
}),
|
|
562
|
+
|
|
563
|
+
ConfigModule.forRootAsync({
|
|
564
|
+
useFactory: async (configService: ConfigService) => ({
|
|
565
|
+
isGlobal: true,
|
|
566
|
+
validate: (config) => {
|
|
567
|
+
// Validate AWS-sourced configuration
|
|
568
|
+
if (!config.DATABASE_URL) {
|
|
569
|
+
throw new Error('DATABASE_URL is required');
|
|
570
|
+
}
|
|
571
|
+
return config;
|
|
572
|
+
}
|
|
573
|
+
}),
|
|
574
|
+
inject: [ConfigService]
|
|
575
|
+
})
|
|
576
|
+
]
|
|
577
|
+
})
|
|
578
|
+
export class AppModule {}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### Namespaced Configuration
|
|
582
|
+
|
|
583
|
+
The integration supports @nestjs/config's `registerAs` pattern for namespaced configuration:
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
586
|
+
// config/database.config.ts
|
|
587
|
+
import { registerAs } from '@nestjs/config';
|
|
588
|
+
|
|
589
|
+
export default registerAs('database', () => ({
|
|
590
|
+
host: process.env.DATABASE_HOST, // Can come from AWS
|
|
591
|
+
port: parseInt(process.env.DATABASE_PORT, 10),
|
|
592
|
+
username: process.env.DATABASE_USERNAME, // From AWS Secrets Manager
|
|
593
|
+
password: process.env.DATABASE_PASSWORD, // From AWS Secrets Manager
|
|
594
|
+
}));
|
|
595
|
+
|
|
596
|
+
// app.module.ts
|
|
597
|
+
@Module({
|
|
598
|
+
imports: [
|
|
599
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
600
|
+
namespaces: ['database'],
|
|
601
|
+
secretsManagerConfig: {
|
|
602
|
+
enabled: true,
|
|
603
|
+
paths: {
|
|
604
|
+
production: '/myapp/prod/database'
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}),
|
|
608
|
+
|
|
609
|
+
ConfigModule.forRoot({
|
|
610
|
+
load: [databaseConfig],
|
|
611
|
+
isGlobal: true
|
|
612
|
+
})
|
|
613
|
+
]
|
|
614
|
+
})
|
|
615
|
+
export class AppModule {}
|
|
616
|
+
|
|
617
|
+
// database.service.ts
|
|
618
|
+
import { Injectable } from '@nestjs/common';
|
|
619
|
+
import { ConfigService } from '@nestjs/config';
|
|
620
|
+
|
|
621
|
+
@Injectable()
|
|
622
|
+
export class DatabaseService {
|
|
623
|
+
constructor(private configService: ConfigService) {}
|
|
624
|
+
|
|
625
|
+
getConnectionConfig() {
|
|
626
|
+
// Access namespaced configuration
|
|
627
|
+
return this.configService.get('database');
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Validation Integration
|
|
633
|
+
|
|
634
|
+
The integration works seamlessly with @nestjs/config validation:
|
|
635
|
+
|
|
636
|
+
#### Using Joi Validation
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
import * as Joi from 'joi';
|
|
640
|
+
|
|
641
|
+
@Module({
|
|
642
|
+
imports: [
|
|
643
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
644
|
+
secretsManagerConfig: { enabled: true }
|
|
645
|
+
}),
|
|
646
|
+
|
|
647
|
+
ConfigModule.forRoot({
|
|
648
|
+
validationSchema: Joi.object({
|
|
649
|
+
NODE_ENV: Joi.string()
|
|
650
|
+
.valid('development', 'production', 'test')
|
|
651
|
+
.default('development'),
|
|
652
|
+
PORT: Joi.number().default(3000),
|
|
653
|
+
DATABASE_URL: Joi.string().required(), // Can come from AWS
|
|
654
|
+
API_KEY: Joi.string().required(), // Can come from AWS
|
|
655
|
+
}),
|
|
656
|
+
validationOptions: {
|
|
657
|
+
allowUnknown: true,
|
|
658
|
+
abortEarly: false,
|
|
659
|
+
}
|
|
660
|
+
})
|
|
661
|
+
]
|
|
662
|
+
})
|
|
663
|
+
export class AppModule {}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
#### Using Class Validator
|
|
667
|
+
|
|
668
|
+
```typescript
|
|
669
|
+
import { IsString, IsNumber, IsUrl } from 'class-validator';
|
|
670
|
+
import { Transform } from 'class-transformer';
|
|
671
|
+
|
|
672
|
+
class EnvironmentVariables {
|
|
673
|
+
@IsString()
|
|
674
|
+
NODE_ENV: string;
|
|
675
|
+
|
|
676
|
+
@IsNumber()
|
|
677
|
+
@Transform(({ value }) => parseInt(value, 10))
|
|
678
|
+
PORT: number;
|
|
679
|
+
|
|
680
|
+
@IsUrl()
|
|
681
|
+
DATABASE_URL: string; // Can come from AWS
|
|
682
|
+
|
|
683
|
+
@IsString()
|
|
684
|
+
API_KEY: string; // Can come from AWS
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
@Module({
|
|
688
|
+
imports: [
|
|
689
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
690
|
+
secretsManagerConfig: { enabled: true }
|
|
691
|
+
}),
|
|
692
|
+
|
|
693
|
+
ConfigModule.forRoot({
|
|
694
|
+
validate: (config: Record<string, unknown>) => {
|
|
695
|
+
const validatedConfig = plainToClass(EnvironmentVariables, config, {
|
|
696
|
+
enableImplicitConversion: true,
|
|
697
|
+
});
|
|
698
|
+
const errors = validateSync(validatedConfig, {
|
|
699
|
+
skipMissingProperties: false,
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
if (errors.length > 0) {
|
|
703
|
+
throw new Error(errors.toString());
|
|
704
|
+
}
|
|
705
|
+
return validatedConfig;
|
|
706
|
+
},
|
|
707
|
+
})
|
|
708
|
+
]
|
|
709
|
+
})
|
|
710
|
+
export class AppModule {}
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
### Error Handling and Graceful Degradation
|
|
714
|
+
|
|
715
|
+
The integration provides robust error handling:
|
|
716
|
+
|
|
717
|
+
```typescript
|
|
718
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
719
|
+
secretsManagerConfig: {
|
|
720
|
+
enabled: true,
|
|
721
|
+
paths: { production: '/myapp/prod/secrets' }
|
|
722
|
+
},
|
|
723
|
+
|
|
724
|
+
// Error handling options
|
|
725
|
+
failOnAwsError: false, // Don't fail if AWS is unavailable
|
|
726
|
+
fallbackToLocal: true, // Use local config if AWS fails
|
|
727
|
+
enableLogging: true, // Enable detailed logging
|
|
728
|
+
|
|
729
|
+
// Graceful degradation
|
|
730
|
+
precedence: 'local-first' // Prefer local values as fallback
|
|
731
|
+
})
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
### Migration Guide
|
|
735
|
+
|
|
736
|
+
#### From @nestjs/config Only
|
|
737
|
+
|
|
738
|
+
If you're currently using only `@nestjs/config`:
|
|
739
|
+
|
|
740
|
+
1. **Install nestjs-config-aws**:
|
|
741
|
+
```bash
|
|
742
|
+
npm install nestjs-config-aws
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
2. **Add integration module** before your existing ConfigModule:
|
|
746
|
+
```typescript
|
|
747
|
+
@Module({
|
|
748
|
+
imports: [
|
|
749
|
+
// Add this before ConfigModule
|
|
750
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
751
|
+
secretsManagerConfig: { enabled: true }
|
|
752
|
+
}),
|
|
753
|
+
|
|
754
|
+
// Your existing ConfigModule setup
|
|
755
|
+
ConfigModule.forRoot({
|
|
756
|
+
isGlobal: true
|
|
757
|
+
})
|
|
758
|
+
]
|
|
759
|
+
})
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
3. **No code changes needed** - your existing ConfigService usage continues to work
|
|
763
|
+
|
|
764
|
+
4. **Configure AWS resources** - add secrets to AWS Secrets Manager or SSM Parameter Store
|
|
765
|
+
|
|
766
|
+
#### From nestjs-config-aws Only
|
|
767
|
+
|
|
768
|
+
If you're currently using only `nestjs-config-aws`:
|
|
769
|
+
|
|
770
|
+
1. **Install @nestjs/config**:
|
|
771
|
+
```bash
|
|
772
|
+
npm install @nestjs/config
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
2. **Replace ConfigModule import**:
|
|
776
|
+
```typescript
|
|
777
|
+
// Before
|
|
778
|
+
import { ConfigModule } from 'nestjs-config-aws';
|
|
779
|
+
|
|
780
|
+
// After
|
|
781
|
+
import { ConfigModule } from '@nestjs/config';
|
|
782
|
+
import { NestConfigAwsIntegrationModule } from 'nestjs-config-aws';
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
3. **Update module imports**:
|
|
786
|
+
```typescript
|
|
787
|
+
@Module({
|
|
788
|
+
imports: [
|
|
789
|
+
// Add integration module
|
|
790
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
791
|
+
// Your existing nestjs-config-aws options
|
|
792
|
+
}),
|
|
793
|
+
|
|
794
|
+
// Add standard ConfigModule
|
|
795
|
+
ConfigModule.forRoot({
|
|
796
|
+
isGlobal: true
|
|
797
|
+
})
|
|
798
|
+
]
|
|
799
|
+
})
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
4. **Update service injection**:
|
|
803
|
+
```typescript
|
|
804
|
+
// Before
|
|
805
|
+
import { ConfigService } from 'nestjs-config-aws';
|
|
806
|
+
|
|
807
|
+
// After
|
|
808
|
+
import { ConfigService } from '@nestjs/config';
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### Integration Troubleshooting
|
|
812
|
+
|
|
813
|
+
#### Common Integration Issues
|
|
814
|
+
|
|
815
|
+
**1. Configuration Not Loading from AWS**
|
|
816
|
+
|
|
817
|
+
Check that the integration module is imported before ConfigModule:
|
|
818
|
+
```typescript
|
|
819
|
+
@Module({
|
|
820
|
+
imports: [
|
|
821
|
+
NestConfigAwsIntegrationModule.forRoot({}), // Must be first
|
|
822
|
+
ConfigModule.forRoot({}) // Then ConfigModule
|
|
823
|
+
]
|
|
824
|
+
})
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
**2. Values Not Available in ConfigService**
|
|
828
|
+
|
|
829
|
+
Ensure AWS loading completes before ConfigModule initialization:
|
|
830
|
+
```typescript
|
|
831
|
+
NestConfigAwsIntegrationModule.forRootAsync({
|
|
832
|
+
useFactory: async () => {
|
|
833
|
+
// Async setup ensures proper initialization order
|
|
834
|
+
return { secretsManagerConfig: { enabled: true } };
|
|
835
|
+
}
|
|
836
|
+
})
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**3. Precedence Rules Not Working**
|
|
840
|
+
|
|
841
|
+
Verify precedence configuration:
|
|
842
|
+
```typescript
|
|
843
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
844
|
+
precedence: 'aws-first', // or 'local-first' or 'merge'
|
|
845
|
+
enableLogging: true // Enable to see precedence decisions
|
|
846
|
+
})
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
**4. Validation Errors with AWS Values**
|
|
850
|
+
|
|
851
|
+
Check that AWS values match validation schema:
|
|
852
|
+
```typescript
|
|
853
|
+
// Enable detailed logging to see loaded values
|
|
854
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
855
|
+
enableLogging: true,
|
|
856
|
+
failOnAwsError: false // Don't fail on AWS errors during debugging
|
|
857
|
+
})
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
**5. Namespace Issues**
|
|
861
|
+
|
|
862
|
+
Ensure namespace configuration matches registerAs usage:
|
|
863
|
+
```typescript
|
|
864
|
+
// In integration config
|
|
865
|
+
NestConfigAwsIntegrationModule.forRoot({
|
|
866
|
+
namespaces: ['database', 'redis'] // Must match registerAs names
|
|
867
|
+
})
|
|
868
|
+
|
|
869
|
+
// In config files
|
|
870
|
+
export default registerAs('database', () => ({ /* config */ }));
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
#### Debug Integration Issues
|
|
874
|
+
|
|
875
|
+
Enable debug logging:
|
|
876
|
+
```bash
|
|
877
|
+
DEBUG=nestjs-config-aws:integration* npm start
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
This provides detailed logs about:
|
|
881
|
+
- AWS configuration loading
|
|
882
|
+
- Factory registration with @nestjs/config
|
|
883
|
+
- Precedence rule application
|
|
884
|
+
- Namespace handling
|
|
885
|
+
- Error scenarios
|
|
886
|
+
|
|
887
|
+
## API Reference
|
|
888
|
+
|
|
889
|
+
### ConfigModule
|
|
890
|
+
|
|
891
|
+
#### `ConfigModule.forRoot(options?: NestConfigAwsModuleOptions)`
|
|
892
|
+
|
|
893
|
+
Configures the module with the provided options.
|
|
894
|
+
|
|
895
|
+
**Parameters:**
|
|
896
|
+
- `options` - Configuration options for the module
|
|
897
|
+
|
|
898
|
+
**Returns:** `DynamicModule`
|
|
899
|
+
|
|
900
|
+
#### `ConfigModule.forRootAsync(options: NestConfigAwsModuleAsyncOptions)`
|
|
901
|
+
|
|
902
|
+
Configures the module asynchronously using a factory function.
|
|
903
|
+
|
|
904
|
+
**Parameters:**
|
|
905
|
+
- `options` - Async configuration options
|
|
906
|
+
|
|
907
|
+
**Returns:** `DynamicModule`
|
|
908
|
+
|
|
909
|
+
### ConfigService
|
|
910
|
+
|
|
911
|
+
#### `get<K extends keyof T>(key: K): T[K]`
|
|
912
|
+
|
|
913
|
+
Retrieves a configuration value by key with type safety.
|
|
914
|
+
|
|
915
|
+
**Parameters:**
|
|
916
|
+
- `key` - The configuration key to retrieve
|
|
917
|
+
|
|
918
|
+
**Returns:** The configuration value with proper typing
|
|
919
|
+
|
|
920
|
+
#### `getAll(): T`
|
|
921
|
+
|
|
922
|
+
Retrieves all configuration values.
|
|
923
|
+
|
|
924
|
+
**Returns:** The complete configuration object
|
|
925
|
+
|
|
926
|
+
#### `isInitialized(): boolean`
|
|
927
|
+
|
|
928
|
+
Checks if the configuration service has been initialized.
|
|
929
|
+
|
|
930
|
+
**Returns:** `true` if the service is ready to serve configuration values
|
|
931
|
+
|
|
932
|
+
### Configuration Loaders
|
|
933
|
+
|
|
934
|
+
#### EnvironmentLoader
|
|
935
|
+
|
|
936
|
+
Loads configuration from `process.env`.
|
|
937
|
+
|
|
938
|
+
#### SecretsManagerLoader
|
|
939
|
+
|
|
940
|
+
Loads configuration from AWS Secrets Manager with environment-aware path construction.
|
|
941
|
+
|
|
942
|
+
#### SSMParameterStoreLoader
|
|
943
|
+
|
|
944
|
+
Loads configuration from AWS Systems Manager Parameter Store with recursive parameter fetching.
|
|
945
|
+
|
|
946
|
+
## Troubleshooting
|
|
947
|
+
|
|
948
|
+
### Common Issues
|
|
949
|
+
|
|
950
|
+
#### 1. AWS Credentials Not Found
|
|
951
|
+
|
|
952
|
+
**Error:** `CredentialsProviderError: Could not load credentials`
|
|
953
|
+
|
|
954
|
+
**Solution:**
|
|
955
|
+
- Ensure AWS credentials are configured via AWS CLI, environment variables, or IAM roles
|
|
956
|
+
- For local development, set up an AWS profile: `aws configure --profile myprofile`
|
|
957
|
+
- Set `AWS_PROFILE` environment variable to use a specific profile
|
|
958
|
+
|
|
959
|
+
#### 2. Configuration Validation Errors
|
|
960
|
+
|
|
961
|
+
**Error:** `ValidationError: Configuration validation failed`
|
|
962
|
+
|
|
963
|
+
**Solution:**
|
|
964
|
+
- Check that all required environment variables are set
|
|
965
|
+
- Verify that configuration values match the expected types in your Zod schema
|
|
966
|
+
- Use `ignoreValidationErrors: true` for debugging (not recommended for production)
|
|
967
|
+
|
|
968
|
+
#### 3. AWS Region Not Detected
|
|
969
|
+
|
|
970
|
+
**Error:** `ConfigurationError: AWS region could not be determined`
|
|
971
|
+
|
|
972
|
+
**Solution:**
|
|
973
|
+
- Set the `AWS_REGION` environment variable
|
|
974
|
+
- Configure region in AWS credentials file
|
|
975
|
+
- Specify region in module configuration
|
|
976
|
+
|
|
977
|
+
#### 4. Secrets Manager Access Denied
|
|
978
|
+
|
|
979
|
+
**Error:** `AccessDenied: User is not authorized to perform secretsmanager:GetSecretValue`
|
|
980
|
+
|
|
981
|
+
**Solution:**
|
|
982
|
+
- Ensure your AWS credentials have the necessary permissions
|
|
983
|
+
- Add the following IAM policy to your user/role:
|
|
984
|
+
|
|
985
|
+
```json
|
|
986
|
+
{
|
|
987
|
+
"Version": "2012-10-17",
|
|
988
|
+
"Statement": [
|
|
989
|
+
{
|
|
990
|
+
"Effect": "Allow",
|
|
991
|
+
"Action": [
|
|
992
|
+
"secretsmanager:GetSecretValue",
|
|
993
|
+
"secretsmanager:DescribeSecret"
|
|
994
|
+
],
|
|
995
|
+
"Resource": "arn:aws:secretsmanager:*:*:secret:/myapp/*"
|
|
996
|
+
}
|
|
997
|
+
]
|
|
998
|
+
}
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
#### 5. SSM Parameter Store Access Denied
|
|
1002
|
+
|
|
1003
|
+
**Error:** `AccessDenied: User is not authorized to perform ssm:GetParameters`
|
|
1004
|
+
|
|
1005
|
+
**Solution:**
|
|
1006
|
+
- Add the following IAM policy:
|
|
1007
|
+
|
|
1008
|
+
```json
|
|
1009
|
+
{
|
|
1010
|
+
"Version": "2012-10-17",
|
|
1011
|
+
"Statement": [
|
|
1012
|
+
{
|
|
1013
|
+
"Effect": "Allow",
|
|
1014
|
+
"Action": [
|
|
1015
|
+
"ssm:GetParameter",
|
|
1016
|
+
"ssm:GetParameters",
|
|
1017
|
+
"ssm:GetParametersByPath"
|
|
1018
|
+
],
|
|
1019
|
+
"Resource": "arn:aws:ssm:*:*:parameter/myapp/*"
|
|
1020
|
+
}
|
|
1021
|
+
]
|
|
1022
|
+
}
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
#### 6. Module Not Loading Configuration
|
|
1026
|
+
|
|
1027
|
+
**Problem:** Configuration service returns undefined values
|
|
1028
|
+
|
|
1029
|
+
**Solution:**
|
|
1030
|
+
- Ensure the module is imported in your root module
|
|
1031
|
+
- Check that the configuration service is properly injected
|
|
1032
|
+
- Verify that `APP_ENV` is set correctly
|
|
1033
|
+
- Check AWS credentials and permissions
|
|
1034
|
+
|
|
1035
|
+
#### 7. Type Safety Issues
|
|
1036
|
+
|
|
1037
|
+
**Problem:** TypeScript errors when accessing configuration
|
|
1038
|
+
|
|
1039
|
+
**Solution:**
|
|
1040
|
+
- Ensure you're using the correct generic type for `ConfigService<T>`
|
|
1041
|
+
- Verify your Zod schema matches your configuration interface
|
|
1042
|
+
- Use type assertion if necessary: `configService.get('KEY' as keyof T)`
|
|
1043
|
+
|
|
1044
|
+
#### 8. @nestjs/config Integration Issues
|
|
1045
|
+
|
|
1046
|
+
**Problem:** Configuration not loading from AWS when using integration
|
|
1047
|
+
|
|
1048
|
+
**Solution:**
|
|
1049
|
+
- Ensure `NestConfigAwsIntegrationModule` is imported before `ConfigModule`
|
|
1050
|
+
- Check that AWS credentials are properly configured
|
|
1051
|
+
- Verify precedence rules are set correctly
|
|
1052
|
+
- Enable logging to debug configuration loading: `enableLogging: true`
|
|
1053
|
+
|
|
1054
|
+
**Problem:** Precedence rules not working as expected
|
|
1055
|
+
|
|
1056
|
+
**Solution:**
|
|
1057
|
+
- Check precedence configuration: `'aws-first'`, `'local-first'`, or `'merge'`
|
|
1058
|
+
- Verify that both local and AWS sources have the same configuration keys
|
|
1059
|
+
- Use debug logging to see which values are being used
|
|
1060
|
+
|
|
1061
|
+
**Problem:** Namespaced configuration not working with integration
|
|
1062
|
+
|
|
1063
|
+
**Solution:**
|
|
1064
|
+
- Ensure namespace names in integration config match `registerAs` names
|
|
1065
|
+
- Check that AWS sources contain the expected namespace structure
|
|
1066
|
+
- Verify that `registerAs` factories are properly loaded by `ConfigModule`
|
|
1067
|
+
|
|
1068
|
+
### Debug Mode
|
|
1069
|
+
|
|
1070
|
+
Enable debug logging by setting the `DEBUG` environment variable:
|
|
1071
|
+
|
|
1072
|
+
```bash
|
|
1073
|
+
DEBUG=nestjs-config-aws* npm start
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
This will provide detailed logs about:
|
|
1077
|
+
- Configuration loading steps
|
|
1078
|
+
- AWS service calls
|
|
1079
|
+
- Validation results
|
|
1080
|
+
- Error details
|
|
1081
|
+
|
|
1082
|
+
### Performance Considerations
|
|
1083
|
+
|
|
1084
|
+
#### Configuration Caching
|
|
1085
|
+
|
|
1086
|
+
The module caches configuration after the initial load. To force a reload:
|
|
1087
|
+
|
|
1088
|
+
```typescript
|
|
1089
|
+
// This is not exposed in the public API but handled internally
|
|
1090
|
+
// Configuration is loaded once during module initialization
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
#### AWS Service Optimization
|
|
1094
|
+
|
|
1095
|
+
- **Connection Pooling**: AWS SDK clients are reused across requests
|
|
1096
|
+
- **Pagination**: SSM Parameter Store queries use efficient pagination
|
|
1097
|
+
- **Regional Optimization**: Specify regions explicitly to avoid auto-detection overhead
|
|
1098
|
+
|
|
1099
|
+
## Examples
|
|
1100
|
+
|
|
1101
|
+
The `examples/` directory contains complete working examples:
|
|
1102
|
+
|
|
1103
|
+
- **[basic-usage/](./examples/basic-usage/)**: Simple setup with default configuration
|
|
1104
|
+
- **[custom-schema/](./examples/custom-schema/)**: Advanced usage with custom Zod schema and AWS integration
|
|
1105
|
+
- **[aws-integration/](./examples/aws-integration/)**: Production-ready AWS service integration
|
|
1106
|
+
- **[nestjs-config-integration/](./examples/nestjs-config-integration/)**: Seamless integration with @nestjs/config
|
|
1107
|
+
- **[docker-compose/](./examples/docker-compose/)**: Complete local development environment
|
|
1108
|
+
|
|
1109
|
+
To run the examples:
|
|
1110
|
+
|
|
1111
|
+
```bash
|
|
1112
|
+
cd examples/nestjs-config-integration
|
|
1113
|
+
npm install
|
|
1114
|
+
cp .env.example .env
|
|
1115
|
+
npm start
|
|
1116
|
+
```
|
|
1117
|
+
|
|
1118
|
+
For a complete local environment with AWS service emulation:
|
|
1119
|
+
|
|
1120
|
+
```bash
|
|
1121
|
+
cd examples/docker-compose
|
|
1122
|
+
docker-compose up -d
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
## Contributing
|
|
1126
|
+
|
|
1127
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
1128
|
+
|
|
1129
|
+
### Development Setup
|
|
1130
|
+
|
|
1131
|
+
```bash
|
|
1132
|
+
# Clone the repository
|
|
1133
|
+
git clone <repository-url>
|
|
1134
|
+
cd nestjs-config-aws
|
|
1135
|
+
|
|
1136
|
+
# Install dependencies
|
|
1137
|
+
npm install
|
|
1138
|
+
|
|
1139
|
+
# Run tests
|
|
1140
|
+
npm test
|
|
1141
|
+
|
|
1142
|
+
# Run tests in watch mode
|
|
1143
|
+
npm run test:watch
|
|
1144
|
+
|
|
1145
|
+
# Build the package
|
|
1146
|
+
npm run build
|
|
1147
|
+
|
|
1148
|
+
# Run linting
|
|
1149
|
+
npm run lint
|
|
1150
|
+
```
|
|
1151
|
+
|
|
1152
|
+
### Running Tests
|
|
1153
|
+
|
|
1154
|
+
```bash
|
|
1155
|
+
# Unit tests
|
|
1156
|
+
npm run test:unit
|
|
1157
|
+
|
|
1158
|
+
# Integration tests (requires AWS credentials)
|
|
1159
|
+
npm run test:integration
|
|
1160
|
+
|
|
1161
|
+
# Coverage report
|
|
1162
|
+
npm run test:coverage
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
## License
|
|
1166
|
+
|
|
1167
|
+
MIT © [Your Organization]
|
|
1168
|
+
|
|
1169
|
+
---
|
|
1170
|
+
|
|
1171
|
+
## Changelog
|
|
1172
|
+
|
|
1173
|
+
### v1.0.0 - First Public Release 🎉
|
|
1174
|
+
- **Core Features**: Environment variable loading, AWS Secrets Manager, and SSM Parameter Store integration
|
|
1175
|
+
- **@nestjs/config Integration**: Seamless compatibility with standard NestJS configuration patterns
|
|
1176
|
+
- **Type Safety**: Full TypeScript support with Zod validation and generic types
|
|
1177
|
+
- **Environment Awareness**: Automatic configuration based on APP_ENV (local, development, test, production)
|
|
1178
|
+
- **Flexible Precedence**: aws-first, local-first, and merge strategies for configuration conflicts
|
|
1179
|
+
- **Performance Optimized**: Efficient loading with caching and pagination support
|
|
1180
|
+
- **Comprehensive Documentation**: Complete API reference, troubleshooting guide, and multiple examples
|
|
1181
|
+
- **Production Ready**: Robust error handling, security best practices, and monitoring support
|
|
1182
|
+
|
|
1183
|
+
See [CHANGELOG.md](CHANGELOG.md) for detailed release notes.
|