@amqp-contract/worker-nestjs 0.7.0 → 0.9.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/README.md +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +22 -8
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +22 -8
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +131 -172
- package/package.json +8 -8
package/README.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -9,13 +9,13 @@ let _amqp_contract_worker = require("@amqp-contract/worker");
|
|
|
9
9
|
const MODULE_OPTIONS_TOKEN = Symbol("AMQP_WORKER_MODULE_OPTIONS");
|
|
10
10
|
|
|
11
11
|
//#endregion
|
|
12
|
-
//#region \0@oxc-project+runtime@0.
|
|
12
|
+
//#region \0@oxc-project+runtime@0.107.0/helpers/decorateMetadata.js
|
|
13
13
|
function __decorateMetadata(k, v) {
|
|
14
14
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
//#endregion
|
|
18
|
-
//#region \0@oxc-project+runtime@0.
|
|
18
|
+
//#region \0@oxc-project+runtime@0.107.0/helpers/decorateParam.js
|
|
19
19
|
function __decorateParam(paramIndex, decorator) {
|
|
20
20
|
return function(target, key) {
|
|
21
21
|
decorator(target, key, paramIndex);
|
|
@@ -23,7 +23,7 @@ function __decorateParam(paramIndex, decorator) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
//#endregion
|
|
26
|
-
//#region \0@oxc-project+runtime@0.
|
|
26
|
+
//#region \0@oxc-project+runtime@0.107.0/helpers/decorate.js
|
|
27
27
|
function __decorate(decorators, target, key, desc) {
|
|
28
28
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
29
29
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -101,11 +101,11 @@ let AmqpWorkerModule = _AmqpWorkerModule = class AmqpWorkerModule$1 {
|
|
|
101
101
|
const providers = [{
|
|
102
102
|
provide: MODULE_OPTIONS_TOKEN,
|
|
103
103
|
useFactory: options.useFactory,
|
|
104
|
-
inject: options.inject
|
|
104
|
+
inject: options.inject ?? []
|
|
105
105
|
}, AmqpWorkerService];
|
|
106
106
|
return {
|
|
107
107
|
module: _AmqpWorkerModule,
|
|
108
|
-
imports: options.imports
|
|
108
|
+
imports: options.imports ?? [],
|
|
109
109
|
providers,
|
|
110
110
|
exports: [AmqpWorkerService]
|
|
111
111
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
|
|
2
2
|
import { DynamicModule, ModuleMetadata, OnModuleDestroy, OnModuleInit, Type } from "@nestjs/common";
|
|
3
|
-
import { WorkerInferConsumerHandlers,
|
|
3
|
+
import { WorkerInferConsumerHandlers, WorkerInferSafeConsumerHandlers, defineHandler, defineHandlers } from "@amqp-contract/worker";
|
|
4
4
|
import { ContractDefinition } from "@amqp-contract/contract";
|
|
5
5
|
|
|
6
6
|
//#region src/worker.service.d.ts
|
|
@@ -12,25 +12,39 @@ import { ContractDefinition } from "@amqp-contract/contract";
|
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```typescript
|
|
15
|
+
* import { defineHandlers, defineUnsafeHandlers } from '@amqp-contract/worker';
|
|
16
|
+
* import { Future, Result } from '@swan-io/boxed';
|
|
17
|
+
* import { RetryableError } from '@amqp-contract/worker';
|
|
18
|
+
*
|
|
19
|
+
* // Using safe handlers (recommended)
|
|
20
|
+
* const options: AmqpWorkerModuleOptions<typeof contract> = {
|
|
21
|
+
* contract: myContract,
|
|
22
|
+
* handlers: defineHandlers(myContract, {
|
|
23
|
+
* processOrder: (message) =>
|
|
24
|
+
* Future.fromPromise(processPayment(message))
|
|
25
|
+
* .mapOk(() => undefined)
|
|
26
|
+
* .mapError((error) => new RetryableError('Payment failed', error))
|
|
27
|
+
* }),
|
|
28
|
+
* urls: ['amqp://localhost'],
|
|
29
|
+
* };
|
|
30
|
+
*
|
|
31
|
+
* // Using unsafe handlers (legacy)
|
|
15
32
|
* const options: AmqpWorkerModuleOptions<typeof contract> = {
|
|
16
33
|
* contract: myContract,
|
|
17
|
-
* handlers: {
|
|
34
|
+
* handlers: defineUnsafeHandlers(myContract, {
|
|
18
35
|
* processOrder: async (message) => {
|
|
19
36
|
* console.log('Processing order:', message.orderId);
|
|
20
37
|
* }
|
|
21
|
-
* },
|
|
38
|
+
* }),
|
|
22
39
|
* urls: ['amqp://localhost'],
|
|
23
|
-
* connectionOptions: {
|
|
24
|
-
* heartbeatIntervalInSeconds: 30
|
|
25
|
-
* }
|
|
26
40
|
* };
|
|
27
41
|
* ```
|
|
28
42
|
*/
|
|
29
43
|
type AmqpWorkerModuleOptions<TContract extends ContractDefinition> = {
|
|
30
44
|
/** The AMQP contract definition specifying consumers and their message schemas */
|
|
31
45
|
contract: TContract;
|
|
32
|
-
/** Message handlers for each consumer defined in the contract */
|
|
33
|
-
handlers:
|
|
46
|
+
/** Message handlers for each consumer defined in the contract. Use defineHandlers or defineUnsafeHandlers to create type-safe handlers. */
|
|
47
|
+
handlers: WorkerInferSafeConsumerHandlers<TContract>;
|
|
34
48
|
/** AMQP broker URL(s). Multiple URLs provide failover support */
|
|
35
49
|
urls: ConnectionUrl[];
|
|
36
50
|
/** Optional connection configuration (heartbeat, reconnect settings, etc.) */
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/worker.service.ts","../src/worker.module.ts","../src/worker.module-definition.ts"],"sourcesContent":[],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/worker.service.ts","../src/worker.module.ts","../src/worker.module-definition.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAyCA;;;;;;;;AA6CA;;;;;;;;;;;;AC9EkE;;;;;;;;AAalE;;;;;AAeY,KDKA,uBCLA,CAAA,kBDK0C,kBCL1C,CAAA,GAAA;EAAc;EAmDb,QAAA,ED5CD,SC4CiB;EAOM;EACE,QAAA,EDlDzB,+BCkDyB,CDlDO,SCkDP,CAAA;EAAxB;EACR,IAAA,EDjDG,aCiDH,EAAA;EAoBmC;EACE,iBAAA,CAAA,EDpEpB,4BCoEoB,GAAA,SAAA;CAA7B;;;;;;ACjHb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cFmFa,oCAAoC,+BACpC,cAAc;;;uBAMG,wBAAwB;;;;;;;;;;;kBAa9B;;;;;;;;qBAWG;;;;;;;AA7E3B,KC3BK,8BD2B8B,CAAA,kBC3BmB,kBD2BnB,CAAA,GC1B/B,uBD0B+B,CC1BP,SD0BO,CAAA,GCzB/B,ODyB+B,CCzBvB,uBDyBuB,CCzBC,SDyBD,CAAA,CAAA;;;;AAIvB,KCxBA,4BDwBA,CAAA,kBCxB+C,kBDwB/C,CAAA,GAAA;EAEJ;;;AAuCR;EACiD,UAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GC5Df,8BD4De,CC5DgB,SD4DhB,CAAA;EAOK;;;;EANzC,MAAA,CAAA,EAAA,CAAA,MAAA,GAAA,MAAA,GCxDiB,IDwDjB,CAAA,OAAA,CAAA,CAAA,EAAA;EAAc;;;YCpDf;;AA5BsD;;;;;;;;AAalE;;;;;;;AAiEA;;;;;;;;;;;;;AClFA;;;;;;;;;;;;;;;;;;;cDmFa,gBAAA;;;;;;;mCAOsB,6BACtB,wBAAwB,aAChC;;;;;;;wCAoBmC,6BAC3B,6BAA6B,aACrC;;;;;;;;cClHQ"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DynamicModule, ModuleMetadata, OnModuleDestroy, OnModuleInit, Type } from "@nestjs/common";
|
|
2
|
-
import { WorkerInferConsumerHandlers,
|
|
2
|
+
import { WorkerInferConsumerHandlers, WorkerInferSafeConsumerHandlers, defineHandler, defineHandlers } from "@amqp-contract/worker";
|
|
3
3
|
import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
|
|
4
4
|
import { ContractDefinition } from "@amqp-contract/contract";
|
|
5
5
|
|
|
@@ -12,25 +12,39 @@ import { ContractDefinition } from "@amqp-contract/contract";
|
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```typescript
|
|
15
|
+
* import { defineHandlers, defineUnsafeHandlers } from '@amqp-contract/worker';
|
|
16
|
+
* import { Future, Result } from '@swan-io/boxed';
|
|
17
|
+
* import { RetryableError } from '@amqp-contract/worker';
|
|
18
|
+
*
|
|
19
|
+
* // Using safe handlers (recommended)
|
|
20
|
+
* const options: AmqpWorkerModuleOptions<typeof contract> = {
|
|
21
|
+
* contract: myContract,
|
|
22
|
+
* handlers: defineHandlers(myContract, {
|
|
23
|
+
* processOrder: (message) =>
|
|
24
|
+
* Future.fromPromise(processPayment(message))
|
|
25
|
+
* .mapOk(() => undefined)
|
|
26
|
+
* .mapError((error) => new RetryableError('Payment failed', error))
|
|
27
|
+
* }),
|
|
28
|
+
* urls: ['amqp://localhost'],
|
|
29
|
+
* };
|
|
30
|
+
*
|
|
31
|
+
* // Using unsafe handlers (legacy)
|
|
15
32
|
* const options: AmqpWorkerModuleOptions<typeof contract> = {
|
|
16
33
|
* contract: myContract,
|
|
17
|
-
* handlers: {
|
|
34
|
+
* handlers: defineUnsafeHandlers(myContract, {
|
|
18
35
|
* processOrder: async (message) => {
|
|
19
36
|
* console.log('Processing order:', message.orderId);
|
|
20
37
|
* }
|
|
21
|
-
* },
|
|
38
|
+
* }),
|
|
22
39
|
* urls: ['amqp://localhost'],
|
|
23
|
-
* connectionOptions: {
|
|
24
|
-
* heartbeatIntervalInSeconds: 30
|
|
25
|
-
* }
|
|
26
40
|
* };
|
|
27
41
|
* ```
|
|
28
42
|
*/
|
|
29
43
|
type AmqpWorkerModuleOptions<TContract extends ContractDefinition> = {
|
|
30
44
|
/** The AMQP contract definition specifying consumers and their message schemas */
|
|
31
45
|
contract: TContract;
|
|
32
|
-
/** Message handlers for each consumer defined in the contract */
|
|
33
|
-
handlers:
|
|
46
|
+
/** Message handlers for each consumer defined in the contract. Use defineHandlers or defineUnsafeHandlers to create type-safe handlers. */
|
|
47
|
+
handlers: WorkerInferSafeConsumerHandlers<TContract>;
|
|
34
48
|
/** AMQP broker URL(s). Multiple URLs provide failover support */
|
|
35
49
|
urls: ConnectionUrl[];
|
|
36
50
|
/** Optional connection configuration (heartbeat, reconnect settings, etc.) */
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/worker.service.ts","../src/worker.module.ts","../src/worker.module-definition.ts"],"sourcesContent":[],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/worker.service.ts","../src/worker.module.ts","../src/worker.module-definition.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAyCA;;;;;;;;AA6CA;;;;;;;;;;;;AC9EkE;;;;;;;;AAalE;;;;;AAeY,KDKA,uBCLA,CAAA,kBDK0C,kBCL1C,CAAA,GAAA;EAAc;EAmDb,QAAA,ED5CD,SC4CiB;EAOM;EACE,QAAA,EDlDzB,+BCkDyB,CDlDO,SCkDP,CAAA;EAAxB;EACR,IAAA,EDjDG,aCiDH,EAAA;EAoBmC;EACE,iBAAA,CAAA,EDpEpB,4BCoEoB,GAAA,SAAA;CAA7B;;;;;;ACjHb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cFmFa,oCAAoC,+BACpC,cAAc;;;uBAMG,wBAAwB;;;;;;;;;;;kBAa9B;;;;;;;;qBAWG;;;;;;;AA7E3B,KC3BK,8BD2B8B,CAAA,kBC3BmB,kBD2BnB,CAAA,GC1B/B,uBD0B+B,CC1BP,SD0BO,CAAA,GCzB/B,ODyB+B,CCzBvB,uBDyBuB,CCzBC,SDyBD,CAAA,CAAA;;;;AAIvB,KCxBA,4BDwBA,CAAA,kBCxB+C,kBDwB/C,CAAA,GAAA;EAEJ;;;AAuCR;EACiD,UAAA,EAAA,CAAA,GAAA,IAAA,EAAA,GAAA,EAAA,EAAA,GC5Df,8BD4De,CC5DgB,SD4DhB,CAAA;EAOK;;;;EANzC,MAAA,CAAA,EAAA,CAAA,MAAA,GAAA,MAAA,GCxDiB,IDwDjB,CAAA,OAAA,CAAA,CAAA,EAAA;EAAc;;;YCpDf;;AA5BsD;;;;;;;;AAalE;;;;;;;AAiEA;;;;;;;;;;;;;AClFA;;;;;;;;;;;;;;;;;;;cDmFa,gBAAA;;;;;;;mCAOsB,6BACtB,wBAAwB,aAChC;;;;;;;wCAoBmC,6BAC3B,6BAA6B,aACrC;;;;;;;;cClHQ"}
|
package/dist/index.mjs
CHANGED
|
@@ -9,13 +9,13 @@ import { TypedAmqpWorker, defineHandler, defineHandlers } from "@amqp-contract/w
|
|
|
9
9
|
const MODULE_OPTIONS_TOKEN = Symbol("AMQP_WORKER_MODULE_OPTIONS");
|
|
10
10
|
|
|
11
11
|
//#endregion
|
|
12
|
-
//#region \0@oxc-project+runtime@0.
|
|
12
|
+
//#region \0@oxc-project+runtime@0.107.0/helpers/decorateMetadata.js
|
|
13
13
|
function __decorateMetadata(k, v) {
|
|
14
14
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
//#endregion
|
|
18
|
-
//#region \0@oxc-project+runtime@0.
|
|
18
|
+
//#region \0@oxc-project+runtime@0.107.0/helpers/decorateParam.js
|
|
19
19
|
function __decorateParam(paramIndex, decorator) {
|
|
20
20
|
return function(target, key) {
|
|
21
21
|
decorator(target, key, paramIndex);
|
|
@@ -23,7 +23,7 @@ function __decorateParam(paramIndex, decorator) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
//#endregion
|
|
26
|
-
//#region \0@oxc-project+runtime@0.
|
|
26
|
+
//#region \0@oxc-project+runtime@0.107.0/helpers/decorate.js
|
|
27
27
|
function __decorate(decorators, target, key, desc) {
|
|
28
28
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
29
29
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -101,11 +101,11 @@ let AmqpWorkerModule = _AmqpWorkerModule = class AmqpWorkerModule$1 {
|
|
|
101
101
|
const providers = [{
|
|
102
102
|
provide: MODULE_OPTIONS_TOKEN,
|
|
103
103
|
useFactory: options.useFactory,
|
|
104
|
-
inject: options.inject
|
|
104
|
+
inject: options.inject ?? []
|
|
105
105
|
}, AmqpWorkerService];
|
|
106
106
|
return {
|
|
107
107
|
module: _AmqpWorkerModule,
|
|
108
|
-
imports: options.imports
|
|
108
|
+
imports: options.imports ?? [],
|
|
109
109
|
providers,
|
|
110
110
|
exports: [AmqpWorkerService]
|
|
111
111
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["AmqpWorkerService","
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["AmqpWorkerService","AmqpWorkerModule"],"sources":["../src/worker.module-definition.ts","../src/worker.service.ts","../src/worker.module.ts"],"sourcesContent":["/**\n * Injection token for AMQP worker module options\n * Used by NestJS DI system to inject configuration into AmqpWorkerService\n */\nexport const MODULE_OPTIONS_TOKEN = Symbol(\"AMQP_WORKER_MODULE_OPTIONS\");\n","import type { AmqpConnectionManagerOptions, ConnectionUrl } from \"amqp-connection-manager\";\nimport { Inject, Injectable, type OnModuleDestroy, type OnModuleInit } from \"@nestjs/common\";\nimport { TypedAmqpWorker, type WorkerInferSafeConsumerHandlers } from \"@amqp-contract/worker\";\nimport type { ContractDefinition } from \"@amqp-contract/contract\";\nimport { MODULE_OPTIONS_TOKEN } from \"./worker.module-definition.js\";\n\n/**\n * Configuration options for the AMQP worker NestJS module.\n *\n * @typeParam TContract - The contract definition type\n *\n * @example\n * ```typescript\n * import { defineHandlers, defineUnsafeHandlers } from '@amqp-contract/worker';\n * import { Future, Result } from '@swan-io/boxed';\n * import { RetryableError } from '@amqp-contract/worker';\n *\n * // Using safe handlers (recommended)\n * const options: AmqpWorkerModuleOptions<typeof contract> = {\n * contract: myContract,\n * handlers: defineHandlers(myContract, {\n * processOrder: (message) =>\n * Future.fromPromise(processPayment(message))\n * .mapOk(() => undefined)\n * .mapError((error) => new RetryableError('Payment failed', error))\n * }),\n * urls: ['amqp://localhost'],\n * };\n *\n * // Using unsafe handlers (legacy)\n * const options: AmqpWorkerModuleOptions<typeof contract> = {\n * contract: myContract,\n * handlers: defineUnsafeHandlers(myContract, {\n * processOrder: async (message) => {\n * console.log('Processing order:', message.orderId);\n * }\n * }),\n * urls: ['amqp://localhost'],\n * };\n * ```\n */\nexport type AmqpWorkerModuleOptions<TContract extends ContractDefinition> = {\n /** The AMQP contract definition specifying consumers and their message schemas */\n contract: TContract;\n /** Message handlers for each consumer defined in the contract. Use defineHandlers or defineUnsafeHandlers to create type-safe handlers. */\n handlers: WorkerInferSafeConsumerHandlers<TContract>;\n /** AMQP broker URL(s). Multiple URLs provide failover support */\n urls: ConnectionUrl[];\n /** Optional connection configuration (heartbeat, reconnect settings, etc.) */\n connectionOptions?: AmqpConnectionManagerOptions | undefined;\n};\n\n/**\n * Type-safe AMQP worker service for NestJS applications.\n *\n * This service wraps {@link TypedAmqpWorker} and integrates it with the NestJS\n * lifecycle, automatically starting message consumption on module init and\n * cleaning up resources on module destroy.\n *\n * @typeParam TContract - The contract definition type\n *\n * @example\n * ```typescript\n * // In your module\n * import { AmqpWorkerModule } from '@amqp-contract/worker-nestjs';\n *\n * @Module({\n * imports: [\n * AmqpWorkerModule.forRoot({\n * contract: myContract,\n * handlers: {\n * processOrder: async (message) => {\n * console.log('Received order:', message.orderId);\n * // Process the order...\n * }\n * },\n * urls: ['amqp://localhost']\n * })\n * ]\n * })\n * export class AppModule {}\n *\n * // The worker automatically starts consuming messages when the module initializes\n * // and stops gracefully when the application shuts down\n * ```\n */\n@Injectable()\nexport class AmqpWorkerService<TContract extends ContractDefinition>\n implements OnModuleInit, OnModuleDestroy\n{\n private worker: TypedAmqpWorker<TContract> | null = null;\n\n constructor(\n @Inject(MODULE_OPTIONS_TOKEN)\n private readonly options: AmqpWorkerModuleOptions<TContract>,\n ) {}\n\n /**\n * Initialize the AMQP worker when the NestJS module starts.\n *\n * This lifecycle hook automatically creates and starts the worker,\n * beginning message consumption from all configured consumers.\n * The connection will be established in the background with\n * automatic reconnection handling.\n *\n * @throws Error if the worker fails to start\n */\n async onModuleInit(): Promise<void> {\n this.worker = await TypedAmqpWorker.create(this.options).resultToPromise();\n }\n\n /**\n * Close the AMQP worker when the NestJS module is destroyed.\n *\n * This lifecycle hook ensures proper cleanup of resources when the\n * NestJS application shuts down, gracefully stopping message consumption\n * and closing the connection.\n */\n async onModuleDestroy(): Promise<void> {\n if (this.worker) {\n await this.worker.close().resultToPromise();\n this.worker = null;\n }\n }\n}\n","import { type AmqpWorkerModuleOptions, AmqpWorkerService } from \"./worker.service.js\";\nimport {\n type DynamicModule,\n Module,\n type ModuleMetadata,\n type Provider,\n type Type,\n} from \"@nestjs/common\";\nimport type { ContractDefinition } from \"@amqp-contract/contract\";\nimport { MODULE_OPTIONS_TOKEN } from \"./worker.module-definition.js\";\n\n/**\n * Factory function return type for async module configuration\n */\ntype AmqpWorkerModuleOptionsFactory<TContract extends ContractDefinition> =\n | AmqpWorkerModuleOptions<TContract>\n | Promise<AmqpWorkerModuleOptions<TContract>>;\n\n/**\n * Options for async module configuration using factory pattern\n */\nexport type AmqpWorkerModuleAsyncOptions<TContract extends ContractDefinition> = {\n /**\n * Factory function that returns the module options.\n * Can use injected dependencies to create configuration.\n */\n // oxlint-disable-next-line no-explicit-any\n useFactory: (...args: any[]) => AmqpWorkerModuleOptionsFactory<TContract>;\n /**\n * Optional dependencies to inject into the factory function.\n * Can be a token (string/symbol) a class or a reference to a provider.\n */\n inject?: (string | symbol | Type<unknown>)[];\n /**\n * Optional list of imported modules that export providers needed by the factory\n */\n imports?: ModuleMetadata[\"imports\"];\n};\n\n/**\n * NestJS module for AMQP worker integration\n * This module provides type-safe AMQP worker functionality using @amqp-contract/worker\n * without relying on NestJS decorators (except for dependency injection)\n *\n * @typeParam TContract - The contract definition type for type-safe handlers\n *\n * @example\n * ```typescript\n * // Synchronous configuration\n * @Module({\n * imports: [\n * AmqpWorkerModule.forRoot({\n * contract: myContract,\n * handlers: {\n * processOrder: async (message) => {\n * // message is fully typed based on the contract\n * console.log('Order:', message.orderId);\n * }\n * },\n * urls: ['amqp://localhost']\n * })\n * ]\n * })\n * export class AppModule {}\n *\n * // Asynchronous configuration\n * @Module({\n * imports: [\n * AmqpWorkerModule.forRootAsync({\n * imports: [ConfigModule],\n * useFactory: (configService: ConfigService) => ({\n * contract: myContract,\n * handlers: {\n * processOrder: async (message) => {\n * console.log('Order:', message.orderId);\n * }\n * },\n * urls: configService.get('AMQP_URLS')\n * }),\n * inject: [ConfigService]\n * })\n * ]\n * })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class AmqpWorkerModule {\n /**\n * Register the AMQP worker module with synchronous configuration\n *\n * @param options - The worker configuration options with contract and handlers\n * @returns A dynamic module for NestJS\n */\n static forRoot<TContract extends ContractDefinition>(\n options: AmqpWorkerModuleOptions<TContract>,\n ): DynamicModule {\n return {\n module: AmqpWorkerModule,\n providers: [\n {\n provide: MODULE_OPTIONS_TOKEN,\n useValue: options,\n },\n AmqpWorkerService,\n ],\n exports: [AmqpWorkerService],\n };\n }\n\n /**\n * Register the AMQP worker module with asynchronous configuration\n *\n * @param options - Async configuration options with factory function\n * @returns A dynamic module for NestJS\n */\n static forRootAsync<TContract extends ContractDefinition>(\n options: AmqpWorkerModuleAsyncOptions<TContract>,\n ): DynamicModule {\n const providers: Provider[] = [\n {\n provide: MODULE_OPTIONS_TOKEN,\n useFactory: options.useFactory,\n inject: options.inject ?? [],\n },\n AmqpWorkerService,\n ];\n\n return {\n module: AmqpWorkerModule,\n imports: options.imports ?? [],\n providers,\n exports: [AmqpWorkerService],\n };\n }\n}\n"],"mappings":";;;;;;;;AAIA,MAAa,uBAAuB,OAAO,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;ACmFjE,8BAAMA,oBAEb;CACE,AAAQ,SAA4C;CAEpD,YACE,AACiB,SACjB;EADiB;;;;;;;;;;;;CAanB,MAAM,eAA8B;AAClC,OAAK,SAAS,MAAM,gBAAgB,OAAO,KAAK,QAAQ,CAAC,iBAAiB;;;;;;;;;CAU5E,MAAM,kBAAiC;AACrC,MAAI,KAAK,QAAQ;AACf,SAAM,KAAK,OAAO,OAAO,CAAC,iBAAiB;AAC3C,QAAK,SAAS;;;;;CAnCnB,YAAY;oBAOR,OAAO,qBAAqB;;;;;;;ACN1B,iDAAMC,mBAAiB;;;;;;;CAO5B,OAAO,QACL,SACe;AACf,SAAO;GACL;GACA,WAAW,CACT;IACE,SAAS;IACT,UAAU;IACX,EACD,kBACD;GACD,SAAS,CAAC,kBAAkB;GAC7B;;;;;;;;CASH,OAAO,aACL,SACe;EACf,MAAM,YAAwB,CAC5B;GACE,SAAS;GACT,YAAY,QAAQ;GACpB,QAAQ,QAAQ,UAAU,EAAE;GAC7B,EACD,kBACD;AAED,SAAO;GACL;GACA,SAAS,QAAQ,WAAW,EAAE;GAC9B;GACA,SAAS,CAAC,kBAAkB;GAC7B;;;mDA/CJ,OAAO,EAAE,CAAC"}
|
package/docs/index.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
### AmqpWorkerModule
|
|
10
10
|
|
|
11
|
-
Defined in: [worker-nestjs/src/worker.module.ts:88](https://github.com/btravers/amqp-contract/blob/
|
|
11
|
+
Defined in: [worker-nestjs/src/worker.module.ts:88](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module.ts#L88)
|
|
12
12
|
|
|
13
13
|
NestJS module for AMQP worker integration
|
|
14
14
|
This module provides type-safe AMQP worker functionality using @amqp-contract/worker
|
|
@@ -79,7 +79,7 @@ new AmqpWorkerModule(): AmqpWorkerModule;
|
|
|
79
79
|
static forRoot<TContract>(options): DynamicModule;
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
Defined in: [worker-nestjs/src/worker.module.ts:95](https://github.com/btravers/amqp-contract/blob/
|
|
82
|
+
Defined in: [worker-nestjs/src/worker.module.ts:95](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module.ts#L95)
|
|
83
83
|
|
|
84
84
|
Register the AMQP worker module with synchronous configuration
|
|
85
85
|
|
|
@@ -107,7 +107,7 @@ A dynamic module for NestJS
|
|
|
107
107
|
static forRootAsync<TContract>(options): DynamicModule;
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
Defined in: [worker-nestjs/src/worker.module.ts:117](https://github.com/btravers/amqp-contract/blob/
|
|
110
|
+
Defined in: [worker-nestjs/src/worker.module.ts:117](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module.ts#L117)
|
|
111
111
|
|
|
112
112
|
Register the AMQP worker module with asynchronous configuration
|
|
113
113
|
|
|
@@ -133,7 +133,7 @@ A dynamic module for NestJS
|
|
|
133
133
|
|
|
134
134
|
### AmqpWorkerService
|
|
135
135
|
|
|
136
|
-
Defined in: [worker-nestjs/src/worker.service.ts:
|
|
136
|
+
Defined in: [worker-nestjs/src/worker.service.ts:88](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L88)
|
|
137
137
|
|
|
138
138
|
Type-safe AMQP worker service for NestJS applications.
|
|
139
139
|
|
|
@@ -186,7 +186,7 @@ export class AppModule {}
|
|
|
186
186
|
new AmqpWorkerService<TContract>(options): AmqpWorkerService<TContract>;
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
Defined in: [worker-nestjs/src/worker.service.ts:
|
|
189
|
+
Defined in: [worker-nestjs/src/worker.service.ts:93](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L93)
|
|
190
190
|
|
|
191
191
|
###### Parameters
|
|
192
192
|
|
|
@@ -206,7 +206,7 @@ Defined in: [worker-nestjs/src/worker.service.ts:79](https://github.com/btravers
|
|
|
206
206
|
onModuleDestroy(): Promise<void>;
|
|
207
207
|
```
|
|
208
208
|
|
|
209
|
-
Defined in: [worker-nestjs/src/worker.service.ts:
|
|
209
|
+
Defined in: [worker-nestjs/src/worker.service.ts:119](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L119)
|
|
210
210
|
|
|
211
211
|
Close the AMQP worker when the NestJS module is destroyed.
|
|
212
212
|
|
|
@@ -230,7 +230,7 @@ OnModuleDestroy.onModuleDestroy
|
|
|
230
230
|
onModuleInit(): Promise<void>;
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
Defined in: [worker-nestjs/src/worker.service.ts:
|
|
233
|
+
Defined in: [worker-nestjs/src/worker.service.ts:108](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L108)
|
|
234
234
|
|
|
235
235
|
Initialize the AMQP worker when the NestJS module starts.
|
|
236
236
|
|
|
@@ -261,7 +261,7 @@ OnModuleInit.onModuleInit
|
|
|
261
261
|
type AmqpWorkerModuleAsyncOptions<TContract> = object;
|
|
262
262
|
```
|
|
263
263
|
|
|
264
|
-
Defined in: [worker-nestjs/src/worker.module.ts:22](https://github.com/btravers/amqp-contract/blob/
|
|
264
|
+
Defined in: [worker-nestjs/src/worker.module.ts:22](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module.ts#L22)
|
|
265
265
|
|
|
266
266
|
Options for async module configuration using factory pattern
|
|
267
267
|
|
|
@@ -275,9 +275,9 @@ Options for async module configuration using factory pattern
|
|
|
275
275
|
|
|
276
276
|
| Property | Type | Description | Defined in |
|
|
277
277
|
| ------ | ------ | ------ | ------ |
|
|
278
|
-
| <a id="imports"></a> `imports?` | `ModuleMetadata`\[`"imports"`\] | Optional list of imported modules that export providers needed by the factory | [worker-nestjs/src/worker.module.ts:37](https://github.com/btravers/amqp-contract/blob/
|
|
279
|
-
| <a id="inject"></a> `inject?` | (`string` \| `symbol` \| `Type`\<`unknown`\>)[] | Optional dependencies to inject into the factory function. Can be a token (string/symbol) a class or a reference to a provider. | [worker-nestjs/src/worker.module.ts:33](https://github.com/btravers/amqp-contract/blob/
|
|
280
|
-
| <a id="usefactory"></a> `useFactory` | (...`args`) => `AmqpWorkerModuleOptionsFactory`\<`TContract`\> | Factory function that returns the module options. Can use injected dependencies to create configuration. | [worker-nestjs/src/worker.module.ts:28](https://github.com/btravers/amqp-contract/blob/
|
|
278
|
+
| <a id="imports"></a> `imports?` | `ModuleMetadata`\[`"imports"`\] | Optional list of imported modules that export providers needed by the factory | [worker-nestjs/src/worker.module.ts:37](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module.ts#L37) |
|
|
279
|
+
| <a id="inject"></a> `inject?` | (`string` \| `symbol` \| `Type`\<`unknown`\>)[] | Optional dependencies to inject into the factory function. Can be a token (string/symbol) a class or a reference to a provider. | [worker-nestjs/src/worker.module.ts:33](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module.ts#L33) |
|
|
280
|
+
| <a id="usefactory"></a> `useFactory` | (...`args`) => `AmqpWorkerModuleOptionsFactory`\<`TContract`\> | Factory function that returns the module options. Can use injected dependencies to create configuration. | [worker-nestjs/src/worker.module.ts:28](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module.ts#L28) |
|
|
281
281
|
|
|
282
282
|
***
|
|
283
283
|
|
|
@@ -287,24 +287,38 @@ Options for async module configuration using factory pattern
|
|
|
287
287
|
type AmqpWorkerModuleOptions<TContract> = object;
|
|
288
288
|
```
|
|
289
289
|
|
|
290
|
-
Defined in: [worker-nestjs/src/worker.service.ts:
|
|
290
|
+
Defined in: [worker-nestjs/src/worker.service.ts:42](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L42)
|
|
291
291
|
|
|
292
292
|
Configuration options for the AMQP worker NestJS module.
|
|
293
293
|
|
|
294
294
|
#### Example
|
|
295
295
|
|
|
296
296
|
```typescript
|
|
297
|
+
import { defineHandlers, defineUnsafeHandlers } from '@amqp-contract/worker';
|
|
298
|
+
import { Future, Result } from '@swan-io/boxed';
|
|
299
|
+
import { RetryableError } from '@amqp-contract/worker';
|
|
300
|
+
|
|
301
|
+
// Using safe handlers (recommended)
|
|
302
|
+
const options: AmqpWorkerModuleOptions<typeof contract> = {
|
|
303
|
+
contract: myContract,
|
|
304
|
+
handlers: defineHandlers(myContract, {
|
|
305
|
+
processOrder: (message) =>
|
|
306
|
+
Future.fromPromise(processPayment(message))
|
|
307
|
+
.mapOk(() => undefined)
|
|
308
|
+
.mapError((error) => new RetryableError('Payment failed', error))
|
|
309
|
+
}),
|
|
310
|
+
urls: ['amqp://localhost'],
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// Using unsafe handlers (legacy)
|
|
297
314
|
const options: AmqpWorkerModuleOptions<typeof contract> = {
|
|
298
315
|
contract: myContract,
|
|
299
|
-
handlers: {
|
|
316
|
+
handlers: defineUnsafeHandlers(myContract, {
|
|
300
317
|
processOrder: async (message) => {
|
|
301
318
|
console.log('Processing order:', message.orderId);
|
|
302
319
|
}
|
|
303
|
-
},
|
|
320
|
+
}),
|
|
304
321
|
urls: ['amqp://localhost'],
|
|
305
|
-
connectionOptions: {
|
|
306
|
-
heartbeatIntervalInSeconds: 30
|
|
307
|
-
}
|
|
308
322
|
};
|
|
309
323
|
```
|
|
310
324
|
|
|
@@ -318,23 +332,20 @@ const options: AmqpWorkerModuleOptions<typeof contract> = {
|
|
|
318
332
|
|
|
319
333
|
| Property | Type | Description | Defined in |
|
|
320
334
|
| ------ | ------ | ------ | ------ |
|
|
321
|
-
| <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | Optional connection configuration (heartbeat, reconnect settings, etc.) | [worker-nestjs/src/worker.service.ts:
|
|
322
|
-
| <a id="contract"></a> `contract` | `TContract` | The AMQP contract definition specifying consumers and their message schemas | [worker-nestjs/src/worker.service.ts:
|
|
323
|
-
| <a id="handlers"></a> `handlers` |
|
|
324
|
-
| <a id="urls"></a> `urls` | `ConnectionUrl`[] | AMQP broker URL(s). Multiple URLs provide failover support | [worker-nestjs/src/worker.service.ts:
|
|
335
|
+
| <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | Optional connection configuration (heartbeat, reconnect settings, etc.) | [worker-nestjs/src/worker.service.ts:50](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L50) |
|
|
336
|
+
| <a id="contract"></a> `contract` | `TContract` | The AMQP contract definition specifying consumers and their message schemas | [worker-nestjs/src/worker.service.ts:44](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L44) |
|
|
337
|
+
| <a id="handlers"></a> `handlers` | `WorkerInferSafeConsumerHandlers`\<`TContract`\> | Message handlers for each consumer defined in the contract. Use defineHandlers or defineUnsafeHandlers to create type-safe handlers. | [worker-nestjs/src/worker.service.ts:46](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L46) |
|
|
338
|
+
| <a id="urls"></a> `urls` | `ConnectionUrl`[] | AMQP broker URL(s). Multiple URLs provide failover support | [worker-nestjs/src/worker.service.ts:48](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.service.ts#L48) |
|
|
325
339
|
|
|
326
340
|
***
|
|
327
341
|
|
|
328
|
-
### WorkerInferConsumerHandlers
|
|
342
|
+
### ~~WorkerInferConsumerHandlers~~
|
|
329
343
|
|
|
330
344
|
```ts
|
|
331
|
-
type WorkerInferConsumerHandlers<TContract> =
|
|
345
|
+
type WorkerInferConsumerHandlers<TContract> = WorkerInferUnsafeConsumerHandlers<TContract>;
|
|
332
346
|
```
|
|
333
347
|
|
|
334
|
-
Defined in: worker/dist/index.d.mts:
|
|
335
|
-
|
|
336
|
-
Infer all consumer handlers for a contract.
|
|
337
|
-
Handlers can be either single-message handlers, batch handlers, or a tuple of [handler, options].
|
|
348
|
+
Defined in: worker/dist/index.d.mts:182
|
|
338
349
|
|
|
339
350
|
#### Type Parameters
|
|
340
351
|
|
|
@@ -342,6 +353,10 @@ Handlers can be either single-message handlers, batch handlers, or a tuple of [h
|
|
|
342
353
|
| ------ |
|
|
343
354
|
| `TContract` *extends* `ContractDefinition` |
|
|
344
355
|
|
|
356
|
+
#### Deprecated
|
|
357
|
+
|
|
358
|
+
Use WorkerInferUnsafeConsumerHandlers instead
|
|
359
|
+
|
|
345
360
|
## Variables
|
|
346
361
|
|
|
347
362
|
### MODULE\_OPTIONS\_TOKEN
|
|
@@ -350,7 +365,7 @@ Handlers can be either single-message handlers, batch handlers, or a tuple of [h
|
|
|
350
365
|
const MODULE_OPTIONS_TOKEN: typeof MODULE_OPTIONS_TOKEN;
|
|
351
366
|
```
|
|
352
367
|
|
|
353
|
-
Defined in: [worker-nestjs/src/worker.module-definition.ts:5](https://github.com/btravers/amqp-contract/blob/
|
|
368
|
+
Defined in: [worker-nestjs/src/worker.module-definition.ts:5](https://github.com/btravers/amqp-contract/blob/f058a24938d9644a82812e57d7995cb683cfd6b5/packages/worker-nestjs/src/worker.module-definition.ts#L5)
|
|
354
369
|
|
|
355
370
|
Injection token for AMQP worker module options
|
|
356
371
|
Used by NestJS DI system to inject configuration into AmqpWorkerService
|
|
@@ -365,24 +380,21 @@ Used by NestJS DI system to inject configuration into AmqpWorkerService
|
|
|
365
380
|
function defineHandler<TContract, TName>(
|
|
366
381
|
contract,
|
|
367
382
|
consumerName,
|
|
368
|
-
handler):
|
|
383
|
+
handler): WorkerInferSafeConsumerHandlerEntry<TContract, TName>;
|
|
369
384
|
```
|
|
370
385
|
|
|
371
|
-
Defined in: worker/dist/index.d.mts:
|
|
386
|
+
Defined in: worker/dist/index.d.mts:511
|
|
372
387
|
|
|
373
388
|
Define a type-safe handler for a specific consumer in a contract.
|
|
374
389
|
|
|
375
|
-
This
|
|
376
|
-
providing
|
|
390
|
+
**Recommended:** This function creates handlers that return `Future<Result<void, HandlerError>>`,
|
|
391
|
+
providing explicit error handling and better control over retry behavior.
|
|
377
392
|
|
|
378
393
|
Supports three patterns:
|
|
379
394
|
1. Simple handler: just the function (single message handler)
|
|
380
395
|
2. Handler with prefetch: [handler, { prefetch: 10 }] (single message handler with config)
|
|
381
396
|
3. Batch handler: [batchHandler, { batchSize: 5, batchTimeout: 1000 }] (REQUIRES batchSize config)
|
|
382
397
|
|
|
383
|
-
**Important**: Batch handlers (handlers that accept an array of messages) MUST include
|
|
384
|
-
batchSize configuration. You cannot create a batch handler without specifying batchSize.
|
|
385
|
-
|
|
386
398
|
##### Type Parameters
|
|
387
399
|
|
|
388
400
|
| Type Parameter | Description |
|
|
@@ -396,49 +408,42 @@ batchSize configuration. You cannot create a batch handler without specifying ba
|
|
|
396
408
|
| ------ | ------ | ------ |
|
|
397
409
|
| `contract` | `TContract` | The contract definition containing the consumer |
|
|
398
410
|
| `consumerName` | `TName` | The name of the consumer from the contract |
|
|
399
|
-
| `handler` | `
|
|
411
|
+
| `handler` | `WorkerInferSafeConsumerHandler`\<`TContract`, `TName`\> | The handler function that returns `Future<Result<void, HandlerError>>` |
|
|
400
412
|
|
|
401
413
|
##### Returns
|
|
402
414
|
|
|
403
|
-
`
|
|
415
|
+
`WorkerInferSafeConsumerHandlerEntry`\<`TContract`, `TName`\>
|
|
404
416
|
|
|
405
417
|
A type-safe handler that can be used with TypedAmqpWorker
|
|
406
418
|
|
|
407
419
|
##### Example
|
|
408
420
|
|
|
409
421
|
```typescript
|
|
410
|
-
import { defineHandler } from '@amqp-contract/worker';
|
|
422
|
+
import { defineHandler, RetryableError, NonRetryableError } from '@amqp-contract/worker';
|
|
423
|
+
import { Future, Result } from '@swan-io/boxed';
|
|
411
424
|
import { orderContract } from './contract';
|
|
412
425
|
|
|
413
|
-
// Simple
|
|
426
|
+
// Simple handler with explicit error handling using mapError
|
|
414
427
|
const processOrderHandler = defineHandler(
|
|
415
428
|
orderContract,
|
|
416
429
|
'processOrder',
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
// Single-message handler with prefetch
|
|
424
|
-
const processOrderWithPrefetch = defineHandler(
|
|
425
|
-
orderContract,
|
|
426
|
-
'processOrder',
|
|
427
|
-
async (message) => {
|
|
428
|
-
await processOrder(message);
|
|
429
|
-
},
|
|
430
|
-
{ prefetch: 10 }
|
|
430
|
+
(message) =>
|
|
431
|
+
Future.fromPromise(processPayment(message))
|
|
432
|
+
.mapOk(() => undefined)
|
|
433
|
+
.mapError((error) => new RetryableError('Payment failed', error))
|
|
431
434
|
);
|
|
432
435
|
|
|
433
|
-
//
|
|
434
|
-
const
|
|
436
|
+
// Handler with validation (non-retryable error)
|
|
437
|
+
const validateOrderHandler = defineHandler(
|
|
435
438
|
orderContract,
|
|
436
|
-
'
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
439
|
+
'validateOrder',
|
|
440
|
+
(message) => {
|
|
441
|
+
if (message.amount < 1) {
|
|
442
|
+
// Won't be retried - goes directly to DLQ
|
|
443
|
+
return Future.value(Result.Error(new NonRetryableError('Invalid order amount')));
|
|
444
|
+
}
|
|
445
|
+
return Future.value(Result.Ok(undefined));
|
|
446
|
+
}
|
|
442
447
|
);
|
|
443
448
|
```
|
|
444
449
|
|
|
@@ -449,24 +454,21 @@ function defineHandler<TContract, TName>(
|
|
|
449
454
|
contract,
|
|
450
455
|
consumerName,
|
|
451
456
|
handler,
|
|
452
|
-
options):
|
|
457
|
+
options): WorkerInferSafeConsumerHandlerEntry<TContract, TName>;
|
|
453
458
|
```
|
|
454
459
|
|
|
455
|
-
Defined in: worker/dist/index.d.mts:
|
|
460
|
+
Defined in: worker/dist/index.d.mts:512
|
|
456
461
|
|
|
457
462
|
Define a type-safe handler for a specific consumer in a contract.
|
|
458
463
|
|
|
459
|
-
This
|
|
460
|
-
providing
|
|
464
|
+
**Recommended:** This function creates handlers that return `Future<Result<void, HandlerError>>`,
|
|
465
|
+
providing explicit error handling and better control over retry behavior.
|
|
461
466
|
|
|
462
467
|
Supports three patterns:
|
|
463
468
|
1. Simple handler: just the function (single message handler)
|
|
464
469
|
2. Handler with prefetch: [handler, { prefetch: 10 }] (single message handler with config)
|
|
465
470
|
3. Batch handler: [batchHandler, { batchSize: 5, batchTimeout: 1000 }] (REQUIRES batchSize config)
|
|
466
471
|
|
|
467
|
-
**Important**: Batch handlers (handlers that accept an array of messages) MUST include
|
|
468
|
-
batchSize configuration. You cannot create a batch handler without specifying batchSize.
|
|
469
|
-
|
|
470
472
|
##### Type Parameters
|
|
471
473
|
|
|
472
474
|
| Type Parameter | Description |
|
|
@@ -480,53 +482,46 @@ batchSize configuration. You cannot create a batch handler without specifying ba
|
|
|
480
482
|
| ------ | ------ | ------ |
|
|
481
483
|
| `contract` | `TContract` | The contract definition containing the consumer |
|
|
482
484
|
| `consumerName` | `TName` | The name of the consumer from the contract |
|
|
483
|
-
| `handler` | `
|
|
484
|
-
| `options` | \{ `batchSize?`: `undefined`; `batchTimeout?`: `undefined`; `prefetch?`: `number`; \} | Optional consumer options (prefetch, batchSize, batchTimeout)
|
|
485
|
+
| `handler` | `WorkerInferSafeConsumerHandler`\<`TContract`, `TName`\> | The handler function that returns `Future<Result<void, HandlerError>>` |
|
|
486
|
+
| `options` | \{ `batchSize?`: `undefined`; `batchTimeout?`: `undefined`; `prefetch?`: `number`; \} | Optional consumer options (prefetch, batchSize, batchTimeout) |
|
|
485
487
|
| `options.batchSize?` | `undefined` | - |
|
|
486
488
|
| `options.batchTimeout?` | `undefined` | - |
|
|
487
489
|
| `options.prefetch?` | `number` | - |
|
|
488
490
|
|
|
489
491
|
##### Returns
|
|
490
492
|
|
|
491
|
-
`
|
|
493
|
+
`WorkerInferSafeConsumerHandlerEntry`\<`TContract`, `TName`\>
|
|
492
494
|
|
|
493
495
|
A type-safe handler that can be used with TypedAmqpWorker
|
|
494
496
|
|
|
495
497
|
##### Example
|
|
496
498
|
|
|
497
499
|
```typescript
|
|
498
|
-
import { defineHandler } from '@amqp-contract/worker';
|
|
500
|
+
import { defineHandler, RetryableError, NonRetryableError } from '@amqp-contract/worker';
|
|
501
|
+
import { Future, Result } from '@swan-io/boxed';
|
|
499
502
|
import { orderContract } from './contract';
|
|
500
503
|
|
|
501
|
-
// Simple
|
|
504
|
+
// Simple handler with explicit error handling using mapError
|
|
502
505
|
const processOrderHandler = defineHandler(
|
|
503
506
|
orderContract,
|
|
504
507
|
'processOrder',
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
);
|
|
510
|
-
|
|
511
|
-
// Single-message handler with prefetch
|
|
512
|
-
const processOrderWithPrefetch = defineHandler(
|
|
513
|
-
orderContract,
|
|
514
|
-
'processOrder',
|
|
515
|
-
async (message) => {
|
|
516
|
-
await processOrder(message);
|
|
517
|
-
},
|
|
518
|
-
{ prefetch: 10 }
|
|
508
|
+
(message) =>
|
|
509
|
+
Future.fromPromise(processPayment(message))
|
|
510
|
+
.mapOk(() => undefined)
|
|
511
|
+
.mapError((error) => new RetryableError('Payment failed', error))
|
|
519
512
|
);
|
|
520
513
|
|
|
521
|
-
//
|
|
522
|
-
const
|
|
514
|
+
// Handler with validation (non-retryable error)
|
|
515
|
+
const validateOrderHandler = defineHandler(
|
|
523
516
|
orderContract,
|
|
524
|
-
'
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
517
|
+
'validateOrder',
|
|
518
|
+
(message) => {
|
|
519
|
+
if (message.amount < 1) {
|
|
520
|
+
// Won't be retried - goes directly to DLQ
|
|
521
|
+
return Future.value(Result.Error(new NonRetryableError('Invalid order amount')));
|
|
522
|
+
}
|
|
523
|
+
return Future.value(Result.Ok(undefined));
|
|
524
|
+
}
|
|
530
525
|
);
|
|
531
526
|
```
|
|
532
527
|
|
|
@@ -537,24 +532,21 @@ function defineHandler<TContract, TName>(
|
|
|
537
532
|
contract,
|
|
538
533
|
consumerName,
|
|
539
534
|
handler,
|
|
540
|
-
options):
|
|
535
|
+
options): WorkerInferSafeConsumerHandlerEntry<TContract, TName>;
|
|
541
536
|
```
|
|
542
537
|
|
|
543
|
-
Defined in: worker/dist/index.d.mts:
|
|
538
|
+
Defined in: worker/dist/index.d.mts:517
|
|
544
539
|
|
|
545
540
|
Define a type-safe handler for a specific consumer in a contract.
|
|
546
541
|
|
|
547
|
-
This
|
|
548
|
-
providing
|
|
542
|
+
**Recommended:** This function creates handlers that return `Future<Result<void, HandlerError>>`,
|
|
543
|
+
providing explicit error handling and better control over retry behavior.
|
|
549
544
|
|
|
550
545
|
Supports three patterns:
|
|
551
546
|
1. Simple handler: just the function (single message handler)
|
|
552
547
|
2. Handler with prefetch: [handler, { prefetch: 10 }] (single message handler with config)
|
|
553
548
|
3. Batch handler: [batchHandler, { batchSize: 5, batchTimeout: 1000 }] (REQUIRES batchSize config)
|
|
554
549
|
|
|
555
|
-
**Important**: Batch handlers (handlers that accept an array of messages) MUST include
|
|
556
|
-
batchSize configuration. You cannot create a batch handler without specifying batchSize.
|
|
557
|
-
|
|
558
550
|
##### Type Parameters
|
|
559
551
|
|
|
560
552
|
| Type Parameter | Description |
|
|
@@ -568,53 +560,46 @@ batchSize configuration. You cannot create a batch handler without specifying ba
|
|
|
568
560
|
| ------ | ------ | ------ |
|
|
569
561
|
| `contract` | `TContract` | The contract definition containing the consumer |
|
|
570
562
|
| `consumerName` | `TName` | The name of the consumer from the contract |
|
|
571
|
-
| `handler` | `
|
|
572
|
-
| `options` | \{ `batchSize`: `number`; `batchTimeout?`: `number`; `prefetch?`: `number`; \} | Optional consumer options (prefetch, batchSize, batchTimeout)
|
|
563
|
+
| `handler` | `WorkerInferSafeConsumerBatchHandler`\<`TContract`, `TName`\> | The handler function that returns `Future<Result<void, HandlerError>>` |
|
|
564
|
+
| `options` | \{ `batchSize`: `number`; `batchTimeout?`: `number`; `prefetch?`: `number`; \} | Optional consumer options (prefetch, batchSize, batchTimeout) |
|
|
573
565
|
| `options.batchSize` | `number` | - |
|
|
574
566
|
| `options.batchTimeout?` | `number` | - |
|
|
575
567
|
| `options.prefetch?` | `number` | - |
|
|
576
568
|
|
|
577
569
|
##### Returns
|
|
578
570
|
|
|
579
|
-
`
|
|
571
|
+
`WorkerInferSafeConsumerHandlerEntry`\<`TContract`, `TName`\>
|
|
580
572
|
|
|
581
573
|
A type-safe handler that can be used with TypedAmqpWorker
|
|
582
574
|
|
|
583
575
|
##### Example
|
|
584
576
|
|
|
585
577
|
```typescript
|
|
586
|
-
import { defineHandler } from '@amqp-contract/worker';
|
|
578
|
+
import { defineHandler, RetryableError, NonRetryableError } from '@amqp-contract/worker';
|
|
579
|
+
import { Future, Result } from '@swan-io/boxed';
|
|
587
580
|
import { orderContract } from './contract';
|
|
588
581
|
|
|
589
|
-
// Simple
|
|
582
|
+
// Simple handler with explicit error handling using mapError
|
|
590
583
|
const processOrderHandler = defineHandler(
|
|
591
584
|
orderContract,
|
|
592
585
|
'processOrder',
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
586
|
+
(message) =>
|
|
587
|
+
Future.fromPromise(processPayment(message))
|
|
588
|
+
.mapOk(() => undefined)
|
|
589
|
+
.mapError((error) => new RetryableError('Payment failed', error))
|
|
597
590
|
);
|
|
598
591
|
|
|
599
|
-
//
|
|
600
|
-
const
|
|
592
|
+
// Handler with validation (non-retryable error)
|
|
593
|
+
const validateOrderHandler = defineHandler(
|
|
601
594
|
orderContract,
|
|
602
|
-
'
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
const processBatchOrders = defineHandler(
|
|
611
|
-
orderContract,
|
|
612
|
-
'processOrders',
|
|
613
|
-
async (messages) => {
|
|
614
|
-
// messages is an array - batchSize configuration is REQUIRED
|
|
615
|
-
await db.insertMany(messages);
|
|
616
|
-
},
|
|
617
|
-
{ batchSize: 5, batchTimeout: 1000 }
|
|
595
|
+
'validateOrder',
|
|
596
|
+
(message) => {
|
|
597
|
+
if (message.amount < 1) {
|
|
598
|
+
// Won't be retried - goes directly to DLQ
|
|
599
|
+
return Future.value(Result.Error(new NonRetryableError('Invalid order amount')));
|
|
600
|
+
}
|
|
601
|
+
return Future.value(Result.Ok(undefined));
|
|
602
|
+
}
|
|
618
603
|
);
|
|
619
604
|
```
|
|
620
605
|
|
|
@@ -623,15 +608,15 @@ const processBatchOrders = defineHandler(
|
|
|
623
608
|
### defineHandlers()
|
|
624
609
|
|
|
625
610
|
```ts
|
|
626
|
-
function defineHandlers<TContract>(contract, handlers):
|
|
611
|
+
function defineHandlers<TContract>(contract, handlers): WorkerInferSafeConsumerHandlers<TContract>;
|
|
627
612
|
```
|
|
628
613
|
|
|
629
|
-
Defined in: worker/dist/index.d.mts:
|
|
614
|
+
Defined in: worker/dist/index.d.mts:551
|
|
630
615
|
|
|
631
616
|
Define multiple type-safe handlers for consumers in a contract.
|
|
632
617
|
|
|
633
|
-
This
|
|
634
|
-
|
|
618
|
+
**Recommended:** This function creates handlers that return `Future<Result<void, HandlerError>>`,
|
|
619
|
+
providing explicit error handling and better control over retry behavior.
|
|
635
620
|
|
|
636
621
|
#### Type Parameters
|
|
637
622
|
|
|
@@ -644,55 +629,29 @@ ensuring type safety and providing better code organization.
|
|
|
644
629
|
| Parameter | Type | Description |
|
|
645
630
|
| ------ | ------ | ------ |
|
|
646
631
|
| `contract` | `TContract` | The contract definition containing the consumers |
|
|
647
|
-
| `handlers` |
|
|
632
|
+
| `handlers` | `WorkerInferSafeConsumerHandlers`\<`TContract`\> | An object with handler functions for each consumer |
|
|
648
633
|
|
|
649
634
|
#### Returns
|
|
650
635
|
|
|
651
|
-
|
|
636
|
+
`WorkerInferSafeConsumerHandlers`\<`TContract`\>
|
|
652
637
|
|
|
653
638
|
A type-safe handlers object that can be used with TypedAmqpWorker
|
|
654
639
|
|
|
655
|
-
####
|
|
640
|
+
#### Example
|
|
656
641
|
|
|
657
642
|
```typescript
|
|
658
|
-
import { defineHandlers } from '@amqp-contract/worker';
|
|
643
|
+
import { defineHandlers, RetryableError } from '@amqp-contract/worker';
|
|
644
|
+
import { Future } from '@swan-io/boxed';
|
|
659
645
|
import { orderContract } from './contract';
|
|
660
646
|
|
|
661
|
-
// Define all handlers at once
|
|
662
|
-
const handlers = defineHandlers(orderContract, {
|
|
663
|
-
processOrder: async (message) => {
|
|
664
|
-
// message is fully typed based on the contract
|
|
665
|
-
console.log('Processing order:', message.orderId);
|
|
666
|
-
await processPayment(message);
|
|
667
|
-
},
|
|
668
|
-
notifyOrder: async (message) => {
|
|
669
|
-
await sendNotification(message);
|
|
670
|
-
},
|
|
671
|
-
shipOrder: async (message) => {
|
|
672
|
-
await prepareShipment(message);
|
|
673
|
-
},
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
// Use the handlers in worker
|
|
677
|
-
const worker = await TypedAmqpWorker.create({
|
|
678
|
-
contract: orderContract,
|
|
679
|
-
handlers,
|
|
680
|
-
connection: 'amqp://localhost',
|
|
681
|
-
});
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
```typescript
|
|
685
|
-
// Separate handler definitions for better organization
|
|
686
|
-
async function handleProcessOrder(message: WorkerInferConsumerInput<typeof orderContract, 'processOrder'>) {
|
|
687
|
-
await processOrder(message);
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
async function handleNotifyOrder(message: WorkerInferConsumerInput<typeof orderContract, 'notifyOrder'>) {
|
|
691
|
-
await sendNotification(message);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
647
|
const handlers = defineHandlers(orderContract, {
|
|
695
|
-
processOrder:
|
|
696
|
-
|
|
648
|
+
processOrder: (message) =>
|
|
649
|
+
Future.fromPromise(processPayment(message))
|
|
650
|
+
.mapOk(() => undefined)
|
|
651
|
+
.mapError((error) => new RetryableError('Payment failed', error)),
|
|
652
|
+
notifyOrder: (message) =>
|
|
653
|
+
Future.fromPromise(sendNotification(message))
|
|
654
|
+
.mapOk(() => undefined)
|
|
655
|
+
.mapError((error) => new RetryableError('Notification failed', error)),
|
|
697
656
|
});
|
|
698
657
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amqp-contract/worker-nestjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "NestJS integration for @amqp-contract/worker",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"amqp",
|
|
@@ -52,29 +52,29 @@
|
|
|
52
52
|
"docs"
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@amqp-contract/contract": "0.
|
|
56
|
-
"@amqp-contract/worker": "0.
|
|
55
|
+
"@amqp-contract/contract": "0.9.0",
|
|
56
|
+
"@amqp-contract/worker": "0.9.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@nestjs/common": "11.1.11",
|
|
60
60
|
"@nestjs/core": "11.1.11",
|
|
61
61
|
"@nestjs/testing": "11.1.11",
|
|
62
62
|
"@swan-io/boxed": "3.2.1",
|
|
63
|
-
"@types/node": "25.0.
|
|
63
|
+
"@types/node": "25.0.5",
|
|
64
64
|
"@vitest/coverage-v8": "4.0.16",
|
|
65
65
|
"amqp-connection-manager": "5.0.0",
|
|
66
66
|
"amqplib": "0.10.9",
|
|
67
67
|
"reflect-metadata": "0.2.2",
|
|
68
68
|
"rxjs": "7.8.2",
|
|
69
|
-
"tsdown": "0.
|
|
69
|
+
"tsdown": "0.19.0",
|
|
70
70
|
"typedoc": "0.28.15",
|
|
71
71
|
"typedoc-plugin-markdown": "4.9.0",
|
|
72
72
|
"typescript": "5.9.3",
|
|
73
73
|
"vitest": "4.0.16",
|
|
74
74
|
"zod": "4.3.5",
|
|
75
|
-
"@amqp-contract/testing": "0.
|
|
76
|
-
"@amqp-contract/tsconfig": "0.
|
|
77
|
-
"@amqp-contract/typedoc": "0.0
|
|
75
|
+
"@amqp-contract/testing": "0.9.0",
|
|
76
|
+
"@amqp-contract/tsconfig": "0.1.0",
|
|
77
|
+
"@amqp-contract/typedoc": "0.1.0"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"@nestjs/common": "^11.0.0",
|