@elsikora/nestjs-typeorm-aws-connector 1.3.1-dev.1 → 1.3.2-dev.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.
Files changed (58) hide show
  1. package/README.md +344 -235
  2. package/dist/cjs/external/tslib/tslib.es6.js.map +1 -1
  3. package/dist/cjs/index.d.ts +1 -1
  4. package/dist/cjs/modules/typeorm-aws-connector/rotator/rotator.service.d.ts +3 -3
  5. package/dist/cjs/modules/typeorm-aws-connector/rotator/rotator.service.js +39 -31
  6. package/dist/cjs/modules/typeorm-aws-connector/rotator/rotator.service.js.map +1 -1
  7. package/dist/cjs/modules/typeorm-aws-connector/typeorm-aws-connector.module.d.ts +1 -1
  8. package/dist/cjs/modules/typeorm-aws-connector/typeorm-aws-connector.module.js +7 -25
  9. package/dist/cjs/modules/typeorm-aws-connector/typeorm-aws-connector.module.js.map +1 -1
  10. package/dist/cjs/modules/typeorm-aws-connector/typeorm-aws-connector.service.d.ts +25 -3
  11. package/dist/cjs/modules/typeorm-aws-connector/typeorm-aws-connector.service.js +246 -30
  12. package/dist/cjs/modules/typeorm-aws-connector/typeorm-aws-connector.service.js.map +1 -1
  13. package/dist/cjs/package.json +4 -4
  14. package/dist/cjs/shared/constant/typeorm-aws-connector/constant.d.ts +7 -0
  15. package/dist/cjs/shared/constant/typeorm-aws-connector/constant.js +70 -2
  16. package/dist/cjs/shared/constant/typeorm-aws-connector/constant.js.map +1 -1
  17. package/dist/cjs/shared/enum/database/type.enum.js.map +1 -1
  18. package/dist/cjs/shared/enum/relation-load-strategy.enum.js.map +1 -1
  19. package/dist/cjs/shared/interface/aws/database-credentials-secret.interface.d.ts +4 -0
  20. package/dist/cjs/shared/interface/aws/index.d.ts +1 -0
  21. package/dist/cjs/shared/interface/typeorm-aws-connector/config.interface.d.ts +11 -12
  22. package/dist/cjs/shared/interface/typeorm-aws-connector/index.d.ts +3 -0
  23. package/dist/cjs/shared/interface/typeorm-aws-connector/module-async-options.interface.d.ts +4 -4
  24. package/dist/cjs/shared/interface/typeorm-aws-connector/ssm-lookup-defaults.interface.d.ts +2 -0
  25. package/dist/cjs/shared/interface/typeorm-aws-connector/ssm-lookups.interface.d.ts +16 -0
  26. package/dist/cjs/shared/interface/typeorm-aws-connector/structured-lookup.interface.d.ts +2 -0
  27. package/dist/cjs/shared/type/database/config-rotation.type.d.ts +1 -3
  28. package/dist/esm/external/tslib/tslib.es6.js.map +1 -1
  29. package/dist/esm/index.d.ts +1 -1
  30. package/dist/esm/modules/typeorm-aws-connector/rotator/rotator.service.d.ts +3 -3
  31. package/dist/esm/modules/typeorm-aws-connector/rotator/rotator.service.js +40 -32
  32. package/dist/esm/modules/typeorm-aws-connector/rotator/rotator.service.js.map +1 -1
  33. package/dist/esm/modules/typeorm-aws-connector/typeorm-aws-connector.module.d.ts +1 -1
  34. package/dist/esm/modules/typeorm-aws-connector/typeorm-aws-connector.module.js +7 -25
  35. package/dist/esm/modules/typeorm-aws-connector/typeorm-aws-connector.module.js.map +1 -1
  36. package/dist/esm/modules/typeorm-aws-connector/typeorm-aws-connector.service.d.ts +25 -3
  37. package/dist/esm/modules/typeorm-aws-connector/typeorm-aws-connector.service.js +248 -32
  38. package/dist/esm/modules/typeorm-aws-connector/typeorm-aws-connector.service.js.map +1 -1
  39. package/dist/esm/package.json +4 -4
  40. package/dist/esm/shared/constant/typeorm-aws-connector/constant.d.ts +7 -0
  41. package/dist/esm/shared/constant/typeorm-aws-connector/constant.js +70 -2
  42. package/dist/esm/shared/constant/typeorm-aws-connector/constant.js.map +1 -1
  43. package/dist/esm/shared/enum/database/type.enum.js.map +1 -1
  44. package/dist/esm/shared/enum/relation-load-strategy.enum.js.map +1 -1
  45. package/dist/esm/shared/interface/aws/database-credentials-secret.interface.d.ts +4 -0
  46. package/dist/esm/shared/interface/aws/index.d.ts +1 -0
  47. package/dist/esm/shared/interface/typeorm-aws-connector/config.interface.d.ts +11 -12
  48. package/dist/esm/shared/interface/typeorm-aws-connector/index.d.ts +3 -0
  49. package/dist/esm/shared/interface/typeorm-aws-connector/module-async-options.interface.d.ts +4 -4
  50. package/dist/esm/shared/interface/typeorm-aws-connector/ssm-lookup-defaults.interface.d.ts +2 -0
  51. package/dist/esm/shared/interface/typeorm-aws-connector/ssm-lookups.interface.d.ts +16 -0
  52. package/dist/esm/shared/interface/typeorm-aws-connector/structured-lookup.interface.d.ts +2 -0
  53. package/dist/esm/shared/type/database/config-rotation.type.d.ts +1 -3
  54. package/package.json +32 -31
  55. package/dist/cjs/shared/interface/aws/secrets-manager/index.d.ts +0 -1
  56. package/dist/cjs/shared/interface/aws/secrets-manager/item.interface.d.ts +0 -4
  57. package/dist/esm/shared/interface/aws/secrets-manager/index.d.ts +0 -1
  58. package/dist/esm/shared/interface/aws/secrets-manager/item.interface.d.ts +0 -4
