@globalart/nestjs-typeorm-outbox 1.2.1 → 1.3.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.
package/dist/index.cjs CHANGED
@@ -147,11 +147,17 @@ let TypeormOutboxCronService = class TypeormOutboxCronService {
147
147
  this.moduleConfig = moduleConfig;
148
148
  this.dataSource = dataSource;
149
149
  }
150
+ cronJob;
150
151
  onApplicationBootstrap() {
151
152
  this.validateBrokerClient();
152
- new cron.CronJob(this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND, () => {
153
+ this.cronJob = new cron.CronJob(this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND, () => {
153
154
  this.executeCronJob();
154
- }).start();
155
+ });
156
+ this.cronJob.start();
157
+ }
158
+ onApplicationShutdown() {
159
+ if (!this.cronJob) return;
160
+ this.cronJob.stop();
155
161
  }
156
162
  validateBrokerClient() {
157
163
  const brokerConfig = this.moduleConfig.brokerConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["CronJob","Transport","TypeOrmModule","ClientProxyFactory"],"sources":["../src/core/typeorm-outbox.di-tokens.ts","../src/core/typeorm-outbox.entity.ts","../src/core/typeorm-outbox.enums.ts","../src/core/typeorm-outbox.interfaces.ts","../src/core/typeorm-outbox-cron.service.ts","../src/core/typeorm-outbox.service.ts","../src/core/typeorm-outbox.module.ts"],"sourcesContent":["import { Inject } from \"@nestjs/common\";\n\nexport const TYPEORM_OUTBOX_CRON_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_CRON_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_SERVICE_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_SERVICE_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_BROKER_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_BROKER_TOKEN\",\n);\n\nexport const InjectTypeormOutboxCronConfig = () =>\n Inject(TYPEORM_OUTBOX_CRON_CONFIG_TOKEN);\nexport const InjectTypeormOutboxModuleConfig = () =>\n Inject(TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN);\nexport const InjectTypeormOutboxService = () =>\n Inject(TYPEORM_OUTBOX_SERVICE_TOKEN);\nexport const InjectTypeormOutboxBroker = () =>\n Inject(TYPEORM_OUTBOX_BROKER_TOKEN);\n","import {\n Column,\n CreateDateColumn,\n Entity,\n PrimaryGeneratedColumn,\n UpdateDateColumn,\n} from \"typeorm\";\n\n@Entity('outbox')\nexport class TypeormOutboxEntity {\n @PrimaryGeneratedColumn()\n id!: number;\n\n @CreateDateColumn({ name: 'created_at' })\n createdAt!: Date;\n\n @UpdateDateColumn({ name: 'updated_at' })\n updatedAt!: Date;\n\n @Column(\"character varying\", { name: 'destination_topic' })\n destinationTopic!: string;\n\n @Column(\"jsonb\", { nullable: true })\n headers!: Record<string, string>;\n\n @Column(\"jsonb\", { nullable: true })\n keys!: Record<string, unknown>;\n\n @Column(\"jsonb\")\n payload!: Record<string, any>;\n}\n","export enum CronExpression {\n EVERY_SECOND = \"* * * * * *\",\n EVERY_2_SECONDS = \"*/2 * * * * *\",\n EVERY_3_SECONDS = \"*/3 * * * * *\",\n EVERY_4_SECONDS = \"*/4 * * * * *\",\n EVERY_5_SECONDS = \"*/5 * * * * *\",\n EVERY_6_SECONDS = \"*/6 * * * * *\",\n EVERY_7_SECONDS = \"*/7 * * * * *\",\n EVERY_8_SECONDS = \"*/8 * * * * *\",\n EVERY_9_SECONDS = \"*/9 * * * * *\",\n EVERY_10_SECONDS = \"*/10 * * * * *\",\n EVERY_11_SECONDS = \"*/11 * * * * *\",\n EVERY_12_SECONDS = \"*/12 * * * * *\",\n EVERY_13_SECONDS = \"*/13 * * * * *\",\n EVERY_14_SECONDS = \"*/14 * * * * *\",\n EVERY_15_SECONDS = \"*/15 * * * * *\",\n EVERY_16_SECONDS = \"*/16 * * * * *\",\n EVERY_17_SECONDS = \"*/17 * * * * *\",\n EVERY_18_SECONDS = \"*/18 * * * * *\",\n EVERY_19_SECONDS = \"*/19 * * * * *\",\n EVERY_20_SECONDS = \"*/20 * * * * *\",\n EVERY_21_SECONDS = \"*/21 * * * * *\",\n EVERY_22_SECONDS = \"*/22 * * * * *\",\n EVERY_23_SECONDS = \"*/23 * * * * *\",\n EVERY_24_SECONDS = \"*/24 * * * * *\",\n EVERY_25_SECONDS = \"*/25 * * * * *\",\n EVERY_26_SECONDS = \"*/26 * * * * *\",\n EVERY_27_SECONDS = \"*/27 * * * * *\",\n EVERY_28_SECONDS = \"*/28 * * * * *\",\n EVERY_29_SECONDS = \"*/29 * * * * *\",\n EVERY_30_SECONDS = \"*/30 * * * * *\",\n EVERY_31_SECONDS = \"*/31 * * * * *\",\n EVERY_32_SECONDS = \"*/32 * * * * *\",\n EVERY_33_SECONDS = \"*/33 * * * * *\",\n EVERY_34_SECONDS = \"*/34 * * * * *\",\n EVERY_35_SECONDS = \"*/35 * * * * *\",\n EVERY_36_SECONDS = \"*/36 * * * * *\",\n EVERY_37_SECONDS = \"*/37 * * * * *\",\n EVERY_38_SECONDS = \"*/38 * * * * *\",\n EVERY_39_SECONDS = \"*/39 * * * * *\",\n EVERY_40_SECONDS = \"*/40 * * * * *\",\n EVERY_41_SECONDS = \"*/41 * * * * *\",\n EVERY_42_SECONDS = \"*/42 * * * * *\",\n EVERY_43_SECONDS = \"*/43 * * * * *\",\n EVERY_44_SECONDS = \"*/44 * * * * *\",\n EVERY_45_SECONDS = \"*/45 * * * * *\",\n EVERY_46_SECONDS = \"*/46 * * * * *\",\n EVERY_47_SECONDS = \"*/47 * * * * *\",\n EVERY_48_SECONDS = \"*/48 * * * * *\",\n EVERY_49_SECONDS = \"*/49 * * * * *\",\n EVERY_50_SECONDS = \"*/50 * * * * *\",\n EVERY_51_SECONDS = \"*/51 * * * * *\",\n EVERY_52_SECONDS = \"*/52 * * * * *\",\n EVERY_53_SECONDS = \"*/53 * * * * *\",\n EVERY_54_SECONDS = \"*/54 * * * * *\",\n EVERY_55_SECONDS = \"*/55 * * * * *\",\n EVERY_56_SECONDS = \"*/56 * * * * *\",\n EVERY_57_SECONDS = \"*/57 * * * * *\",\n EVERY_58_SECONDS = \"*/58 * * * * *\",\n EVERY_59_SECONDS = \"*/59 * * * * *\",\n EVERY_MINUTE = \"0 * * * * *\",\n}","import { KafkaOptions, MqttOptions, NatsOptions } from \"@nestjs/microservices\";\nimport { InjectionToken, ModuleMetadata, Type } from \"@nestjs/common\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\ntype BrokerConfig = MqttOptions | NatsOptions | KafkaOptions;\n\nexport class TypeormOutboxRegisterCronModuleOptions {\n brokerConfig: BrokerConfig = {};\n typeOrmConnectionName?: string = \"default\";\n cronExpression?: string = CronExpression.EVERY_SECOND;\n}\n\nexport interface TypeormOutboxRegisterCronAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useExisting?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useClass?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useFactory?: (\n ...args: unknown[]\n ) =>\n | Promise<TypeormOutboxRegisterCronModuleOptions>\n | TypeormOutboxRegisterCronModuleOptions;\n}\n\nexport class TypeormOutboxModuleOptions {\n typeOrmConnectionName?: string = \"default\";\n}\n\nexport interface TypeormOutboxModuleAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useFactory?: (\n ...args: unknown[]\n ) => Promise<TypeormOutboxModuleOptions> | TypeormOutboxModuleOptions;\n}\n","import {\n Injectable,\n OnApplicationBootstrap,\n OnModuleInit,\n} from \"@nestjs/common\";\nimport {\n InjectTypeormOutboxBroker,\n InjectTypeormOutboxCronConfig,\n} from \"./typeorm-outbox.di-tokens\";\nimport { hashStringToInt } from \"@globalart/text-utils\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { firstValueFrom } from \"rxjs\";\nimport { ClientProxy, Transport } from \"@nestjs/microservices\";\nimport { CronJob } from \"cron\";\nimport { TypeormOutboxRegisterCronModuleOptions } from \"./typeorm-outbox.interfaces\";\nimport { DataSource } from \"typeorm\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\n@Injectable()\nexport class TypeormOutboxCronService implements OnApplicationBootstrap {\n constructor(\n @InjectTypeormOutboxBroker()\n private readonly brokerClient: ClientProxy,\n @InjectTypeormOutboxCronConfig()\n private readonly moduleConfig: TypeormOutboxRegisterCronModuleOptions,\n private readonly dataSource: DataSource,\n ) {}\n\n onApplicationBootstrap() {\n this.validateBrokerClient();\n const cronJob = new CronJob(\n this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND,\n () => {\n this.executeCronJob();\n },\n );\n cronJob.start();\n }\n\n private validateBrokerClient() {\n const brokerConfig = this.moduleConfig.brokerConfig;\n if (\n ![Transport.KAFKA, Transport.NATS, Transport.MQTT].includes(\n brokerConfig?.transport as Transport,\n )\n ) {\n throw new Error(\n `[TypeormOutboxCronService] Broker config must be an instance of KafkaOptions, NatsOptions, or MqttOptions`,\n );\n }\n }\n\n private async executeCronJob() {\n const queryRunner = this.dataSource.createQueryRunner();\n await queryRunner.connect();\n const lockKey = hashStringToInt(\"typeorm-outbox-cron-lock\");\n\n try {\n const lockResult = await queryRunner.query(\n \"SELECT pg_try_advisory_lock($1) as locked\",\n [lockKey],\n );\n\n if (!lockResult[0].locked) {\n return;\n }\n try {\n await queryRunner.startTransaction(\"REPEATABLE READ\");\n\n const entities = await queryRunner.manager.find(TypeormOutboxEntity, {\n order: {\n createdAt: \"ASC\",\n },\n });\n\n for (const entity of entities) {\n await firstValueFrom(\n this.brokerClient.emit(entity.destinationTopic, {\n key: entity.keys,\n value: entity.payload,\n headers: entity.headers,\n }),\n );\n await queryRunner.manager.delete(TypeormOutboxEntity, entity.id);\n }\n\n await queryRunner.commitTransaction();\n } catch (error) {\n await queryRunner.rollbackTransaction();\n throw error;\n } finally {\n await queryRunner.query(\"SELECT pg_advisory_unlock($1)\", [lockKey]);\n }\n } finally {\n await queryRunner.release();\n }\n }\n}\n","import { Injectable } from \"@nestjs/common\";\nimport { InjectRepository } from \"@nestjs/typeorm\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { Repository } from \"typeorm\";\n\nexport interface CreateOutboxOptions {\n destinationTopic: string;\n payload: Record<string, unknown>;\n headers?: Record<string, string>;\n keys?: Record<string, unknown>;\n}\n\n@Injectable()\nexport class TypeormOutboxService {\n constructor(\n @InjectRepository(TypeormOutboxEntity)\n private readonly outboxRepository: Repository<TypeormOutboxEntity>,\n ) {}\n\n async create(options: CreateOutboxOptions): Promise<TypeormOutboxEntity> {\n return this.outboxRepository.save({\n destinationTopic: options.destinationTopic,\n headers: options.headers,\n keys: options.keys,\n payload: options.payload,\n });\n }\n}\n","import { TypeOrmModule } from \"@nestjs/typeorm\";\nimport { DynamicModule, Module, Provider } from \"@nestjs/common\";\nimport {\n TypeormOutboxRegisterCronAsyncOptions,\n TypeormOutboxRegisterCronModuleOptions,\n TypeormOutboxModuleOptions,\n TypeormOutboxModuleAsyncOptions,\n} from \"./typeorm-outbox.interfaces\";\nimport {\n TYPEORM_OUTBOX_BROKER_TOKEN,\n TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n TYPEORM_OUTBOX_SERVICE_TOKEN,\n} from \"./typeorm-outbox.di-tokens\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { TypeormOutboxService } from \"./typeorm-outbox.service\";\nimport { ClientProxyFactory } from \"@nestjs/microservices\";\nimport { TypeormOutboxCronService } from \"./typeorm-outbox-cron.service\";\n\n@Module({})\nexport class TypeormOutboxModule {\n private static createServiceProvider(): Provider {\n return {\n provide: TYPEORM_OUTBOX_SERVICE_TOKEN,\n useClass: TypeormOutboxService,\n };\n }\n\n private static createBrokerProvider(useValue: unknown = null): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useValue,\n };\n }\n\n private static createTypeOrmFeature(connectionName?: string) {\n return TypeOrmModule.forFeature(\n [TypeormOutboxEntity],\n connectionName || \"default\",\n );\n }\n\n private static createModuleConfigProvider(\n options: TypeormOutboxModuleOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useValue: {\n ...new TypeormOutboxModuleOptions(),\n ...options,\n },\n };\n }\n\n private static createAsyncModuleConfigProvider(\n options: TypeormOutboxModuleAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = (await options.useFactory?.(...args)) as\n | TypeormOutboxModuleOptions;\n \n return {\n ...new TypeormOutboxModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronConfigProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n return {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronBrokerProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n const config = {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n return ClientProxyFactory.create(config?.brokerConfig ?? {});\n },\n inject: options.inject || [],\n };\n }\n\n static forRoot(options: TypeormOutboxModuleOptions = {}): DynamicModule {\n const configProvider = this.createModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n const PROVIDERS = [configProvider, serviceProvider, brokerProvider];\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature(options.typeOrmConnectionName)],\n providers: [...PROVIDERS],\n exports: [...PROVIDERS],\n };\n }\n\n static forRootAsync(\n options: TypeormOutboxModuleAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createAsyncModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature()],\n providers: [configProvider, serviceProvider, brokerProvider],\n exports: [configProvider, serviceProvider, brokerProvider],\n };\n }\n\n static registerCronAsync(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createCronConfigProvider(options);\n const brokerProvider = this.createCronBrokerProvider(options);\n const serviceProvider = this.createServiceProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [\n this.createTypeOrmFeature(),\n ],\n providers: [\n TypeormOutboxCronService,\n configProvider,\n brokerProvider,\n serviceProvider,\n ],\n exports: [configProvider, brokerProvider, serviceProvider],\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["CronJob","Transport","TypeOrmModule","ClientProxyFactory"],"sources":["../src/core/typeorm-outbox.di-tokens.ts","../src/core/typeorm-outbox.entity.ts","../src/core/typeorm-outbox.enums.ts","../src/core/typeorm-outbox.interfaces.ts","../src/core/typeorm-outbox-cron.service.ts","../src/core/typeorm-outbox.service.ts","../src/core/typeorm-outbox.module.ts"],"sourcesContent":["import { Inject } from \"@nestjs/common\";\n\nexport const TYPEORM_OUTBOX_CRON_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_CRON_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_SERVICE_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_SERVICE_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_BROKER_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_BROKER_TOKEN\",\n);\n\nexport const InjectTypeormOutboxCronConfig = () =>\n Inject(TYPEORM_OUTBOX_CRON_CONFIG_TOKEN);\nexport const InjectTypeormOutboxModuleConfig = () =>\n Inject(TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN);\nexport const InjectTypeormOutboxService = () =>\n Inject(TYPEORM_OUTBOX_SERVICE_TOKEN);\nexport const InjectTypeormOutboxBroker = () =>\n Inject(TYPEORM_OUTBOX_BROKER_TOKEN);\n","import {\n Column,\n CreateDateColumn,\n Entity,\n PrimaryGeneratedColumn,\n UpdateDateColumn,\n} from \"typeorm\";\n\n@Entity('outbox')\nexport class TypeormOutboxEntity {\n @PrimaryGeneratedColumn()\n id!: number;\n\n @CreateDateColumn({ name: 'created_at' })\n createdAt!: Date;\n\n @UpdateDateColumn({ name: 'updated_at' })\n updatedAt!: Date;\n\n @Column(\"character varying\", { name: 'destination_topic' })\n destinationTopic!: string;\n\n @Column(\"jsonb\", { nullable: true })\n headers!: Record<string, string>;\n\n @Column(\"jsonb\", { nullable: true })\n keys!: Record<string, unknown>;\n\n @Column(\"jsonb\")\n payload!: Record<string, any>;\n}\n","export enum CronExpression {\n EVERY_SECOND = \"* * * * * *\",\n EVERY_2_SECONDS = \"*/2 * * * * *\",\n EVERY_3_SECONDS = \"*/3 * * * * *\",\n EVERY_4_SECONDS = \"*/4 * * * * *\",\n EVERY_5_SECONDS = \"*/5 * * * * *\",\n EVERY_6_SECONDS = \"*/6 * * * * *\",\n EVERY_7_SECONDS = \"*/7 * * * * *\",\n EVERY_8_SECONDS = \"*/8 * * * * *\",\n EVERY_9_SECONDS = \"*/9 * * * * *\",\n EVERY_10_SECONDS = \"*/10 * * * * *\",\n EVERY_11_SECONDS = \"*/11 * * * * *\",\n EVERY_12_SECONDS = \"*/12 * * * * *\",\n EVERY_13_SECONDS = \"*/13 * * * * *\",\n EVERY_14_SECONDS = \"*/14 * * * * *\",\n EVERY_15_SECONDS = \"*/15 * * * * *\",\n EVERY_16_SECONDS = \"*/16 * * * * *\",\n EVERY_17_SECONDS = \"*/17 * * * * *\",\n EVERY_18_SECONDS = \"*/18 * * * * *\",\n EVERY_19_SECONDS = \"*/19 * * * * *\",\n EVERY_20_SECONDS = \"*/20 * * * * *\",\n EVERY_21_SECONDS = \"*/21 * * * * *\",\n EVERY_22_SECONDS = \"*/22 * * * * *\",\n EVERY_23_SECONDS = \"*/23 * * * * *\",\n EVERY_24_SECONDS = \"*/24 * * * * *\",\n EVERY_25_SECONDS = \"*/25 * * * * *\",\n EVERY_26_SECONDS = \"*/26 * * * * *\",\n EVERY_27_SECONDS = \"*/27 * * * * *\",\n EVERY_28_SECONDS = \"*/28 * * * * *\",\n EVERY_29_SECONDS = \"*/29 * * * * *\",\n EVERY_30_SECONDS = \"*/30 * * * * *\",\n EVERY_31_SECONDS = \"*/31 * * * * *\",\n EVERY_32_SECONDS = \"*/32 * * * * *\",\n EVERY_33_SECONDS = \"*/33 * * * * *\",\n EVERY_34_SECONDS = \"*/34 * * * * *\",\n EVERY_35_SECONDS = \"*/35 * * * * *\",\n EVERY_36_SECONDS = \"*/36 * * * * *\",\n EVERY_37_SECONDS = \"*/37 * * * * *\",\n EVERY_38_SECONDS = \"*/38 * * * * *\",\n EVERY_39_SECONDS = \"*/39 * * * * *\",\n EVERY_40_SECONDS = \"*/40 * * * * *\",\n EVERY_41_SECONDS = \"*/41 * * * * *\",\n EVERY_42_SECONDS = \"*/42 * * * * *\",\n EVERY_43_SECONDS = \"*/43 * * * * *\",\n EVERY_44_SECONDS = \"*/44 * * * * *\",\n EVERY_45_SECONDS = \"*/45 * * * * *\",\n EVERY_46_SECONDS = \"*/46 * * * * *\",\n EVERY_47_SECONDS = \"*/47 * * * * *\",\n EVERY_48_SECONDS = \"*/48 * * * * *\",\n EVERY_49_SECONDS = \"*/49 * * * * *\",\n EVERY_50_SECONDS = \"*/50 * * * * *\",\n EVERY_51_SECONDS = \"*/51 * * * * *\",\n EVERY_52_SECONDS = \"*/52 * * * * *\",\n EVERY_53_SECONDS = \"*/53 * * * * *\",\n EVERY_54_SECONDS = \"*/54 * * * * *\",\n EVERY_55_SECONDS = \"*/55 * * * * *\",\n EVERY_56_SECONDS = \"*/56 * * * * *\",\n EVERY_57_SECONDS = \"*/57 * * * * *\",\n EVERY_58_SECONDS = \"*/58 * * * * *\",\n EVERY_59_SECONDS = \"*/59 * * * * *\",\n EVERY_MINUTE = \"0 * * * * *\",\n}","import { KafkaOptions, MqttOptions, NatsOptions } from \"@nestjs/microservices\";\nimport { InjectionToken, ModuleMetadata, Type } from \"@nestjs/common\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\ntype BrokerConfig = MqttOptions | NatsOptions | KafkaOptions;\n\nexport class TypeormOutboxRegisterCronModuleOptions {\n brokerConfig: BrokerConfig = {};\n typeOrmConnectionName?: string = \"default\";\n cronExpression?: string = CronExpression.EVERY_SECOND;\n}\n\nexport interface TypeormOutboxRegisterCronAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useExisting?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useClass?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useFactory?: (\n ...args: unknown[]\n ) =>\n | Promise<TypeormOutboxRegisterCronModuleOptions>\n | TypeormOutboxRegisterCronModuleOptions;\n}\n\nexport class TypeormOutboxModuleOptions {\n typeOrmConnectionName?: string = \"default\";\n}\n\nexport interface TypeormOutboxModuleAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useFactory?: (\n ...args: unknown[]\n ) => Promise<TypeormOutboxModuleOptions> | TypeormOutboxModuleOptions;\n}\n","import {\n Injectable,\n OnApplicationBootstrap,\n OnApplicationShutdown,\n OnModuleInit,\n} from \"@nestjs/common\";\nimport {\n InjectTypeormOutboxBroker,\n InjectTypeormOutboxCronConfig,\n} from \"./typeorm-outbox.di-tokens\";\nimport { hashStringToInt } from \"@globalart/text-utils\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { firstValueFrom } from \"rxjs\";\nimport { ClientProxy, Transport } from \"@nestjs/microservices\";\nimport { CronJob } from \"cron\";\nimport { TypeormOutboxRegisterCronModuleOptions } from \"./typeorm-outbox.interfaces\";\nimport { DataSource } from \"typeorm\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\n@Injectable()\nexport class TypeormOutboxCronService\n implements OnApplicationBootstrap, OnApplicationShutdown\n{\n constructor(\n @InjectTypeormOutboxBroker()\n private readonly brokerClient: ClientProxy,\n @InjectTypeormOutboxCronConfig()\n private readonly moduleConfig: TypeormOutboxRegisterCronModuleOptions,\n private readonly dataSource: DataSource,\n ) {}\n private cronJob!: CronJob;\n\n onApplicationBootstrap() {\n this.validateBrokerClient();\n this.cronJob = new CronJob(\n this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND,\n () => {\n this.executeCronJob();\n },\n );\n this.cronJob.start();\n }\n\n onApplicationShutdown() {\n if (!this.cronJob) {\n return;\n }\n this.cronJob.stop();\n }\n\n private validateBrokerClient() {\n const brokerConfig = this.moduleConfig.brokerConfig;\n if (\n ![Transport.KAFKA, Transport.NATS, Transport.MQTT].includes(\n brokerConfig?.transport as Transport,\n )\n ) {\n throw new Error(\n `[TypeormOutboxCronService] Broker config must be an instance of KafkaOptions, NatsOptions, or MqttOptions`,\n );\n }\n }\n\n private async executeCronJob() {\n const queryRunner = this.dataSource.createQueryRunner();\n await queryRunner.connect();\n const lockKey = hashStringToInt(\"typeorm-outbox-cron-lock\");\n\n try {\n const lockResult = await queryRunner.query(\n \"SELECT pg_try_advisory_lock($1) as locked\",\n [lockKey],\n );\n\n if (!lockResult[0].locked) {\n return;\n }\n try {\n await queryRunner.startTransaction(\"REPEATABLE READ\");\n\n const entities = await queryRunner.manager.find(TypeormOutboxEntity, {\n order: {\n createdAt: \"ASC\",\n },\n });\n\n for (const entity of entities) {\n await firstValueFrom(\n this.brokerClient.emit(entity.destinationTopic, {\n key: entity.keys,\n value: entity.payload,\n headers: entity.headers,\n }),\n );\n await queryRunner.manager.delete(TypeormOutboxEntity, entity.id);\n }\n\n await queryRunner.commitTransaction();\n } catch (error) {\n await queryRunner.rollbackTransaction();\n throw error;\n } finally {\n await queryRunner.query(\"SELECT pg_advisory_unlock($1)\", [lockKey]);\n }\n } finally {\n await queryRunner.release();\n }\n }\n}\n","import { Injectable } from \"@nestjs/common\";\nimport { InjectRepository } from \"@nestjs/typeorm\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { Repository } from \"typeorm\";\n\nexport interface CreateOutboxOptions {\n destinationTopic: string;\n payload: Record<string, unknown>;\n headers?: Record<string, string>;\n keys?: Record<string, unknown>;\n}\n\n@Injectable()\nexport class TypeormOutboxService {\n constructor(\n @InjectRepository(TypeormOutboxEntity)\n private readonly outboxRepository: Repository<TypeormOutboxEntity>,\n ) {}\n\n async create(options: CreateOutboxOptions): Promise<TypeormOutboxEntity> {\n return this.outboxRepository.save({\n destinationTopic: options.destinationTopic,\n headers: options.headers,\n keys: options.keys,\n payload: options.payload,\n });\n }\n}\n","import { TypeOrmModule } from \"@nestjs/typeorm\";\nimport { DynamicModule, Module, Provider } from \"@nestjs/common\";\nimport {\n TypeormOutboxRegisterCronAsyncOptions,\n TypeormOutboxRegisterCronModuleOptions,\n TypeormOutboxModuleOptions,\n TypeormOutboxModuleAsyncOptions,\n} from \"./typeorm-outbox.interfaces\";\nimport {\n TYPEORM_OUTBOX_BROKER_TOKEN,\n TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n TYPEORM_OUTBOX_SERVICE_TOKEN,\n} from \"./typeorm-outbox.di-tokens\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { TypeormOutboxService } from \"./typeorm-outbox.service\";\nimport { ClientProxyFactory } from \"@nestjs/microservices\";\nimport { TypeormOutboxCronService } from \"./typeorm-outbox-cron.service\";\n\n@Module({})\nexport class TypeormOutboxModule {\n private static createServiceProvider(): Provider {\n return {\n provide: TYPEORM_OUTBOX_SERVICE_TOKEN,\n useClass: TypeormOutboxService,\n };\n }\n\n private static createBrokerProvider(useValue: unknown = null): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useValue,\n };\n }\n\n private static createTypeOrmFeature(connectionName?: string) {\n return TypeOrmModule.forFeature(\n [TypeormOutboxEntity],\n connectionName || \"default\",\n );\n }\n\n private static createModuleConfigProvider(\n options: TypeormOutboxModuleOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useValue: {\n ...new TypeormOutboxModuleOptions(),\n ...options,\n },\n };\n }\n\n private static createAsyncModuleConfigProvider(\n options: TypeormOutboxModuleAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = (await options.useFactory?.(...args)) as\n | TypeormOutboxModuleOptions;\n \n return {\n ...new TypeormOutboxModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronConfigProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n return {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronBrokerProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n const config = {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n return ClientProxyFactory.create(config?.brokerConfig ?? {});\n },\n inject: options.inject || [],\n };\n }\n\n static forRoot(options: TypeormOutboxModuleOptions = {}): DynamicModule {\n const configProvider = this.createModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n const PROVIDERS = [configProvider, serviceProvider, brokerProvider];\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature(options.typeOrmConnectionName)],\n providers: [...PROVIDERS],\n exports: [...PROVIDERS],\n };\n }\n\n static forRootAsync(\n options: TypeormOutboxModuleAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createAsyncModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature()],\n providers: [configProvider, serviceProvider, brokerProvider],\n exports: [configProvider, serviceProvider, brokerProvider],\n };\n }\n\n static registerCronAsync(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createCronConfigProvider(options);\n const brokerProvider = this.createCronBrokerProvider(options);\n const serviceProvider = this.createServiceProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [\n this.createTypeOrmFeature(),\n ],\n providers: [\n TypeormOutboxCronService,\n configProvider,\n brokerProvider,\n serviceProvider,\n ],\n exports: [configProvider, brokerProvider, serviceProvider],\n };\n }\n}\n"],"mappings":";;;;;;;;;;AAEA,MAAa,mCAAmC,OAC9C,mCACD;AACD,MAAa,qCAAqC,OAChD,qCACD;AACD,MAAa,+BAA+B,OAC1C,+BACD;AACD,MAAa,8BAA8B,OACzC,8BACD;AAED,MAAa,iEACJ,iCAAiC;AAC1C,MAAa,mEACJ,mCAAmC;AAC5C,MAAa,8DACJ,6BAA6B;AACtC,MAAa,6DACJ,4BAA4B;;;;;;;;;;;;;;;;;;;;ACb9B,gCAAM,oBAAoB;CAC/B,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;;iDAnByB;0CAGP,EAAE,MAAM,cAAc,CAAC;0CAGvB,EAAE,MAAM,cAAc,CAAC;gCAGjC,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;gCAGnD,SAAS,EAAE,UAAU,MAAM,CAAC;gCAG5B,SAAS,EAAE,UAAU,MAAM,CAAC;gCAG5B,QAAQ;sDApBV,SAAS;;;;ACRjB,IAAY,0DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;ACtDF,IAAa,yCAAb,MAAoD;CAClD,eAA6B,EAAE;CAC/B,wBAAiC;CACjC,iBAA0B,eAAe;;AAe3C,IAAa,6BAAb,MAAwC;CACtC,wBAAiC;;;;;;;;;;;;;;ACL5B,qCAAM,yBAEb;CACE,YACE,AACiB,cACjB,AACiB,cACjB,AAAiB,YACjB;EAJiB;EAEA;EACA;;CAEnB,AAAQ;CAER,yBAAyB;AACvB,OAAK,sBAAsB;AAC3B,OAAK,UAAU,IAAIA,aACjB,KAAK,aAAa,kBAAkB,eAAe,oBAC7C;AACJ,QAAK,gBAAgB;IAExB;AACD,OAAK,QAAQ,OAAO;;CAGtB,wBAAwB;AACtB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,QAAQ,MAAM;;CAGrB,AAAQ,uBAAuB;EAC7B,MAAM,eAAe,KAAK,aAAa;AACvC,MACE,CAAC;GAACC,gCAAU;GAAOA,gCAAU;GAAMA,gCAAU;GAAK,CAAC,SACjD,cAAc,UACf,CAED,OAAM,IAAI,MACR,4GACD;;CAIL,MAAc,iBAAiB;EAC7B,MAAM,cAAc,KAAK,WAAW,mBAAmB;AACvD,QAAM,YAAY,SAAS;EAC3B,MAAM,qDAA0B,2BAA2B;AAE3D,MAAI;AAMF,OAAI,EALe,MAAM,YAAY,MACnC,6CACA,CAAC,QAAQ,CACV,EAEe,GAAG,OACjB;AAEF,OAAI;AACF,UAAM,YAAY,iBAAiB,kBAAkB;IAErD,MAAM,WAAW,MAAM,YAAY,QAAQ,KAAK,qBAAqB,EACnE,OAAO,EACL,WAAW,OACZ,EACF,CAAC;AAEF,SAAK,MAAM,UAAU,UAAU;AAC7B,oCACE,KAAK,aAAa,KAAK,OAAO,kBAAkB;MAC9C,KAAK,OAAO;MACZ,OAAO,OAAO;MACd,SAAS,OAAO;MACjB,CAAC,CACH;AACD,WAAM,YAAY,QAAQ,OAAO,qBAAqB,OAAO,GAAG;;AAGlE,UAAM,YAAY,mBAAmB;YAC9B,OAAO;AACd,UAAM,YAAY,qBAAqB;AACvC,UAAM;aACE;AACR,UAAM,YAAY,MAAM,iCAAiC,CAAC,QAAQ,CAAC;;YAE7D;AACR,SAAM,YAAY,SAAS;;;;;iCAtFpB;oBAKR,2BAA2B;oBAE3B,+BAA+B;;;;;;;;;;;ACb7B,iCAAM,qBAAqB;CAChC,YACE,AACiB,kBACjB;EADiB;;CAGnB,MAAM,OAAO,SAA4D;AACvE,SAAO,KAAK,iBAAiB,KAAK;GAChC,kBAAkB,QAAQ;GAC1B,SAAS,QAAQ;GACjB,MAAM,QAAQ;GACd,SAAS,QAAQ;GAClB,CAAC;;;;iCAbO;0DAGS,oBAAoB;;;;;;;ACKnC,uDAAM,oBAAoB;CAC/B,OAAe,wBAAkC;AAC/C,SAAO;GACL,SAAS;GACT,UAAU;GACX;;CAGH,OAAe,qBAAqB,WAAoB,MAAgB;AACtE,SAAO;GACL,SAAS;GACT;GACD;;CAGH,OAAe,qBAAqB,gBAAyB;AAC3D,SAAOC,8BAAc,WACnB,CAAC,oBAAoB,EACrB,kBAAkB,UACnB;;CAGH,OAAe,2BACb,SACU;AACV,SAAO;GACL,SAAS;GACT,UAAU;IACR,GAAG,IAAI,4BAA4B;IACnC,GAAG;IACJ;GACF;;CAGH,OAAe,gCACb,SACU;AACV,SAAO;GACL,SAAS;GACT,YAAY,OAAO,GAAG,SAAoB;IACxC,MAAM,gBAAiB,MAAM,QAAQ,aAAa,GAAG,KAAK;AAG1D,WAAO;KACL,GAAG,IAAI,4BAA4B;KACnC,GAAG;KACJ;;GAEH,QAAQ,QAAQ,UAAU,EAAE;GAC7B;;CAGH,OAAe,yBACb,SACU;AACV,SAAO;GACL,SAAS;GACT,YAAY,OAAO,GAAG,SAAoB;IACxC,MAAM,gBAAgB,MAAM,QAAQ,aAAa,GAAG,KAAK;AACzD,WAAO;KACL,GAAG,IAAI,wCAAwC;KAC/C,GAAG;KACJ;;GAEH,QAAQ,QAAQ,UAAU,EAAE;GAC7B;;CAGH,OAAe,yBACb,SACU;AACV,SAAO;GACL,SAAS;GACT,YAAY,OAAO,GAAG,SAAoB;IACxC,MAAM,gBAAgB,MAAM,QAAQ,aAAa,GAAG,KAAK;IACzD,MAAM,SAAS;KACb,GAAG,IAAI,wCAAwC;KAC/C,GAAG;KACJ;AACD,WAAOC,yCAAmB,OAAO,QAAQ,gBAAgB,EAAE,CAAC;;GAE9D,QAAQ,QAAQ,UAAU,EAAE;GAC7B;;CAGH,OAAO,QAAQ,UAAsC,EAAE,EAAiB;EAItE,MAAM,YAAY;GAHK,KAAK,2BAA2B,QAAQ;GACvC,KAAK,uBAAuB;GAC7B,KAAK,sBAAsB;GACiB;AAEnE,SAAO;GACL;GACA,QAAQ;GACR,SAAS,CAAC,KAAK,qBAAqB,QAAQ,sBAAsB,CAAC;GACnE,WAAW,CAAC,GAAG,UAAU;GACzB,SAAS,CAAC,GAAG,UAAU;GACxB;;CAGH,OAAO,aACL,SACe;EACf,MAAM,iBAAiB,KAAK,gCAAgC,QAAQ;EACpE,MAAM,kBAAkB,KAAK,uBAAuB;EACpD,MAAM,iBAAiB,KAAK,sBAAsB;AAElD,SAAO;GACL;GACA,QAAQ;GACR,SAAS,CAAC,KAAK,sBAAsB,CAAC;GACtC,WAAW;IAAC;IAAgB;IAAiB;IAAe;GAC5D,SAAS;IAAC;IAAgB;IAAiB;IAAe;GAC3D;;CAGH,OAAO,kBACL,SACe;EACf,MAAM,iBAAiB,KAAK,yBAAyB,QAAQ;EAC7D,MAAM,iBAAiB,KAAK,yBAAyB,QAAQ;EAC7D,MAAM,kBAAkB,KAAK,uBAAuB;AAEpD,SAAO;GACL;GACA,QAAQ;GACR,SAAS,CACP,KAAK,sBAAsB,CAC5B;GACD,WAAW;IACT;IACA;IACA;IACA;IACD;GACD,SAAS;IAAC;IAAgB;IAAgB;IAAgB;GAC3D;;;oFAzIG,EAAE,CAAC"}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { DynamicModule, InjectionToken, ModuleMetadata, OnApplicationBootstrap, Type } from "@nestjs/common";
