@amqp-contract/worker 0.3.1 → 0.3.3

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 CHANGED
@@ -20,8 +20,17 @@ pnpm add @amqp-contract/worker
20
20
 
21
21
  ```typescript
22
22
  import { TypedAmqpWorker } from '@amqp-contract/worker';
23
+ import type { Logger } from '@amqp-contract/core';
23
24
  import { contract } from './contract';
24
25
 
26
+ // Optional: Create a logger implementation
27
+ const logger: Logger = {
28
+ debug: (message, context) => console.debug(message, context),
29
+ info: (message, context) => console.info(message, context),
30
+ warn: (message, context) => console.warn(message, context),
31
+ error: (message, context) => console.error(message, context),
32
+ };
33
+
25
34
  // Create worker from contract with handlers (automatically connects and starts consuming)
26
35
  const worker = await TypedAmqpWorker.create({
27
36
  contract,
@@ -36,7 +45,8 @@ const worker = await TypedAmqpWorker.create({
36
45
  // If an exception is thrown, the message is automatically requeued
37
46
  },
38
47
  },
39
- connection: 'amqp://localhost',
48
+ urls: ['amqp://localhost'],
49
+ logger, // Optional: logs message consumption and errors
40
50
  });
41
51
 
42
52
  // Worker is already consuming messages
@@ -80,7 +90,7 @@ These errors are logged but **handlers don't need to use them** - just throw sta
80
90
 
81
91
  ## API
82
92
 
83
- See the [Worker API documentation](https://btravers.github.io/amqp-contract/api/worker) for complete API reference.
93
+ For complete API documentation, see the [Worker API Reference](https://btravers.github.io/amqp-contract/api/worker).
84
94
 
85
95
  ## Documentation
86
96
 
package/dist/index.cjs CHANGED
@@ -79,10 +79,11 @@ var MessageValidationError = class extends WorkerError {
79
79
  * ```
80
80
  */
81
81
  var TypedAmqpWorker = class TypedAmqpWorker {
82
- constructor(contract, amqpClient, handlers) {
82
+ constructor(contract, amqpClient, handlers, logger) {
83
83
  this.contract = contract;
84
84
  this.amqpClient = amqpClient;
85
85
  this.handlers = handlers;
86
+ this.logger = logger;
86
87
  }
87
88
  /**
88
89
  * Create a type-safe AMQP worker from a contract.
@@ -110,11 +111,11 @@ var TypedAmqpWorker = class TypedAmqpWorker {
110
111
  * }
111
112
  * ```
112
113
  */
113
- static create({ contract, handlers, urls, connectionOptions }) {
114
+ static create({ contract, handlers, urls, connectionOptions, logger }) {
114
115
  const worker = new TypedAmqpWorker(contract, new _amqp_contract_core.AmqpClient(contract, {
115
116
  urls,
116
117
  connectionOptions
117
- }), handlers);
118
+ }), handlers, logger);
118
119
  return worker.waitForConnectionReady().flatMapOk(() => worker.consumeAll()).mapOk(() => worker);
119
120
  }
120
121
  /**
@@ -164,7 +165,11 @@ var TypedAmqpWorker = class TypedAmqpWorker {
164
165
  return _swan_io_boxed.Future.fromPromise(this.amqpClient.channel.consume(consumer.queue.name, async (msg) => {
165
166
  const parseResult = _swan_io_boxed.Result.fromExecution(() => JSON.parse(msg.content.toString()));
166
167
  if (parseResult.isError()) {
167
- console.error(new TechnicalError(`Error parsing message for consumer "${String(consumerName)}"`, parseResult.error));
168
+ this.logger?.error("Error parsing message", {
169
+ consumerName: String(consumerName),
170
+ queueName: consumer.queue.name,
171
+ error: parseResult.error
172
+ });
168
173
  this.amqpClient.channel.nack(msg, false, false);
169
174
  return;
170
175
  }
@@ -173,12 +178,24 @@ var TypedAmqpWorker = class TypedAmqpWorker {
173
178
  if (validationResult.issues) return _swan_io_boxed.Result.Error(new MessageValidationError(String(consumerName), validationResult.issues));
174
179
  return _swan_io_boxed.Result.Ok(validationResult.value);
175
180
  }).tapError((error) => {
176
- console.error(error);
181
+ this.logger?.error("Message validation failed", {
182
+ consumerName: String(consumerName),
183
+ queueName: consumer.queue.name,
184
+ error
185
+ });
177
186
  this.amqpClient.channel.nack(msg, false, false);
178
187
  }).flatMapOk((validatedMessage) => _swan_io_boxed.Future.fromPromise(handler(validatedMessage)).tapError((error) => {
179
- console.error(new TechnicalError(`Error processing message for consumer "${String(consumerName)}"`, error));
188
+ this.logger?.error("Error processing message", {
189
+ consumerName: String(consumerName),
190
+ queueName: consumer.queue.name,
191
+ error
192
+ });
180
193
  this.amqpClient.channel.nack(msg, false, true);
181
194
  })).tapOk(() => {
195
+ this.logger?.info("Message consumed successfully", {
196
+ consumerName: String(consumerName),
197
+ queueName: consumer.queue.name
198
+ });
182
199
  this.amqpClient.channel.ack(msg);
183
200
  }).toPromise();
184
201
  })).mapError((error) => new TechnicalError(`Failed to start consuming for "${String(consumerName)}"`, error)).mapOk(() => void 0);
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ConsumerDefinition, ContractDefinition, InferConsumerNames } from "@amqp-contract/contract";
2
+ import { Logger } from "@amqp-contract/core";
2
3
  import { Future, Result } from "@swan-io/boxed";
3
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
4
5
  import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
@@ -75,7 +76,8 @@ type WorkerInferConsumerHandlers<TContract extends ContractDefinition> = { [K in
75
76
  * urls: ['amqp://localhost'],
76
77
  * connectionOptions: {
77
78
  * heartbeatIntervalInSeconds: 30
78
- * }
79
+ * },
80
+ * logger: myLogger
79
81
  * };
80
82
  * ```
81
83
  */
@@ -88,6 +90,8 @@ type CreateWorkerOptions<TContract extends ContractDefinition> = {
88
90
  urls: ConnectionUrl[];
89
91
  /** Optional connection configuration (heartbeat, reconnect settings, etc.) */
90
92
  connectionOptions?: AmqpConnectionManagerOptions | undefined;
93
+ /** Optional logger for logging message consumption and errors */
94
+ logger?: Logger | undefined;
91
95
  };
92
96
  /**
93
97
  * Type-safe AMQP worker for consuming messages from RabbitMQ.
@@ -133,6 +137,7 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
133
137
  private readonly contract;
134
138
  private readonly amqpClient;
135
139
  private readonly handlers;
140
+ private readonly logger?;
136
141
  private constructor();
137
142
  /**
138
143
  * Create a type-safe AMQP worker from a contract.
@@ -164,7 +169,8 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
164
169
  contract,
165
170
  handlers,
166
171
  urls,
167
- connectionOptions
172
+ connectionOptions,
173
+ logger
168
174
  }: CreateWorkerOptions<TContract>): Future<Result<TypedAmqpWorker<TContract>, TechnicalError>>;
169
175
  /**
170
176
  * Close the AMQP channel and connection.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Logger } from "@amqp-contract/core";
1
2
  import { Future, Result } from "@swan-io/boxed";
2
3
  import { ConsumerDefinition, ContractDefinition, InferConsumerNames } from "@amqp-contract/contract";
3
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
@@ -75,7 +76,8 @@ type WorkerInferConsumerHandlers<TContract extends ContractDefinition> = { [K in
75
76
  * urls: ['amqp://localhost'],
76
77
  * connectionOptions: {
77
78
  * heartbeatIntervalInSeconds: 30
78
- * }
79
+ * },
80
+ * logger: myLogger
79
81
  * };
80
82
  * ```
81
83
  */