package/README.md CHANGED
@@ -1,337 +1,446 @@
1
+ <a id="top"></a>
2
+
1
3
  <p align="center">
2
- <img src="https://6jft62zmy9nx2oea.public.blob.vercel-storage.com/nestjs-typeorm-aws-connector-moPeh5TktoUIqqecoEMyixlLWpCIfL.png" width="500" alt="project-logo">
4
+ <img src="https://6jft62zmy9nx2oea.public.blob.vercel-storage.com/nestjs-typeorm-aws-connector-moPeh5TktoUIqqecoEMyixlLWpCIfL.png" width="700" alt="project-logo">
3
5
  </p>
4
6
 
5
- <h1 align="center">NestJS-TypeORM-AWS-Connector 🔌</h1>
6
- <p align="center"><em>Seamlessly connect your NestJS applications with AWS Parameter Store and TypeORM</em></p>
7
+ <h1 align="center">🔌 NestJS-TypeORM-AWS-Connector</h1>
8
+ <p align="center"><em>Seamlessly bridge TypeORM with AWS Parameter Store & Secrets Manager for secure, auto-rotating database connections in NestJS</em></p>
7
9
 
8
10
  <p align="center">
9
11
  <a aria-label="ElsiKora logo" href="https://elsikora.com">
10
12
  <img src="https://img.shields.io/badge/MADE%20BY%20ElsiKora-333333.svg?style=for-the-badge" alt="ElsiKora">
11
- </a> <img src="https://img.shields.io/badge/npm-blue.svg?style=for-the-badge&logo=npm&logoColor=white" alt="npm"> <img src="https://img.shields.io/badge/nestjs-E0234E.svg?style=for-the-badge&logo=nestjs&logoColor=white" alt="nestjs"> <img src="https://img.shields.io/badge/typescript-3178C6.svg?style=for-the-badge&logo=typescript&logoColor=white" alt="typescript"> <img src="https://img.shields.io/badge/aws-232F3E.svg?style=for-the-badge&logo=amazonaws&logoColor=white" alt="aws"> <img src="https://img.shields.io/badge/typeorm-orange.svg?style=for-the-badge&logo=typeorm&logoColor=white" alt="typeorm"> <img src="https://img.shields.io/badge/license-MIT-yellow.svg?style=for-the-badge&logo=license&logoColor=white" alt="license-MIT">
13
+ </a> <img src="https://img.shields.io/badge/TypeScript-3178C6.svg?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript"> <img src="https://img.shields.io/badge/NestJS-E0234E.svg?style=for-the-badge&logo=nestjs&logoColor=white" alt="NestJS"> <img src="https://img.shields.io/badge/Node.js-339933.svg?style=for-the-badge&logo=node.js&logoColor=white" alt="Node.js"> <img src="https://img.shields.io/badge/AWS-232F3E.svg?style=for-the-badge&logo=amazon-aws&logoColor=white" alt="AWS"> <img src="https://img.shields.io/badge/Rollup-EC4A3F.svg?style=for-the-badge&logo=rollup&logoColor=white" alt="Rollup"> <img src="https://img.shields.io/badge/ESLint-4B32C3.svg?style=for-the-badge&logo=eslint&logoColor=white" alt="ESLint"> <img src="https://img.shields.io/badge/Prettier-F7B93E.svg?style=for-the-badge&logo=prettier&logoColor=black" alt="Prettier"> <img src="https://img.shields.io/badge/GitHub%20Actions-2088FF.svg?style=for-the-badge&logo=github-actions&logoColor=white" alt="GitHub Actions"> <img src="https://img.shields.io/badge/npm-CB3837.svg?style=for-the-badge&logo=npm&logoColor=white" alt="npm"> <img src="https://img.shields.io/badge/PostgreSQL-4169E1.svg?style=for-the-badge&logo=postgresql&logoColor=white" alt="PostgreSQL"> <img src="https://img.shields.io/badge/MySQL-4479A1.svg?style=for-the-badge&logo=mysql&logoColor=white" alt="MySQL">
12
14
  </p>
13
15
 
16
+ ## 💡 Highlights
17
+
18
+ - 🔐 Zero-credential codebase — resolves all database config from AWS SSM Parameter Store & Secrets Manager at runtime
19
+ - ♻️ Built-in automatic credential rotation with health checks, emergency recovery, and zero-downtime connection swaps
20
+ - 🏗️ Split-source architecture — infra teams own host/port/secrets, app teams own pool/timeout/sync settings independently
21
+ - 📦 Dual ESM/CJS module output with full TypeScript declarations and broad NestJS compatibility (v8–v11)
14
22
 
15
23
  ## 📚 Table of Contents