1
+ import { DynamicModule, InjectionToken, ModuleMetadata, OnApplicationBootstrap, OnApplicationShutdown, Type } from "@nestjs/common";
2
2
  import { ClientProxy, KafkaOptions, MqttOptions, NatsOptions } from "@nestjs/microservices";
3
3
  import { DataSource, Repository } from "typeorm";
4
4
 
@@ -24,12 +24,14 @@ interface TypeormOutboxModuleAsyncOptions extends Pick<ModuleMetadata, "imports"
24
24
  }
25
25
  //#endregion
26
26
  //#region src/core/typeorm-outbox-cron.service.d.ts
27
- declare class TypeormOutboxCronService implements OnApplicationBootstrap {
27
+ declare class TypeormOutboxCronService implements OnApplicationBootstrap, OnApplicationShutdown {
28
28
  private readonly brokerClient;
29
29
  private readonly moduleConfig;
30
30
  private readonly dataSource;
31
31
  constructor(brokerClient: ClientProxy, moduleConfig: TypeormOutboxRegisterCronModuleOptions, dataSource: DataSource);
32
+ private cronJob;
32
33
  onApplicationBootstrap(): void;
34
+ onApplicationShutdown(): void;
33
35
  private validateBrokerClient;
34
36
  private executeCronJob;
35
37
  }
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { DynamicModule, InjectionToken, ModuleMetadata, OnApplicationBootstrap, Type } from "@nestjs/common";
1
+ import { DynamicModule, InjectionToken, ModuleMetadata, OnApplicationBootstrap, OnApplicationShutdown, Type } from "@nestjs/common";
2
2
  import { DataSource, Repository } from "typeorm";
3
3
  import { ClientProxy, KafkaOptions, MqttOptions, NatsOptions } from "@nestjs/microservices";
4
4
 
@@ -24,12 +24,14 @@ interface TypeormOutboxModuleAsyncOptions extends Pick<ModuleMetadata, "imports"
24
24
  }
