@vn.chemgio/nestjs-utilities 2.0.0

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.
@@ -0,0 +1,100 @@
1
+ # @vn.chemgio/nestjs-utilities/typeorm
2
+
3
+ TypeORM configuration helpers for cloud databases (RDS PostgreSQL / MySQL).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @vn.chemgio/nestjs-utilities @nestjs/typeorm @nestjs/config
9
+ ```
10
+
11
+ ## Prerequisites
12
+
13
+ The following environment variables must be declared in your `.env` file (or provided to `ConfigModule.forRoot()`):
14
+
15
+ | Variable | Required | Default |
16
+ |---|---|---|
17
+ | `DB_HOST` | No | `localhost` |
18
+ | `DB_PORT` | No | `5432` (PG) / `3306` (MySQL) |
19
+ | `DB_USERNAME` | Yes | — |
20
+ | `DB_PASSWORD` | Yes | — |
21
+ | `DB_DATABASE` | No | `postgres` / `mysql` |
22
+ | `DB_SYNCHRONIZE` | No | `false` |
23
+ | `DB_LOGGING` | No | `false` |
24
+ | `DB_SSL_REJECT_UNAUTHORIZED` | No | `false` |
25
+
26
+ ## Usage
27
+
28
+ ```typescript
29
+ // app.module.ts
30
+ import { Module } from '@nestjs/common'
31
+ import { ConfigModule, ConfigService } from '@nestjs/config'
32
+ import { TypeOrmModule } from '@nestjs/typeorm'
33
+ import { configTypeOrmRDSPostgres } from '@vn.chemgio/nestjs-utilities/typeorm'
34
+
35
+ @Module({
36
+ imports: [
37
+ ConfigModule.forRoot(),
38
+ TypeOrmModule.forRootAsync({
39
+ inject: [ConfigService],
40
+ useFactory: (config: ConfigService) =>
41
+ configTypeOrmRDSPostgres(config, {
42
+ poolSize: 20,
43
+ schema: 'public',
44
+ }),
45
+ }),
46
+ ],
47
+ })
48
+ export class AppModule {}
49
+ ```
50
+
51
+ ## Environment variables
52
+
53
+ | Variable | Default | Type | Description |
54
+ |---|---|---|---|
55
+ | `DB_HOST` | `localhost` | `string` | Database host |
56
+ | `DB_PORT` | `5432` (PG) / `3306` (MySQL) | `number` | Connection port |
57
+ | `DB_USERNAME` | — | `string` | Database username |
58
+ | `DB_PASSWORD` | — | `string` | Database password |
59
+ | `DB_DATABASE` | `postgres` / `mysql` | `string` | Database name |
60
+ | `DB_SYNCHRONIZE` | `false` | `boolean` | Auto-sync schema (dev only) |
61
+ | `DB_LOGGING` | `false` | `boolean` | Enable query logging |
62
+ | `DB_SSL_REJECT_UNAUTHORIZED` | `false` | `boolean` | Reject unauthorized SSL certs |
63
+
64
+ ## TypeOrmConfigOptions
65
+
66
+ | Option | Default | Description |
67
+ |---|---|---|
68
+ | `schema` | — | PostgreSQL schema (e.g. `public`) |
69
+ | `poolSize` | `20` (PG) / `10` (MySQL) | Maximum connections in pool |
70
+ | `idleTimeoutMs` | `30000` (PG) / `10000` (MySQL) | Max idle time before closing |
71
+ | `connectionTimeoutMs` | `10000` (PG) / `5000` (MySQL) | Connection timeout |
72
+ | `statementTimeoutMs` | `30000` (PG) | Query timeout |
73
+
74
+ ## SSL — why both `ssl` and `extra.ssl`?
75
+
76
+ ```typescript
77
+ ssl: { rejectUnauthorized: false },
78
+ extra: {
79
+ ssl: { rejectUnauthorized: false },
80
+ // ...
81
+ }
82
+ ```
83
+
84
+ - **`ssl`** — tells TypeORM to configure the driver (`pg` / `mysql2`) with TLS
85
+ - **`extra.ssl`** — passes SSL config directly to the underlying driver pool
86
+
87
+ Cloud databases (AWS RDS, Google Cloud SQL, etc.) often use self-signed certificates, requiring `rejectUnauthorized: false` to trust them.
88
+
89
+ ## Sample .env
90
+
91
+ ```bash
92
+ DB_HOST=database-1.xxxxxx.us-east-1.rds.amazonaws.com
93
+ DB_PORT=5432
94
+ DB_USERNAME=postgres
95
+ DB_PASSWORD=my-secret-pw
96
+ DB_DATABASE=mydb
97
+ DB_SYNCHRONIZE=false
98
+ DB_LOGGING=true
99
+ DB_SSL_REJECT_UNAUTHORIZED=false
100
+ ```
@@ -0,0 +1,11 @@
1
+ import type { ConfigService } from '@nestjs/config';
2
+ import type { TypeOrmModuleOptions } from '@nestjs/typeorm';
3
+ export interface TypeOrmConfigOptions {
4
+ schema?: string;
5
+ poolSize?: number;
6
+ idleTimeoutMs?: number;
7
+ connectionTimeoutMs?: number;
8
+ statementTimeoutMs?: number;
9
+ }
10
+ export declare function configTypeOrmRDSPostgres(configService: ConfigService, options?: TypeOrmConfigOptions): TypeOrmModuleOptions;
11
+ export declare function configTypeOrmMySQL(configService: ConfigService, options?: TypeOrmConfigOptions): TypeOrmModuleOptions;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configTypeOrmRDSPostgres = configTypeOrmRDSPostgres;
4
+ exports.configTypeOrmMySQL = configTypeOrmMySQL;
5
+ function configTypeOrmRDSPostgres(configService, options) {
6
+ const rejectUnauthorized = configService.get('DB_SSL_REJECT_UNAUTHORIZED', false);
7
+ return {
8
+ type: 'postgres',
9
+ host: configService.get('DB_HOST', 'localhost'),
10
+ port: configService.get('DB_PORT', 5432),
11
+ username: configService.get('DB_USERNAME'),
12
+ password: configService.get('DB_PASSWORD'),
13
+ database: configService.get('DB_DATABASE', 'postgres'),
14
+ synchronize: configService.get('DB_SYNCHRONIZE', false),
15
+ logging: configService.get('DB_LOGGING', false) ? 'all' : false,
16
+ ssl: { rejectUnauthorized },
17
+ extra: {
18
+ ssl: { rejectUnauthorized },
19
+ max: options?.poolSize ?? 20,
20
+ idleTimeoutMillis: options?.idleTimeoutMs ?? 30000,
21
+ connectionTimeoutMillis: options?.connectionTimeoutMs ?? 10000,
22
+ statement_timeout: options?.statementTimeoutMs ?? 30000,
23
+ ...(options?.schema ? { schema: options.schema } : {}),
24
+ },
25
+ autoLoadEntities: true,
26
+ retryAttempts: 10,
27
+ retryDelay: 3000,
28
+ };
29
+ }
30
+ function configTypeOrmMySQL(configService, options) {
31
+ const rejectUnauthorized = configService.get('DB_SSL_REJECT_UNAUTHORIZED', false);
32
+ return {
33
+ type: 'mysql',
34
+ host: configService.get('DB_HOST', 'localhost'),
35
+ port: configService.get('DB_PORT', 3306),
36
+ username: configService.get('DB_USERNAME'),
37
+ password: configService.get('DB_PASSWORD'),
38
+ database: configService.get('DB_DATABASE', 'mysql'),
39
+ synchronize: configService.get('DB_SYNCHRONIZE', false),
40
+ logging: configService.get('DB_LOGGING', false) ? 'all' : false,
41
+ ssl: { rejectUnauthorized },
42
+ extra: {
43
+ ssl: { rejectUnauthorized },
44
+ max: options?.poolSize ?? 10,
45
+ idleTimeoutMillis: options?.idleTimeoutMs ?? 10000,
46
+ connectionTimeoutMillis: options?.connectionTimeoutMs ?? 5000,
47
+ },
48
+ autoLoadEntities: true,
49
+ retryAttempts: 10,
50
+ retryDelay: 3000,
51
+ };
52
+ }
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/typeorm/index.ts"],"names":[],"mappings":";;AAWA,4DA8BC;AAED,gDA4BC;AA5DD,SAAgB,wBAAwB,CACtC,aAA4B,EAC5B,OAA8B;IAE9B,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAC1C,4BAA4B,EAC5B,KAAK,CACN,CAAC;IACF,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,aAAa,CAAC,GAAG,CAAS,SAAS,EAAE,WAAW,CAAC;QACvD,IAAI,EAAE,aAAa,CAAC,GAAG,CAAS,SAAS,EAAE,IAAI,CAAC;QAChD,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAqB,aAAa,CAAC;QAC9D,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAqB,aAAa,CAAC;QAC9D,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAS,aAAa,EAAE,UAAU,CAAC;QAC9D,WAAW,EAAE,aAAa,CAAC,GAAG,CAAU,gBAAgB,EAAE,KAAK,CAAC;QAChE,OAAO,EAAE,aAAa,CAAC,GAAG,CAAU,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;QACxE,GAAG,EAAE,EAAE,kBAAkB,EAAE;QAC3B,KAAK,EAAE;YACL,GAAG,EAAE,EAAE,kBAAkB,EAAE;YAC3B,GAAG,EAAE,OAAO,EAAE,QAAQ,IAAI,EAAE;YAC5B,iBAAiB,EAAE,OAAO,EAAE,aAAa,IAAI,KAAK;YAClD,uBAAuB,EAAE,OAAO,EAAE,mBAAmB,IAAI,KAAK;YAC9D,iBAAiB,EAAE,OAAO,EAAE,kBAAkB,IAAI,KAAK;YACvD,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvD;QACD,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,EAAE;QACjB,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAChC,aAA4B,EAC5B,OAA8B;IAE9B,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAC1C,4BAA4B,EAC5B,KAAK,CACN,CAAC;IACF,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,aAAa,CAAC,GAAG,CAAS,SAAS,EAAE,WAAW,CAAC;QACvD,IAAI,EAAE,aAAa,CAAC,GAAG,CAAS,SAAS,EAAE,IAAI,CAAC;QAChD,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAqB,aAAa,CAAC;QAC9D,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAqB,aAAa,CAAC;QAC9D,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAS,aAAa,EAAE,OAAO,CAAC;QAC3D,WAAW,EAAE,aAAa,CAAC,GAAG,CAAU,gBAAgB,EAAE,KAAK,CAAC;QAChE,OAAO,EAAE,aAAa,CAAC,GAAG,CAAU,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;QACxE,GAAG,EAAE,EAAE,kBAAkB,EAAE;QAC3B,KAAK,EAAE;YACL,GAAG,EAAE,EAAE,kBAAkB,EAAE;YAC3B,GAAG,EAAE,OAAO,EAAE,QAAQ,IAAI,EAAE;YAC5B,iBAAiB,EAAE,OAAO,EAAE,aAAa,IAAI,KAAK;YAClD,uBAAuB,EAAE,OAAO,EAAE,mBAAmB,IAAI,IAAI;SAC9D;QACD,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,EAAE;QACjB,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,156 @@
1
+ {
2
+ "name": "@vn.chemgio/nestjs-utilities",
3
+ "version": "2.0.0",
4
+ "description": "NestJS utilities collection - modular packages for common NestJS integrations",
5
+ "author": {
6
+ "name": "Wind Blade",
7
+ "url": "https://github.com/Vn-ChemGio"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/Vn-ChemGio/nestjs-utilities.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Vn-ChemGio/nestjs-utilities/issues"
15
+ },
16
+ "homepage": "https://github.com/Vn-ChemGio/nestjs-utilities#readme",
17
+ "private": false,
18
+ "license": "MIT",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js",
23
+ "require": "./dist/index.js"
24
+ },
25
+ "./typeorm": {
26
+ "types": "./dist/typeorm/index.d.ts",
27
+ "import": "./dist/typeorm/index.js",
28
+ "require": "./dist/typeorm/index.js"
29
+ },
30
+ "./cache": {
31
+ "types": "./dist/cache/index.d.ts",
32
+ "import": "./dist/cache/index.js",
33
+ "require": "./dist/cache/index.js"
34
+ },
35
+ "./queue": {
36
+ "types": "./dist/queue/index.d.ts",
37
+ "import": "./dist/queue/index.js",
38
+ "require": "./dist/queue/index.js"
39
+ }
40
+ },
41
+ "typesVersions": {
42
+ "*": {
43
+ "typeorm": [
44
+ "./dist/typeorm/index.d.ts"
45
+ ],
46
+ "cache": [
47
+ "./dist/cache/index.d.ts"
48
+ ],
49
+ "queue": [
50
+ "./dist/queue/index.d.ts"
51
+ ]
52
+ }
53
+ },
54
+ "main": "./dist/index.js",
55
+ "types": "./dist/index.d.ts",
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "files": [
60
+ "dist",
61
+ "README.md",
62
+ "src/typeorm/README.md",
63
+ "src/cache/README.md",
64
+ "src/queue/README.md"
65
+ ],
66
+ "scripts": {
67
+ "build": "tsc -p tsconfig.build.json && node -e \"require('fs').copyFileSync('src/typeorm/README.md','dist/typeorm/README.md');require('fs').copyFileSync('src/cache/README.md','dist/cache/README.md');require('fs').copyFileSync('src/queue/README.md','dist/queue/README.md')\"",
68
+ "clean": "rimraf dist",
69
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
70
+ "lint": "eslint \"{src,test}/**/*.ts\" --fix",
71
+ "test": "jest",
72
+ "test:watch": "jest --watch",
73
+ "test:cov": "jest --coverage",
74
+ "prepublishOnly": "npm run build",
75
+ "prepack": "npm run build"
76
+ },
77
+ "peerDependencies": {
78
+ "@keyv/redis": "^5.1.6",
79
+ "@keyv/valkey": "^1.0.11",
80
+ "@nestjs/common": "^11.0.1",
81
+ "@nestjs/config": "^4.0.4",
82
+ "@nestjs/core": "^11.0.1",
83
+ "@nestjs/typeorm": "^11.0.1",
84
+ "rxjs": "^7.8.1",
85
+ "@nestjs/bullmq": "^11.0.0",
86
+ "bullmq": "^5.44.0"
87
+ },
88
+ "peerDependenciesMeta": {
89
+ "@nestjs/typeorm": {
90
+ "optional": true
91
+ },
92
+ "@nestjs/config": {
93
+ "optional": true
94
+ },
95
+ "@keyv/valkey": {
96
+ "optional": true
97
+ },
98
+ "@keyv/redis": {
99
+ "optional": true
100
+ },
101
+ "@nestjs/bullmq": {
102
+ "optional": true
103
+ },
104
+ "bullmq": {
105
+ "optional": true
106
+ }
107
+ },
108
+ "dependencies": {
109
+ "cacheable": "^2.3.5",
110
+ "keyv": "^5.6.0",
111
+ "reflect-metadata": "^0.2.2"
112
+ },
113
+ "devDependencies": {
114
+ "@eslint/eslintrc": "^3.2.0",
115
+ "@eslint/js": "^9.18.0",
116
+ "@keyv/redis": "^5.1.6",
117
+ "@keyv/valkey": "^1.0.11",
118
+ "@nestjs/common": "^11.0.1",
119
+ "@nestjs/config": "^4.0.4",
120
+ "@nestjs/core": "^11.0.1",
121
+ "@nestjs/testing": "^11.0.1",
122
+ "@nestjs/typeorm": "^11.0.1",
123
+ "@nestjs/bullmq": "^11.0.0",
124
+ "bullmq": "^5.44.0",
125
+ "@types/jest": "^30.0.0",
126
+ "@types/node": "^24.0.0",
127
+ "eslint": "^9.18.0",
128
+ "eslint-config-prettier": "^10.0.1",
129
+ "eslint-plugin-prettier": "^5.2.2",
130
+ "globals": "^17.0.0",
131
+ "jest": "^30.0.0",
132
+ "prettier": "^3.4.2",
133
+ "rimraf": "^6.0.1",
134
+ "rxjs": "^7.8.1",
135
+ "ts-jest": "^29.2.5",
136
+ "typescript": "^5.7.3",
137
+ "typescript-eslint": "^8.20.0"
138
+ },
139
+ "jest": {
140
+ "moduleFileExtensions": [
141
+ "js",
142
+ "json",
143
+ "ts"
144
+ ],
145
+ "rootDir": "src",
146
+ "testRegex": ".*\\.spec\\.ts$",
147
+ "transform": {
148
+ "^.+\\.(t|j)s$": "ts-jest"
149
+ },
150
+ "collectCoverageFrom": [
151
+ "**/*.(t|j)s"
152
+ ],
153
+ "coverageDirectory": "../coverage",
154
+ "testEnvironment": "node"
155
+ }
156
+ }
@@ -0,0 +1,91 @@
1
+ # @vn.chemgio/nestjs-utilities/cache
2
+
3
+ A global NestJS cache module using [Keyv](https://keyv.org/) + [Cacheable](https://github.com/jaredwray/cacheable) with Valkey or Redis backend.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @vn.chemgio/nestjs-utilities keyv cacheable
9
+ ```
10
+
11
+ Depending on your store:
12
+
13
+ - **Valkey**: `npm install @keyv/valkey`
14
+ - **Redis**: `npm install @keyv/redis`
15
+
16
+ ## Quick start
17
+
18
+ ### Valkey (reads `VALKEY_URL` from env)
19
+
20
+ ```typescript
21
+ // app.module.ts
22
+ import { CacheModule } from '@vn.chemgio/nestjs-utilities/cache'
23
+
24
+ @Module({
25
+ imports: [
26
+ CacheModule.forRoot({ store: 'valkey' }),
27
+ // Requires VALKEY_URL in your .env:
28
+ // VALKEY_URL=valkey://localhost:6379
29
+ ],
30
+ })
31
+ export class AppModule {}
32
+ ```
33
+
34
+ ### Redis (reads `REDIS_URL` from env)
35
+
36
+ ```typescript
37
+ CacheModule.forRoot({ store: 'redis' })
38
+ // Requires REDIS_URL in .env:
39
+ // REDIS_URL=redis://localhost:6379
40
+ ```
41
+
42
+ ### Direct URL (no env vars needed)
43
+
44
+ ```typescript
45
+ CacheModule.forRoot({
46
+ store: 'valkey',
47
+ url: 'valkey://user:pass@host:6379',
48
+ })
49
+ ```
50
+
51
+ ## Usage in a service
52
+
53
+ ```typescript
54
+ import { Inject } from '@nestjs/common'
55
+ import { CACHE_MANAGER } from '@vn.chemgio/nestjs-utilities/cache'
56
+ import { Cacheable } from 'cacheable'
57
+
58
+ @Injectable()
59
+ export class MyService {
60
+ constructor(
61
+ @Inject(CACHE_MANAGER) private readonly cache: Cacheable,
62
+ ) {}
63
+
64
+ async getData(key: string) {
65
+ return this.cache.get(key)
66
+ }
67
+
68
+ async setData(key: string, value: unknown, ttl?: number) {
69
+ await this.cache.set(key, value, ttl)
70
+ }
71
+ }
72
+ ```
73
+
74
+ ## CacheModuleOptions
75
+
76
+ | Option | Default | Description |
77
+ |---|---|---|
78
+ | `store` | `'valkey'` | Backend store: `'valkey'` or `'redis'` |
79
+ | `namespace` | `'{default}'` | Cache namespace prefix |
80
+ | `url` | — | Connection URL. If omitted, reads `VALKEY_URL` or `REDIS_URL` from env |
81
+
82
+ ## How it works
83
+
84
+ ```
85
+ Cacheable → Keyv → KeyvValkey / KeyvRedis → Valkey / Redis
86
+ ```
87
+
88
+ - `KeyvValkey` / `KeyvRedis` connects to the backend
89
+ - `Keyv` wraps it with a uniform API
90
+ - `Cacheable` adds TTL, namespace, and caching logic
91
+ - The module is `@Global()`, so `CACHE_MANAGER` is available everywhere
@@ -0,0 +1,82 @@
1
+ # @vn.chemgio/nestjs-utilities/queue
2
+
3
+ RDS-style config factory for [BullMQ](https://bullmq.io) (via `@nestjs/bullmq`).
4
+
5
+ Works with either Valkey (`VALKEY_URL`) or Redis (`REDIS_URL`) environment variables.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @vn.chemgio/nestjs-utilities @nestjs/bullmq bullmq
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { BullModule } from '@nestjs/bullmq';
17
+ import { configBullMQ } from '@vn.chemgio/nestjs-utilities/queue';
18
+
19
+ @Module({
20
+ imports: [
21
+ BullModule.forRootAsync({
22
+ useFactory: configBullMQ,
23
+ inject: [ConfigService],
24
+ }),
25
+ BullModule.registerQueue({ name: 'email' }),
26
+ ],
27
+ })
28
+ export class AppModule {}
29
+ ```
30
+
31
+ ### Valkey (reads `VALKEY_URL` from env)
32
+
33
+ ```typescript
34
+ BullModule.forRootAsync({
35
+ // Requires VALKEY_URL in .env:
36
+ // VALKEY_URL=valkey://localhost:6379
37
+ useFactory: configBullMQ,
38
+ inject: [ConfigService],
39
+ })
40
+ ```
41
+
42
+ ### Redis (reads `REDIS_URL` from env)
43
+
44
+ ```typescript
45
+ BullModule.forRootAsync({
46
+ useFactory: (config: ConfigService) =>
47
+ configBullMQ(config, { store: 'redis' }),
48
+ inject: [ConfigService],
49
+ })
50
+ ```
51
+
52
+ ### With custom prefix and default job options
53
+
54
+ ```typescript
55
+ BullModule.forRootAsync({
56
+ useFactory: (config: ConfigService) =>
57
+ configBullMQ(config, {
58
+ prefix: '{myapp}',
59
+ defaultJobOptions: { attempts: 3, removeOnComplete: 100 },
60
+ }),
61
+ inject: [ConfigService],
62
+ })
63
+ ```
64
+
65
+ ### Direct URL (no env vars)
66
+
67
+ ```typescript
68
+ BullModule.forRootAsync({
69
+ useFactory: () => ({
70
+ connection: { url: 'redis://user:pass@host:6379' },
71
+ prefix: '{default}',
72
+ }),
73
+ })
74
+ ```
75
+
76
+ ## QueueModuleOptions
77
+
78
+ | Option | Default | Description |
79
+ |---|---|---|
80
+ | `store` | `'valkey'` | Backend store: `'valkey'` or `'redis'` |
81
+ | `prefix` | `'{default}'` | BullMQ key prefix |
82
+ | `defaultJobOptions` | — | Default job options for all queues (e.g. `{ attempts: 3 }`) |
@@ -0,0 +1,100 @@
1
+ # @vn.chemgio/nestjs-utilities/typeorm
2
+
3
+ TypeORM configuration helpers for cloud databases (RDS PostgreSQL / MySQL).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @vn.chemgio/nestjs-utilities @nestjs/typeorm @nestjs/config
9
+ ```
10
+
11
+ ## Prerequisites
12
+
13
+ The following environment variables must be declared in your `.env` file (or provided to `ConfigModule.forRoot()`):
14
+
15
+ | Variable | Required | Default |
16
+ |---|---|---|
17
+ | `DB_HOST` | No | `localhost` |
18
+ | `DB_PORT` | No | `5432` (PG) / `3306` (MySQL) |
19
+ | `DB_USERNAME` | Yes | — |
20
+ | `DB_PASSWORD` | Yes | — |
21
+ | `DB_DATABASE` | No | `postgres` / `mysql` |
22
+ | `DB_SYNCHRONIZE` | No | `false` |
23
+ | `DB_LOGGING` | No | `false` |
24
+ | `DB_SSL_REJECT_UNAUTHORIZED` | No | `false` |
25
+
26
+ ## Usage
27
+
28
+ ```typescript
29
+ // app.module.ts
30
+ import { Module } from '@nestjs/common'
31
+ import { ConfigModule, ConfigService } from '@nestjs/config'
32
+ import { TypeOrmModule } from '@nestjs/typeorm'
33
+ import { configTypeOrmRDSPostgres } from '@vn.chemgio/nestjs-utilities/typeorm'
34
+
35
+ @Module({
36
+ imports: [
37
+ ConfigModule.forRoot(),
38
+ TypeOrmModule.forRootAsync({
39
+ inject: [ConfigService],
40
+ useFactory: (config: ConfigService) =>
41
+ configTypeOrmRDSPostgres(config, {
42
+ poolSize: 20,
43
+ schema: 'public',
44
+ }),
45
+ }),
46
+ ],
47
+ })
48
+ export class AppModule {}
49
+ ```
50
+
51
+ ## Environment variables
52
+
53
+ | Variable | Default | Type | Description |
54
+ |---|---|---|---|
55
+ | `DB_HOST` | `localhost` | `string` | Database host |
56
+ | `DB_PORT` | `5432` (PG) / `3306` (MySQL) | `number` | Connection port |
57
+ | `DB_USERNAME` | — | `string` | Database username |
58
+ | `DB_PASSWORD` | — | `string` | Database password |
59
+ | `DB_DATABASE` | `postgres` / `mysql` | `string` | Database name |
60
+ | `DB_SYNCHRONIZE` | `false` | `boolean` | Auto-sync schema (dev only) |
61
+ | `DB_LOGGING` | `false` | `boolean` | Enable query logging |
62
+ | `DB_SSL_REJECT_UNAUTHORIZED` | `false` | `boolean` | Reject unauthorized SSL certs |
63
+
64
+ ## TypeOrmConfigOptions
65
+
66
+ | Option | Default | Description |
67
+ |---|---|---|
68
+ | `schema` | — | PostgreSQL schema (e.g. `public`) |
69
+ | `poolSize` | `20` (PG) / `10` (MySQL) | Maximum connections in pool |
70
+ | `idleTimeoutMs` | `30000` (PG) / `10000` (MySQL) | Max idle time before closing |
71
+ | `connectionTimeoutMs` | `10000` (PG) / `5000` (MySQL) | Connection timeout |
72
+ | `statementTimeoutMs` | `30000` (PG) | Query timeout |
73
+
74
+ ## SSL — why both `ssl` and `extra.ssl`?
75
+
76
+ ```typescript
77
+ ssl: { rejectUnauthorized: false },
78
+ extra: {
79
+ ssl: { rejectUnauthorized: false },
80
+ // ...
81
+ }
82
+ ```
83
+
84
+ - **`ssl`** — tells TypeORM to configure the driver (`pg` / `mysql2`) with TLS
85
+ - **`extra.ssl`** — passes SSL config directly to the underlying driver pool
86
+
87
+ Cloud databases (AWS RDS, Google Cloud SQL, etc.) often use self-signed certificates, requiring `rejectUnauthorized: false` to trust them.
88
+
89
+ ## Sample .env
90
+
91
+ ```bash
92
+ DB_HOST=database-1.xxxxxx.us-east-1.rds.amazonaws.com
93
+ DB_PORT=5432
94
+ DB_USERNAME=postgres
95
+ DB_PASSWORD=my-secret-pw
96
+ DB_DATABASE=mydb
97
+ DB_SYNCHRONIZE=false
98
+ DB_LOGGING=true
99
+ DB_SSL_REJECT_UNAUTHORIZED=false
100
+ ```