diff --git a/examples/client-app/.env b/examples/client-app/.env new file mode 100644 index 0000000..6323283 --- /dev/null +++ b/examples/client-app/.env @@ -0,0 +1,4 @@ +REDIS_CONSUMER=api-1 +REDIS_CONSUMER_GROUP=api +REDIS_MAX_BLOCK_TIME_MS=5000 +REDIS_URL=0.0.0.0:6379 \ No newline at end of file diff --git a/examples/client-app/package-lock.json b/examples/client-app/package-lock.json index 99f7653..391c4a9 100644 --- a/examples/client-app/package-lock.json +++ b/examples/client-app/package-lock.json @@ -10,6 +10,7 @@ "license": "UNLICENSED", "dependencies": { "@nestjs/common": "^9.0.0", + "@nestjs/config": "^3.1.1", "@nestjs/core": "^9.0.0", "@nestjs/platform-express": "^9.0.0", "@tamimaj/nestjs-redis-streams": "file:../..", @@ -42,13 +43,15 @@ } }, "../..": { - "version": "0.0.4", + "name": "@tamimaj/nestjs-redis-streams", + "version": "1.0.0", "license": "MIT", "dependencies": { "@nestjs/common": "^9.0.0", "@nestjs/microservices": "^9.0.0", "ioredis": "^5.2.3", - "rxjs": "^7.2.0" + "rxjs": "^7.2.0", + "uuid": "^9.0.0" }, "devDependencies": { "@nestjs/testing": "^9.0.0", @@ -1581,6 +1584,21 @@ } } }, + "node_modules/@nestjs/config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.1.1.tgz", + "integrity": "sha512-qu5QlNiJdqQtOsnB6lx4JCXPQ96jkKUsOGd+JXfXwqJqZcOSAq6heNFg0opW4pq4J/VZoNwoo87TNnx9wthnqQ==", + "dependencies": { + "dotenv": "16.3.1", + "dotenv-expand": "10.0.0", + "lodash": "4.17.21", + "uuid": "9.0.0" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "reflect-metadata": "^0.1.13" + } + }, "node_modules/@nestjs/core": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz", @@ -3514,6 +3532,25 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "engines": { + "node": ">=12" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -5930,8 +5967,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -9567,6 +9603,17 @@ "uuid": "9.0.0" } }, + "@nestjs/config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.1.1.tgz", + "integrity": "sha512-qu5QlNiJdqQtOsnB6lx4JCXPQ96jkKUsOGd+JXfXwqJqZcOSAq6heNFg0opW4pq4J/VZoNwoo87TNnx9wthnqQ==", + "requires": { + "dotenv": "16.3.1", + "dotenv-expand": "10.0.0", + "lodash": "4.17.21", + "uuid": "9.0.0" + } + }, "@nestjs/core": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.2.0.tgz", @@ -9775,7 +9822,8 @@ "ts-jest": "28.0.8", "ts-loader": "^9.2.3", "ts-node": "^10.0.0", - "typescript": "^4.7.4" + "typescript": "^4.7.4", + "uuid": "^9.0.0" } }, "@tsconfig/node10": { @@ -11065,6 +11113,16 @@ "esutils": "^2.0.2" } }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" + }, + "dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==" + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -12880,8 +12938,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.memoize": { "version": "4.1.2", diff --git a/examples/client-app/package.json b/examples/client-app/package.json index 10485a2..0e1b913 100644 --- a/examples/client-app/package.json +++ b/examples/client-app/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@nestjs/common": "^9.0.0", + "@nestjs/config": "^3.1.1", "@nestjs/core": "^9.0.0", "@nestjs/platform-express": "^9.0.0", "@tamimaj/nestjs-redis-streams": "file:../..", diff --git a/examples/client-app/src/app.module.ts b/examples/client-app/src/app.module.ts index 6421efa..a70b43f 100644 --- a/examples/client-app/src/app.module.ts +++ b/examples/client-app/src/app.module.ts @@ -5,6 +5,7 @@ import { } from '@tamimaj/nestjs-redis-streams'; import { AppController } from './app.controller'; import { AppService } from './app.service'; +import { ConfigModule, ConfigService } from '@nestjs/config'; // Any class that implements createRedisStreamClientModuleOptions method. // ConfigService is a good candidate. @@ -21,18 +22,42 @@ class ClassOptions { @Module({ imports: [ - // Register / forRoot. - RedisStreamClientModule.register({ - connection: { url: '0.0.0.0:6379' }, - streams: { consumer: 'api-1', block: 5000, consumerGroup: 'api' }, - responseStreams: ['users:created', 'users:created:copy'], - }), + /////////////////////////////////// + // SYNC CONFIGURATION + /////////////////////////////////// - // registerAsync / forRootAsync. + // RedisStreamClientModule.forRoot({ + // connection: { url: '0.0.0.0:6379' }, + // streams: { consumer: 'api-1', block: 5000, consumerGroup: 'api' }, + // responseStreams: ['users:created', 'users:created:copy'], + // }), + + /////////////////////////////////////////// + // ASYNC CONFIGURATION with ConfigModule + /////////////////////////////////////////// + + ConfigModule.forRoot(), + RedisStreamClientModule.forRootAsync({ + imports: [ConfigModule], + useFactory: (configService: ConfigService) => { + return { + connection: { + url: configService.get('REDIS_URL'), + }, + streams: { + consumer: configService.get('REDIS_CONSUMER'), + consumerGroup: configService.get('REDIS_CONSUMER_GROUP'), + block: configService.get('REDIS_MAX_BLOCK_TIME_MS'), + }, + responseStreams: ['users:created', 'users:created:copy'], + }; + }, + inject: [ConfigService], + }), - ////////////////////// - // Use Factory. // - ////////////////////// + /////////////////////////////////////////// + // ASYNC CONFIGURATION with useFactory + /////////////////////////////////////////// // RedisStreamClientModule.registerAsync({ // useFactory: async () => { @@ -44,9 +69,10 @@ class ClassOptions { // }, // }), - ////////////////////// - // Use Class. // - ////////////////////// + /////////////////////////////////////////////////////////////////////////// + // ASYNC CONFIGURATION with useClass + // class must implement createRedisStreamClientModuleOptions method. + /////////////////////////////////////////////////////////////////////////// // RedisStreamClientModule.forRootAsync({ // useClass: ClassOptions, diff --git a/examples/users-microservice/package-lock.json b/examples/users-microservice/package-lock.json index 0210f6c..345aae9 100644 --- a/examples/users-microservice/package-lock.json +++ b/examples/users-microservice/package-lock.json @@ -46,13 +46,14 @@ }, "../..": { "name": "@tamimaj/nestjs-redis-streams", - "version": "0.0.3", + "version": "1.0.0", "license": "MIT", "dependencies": { "@nestjs/common": "^9.0.0", "@nestjs/microservices": "^9.0.0", "ioredis": "^5.2.3", - "rxjs": "^7.2.0" + "rxjs": "^7.2.0", + "uuid": "^9.0.0" }, "devDependencies": { "@nestjs/testing": "^9.0.0", @@ -10177,7 +10178,8 @@ "ts-jest": "28.0.8", "ts-loader": "^9.2.3", "ts-node": "^10.0.0", - "typescript": "^4.7.4" + "typescript": "^4.7.4", + "uuid": "^9.0.0" } }, "@tsconfig/node10": { diff --git a/lib/redis-stream-client.core-module.ts b/lib/redis-stream-client.core-module.ts index 0832b8f..29cadca 100644 --- a/lib/redis-stream-client.core-module.ts +++ b/lib/redis-stream-client.core-module.ts @@ -6,6 +6,8 @@ import { } from './interfaces'; import { RedisStreamClient } from './redis.client'; +const REDIS_STREAM_CLIENT_MODULE_OPTIONS = 'REDIS_STREAM_CLIENT_MODULE_OPTIONS'; + @Global() @Module({}) export class RedisStreamClientCoreModule { @@ -26,14 +28,22 @@ export class RedisStreamClientCoreModule { public static forRootAsync( options: RedisStreamModuleAsyncOptions, ): DynamicModule { - console.log('forRootAsync options', options); + const redisStreamClientProvider: Provider = { + provide: RedisStreamClient, + useFactory: (options: ClientConstructorOptions) => { + return new RedisStreamClient(options); + }, + inject: [REDIS_STREAM_CLIENT_MODULE_OPTIONS], + }; return { module: RedisStreamClientCoreModule, imports: options.imports, - providers: [...this.createAsyncProviders(options)], // here we let the logic to create the provider pending on the type of the - // useFactory, useClass or useExisting - exports: [RedisStreamClient], // this means we will export the RedisStreamClient provider + providers: [ + ...this.createAsyncProviders(options), + redisStreamClientProvider, + ], + exports: [redisStreamClientProvider], }; } @@ -70,27 +80,17 @@ export class RedisStreamClientCoreModule { // if is a useFactory, get options then return the RedisStreamClient if (options.useFactory) { return { - provide: RedisStreamClient, - useFactory: async () => { - const clientOptions = await options.useFactory(); - return new RedisStreamClient(clientOptions); - }, + provide: REDIS_STREAM_CLIENT_MODULE_OPTIONS, + useFactory: options.useFactory, inject: options.inject || [], }; } - // if is a useClass or useExisting, - // get the options from the ProvidedClass.createRedisStreamClientModuleOptions() - // that must be implemented by the provided class. return { - provide: RedisStreamClient, - async useFactory( + provide: REDIS_STREAM_CLIENT_MODULE_OPTIONS, + useFactory: async ( optionsFactory: RedisStreamClientModuleOptionsFactory, - ): Promise { - const options = - await optionsFactory.createRedisStreamClientModuleOptions(); - return new RedisStreamClient(options); - }, + ) => optionsFactory.createRedisStreamClientModuleOptions(), inject: [options.useClass || options.useExisting], }; } diff --git a/package-lock.json b/package-lock.json index d456738..7318445 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tamimaj/nestjs-redis-streams", - "version": "0.0.4", + "version": "1.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@tamimaj/nestjs-redis-streams", - "version": "0.0.4", + "version": "1.0.1", "license": "MIT", "dependencies": { "@nestjs/common": "^9.0.0", diff --git a/package.json b/package.json index 433434b..bf7877f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tamimaj/nestjs-redis-streams", - "version": "1.0.0", + "version": "1.0.1", "description": "Redis Streams Transport for NestJS.", "author": "Tamim Abbas Aljuratli ", "private": false,