@@ -88,6 +90,8 @@ type CreateWorkerOptions<TContract extends ContractDefinition> = {
88
90
  urls: ConnectionUrl[];
89
91
  /** Optional connection configuration (heartbeat, reconnect settings, etc.) */
90
92
  connectionOptions?: AmqpConnectionManagerOptions | undefined;
93
+ /** Optional logger for logging message consumption and errors */
94
+ logger?: Logger | undefined;
91
95
  };
92
96
  /**
93
97
  * Type-safe AMQP worker for consuming messages from RabbitMQ.
@@ -133,6 +137,7 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
133
137
  private readonly contract;
134
138
  private readonly amqpClient;
135
139
  private readonly handlers;
140
+ private readonly logger?;
136
141
  private constructor();
137
142
  /**
138
143
  * Create a type-safe AMQP worker from a contract.
@@ -164,7 +169,8 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
164
169
  contract,
165
170
  handlers,
166
171
  urls,
167
- connectionOptions
172
+ connectionOptions,
173
+ logger
168
174
  }: CreateWorkerOptions<TContract>): Future<Result<TypedAmqpWorker<TContract>, TechnicalError>>;
169
175
  /**
170
176
  * Close the AMQP channel and connection.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -79,10 +79,11 @@ var MessageValidationError = class extends WorkerError {
79
79
  * ```
80
80
  */
81
81
  var TypedAmqpWorker = class TypedAmqpWorker {
82
- constructor(contract, amqpClient, handlers) {
82
+ constructor(contract, amqpClient, handlers, logger) {
83
83
  this.contract = contract;
84
84
  this.amqpClient = amqpClient;
85
85
  this.handlers = handlers;
86
+ this.logger = logger;
86
87
  }
87
88
  /**
88
89
  * Create a type-safe AMQP worker from a contract.
@@ -110,11 +111,11 @@ var TypedAmqpWorker = class TypedAmqpWorker {
110
111
  * }
111
112
  * ```
112
113
  */
113
- static create({ contract, handlers, urls, connectionOptions }) {
114
+ static create({ contract, handlers, urls, connectionOptions, logger }) {
114
115
  const worker = new TypedAmqpWorker(contract, new AmqpClient(contract, {
115
116
  urls,
116
117
  connectionOptions
117
- }), handlers);
118
+ }), handlers, logger);
118
119
  return worker.waitForConnectionReady().flatMapOk(() => worker.consumeAll()).mapOk(() => worker);
119
120
  }