25
25
  //#endregion
26
26
  //#region src/core/typeorm-outbox-cron.service.d.ts
27
- declare class TypeormOutboxCronService implements OnApplicationBootstrap {
27
+ declare class TypeormOutboxCronService implements OnApplicationBootstrap, OnApplicationShutdown {
28
28
  private readonly brokerClient;
29
29
  private readonly moduleConfig;
30
30
  private readonly dataSource;
31
31
  constructor(brokerClient: ClientProxy, moduleConfig: TypeormOutboxRegisterCronModuleOptions, dataSource: DataSource);
32
+ private cronJob;
32
33
  onApplicationBootstrap(): void;
34
+ onApplicationShutdown(): void;
33
35
  private validateBrokerClient;
34
36
  private executeCronJob;
35
37
  }
package/dist/index.mjs CHANGED
@@ -146,11 +146,17 @@ let TypeormOutboxCronService = class TypeormOutboxCronService {
146
146
  this.moduleConfig = moduleConfig;
147
147
  this.dataSource = dataSource;
148
148
  }
149
+ cronJob;
149
150
  onApplicationBootstrap() {
150
151
  this.validateBrokerClient();
151
- new CronJob(this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND, () => {
152
+ this.cronJob = new CronJob(this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND, () => {
152
153
  this.executeCronJob();
153
- }).start();
154
+ });
155
+ this.cronJob.start();
156
+ }
157
+ onApplicationShutdown() {
158
+ if (!this.cronJob) return;
159
+ this.cronJob.stop();
154
160
  }
155
161
  validateBrokerClient() {
156
162
  const brokerConfig = this.moduleConfig.brokerConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/core/typeorm-outbox.di-tokens.ts","../src/core/typeorm-outbox.entity.ts","../src/core/typeorm-outbox.enums.ts","../src/core/typeorm-outbox.interfaces.ts","../src/core/typeorm-outbox-cron.service.ts","../src/core/typeorm-outbox.service.ts","../src/core/typeorm-outbox.module.ts"],"sourcesContent":["import { Inject } from \"@nestjs/common\";\n\nexport const TYPEORM_OUTBOX_CRON_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_CRON_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_SERVICE_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_SERVICE_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_BROKER_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_BROKER_TOKEN\",\n);\n\nexport const InjectTypeormOutboxCronConfig = () =>\n Inject(TYPEORM_OUTBOX_CRON_CONFIG_TOKEN);\nexport const InjectTypeormOutboxModuleConfig = () =>\n Inject(TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN);\nexport const InjectTypeormOutboxService = () =>\n Inject(TYPEORM_OUTBOX_SERVICE_TOKEN);\nexport const InjectTypeormOutboxBroker = () =>\n Inject(TYPEORM_OUTBOX_BROKER_TOKEN);\n","import {\n Column,\n CreateDateColumn,\n Entity,\n PrimaryGeneratedColumn,\n UpdateDateColumn,\n} from \"typeorm\";\n\n@Entity('outbox')\nexport class TypeormOutboxEntity {\n @PrimaryGeneratedColumn()\n id!: number;\n\n @CreateDateColumn({ name: 'created_at' })\n createdAt!: Date;\n\n @UpdateDateColumn({ name: 'updated_at' })\n updatedAt!: Date;\n\n @Column(\"character varying\", { name: 'destination_topic' })\n destinationTopic!: string;\n\n @Column(\"jsonb\", { nullable: true })\n headers!: Record<string, string>;\n\n @Column(\"jsonb\", { nullable: true })\n keys!: Record<string, unknown>;\n\n @Column(\"jsonb\")\n payload!: Record<string, any>;\n}\n","export enum CronExpression {\n EVERY_SECOND = \"* * * * * *\",\n EVERY_2_SECONDS = \"*/2 * * * * *\",\n EVERY_3_SECONDS = \"*/3 * * * * *\",\n EVERY_4_SECONDS = \"*/4 * * * * *\",\n EVERY_5_SECONDS = \"*/5 * * * * *\",\n EVERY_6_SECONDS = \"*/6 * * * * *\",\n EVERY_7_SECONDS = \"*/7 * * * * *\",\n EVERY_8_SECONDS = \"*/8 * * * * *\",\n EVERY_9_SECONDS = \"*/9 * * * * *\",\n EVERY_10_SECONDS = \"*/10 * * * * *\",\n EVERY_11_SECONDS = \"*/11 * * * * *\",\n EVERY_12_SECONDS = \"*/12 * * * * *\",\n EVERY_13_SECONDS = \"*/13 * * * * *\",\n EVERY_14_SECONDS = \"*/14 * * * * *\",\n EVERY_15_SECONDS = \"*/15 * * * * *\",\n EVERY_16_SECONDS = \"*/16 * * * * *\",\n EVERY_17_SECONDS = \"*/17 * * * * *\",\n EVERY_18_SECONDS = \"*/18 * * * * *\",\n EVERY_19_SECONDS = \"*/19 * * * * *\",\n EVERY_20_SECONDS = \"*/20 * * * * *\",\n EVERY_21_SECONDS = \"*/21 * * * * *\",\n EVERY_22_SECONDS = \"*/22 * * * * *\",\n EVERY_23_SECONDS = \"*/23 * * * * *\",\n EVERY_24_SECONDS = \"*/24 * * * * *\",\n EVERY_25_SECONDS = \"*/25 * * * * *\",\n EVERY_26_SECONDS = \"*/26 * * * * *\",\n EVERY_27_SECONDS = \"*/27 * * * * *\",\n EVERY_28_SECONDS = \"*/28 * * * * *\",\n EVERY_29_SECONDS = \"*/29 * * * * *\",\n EVERY_30_SECONDS = \"*/30 * * * * *\",\n EVERY_31_SECONDS = \"*/31 * * * * *\",\n EVERY_32_SECONDS = \"*/32 * * * * *\",\n EVERY_33_SECONDS = \"*/33 * * * * *\",\n EVERY_34_SECONDS = \"*/34 * * * * *\",\n EVERY_35_SECONDS = \"*/35 * * * * *\",\n EVERY_36_SECONDS = \"*/36 * * * * *\",\n EVERY_37_SECONDS = \"*/37 * * * * *\",\n EVERY_38_SECONDS = \"*/38 * * * * *\",\n EVERY_39_SECONDS = \"*/39 * * * * *\",\n EVERY_40_SECONDS = \"*/40 * * * * *\",\n EVERY_41_SECONDS = \"*/41 * * * * *\",\n EVERY_42_SECONDS = \"*/42 * * * * *\",\n EVERY_43_SECONDS = \"*/43 * * * * *\",\n EVERY_44_SECONDS = \"*/44 * * * * *\",\n EVERY_45_SECONDS = \"*/45 * * * * *\",\n EVERY_46_SECONDS = \"*/46 * * * * *\",\n EVERY_47_SECONDS = \"*/47 * * * * *\",\n EVERY_48_SECONDS = \"*/48 * * * * *\",\n EVERY_49_SECONDS = \"*/49 * * * * *\",\n EVERY_50_SECONDS = \"*/50 * * * * *\",\n EVERY_51_SECONDS = \"*/51 * * * * *\",\n EVERY_52_SECONDS = \"*/52 * * * * *\",\n EVERY_53_SECONDS = \"*/53 * * * * *\",\n EVERY_54_SECONDS = \"*/54 * * * * *\",\n EVERY_55_SECONDS = \"*/55 * * * * *\",\n EVERY_56_SECONDS = \"*/56 * * * * *\",\n EVERY_57_SECONDS = \"*/57 * * * * *\",\n EVERY_58_SECONDS = \"*/58 * * * * *\",\n EVERY_59_SECONDS = \"*/59 * * * * *\",\n EVERY_MINUTE = \"0 * * * * *\",\n}","import { KafkaOptions, MqttOptions, NatsOptions } from \"@nestjs/microservices\";\nimport { InjectionToken, ModuleMetadata, Type } from \"@nestjs/common\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\ntype BrokerConfig = MqttOptions | NatsOptions | KafkaOptions;\n\nexport class TypeormOutboxRegisterCronModuleOptions {\n brokerConfig: BrokerConfig = {};\n typeOrmConnectionName?: string = \"default\";\n cronExpression?: string = CronExpression.EVERY_SECOND;\n}\n\nexport interface TypeormOutboxRegisterCronAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useExisting?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useClass?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useFactory?: (\n ...args: unknown[]\n ) =>\n | Promise<TypeormOutboxRegisterCronModuleOptions>\n | TypeormOutboxRegisterCronModuleOptions;\n}\n\nexport class TypeormOutboxModuleOptions {\n typeOrmConnectionName?: string = \"default\";\n}\n\nexport interface TypeormOutboxModuleAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useFactory?: (\n ...args: unknown[]\n ) => Promise<TypeormOutboxModuleOptions> | TypeormOutboxModuleOptions;\n}\n","import {\n Injectable,\n OnApplicationBootstrap,\n OnModuleInit,\n} from \"@nestjs/common\";\nimport {\n InjectTypeormOutboxBroker,\n InjectTypeormOutboxCronConfig,\n} from \"./typeorm-outbox.di-tokens\";\nimport { hashStringToInt } from \"@globalart/text-utils\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { firstValueFrom } from \"rxjs\";\nimport { ClientProxy, Transport } from \"@nestjs/microservices\";\nimport { CronJob } from \"cron\";\nimport { TypeormOutboxRegisterCronModuleOptions } from \"./typeorm-outbox.interfaces\";\nimport { DataSource } from \"typeorm\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\n@Injectable()\nexport class TypeormOutboxCronService implements OnApplicationBootstrap {\n constructor(\n @InjectTypeormOutboxBroker()\n private readonly brokerClient: ClientProxy,\n @InjectTypeormOutboxCronConfig()\n private readonly moduleConfig: TypeormOutboxRegisterCronModuleOptions,\n private readonly dataSource: DataSource,\n ) {}\n\n onApplicationBootstrap() {\n this.validateBrokerClient();\n const cronJob = new CronJob(\n this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND,\n () => {\n this.executeCronJob();\n },\n );\n cronJob.start();\n }\n\n private validateBrokerClient() {\n const brokerConfig = this.moduleConfig.brokerConfig;\n if (\n ![Transport.KAFKA, Transport.NATS, Transport.MQTT].includes(\n brokerConfig?.transport as Transport,\n )\n ) {\n throw new Error(\n `[TypeormOutboxCronService] Broker config must be an instance of KafkaOptions, NatsOptions, or MqttOptions`,\n );\n }\n }\n\n private async executeCronJob() {\n const queryRunner = this.dataSource.createQueryRunner();\n await queryRunner.connect();\n const lockKey = hashStringToInt(\"typeorm-outbox-cron-lock\");\n\n try {\n const lockResult = await queryRunner.query(\n \"SELECT pg_try_advisory_lock($1) as locked\",\n [lockKey],\n );\n\n if (!lockResult[0].locked) {\n return;\n }\n try {\n await queryRunner.startTransaction(\"REPEATABLE READ\");\n\n const entities = await queryRunner.manager.find(TypeormOutboxEntity, {\n order: {\n createdAt: \"ASC\",\n },\n });\n\n for (const entity of entities) {\n await firstValueFrom(\n this.brokerClient.emit(entity.destinationTopic, {\n key: entity.keys,\n value: entity.payload,\n headers: entity.headers,\n }),\n );\n await queryRunner.manager.delete(TypeormOutboxEntity, entity.id);\n }\n\n await queryRunner.commitTransaction();\n } catch (error) {\n await queryRunner.rollbackTransaction();\n throw error;\n } finally {\n await queryRunner.query(\"SELECT pg_advisory_unlock($1)\", [lockKey]);\n }\n } finally {\n await queryRunner.release();\n }\n }\n}\n","import { Injectable } from \"@nestjs/common\";\nimport { InjectRepository } from \"@nestjs/typeorm\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { Repository } from \"typeorm\";\n\nexport interface CreateOutboxOptions {\n destinationTopic: string;\n payload: Record<string, unknown>;\n headers?: Record<string, string>;\n keys?: Record<string, unknown>;\n}\n\n@Injectable()\nexport class TypeormOutboxService {\n constructor(\n @InjectRepository(TypeormOutboxEntity)\n private readonly outboxRepository: Repository<TypeormOutboxEntity>,\n ) {}\n\n async create(options: CreateOutboxOptions): Promise<TypeormOutboxEntity> {\n return this.outboxRepository.save({\n destinationTopic: options.destinationTopic,\n headers: options.headers,\n keys: options.keys,\n payload: options.payload,\n });\n }\n}\n","import { TypeOrmModule } from \"@nestjs/typeorm\";\nimport { DynamicModule, Module, Provider } from \"@nestjs/common\";\nimport {\n TypeormOutboxRegisterCronAsyncOptions,\n TypeormOutboxRegisterCronModuleOptions,\n TypeormOutboxModuleOptions,\n TypeormOutboxModuleAsyncOptions,\n} from \"./typeorm-outbox.interfaces\";\nimport {\n TYPEORM_OUTBOX_BROKER_TOKEN,\n TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n TYPEORM_OUTBOX_SERVICE_TOKEN,\n} from \"./typeorm-outbox.di-tokens\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { TypeormOutboxService } from \"./typeorm-outbox.service\";\nimport { ClientProxyFactory } from \"@nestjs/microservices\";\nimport { TypeormOutboxCronService } from \"./typeorm-outbox-cron.service\";\n\n@Module({})\nexport class TypeormOutboxModule {\n private static createServiceProvider(): Provider {\n return {\n provide: TYPEORM_OUTBOX_SERVICE_TOKEN,\n useClass: TypeormOutboxService,\n };\n }\n\n private static createBrokerProvider(useValue: unknown = null): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useValue,\n };\n }\n\n private static createTypeOrmFeature(connectionName?: string) {\n return TypeOrmModule.forFeature(\n [TypeormOutboxEntity],\n connectionName || \"default\",\n );\n }\n\n private static createModuleConfigProvider(\n options: TypeormOutboxModuleOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useValue: {\n ...new TypeormOutboxModuleOptions(),\n ...options,\n },\n };\n }\n\n private static createAsyncModuleConfigProvider(\n options: TypeormOutboxModuleAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = (await options.useFactory?.(...args)) as\n | TypeormOutboxModuleOptions;\n \n return {\n ...new TypeormOutboxModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronConfigProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n return {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronBrokerProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n const config = {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n return ClientProxyFactory.create(config?.brokerConfig ?? {});\n },\n inject: options.inject || [],\n };\n }\n\n static forRoot(options: TypeormOutboxModuleOptions = {}): DynamicModule {\n const configProvider = this.createModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n const PROVIDERS = [configProvider, serviceProvider, brokerProvider];\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature(options.typeOrmConnectionName)],\n providers: [...PROVIDERS],\n exports: [...PROVIDERS],\n };\n }\n\n static forRootAsync(\n options: TypeormOutboxModuleAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createAsyncModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature()],\n providers: [configProvider, serviceProvider, brokerProvider],\n exports: [configProvider, serviceProvider, brokerProvider],\n };\n }\n\n static registerCronAsync(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createCronConfigProvider(options);\n const brokerProvider = this.createCronBrokerProvider(options);\n const serviceProvider = this.createServiceProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [\n this.createTypeOrmFeature(),\n ],\n providers: [\n TypeormOutboxCronService,\n configProvider,\n brokerProvider,\n serviceProvider,\n ],\n exports: [configProvider, brokerProvider, serviceProvider],\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/core/typeorm-outbox.di-tokens.ts","../src/core/typeorm-outbox.entity.ts","../src/core/typeorm-outbox.enums.ts","../src/core/typeorm-outbox.interfaces.ts","../src/core/typeorm-outbox-cron.service.ts","../src/core/typeorm-outbox.service.ts","../src/core/typeorm-outbox.module.ts"],"sourcesContent":["import { Inject } from \"@nestjs/common\";\n\nexport const TYPEORM_OUTBOX_CRON_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_CRON_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_SERVICE_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_SERVICE_TOKEN\",\n);\nexport const TYPEORM_OUTBOX_BROKER_TOKEN = Symbol(\n \"TYPEORM_OUTBOX_BROKER_TOKEN\",\n);\n\nexport const InjectTypeormOutboxCronConfig = () =>\n Inject(TYPEORM_OUTBOX_CRON_CONFIG_TOKEN);\nexport const InjectTypeormOutboxModuleConfig = () =>\n Inject(TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN);\nexport const InjectTypeormOutboxService = () =>\n Inject(TYPEORM_OUTBOX_SERVICE_TOKEN);\nexport const InjectTypeormOutboxBroker = () =>\n Inject(TYPEORM_OUTBOX_BROKER_TOKEN);\n","import {\n Column,\n CreateDateColumn,\n Entity,\n PrimaryGeneratedColumn,\n UpdateDateColumn,\n} from \"typeorm\";\n\n@Entity('outbox')\nexport class TypeormOutboxEntity {\n @PrimaryGeneratedColumn()\n id!: number;\n\n @CreateDateColumn({ name: 'created_at' })\n createdAt!: Date;\n\n @UpdateDateColumn({ name: 'updated_at' })\n updatedAt!: Date;\n\n @Column(\"character varying\", { name: 'destination_topic' })\n destinationTopic!: string;\n\n @Column(\"jsonb\", { nullable: true })\n headers!: Record<string, string>;\n\n @Column(\"jsonb\", { nullable: true })\n keys!: Record<string, unknown>;\n\n @Column(\"jsonb\")\n payload!: Record<string, any>;\n}\n","export enum CronExpression {\n EVERY_SECOND = \"* * * * * *\",\n EVERY_2_SECONDS = \"*/2 * * * * *\",\n EVERY_3_SECONDS = \"*/3 * * * * *\",\n EVERY_4_SECONDS = \"*/4 * * * * *\",\n EVERY_5_SECONDS = \"*/5 * * * * *\",\n EVERY_6_SECONDS = \"*/6 * * * * *\",\n EVERY_7_SECONDS = \"*/7 * * * * *\",\n EVERY_8_SECONDS = \"*/8 * * * * *\",\n EVERY_9_SECONDS = \"*/9 * * * * *\",\n EVERY_10_SECONDS = \"*/10 * * * * *\",\n EVERY_11_SECONDS = \"*/11 * * * * *\",\n EVERY_12_SECONDS = \"*/12 * * * * *\",\n EVERY_13_SECONDS = \"*/13 * * * * *\",\n EVERY_14_SECONDS = \"*/14 * * * * *\",\n EVERY_15_SECONDS = \"*/15 * * * * *\",\n EVERY_16_SECONDS = \"*/16 * * * * *\",\n EVERY_17_SECONDS = \"*/17 * * * * *\",\n EVERY_18_SECONDS = \"*/18 * * * * *\",\n EVERY_19_SECONDS = \"*/19 * * * * *\",\n EVERY_20_SECONDS = \"*/20 * * * * *\",\n EVERY_21_SECONDS = \"*/21 * * * * *\",\n EVERY_22_SECONDS = \"*/22 * * * * *\",\n EVERY_23_SECONDS = \"*/23 * * * * *\",\n EVERY_24_SECONDS = \"*/24 * * * * *\",\n EVERY_25_SECONDS = \"*/25 * * * * *\",\n EVERY_26_SECONDS = \"*/26 * * * * *\",\n EVERY_27_SECONDS = \"*/27 * * * * *\",\n EVERY_28_SECONDS = \"*/28 * * * * *\",\n EVERY_29_SECONDS = \"*/29 * * * * *\",\n EVERY_30_SECONDS = \"*/30 * * * * *\",\n EVERY_31_SECONDS = \"*/31 * * * * *\",\n EVERY_32_SECONDS = \"*/32 * * * * *\",\n EVERY_33_SECONDS = \"*/33 * * * * *\",\n EVERY_34_SECONDS = \"*/34 * * * * *\",\n EVERY_35_SECONDS = \"*/35 * * * * *\",\n EVERY_36_SECONDS = \"*/36 * * * * *\",\n EVERY_37_SECONDS = \"*/37 * * * * *\",\n EVERY_38_SECONDS = \"*/38 * * * * *\",\n EVERY_39_SECONDS = \"*/39 * * * * *\",\n EVERY_40_SECONDS = \"*/40 * * * * *\",\n EVERY_41_SECONDS = \"*/41 * * * * *\",\n EVERY_42_SECONDS = \"*/42 * * * * *\",\n EVERY_43_SECONDS = \"*/43 * * * * *\",\n EVERY_44_SECONDS = \"*/44 * * * * *\",\n EVERY_45_SECONDS = \"*/45 * * * * *\",\n EVERY_46_SECONDS = \"*/46 * * * * *\",\n EVERY_47_SECONDS = \"*/47 * * * * *\",\n EVERY_48_SECONDS = \"*/48 * * * * *\",\n EVERY_49_SECONDS = \"*/49 * * * * *\",\n EVERY_50_SECONDS = \"*/50 * * * * *\",\n EVERY_51_SECONDS = \"*/51 * * * * *\",\n EVERY_52_SECONDS = \"*/52 * * * * *\",\n EVERY_53_SECONDS = \"*/53 * * * * *\",\n EVERY_54_SECONDS = \"*/54 * * * * *\",\n EVERY_55_SECONDS = \"*/55 * * * * *\",\n EVERY_56_SECONDS = \"*/56 * * * * *\",\n EVERY_57_SECONDS = \"*/57 * * * * *\",\n EVERY_58_SECONDS = \"*/58 * * * * *\",\n EVERY_59_SECONDS = \"*/59 * * * * *\",\n EVERY_MINUTE = \"0 * * * * *\",\n}","import { KafkaOptions, MqttOptions, NatsOptions } from \"@nestjs/microservices\";\nimport { InjectionToken, ModuleMetadata, Type } from \"@nestjs/common\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\ntype BrokerConfig = MqttOptions | NatsOptions | KafkaOptions;\n\nexport class TypeormOutboxRegisterCronModuleOptions {\n brokerConfig: BrokerConfig = {};\n typeOrmConnectionName?: string = \"default\";\n cronExpression?: string = CronExpression.EVERY_SECOND;\n}\n\nexport interface TypeormOutboxRegisterCronAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useExisting?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useClass?: Type<TypeormOutboxRegisterCronModuleOptions>;\n useFactory?: (\n ...args: unknown[]\n ) =>\n | Promise<TypeormOutboxRegisterCronModuleOptions>\n | TypeormOutboxRegisterCronModuleOptions;\n}\n\nexport class TypeormOutboxModuleOptions {\n typeOrmConnectionName?: string = \"default\";\n}\n\nexport interface TypeormOutboxModuleAsyncOptions\n extends Pick<ModuleMetadata, \"imports\"> {\n inject?: InjectionToken[];\n useFactory?: (\n ...args: unknown[]\n ) => Promise<TypeormOutboxModuleOptions> | TypeormOutboxModuleOptions;\n}\n","import {\n Injectable,\n OnApplicationBootstrap,\n OnApplicationShutdown,\n OnModuleInit,\n} from \"@nestjs/common\";\nimport {\n InjectTypeormOutboxBroker,\n InjectTypeormOutboxCronConfig,\n} from \"./typeorm-outbox.di-tokens\";\nimport { hashStringToInt } from \"@globalart/text-utils\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { firstValueFrom } from \"rxjs\";\nimport { ClientProxy, Transport } from \"@nestjs/microservices\";\nimport { CronJob } from \"cron\";\nimport { TypeormOutboxRegisterCronModuleOptions } from \"./typeorm-outbox.interfaces\";\nimport { DataSource } from \"typeorm\";\nimport { CronExpression } from \"./typeorm-outbox.enums\";\n\n@Injectable()\nexport class TypeormOutboxCronService\n implements OnApplicationBootstrap, OnApplicationShutdown\n{\n constructor(\n @InjectTypeormOutboxBroker()\n private readonly brokerClient: ClientProxy,\n @InjectTypeormOutboxCronConfig()\n private readonly moduleConfig: TypeormOutboxRegisterCronModuleOptions,\n private readonly dataSource: DataSource,\n ) {}\n private cronJob!: CronJob;\n\n onApplicationBootstrap() {\n this.validateBrokerClient();\n this.cronJob = new CronJob(\n this.moduleConfig.cronExpression ?? CronExpression.EVERY_SECOND,\n () => {\n this.executeCronJob();\n },\n );\n this.cronJob.start();\n }\n\n onApplicationShutdown() {\n if (!this.cronJob) {\n return;\n }\n this.cronJob.stop();\n }\n\n private validateBrokerClient() {\n const brokerConfig = this.moduleConfig.brokerConfig;\n if (\n ![Transport.KAFKA, Transport.NATS, Transport.MQTT].includes(\n brokerConfig?.transport as Transport,\n )\n ) {\n throw new Error(\n `[TypeormOutboxCronService] Broker config must be an instance of KafkaOptions, NatsOptions, or MqttOptions`,\n );\n }\n }\n\n private async executeCronJob() {\n const queryRunner = this.dataSource.createQueryRunner();\n await queryRunner.connect();\n const lockKey = hashStringToInt(\"typeorm-outbox-cron-lock\");\n\n try {\n const lockResult = await queryRunner.query(\n \"SELECT pg_try_advisory_lock($1) as locked\",\n [lockKey],\n );\n\n if (!lockResult[0].locked) {\n return;\n }\n try {\n await queryRunner.startTransaction(\"REPEATABLE READ\");\n\n const entities = await queryRunner.manager.find(TypeormOutboxEntity, {\n order: {\n createdAt: \"ASC\",\n },\n });\n\n for (const entity of entities) {\n await firstValueFrom(\n this.brokerClient.emit(entity.destinationTopic, {\n key: entity.keys,\n value: entity.payload,\n headers: entity.headers,\n }),\n );\n await queryRunner.manager.delete(TypeormOutboxEntity, entity.id);\n }\n\n await queryRunner.commitTransaction();\n } catch (error) {\n await queryRunner.rollbackTransaction();\n throw error;\n } finally {\n await queryRunner.query(\"SELECT pg_advisory_unlock($1)\", [lockKey]);\n }\n } finally {\n await queryRunner.release();\n }\n }\n}\n","import { Injectable } from \"@nestjs/common\";\nimport { InjectRepository } from \"@nestjs/typeorm\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { Repository } from \"typeorm\";\n\nexport interface CreateOutboxOptions {\n destinationTopic: string;\n payload: Record<string, unknown>;\n headers?: Record<string, string>;\n keys?: Record<string, unknown>;\n}\n\n@Injectable()\nexport class TypeormOutboxService {\n constructor(\n @InjectRepository(TypeormOutboxEntity)\n private readonly outboxRepository: Repository<TypeormOutboxEntity>,\n ) {}\n\n async create(options: CreateOutboxOptions): Promise<TypeormOutboxEntity> {\n return this.outboxRepository.save({\n destinationTopic: options.destinationTopic,\n headers: options.headers,\n keys: options.keys,\n payload: options.payload,\n });\n }\n}\n","import { TypeOrmModule } from \"@nestjs/typeorm\";\nimport { DynamicModule, Module, Provider } from \"@nestjs/common\";\nimport {\n TypeormOutboxRegisterCronAsyncOptions,\n TypeormOutboxRegisterCronModuleOptions,\n TypeormOutboxModuleOptions,\n TypeormOutboxModuleAsyncOptions,\n} from \"./typeorm-outbox.interfaces\";\nimport {\n TYPEORM_OUTBOX_BROKER_TOKEN,\n TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n TYPEORM_OUTBOX_SERVICE_TOKEN,\n} from \"./typeorm-outbox.di-tokens\";\nimport { TypeormOutboxEntity } from \"./typeorm-outbox.entity\";\nimport { TypeormOutboxService } from \"./typeorm-outbox.service\";\nimport { ClientProxyFactory } from \"@nestjs/microservices\";\nimport { TypeormOutboxCronService } from \"./typeorm-outbox-cron.service\";\n\n@Module({})\nexport class TypeormOutboxModule {\n private static createServiceProvider(): Provider {\n return {\n provide: TYPEORM_OUTBOX_SERVICE_TOKEN,\n useClass: TypeormOutboxService,\n };\n }\n\n private static createBrokerProvider(useValue: unknown = null): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useValue,\n };\n }\n\n private static createTypeOrmFeature(connectionName?: string) {\n return TypeOrmModule.forFeature(\n [TypeormOutboxEntity],\n connectionName || \"default\",\n );\n }\n\n private static createModuleConfigProvider(\n options: TypeormOutboxModuleOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useValue: {\n ...new TypeormOutboxModuleOptions(),\n ...options,\n },\n };\n }\n\n private static createAsyncModuleConfigProvider(\n options: TypeormOutboxModuleAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_MODULE_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = (await options.useFactory?.(...args)) as\n | TypeormOutboxModuleOptions;\n \n return {\n ...new TypeormOutboxModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronConfigProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_CRON_CONFIG_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n return {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n },\n inject: options.inject || [],\n };\n }\n\n private static createCronBrokerProvider(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): Provider {\n return {\n provide: TYPEORM_OUTBOX_BROKER_TOKEN,\n useFactory: async (...args: unknown[]) => {\n const moduleOptions = await options.useFactory?.(...args);\n const config = {\n ...new TypeormOutboxRegisterCronModuleOptions(),\n ...moduleOptions,\n };\n return ClientProxyFactory.create(config?.brokerConfig ?? {});\n },\n inject: options.inject || [],\n };\n }\n\n static forRoot(options: TypeormOutboxModuleOptions = {}): DynamicModule {\n const configProvider = this.createModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n const PROVIDERS = [configProvider, serviceProvider, brokerProvider];\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature(options.typeOrmConnectionName)],\n providers: [...PROVIDERS],\n exports: [...PROVIDERS],\n };\n }\n\n static forRootAsync(\n options: TypeormOutboxModuleAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createAsyncModuleConfigProvider(options);\n const serviceProvider = this.createServiceProvider();\n const brokerProvider = this.createBrokerProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [this.createTypeOrmFeature()],\n providers: [configProvider, serviceProvider, brokerProvider],\n exports: [configProvider, serviceProvider, brokerProvider],\n };\n }\n\n static registerCronAsync(\n options: TypeormOutboxRegisterCronAsyncOptions,\n ): DynamicModule {\n const configProvider = this.createCronConfigProvider(options);\n const brokerProvider = this.createCronBrokerProvider(options);\n const serviceProvider = this.createServiceProvider();\n\n return {\n module: TypeormOutboxModule,\n global: true,\n imports: [\n this.createTypeOrmFeature(),\n ],\n providers: [\n TypeormOutboxCronService,\n configProvider,\n brokerProvider,\n serviceProvider,\n ],\n exports: [configProvider, brokerProvider, serviceProvider],\n };\n }\n}\n"],"mappings":";;;;;;;;;AAEA,MAAa,mCAAmC,OAC9C,mCACD;AACD,MAAa,qCAAqC,OAChD,qCACD;AACD,MAAa,+BAA+B,OAC1C,+BACD;AACD,MAAa,8BAA8B,OACzC,8BACD;AAED,MAAa,sCACX,OAAO,iCAAiC;AAC1C,MAAa,wCACX,OAAO,mCAAmC;AAC5C,MAAa,mCACX,OAAO,6BAA6B;AACtC,MAAa,kCACX,OAAO,4BAA4B;;;;;;;;;;;;;;;;;;;;ACb9B,gCAAM,oBAAoB;CAC/B,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;CAEA,AACA;;YAnBC,wBAAwB;YAGxB,iBAAiB,EAAE,MAAM,cAAc,CAAC;YAGxC,iBAAiB,EAAE,MAAM,cAAc,CAAC;YAGxC,OAAO,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;YAG1D,OAAO,SAAS,EAAE,UAAU,MAAM,CAAC;YAGnC,OAAO,SAAS,EAAE,UAAU,MAAM,CAAC;YAGnC,OAAO,QAAQ;kCApBjB,OAAO,SAAS;;;;ACRjB,IAAY,0DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;ACtDF,IAAa,yCAAb,MAAoD;CAClD,eAA6B,EAAE;CAC/B,wBAAiC;CACjC,iBAA0B,eAAe;;AAe3C,IAAa,6BAAb,MAAwC;CACtC,wBAAiC;;;;;;;;;;;;;;ACL5B,qCAAM,yBAEb;CACE,YACE,AACiB,cACjB,AACiB,cACjB,AAAiB,YACjB;EAJiB;EAEA;EACA;;CAEnB,AAAQ;CAER,yBAAyB;AACvB,OAAK,sBAAsB;AAC3B,OAAK,UAAU,IAAI,QACjB,KAAK,aAAa,kBAAkB,eAAe,oBAC7C;AACJ,QAAK,gBAAgB;IAExB;AACD,OAAK,QAAQ,OAAO;;CAGtB,wBAAwB;AACtB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,QAAQ,MAAM;;CAGrB,AAAQ,uBAAuB;EAC7B,MAAM,eAAe,KAAK,aAAa;AACvC,MACE,CAAC;GAAC,UAAU;GAAO,UAAU;GAAM,UAAU;GAAK,CAAC,SACjD,cAAc,UACf,CAED,OAAM,IAAI,MACR,4GACD;;CAIL,MAAc,iBAAiB;EAC7B,MAAM,cAAc,KAAK,WAAW,mBAAmB;AACvD,QAAM,YAAY,SAAS;EAC3B,MAAM,UAAU,gBAAgB,2BAA2B;AAE3D,MAAI;AAMF,OAAI,EALe,MAAM,YAAY,MACnC,6CACA,CAAC,QAAQ,CACV,EAEe,GAAG,OACjB;AAEF,OAAI;AACF,UAAM,YAAY,iBAAiB,kBAAkB;IAErD,MAAM,WAAW,MAAM,YAAY,QAAQ,KAAK,qBAAqB,EACnE,OAAO,EACL,WAAW,OACZ,EACF,CAAC;AAEF,SAAK,MAAM,UAAU,UAAU;AAC7B,WAAM,eACJ,KAAK,aAAa,KAAK,OAAO,kBAAkB;MAC9C,KAAK,OAAO;MACZ,OAAO,OAAO;MACd,SAAS,OAAO;MACjB,CAAC,CACH;AACD,WAAM,YAAY,QAAQ,OAAO,qBAAqB,OAAO,GAAG;;AAGlE,UAAM,YAAY,mBAAmB;YAC9B,OAAO;AACd,UAAM,YAAY,qBAAqB;AACvC,UAAM;aACE;AACR,UAAM,YAAY,MAAM,iCAAiC,CAAC,QAAQ,CAAC;;YAE7D;AACR,SAAM,YAAY,SAAS;;;;;CAtFhC,YAAY;oBAKR,2BAA2B;oBAE3B,+BAA+B;;;;;;;;;;;ACb7B,iCAAM,qBAAqB;CAChC,YACE,AACiB,kBACjB;EADiB;;CAGnB,MAAM,OAAO,SAA4D;AACvE,SAAO,KAAK,iBAAiB,KAAK;GAChC,kBAAkB,QAAQ;GAC1B,SAAS,QAAQ;GACjB,MAAM,QAAQ;GACd,SAAS,QAAQ;GAClB,CAAC;;;;CAbL,YAAY;oBAGR,iBAAiB,oBAAoB;;;;;;;ACKnC,uDAAM,oBAAoB;CAC/B,OAAe,wBAAkC;AAC/C,SAAO;GACL,SAAS;GACT,UAAU;GACX;;CAGH,OAAe,qBAAqB,WAAoB,MAAgB;AACtE,SAAO;GACL,SAAS;GACT;GACD;;CAGH,OAAe,qBAAqB,gBAAyB;AAC3D,SAAO,cAAc,WACnB,CAAC,oBAAoB,EACrB,kBAAkB,UACnB;;CAGH,OAAe,2BACb,SACU;AACV,SAAO;GACL,SAAS;GACT,UAAU;IACR,GAAG,IAAI,4BAA4B;IACnC,GAAG;IACJ;GACF;;CAGH,OAAe,gCACb,SACU;AACV,SAAO;GACL,SAAS;GACT,YAAY,OAAO,GAAG,SAAoB;IACxC,MAAM,gBAAiB,MAAM,QAAQ,aAAa,GAAG,KAAK;AAG1D,WAAO;KACL,GAAG,IAAI,4BAA4B;KACnC,GAAG;KACJ;;GAEH,QAAQ,QAAQ,UAAU,EAAE;GAC7B;;CAGH,OAAe,yBACb,SACU;AACV,SAAO;GACL,SAAS;GACT,YAAY,OAAO,GAAG,SAAoB;IACxC,MAAM,gBAAgB,MAAM,QAAQ,aAAa,GAAG,KAAK;AACzD,WAAO;KACL,GAAG,IAAI,wCAAwC;KAC/C,GAAG;KACJ;;GAEH,QAAQ,QAAQ,UAAU,EAAE;GAC7B;;CAGH,OAAe,yBACb,SACU;AACV,SAAO;GACL,SAAS;GACT,YAAY,OAAO,GAAG,SAAoB;IACxC,MAAM,gBAAgB,MAAM,QAAQ,aAAa,GAAG,KAAK;IACzD,MAAM,SAAS;KACb,GAAG,IAAI,wCAAwC;KAC/C,GAAG;KACJ;AACD,WAAO,mBAAmB,OAAO,QAAQ,gBAAgB,EAAE,CAAC;;GAE9D,QAAQ,QAAQ,UAAU,EAAE;GAC7B;;CAGH,OAAO,QAAQ,UAAsC,EAAE,EAAiB;EAItE,MAAM,YAAY;GAHK,KAAK,2BAA2B,QAAQ;GACvC,KAAK,uBAAuB;GAC7B,KAAK,sBAAsB;GACiB;AAEnE,SAAO;GACL;GACA,QAAQ;GACR,SAAS,CAAC,KAAK,qBAAqB,QAAQ,sBAAsB,CAAC;GACnE,WAAW,CAAC,GAAG,UAAU;GACzB,SAAS,CAAC,GAAG,UAAU;GACxB;;CAGH,OAAO,aACL,SACe;EACf,MAAM,iBAAiB,KAAK,gCAAgC,QAAQ;EACpE,MAAM,kBAAkB,KAAK,uBAAuB;EACpD,MAAM,iBAAiB,KAAK,sBAAsB;AAElD,SAAO;GACL;GACA,QAAQ;GACR,SAAS,CAAC,KAAK,sBAAsB,CAAC;GACtC,WAAW;IAAC;IAAgB;IAAiB;IAAe;GAC5D,SAAS;IAAC;IAAgB;IAAiB;IAAe;GAC3D;;CAGH,OAAO,kBACL,SACe;EACf,MAAM,iBAAiB,KAAK,yBAAyB,QAAQ;EAC7D,MAAM,iBAAiB,KAAK,yBAAyB,QAAQ;EAC7D,MAAM,kBAAkB,KAAK,uBAAuB;AAEpD,SAAO;GACL;GACA,QAAQ;GACR,SAAS,CACP,KAAK,sBAAsB,CAC5B;GACD,WAAW;IACT;IACA;IACA;IACA;IACD;GACD,SAAS;IAAC;IAAgB;IAAgB;IAAgB;GAC3D;;;yDAzIJ,OAAO,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@globalart/nestjs-typeorm-outbox",
3
3
  "description": "TypeORM Outbox integration for NestJS",
4
- "version": "1.2.1",
4
+ "version": "1.3.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
7
7
  "module": "dist/index.mjs",
@@ -45,10 +45,10 @@
45
45
  "publish:npm": "release-it --config ../../.release-it.json"
46
46
  },
47
47
  "dependencies": {
48
- "@globalart/text-utils": "^1.0.5",
49
- "@nestjs/common": "11.1.13",
50
- "@nestjs/core": "11.1.13",
51
- "@nestjs/microservices": "^11.1.12",
48
+ "@globalart/text-utils": "^1.0.6",
49
+ "@nestjs/common": "11.1.14",
50
+ "@nestjs/core": "11.1.14",
51
+ "@nestjs/microservices": "^11.1.14",
52
52
  "@nestjs/typeorm": "^11.0.0",
53
53
  "cron": "^4.4.0",
54
54
  "kafkajs": "^2.2.4",
@@ -57,11 +57,11 @@
57
57
  "typeorm": "^0.3.28"
58
58
  },
59
59
  "devDependencies": {
60
- "@types/node": "25.2.3",
60
+ "@types/node": "25.3.5",
61
61
  "prettier": "^3.8.1",
62
62
  "reflect-metadata": "^0.2.2",
63
63
  "release-it": "19.2.4",
64
- "tsdown": "0.20.3",
64
+ "tsdown": "0.21.0",
65
65
  "typescript": "^5.9.3"
66
66
  }
67
67
  }