16
24
  - [Description](#-description)
25
+ - [Tech Stack](#-tech-stack)
17
26
  - [Features](#-features)
27
+ - [Architecture](#-architecture)
28
+ - [Project Structure](#-project-structure)
29
+ - [Prerequisites](#-prerequisites)
18
30
  - [Installation](#-installation)
19
31
  - [Usage](#-usage)
20
32
  - [Roadmap](#-roadmap)
21
33
  - [FAQ](#-faq)
22
34
  - [License](#-license)
23
-
35
+ - [Acknowledgments](#-acknowledgments)
24
36
 
25
37
  ## 📖 Description
26
- NestJS-TypeORM-AWS-Connector provides a robust solution for NestJS applications requiring secure database connections with credentials stored in AWS. This connector bridges the gap between your TypeORM-powered NestJS application and AWS services like Secrets Manager and Parameter Store, enabling secure credential management and automated rotation. Perfect for cloud-native applications, microservices, and enterprise systems where security and reliability are paramount. The connector supports multiple database types, connection pooling optimization, and eliminates hardcoded credentials in your codebase, significantly enhancing your application's security posture.
38
+ **NestJS-TypeORM-AWS-Connector** is a production-grade NestJS module that eliminates the pain of managing database configuration in AWS-hosted applications. Instead of hardcoding credentials or juggling environment variables, this connector resolves your entire TypeORM `DataSourceOptions` from **AWS Systems Manager Parameter Store** and **AWS Secrets Manager** — with built-in credential rotation.
27
39
 
28
- ## 🚀 Features
29
- - ✨ **Secure credential management with AWS Secrets Manager integration**
30
- - ✨ **Automatic database connection rotation to mitigate credential leaks**
31
- - ✨ **Configurable connection pooling for optimal database performance**
32
- - ✨ **Support for multiple database types (MySQL, PostgreSQL)**
33
- - ✨ **Customizable relation load strategies for performance optimization**
34
- - ✨ **Failure recovery mechanism for maintaining database connectivity**
35
- - ✨ **Easy integration with NestJS application configurations**
36
- - ✨ **Support for both synchronous and asynchronous module registration**
37
- - ✨ **Extensive logging for debugging and monitoring**
38
- - ✨ **Zero configuration option with sensible defaults**
40
+ In modern cloud-native architectures, database credentials are rotated regularly for security compliance. Traditional approaches break connections during rotation, causing downtime. This connector solves that with an intelligent **automatic credential rotation service** that seamlessly refreshes database connections with zero downtime, including emergency recovery after consecutive failures.
39
41
 
40
- ## 🛠 Installation
41
- ```bash
42
- # Using npm
43
- npm install @elsikora/nestjs-typeorm-aws-connector
42
+ ### Real-World Use Cases
44
43
 
45
- # Using yarn
46
- yarn add @elsikora/nestjs-typeorm-aws-connector
44
+ - **ECS Fargate Microservices**: Deploy NestJS APIs on Fargate where credentials are managed by AWS Secrets Manager with automatic rotation policies — the connector picks up fresh credentials without redeployment.
45
+ - **Multi-Environment Deployments**: Use the same codebase across `dev`, `staging`, and `production` — each environment resolves its own database configuration from namespaced SSM parameters.
46
+ - **Aurora PostgreSQL / RDS MySQL**: Connect to managed AWS databases where infrastructure teams control host, port, and secret references via Parameter Store, while application teams only configure entities and behavior.
47
+ - **Compliance-First Organizations**: Meet SOC2 and PCI-DSS requirements by never storing credentials in code, environment files, or container images.
47
48
 
48
- # Using pnpm
49
- pnpm add @elsikora/nestjs-typeorm-aws-connector
49
+ The connector uses a **split-source model**: infrastructure-owned parameters (host, port, secret ID) live in canonical AWS namespaces, while application-owned settings (pool size, timeouts, sync behavior) live in your app's namespace. Raw value overrides let you bypass SSM entirely for local development.
50
50
 
51
+ ## 🛠️ Tech Stack
51
52
 
52
- ### Prerequisites
53
+ | Category | Technologies |
54
+ |----------|-------------|
55
+ | **Language** | TypeScript |
56
+ | **Runtime** | Node.js |
57
+ | **Framework** | NestJS |
58
+ | **ORM** | TypeORM |
59
+ | **Cloud Services** | AWS SSM Parameter Store, AWS Secrets Manager |
60
+ | **Build Tool** | Rollup |
61
+ | **Linting** | ESLint, Prettier |
62
+ | **CI/CD** | GitHub Actions, Semantic Release |
63
+ | **Package Manager** | npm |
53
64
 
54
- - NestJS application
55
- - AWS credentials configured
56
- - TypeORM integrated with your NestJS app
65
+ ## 🚀 Features
66
+ - ✨ ****AWS Parameter Store Integration** — Resolves database host, port, name, type, and tuning parameters from structured SSM paths with hierarchical namespace support**
67
+ - ✨ ****AWS Secrets Manager Integration** — Fetches username/password credentials from Secrets Manager with proper error handling for missing or malformed secrets**
68
+ - ✨ ****Automatic Credential Rotation** — Configurable interval-based rotation that swaps database connections with zero downtime, including subscriber preservation**
69
+ - ✨ ****Emergency Recovery** — After 3 consecutive rotation failures, automatically attempts full connection recovery with fresh credentials from AWS**
70
+ - ✨ ****Connection Health Validation** — Validates both existing and new connections with `SELECT 1` queries before and after rotation**
71
+ - ✨ ****Split-Source Configuration Model** — Infrastructure-owned settings (host, port, secret-id) use canonical AWS namespaces; app-owned settings use your module namespace**
72
+ - ✨ ****Raw Value Overrides** — Bypass SSM entirely for any field by providing direct values — perfect for local development with `host: '127.0.0.1'`**
73
+ - ✨ ****Hierarchical Lookup Resolution** — Field-level SSM lookup → canonical defaults → ssmLookupDefaults → ParameterStoreConfigModule defaults**
74
+ - ✨ ****Dual Module Format** — Ships both ESM and CJS builds with full TypeScript declarations and source maps**
75
+ - ✨ ****Comprehensive Error Model** — Contextual error messages include the failing field name and full structured lookup context for fast debugging**
76
+ - ✨ ****Broad NestJS Compatibility** — Supports NestJS v8 through v11 as peer dependencies**
77
+ - ✨ ****Sync & Async Registration** — Use `register()` for static config or `registerAsync()` with factory functions for dynamic configuration**
78
+
79
+ ## 🏗 Architecture
80
+
81
+ ### System Architecture
82
+
83
+ ```mermaid
84
+ flowchart TD
85
+ appModule[AppModule] --> paramStore[ParameterStoreConfigModule]
86
+ appModule --> connectorModule[TypeOrmAwsConnectorModule]
87
+ connectorModule --> connectorService[TypeOrmAwsConnectorService]
88
+ connectorModule --> rotatorService[RotatorService]
89
+ connectorModule --> scheduleModule[ScheduleModule]
90
+ connectorService --> paramStoreService[ParameterStoreConfigService]
91
+ connectorService --> configService[NestJS ConfigService]
92
+ connectorService --> ssmParameterStore[AWS SSM Parameter Store]
93
+ connectorService --> secretsManager[AWS Secrets Manager]
94
+ rotatorService --> connectorService
95
+ rotatorService --> dataSource[TypeORM DataSource]
96
+ connectorModule --> typeOrmModule[TypeOrmModule.forRootAsync]
57
97
  ```
58
98
 
59
- ## ⚠️ Important Prerequisites
60
-
61
- This module requires `@elsikora/nestjs-aws-parameter-store-config` to function properly. Before using this module, please:
99
+ ### Data Flow
100
+
101
+ ```mermaid
102
+ sequenceDiagram
103
+ participant App as NestJS App
104
+ participant Connector as ConnectorService
105
+ participant SSM as AWS Parameter Store
106
+ participant SM as AWS Secrets Manager
107
+ participant TypeORM as TypeORM DataSource
108
+ participant Rotator as RotatorService
109
+
110
+ App->>Connector: getTypeOrmOptions()
111
+ Connector->>SSM: Resolve host, port, dbName, type
112
+ SSM-->>Connector: Parameter values
113
+ Connector->>SSM: Resolve secretId
114
+ SSM-->>Connector: Secret ID
115
+ Connector->>SM: GetSecretValue(secretId)
116
+ SM-->>Connector: username + password
117
+ Connector->>SSM: Resolve optional tuning params
118
+ SSM-->>Connector: poolSize, timeouts, etc.
119
+ Connector-->>App: DataSourceOptions
120
+ App->>TypeORM: Initialize DataSource
121
+
122
+ loop Every rotation interval
123
+ Rotator->>TypeORM: Validate connection health
124
+ Rotator->>Connector: getTypeOrmOptions()
125
+ Connector->>SM: Fetch fresh credentials
126
+ SM-->>Connector: New username + password
127
+ Rotator->>TypeORM: Destroy old connection
128
+ Rotator->>TypeORM: Initialize new DataSource
129
+ Rotator->>TypeORM: Verify with SELECT 1
130
+ Rotator->>TypeORM: Swap driver + restore subscribers
131
+ end
132
+ ```
62
133
 
63
- 1. Install and configure `@elsikora/nestjs-aws-parameter-store-config`
64
- 2. Familiarize yourself with its documentation and setup
65
- 3. Ensure it's properly configured in your NestJS application
134
+ ## 📁 Project Structure
66
135
 
67
- Example of both modules working together:
136
+ <details>
137
+ <summary>Click to expand</summary>
68
138
 
69
- ```typescript
70
- @Module({
71
- imports: [
72
- // First, configure Parameter Store
73
- ParameterStoreConfigModule.registerAsync({
74
- imports: [ConfigModule],
75
- inject: [ConfigService],
76
- useFactory: (config: ConfigService) => ({
77
- application: config.get<string>("APPLICATION"),
78
- config: {
79
- region: config.get<string>("AWS_REGION"),
80
- },
81
- decryptParameters: true,
82
- environment: config.get<string>("ENVIRONMENT"),
83
- recursiveLoading: true,
84
- }),
85
- }),
86
- // Then, configure Database module
87
- TypeOrmAwsConnectorModule.registerAsync({
88
- imports: [ConfigModule],
89
- inject: [ConfigService],
90
- useFactory: async () => ({
91
- connectionTimeoutMs: 30_000,
92
- databaseName: "app",
93
- entities: [Bank],
94
- // ... other options
95
- }),
96
- }),
97
- ],
98
- })
99
- export class AppModule {}
100
139
  ```
140
+ NestJS-TypeORM-AWS-Connector/
141
+ ├── .github/
142
+ │ ├── workflows/
143
+ │ │ ├── mirror-to-codecommit.yml
144
+ │ │ ├── qodana-quality-scan.yml
145
+ │ │ ├── release.yml
146
+ │ │ └── snyk-security-scan.yml
147
+ │ └── dependabot.yml
148
+ ├── src/
149
+ │ ├── modules/
150
+ │ │ └── typeorm-aws-connector/
151
+ │ ├── shared/
152
+ │ │ ├── constant/
153
+ │ │ ├── enum/
154
+ │ │ ├── interface/
155
+ │ │ ├── provider/
156
+ │ │ └── type/
157
+ │ └── index.ts
158
+ ├── CHANGELOG.md
159
+ ├── commitlint.config.js
160
+ ├── eslint.config.js
161
+ ├── LICENSE
162
+ ├── lint-staged.config.js
163
+ ├── nest-cli.json
164
+ ├── package-lock.json
165
+ ├── package.json
166
+ ├── prettier.config.js
167
+ ├── README.md
168
+ ├── release.config.js
169
+ ├── rollup.config.js
170
+ ├── tsconfig.build.json
171
+ └── tsconfig.json
172
+ ```
173
+
174
+ </details>
175
+
176
+ ## 📋 Prerequisites
177
+
178
+ - Node.js >= 18.0.0
179
+ - npm >= 9.0.0
180
+ - @nestjs/common ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0
181
+ - @aws-sdk/client-ssm ^3.535.0
182
+ - typeorm ^0.3.20
183
+ - @elsikora/nestjs-aws-parameter-store-config ^2.0.1 (installed automatically)
184
+ - AWS credentials configured (IAM role, environment variables, or AWS CLI profile)
185
+
186
+ ## 🛠 Installation
187
+ ```bash
188
+ # Install the connector and its required peer dependencies
189
+ npm install @elsikora/nestjs-typeorm-aws-connector @aws-sdk/client-ssm @nestjs/common typeorm
101
190
 
102
- For more information about the Parameter Store configuration, please refer to the [@elsikora/nestjs-aws-parameter-store-config documentation](https://github.com/ElsiKora/NestJS-AWS-Parameter-Store-Config).
191
+ # The following are installed automatically as dependencies:
192
+ # @aws-sdk/client-secrets-manager
193
+ # @elsikora/nestjs-aws-parameter-store-config
194
+ # @nestjs/config
195
+ # @nestjs/schedule
196
+
197
+
198
+ ### Verify Installation
199
+
200
+
201
+ npm ls @elsikora/nestjs-typeorm-aws-connector
202
+ ```
103
203
 
104
204
  ## 💡 Usage
105
- ## Basic Usage
205
+ ### Prerequisites: Register Parameter Store Config Module
106
206
 
107
- First, import the module in your NestJS application's main module:
207
+ Before using the connector, register `ParameterStoreConfigModule` from `@elsikora/nestjs-aws-parameter-store-config`:
108
208
 
109
209
  ```typescript
110
- import { Module } from '@nestjs/common';
111
- import { TypeOrmAwsConnectorModule } from '@elsikora/nestjs-typeorm-aws-connector';
112
- import { EDatabaseType } from '@elsikora/nestjs-typeorm-aws-connector';
113
- import { UserEntity } from './entities/user.entity';
210
+ import { Module } from "@nestjs/common";
211
+ import { ConfigModule, ConfigService } from "@nestjs/config";
212
+ import { ENamespace, ParameterStoreConfigModule } from "@elsikora/nestjs-aws-parameter-store-config";
114
213
 
115
214
  @Module({
116
215
  imports: [
117
- TypeOrmAwsConnectorModule.register({
118
- type: EDatabaseType.POSTGRES,
119
- databaseName: 'my_database',
120
- port: 5432,
121
- entities: [UserEntity],
122
- // Optionally enable credential rotation
123
- rotation: {
124
- isEnabled: true,
125
- intervalMs: 3600000, // 1 hour
126
- }
216
+ ConfigModule.forRoot(),
217
+ ParameterStoreConfigModule.registerAsync({
218
+ imports: [ConfigModule],
219
+ inject: [ConfigService],
220
+ useFactory: (configService: ConfigService) => ({
221
+ application: configService.getOrThrow<string>("APPLICATION"),
222
+ config: { region: configService.getOrThrow<string>("AWS_REGION") },
223
+ environment: configService.getOrThrow<string>("ENVIRONMENT"),
224
+ instanceName: "my-api",
225
+ namespace: ENamespace.AWS_ECS_FARGATE,
226
+ shouldDecryptParameters: true,
227
+ }),
127
228
  }),
128
229
  ],
129
230
  })
130
231
  export class AppModule {}
131
232
  ```
132
233
 
133
- ## Asynchronous Configuration
234
+ ---
134
235
 
135
- If you need to load configuration asynchronously, use the `registerAsync` method:
236
+ ### Basic Usage: Static Registration
136
237
 
137
238
  ```typescript
138
- import { Module } from '@nestjs/common';
139
- import { ConfigModule, ConfigService } from '@nestjs/config';
140
- import { TypeOrmAwsConnectorModule } from '@elsikora/nestjs-typeorm-aws-connector';
141
- import { EDatabaseType } from '@elsikora/nestjs-typeorm-aws-connector';
239
+ import { Module } from "@nestjs/common";
240
+ import { TypeOrmModule } from "@nestjs/typeorm";
241
+ import {
242
+ TypeOrmAwsConnectorModule,
243
+ TypeOrmAwsConnectorService,
244
+ } from "@elsikora/nestjs-typeorm-aws-connector";
245
+ import { UserEntity } from "./entities/user.entity";
142
246
 
143
247
  @Module({
144
248
  imports: [
145
- ConfigModule.forRoot(),
146
- TypeOrmAwsConnectorModule.registerAsync({
147
- imports: [ConfigModule],
148
- inject: [ConfigService],
149
- useFactory: (configService: ConfigService) => ({
150
- type: EDatabaseType.MYSQL,
151
- databaseName: configService.get('DB_NAME'),
152
- port: configService.get('DB_PORT'),
153
- entities: [__dirname + '/**/*.entity{.ts,.js}'],
154
- rotation: {
155
- isEnabled: configService.get('DB_ROTATION_ENABLED') === 'true',
156
- },
157
- }),
249
+ // Register the connector with your entities
250
+ TypeOrmAwsConnectorModule.register({
251
+ entities: [UserEntity],
252
+ }),
253
+ // Wire it into TypeOrmModule
254
+ TypeOrmModule.forRootAsync({
255
+ imports: [TypeOrmAwsConnectorModule],
256
+ inject: [TypeOrmAwsConnectorService],
257
+ useFactory: async (connector: TypeOrmAwsConnectorService) =>
258
+ connector.getTypeOrmOptions(),
158
259
  }),
159
260
  ],
160
261
  })
161
- export class AppModule {}
262
+ export class DatabaseModule {}
162
263
  ```
163
264
 
164
- ## Using TypeOrmAwsConnectorService
265
+ ---
266
+
267
+ ### Custom SSM Lookups
165
268
 
166
- Inject the service to manually retrieve database connection options:
269
+ Override where specific fields are resolved from in Parameter Store:
167
270
 
168
271
  ```typescript
169
- import { Injectable } from '@nestjs/common';
170
- import { TypeOrmAwsConnectorService } from '@elsikora/nestjs-typeorm-aws-connector';
171
- import { DataSource, DataSourceOptions } from 'typeorm';
172
-
173
- @Injectable()
174
- export class DatabaseService {
175
- private dataSource: DataSource;
176
-
177
- constructor(private readonly connectorService: TypeOrmAwsConnectorService) {}
178
-
179
- async initializeConnection() {
180
- const options: DataSourceOptions = await this.connectorService.getTypeOrmOptions();
181
- this.dataSource = new DataSource(options);
182
- await this.dataSource.initialize();
183
- return this.dataSource;
184
- }
185
- }
272
+ import { ENamespace } from "@elsikora/nestjs-aws-parameter-store-config";
273
+ import { TypeOrmAwsConnectorModule } from "@elsikora/nestjs-typeorm-aws-connector";
274
+
275
+ TypeOrmAwsConnectorModule.register({
276
+ entities: [UserEntity],
277
+ ssmLookupDefaults: {
278
+ instanceName: "my-api",
279
+ namespace: ENamespace.AWS_ECS_FARGATE,
280
+ },
281
+ ssmLookups: {
282
+ secretId: {
283
+ instanceName: "database",
284
+ namespace: ENamespace.AWS_SECRETS_MANAGER,
285
+ path: ["secret-id"],
286
+ },
287
+ host: {
288
+ instanceName: "aurora-postgres",
289
+ namespace: ENamespace.AWS_RDS,
290
+ path: ["host"],
291
+ },
292
+ port: {
293
+ instanceName: "aurora-postgres",
294
+ namespace: ENamespace.AWS_RDS,
295
+ path: ["port"],
296
+ },
297
+ },
298
+ });
186
299
  ```
187
300
 
188
- ## AWS Parameter Store and Secrets Manager Configuration
301
+ ---
302
+
303
+ ### Local Development: Raw Value Overrides
189
304
 
190
- The connector expects your AWS environment to be properly configured:
305
+ Bypass AWS entirely for local development:
191
306
 
192
307
  ```typescript
193
- // Simplified example of AWS setup requirements
194
- // In your AWS Parameter Store:
195
- // /myapp/database-credentials-secret-id -> 'db-credentials-secret-id'
196
- // /myapp/host -> 'your-database-hostname'
197
-
198
- // In AWS Secrets Manager (with ID 'db-credentials-secret-id'):
199
- // {
200
- // "username": "dbuser",
201
- // "password": "dbpassword"
202
- // }
203
-
204
- // Your NestJS module configuration
308
+ import { EDatabaseType } from "@elsikora/nestjs-typeorm-aws-connector";
309
+
205
310
  TypeOrmAwsConnectorModule.register({
206
- type: EDatabaseType.POSTGRES,
207
- databaseName: 'myapp_db',
311
+ entities: [UserEntity],
312
+ host: "127.0.0.1",
208
313
  port: 5432,
209
- entities: [__dirname + '/**/*.entity{.ts,.js}'],
210
- secretID: {
211
- path: ['myapp', 'database-credentials-secret-id'],
212
- service: EService.AWS_SECRETS_MANAGER
213
- },
214
- host: {
215
- path: ['myapp', 'host'],
216
- service: EService.AWS_RDS
217
- }
218
- })
314
+ username: "local-user",
315
+ password: "local-password",
316
+ databaseName: "mydb",
317
+ type: EDatabaseType.POSTGRES,
318
+ });
219
319
  ```
220
320
 
221
- ## Connection Rotation
321
+ ---
322
+
323
+ ### Enabling Credential Rotation
222
324
 
223
- Enable automatic credential rotation for enhanced security:
325
+ Enable automatic credential rotation for long-running services:
224
326
 
225
327
  ```typescript
226
328
  TypeOrmAwsConnectorModule.register({
227
- // Basic config...
228
- type: EDatabaseType.POSTGRES,
229
- databaseName: 'myapp_db',
230
- port: 5432,
231
329
  entities: [UserEntity],
232
-
233
- // Rotation config
234
330
  rotation: {
235
331
  isEnabled: true,
236
- intervalMs: 1800000 // Rotate every 30 minutes
332
+ intervalMs: 3_600_000, // Rotate every hour
237
333
  },
238
-
239
- // Advanced connection pool settings
240
- poolSize: 20,
241
- connectionTimeoutMs: 60000,
242
- idleTimeoutMs: 30000
243
- })
334
+ });
244
335
  ```
245
336
 
246
- ## Advanced Configuration Options
337
+ The rotation service will:
338
+ 1. Validate current connection health
339
+ 2. Fetch fresh credentials from AWS Secrets Manager
340
+ 3. Create a new DataSource with updated credentials
341
+ 4. Verify the new connection with a `SELECT 1` query
342
+ 5. Swap the driver seamlessly, preserving all subscribers
343
+ 6. Attempt emergency recovery after 3 consecutive failures
247
344
 
248
- You can fine-tune the connector with various options:
345
+ ---
249
346
 
250
- ```typescript
251
- import { ERelationLoadStrategy } from '@elsikora/nestjs-typeorm-aws-connector';
347
+ ### Async Registration with Factory
252
348
 
253
- TypeOrmAwsConnectorModule.register({
254
- // Basic config...
255
- type: EDatabaseType.POSTGRES,
256
- databaseName: 'myapp_db',
257
- port: 5432,
258
- entities: [UserEntity],
259
-
260
- // Performance settings
261
- poolSize: 15,
262
- connectionTimeoutMs: 30000,
263
- idleTimeoutMs: 60000,
264
-
265
- // Database behavior
266
- shouldSynchronize: false,
267
- isVerbose: true,
268
- relationLoadStrategy: ERelationLoadStrategy.QUERY,
269
-
270
- // AWS configuration
271
- secretID: {
272
- path: ['my-app', 'db-secret-id'],
273
- service: EService.AWS_SECRETS_MANAGER
274
- },
275
- host: {
276
- path: ['my-app', 'db-host'],
277
- service: EService.AWS_RDS
278
- }
279
- })
349
+ ```typescript
350
+ TypeOrmAwsConnectorModule.registerAsync({
351
+ imports: [ConfigModule],
352
+ inject: [ConfigService],
353
+ useFactory: (configService: ConfigService) => ({
354
+ entities: [UserEntity],
355
+ rotation: {
356
+ isEnabled: configService.get<boolean>("DB_ROTATION_ENABLED", false),
357
+ intervalMs: configService.get<number>("DB_ROTATION_INTERVAL", 3_600_000),
358
+ },
359
+ }),
360
+ });
280
361
  ```
281
362
 
363
+ ---
364
+
365
+ ### Value Resolution Priority
366
+
367
+ For each configuration field, values are resolved in this order:
368
+
369
+ 1. **Raw value override** (provided directly in config)
370
+ 2. **SSM Parameter Store lookup** (via structured lookup)
371
+ 3. **Built-in default** (only for optional tuning fields like `poolSize`, `connectionTimeoutMs`)
372
+
373
+ Required fields (`host`, `port`, `databaseName`, `type`, `secretId`) throw explicit errors if not resolvable.
374
+
282
375
  ## 🛣 Roadmap
376
+
377
+ <details>
378
+ <summary>Click to expand</summary>
379
+
283
380
  | Task / Feature | Status |
284
- |---------------|--------|
285
- | Core module implementation | ✅ Done |
286
- | AWS Secrets Manager integration | ✅ Done |
287
- | TypeORM configuration provider | ✅ Done |
288
- | Connection rotation service | ✅ Done |
289
- | Credential rotation automation | ✅ Done |
290
- | PostgreSQL database support | ✅ Done |
291
- | MySQL database support | ✅ Done |
292
- | Failover recovery mechanism | ✅ Done |
293
- | Customizable rotation intervals | ✅ Done |
294
- | Connection pooling optimization | ✅ Done |
295
- | Multiple AWS regions support | 🚧 In Progress |
296
- | Automatic Schema Migration | 🚧 In Progress |
297
- | Connection encryption options | 🚧 In Progress |
298
- | MongoDB support | 🚧 In Progress |
299
- | Connection health metrics | 🚧 In Progress |
300
- | Multi-database connection management | 🚧 In Progress |
301
- | Docker integration examples | 🚧 In Progress |
302
- | AWS Lambda optimized configuration | 🚧 In Progress |
381
+ |---|---|
382
+ | Dual ESM/CJS module output | ✅ Done |
383
+ | AWS Secrets Manager credential resolution | ✅ Done |
384
+ | Automatic credential rotation with zero downtime | ✅ Done |
385
+ | Emergency recovery after consecutive rotation failures | ✅ Done |
386
+ | Split-source configuration model (infra vs app namespaces) | ✅ Done |
387
+ | Raw value overrides for local development | ✅ Done |
388
+ | Async module registration with factory pattern | ✅ Done |
389
+ | Semantic release with prerelease channel | ✅ Done |
390
+ | Support for additional database types (e.g., MariaDB, CockroachDB) | 🚧 In Progress |
391
+ | Connection pool monitoring and metrics export | 🚧 In Progress |
392
+ | Read replica support with separate SSM lookups | 🚧 In Progress |
393
+ | Integration test suite with LocalStack | 🚧 In Progress |
394
+
395
+ </details>
303
396
 
304
397
  ## ❓ FAQ
305
- ### Frequently Asked Questions
306
398
 
307
- #### Q: Does this library work with AWS Fargate and ECS?
308
- A: Yes, this library is designed to work seamlessly with AWS container services like Fargate and ECS. Ensure your task roles have proper permissions to access Parameter Store and Secrets Manager.
399
+ <details>
400
+ <summary>Click to expand</summary>
309
401
 
310
- #### Q: How does credential rotation work?
311
- A: When rotation is enabled, the connector periodically fetches fresh credentials from AWS Secrets Manager without disrupting existing connections. It creates a new connection pool with updated credentials, verifies it works correctly, and then seamlessly replaces the old connection.
402
+ ### ❓ Frequently Asked Questions
312
403
 
313
- #### Q: What happens if AWS services are temporarily unavailable?
314
- A: The connector includes a failover mechanism that retries connection attempts and maintains the current connection until AWS services become available again. After multiple failures, it will attempt an emergency recovery process.
404
+ **Q: Do I need AWS credentials to use this locally?**
405
+ A: No! Use raw value overrides to bypass AWS entirely during local development. Set `host`, `port`, `username`, `password`, `databaseName`, and `type` directly in the config.
315
406
 
316
- #### Q: Can I use this with non-AWS hosted databases?
317
- A: Yes, you can use this connector with any database as long as the connection credentials are stored in AWS Secrets Manager and Parameter Store. The actual database can be hosted anywhere.
407
+ **Q: Which databases are supported?**
408
+ A: Currently PostgreSQL (`EDatabaseType.POSTGRES`) and MySQL (`EDatabaseType.MYSQL`). The `type` field is resolved from SSM or set directly.
318
409
 
319
- #### Q: Does this support custom TypeORM entities and migrations?
320
- A: Absolutely. The connector seamlessly integrates with your existing TypeORM entities and migration configurations.
410
+ **Q: What happens if AWS Secrets Manager is unreachable during rotation?**
411
+ A: The rotation service catches the error, increments a failure counter, and logs it. After 3 consecutive failures, it attempts an emergency recovery with a completely fresh DataSource. The existing connection continues to function until rotation succeeds.
321
412
 
322
- #### Q: What permissions do I need in AWS?
323
- A: Your AWS role needs read permissions for Parameter Store and Secrets Manager. Specifically, you need `ssm:GetParameter` and `secretsmanager:GetSecretValue` permissions.
413
+ **Q: Can I use this without `@elsikora/nestjs-aws-parameter-store-config`?**
414
+ A: No. The connector depends on `ParameterStoreConfigService.get()` for SSM lookups. You must register `ParameterStoreConfigModule` first. However, if you provide raw values for all fields, SSM lookups won't actually be invoked.
324
415
 
325
- #### Q: Can I customize the logger?
326
- A: The connector uses NestJS's built-in logger by default, which you can customize through your NestJS application configuration.
416
+ **Q: How does the split-source model work?**
417
+ A: Infrastructure-owned fields like `host`, `port`, and `secretId` default to canonical AWS namespaces (e.g., `aws-rds/aurora-postgres`). Application-owned fields like `poolSize` and `connectionTimeoutMs` use your app's namespace (e.g., `aws-ecs-fargate/my-api`). You can override any lookup.
327
418
 
328
- ## 🔒 License
329
- This project is licensed under **MIT License
419
+ **Q: Is this compatible with NestJS v8?**
420
+ A: Yes. The peer dependency accepts `@nestjs/common ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0`.
330
421
 
331
- Copyright (c) 2025 ElsiKora
422
+ **Q: How do I disable credential rotation?**
423
+ A: Don't set the `rotation` config, or explicitly set `rotation.isEnabled: false`. The `RotatorService` will skip interval registration entirely.
332
424
 
333
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
425
+ **Q: What's the default rotation interval?**
426
+ A: 1 hour (3,600,000 ms). Override it via `rotation.intervalMs` or the SSM path `typeorm/rotation/interval-ms`.
334
427
 
335
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
428
+ </details>
336
429
 
337
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**.
430
+ ## 🔒 License
431
+ This project is licensed under **MIT**.
432
+
433
+ ## 🙏 Acknowledgments
434
+ - **[NestJS](https://nestjs.com/)** — The progressive Node.js framework that makes building server-side applications a joy
435
+ - **[TypeORM](https://typeorm.io/)** — The ORM that powers the database layer with decorator-based entity definitions
436
+ - **[AWS SDK for JavaScript v3](https://github.com/aws/aws-sdk-js-v3)** — Modular AWS SDK used for SSM and Secrets Manager client operations
437
+ - **[@elsikora/nestjs-aws-parameter-store-config](https://github.com/ElsiKora/nestjs-aws-parameter-store-config)** — The Parameter Store config module that provides the structured lookup foundation
438
+ - **[Semantic Release](https://semantic-release.gitbook.io/)** — Automated versioning and changelog generation
439
+ - **[Rollup](https://rollupjs.org/)** — Module bundler powering the dual ESM/CJS build output
440
+ - Built with ❤️ by [ElsiKora](https://github.com/ElsiKora)
441
+
442
+ ---
443
+
444
+ <p align="center">
445
+ <a href="#top">Back to Top</a>
446
+ </p>