120
121
  /**
@@ -164,7 +165,11 @@ var TypedAmqpWorker = class TypedAmqpWorker {
164
165
  return Future.fromPromise(this.amqpClient.channel.consume(consumer.queue.name, async (msg) => {
165
166
  const parseResult = Result.fromExecution(() => JSON.parse(msg.content.toString()));
166
167
  if (parseResult.isError()) {
167
- console.error(new TechnicalError(`Error parsing message for consumer "${String(consumerName)}"`, parseResult.error));
168
+ this.logger?.error("Error parsing message", {
169
+ consumerName: String(consumerName),
170
+ queueName: consumer.queue.name,
171
+ error: parseResult.error
172
+ });
168
173
  this.amqpClient.channel.nack(msg, false, false);
169
174
  return;
170
175
  }
@@ -173,12 +178,24 @@ var TypedAmqpWorker = class TypedAmqpWorker {
173
178
  if (validationResult.issues) return Result.Error(new MessageValidationError(String(consumerName), validationResult.issues));
174
179
  return Result.Ok(validationResult.value);
175
180
  }).tapError((error) => {
176
- console.error(error);
181
+ this.logger?.error("Message validation failed", {
182
+ consumerName: String(consumerName),
183
+ queueName: consumer.queue.name,
184
+ error
185
+ });
177
186
  this.amqpClient.channel.nack(msg, false, false);
178
187
  }).flatMapOk((validatedMessage) => Future.fromPromise(handler(validatedMessage)).tapError((error) => {
179
- console.error(new TechnicalError(`Error processing message for consumer "${String(consumerName)}"`, error));
188
+ this.logger?.error("Error processing message", {
189
+ consumerName: String(consumerName),
190
+ queueName: consumer.queue.name,
191
+ error
192
+ });
180
193
  this.amqpClient.channel.nack(msg, false, true);
181
194
  })).tapOk(() => {
195
+ this.logger?.info("Message consumed successfully", {
196
+ consumerName: String(consumerName),
197
+ queueName: consumer.queue.name
198
+ });
182
199
  this.amqpClient.channel.ack(msg);
183
200
  }).toPromise();
184
201
  })).mapError((error) => new TechnicalError(`Failed to start consuming for "${String(consumerName)}"`, error)).mapOk(() => void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["cause?: unknown","consumerName: string","issues: unknown","contract: TContract","amqpClient: AmqpClient","handlers: WorkerInferConsumerHandlers<TContract>"],"sources":["../src/errors.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":["/**\n * Base error class for worker errors\n */\nabstract class WorkerError extends Error {\n protected constructor(message: string) {\n super(message);\n this.name = \"WorkerError\";\n // Node.js specific stack trace capture\n const ErrorConstructor = Error as unknown as {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (typeof ErrorConstructor.captureStackTrace === \"function\") {\n ErrorConstructor.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error for technical/runtime failures in worker operations\n * This includes validation failures, parsing failures, and processing failures\n */\nexport class TechnicalError extends WorkerError {\n constructor(\n message: string,\n public override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"TechnicalError\";\n }\n}\n\n/**\n * Error thrown when message validation fails\n */\nexport class MessageValidationError extends WorkerError {\n constructor(\n public readonly consumerName: string,\n public readonly issues: unknown,\n ) {\n super(`Message validation failed for consumer \"${consumerName}\"`);\n this.name = \"MessageValidationError\";\n }\n}\n","import type { ContractDefinition, InferConsumerNames } from \"@amqp-contract/contract\";\nimport { AmqpClient } from \"@amqp-contract/core\";\nimport { Future, Result } from \"@swan-io/boxed\";\nimport { MessageValidationError, TechnicalError } from \"./errors.js\";\nimport type { WorkerInferConsumerHandlers, WorkerInferConsumerInput } from \"./types.js\";\nimport type { AmqpConnectionManagerOptions, ConnectionUrl } from \"amqp-connection-manager\";\n\n/**\n * Options for creating a type-safe AMQP worker.\n *\n * @typeParam TContract - The contract definition type\n *\n * @example\n * ```typescript\n * const options: CreateWorkerOptions<typeof contract> = {\n * contract: myContract,\n * handlers: {\n * processOrder: async (message) => {\n * console.log('Processing order:', message.orderId);\n * }\n * },\n * urls: ['amqp://localhost'],\n * connectionOptions: {\n * heartbeatIntervalInSeconds: 30\n * }\n * };\n * ```\n */\nexport type CreateWorkerOptions<TContract extends ContractDefinition> = {\n /** The AMQP contract definition specifying consumers and their message schemas */\n contract: TContract;\n /** Handlers for each consumer defined in the contract */\n handlers: WorkerInferConsumerHandlers<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 for consuming messages from RabbitMQ.\n *\n * This class provides automatic message validation, connection management,\n * and error handling for consuming messages based on a contract definition.\n *\n * @typeParam TContract - The contract definition type\n *\n * @example\n * ```typescript\n * import { TypedAmqpWorker } from '@amqp-contract/worker';\n * import { z } from 'zod';\n *\n * const contract = defineContract({\n * queues: {\n * orderProcessing: defineQueue('order-processing', { durable: true })\n * },\n * consumers: {\n * processOrder: defineConsumer('order-processing', z.object({\n * orderId: z.string(),\n * amount: z.number()\n * }))\n * }\n * });\n *\n * const worker = await TypedAmqpWorker.create({\n * contract,\n * handlers: {\n * processOrder: async (message) => {\n * console.log('Processing order', message.orderId);\n * // Process the order...\n * }\n * },\n * urls: ['amqp://localhost']\n * }).resultToPromise();\n *\n * // Close when done\n * await worker.close().resultToPromise();\n * ```\n */\nexport class TypedAmqpWorker<TContract extends ContractDefinition> {\n private constructor(\n private readonly contract: TContract,\n private readonly amqpClient: AmqpClient,\n private readonly handlers: WorkerInferConsumerHandlers<TContract>,\n ) {}\n\n /**\n * Create a type-safe AMQP worker from a contract.\n *\n * Connection management (including automatic reconnection) is handled internally\n * by amqp-connection-manager via the {@link AmqpClient}. The worker will set up\n * consumers for all contract-defined handlers asynchronously in the background\n * once the underlying connection and channels are ready.\n *\n * @param options - Configuration options for the worker\n * @returns A Future that resolves to a Result containing the worker or an error\n *\n * @example\n * ```typescript\n * const workerResult = await TypedAmqpWorker.create({\n * contract: myContract,\n * handlers: {\n * processOrder: async (msg) => console.log('Order:', msg.orderId)\n * },\n * urls: ['amqp://localhost']\n * }).resultToPromise();\n *\n * if (workerResult.isError()) {\n * console.error('Failed to create worker:', workerResult.error);\n * }\n * ```\n */\n static create<TContract extends ContractDefinition>({\n contract,\n handlers,\n urls,\n connectionOptions,\n }: CreateWorkerOptions<TContract>): Future<Result<TypedAmqpWorker<TContract>, TechnicalError>> {\n const worker = new TypedAmqpWorker(\n contract,\n new AmqpClient(contract, {\n urls,\n connectionOptions,\n }),\n handlers,\n );\n\n return worker\n .waitForConnectionReady()\n .flatMapOk(() => worker.consumeAll())\n .mapOk(() => worker);\n }\n\n /**\n * Close the AMQP channel and connection.\n *\n * This gracefully closes the connection to the AMQP broker,\n * stopping all message consumption and cleaning up resources.\n *\n * @returns A Future that resolves to a Result indicating success or failure\n *\n * @example\n * ```typescript\n * const closeResult = await worker.close().resultToPromise();\n * if (closeResult.isOk()) {\n * console.log('Worker closed successfully');\n * }\n * ```\n */\n close(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.amqpClient.close())\n .mapError((error) => new TechnicalError(\"Failed to close AMQP connection\", error))\n .mapOk(() => undefined);\n }\n\n /**\n * Start consuming messages for all consumers\n */\n private consumeAll(): Future<Result<void, TechnicalError>> {\n if (!this.contract.consumers) {\n return Future.value(Result.Error(new TechnicalError(\"No consumers defined in contract\")));\n }\n\n const consumerNames = Object.keys(this.contract.consumers) as InferConsumerNames<TContract>[];\n\n return Future.all(consumerNames.map((consumerName) => this.consume(consumerName)))\n .map(Result.all)\n .mapOk(() => undefined);\n }\n\n private waitForConnectionReady(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.amqpClient.channel.waitForConnect()).mapError(\n (error) => new TechnicalError(\"Failed to wait for connection ready\", error),\n );\n }\n\n /**\n * Start consuming messages for a specific consumer\n */\n private consume<TName extends InferConsumerNames<TContract>>(\n consumerName: TName,\n ): Future<Result<void, TechnicalError>> {\n const consumers = this.contract.consumers;\n if (!consumers) {\n return Future.value(Result.Error(new TechnicalError(\"No consumers defined in contract\")));\n }\n\n const consumer = consumers[consumerName as string];\n if (!consumer) {\n const availableConsumers = Object.keys(consumers);\n const available = availableConsumers.length > 0 ? availableConsumers.join(\", \") : \"none\";\n return Future.value(\n Result.Error(\n new TechnicalError(\n `Consumer not found: \"${String(consumerName)}\". Available consumers: ${available}`,\n ),\n ),\n );\n }\n\n const handler = this.handlers[consumerName];\n if (!handler) {\n return Future.value(\n Result.Error(new TechnicalError(`Handler for \"${String(consumerName)}\" not provided`)),\n );\n }\n\n // Start consuming\n return Future.fromPromise(\n this.amqpClient.channel.consume(consumer.queue.name, async (msg) => {\n // Parse message\n const parseResult = Result.fromExecution(() => JSON.parse(msg.content.toString()));\n if (parseResult.isError()) {\n // fixme: define a proper logging mechanism\n // fixme: do not log just an error, use a proper logging mechanism\n console.error(\n new TechnicalError(\n `Error parsing message for consumer \"${String(consumerName)}\"`,\n parseResult.error,\n ),\n );\n\n // fixme proper error handling strategy\n // Reject message with no requeue (malformed JSON)\n this.amqpClient.channel.nack(msg, false, false);\n return;\n }\n\n const rawValidation = consumer.message.payload[\"~standard\"].validate(parseResult.value);\n await Future.fromPromise(\n rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation),\n )\n .mapOkToResult((validationResult) => {\n if (validationResult.issues) {\n return Result.Error(\n new MessageValidationError(String(consumerName), validationResult.issues),\n );\n }\n\n return Result.Ok(validationResult.value as WorkerInferConsumerInput<TContract, TName>);\n })\n .tapError((error) => {\n // fixme: define a proper logging mechanism\n // fixme: do not log just an error, use a proper logging mechanism\n console.error(error);\n\n // fixme proper error handling strategy\n // Reject message with no requeue (validation failed)\n this.amqpClient.channel.nack(msg, false, false);\n })\n .flatMapOk((validatedMessage) =>\n Future.fromPromise(handler(validatedMessage)).tapError((error) => {\n // fixme: define a proper logging mechanism\n // fixme: do not log just an error, use a proper logging mechanism\n console.error(\n new TechnicalError(\n `Error processing message for consumer \"${String(consumerName)}\"`,\n error,\n ),\n );\n\n // fixme proper error handling strategy\n // Reject message and requeue (handler failed)\n this.amqpClient.channel.nack(msg, false, true);\n }),\n )\n .tapOk(() => {\n // Acknowledge message\n this.amqpClient.channel.ack(msg);\n })\n .toPromise();\n }),\n )\n .mapError(\n (error) =>\n new TechnicalError(`Failed to start consuming for \"${String(consumerName)}\"`, error),\n )\n .mapOk(() => undefined);\n }\n}\n","import type { ContractDefinition, InferConsumerNames } from \"@amqp-contract/contract\";\nimport type { WorkerInferConsumerHandler, WorkerInferConsumerHandlers } from \"./types.js\";\n\n/**\n * Define a type-safe handler for a specific consumer in a contract.\n *\n * This utility allows you to define handlers outside of the worker creation,\n * providing better code organization and reusability.\n *\n * @template TContract - The contract definition type\n * @template TName - The consumer name from the contract\n * @param contract - The contract definition containing the consumer\n * @param consumerName - The name of the consumer from the contract\n * @param handler - The async handler function that processes messages\n * @returns A type-safe handler that can be used with TypedAmqpWorker\n *\n * @example\n * ```typescript\n * import { defineHandler } from '@amqp-contract/worker';\n * import { orderContract } from './contract';\n *\n * // Define handler outside of worker creation\n * const processOrderHandler = defineHandler(\n * orderContract,\n * 'processOrder',\n * async (message) => {\n * // message is fully typed based on the contract\n * console.log('Processing order:', message.orderId);\n * await processPayment(message);\n * }\n * );\n *\n * // Use the handler in worker\n * const worker = await TypedAmqpWorker.create({\n * contract: orderContract,\n * handlers: {\n * processOrder: processOrderHandler,\n * },\n * connection: 'amqp://localhost',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Define multiple handlers\n * const processOrderHandler = defineHandler(\n * orderContract,\n * 'processOrder',\n * async (message) => {\n * await processOrder(message);\n * }\n * );\n *\n * const notifyOrderHandler = defineHandler(\n * orderContract,\n * 'notifyOrder',\n * async (message) => {\n * await sendNotification(message);\n * }\n * );\n *\n * // Compose handlers\n * const worker = await TypedAmqpWorker.create({\n * contract: orderContract,\n * handlers: {\n * processOrder: processOrderHandler,\n * notifyOrder: notifyOrderHandler,\n * },\n * connection: 'amqp://localhost',\n * });\n * ```\n */\nexport function defineHandler<\n TContract extends ContractDefinition,\n TName extends InferConsumerNames<TContract>,\n>(\n contract: TContract,\n consumerName: TName,\n handler: WorkerInferConsumerHandler<TContract, TName>,\n): WorkerInferConsumerHandler<TContract, TName> {\n // Validate that the consumer exists in the contract\n const consumers = contract.consumers;\n\n if (!consumers || !(consumerName in consumers)) {\n const availableConsumers = consumers ? Object.keys(consumers) : [];\n const available = availableConsumers.length > 0 ? availableConsumers.join(\", \") : \"none\";\n throw new Error(\n `Consumer \"${String(consumerName)}\" not found in contract. Available consumers: ${available}`,\n );\n }\n\n // Return the handler as-is, with type checking enforced\n return handler;\n}\n\n/**\n * Define multiple type-safe handlers for consumers in a contract.\n *\n * This utility allows you to define all handlers at once outside of the worker creation,\n * ensuring type safety and providing better code organization.\n *\n * @template TContract - The contract definition type\n * @param contract - The contract definition containing the consumers\n * @param handlers - An object with async handler functions for each consumer\n * @returns A type-safe handlers object that can be used with TypedAmqpWorker\n *\n * @example\n * ```typescript\n * import { defineHandlers } from '@amqp-contract/worker';\n * import { orderContract } from './contract';\n *\n * // Define all handlers at once\n * const handlers = defineHandlers(orderContract, {\n * processOrder: async (message) => {\n * // message is fully typed based on the contract\n * console.log('Processing order:', message.orderId);\n * await processPayment(message);\n * },\n * notifyOrder: async (message) => {\n * await sendNotification(message);\n * },\n * shipOrder: async (message) => {\n * await prepareShipment(message);\n * },\n * });\n *\n * // Use the handlers in worker\n * const worker = await TypedAmqpWorker.create({\n * contract: orderContract,\n * handlers,\n * connection: 'amqp://localhost',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Separate handler definitions for better organization\n * async function handleProcessOrder(message: WorkerInferConsumerInput<typeof orderContract, 'processOrder'>) {\n * await processOrder(message);\n * }\n *\n * async function handleNotifyOrder(message: WorkerInferConsumerInput<typeof orderContract, 'notifyOrder'>) {\n * await sendNotification(message);\n * }\n *\n * const handlers = defineHandlers(orderContract, {\n * processOrder: handleProcessOrder,\n * notifyOrder: handleNotifyOrder,\n * });\n * ```\n */\nexport function defineHandlers<TContract extends ContractDefinition>(\n contract: TContract,\n handlers: WorkerInferConsumerHandlers<TContract>,\n): WorkerInferConsumerHandlers<TContract> {\n // Validate that all consumers in handlers exist in the contract\n const consumers = contract.consumers;\n const availableConsumers = Object.keys(consumers ?? {});\n const availableConsumerNames =\n availableConsumers.length > 0 ? availableConsumers.join(\", \") : \"none\";\n\n for (const handlerName of Object.keys(handlers)) {\n if (!consumers || !(handlerName in consumers)) {\n throw new Error(\n `Consumer \"${handlerName}\" not found in contract. Available consumers: ${availableConsumerNames}`,\n );\n }\n }\n\n // Return the handlers as-is, with type checking enforced\n return handlers;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["cause?: unknown","consumerName: string","issues: unknown","contract: TContract","amqpClient: AmqpClient","handlers: WorkerInferConsumerHandlers<TContract>","logger?: Logger"],"sources":["../src/errors.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":["/**\n * Base error class for worker errors\n */\nabstract class WorkerError extends Error {\n protected constructor(message: string) {\n super(message);\n this.name = \"WorkerError\";\n // Node.js specific stack trace capture\n const ErrorConstructor = Error as unknown as {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (typeof ErrorConstructor.captureStackTrace === \"function\") {\n ErrorConstructor.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error for technical/runtime failures in worker operations\n * This includes validation failures, parsing failures, and processing failures\n */\nexport class TechnicalError extends WorkerError {\n constructor(\n message: string,\n public override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"TechnicalError\";\n }\n}\n\n/**\n * Error thrown when message validation fails\n */\nexport class MessageValidationError extends WorkerError {\n constructor(\n public readonly consumerName: string,\n public readonly issues: unknown,\n ) {\n super(`Message validation failed for consumer \"${consumerName}\"`);\n this.name = \"MessageValidationError\";\n }\n}\n","import type { ContractDefinition, InferConsumerNames } from \"@amqp-contract/contract\";\nimport { AmqpClient, type Logger } from \"@amqp-contract/core\";\nimport { Future, Result } from \"@swan-io/boxed\";\nimport { MessageValidationError, TechnicalError } from \"./errors.js\";\nimport type { WorkerInferConsumerHandlers, WorkerInferConsumerInput } from \"./types.js\";\nimport type { AmqpConnectionManagerOptions, ConnectionUrl } from \"amqp-connection-manager\";\n\n/**\n * Options for creating a type-safe AMQP worker.\n *\n * @typeParam TContract - The contract definition type\n *\n * @example\n * ```typescript\n * const options: CreateWorkerOptions<typeof contract> = {\n * contract: myContract,\n * handlers: {\n * processOrder: async (message) => {\n * console.log('Processing order:', message.orderId);\n * }\n * },\n * urls: ['amqp://localhost'],\n * connectionOptions: {\n * heartbeatIntervalInSeconds: 30\n * },\n * logger: myLogger\n * };\n * ```\n */\nexport type CreateWorkerOptions<TContract extends ContractDefinition> = {\n /** The AMQP contract definition specifying consumers and their message schemas */\n contract: TContract;\n /** Handlers for each consumer defined in the contract */\n handlers: WorkerInferConsumerHandlers<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 /** Optional logger for logging message consumption and errors */\n logger?: Logger | undefined;\n};\n\n/**\n * Type-safe AMQP worker for consuming messages from RabbitMQ.\n *\n * This class provides automatic message validation, connection management,\n * and error handling for consuming messages based on a contract definition.\n *\n * @typeParam TContract - The contract definition type\n *\n * @example\n * ```typescript\n * import { TypedAmqpWorker } from '@amqp-contract/worker';\n * import { z } from 'zod';\n *\n * const contract = defineContract({\n * queues: {\n * orderProcessing: defineQueue('order-processing', { durable: true })\n * },\n * consumers: {\n * processOrder: defineConsumer('order-processing', z.object({\n * orderId: z.string(),\n * amount: z.number()\n * }))\n * }\n * });\n *\n * const worker = await TypedAmqpWorker.create({\n * contract,\n * handlers: {\n * processOrder: async (message) => {\n * console.log('Processing order', message.orderId);\n * // Process the order...\n * }\n * },\n * urls: ['amqp://localhost']\n * }).resultToPromise();\n *\n * // Close when done\n * await worker.close().resultToPromise();\n * ```\n */\nexport class TypedAmqpWorker<TContract extends ContractDefinition> {\n private constructor(\n private readonly contract: TContract,\n private readonly amqpClient: AmqpClient,\n private readonly handlers: WorkerInferConsumerHandlers<TContract>,\n private readonly logger?: Logger,\n ) {}\n\n /**\n * Create a type-safe AMQP worker from a contract.\n *\n * Connection management (including automatic reconnection) is handled internally\n * by amqp-connection-manager via the {@link AmqpClient}. The worker will set up\n * consumers for all contract-defined handlers asynchronously in the background\n * once the underlying connection and channels are ready.\n *\n * @param options - Configuration options for the worker\n * @returns A Future that resolves to a Result containing the worker or an error\n *\n * @example\n * ```typescript\n * const workerResult = await TypedAmqpWorker.create({\n * contract: myContract,\n * handlers: {\n * processOrder: async (msg) => console.log('Order:', msg.orderId)\n * },\n * urls: ['amqp://localhost']\n * }).resultToPromise();\n *\n * if (workerResult.isError()) {\n * console.error('Failed to create worker:', workerResult.error);\n * }\n * ```\n */\n static create<TContract extends ContractDefinition>({\n contract,\n handlers,\n urls,\n connectionOptions,\n logger,\n }: CreateWorkerOptions<TContract>): Future<Result<TypedAmqpWorker<TContract>, TechnicalError>> {\n const worker = new TypedAmqpWorker(\n contract,\n new AmqpClient(contract, {\n urls,\n connectionOptions,\n }),\n handlers,\n logger,\n );\n\n return worker\n .waitForConnectionReady()\n .flatMapOk(() => worker.consumeAll())\n .mapOk(() => worker);\n }\n\n /**\n * Close the AMQP channel and connection.\n *\n * This gracefully closes the connection to the AMQP broker,\n * stopping all message consumption and cleaning up resources.\n *\n * @returns A Future that resolves to a Result indicating success or failure\n *\n * @example\n * ```typescript\n * const closeResult = await worker.close().resultToPromise();\n * if (closeResult.isOk()) {\n * console.log('Worker closed successfully');\n * }\n * ```\n */\n close(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.amqpClient.close())\n .mapError((error) => new TechnicalError(\"Failed to close AMQP connection\", error))\n .mapOk(() => undefined);\n }\n\n /**\n * Start consuming messages for all consumers\n */\n private consumeAll(): Future<Result<void, TechnicalError>> {\n if (!this.contract.consumers) {\n return Future.value(Result.Error(new TechnicalError(\"No consumers defined in contract\")));\n }\n\n const consumerNames = Object.keys(this.contract.consumers) as InferConsumerNames<TContract>[];\n\n return Future.all(consumerNames.map((consumerName) => this.consume(consumerName)))\n .map(Result.all)\n .mapOk(() => undefined);\n }\n\n private waitForConnectionReady(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.amqpClient.channel.waitForConnect()).mapError(\n (error) => new TechnicalError(\"Failed to wait for connection ready\", error),\n );\n }\n\n /**\n * Start consuming messages for a specific consumer\n */\n private consume<TName extends InferConsumerNames<TContract>>(\n consumerName: TName,\n ): Future<Result<void, TechnicalError>> {\n const consumers = this.contract.consumers;\n if (!consumers) {\n return Future.value(Result.Error(new TechnicalError(\"No consumers defined in contract\")));\n }\n\n const consumer = consumers[consumerName as string];\n if (!consumer) {\n const availableConsumers = Object.keys(consumers);\n const available = availableConsumers.length > 0 ? availableConsumers.join(\", \") : \"none\";\n return Future.value(\n Result.Error(\n new TechnicalError(\n `Consumer not found: \"${String(consumerName)}\". Available consumers: ${available}`,\n ),\n ),\n );\n }\n\n const handler = this.handlers[consumerName];\n if (!handler) {\n return Future.value(\n Result.Error(new TechnicalError(`Handler for \"${String(consumerName)}\" not provided`)),\n );\n }\n\n // Start consuming\n return Future.fromPromise(\n this.amqpClient.channel.consume(consumer.queue.name, async (msg) => {\n // Parse message\n const parseResult = Result.fromExecution(() => JSON.parse(msg.content.toString()));\n if (parseResult.isError()) {\n this.logger?.error(\"Error parsing message\", {\n consumerName: String(consumerName),\n queueName: consumer.queue.name,\n error: parseResult.error,\n });\n\n // fixme proper error handling strategy\n // Reject message with no requeue (malformed JSON)\n this.amqpClient.channel.nack(msg, false, false);\n return;\n }\n\n const rawValidation = consumer.message.payload[\"~standard\"].validate(parseResult.value);\n await Future.fromPromise(\n rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation),\n )\n .mapOkToResult((validationResult) => {\n if (validationResult.issues) {\n return Result.Error(\n new MessageValidationError(String(consumerName), validationResult.issues),\n );\n }\n\n return Result.Ok(validationResult.value as WorkerInferConsumerInput<TContract, TName>);\n })\n .tapError((error) => {\n this.logger?.error(\"Message validation failed\", {\n consumerName: String(consumerName),\n queueName: consumer.queue.name,\n error,\n });\n\n // fixme proper error handling strategy\n // Reject message with no requeue (validation failed)\n this.amqpClient.channel.nack(msg, false, false);\n })\n .flatMapOk((validatedMessage) =>\n Future.fromPromise(handler(validatedMessage)).tapError((error) => {\n this.logger?.error(\"Error processing message\", {\n consumerName: String(consumerName),\n queueName: consumer.queue.name,\n error,\n });\n\n // fixme proper error handling strategy\n // Reject message and requeue (handler failed)\n this.amqpClient.channel.nack(msg, false, true);\n }),\n )\n .tapOk(() => {\n this.logger?.info(\"Message consumed successfully\", {\n consumerName: String(consumerName),\n queueName: consumer.queue.name,\n });\n\n // Acknowledge message\n this.amqpClient.channel.ack(msg);\n })\n .toPromise();\n }),\n )\n .mapError(\n (error) =>\n new TechnicalError(`Failed to start consuming for \"${String(consumerName)}\"`, error),\n )\n .mapOk(() => undefined);\n }\n}\n","import type { ContractDefinition, InferConsumerNames } from \"@amqp-contract/contract\";\nimport type { WorkerInferConsumerHandler, WorkerInferConsumerHandlers } from \"./types.js\";\n\n/**\n * Define a type-safe handler for a specific consumer in a contract.\n *\n * This utility allows you to define handlers outside of the worker creation,\n * providing better code organization and reusability.\n *\n * @template TContract - The contract definition type\n * @template TName - The consumer name from the contract\n * @param contract - The contract definition containing the consumer\n * @param consumerName - The name of the consumer from the contract\n * @param handler - The async handler function that processes messages\n * @returns A type-safe handler that can be used with TypedAmqpWorker\n *\n * @example\n * ```typescript\n * import { defineHandler } from '@amqp-contract/worker';\n * import { orderContract } from './contract';\n *\n * // Define handler outside of worker creation\n * const processOrderHandler = defineHandler(\n * orderContract,\n * 'processOrder',\n * async (message) => {\n * // message is fully typed based on the contract\n * console.log('Processing order:', message.orderId);\n * await processPayment(message);\n * }\n * );\n *\n * // Use the handler in worker\n * const worker = await TypedAmqpWorker.create({\n * contract: orderContract,\n * handlers: {\n * processOrder: processOrderHandler,\n * },\n * connection: 'amqp://localhost',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Define multiple handlers\n * const processOrderHandler = defineHandler(\n * orderContract,\n * 'processOrder',\n * async (message) => {\n * await processOrder(message);\n * }\n * );\n *\n * const notifyOrderHandler = defineHandler(\n * orderContract,\n * 'notifyOrder',\n * async (message) => {\n * await sendNotification(message);\n * }\n * );\n *\n * // Compose handlers\n * const worker = await TypedAmqpWorker.create({\n * contract: orderContract,\n * handlers: {\n * processOrder: processOrderHandler,\n * notifyOrder: notifyOrderHandler,\n * },\n * connection: 'amqp://localhost',\n * });\n * ```\n */\nexport function defineHandler<\n TContract extends ContractDefinition,\n TName extends InferConsumerNames<TContract>,\n>(\n contract: TContract,\n consumerName: TName,\n handler: WorkerInferConsumerHandler<TContract, TName>,\n): WorkerInferConsumerHandler<TContract, TName> {\n // Validate that the consumer exists in the contract\n const consumers = contract.consumers;\n\n if (!consumers || !(consumerName in consumers)) {\n const availableConsumers = consumers ? Object.keys(consumers) : [];\n const available = availableConsumers.length > 0 ? availableConsumers.join(\", \") : \"none\";\n throw new Error(\n `Consumer \"${String(consumerName)}\" not found in contract. Available consumers: ${available}`,\n );\n }\n\n // Return the handler as-is, with type checking enforced\n return handler;\n}\n\n/**\n * Define multiple type-safe handlers for consumers in a contract.\n *\n * This utility allows you to define all handlers at once outside of the worker creation,\n * ensuring type safety and providing better code organization.\n *\n * @template TContract - The contract definition type\n * @param contract - The contract definition containing the consumers\n * @param handlers - An object with async handler functions for each consumer\n * @returns A type-safe handlers object that can be used with TypedAmqpWorker\n *\n * @example\n * ```typescript\n * import { defineHandlers } from '@amqp-contract/worker';\n * import { orderContract } from './contract';\n *\n * // Define all handlers at once\n * const handlers = defineHandlers(orderContract, {\n * processOrder: async (message) => {\n * // message is fully typed based on the contract\n * console.log('Processing order:', message.orderId);\n * await processPayment(message);\n * },\n * notifyOrder: async (message) => {\n * await sendNotification(message);\n * },\n * shipOrder: async (message) => {\n * await prepareShipment(message);\n * },\n * });\n *\n * // Use the handlers in worker\n * const worker = await TypedAmqpWorker.create({\n * contract: orderContract,\n * handlers,\n * connection: 'amqp://localhost',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Separate handler definitions for better organization\n * async function handleProcessOrder(message: WorkerInferConsumerInput<typeof orderContract, 'processOrder'>) {\n * await processOrder(message);\n * }\n *\n * async function handleNotifyOrder(message: WorkerInferConsumerInput<typeof orderContract, 'notifyOrder'>) {\n * await sendNotification(message);\n * }\n *\n * const handlers = defineHandlers(orderContract, {\n * processOrder: handleProcessOrder,\n * notifyOrder: handleNotifyOrder,\n * });\n * ```\n */\nexport function defineHandlers<TContract extends ContractDefinition>(\n contract: TContract,\n handlers: WorkerInferConsumerHandlers<TContract>,\n): WorkerInferConsumerHandlers<TContract> {\n // Validate that all consumers in handlers exist in the contract\n const consumers = contract.consumers;\n const availableConsumers = Object.keys(consumers ?? {});\n const availableConsumerNames =\n availableConsumers.length > 0 ? availableConsumers.join(\", \") : \"none\";\n\n for (const handlerName of Object.keys(handlers)) {\n if (!consumers || !(handlerName in consumers)) {\n throw new Error(\n `Consumer \"${handlerName}\" not found in contract. Available consumers: ${availableConsumerNames}`,\n );\n }\n }\n\n // Return the handlers as-is, with type checking enforced\n return handlers;\n}\n"],"mappings":";;;;;;;AAGA,IAAe,cAAf,cAAmC,MAAM;CACvC,AAAU,YAAY,SAAiB;AACrC,QAAM,QAAQ;AACd,OAAK,OAAO;EAEZ,MAAM,mBAAmB;AAGzB,MAAI,OAAO,iBAAiB,sBAAsB,WAChD,kBAAiB,kBAAkB,MAAM,KAAK,YAAY;;;;;;;AAShE,IAAa,iBAAb,cAAoC,YAAY;CAC9C,YACE,SACA,AAAyBA,OACzB;AACA,QAAM,QAAQ;EAFW;AAGzB,OAAK,OAAO;;;;;;AAOhB,IAAa,yBAAb,cAA4C,YAAY;CACtD,YACE,AAAgBC,cAChB,AAAgBC,QAChB;AACA,QAAM,2CAA2C,aAAa,GAAG;EAHjD;EACA;AAGhB,OAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC0ChB,IAAa,kBAAb,MAAa,gBAAsD;CACjE,AAAQ,YACN,AAAiBC,UACjB,AAAiBC,YACjB,AAAiBC,UACjB,AAAiBC,QACjB;EAJiB;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BnB,OAAO,OAA6C,EAClD,UACA,UACA,MACA,mBACA,UAC6F;EAC7F,MAAM,SAAS,IAAI,gBACjB,UACA,IAAI,WAAW,UAAU;GACvB;GACA;GACD,CAAC,EACF,UACA,OACD;AAED,SAAO,OACJ,wBAAwB,CACxB,gBAAgB,OAAO,YAAY,CAAC,CACpC,YAAY,OAAO;;;;;;;;;;;;;;;;;;CAmBxB,QAA8C;AAC5C,SAAO,OAAO,YAAY,KAAK,WAAW,OAAO,CAAC,CAC/C,UAAU,UAAU,IAAI,eAAe,mCAAmC,MAAM,CAAC,CACjF,YAAY,OAAU;;;;;CAM3B,AAAQ,aAAmD;AACzD,MAAI,CAAC,KAAK,SAAS,UACjB,QAAO,OAAO,MAAM,OAAO,MAAM,IAAI,eAAe,mCAAmC,CAAC,CAAC;EAG3F,MAAM,gBAAgB,OAAO,KAAK,KAAK,SAAS,UAAU;AAE1D,SAAO,OAAO,IAAI,cAAc,KAAK,iBAAiB,KAAK,QAAQ,aAAa,CAAC,CAAC,CAC/E,IAAI,OAAO,IAAI,CACf,YAAY,OAAU;;CAG3B,AAAQ,yBAA+D;AACrE,SAAO,OAAO,YAAY,KAAK,WAAW,QAAQ,gBAAgB,CAAC,CAAC,UACjE,UAAU,IAAI,eAAe,uCAAuC,MAAM,CAC5E;;;;;CAMH,AAAQ,QACN,cACsC;EACtC,MAAM,YAAY,KAAK,SAAS;AAChC,MAAI,CAAC,UACH,QAAO,OAAO,MAAM,OAAO,MAAM,IAAI,eAAe,mCAAmC,CAAC,CAAC;EAG3F,MAAM,WAAW,UAAU;AAC3B,MAAI,CAAC,UAAU;GACb,MAAM,qBAAqB,OAAO,KAAK,UAAU;GACjD,MAAM,YAAY,mBAAmB,SAAS,IAAI,mBAAmB,KAAK,KAAK,GAAG;AAClF,UAAO,OAAO,MACZ,OAAO,MACL,IAAI,eACF,wBAAwB,OAAO,aAAa,CAAC,0BAA0B,YACxE,CACF,CACF;;EAGH,MAAM,UAAU,KAAK,SAAS;AAC9B,MAAI,CAAC,QACH,QAAO,OAAO,MACZ,OAAO,MAAM,IAAI,eAAe,gBAAgB,OAAO,aAAa,CAAC,gBAAgB,CAAC,CACvF;AAIH,SAAO,OAAO,YACZ,KAAK,WAAW,QAAQ,QAAQ,SAAS,MAAM,MAAM,OAAO,QAAQ;GAElE,MAAM,cAAc,OAAO,oBAAoB,KAAK,MAAM,IAAI,QAAQ,UAAU,CAAC,CAAC;AAClF,OAAI,YAAY,SAAS,EAAE;AACzB,SAAK,QAAQ,MAAM,yBAAyB;KAC1C,cAAc,OAAO,aAAa;KAClC,WAAW,SAAS,MAAM;KAC1B,OAAO,YAAY;KACpB,CAAC;AAIF,SAAK,WAAW,QAAQ,KAAK,KAAK,OAAO,MAAM;AAC/C;;GAGF,MAAM,gBAAgB,SAAS,QAAQ,QAAQ,aAAa,SAAS,YAAY,MAAM;AACvF,SAAM,OAAO,YACX,yBAAyB,UAAU,gBAAgB,QAAQ,QAAQ,cAAc,CAClF,CACE,eAAe,qBAAqB;AACnC,QAAI,iBAAiB,OACnB,QAAO,OAAO,MACZ,IAAI,uBAAuB,OAAO,aAAa,EAAE,iBAAiB,OAAO,CAC1E;AAGH,WAAO,OAAO,GAAG,iBAAiB,MAAoD;KACtF,CACD,UAAU,UAAU;AACnB,SAAK,QAAQ,MAAM,6BAA6B;KAC9C,cAAc,OAAO,aAAa;KAClC,WAAW,SAAS,MAAM;KAC1B;KACD,CAAC;AAIF,SAAK,WAAW,QAAQ,KAAK,KAAK,OAAO,MAAM;KAC/C,CACD,WAAW,qBACV,OAAO,YAAY,QAAQ,iBAAiB,CAAC,CAAC,UAAU,UAAU;AAChE,SAAK,QAAQ,MAAM,4BAA4B;KAC7C,cAAc,OAAO,aAAa;KAClC,WAAW,SAAS,MAAM;KAC1B;KACD,CAAC;AAIF,SAAK,WAAW,QAAQ,KAAK,KAAK,OAAO,KAAK;KAC9C,CACH,CACA,YAAY;AACX,SAAK,QAAQ,KAAK,iCAAiC;KACjD,cAAc,OAAO,aAAa;KAClC,WAAW,SAAS,MAAM;KAC3B,CAAC;AAGF,SAAK,WAAW,QAAQ,IAAI,IAAI;KAChC,CACD,WAAW;IACd,CACH,CACE,UACE,UACC,IAAI,eAAe,kCAAkC,OAAO,aAAa,CAAC,IAAI,MAAM,CACvF,CACA,YAAY,OAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpN7B,SAAgB,cAId,UACA,cACA,SAC8C;CAE9C,MAAM,YAAY,SAAS;AAE3B,KAAI,CAAC,aAAa,EAAE,gBAAgB,YAAY;EAC9C,MAAM,qBAAqB,YAAY,OAAO,KAAK,UAAU,GAAG,EAAE;EAClE,MAAM,YAAY,mBAAmB,SAAS,IAAI,mBAAmB,KAAK,KAAK,GAAG;AAClF,QAAM,IAAI,MACR,aAAa,OAAO,aAAa,CAAC,gDAAgD,YACnF;;AAIH,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DT,SAAgB,eACd,UACA,UACwC;CAExC,MAAM,YAAY,SAAS;CAC3B,MAAM,qBAAqB,OAAO,KAAK,aAAa,EAAE,CAAC;CACvD,MAAM,yBACJ,mBAAmB,SAAS,IAAI,mBAAmB,KAAK,KAAK,GAAG;AAElE,MAAK,MAAM,eAAe,OAAO,KAAK,SAAS,CAC7C,KAAI,CAAC,aAAa,EAAE,eAAe,WACjC,OAAM,IAAI,MACR,aAAa,YAAY,gDAAgD,yBAC1E;AAKL,QAAO"}
package/docs/index.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ### MessageValidationError
10
10
 
11
- Defined in: [packages/worker/src/errors.ts:35](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/errors.ts#L35)
11
+ Defined in: [packages/worker/src/errors.ts:35](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/errors.ts#L35)
12
12
 
13
13
  Error thrown when message validation fails
14
14
 
@@ -24,7 +24,7 @@ Error thrown when message validation fails
24
24
  new MessageValidationError(consumerName, issues): MessageValidationError;
25
25
  ```
26
26
 
27
- Defined in: [packages/worker/src/errors.ts:36](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/errors.ts#L36)
27
+ Defined in: [packages/worker/src/errors.ts:36](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/errors.ts#L36)
28
28
 
29
29
  ###### Parameters
30
30
 
@@ -48,8 +48,8 @@ WorkerError.constructor
48
48
  | Property | Modifier | Type | Description | Inherited from | Defined in |
49
49
  | ------ | ------ | ------ | ------ | ------ | ------ |
50
50
  | <a id="cause"></a> `cause?` | `public` | `unknown` | - | `WorkerError.cause` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:26 |
51
- | <a id="consumername"></a> `consumerName` | `readonly` | `string` | - | - | [packages/worker/src/errors.ts:37](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/errors.ts#L37) |
52
- | <a id="issues"></a> `issues` | `readonly` | `unknown` | - | - | [packages/worker/src/errors.ts:38](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/errors.ts#L38) |
51
+ | <a id="consumername"></a> `consumerName` | `readonly` | `string` | - | - | [packages/worker/src/errors.ts:37](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/errors.ts#L37) |
52
+ | <a id="issues"></a> `issues` | `readonly` | `unknown` | - | - | [packages/worker/src/errors.ts:38](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/errors.ts#L38) |
53
53
  | <a id="message"></a> `message` | `public` | `string` | - | `WorkerError.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
54
54
  | <a id="name"></a> `name` | `public` | `string` | - | `WorkerError.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
55
55
  | <a id="stack"></a> `stack?` | `public` | `string` | - | `WorkerError.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
@@ -159,7 +159,7 @@ WorkerError.prepareStackTrace
159
159
 
160
160
  ### TechnicalError
161
161
 
162
- Defined in: [packages/worker/src/errors.ts:22](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/errors.ts#L22)
162
+ Defined in: [packages/worker/src/errors.ts:22](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/errors.ts#L22)
163
163
 
164
164
  Error for technical/runtime failures in worker operations
165
165
  This includes validation failures, parsing failures, and processing failures
@@ -176,7 +176,7 @@ This includes validation failures, parsing failures, and processing failures
176
176
  new TechnicalError(message, cause?): TechnicalError;
177
177
  ```
178
178
 
179
- Defined in: [packages/worker/src/errors.ts:23](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/errors.ts#L23)
179
+ Defined in: [packages/worker/src/errors.ts:23](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/errors.ts#L23)
180
180
 
181
181
  ###### Parameters
182
182
 
@@ -199,7 +199,7 @@ WorkerError.constructor
199
199
 
200
200
  | Property | Modifier | Type | Description | Inherited from | Defined in |
201
201
  | ------ | ------ | ------ | ------ | ------ | ------ |
202
- | <a id="cause-1"></a> `cause?` | `readonly` | `unknown` | - | `WorkerError.cause` | [packages/worker/src/errors.ts:25](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/errors.ts#L25) |
202
+ | <a id="cause-1"></a> `cause?` | `readonly` | `unknown` | - | `WorkerError.cause` | [packages/worker/src/errors.ts:25](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/errors.ts#L25) |
203
203
  | <a id="message-1"></a> `message` | `public` | `string` | - | `WorkerError.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
204
204
  | <a id="name-1"></a> `name` | `public` | `string` | - | `WorkerError.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
205
205
  | <a id="stack-1"></a> `stack?` | `public` | `string` | - | `WorkerError.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
@@ -309,7 +309,7 @@ WorkerError.prepareStackTrace
309
309
 
310
310
  ### TypedAmqpWorker
311
311
 
312
- Defined in: [packages/worker/src/worker.ts:80](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L80)
312
+ Defined in: [packages/worker/src/worker.ts:83](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L83)
313
313
 
314
314
  Type-safe AMQP worker for consuming messages from RabbitMQ.
315
315
 
@@ -363,7 +363,7 @@ await worker.close().resultToPromise();
363
363
  close(): Future<Result<void, TechnicalError>>;
364
364
  ```
365
365
 
366
- Defined in: [packages/worker/src/worker.ts:150](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L150)
366
+ Defined in: [packages/worker/src/worker.ts:156](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L156)
367
367
 
368
368
  Close the AMQP channel and connection.
369
369
 
@@ -391,7 +391,7 @@ if (closeResult.isOk()) {
391
391
  static create<TContract>(options): Future<Result<TypedAmqpWorker<TContract>, TechnicalError>>;
392
392
  ```
393
393
 
394
- Defined in: [packages/worker/src/worker.ts:113](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L113)
394
+ Defined in: [packages/worker/src/worker.ts:117](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L117)
395
395
 
396
396
  Create a type-safe AMQP worker from a contract.
397
397
 
@@ -442,7 +442,7 @@ if (workerResult.isError()) {
442
442
  type CreateWorkerOptions<TContract> = object;
443
443
  ```
444
444
 
445
- Defined in: [packages/worker/src/worker.ts:29](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L29)
445
+ Defined in: [packages/worker/src/worker.ts:30](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L30)
446
446
 
447
447
  Options for creating a type-safe AMQP worker.
448
448
 
@@ -459,7 +459,8 @@ const options: CreateWorkerOptions<typeof contract> = {
459
459
  urls: ['amqp://localhost'],
460
460
  connectionOptions: {
461
461
  heartbeatIntervalInSeconds: 30
462
- }
462
+ },
463
+ logger: myLogger
463
464
  };
464
465
  ```
465
466
 
@@ -473,10 +474,11 @@ const options: CreateWorkerOptions<typeof contract> = {
473
474
 
474
475
  | Property | Type | Description | Defined in |
475
476
  | ------ | ------ | ------ | ------ |
476
- | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | Optional connection configuration (heartbeat, reconnect settings, etc.) | [packages/worker/src/worker.ts:37](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L37) |
477
- | <a id="contract"></a> `contract` | `TContract` | The AMQP contract definition specifying consumers and their message schemas | [packages/worker/src/worker.ts:31](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L31) |
478
- | <a id="handlers"></a> `handlers` | [`WorkerInferConsumerHandlers`](#workerinferconsumerhandlers)\<`TContract`\> | Handlers for each consumer defined in the contract | [packages/worker/src/worker.ts:33](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L33) |
479
- | <a id="urls"></a> `urls` | `ConnectionUrl`[] | AMQP broker URL(s). Multiple URLs provide failover support | [packages/worker/src/worker.ts:35](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/worker.ts#L35) |
477
+ | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | Optional connection configuration (heartbeat, reconnect settings, etc.) | [packages/worker/src/worker.ts:38](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L38) |
478
+ | <a id="contract"></a> `contract` | `TContract` | The AMQP contract definition specifying consumers and their message schemas | [packages/worker/src/worker.ts:32](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L32) |
479
+ | <a id="handlers"></a> `handlers` | [`WorkerInferConsumerHandlers`](#workerinferconsumerhandlers)\<`TContract`\> | Handlers for each consumer defined in the contract | [packages/worker/src/worker.ts:34](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L34) |
480
+ | <a id="logger"></a> `logger?` | `Logger` | Optional logger for logging message consumption and errors | [packages/worker/src/worker.ts:40](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L40) |
481
+ | <a id="urls"></a> `urls` | `ConnectionUrl`[] | AMQP broker URL(s). Multiple URLs provide failover support | [packages/worker/src/worker.ts:36](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/worker.ts#L36) |
480
482
 
481
483
  ***
482
484
 
@@ -486,7 +488,7 @@ const options: CreateWorkerOptions<typeof contract> = {
486
488
  type WorkerInferConsumerHandler<TContract, TName> = (message) => Promise<void>;
487
489
  ```
488
490
 
489
- Defined in: [packages/worker/src/types.ts:45](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/types.ts#L45)
491
+ Defined in: [packages/worker/src/types.ts:45](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/types.ts#L45)
490
492
 
491
493
  Infer consumer handler type for a specific consumer
492
494
 
@@ -515,7 +517,7 @@ Infer consumer handler type for a specific consumer
515
517
  type WorkerInferConsumerHandlers<TContract> = { [K in InferConsumerNames<TContract>]: WorkerInferConsumerHandler<TContract, K> };
516
518
  ```
517
519
 
518
- Defined in: [packages/worker/src/types.ts:53](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/types.ts#L53)
520
+ Defined in: [packages/worker/src/types.ts:53](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/types.ts#L53)
519
521
 
520
522
  Infer all consumer handlers for a contract
521
523
 
@@ -533,7 +535,7 @@ Infer all consumer handlers for a contract
533
535
  type WorkerInferConsumerInput<TContract, TName> = ConsumerInferInput<InferConsumer<TContract, TName>>;
534
536
  ```
535
537
 
536
- Defined in: [packages/worker/src/types.ts:37](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/types.ts#L37)
538
+ Defined in: [packages/worker/src/types.ts:37](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/types.ts#L37)
537
539
 
538
540
  Worker perspective types - for consuming messages
539
541
 
@@ -555,7 +557,7 @@ function defineHandler<TContract, TName>(
555
557
  handler): WorkerInferConsumerHandler<TContract, TName>;
556
558
  ```
557
559
 
558
- Defined in: [packages/worker/src/handlers.ts:73](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/handlers.ts#L73)
560
+ Defined in: [packages/worker/src/handlers.ts:73](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/handlers.ts#L73)
559
561
 
560
562
  Define a type-safe handler for a specific consumer in a contract.
561
563
 
@@ -647,7 +649,7 @@ const worker = await TypedAmqpWorker.create({
647
649
  function defineHandlers<TContract>(contract, handlers): WorkerInferConsumerHandlers<TContract>;
648
650
  ```
649
651
 
650
- Defined in: [packages/worker/src/handlers.ts:152](https://github.com/btravers/amqp-contract/blob/9351cdf40185977e98479881b5fc5e55897fdf7b/packages/worker/src/handlers.ts#L152)
652
+ Defined in: [packages/worker/src/handlers.ts:152](https://github.com/btravers/amqp-contract/blob/fb7fe976925e332da34b847357ebcbeefd37355d/packages/worker/src/handlers.ts#L152)
651
653
 
652
654
  Define multiple type-safe handlers for consumers in a contract.
653
655
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amqp-contract/worker",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Worker utilities for consuming messages using amqp-contract",
5
5
  "keywords": [
6
6
  "amqp",
@@ -44,8 +44,8 @@
44
44
  "dependencies": {
45
45
  "@standard-schema/spec": "1.1.0",
46
46
  "@swan-io/boxed": "3.2.1",
47
- "@amqp-contract/core": "0.3.1",
48
- "@amqp-contract/contract": "0.3.1"
47
+ "@amqp-contract/contract": "0.3.3",
48
+ "@amqp-contract/core": "0.3.3"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/amqplib": "0.10.8",
@@ -59,8 +59,8 @@
59
59
  "typescript": "5.9.3",
60
60
  "vitest": "4.0.16",
61
61
  "zod": "4.2.1",
62
- "@amqp-contract/client": "0.3.1",
63
- "@amqp-contract/testing": "0.3.1",
62
+ "@amqp-contract/client": "0.3.3",
63
+ "@amqp-contract/testing": "0.3.3",
64
64
  "@amqp-contract/tsconfig": "0.0.0",
65
65
  "@amqp-contract/typedoc": "0.0.1"
66
66
  },