@amqp-contract/core 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -173,6 +173,25 @@ var TechnicalError = class extends Error {
173
173
  if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
174
174
  }
175
175
  };
176
+ /**
177
+ * Error thrown when message validation fails (payload or headers).
178
+ *
179
+ * Used by both the client (publish-time payload validation) and the worker
180
+ * (consume-time payload and headers validation).
181
+ *
182
+ * @param source - The name of the publisher or consumer that triggered the validation
183
+ * @param issues - The validation issues from the Standard Schema validation
184
+ */
185
+ var MessageValidationError = class extends Error {
186
+ constructor(source, issues) {
187
+ super(`Message validation failed for "${source}"`);
188
+ this.source = source;
189
+ this.issues = issues;
190
+ this.name = "MessageValidationError";
191
+ const ErrorConstructor = Error;
192
+ if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
193
+ }
194
+ };
176
195
 
177
196
  //#endregion
178
197
  //#region src/setup.ts
@@ -188,7 +207,7 @@ var TechnicalError = class extends Error {
188
207
  * @param channel - The AMQP channel to use for topology setup
189
208
  * @param contract - The contract definition containing the topology specification
190
209
  * @throws {AggregateError} If any exchanges, queues, or bindings fail to be created
191
- * @throws {Error} If a queue references a dead letter exchange not declared in the contract
210
+ * @throws {TechnicalError} If a queue references a dead letter exchange not declared in the contract
192
211
  *
193
212
  * @example
194
213
  * ```typescript
@@ -208,7 +227,7 @@ async function setupAmqpTopology(channel, contract) {
208
227
  const queue = (0, _amqp_contract_contract.extractQueue)(queueEntry);
209
228
  if (queue.deadLetter) {
210
229
  const dlxName = queue.deadLetter.exchange.name;
211
- if (!Object.values(contract.exchanges ?? {}).some((exchange) => exchange.name === dlxName)) throw new Error(`Queue "${queue.name}" references dead letter exchange "${dlxName}" which is not declared in the contract. Add the exchange to contract.exchanges to ensure it is created before the queue.`);
230
+ if (!Object.values(contract.exchanges ?? {}).some((exchange) => exchange.name === dlxName)) throw new TechnicalError(`Queue "${queue.name}" references dead letter exchange "${dlxName}" which is not declared in the contract. Add the exchange to contract.exchanges to ensure it is created before the queue.`);
212
231
  }
213
232
  }
214
233
  const queueErrors = (await Promise.allSettled(Object.values(contract.queues ?? {}).map((queueEntry) => {
@@ -245,6 +264,20 @@ async function setupAmqpTopology(channel, contract) {
245
264
  //#endregion
246
265
  //#region src/amqp-client.ts
247
266
  /**
267
+ * Invoke a SetupFunc, handling both callback-based and promise-based signatures.
268
+ * Uses Function.length to distinguish (same approach as promise-breaker).
269
+ * @internal
270
+ */
271
+ function callSetupFunc(setup, channel) {
272
+ if (setup.length >= 2) return new Promise((resolve, reject) => {
273
+ setup(channel, (error) => {
274
+ if (error) reject(error);
275
+ else resolve();
276
+ });
277
+ });
278
+ return setup(channel);
279
+ }
280
+ /**
248
281
  * AMQP client that manages connections and channels with automatic topology setup.
249
282
  *
250
283
  * This class handles:
@@ -302,13 +335,7 @@ var AmqpClient = class {
302
335
  };
303
336
  if (userSetup) channelOpts.setup = async (channel) => {
304
337
  await defaultSetup(channel);
305
- if (userSetup.length === 2) await new Promise((resolve, reject) => {
306
- userSetup(channel, (error) => {
307
- if (error) reject(error);
308
- else resolve();
309
- });
310
- });
311
- else await userSetup(channel);
338
+ await callSetupFunc(userSetup, channel);
312
339
  };
313
340
  this.channelWrapper = this.connection.createChannel(channelOpts);
314
341
  }
@@ -449,17 +476,15 @@ const MessagingSemanticConventions = {
449
476
  MESSAGING_DESTINATION: "messaging.destination.name",
450
477
  MESSAGING_DESTINATION_KIND: "messaging.destination.kind",
451
478
  MESSAGING_OPERATION: "messaging.operation",
452
- MESSAGING_MESSAGE_ID: "messaging.message.id",
453
- MESSAGING_MESSAGE_PAYLOAD_SIZE: "messaging.message.body.size",
454
- MESSAGING_MESSAGE_CONVERSATION_ID: "messaging.message.conversation_id",
455
479
  MESSAGING_RABBITMQ_ROUTING_KEY: "messaging.rabbitmq.destination.routing_key",
456
480
  MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG: "messaging.rabbitmq.message.delivery_tag",
481
+ AMQP_PUBLISHER_NAME: "amqp.publisher.name",
482
+ AMQP_CONSUMER_NAME: "amqp.consumer.name",
457
483
  ERROR_TYPE: "error.type",
458
484
  MESSAGING_SYSTEM_RABBITMQ: "rabbitmq",
459
485
  MESSAGING_DESTINATION_KIND_EXCHANGE: "exchange",
460
486
  MESSAGING_DESTINATION_KIND_QUEUE: "queue",
461
487
  MESSAGING_OPERATION_PUBLISH: "publish",
462
- MESSAGING_OPERATION_RECEIVE: "receive",
463
488
  MESSAGING_OPERATION_PROCESS: "process"
464
489
  };
465
490
  /**
@@ -581,7 +606,7 @@ function startConsumeSpan(provider, queueName, consumerName, attributes) {
581
606
  [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,
582
607
  [MessagingSemanticConventions.MESSAGING_DESTINATION_KIND]: MessagingSemanticConventions.MESSAGING_DESTINATION_KIND_QUEUE,
583
608
  [MessagingSemanticConventions.MESSAGING_OPERATION]: MessagingSemanticConventions.MESSAGING_OPERATION_PROCESS,
584
- "amqp.consumer.name": consumerName,
609
+ [MessagingSemanticConventions.AMQP_CONSUMER_NAME]: consumerName,
585
610
  ...attributes
586
611
  }
587
612
  });
@@ -635,7 +660,7 @@ function recordConsumeMetric(provider, queueName, consumerName, success, duratio
635
660
  const attributes = {
636
661
  [MessagingSemanticConventions.MESSAGING_SYSTEM]: MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,
637
662
  [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,
638
- "amqp.consumer.name": consumerName,
663
+ [MessagingSemanticConventions.AMQP_CONSUMER_NAME]: consumerName,
639
664
  success
640
665
  };
641
666
  consumeCounter?.add(1, attributes);
@@ -658,6 +683,7 @@ function _resetTelemetryCacheForTesting() {
658
683
  //#endregion
659
684
  exports.AmqpClient = AmqpClient;
660
685
  exports.ConnectionManagerSingleton = ConnectionManagerSingleton;
686
+ exports.MessageValidationError = MessageValidationError;
661
687
  exports.MessagingSemanticConventions = MessagingSemanticConventions;
662
688
  exports.TechnicalError = TechnicalError;
663
689
  exports._resetTelemetryCacheForTesting = _resetTelemetryCacheForTesting;
package/dist/index.d.cts CHANGED
@@ -71,6 +71,20 @@ declare class TechnicalError extends Error {
71
71
  readonly cause?: unknown | undefined;
72
72
  constructor(message: string, cause?: unknown | undefined);
73
73
  }
74
+ /**
75
+ * Error thrown when message validation fails (payload or headers).
76
+ *
77
+ * Used by both the client (publish-time payload validation) and the worker
78
+ * (consume-time payload and headers validation).
79
+ *
80
+ * @param source - The name of the publisher or consumer that triggered the validation
81
+ * @param issues - The validation issues from the Standard Schema validation
82
+ */
83
+ declare class MessageValidationError extends Error {
84
+ readonly source: string;
85
+ readonly issues: unknown;
86
+ constructor(source: string, issues: unknown);
87
+ }
74
88
  //#endregion
75
89
  //#region src/amqp-client.d.ts
76
90
  /**
@@ -325,7 +339,7 @@ declare class ConnectionManagerSingleton {
325
339
  * @param channel - The AMQP channel to use for topology setup
326
340
  * @param contract - The contract definition containing the topology specification
327
341
  * @throws {AggregateError} If any exchanges, queues, or bindings fail to be created
328
- * @throws {Error} If a queue references a dead letter exchange not declared in the contract
342
+ * @throws {TechnicalError} If a queue references a dead letter exchange not declared in the contract
329
343
  *
330
344
  * @example
331
345
  * ```typescript
@@ -345,17 +359,15 @@ declare const MessagingSemanticConventions: {
345
359
  readonly MESSAGING_DESTINATION: "messaging.destination.name";
346
360
  readonly MESSAGING_DESTINATION_KIND: "messaging.destination.kind";
347
361
  readonly MESSAGING_OPERATION: "messaging.operation";
348
- readonly MESSAGING_MESSAGE_ID: "messaging.message.id";
349
- readonly MESSAGING_MESSAGE_PAYLOAD_SIZE: "messaging.message.body.size";
350
- readonly MESSAGING_MESSAGE_CONVERSATION_ID: "messaging.message.conversation_id";
351
362
  readonly MESSAGING_RABBITMQ_ROUTING_KEY: "messaging.rabbitmq.destination.routing_key";
352
363
  readonly MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG: "messaging.rabbitmq.message.delivery_tag";
364
+ readonly AMQP_PUBLISHER_NAME: "amqp.publisher.name";
365
+ readonly AMQP_CONSUMER_NAME: "amqp.consumer.name";
353
366
  readonly ERROR_TYPE: "error.type";
354
367
  readonly MESSAGING_SYSTEM_RABBITMQ: "rabbitmq";
355
368
  readonly MESSAGING_DESTINATION_KIND_EXCHANGE: "exchange";
356
369
  readonly MESSAGING_DESTINATION_KIND_QUEUE: "queue";
357
370
  readonly MESSAGING_OPERATION_PUBLISH: "publish";
358
- readonly MESSAGING_OPERATION_RECEIVE: "receive";
359
371
  readonly MESSAGING_OPERATION_PROCESS: "process";
360
372
  };
361
373
  /**
@@ -426,5 +438,5 @@ declare function recordConsumeMetric(provider: TelemetryProvider, queueName: str
426
438
  */
427
439
  declare function _resetTelemetryCacheForTesting(): void;
428
440
  //#endregion
429
- export { AmqpClient, type AmqpClientOptions, ConnectionManagerSingleton, type ConsumeCallback, type Logger, type LoggerContext, MessagingSemanticConventions, TechnicalError, type TelemetryProvider, _resetTelemetryCacheForTesting, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordConsumeMetric, recordPublishMetric, setupAmqpTopology, startConsumeSpan, startPublishSpan };
441
+ export { AmqpClient, type AmqpClientOptions, ConnectionManagerSingleton, type ConsumeCallback, type Logger, type LoggerContext, MessageValidationError, MessagingSemanticConventions, TechnicalError, type TelemetryProvider, _resetTelemetryCacheForTesting, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordConsumeMetric, recordPublishMetric, setupAmqpTopology, startConsumeSpan, startPublishSpan };
430
442
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/logger.ts","../src/errors.ts","../src/amqp-client.ts","../src/connection-manager.ts","../src/setup.ts","../src/telemetry.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/logger.ts","../src/errors.ts","../src/amqp-client.ts","../src/connection-manager.ts","../src/setup.ts","../src/telemetry.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -71,6 +71,20 @@ declare class TechnicalError extends Error {
71
71
  readonly cause?: unknown | undefined;
72
72
  constructor(message: string, cause?: unknown | undefined);
73
73
  }
74
+ /**
75
+ * Error thrown when message validation fails (payload or headers).
76
+ *
77
+ * Used by both the client (publish-time payload validation) and the worker
78
+ * (consume-time payload and headers validation).
79
+ *
80
+ * @param source - The name of the publisher or consumer that triggered the validation
81
+ * @param issues - The validation issues from the Standard Schema validation
82
+ */
83
+ declare class MessageValidationError extends Error {
84
+ readonly source: string;
85
+ readonly issues: unknown;
86
+ constructor(source: string, issues: unknown);
87
+ }
74
88
  //#endregion
75
89
  //#region src/amqp-client.d.ts
76
90
  /**
@@ -325,7 +339,7 @@ declare class ConnectionManagerSingleton {
325
339
  * @param channel - The AMQP channel to use for topology setup
326
340
  * @param contract - The contract definition containing the topology specification
327
341
  * @throws {AggregateError} If any exchanges, queues, or bindings fail to be created
328
- * @throws {Error} If a queue references a dead letter exchange not declared in the contract
342
+ * @throws {TechnicalError} If a queue references a dead letter exchange not declared in the contract
329
343
  *
330
344
  * @example
331
345
  * ```typescript
@@ -345,17 +359,15 @@ declare const MessagingSemanticConventions: {
345
359
  readonly MESSAGING_DESTINATION: "messaging.destination.name";
346
360
  readonly MESSAGING_DESTINATION_KIND: "messaging.destination.kind";
347
361
  readonly MESSAGING_OPERATION: "messaging.operation";
348
- readonly MESSAGING_MESSAGE_ID: "messaging.message.id";
349
- readonly MESSAGING_MESSAGE_PAYLOAD_SIZE: "messaging.message.body.size";
350
- readonly MESSAGING_MESSAGE_CONVERSATION_ID: "messaging.message.conversation_id";
351
362
  readonly MESSAGING_RABBITMQ_ROUTING_KEY: "messaging.rabbitmq.destination.routing_key";
352
363
  readonly MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG: "messaging.rabbitmq.message.delivery_tag";
364
+ readonly AMQP_PUBLISHER_NAME: "amqp.publisher.name";
365
+ readonly AMQP_CONSUMER_NAME: "amqp.consumer.name";
353
366
  readonly ERROR_TYPE: "error.type";
354
367
  readonly MESSAGING_SYSTEM_RABBITMQ: "rabbitmq";
355
368
  readonly MESSAGING_DESTINATION_KIND_EXCHANGE: "exchange";
356
369
  readonly MESSAGING_DESTINATION_KIND_QUEUE: "queue";
357
370
  readonly MESSAGING_OPERATION_PUBLISH: "publish";
358
- readonly MESSAGING_OPERATION_RECEIVE: "receive";
359
371
  readonly MESSAGING_OPERATION_PROCESS: "process";
360
372
  };
361
373
  /**
@@ -426,5 +438,5 @@ declare function recordConsumeMetric(provider: TelemetryProvider, queueName: str
426
438
  */
427
439
  declare function _resetTelemetryCacheForTesting(): void;
428
440
  //#endregion
429
- export { AmqpClient, type AmqpClientOptions, ConnectionManagerSingleton, type ConsumeCallback, type Logger, type LoggerContext, MessagingSemanticConventions, TechnicalError, type TelemetryProvider, _resetTelemetryCacheForTesting, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordConsumeMetric, recordPublishMetric, setupAmqpTopology, startConsumeSpan, startPublishSpan };
441
+ export { AmqpClient, type AmqpClientOptions, ConnectionManagerSingleton, type ConsumeCallback, type Logger, type LoggerContext, MessageValidationError, MessagingSemanticConventions, TechnicalError, type TelemetryProvider, _resetTelemetryCacheForTesting, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordConsumeMetric, recordPublishMetric, setupAmqpTopology, startConsumeSpan, startPublishSpan };
430
442
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/logger.ts","../src/errors.ts","../src/amqp-client.ts","../src/connection-manager.ts","../src/setup.ts","../src/telemetry.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/logger.ts","../src/errors.ts","../src/amqp-client.ts","../src/connection-manager.ts","../src/setup.ts","../src/telemetry.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -149,6 +149,25 @@ var TechnicalError = class extends Error {
149
149
  if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
150
150
  }
151
151
  };
152
+ /**
153
+ * Error thrown when message validation fails (payload or headers).
154
+ *
155
+ * Used by both the client (publish-time payload validation) and the worker
156
+ * (consume-time payload and headers validation).
157
+ *
158
+ * @param source - The name of the publisher or consumer that triggered the validation
159
+ * @param issues - The validation issues from the Standard Schema validation
160
+ */
161
+ var MessageValidationError = class extends Error {
162
+ constructor(source, issues) {
163
+ super(`Message validation failed for "${source}"`);
164
+ this.source = source;
165
+ this.issues = issues;
166
+ this.name = "MessageValidationError";
167
+ const ErrorConstructor = Error;
168
+ if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
169
+ }
170
+ };
152
171
 
153
172
  //#endregion
154
173
  //#region src/setup.ts
@@ -164,7 +183,7 @@ var TechnicalError = class extends Error {
164
183
  * @param channel - The AMQP channel to use for topology setup
165
184
  * @param contract - The contract definition containing the topology specification
166
185
  * @throws {AggregateError} If any exchanges, queues, or bindings fail to be created
167
- * @throws {Error} If a queue references a dead letter exchange not declared in the contract
186
+ * @throws {TechnicalError} If a queue references a dead letter exchange not declared in the contract
168
187
  *
169
188
  * @example
170
189
  * ```typescript
@@ -184,7 +203,7 @@ async function setupAmqpTopology(channel, contract) {
184
203
  const queue = extractQueue(queueEntry);
185
204
  if (queue.deadLetter) {
186
205
  const dlxName = queue.deadLetter.exchange.name;
187
- if (!Object.values(contract.exchanges ?? {}).some((exchange) => exchange.name === dlxName)) throw new Error(`Queue "${queue.name}" references dead letter exchange "${dlxName}" which is not declared in the contract. Add the exchange to contract.exchanges to ensure it is created before the queue.`);
206
+ if (!Object.values(contract.exchanges ?? {}).some((exchange) => exchange.name === dlxName)) throw new TechnicalError(`Queue "${queue.name}" references dead letter exchange "${dlxName}" which is not declared in the contract. Add the exchange to contract.exchanges to ensure it is created before the queue.`);
188
207
  }
189
208
  }
190
209
  const queueErrors = (await Promise.allSettled(Object.values(contract.queues ?? {}).map((queueEntry) => {
@@ -221,6 +240,20 @@ async function setupAmqpTopology(channel, contract) {
221
240
  //#endregion
222
241
  //#region src/amqp-client.ts
223
242
  /**
243
+ * Invoke a SetupFunc, handling both callback-based and promise-based signatures.
244
+ * Uses Function.length to distinguish (same approach as promise-breaker).
245
+ * @internal
246
+ */
247
+ function callSetupFunc(setup, channel) {
248
+ if (setup.length >= 2) return new Promise((resolve, reject) => {
249
+ setup(channel, (error) => {
250
+ if (error) reject(error);
251
+ else resolve();
252
+ });
253
+ });
254
+ return setup(channel);
255
+ }
256
+ /**
224
257
  * AMQP client that manages connections and channels with automatic topology setup.
225
258
  *
226
259
  * This class handles:
@@ -278,13 +311,7 @@ var AmqpClient = class {
278
311
  };
279
312
  if (userSetup) channelOpts.setup = async (channel) => {
280
313
  await defaultSetup(channel);
281
- if (userSetup.length === 2) await new Promise((resolve, reject) => {
282
- userSetup(channel, (error) => {
283
- if (error) reject(error);
284
- else resolve();
285
- });
286
- });
287
- else await userSetup(channel);
314
+ await callSetupFunc(userSetup, channel);
288
315
  };
289
316
  this.channelWrapper = this.connection.createChannel(channelOpts);
290
317
  }
@@ -425,17 +452,15 @@ const MessagingSemanticConventions = {
425
452
  MESSAGING_DESTINATION: "messaging.destination.name",
426
453
  MESSAGING_DESTINATION_KIND: "messaging.destination.kind",
427
454
  MESSAGING_OPERATION: "messaging.operation",
428
- MESSAGING_MESSAGE_ID: "messaging.message.id",
429
- MESSAGING_MESSAGE_PAYLOAD_SIZE: "messaging.message.body.size",
430
- MESSAGING_MESSAGE_CONVERSATION_ID: "messaging.message.conversation_id",
431
455
  MESSAGING_RABBITMQ_ROUTING_KEY: "messaging.rabbitmq.destination.routing_key",
432
456
  MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG: "messaging.rabbitmq.message.delivery_tag",
457
+ AMQP_PUBLISHER_NAME: "amqp.publisher.name",
458
+ AMQP_CONSUMER_NAME: "amqp.consumer.name",
433
459
  ERROR_TYPE: "error.type",
434
460
  MESSAGING_SYSTEM_RABBITMQ: "rabbitmq",
435
461
  MESSAGING_DESTINATION_KIND_EXCHANGE: "exchange",
436
462
  MESSAGING_DESTINATION_KIND_QUEUE: "queue",
437
463
  MESSAGING_OPERATION_PUBLISH: "publish",
438
- MESSAGING_OPERATION_RECEIVE: "receive",
439
464
  MESSAGING_OPERATION_PROCESS: "process"
440
465
  };
441
466
  /**
@@ -557,7 +582,7 @@ function startConsumeSpan(provider, queueName, consumerName, attributes) {
557
582
  [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,
558
583
  [MessagingSemanticConventions.MESSAGING_DESTINATION_KIND]: MessagingSemanticConventions.MESSAGING_DESTINATION_KIND_QUEUE,
559
584
  [MessagingSemanticConventions.MESSAGING_OPERATION]: MessagingSemanticConventions.MESSAGING_OPERATION_PROCESS,
560
- "amqp.consumer.name": consumerName,
585
+ [MessagingSemanticConventions.AMQP_CONSUMER_NAME]: consumerName,
561
586
  ...attributes
562
587
  }
563
588
  });
@@ -611,7 +636,7 @@ function recordConsumeMetric(provider, queueName, consumerName, success, duratio
611
636
  const attributes = {
612
637
  [MessagingSemanticConventions.MESSAGING_SYSTEM]: MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,
613
638
  [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,
614
- "amqp.consumer.name": consumerName,
639
+ [MessagingSemanticConventions.AMQP_CONSUMER_NAME]: consumerName,
615
640
  success
616
641
  };
617
642
  consumeCounter?.add(1, attributes);
@@ -632,5 +657,5 @@ function _resetTelemetryCacheForTesting() {
632
657
  }
633
658
 
634
659
  //#endregion
635
- export { AmqpClient, ConnectionManagerSingleton, MessagingSemanticConventions, TechnicalError, _resetTelemetryCacheForTesting, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordConsumeMetric, recordPublishMetric, setupAmqpTopology, startConsumeSpan, startPublishSpan };
660
+ export { AmqpClient, ConnectionManagerSingleton, MessageValidationError, MessagingSemanticConventions, TechnicalError, _resetTelemetryCacheForTesting, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordConsumeMetric, recordPublishMetric, setupAmqpTopology, startConsumeSpan, startPublishSpan };
636
661
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/connection-manager.ts","../src/errors.ts","../src/setup.ts","../src/amqp-client.ts","../src/telemetry.ts"],"sourcesContent":["import amqp, {\n AmqpConnectionManager,\n AmqpConnectionManagerOptions,\n ConnectionUrl,\n} from \"amqp-connection-manager\";\n\n/**\n * Connection manager singleton for sharing AMQP connections across clients.\n *\n * This singleton implements connection pooling to avoid creating multiple connections\n * to the same broker, which is a RabbitMQ best practice. Connections are identified\n * by their URLs and connection options, and reference counting ensures connections\n * are only closed when all clients have released them.\n *\n * @example\n * ```typescript\n * const manager = ConnectionManagerSingleton.getInstance();\n * const connection = manager.getConnection(['amqp://localhost']);\n * // ... use connection ...\n * await manager.releaseConnection(['amqp://localhost']);\n * ```\n */\nexport class ConnectionManagerSingleton {\n private static instance: ConnectionManagerSingleton;\n private connections: Map<string, AmqpConnectionManager> = new Map();\n private refCounts: Map<string, number> = new Map();\n\n private constructor() {}\n\n /**\n * Get the singleton instance of the connection manager.\n *\n * @returns The singleton instance\n */\n static getInstance(): ConnectionManagerSingleton {\n if (!ConnectionManagerSingleton.instance) {\n ConnectionManagerSingleton.instance = new ConnectionManagerSingleton();\n }\n return ConnectionManagerSingleton.instance;\n }\n\n /**\n * Get or create a connection for the given URLs and options.\n *\n * If a connection already exists with the same URLs and options, it is reused\n * and its reference count is incremented. Otherwise, a new connection is created.\n *\n * @param urls - AMQP broker URL(s)\n * @param connectionOptions - Optional connection configuration\n * @returns The AMQP connection manager instance\n */\n getConnection(\n urls: ConnectionUrl[],\n connectionOptions?: AmqpConnectionManagerOptions,\n ): AmqpConnectionManager {\n // Create a key based on URLs and connection options\n const key = this.createConnectionKey(urls, connectionOptions);\n\n if (!this.connections.has(key)) {\n const connection = amqp.connect(urls, connectionOptions);\n this.connections.set(key, connection);\n this.refCounts.set(key, 0);\n }\n\n // Increment reference count\n this.refCounts.set(key, (this.refCounts.get(key) ?? 0) + 1);\n\n return this.connections.get(key)!;\n }\n\n /**\n * Release a connection reference.\n *\n * Decrements the reference count for the connection. If the count reaches zero,\n * the connection is closed and removed from the pool.\n *\n * @param urls - AMQP broker URL(s) used to identify the connection\n * @param connectionOptions - Optional connection configuration used to identify the connection\n * @returns A promise that resolves when the connection is released (and closed if necessary)\n */\n async releaseConnection(\n urls: ConnectionUrl[],\n connectionOptions?: AmqpConnectionManagerOptions,\n ): Promise<void> {\n const key = this.createConnectionKey(urls, connectionOptions);\n const refCount = this.refCounts.get(key) ?? 0;\n\n if (refCount <= 1) {\n // Last reference - close and remove connection\n const connection = this.connections.get(key);\n if (connection) {\n await connection.close();\n this.connections.delete(key);\n this.refCounts.delete(key);\n }\n } else {\n // Decrement reference count\n this.refCounts.set(key, refCount - 1);\n }\n }\n\n /**\n * Create a unique key for a connection based on URLs and options.\n *\n * The key is deterministic: same URLs and options always produce the same key,\n * enabling connection reuse.\n *\n * @param urls - AMQP broker URL(s)\n * @param connectionOptions - Optional connection configuration\n * @returns A unique string key identifying the connection\n */\n private createConnectionKey(\n urls: ConnectionUrl[],\n connectionOptions?: AmqpConnectionManagerOptions,\n ): string {\n // Create a deterministic key from URLs and options\n // Use JSON.stringify for URLs to avoid ambiguity (e.g., ['a,b'] vs ['a', 'b'])\n const urlsStr = JSON.stringify(urls);\n // Sort object keys for deterministic serialization of connection options\n const optsStr = connectionOptions ? this.serializeOptions(connectionOptions) : \"\";\n return `${urlsStr}::${optsStr}`;\n }\n\n /**\n * Serialize connection options to a deterministic string.\n *\n * @param options - Connection options to serialize\n * @returns A JSON string with sorted keys for deterministic comparison\n */\n private serializeOptions(options: AmqpConnectionManagerOptions): string {\n // Create a deterministic string representation by deeply sorting all object keys\n const sorted = this.deepSort(options);\n return JSON.stringify(sorted);\n }\n\n /**\n * Deep sort an object's keys for deterministic serialization.\n *\n * @param value - The value to deep sort (can be object, array, or primitive)\n * @returns The value with all object keys sorted alphabetically\n */\n private deepSort(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((item) => this.deepSort(item));\n }\n\n if (value !== null && typeof value === \"object\") {\n const obj = value as Record<string, unknown>;\n const sortedKeys = Object.keys(obj).sort();\n const result: Record<string, unknown> = {};\n\n for (const key of sortedKeys) {\n result[key] = this.deepSort(obj[key]);\n }\n\n return result;\n }\n\n return value;\n }\n\n /**\n * Reset all cached connections (for testing purposes)\n * @internal\n */\n async _resetForTesting(): Promise<void> {\n // Close all connections before clearing\n const closePromises = Array.from(this.connections.values()).map((conn) => conn.close());\n await Promise.all(closePromises);\n this.connections.clear();\n this.refCounts.clear();\n }\n}\n","/**\n * Error for technical/runtime failures that cannot be prevented by TypeScript.\n *\n * This includes AMQP connection failures, channel issues, validation failures,\n * and other runtime errors. This error is shared across core, worker, and client packages.\n */\nexport class TechnicalError extends Error {\n constructor(\n message: string,\n public override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"TechnicalError\";\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","import type { Channel } from \"amqplib\";\nimport type { ContractDefinition } from \"@amqp-contract/contract\";\nimport { extractQueue } from \"@amqp-contract/contract\";\n\n/**\n * Setup AMQP topology (exchanges, queues, and bindings) from a contract definition.\n *\n * This function sets up the complete AMQP topology in the correct order:\n * 1. Assert all exchanges defined in the contract\n * 2. Validate dead letter exchanges are declared before referencing them\n * 3. Assert all queues with their configurations (including dead letter settings)\n * 4. Create all bindings (queue-to-exchange and exchange-to-exchange)\n *\n * @param channel - The AMQP channel to use for topology setup\n * @param contract - The contract definition containing the topology specification\n * @throws {AggregateError} If any exchanges, queues, or bindings fail to be created\n * @throws {Error} If a queue references a dead letter exchange not declared in the contract\n *\n * @example\n * ```typescript\n * const channel = await connection.createChannel();\n * await setupAmqpTopology(channel, contract);\n * ```\n */\nexport async function setupAmqpTopology(\n channel: Channel,\n contract: ContractDefinition,\n): Promise<void> {\n // Setup exchanges\n const exchangeResults = await Promise.allSettled(\n Object.values(contract.exchanges ?? {}).map((exchange) =>\n channel.assertExchange(exchange.name, exchange.type, {\n durable: exchange.durable,\n autoDelete: exchange.autoDelete,\n internal: exchange.internal,\n arguments: exchange.arguments,\n }),\n ),\n );\n const exchangeErrors = exchangeResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (exchangeErrors.length > 0) {\n throw new AggregateError(\n exchangeErrors.map(({ reason }) => reason),\n \"Failed to setup exchanges\",\n );\n }\n\n // Validate dead letter exchanges before setting up queues\n for (const queueEntry of Object.values(contract.queues ?? {})) {\n const queue = extractQueue(queueEntry);\n if (queue.deadLetter) {\n const dlxName = queue.deadLetter.exchange.name;\n const exchangeExists = Object.values(contract.exchanges ?? {}).some(\n (exchange) => exchange.name === dlxName,\n );\n\n if (!exchangeExists) {\n throw new Error(\n `Queue \"${queue.name}\" references dead letter exchange \"${dlxName}\" which is not declared in the contract. ` +\n `Add the exchange to contract.exchanges to ensure it is created before the queue.`,\n );\n }\n }\n }\n\n // Setup queues\n const queueResults = await Promise.allSettled(\n Object.values(contract.queues ?? {}).map((queueEntry) => {\n const queue = extractQueue(queueEntry);\n // Build queue arguments, merging dead letter configuration and queue type\n const queueArguments: Record<string, unknown> = { ...queue.arguments };\n\n // Set queue type\n queueArguments[\"x-queue-type\"] = queue.type;\n\n if (queue.deadLetter) {\n queueArguments[\"x-dead-letter-exchange\"] = queue.deadLetter.exchange.name;\n if (queue.deadLetter.routingKey) {\n queueArguments[\"x-dead-letter-routing-key\"] = queue.deadLetter.routingKey;\n }\n }\n\n // Handle type-specific properties using discriminated union\n if (queue.type === \"quorum\") {\n // Set delivery limit for quorum queues (native retry support)\n if (queue.deliveryLimit !== undefined) {\n queueArguments[\"x-delivery-limit\"] = queue.deliveryLimit;\n }\n\n // Quorum queues are always durable\n return channel.assertQueue(queue.name, {\n durable: true,\n autoDelete: queue.autoDelete,\n arguments: queueArguments,\n });\n }\n\n // Classic queue\n return channel.assertQueue(queue.name, {\n durable: queue.durable,\n exclusive: queue.exclusive,\n autoDelete: queue.autoDelete,\n arguments: queueArguments,\n });\n }),\n );\n const queueErrors = queueResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (queueErrors.length > 0) {\n throw new AggregateError(\n queueErrors.map(({ reason }) => reason),\n \"Failed to setup queues\",\n );\n }\n\n // Setup bindings\n const bindingResults = await Promise.allSettled(\n Object.values(contract.bindings ?? {}).map((binding) => {\n if (binding.type === \"queue\") {\n return channel.bindQueue(\n binding.queue.name,\n binding.exchange.name,\n binding.routingKey ?? \"\",\n binding.arguments,\n );\n }\n\n return channel.bindExchange(\n binding.destination.name,\n binding.source.name,\n binding.routingKey ?? \"\",\n binding.arguments,\n );\n }),\n );\n const bindingErrors = bindingResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (bindingErrors.length > 0) {\n throw new AggregateError(\n bindingErrors.map(({ reason }) => reason),\n \"Failed to setup bindings\",\n );\n }\n}\n","import type {\n AmqpConnectionManager,\n AmqpConnectionManagerOptions,\n ChannelWrapper,\n ConnectionUrl,\n CreateChannelOpts,\n} from \"amqp-connection-manager\";\nimport type { Channel, ConsumeMessage, Options } from \"amqplib\";\nimport { Future, Result } from \"@swan-io/boxed\";\nimport { ConnectionManagerSingleton } from \"./connection-manager.js\";\nimport type { ContractDefinition } from \"@amqp-contract/contract\";\nimport { TechnicalError } from \"./errors.js\";\nimport { setupAmqpTopology } from \"./setup.js\";\n\n/**\n * Options for creating an AMQP client.\n *\n * @property urls - AMQP broker URL(s). Multiple URLs provide failover support.\n * @property connectionOptions - Optional connection configuration (heartbeat, reconnect settings, etc.).\n * @property channelOptions - Optional channel configuration options.\n */\nexport type AmqpClientOptions = {\n urls: ConnectionUrl[];\n connectionOptions?: AmqpConnectionManagerOptions | undefined;\n channelOptions?: Partial<CreateChannelOpts> | undefined;\n};\n\n/**\n * Callback type for consuming messages.\n */\nexport type ConsumeCallback = (msg: ConsumeMessage | null) => void | Promise<void>;\n\n/**\n * AMQP client that manages connections and channels with automatic topology setup.\n *\n * This class handles:\n * - Connection management with automatic reconnection via amqp-connection-manager\n * - Connection pooling and sharing across instances with the same URLs\n * - Automatic AMQP topology setup (exchanges, queues, bindings) from contract\n * - Channel creation with JSON serialization enabled by default\n *\n * All operations return `Future<Result<T, TechnicalError>>` for consistent error handling.\n *\n * @example\n * ```typescript\n * const client = new AmqpClient(contract, {\n * urls: ['amqp://localhost'],\n * connectionOptions: { heartbeatIntervalInSeconds: 30 }\n * });\n *\n * // Wait for connection\n * await client.waitForConnect().resultToPromise();\n *\n * // Publish a message\n * const result = await client.publish('exchange', 'routingKey', { data: 'value' }).resultToPromise();\n *\n * // Close when done\n * await client.close().resultToPromise();\n * ```\n */\nexport class AmqpClient {\n private readonly connection: AmqpConnectionManager;\n private readonly channelWrapper: ChannelWrapper;\n private readonly urls: ConnectionUrl[];\n private readonly connectionOptions?: AmqpConnectionManagerOptions;\n\n /**\n * Create a new AMQP client instance.\n *\n * The client will automatically:\n * - Get or create a shared connection using the singleton pattern\n * - Set up AMQP topology (exchanges, queues, bindings) from the contract\n * - Create a channel with JSON serialization enabled\n *\n * @param contract - The contract definition specifying the AMQP topology\n * @param options - Client configuration options\n */\n constructor(\n private readonly contract: ContractDefinition,\n options: AmqpClientOptions,\n ) {\n // Store for cleanup\n this.urls = options.urls;\n if (options.connectionOptions !== undefined) {\n this.connectionOptions = options.connectionOptions;\n }\n\n // Always use singleton to get/create connection\n const singleton = ConnectionManagerSingleton.getInstance();\n this.connection = singleton.getConnection(options.urls, options.connectionOptions);\n\n // Create default setup function that calls setupAmqpTopology\n const defaultSetup = (channel: Channel) => setupAmqpTopology(channel, this.contract);\n\n // Destructure setup from channelOptions to handle it separately\n const { setup: userSetup, ...otherChannelOptions } = options.channelOptions ?? {};\n\n // Merge user-provided channel options with defaults\n const channelOpts: CreateChannelOpts = {\n json: true,\n setup: defaultSetup,\n ...otherChannelOptions,\n };\n\n // If user provided a custom setup, wrap it to call both\n if (userSetup) {\n channelOpts.setup = async (channel: Channel) => {\n // First run the topology setup\n await defaultSetup(channel);\n // Then run user's setup - check arity to determine if it expects a callback\n if (userSetup.length === 2) {\n // Callback-based setup function\n await new Promise<void>((resolve, reject) => {\n (userSetup as (channel: Channel, callback: (error?: Error) => void) => void)(\n channel,\n (error?: Error) => {\n if (error) reject(error);\n else resolve();\n },\n );\n });\n } else {\n // Promise-based setup function\n await (userSetup as (channel: Channel) => Promise<void>)(channel);\n }\n };\n }\n\n this.channelWrapper = this.connection.createChannel(channelOpts);\n }\n\n /**\n * Get the underlying connection manager\n *\n * This method exposes the AmqpConnectionManager instance that this client uses.\n * The connection is automatically shared across all AmqpClient instances that\n * use the same URLs and connection options.\n *\n * @returns The AmqpConnectionManager instance used by this client\n */\n getConnection(): AmqpConnectionManager {\n return this.connection;\n }\n\n /**\n * Wait for the channel to be connected and ready.\n *\n * @returns A Future that resolves when the channel is connected\n */\n waitForConnect(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.waitForConnect()).mapError(\n (error: unknown) => new TechnicalError(\"Failed to connect to AMQP broker\", error),\n );\n }\n\n /**\n * Publish a message to an exchange.\n *\n * @param exchange - The exchange name\n * @param routingKey - The routing key\n * @param content - The message content (will be JSON serialized if json: true)\n * @param options - Optional publish options\n * @returns A Future with `Result<boolean>` - true if message was sent, false if channel buffer is full\n */\n publish(\n exchange: string,\n routingKey: string,\n content: Buffer | unknown,\n options?: Options.Publish,\n ): Future<Result<boolean, TechnicalError>> {\n return Future.fromPromise(\n this.channelWrapper.publish(exchange, routingKey, content, options),\n ).mapError((error: unknown) => new TechnicalError(\"Failed to publish message\", error));\n }\n\n /**\n * Start consuming messages from a queue.\n *\n * @param queue - The queue name\n * @param callback - The callback to invoke for each message\n * @param options - Optional consume options\n * @returns A Future with `Result<string>` - the consumer tag\n */\n consume(\n queue: string,\n callback: ConsumeCallback,\n options?: Options.Consume,\n ): Future<Result<string, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.consume(queue, callback, options))\n .mapError((error: unknown) => new TechnicalError(\"Failed to start consuming messages\", error))\n .mapOk((reply: { consumerTag: string }) => reply.consumerTag);\n }\n\n /**\n * Cancel a consumer by its consumer tag.\n *\n * @param consumerTag - The consumer tag to cancel\n * @returns A Future that resolves when the consumer is cancelled\n */\n cancel(consumerTag: string): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.cancel(consumerTag))\n .mapError((error: unknown) => new TechnicalError(\"Failed to cancel consumer\", error))\n .mapOk(() => undefined);\n }\n\n /**\n * Acknowledge a message.\n *\n * @param msg - The message to acknowledge\n * @param allUpTo - If true, acknowledge all messages up to and including this one\n */\n ack(msg: ConsumeMessage, allUpTo = false): void {\n this.channelWrapper.ack(msg, allUpTo);\n }\n\n /**\n * Negative acknowledge a message.\n *\n * @param msg - The message to nack\n * @param allUpTo - If true, nack all messages up to and including this one\n * @param requeue - If true, requeue the message(s)\n */\n nack(msg: ConsumeMessage, allUpTo = false, requeue = true): void {\n this.channelWrapper.nack(msg, allUpTo, requeue);\n }\n\n /**\n * Add a setup function to be called when the channel is created or reconnected.\n *\n * This is useful for setting up channel-level configuration like prefetch.\n *\n * @param setup - The setup function to add\n */\n addSetup(setup: (channel: Channel) => void | Promise<void>): void {\n this.channelWrapper.addSetup(setup);\n }\n\n /**\n * Register an event listener on the channel wrapper.\n *\n * Available events:\n * - 'connect': Emitted when the channel is (re)connected\n * - 'close': Emitted when the channel is closed\n * - 'error': Emitted when an error occurs\n *\n * @param event - The event name\n * @param listener - The event listener\n */\n on(event: string, listener: (...args: unknown[]) => void): void {\n this.channelWrapper.on(event, listener);\n }\n\n /**\n * Close the channel and release the connection reference.\n *\n * This will:\n * - Close the channel wrapper\n * - Decrease the reference count on the shared connection\n * - Close the connection if this was the last client using it\n *\n * @returns A Future that resolves when the channel and connection are closed\n */\n close(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.close())\n .mapError((error: unknown) => new TechnicalError(\"Failed to close channel\", error))\n .flatMapOk(() =>\n Future.fromPromise(\n ConnectionManagerSingleton.getInstance().releaseConnection(\n this.urls,\n this.connectionOptions,\n ),\n ).mapError((error: unknown) => new TechnicalError(\"Failed to release connection\", error)),\n )\n .mapOk(() => undefined);\n }\n\n /**\n * Reset connection singleton cache (for testing only)\n * @internal\n */\n static async _resetConnectionCacheForTesting(): Promise<void> {\n await ConnectionManagerSingleton.getInstance()._resetForTesting();\n }\n}\n","import {\n type Attributes,\n type Counter,\n type Histogram,\n type Span,\n type Tracer,\n} from \"@opentelemetry/api\";\n\n/**\n * SpanKind values from OpenTelemetry.\n * Defined as constants to avoid runtime dependency when types are used.\n * @see https://opentelemetry.io/docs/specs/otel/trace/api/#spankind\n */\nconst SpanKind = {\n /** Producer span represents a message producer */\n PRODUCER: 3,\n /** Consumer span represents a message consumer */\n CONSUMER: 4,\n} as const;\n\n/**\n * Semantic conventions for AMQP messaging following OpenTelemetry standards.\n * @see https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/\n */\nexport const MessagingSemanticConventions = {\n // Messaging attributes\n MESSAGING_SYSTEM: \"messaging.system\",\n MESSAGING_DESTINATION: \"messaging.destination.name\",\n MESSAGING_DESTINATION_KIND: \"messaging.destination.kind\",\n MESSAGING_OPERATION: \"messaging.operation\",\n MESSAGING_MESSAGE_ID: \"messaging.message.id\",\n MESSAGING_MESSAGE_PAYLOAD_SIZE: \"messaging.message.body.size\",\n MESSAGING_MESSAGE_CONVERSATION_ID: \"messaging.message.conversation_id\",\n\n // AMQP specific attributes\n MESSAGING_RABBITMQ_ROUTING_KEY: \"messaging.rabbitmq.destination.routing_key\",\n MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG: \"messaging.rabbitmq.message.delivery_tag\",\n\n // Error attributes\n ERROR_TYPE: \"error.type\",\n\n // Values\n MESSAGING_SYSTEM_RABBITMQ: \"rabbitmq\",\n MESSAGING_DESTINATION_KIND_EXCHANGE: \"exchange\",\n MESSAGING_DESTINATION_KIND_QUEUE: \"queue\",\n MESSAGING_OPERATION_PUBLISH: \"publish\",\n MESSAGING_OPERATION_RECEIVE: \"receive\",\n MESSAGING_OPERATION_PROCESS: \"process\",\n} as const;\n\n/**\n * Telemetry provider for AMQP operations.\n * Uses lazy loading to gracefully handle cases where OpenTelemetry is not installed.\n */\nexport type TelemetryProvider = {\n /**\n * Get a tracer instance for creating spans.\n * Returns undefined if OpenTelemetry is not available.\n */\n getTracer: () => Tracer | undefined;\n\n /**\n * Get a counter for messages published.\n * Returns undefined if OpenTelemetry is not available.\n */\n getPublishCounter: () => Counter | undefined;\n\n /**\n * Get a counter for messages consumed.\n * Returns undefined if OpenTelemetry is not available.\n */\n getConsumeCounter: () => Counter | undefined;\n\n /**\n * Get a histogram for publish latency.\n * Returns undefined if OpenTelemetry is not available.\n */\n getPublishLatencyHistogram: () => Histogram | undefined;\n\n /**\n * Get a histogram for consume/process latency.\n * Returns undefined if OpenTelemetry is not available.\n */\n getConsumeLatencyHistogram: () => Histogram | undefined;\n};\n\n/**\n * Instrumentation scope name for amqp-contract.\n */\nconst INSTRUMENTATION_SCOPE_NAME = \"@amqp-contract\";\nconst INSTRUMENTATION_SCOPE_VERSION = \"0.1.0\";\n\n// Cache for OpenTelemetry API module and instruments\nlet otelApi: typeof import(\"@opentelemetry/api\") | null | undefined;\nlet cachedTracer: Tracer | undefined;\nlet cachedPublishCounter: Counter | undefined;\nlet cachedConsumeCounter: Counter | undefined;\nlet cachedPublishLatencyHistogram: Histogram | undefined;\nlet cachedConsumeLatencyHistogram: Histogram | undefined;\n\n/**\n * Try to load the OpenTelemetry API module.\n * Returns null if the module is not available.\n */\nfunction tryLoadOpenTelemetryApi(): typeof import(\"@opentelemetry/api\") | null {\n if (otelApi === undefined) {\n try {\n // Dynamic import using require to avoid bundler issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n otelApi = require(\"@opentelemetry/api\") as typeof import(\"@opentelemetry/api\");\n } catch {\n otelApi = null;\n }\n }\n return otelApi;\n}\n\n/**\n * Get or create a tracer instance.\n */\nfunction getTracer(): Tracer | undefined {\n if (cachedTracer !== undefined) {\n return cachedTracer;\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (!api) {\n return undefined;\n }\n\n cachedTracer = api.trace.getTracer(INSTRUMENTATION_SCOPE_NAME, INSTRUMENTATION_SCOPE_VERSION);\n return cachedTracer;\n}\n\n/**\n * Get or create a meter and its instruments.\n */\nfunction getMeterInstruments(): {\n publishCounter: Counter | undefined;\n consumeCounter: Counter | undefined;\n publishLatencyHistogram: Histogram | undefined;\n consumeLatencyHistogram: Histogram | undefined;\n} {\n if (cachedPublishCounter !== undefined) {\n return {\n publishCounter: cachedPublishCounter,\n consumeCounter: cachedConsumeCounter,\n publishLatencyHistogram: cachedPublishLatencyHistogram,\n consumeLatencyHistogram: cachedConsumeLatencyHistogram,\n };\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (!api) {\n return {\n publishCounter: undefined,\n consumeCounter: undefined,\n publishLatencyHistogram: undefined,\n consumeLatencyHistogram: undefined,\n };\n }\n\n const meter = api.metrics.getMeter(INSTRUMENTATION_SCOPE_NAME, INSTRUMENTATION_SCOPE_VERSION);\n\n cachedPublishCounter = meter.createCounter(\"amqp.client.messages.published\", {\n description: \"Number of messages published to AMQP broker\",\n unit: \"{message}\",\n });\n\n cachedConsumeCounter = meter.createCounter(\"amqp.worker.messages.consumed\", {\n description: \"Number of messages consumed from AMQP broker\",\n unit: \"{message}\",\n });\n\n cachedPublishLatencyHistogram = meter.createHistogram(\"amqp.client.publish.duration\", {\n description: \"Duration of message publish operations\",\n unit: \"ms\",\n });\n\n cachedConsumeLatencyHistogram = meter.createHistogram(\"amqp.worker.process.duration\", {\n description: \"Duration of message processing operations\",\n unit: \"ms\",\n });\n\n return {\n publishCounter: cachedPublishCounter,\n consumeCounter: cachedConsumeCounter,\n publishLatencyHistogram: cachedPublishLatencyHistogram,\n consumeLatencyHistogram: cachedConsumeLatencyHistogram,\n };\n}\n\n/**\n * Default telemetry provider that uses OpenTelemetry API if available.\n */\nexport const defaultTelemetryProvider: TelemetryProvider = {\n getTracer,\n getPublishCounter: () => getMeterInstruments().publishCounter,\n getConsumeCounter: () => getMeterInstruments().consumeCounter,\n getPublishLatencyHistogram: () => getMeterInstruments().publishLatencyHistogram,\n getConsumeLatencyHistogram: () => getMeterInstruments().consumeLatencyHistogram,\n};\n\n/**\n * Create a span for a publish operation.\n * Returns undefined if OpenTelemetry is not available.\n */\nexport function startPublishSpan(\n provider: TelemetryProvider,\n exchangeName: string,\n routingKey: string | undefined,\n attributes?: Attributes,\n): Span | undefined {\n const tracer = provider.getTracer();\n if (!tracer) {\n return undefined;\n }\n\n const spanName = `${exchangeName} publish`;\n\n return tracer.startSpan(spanName, {\n kind: SpanKind.PRODUCER,\n attributes: {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: exchangeName,\n [MessagingSemanticConventions.MESSAGING_DESTINATION_KIND]:\n MessagingSemanticConventions.MESSAGING_DESTINATION_KIND_EXCHANGE,\n [MessagingSemanticConventions.MESSAGING_OPERATION]:\n MessagingSemanticConventions.MESSAGING_OPERATION_PUBLISH,\n ...(routingKey\n ? { [MessagingSemanticConventions.MESSAGING_RABBITMQ_ROUTING_KEY]: routingKey }\n : {}),\n ...attributes,\n },\n });\n}\n\n/**\n * Create a span for a consume/process operation.\n * Returns undefined if OpenTelemetry is not available.\n */\nexport function startConsumeSpan(\n provider: TelemetryProvider,\n queueName: string,\n consumerName: string,\n attributes?: Attributes,\n): Span | undefined {\n const tracer = provider.getTracer();\n if (!tracer) {\n return undefined;\n }\n\n const spanName = `${queueName} process`;\n\n return tracer.startSpan(spanName, {\n kind: SpanKind.CONSUMER,\n attributes: {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,\n [MessagingSemanticConventions.MESSAGING_DESTINATION_KIND]:\n MessagingSemanticConventions.MESSAGING_DESTINATION_KIND_QUEUE,\n [MessagingSemanticConventions.MESSAGING_OPERATION]:\n MessagingSemanticConventions.MESSAGING_OPERATION_PROCESS,\n \"amqp.consumer.name\": consumerName,\n ...attributes,\n },\n });\n}\n\n/**\n * End a span with success status.\n */\nexport function endSpanSuccess(span: Span | undefined): void {\n if (!span) {\n return;\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (api) {\n span.setStatus({ code: api.SpanStatusCode.OK });\n }\n span.end();\n}\n\n/**\n * End a span with error status.\n */\nexport function endSpanError(span: Span | undefined, error: Error): void {\n if (!span) {\n return;\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (api) {\n span.setStatus({ code: api.SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.setAttribute(MessagingSemanticConventions.ERROR_TYPE, error.name);\n }\n span.end();\n}\n\n/**\n * Record a publish metric.\n */\nexport function recordPublishMetric(\n provider: TelemetryProvider,\n exchangeName: string,\n routingKey: string | undefined,\n success: boolean,\n durationMs: number,\n): void {\n const publishCounter = provider.getPublishCounter();\n const publishLatencyHistogram = provider.getPublishLatencyHistogram();\n\n const attributes: Attributes = {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: exchangeName,\n ...(routingKey\n ? { [MessagingSemanticConventions.MESSAGING_RABBITMQ_ROUTING_KEY]: routingKey }\n : {}),\n success: success,\n };\n\n publishCounter?.add(1, attributes);\n publishLatencyHistogram?.record(durationMs, attributes);\n}\n\n/**\n * Record a consume metric.\n */\nexport function recordConsumeMetric(\n provider: TelemetryProvider,\n queueName: string,\n consumerName: string,\n success: boolean,\n durationMs: number,\n): void {\n const consumeCounter = provider.getConsumeCounter();\n const consumeLatencyHistogram = provider.getConsumeLatencyHistogram();\n\n const attributes: Attributes = {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,\n \"amqp.consumer.name\": consumerName,\n success: success,\n };\n\n consumeCounter?.add(1, attributes);\n consumeLatencyHistogram?.record(durationMs, attributes);\n}\n\n/**\n * Reset the cached OpenTelemetry API module and instruments.\n * For testing purposes only.\n * @internal\n */\nexport function _resetTelemetryCacheForTesting(): void {\n otelApi = undefined;\n cachedTracer = undefined;\n cachedPublishCounter = undefined;\n cachedConsumeCounter = undefined;\n cachedPublishLatencyHistogram = undefined;\n cachedConsumeLatencyHistogram = undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/connection-manager.ts","../src/errors.ts","../src/setup.ts","../src/amqp-client.ts","../src/telemetry.ts"],"sourcesContent":["import amqp, {\n AmqpConnectionManager,\n AmqpConnectionManagerOptions,\n ConnectionUrl,\n} from \"amqp-connection-manager\";\n\n/**\n * Connection manager singleton for sharing AMQP connections across clients.\n *\n * This singleton implements connection pooling to avoid creating multiple connections\n * to the same broker, which is a RabbitMQ best practice. Connections are identified\n * by their URLs and connection options, and reference counting ensures connections\n * are only closed when all clients have released them.\n *\n * @example\n * ```typescript\n * const manager = ConnectionManagerSingleton.getInstance();\n * const connection = manager.getConnection(['amqp://localhost']);\n * // ... use connection ...\n * await manager.releaseConnection(['amqp://localhost']);\n * ```\n */\nexport class ConnectionManagerSingleton {\n private static instance: ConnectionManagerSingleton;\n private connections: Map<string, AmqpConnectionManager> = new Map();\n private refCounts: Map<string, number> = new Map();\n\n private constructor() {}\n\n /**\n * Get the singleton instance of the connection manager.\n *\n * @returns The singleton instance\n */\n static getInstance(): ConnectionManagerSingleton {\n if (!ConnectionManagerSingleton.instance) {\n ConnectionManagerSingleton.instance = new ConnectionManagerSingleton();\n }\n return ConnectionManagerSingleton.instance;\n }\n\n /**\n * Get or create a connection for the given URLs and options.\n *\n * If a connection already exists with the same URLs and options, it is reused\n * and its reference count is incremented. Otherwise, a new connection is created.\n *\n * @param urls - AMQP broker URL(s)\n * @param connectionOptions - Optional connection configuration\n * @returns The AMQP connection manager instance\n */\n getConnection(\n urls: ConnectionUrl[],\n connectionOptions?: AmqpConnectionManagerOptions,\n ): AmqpConnectionManager {\n // Create a key based on URLs and connection options\n const key = this.createConnectionKey(urls, connectionOptions);\n\n if (!this.connections.has(key)) {\n const connection = amqp.connect(urls, connectionOptions);\n this.connections.set(key, connection);\n this.refCounts.set(key, 0);\n }\n\n // Increment reference count\n this.refCounts.set(key, (this.refCounts.get(key) ?? 0) + 1);\n\n return this.connections.get(key)!;\n }\n\n /**\n * Release a connection reference.\n *\n * Decrements the reference count for the connection. If the count reaches zero,\n * the connection is closed and removed from the pool.\n *\n * @param urls - AMQP broker URL(s) used to identify the connection\n * @param connectionOptions - Optional connection configuration used to identify the connection\n * @returns A promise that resolves when the connection is released (and closed if necessary)\n */\n async releaseConnection(\n urls: ConnectionUrl[],\n connectionOptions?: AmqpConnectionManagerOptions,\n ): Promise<void> {\n const key = this.createConnectionKey(urls, connectionOptions);\n const refCount = this.refCounts.get(key) ?? 0;\n\n if (refCount <= 1) {\n // Last reference - close and remove connection\n const connection = this.connections.get(key);\n if (connection) {\n await connection.close();\n this.connections.delete(key);\n this.refCounts.delete(key);\n }\n } else {\n // Decrement reference count\n this.refCounts.set(key, refCount - 1);\n }\n }\n\n /**\n * Create a unique key for a connection based on URLs and options.\n *\n * The key is deterministic: same URLs and options always produce the same key,\n * enabling connection reuse.\n *\n * @param urls - AMQP broker URL(s)\n * @param connectionOptions - Optional connection configuration\n * @returns A unique string key identifying the connection\n */\n private createConnectionKey(\n urls: ConnectionUrl[],\n connectionOptions?: AmqpConnectionManagerOptions,\n ): string {\n // Create a deterministic key from URLs and options\n // Use JSON.stringify for URLs to avoid ambiguity (e.g., ['a,b'] vs ['a', 'b'])\n const urlsStr = JSON.stringify(urls);\n // Sort object keys for deterministic serialization of connection options\n const optsStr = connectionOptions ? this.serializeOptions(connectionOptions) : \"\";\n return `${urlsStr}::${optsStr}`;\n }\n\n /**\n * Serialize connection options to a deterministic string.\n *\n * @param options - Connection options to serialize\n * @returns A JSON string with sorted keys for deterministic comparison\n */\n private serializeOptions(options: AmqpConnectionManagerOptions): string {\n // Create a deterministic string representation by deeply sorting all object keys\n const sorted = this.deepSort(options);\n return JSON.stringify(sorted);\n }\n\n /**\n * Deep sort an object's keys for deterministic serialization.\n *\n * @param value - The value to deep sort (can be object, array, or primitive)\n * @returns The value with all object keys sorted alphabetically\n */\n private deepSort(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((item) => this.deepSort(item));\n }\n\n if (value !== null && typeof value === \"object\") {\n const obj = value as Record<string, unknown>;\n const sortedKeys = Object.keys(obj).sort();\n const result: Record<string, unknown> = {};\n\n for (const key of sortedKeys) {\n result[key] = this.deepSort(obj[key]);\n }\n\n return result;\n }\n\n return value;\n }\n\n /**\n * Reset all cached connections (for testing purposes)\n * @internal\n */\n async _resetForTesting(): Promise<void> {\n // Close all connections before clearing\n const closePromises = Array.from(this.connections.values()).map((conn) => conn.close());\n await Promise.all(closePromises);\n this.connections.clear();\n this.refCounts.clear();\n }\n}\n","/**\n * Error for technical/runtime failures that cannot be prevented by TypeScript.\n *\n * This includes AMQP connection failures, channel issues, validation failures,\n * and other runtime errors. This error is shared across core, worker, and client packages.\n */\nexport class TechnicalError extends Error {\n constructor(\n message: string,\n public override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"TechnicalError\";\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 thrown when message validation fails (payload or headers).\n *\n * Used by both the client (publish-time payload validation) and the worker\n * (consume-time payload and headers validation).\n *\n * @param source - The name of the publisher or consumer that triggered the validation\n * @param issues - The validation issues from the Standard Schema validation\n */\nexport class MessageValidationError extends Error {\n constructor(\n public readonly source: string,\n public readonly issues: unknown,\n ) {\n super(`Message validation failed for \"${source}\"`);\n this.name = \"MessageValidationError\";\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","import type { Channel } from \"amqplib\";\nimport type { ContractDefinition } from \"@amqp-contract/contract\";\nimport { extractQueue } from \"@amqp-contract/contract\";\nimport { TechnicalError } from \"./errors.js\";\n\n/**\n * Setup AMQP topology (exchanges, queues, and bindings) from a contract definition.\n *\n * This function sets up the complete AMQP topology in the correct order:\n * 1. Assert all exchanges defined in the contract\n * 2. Validate dead letter exchanges are declared before referencing them\n * 3. Assert all queues with their configurations (including dead letter settings)\n * 4. Create all bindings (queue-to-exchange and exchange-to-exchange)\n *\n * @param channel - The AMQP channel to use for topology setup\n * @param contract - The contract definition containing the topology specification\n * @throws {AggregateError} If any exchanges, queues, or bindings fail to be created\n * @throws {TechnicalError} If a queue references a dead letter exchange not declared in the contract\n *\n * @example\n * ```typescript\n * const channel = await connection.createChannel();\n * await setupAmqpTopology(channel, contract);\n * ```\n */\nexport async function setupAmqpTopology(\n channel: Channel,\n contract: ContractDefinition,\n): Promise<void> {\n // Setup exchanges\n const exchangeResults = await Promise.allSettled(\n Object.values(contract.exchanges ?? {}).map((exchange) =>\n channel.assertExchange(exchange.name, exchange.type, {\n durable: exchange.durable,\n autoDelete: exchange.autoDelete,\n internal: exchange.internal,\n arguments: exchange.arguments,\n }),\n ),\n );\n const exchangeErrors = exchangeResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (exchangeErrors.length > 0) {\n throw new AggregateError(\n exchangeErrors.map(({ reason }) => reason),\n \"Failed to setup exchanges\",\n );\n }\n\n // Validate dead letter exchanges before setting up queues\n for (const queueEntry of Object.values(contract.queues ?? {})) {\n const queue = extractQueue(queueEntry);\n if (queue.deadLetter) {\n const dlxName = queue.deadLetter.exchange.name;\n const exchangeExists = Object.values(contract.exchanges ?? {}).some(\n (exchange) => exchange.name === dlxName,\n );\n\n if (!exchangeExists) {\n throw new TechnicalError(\n `Queue \"${queue.name}\" references dead letter exchange \"${dlxName}\" which is not declared in the contract. ` +\n `Add the exchange to contract.exchanges to ensure it is created before the queue.`,\n );\n }\n }\n }\n\n // Setup queues\n const queueResults = await Promise.allSettled(\n Object.values(contract.queues ?? {}).map((queueEntry) => {\n const queue = extractQueue(queueEntry);\n // Build queue arguments, merging dead letter configuration and queue type\n const queueArguments: Record<string, unknown> = { ...queue.arguments };\n\n // Set queue type\n queueArguments[\"x-queue-type\"] = queue.type;\n\n if (queue.deadLetter) {\n queueArguments[\"x-dead-letter-exchange\"] = queue.deadLetter.exchange.name;\n if (queue.deadLetter.routingKey) {\n queueArguments[\"x-dead-letter-routing-key\"] = queue.deadLetter.routingKey;\n }\n }\n\n // Handle type-specific properties using discriminated union\n if (queue.type === \"quorum\") {\n // Set delivery limit for quorum queues (native retry support)\n if (queue.deliveryLimit !== undefined) {\n queueArguments[\"x-delivery-limit\"] = queue.deliveryLimit;\n }\n\n // Quorum queues are always durable\n return channel.assertQueue(queue.name, {\n durable: true,\n autoDelete: queue.autoDelete,\n arguments: queueArguments,\n });\n }\n\n // Classic queue\n return channel.assertQueue(queue.name, {\n durable: queue.durable,\n exclusive: queue.exclusive,\n autoDelete: queue.autoDelete,\n arguments: queueArguments,\n });\n }),\n );\n const queueErrors = queueResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (queueErrors.length > 0) {\n throw new AggregateError(\n queueErrors.map(({ reason }) => reason),\n \"Failed to setup queues\",\n );\n }\n\n // Setup bindings\n const bindingResults = await Promise.allSettled(\n Object.values(contract.bindings ?? {}).map((binding) => {\n if (binding.type === \"queue\") {\n return channel.bindQueue(\n binding.queue.name,\n binding.exchange.name,\n binding.routingKey ?? \"\",\n binding.arguments,\n );\n }\n\n return channel.bindExchange(\n binding.destination.name,\n binding.source.name,\n binding.routingKey ?? \"\",\n binding.arguments,\n );\n }),\n );\n const bindingErrors = bindingResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (bindingErrors.length > 0) {\n throw new AggregateError(\n bindingErrors.map(({ reason }) => reason),\n \"Failed to setup bindings\",\n );\n }\n}\n","import type {\n AmqpConnectionManager,\n AmqpConnectionManagerOptions,\n ChannelWrapper,\n ConnectionUrl,\n CreateChannelOpts,\n} from \"amqp-connection-manager\";\nimport type { Channel, ConsumeMessage, Options } from \"amqplib\";\nimport { Future, Result } from \"@swan-io/boxed\";\nimport { ConnectionManagerSingleton } from \"./connection-manager.js\";\nimport type { ContractDefinition } from \"@amqp-contract/contract\";\nimport { TechnicalError } from \"./errors.js\";\nimport { setupAmqpTopology } from \"./setup.js\";\n\n/**\n * Invoke a SetupFunc, handling both callback-based and promise-based signatures.\n * Uses Function.length to distinguish (same approach as promise-breaker).\n * @internal\n */\nfunction callSetupFunc(\n setup: NonNullable<CreateChannelOpts[\"setup\"]>,\n channel: Channel,\n): Promise<void> {\n if (setup.length >= 2) {\n return new Promise<void>((resolve, reject) => {\n (setup as (channel: Channel, callback: (error?: Error) => void) => void)(\n channel,\n (error?: Error) => {\n if (error) reject(error);\n else resolve();\n },\n );\n });\n }\n return (setup as (channel: Channel) => Promise<void>)(channel);\n}\n\n/**\n * Options for creating an AMQP client.\n *\n * @property urls - AMQP broker URL(s). Multiple URLs provide failover support.\n * @property connectionOptions - Optional connection configuration (heartbeat, reconnect settings, etc.).\n * @property channelOptions - Optional channel configuration options.\n */\nexport type AmqpClientOptions = {\n urls: ConnectionUrl[];\n connectionOptions?: AmqpConnectionManagerOptions | undefined;\n channelOptions?: Partial<CreateChannelOpts> | undefined;\n};\n\n/**\n * Callback type for consuming messages.\n */\nexport type ConsumeCallback = (msg: ConsumeMessage | null) => void | Promise<void>;\n\n/**\n * AMQP client that manages connections and channels with automatic topology setup.\n *\n * This class handles:\n * - Connection management with automatic reconnection via amqp-connection-manager\n * - Connection pooling and sharing across instances with the same URLs\n * - Automatic AMQP topology setup (exchanges, queues, bindings) from contract\n * - Channel creation with JSON serialization enabled by default\n *\n * All operations return `Future<Result<T, TechnicalError>>` for consistent error handling.\n *\n * @example\n * ```typescript\n * const client = new AmqpClient(contract, {\n * urls: ['amqp://localhost'],\n * connectionOptions: { heartbeatIntervalInSeconds: 30 }\n * });\n *\n * // Wait for connection\n * await client.waitForConnect().resultToPromise();\n *\n * // Publish a message\n * const result = await client.publish('exchange', 'routingKey', { data: 'value' }).resultToPromise();\n *\n * // Close when done\n * await client.close().resultToPromise();\n * ```\n */\nexport class AmqpClient {\n private readonly connection: AmqpConnectionManager;\n private readonly channelWrapper: ChannelWrapper;\n private readonly urls: ConnectionUrl[];\n private readonly connectionOptions?: AmqpConnectionManagerOptions;\n\n /**\n * Create a new AMQP client instance.\n *\n * The client will automatically:\n * - Get or create a shared connection using the singleton pattern\n * - Set up AMQP topology (exchanges, queues, bindings) from the contract\n * - Create a channel with JSON serialization enabled\n *\n * @param contract - The contract definition specifying the AMQP topology\n * @param options - Client configuration options\n */\n constructor(\n private readonly contract: ContractDefinition,\n options: AmqpClientOptions,\n ) {\n // Store for cleanup\n this.urls = options.urls;\n if (options.connectionOptions !== undefined) {\n this.connectionOptions = options.connectionOptions;\n }\n\n // Always use singleton to get/create connection\n const singleton = ConnectionManagerSingleton.getInstance();\n this.connection = singleton.getConnection(options.urls, options.connectionOptions);\n\n // Create default setup function that calls setupAmqpTopology\n const defaultSetup = (channel: Channel) => setupAmqpTopology(channel, this.contract);\n\n // Destructure setup from channelOptions to handle it separately\n const { setup: userSetup, ...otherChannelOptions } = options.channelOptions ?? {};\n\n // Merge user-provided channel options with defaults\n const channelOpts: CreateChannelOpts = {\n json: true,\n setup: defaultSetup,\n ...otherChannelOptions,\n };\n\n // If user provided a custom setup, wrap it to call both\n if (userSetup) {\n channelOpts.setup = async (channel: Channel) => {\n await defaultSetup(channel);\n await callSetupFunc(userSetup, channel);\n };\n }\n\n this.channelWrapper = this.connection.createChannel(channelOpts);\n }\n\n /**\n * Get the underlying connection manager\n *\n * This method exposes the AmqpConnectionManager instance that this client uses.\n * The connection is automatically shared across all AmqpClient instances that\n * use the same URLs and connection options.\n *\n * @returns The AmqpConnectionManager instance used by this client\n */\n getConnection(): AmqpConnectionManager {\n return this.connection;\n }\n\n /**\n * Wait for the channel to be connected and ready.\n *\n * @returns A Future that resolves when the channel is connected\n */\n waitForConnect(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.waitForConnect()).mapError(\n (error: unknown) => new TechnicalError(\"Failed to connect to AMQP broker\", error),\n );\n }\n\n /**\n * Publish a message to an exchange.\n *\n * @param exchange - The exchange name\n * @param routingKey - The routing key\n * @param content - The message content (will be JSON serialized if json: true)\n * @param options - Optional publish options\n * @returns A Future with `Result<boolean>` - true if message was sent, false if channel buffer is full\n */\n publish(\n exchange: string,\n routingKey: string,\n content: Buffer | unknown,\n options?: Options.Publish,\n ): Future<Result<boolean, TechnicalError>> {\n return Future.fromPromise(\n this.channelWrapper.publish(exchange, routingKey, content, options),\n ).mapError((error: unknown) => new TechnicalError(\"Failed to publish message\", error));\n }\n\n /**\n * Start consuming messages from a queue.\n *\n * @param queue - The queue name\n * @param callback - The callback to invoke for each message\n * @param options - Optional consume options\n * @returns A Future with `Result<string>` - the consumer tag\n */\n consume(\n queue: string,\n callback: ConsumeCallback,\n options?: Options.Consume,\n ): Future<Result<string, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.consume(queue, callback, options))\n .mapError((error: unknown) => new TechnicalError(\"Failed to start consuming messages\", error))\n .mapOk((reply: { consumerTag: string }) => reply.consumerTag);\n }\n\n /**\n * Cancel a consumer by its consumer tag.\n *\n * @param consumerTag - The consumer tag to cancel\n * @returns A Future that resolves when the consumer is cancelled\n */\n cancel(consumerTag: string): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.cancel(consumerTag))\n .mapError((error: unknown) => new TechnicalError(\"Failed to cancel consumer\", error))\n .mapOk(() => undefined);\n }\n\n /**\n * Acknowledge a message.\n *\n * @param msg - The message to acknowledge\n * @param allUpTo - If true, acknowledge all messages up to and including this one\n */\n ack(msg: ConsumeMessage, allUpTo = false): void {\n this.channelWrapper.ack(msg, allUpTo);\n }\n\n /**\n * Negative acknowledge a message.\n *\n * @param msg - The message to nack\n * @param allUpTo - If true, nack all messages up to and including this one\n * @param requeue - If true, requeue the message(s)\n */\n nack(msg: ConsumeMessage, allUpTo = false, requeue = true): void {\n this.channelWrapper.nack(msg, allUpTo, requeue);\n }\n\n /**\n * Add a setup function to be called when the channel is created or reconnected.\n *\n * This is useful for setting up channel-level configuration like prefetch.\n *\n * @param setup - The setup function to add\n */\n addSetup(setup: (channel: Channel) => void | Promise<void>): void {\n this.channelWrapper.addSetup(setup);\n }\n\n /**\n * Register an event listener on the channel wrapper.\n *\n * Available events:\n * - 'connect': Emitted when the channel is (re)connected\n * - 'close': Emitted when the channel is closed\n * - 'error': Emitted when an error occurs\n *\n * @param event - The event name\n * @param listener - The event listener\n */\n on(event: string, listener: (...args: unknown[]) => void): void {\n this.channelWrapper.on(event, listener);\n }\n\n /**\n * Close the channel and release the connection reference.\n *\n * This will:\n * - Close the channel wrapper\n * - Decrease the reference count on the shared connection\n * - Close the connection if this was the last client using it\n *\n * @returns A Future that resolves when the channel and connection are closed\n */\n close(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.channelWrapper.close())\n .mapError((error: unknown) => new TechnicalError(\"Failed to close channel\", error))\n .flatMapOk(() =>\n Future.fromPromise(\n ConnectionManagerSingleton.getInstance().releaseConnection(\n this.urls,\n this.connectionOptions,\n ),\n ).mapError((error: unknown) => new TechnicalError(\"Failed to release connection\", error)),\n )\n .mapOk(() => undefined);\n }\n\n /**\n * Reset connection singleton cache (for testing only)\n * @internal\n */\n static async _resetConnectionCacheForTesting(): Promise<void> {\n await ConnectionManagerSingleton.getInstance()._resetForTesting();\n }\n}\n","import {\n type Attributes,\n type Counter,\n type Histogram,\n type Span,\n type Tracer,\n} from \"@opentelemetry/api\";\n\n/**\n * SpanKind values from OpenTelemetry.\n * Defined as constants to avoid runtime dependency when types are used.\n * @see https://opentelemetry.io/docs/specs/otel/trace/api/#spankind\n */\nconst SpanKind = {\n /** Producer span represents a message producer */\n PRODUCER: 3,\n /** Consumer span represents a message consumer */\n CONSUMER: 4,\n} as const;\n\n/**\n * Semantic conventions for AMQP messaging following OpenTelemetry standards.\n * @see https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/\n */\nexport const MessagingSemanticConventions = {\n // Messaging attributes\n MESSAGING_SYSTEM: \"messaging.system\",\n MESSAGING_DESTINATION: \"messaging.destination.name\",\n MESSAGING_DESTINATION_KIND: \"messaging.destination.kind\",\n MESSAGING_OPERATION: \"messaging.operation\",\n\n // AMQP/RabbitMQ specific attributes\n MESSAGING_RABBITMQ_ROUTING_KEY: \"messaging.rabbitmq.destination.routing_key\",\n MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG: \"messaging.rabbitmq.message.delivery_tag\",\n AMQP_PUBLISHER_NAME: \"amqp.publisher.name\",\n AMQP_CONSUMER_NAME: \"amqp.consumer.name\",\n\n // Error attributes\n ERROR_TYPE: \"error.type\",\n\n // Values\n MESSAGING_SYSTEM_RABBITMQ: \"rabbitmq\",\n MESSAGING_DESTINATION_KIND_EXCHANGE: \"exchange\",\n MESSAGING_DESTINATION_KIND_QUEUE: \"queue\",\n MESSAGING_OPERATION_PUBLISH: \"publish\",\n MESSAGING_OPERATION_PROCESS: \"process\",\n} as const;\n\n/**\n * Telemetry provider for AMQP operations.\n * Uses lazy loading to gracefully handle cases where OpenTelemetry is not installed.\n */\nexport type TelemetryProvider = {\n /**\n * Get a tracer instance for creating spans.\n * Returns undefined if OpenTelemetry is not available.\n */\n getTracer: () => Tracer | undefined;\n\n /**\n * Get a counter for messages published.\n * Returns undefined if OpenTelemetry is not available.\n */\n getPublishCounter: () => Counter | undefined;\n\n /**\n * Get a counter for messages consumed.\n * Returns undefined if OpenTelemetry is not available.\n */\n getConsumeCounter: () => Counter | undefined;\n\n /**\n * Get a histogram for publish latency.\n * Returns undefined if OpenTelemetry is not available.\n */\n getPublishLatencyHistogram: () => Histogram | undefined;\n\n /**\n * Get a histogram for consume/process latency.\n * Returns undefined if OpenTelemetry is not available.\n */\n getConsumeLatencyHistogram: () => Histogram | undefined;\n};\n\n/**\n * Instrumentation scope name for amqp-contract.\n */\nconst INSTRUMENTATION_SCOPE_NAME = \"@amqp-contract\";\nconst INSTRUMENTATION_SCOPE_VERSION = \"0.1.0\";\n\n// Cache for OpenTelemetry API module and instruments\nlet otelApi: typeof import(\"@opentelemetry/api\") | null | undefined;\nlet cachedTracer: Tracer | undefined;\nlet cachedPublishCounter: Counter | undefined;\nlet cachedConsumeCounter: Counter | undefined;\nlet cachedPublishLatencyHistogram: Histogram | undefined;\nlet cachedConsumeLatencyHistogram: Histogram | undefined;\n\n/**\n * Try to load the OpenTelemetry API module.\n * Returns null if the module is not available.\n */\nfunction tryLoadOpenTelemetryApi(): typeof import(\"@opentelemetry/api\") | null {\n if (otelApi === undefined) {\n try {\n // Dynamic import using require to avoid bundler issues\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n otelApi = require(\"@opentelemetry/api\") as typeof import(\"@opentelemetry/api\");\n } catch {\n otelApi = null;\n }\n }\n return otelApi;\n}\n\n/**\n * Get or create a tracer instance.\n */\nfunction getTracer(): Tracer | undefined {\n if (cachedTracer !== undefined) {\n return cachedTracer;\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (!api) {\n return undefined;\n }\n\n cachedTracer = api.trace.getTracer(INSTRUMENTATION_SCOPE_NAME, INSTRUMENTATION_SCOPE_VERSION);\n return cachedTracer;\n}\n\n/**\n * Get or create a meter and its instruments.\n */\nfunction getMeterInstruments(): {\n publishCounter: Counter | undefined;\n consumeCounter: Counter | undefined;\n publishLatencyHistogram: Histogram | undefined;\n consumeLatencyHistogram: Histogram | undefined;\n} {\n if (cachedPublishCounter !== undefined) {\n return {\n publishCounter: cachedPublishCounter,\n consumeCounter: cachedConsumeCounter,\n publishLatencyHistogram: cachedPublishLatencyHistogram,\n consumeLatencyHistogram: cachedConsumeLatencyHistogram,\n };\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (!api) {\n return {\n publishCounter: undefined,\n consumeCounter: undefined,\n publishLatencyHistogram: undefined,\n consumeLatencyHistogram: undefined,\n };\n }\n\n const meter = api.metrics.getMeter(INSTRUMENTATION_SCOPE_NAME, INSTRUMENTATION_SCOPE_VERSION);\n\n cachedPublishCounter = meter.createCounter(\"amqp.client.messages.published\", {\n description: \"Number of messages published to AMQP broker\",\n unit: \"{message}\",\n });\n\n cachedConsumeCounter = meter.createCounter(\"amqp.worker.messages.consumed\", {\n description: \"Number of messages consumed from AMQP broker\",\n unit: \"{message}\",\n });\n\n cachedPublishLatencyHistogram = meter.createHistogram(\"amqp.client.publish.duration\", {\n description: \"Duration of message publish operations\",\n unit: \"ms\",\n });\n\n cachedConsumeLatencyHistogram = meter.createHistogram(\"amqp.worker.process.duration\", {\n description: \"Duration of message processing operations\",\n unit: \"ms\",\n });\n\n return {\n publishCounter: cachedPublishCounter,\n consumeCounter: cachedConsumeCounter,\n publishLatencyHistogram: cachedPublishLatencyHistogram,\n consumeLatencyHistogram: cachedConsumeLatencyHistogram,\n };\n}\n\n/**\n * Default telemetry provider that uses OpenTelemetry API if available.\n */\nexport const defaultTelemetryProvider: TelemetryProvider = {\n getTracer,\n getPublishCounter: () => getMeterInstruments().publishCounter,\n getConsumeCounter: () => getMeterInstruments().consumeCounter,\n getPublishLatencyHistogram: () => getMeterInstruments().publishLatencyHistogram,\n getConsumeLatencyHistogram: () => getMeterInstruments().consumeLatencyHistogram,\n};\n\n/**\n * Create a span for a publish operation.\n * Returns undefined if OpenTelemetry is not available.\n */\nexport function startPublishSpan(\n provider: TelemetryProvider,\n exchangeName: string,\n routingKey: string | undefined,\n attributes?: Attributes,\n): Span | undefined {\n const tracer = provider.getTracer();\n if (!tracer) {\n return undefined;\n }\n\n const spanName = `${exchangeName} publish`;\n\n return tracer.startSpan(spanName, {\n kind: SpanKind.PRODUCER,\n attributes: {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: exchangeName,\n [MessagingSemanticConventions.MESSAGING_DESTINATION_KIND]:\n MessagingSemanticConventions.MESSAGING_DESTINATION_KIND_EXCHANGE,\n [MessagingSemanticConventions.MESSAGING_OPERATION]:\n MessagingSemanticConventions.MESSAGING_OPERATION_PUBLISH,\n ...(routingKey\n ? { [MessagingSemanticConventions.MESSAGING_RABBITMQ_ROUTING_KEY]: routingKey }\n : {}),\n ...attributes,\n },\n });\n}\n\n/**\n * Create a span for a consume/process operation.\n * Returns undefined if OpenTelemetry is not available.\n */\nexport function startConsumeSpan(\n provider: TelemetryProvider,\n queueName: string,\n consumerName: string,\n attributes?: Attributes,\n): Span | undefined {\n const tracer = provider.getTracer();\n if (!tracer) {\n return undefined;\n }\n\n const spanName = `${queueName} process`;\n\n return tracer.startSpan(spanName, {\n kind: SpanKind.CONSUMER,\n attributes: {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,\n [MessagingSemanticConventions.MESSAGING_DESTINATION_KIND]:\n MessagingSemanticConventions.MESSAGING_DESTINATION_KIND_QUEUE,\n [MessagingSemanticConventions.MESSAGING_OPERATION]:\n MessagingSemanticConventions.MESSAGING_OPERATION_PROCESS,\n [MessagingSemanticConventions.AMQP_CONSUMER_NAME]: consumerName,\n ...attributes,\n },\n });\n}\n\n/**\n * End a span with success status.\n */\nexport function endSpanSuccess(span: Span | undefined): void {\n if (!span) {\n return;\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (api) {\n span.setStatus({ code: api.SpanStatusCode.OK });\n }\n span.end();\n}\n\n/**\n * End a span with error status.\n */\nexport function endSpanError(span: Span | undefined, error: Error): void {\n if (!span) {\n return;\n }\n\n const api = tryLoadOpenTelemetryApi();\n if (api) {\n span.setStatus({ code: api.SpanStatusCode.ERROR, message: error.message });\n span.recordException(error);\n span.setAttribute(MessagingSemanticConventions.ERROR_TYPE, error.name);\n }\n span.end();\n}\n\n/**\n * Record a publish metric.\n */\nexport function recordPublishMetric(\n provider: TelemetryProvider,\n exchangeName: string,\n routingKey: string | undefined,\n success: boolean,\n durationMs: number,\n): void {\n const publishCounter = provider.getPublishCounter();\n const publishLatencyHistogram = provider.getPublishLatencyHistogram();\n\n const attributes: Attributes = {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: exchangeName,\n ...(routingKey\n ? { [MessagingSemanticConventions.MESSAGING_RABBITMQ_ROUTING_KEY]: routingKey }\n : {}),\n success: success,\n };\n\n publishCounter?.add(1, attributes);\n publishLatencyHistogram?.record(durationMs, attributes);\n}\n\n/**\n * Record a consume metric.\n */\nexport function recordConsumeMetric(\n provider: TelemetryProvider,\n queueName: string,\n consumerName: string,\n success: boolean,\n durationMs: number,\n): void {\n const consumeCounter = provider.getConsumeCounter();\n const consumeLatencyHistogram = provider.getConsumeLatencyHistogram();\n\n const attributes: Attributes = {\n [MessagingSemanticConventions.MESSAGING_SYSTEM]:\n MessagingSemanticConventions.MESSAGING_SYSTEM_RABBITMQ,\n [MessagingSemanticConventions.MESSAGING_DESTINATION]: queueName,\n [MessagingSemanticConventions.AMQP_CONSUMER_NAME]: consumerName,\n success: success,\n };\n\n consumeCounter?.add(1, attributes);\n consumeLatencyHistogram?.record(durationMs, attributes);\n}\n\n/**\n * Reset the cached OpenTelemetry API module and instruments.\n * For testing purposes only.\n * @internal\n */\nexport function _resetTelemetryCacheForTesting(): void {\n otelApi = undefined;\n cachedTracer = undefined;\n cachedPublishCounter = undefined;\n cachedConsumeCounter = undefined;\n cachedPublishLatencyHistogram = undefined;\n cachedConsumeLatencyHistogram = undefined;\n}\n"],"mappings":"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"}
package/docs/index.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ### AmqpClient
10
10
 
11
- Defined in: [packages/core/src/amqp-client.ts:61](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L61)
11
+ Defined in: [packages/core/src/amqp-client.ts:84](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L84)
12
12
 
13
13
  AMQP client that manages connections and channels with automatic topology setup.
14
14
 
@@ -46,7 +46,7 @@ await client.close().resultToPromise();
46
46
  new AmqpClient(contract, options): AmqpClient;
47
47
  ```
48
48
 
49
- Defined in: [packages/core/src/amqp-client.ts:78](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L78)
49
+ Defined in: [packages/core/src/amqp-client.ts:101](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L101)
50
50
 
51
51
  Create a new AMQP client instance.
52
52
 
@@ -74,7 +74,7 @@ The client will automatically:
74
74
  ack(msg, allUpTo?): void;
75
75
  ```
76
76
 
77
- Defined in: [packages/core/src/amqp-client.ts:212](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L212)
77
+ Defined in: [packages/core/src/amqp-client.ts:219](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L219)
78
78
 
79
79
  Acknowledge a message.
80
80
 
@@ -95,7 +95,7 @@ Acknowledge a message.
95
95
  addSetup(setup): void;
96
96
  ```
97
97
 
98
- Defined in: [packages/core/src/amqp-client.ts:234](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L234)
98
+ Defined in: [packages/core/src/amqp-client.ts:241](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L241)
99
99
 
100
100
  Add a setup function to be called when the channel is created or reconnected.
101
101
 
@@ -117,7 +117,7 @@ This is useful for setting up channel-level configuration like prefetch.
117
117
  cancel(consumerTag): Future<Result<void, TechnicalError>>;
118
118
  ```
119
119
 
120
- Defined in: [packages/core/src/amqp-client.ts:200](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L200)
120
+ Defined in: [packages/core/src/amqp-client.ts:207](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L207)
121
121
 
122
122
  Cancel a consumer by its consumer tag.
123
123
 
@@ -139,7 +139,7 @@ A Future that resolves when the consumer is cancelled
139
139
  close(): Future<Result<void, TechnicalError>>;
140
140
  ```
141
141
 
142
- Defined in: [packages/core/src/amqp-client.ts:263](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L263)
142
+ Defined in: [packages/core/src/amqp-client.ts:270](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L270)
143
143
 
144
144
  Close the channel and release the connection reference.
145
145
 
@@ -163,7 +163,7 @@ consume(
163
163
  options?): Future<Result<string, TechnicalError>>;
164
164
  ```
165
165
 
166
- Defined in: [packages/core/src/amqp-client.ts:184](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L184)
166
+ Defined in: [packages/core/src/amqp-client.ts:191](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L191)
167
167
 
168
168
  Start consuming messages from a queue.
169
169
 
@@ -187,7 +187,7 @@ A Future with `Result<string>` - the consumer tag
187
187
  getConnection(): IAmqpConnectionManager;
188
188
  ```
189
189
 
190
- Defined in: [packages/core/src/amqp-client.ts:141](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L141)
190
+ Defined in: [packages/core/src/amqp-client.ts:148](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L148)
191
191
 
192
192
  Get the underlying connection manager
193
193
 
@@ -210,7 +210,7 @@ nack(
210
210
  requeue?): void;
211
211
  ```
212
212
 
213
- Defined in: [packages/core/src/amqp-client.ts:223](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L223)
213
+ Defined in: [packages/core/src/amqp-client.ts:230](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L230)
214
214
 
215
215
  Negative acknowledge a message.
216
216
 
@@ -232,7 +232,7 @@ Negative acknowledge a message.
232
232
  on(event, listener): void;
233
233
  ```
234
234
 
235
- Defined in: [packages/core/src/amqp-client.ts:249](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L249)
235
+ Defined in: [packages/core/src/amqp-client.ts:256](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L256)
236
236
 
237
237
  Register an event listener on the channel wrapper.
238
238
 
@@ -262,7 +262,7 @@ publish(
262
262
  options?): Future<Result<boolean, TechnicalError>>;
263
263
  ```
264
264
 
265
- Defined in: [packages/core/src/amqp-client.ts:165](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L165)
265
+ Defined in: [packages/core/src/amqp-client.ts:172](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L172)
266
266
 
267
267
  Publish a message to an exchange.
268
268
 
@@ -287,7 +287,7 @@ A Future with `Result<boolean>` - true if message was sent, false if channel buf
287
287
  waitForConnect(): Future<Result<void, TechnicalError>>;
288
288
  ```
289
289
 
290
- Defined in: [packages/core/src/amqp-client.ts:150](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L150)
290
+ Defined in: [packages/core/src/amqp-client.ts:157](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L157)
291
291
 
292
292
  Wait for the channel to be connected and ready.
293
293
 
@@ -301,7 +301,7 @@ A Future that resolves when the channel is connected
301
301
 
302
302
  ### ConnectionManagerSingleton
303
303
 
304
- Defined in: [packages/core/src/connection-manager.ts:23](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/connection-manager.ts#L23)
304
+ Defined in: [packages/core/src/connection-manager.ts:23](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/connection-manager.ts#L23)
305
305
 
306
306
  Connection manager singleton for sharing AMQP connections across clients.
307
307
 
@@ -327,7 +327,7 @@ await manager.releaseConnection(['amqp://localhost']);
327
327
  getConnection(urls, connectionOptions?): IAmqpConnectionManager;
328
328
  ```
329
329
 
330
- Defined in: [packages/core/src/connection-manager.ts:52](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/connection-manager.ts#L52)
330
+ Defined in: [packages/core/src/connection-manager.ts:52](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/connection-manager.ts#L52)
331
331
 
332
332
  Get or create a connection for the given URLs and options.
333
333
 
@@ -353,7 +353,7 @@ The AMQP connection manager instance
353
353
  releaseConnection(urls, connectionOptions?): Promise<void>;
354
354
  ```
355
355
 
356
- Defined in: [packages/core/src/connection-manager.ts:81](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/connection-manager.ts#L81)
356
+ Defined in: [packages/core/src/connection-manager.ts:81](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/connection-manager.ts#L81)
357
357
 
358
358
  Release a connection reference.
359
359
 
@@ -379,7 +379,7 @@ A promise that resolves when the connection is released (and closed if necessary
379
379
  static getInstance(): ConnectionManagerSingleton;
380
380
  ```
381
381
 
382
- Defined in: [packages/core/src/connection-manager.ts:35](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/connection-manager.ts#L35)
382
+ Defined in: [packages/core/src/connection-manager.ts:35](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/connection-manager.ts#L35)
383
383
 
384
384
  Get the singleton instance of the connection manager.
385
385
 
@@ -391,9 +391,171 @@ The singleton instance
391
391
 
392
392
  ***
393
393
 
394
+ ### MessageValidationError
395
+
396
+ Defined in: [packages/core/src/errors.ts:33](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/errors.ts#L33)
397
+
398
+ Error thrown when message validation fails (payload or headers).
399
+
400
+ Used by both the client (publish-time payload validation) and the worker
401
+ (consume-time payload and headers validation).
402
+
403
+ #### Param
404
+
405
+ The name of the publisher or consumer that triggered the validation
406
+
407
+ #### Param
408
+
409
+ The validation issues from the Standard Schema validation
410
+
411
+ #### Extends
412
+
413
+ - `Error`
414
+
415
+ #### Constructors
416
+
417
+ ##### Constructor
418
+
419
+ ```ts
420
+ new MessageValidationError(source, issues): MessageValidationError;
421
+ ```
422
+
423
+ Defined in: [packages/core/src/errors.ts:34](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/errors.ts#L34)
424
+
425
+ ###### Parameters
426
+
427
+ | Parameter | Type |
428
+ | ------ | ------ |
429
+ | `source` | `string` |
430
+ | `issues` | `unknown` |
431
+
432
+ ###### Returns
433
+
434
+ [`MessageValidationError`](#messagevalidationerror)
435
+
436
+ ###### Overrides
437
+
438
+ ```ts
439
+ Error.constructor
440
+ ```
441
+
442
+ #### Properties
443
+
444
+ | Property | Modifier | Type | Description | Inherited from | Defined in |
445
+ | ------ | ------ | ------ | ------ | ------ | ------ |
446
+ | <a id="cause"></a> `cause?` | `public` | `unknown` | - | `Error.cause` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:26 |
447
+ | <a id="issues"></a> `issues` | `readonly` | `unknown` | - | - | [packages/core/src/errors.ts:36](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/errors.ts#L36) |
448
+ | <a id="message"></a> `message` | `public` | `string` | - | `Error.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
449
+ | <a id="name"></a> `name` | `public` | `string` | - | `Error.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
450
+ | <a id="source"></a> `source` | `readonly` | `string` | - | - | [packages/core/src/errors.ts:35](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/errors.ts#L35) |
451
+ | <a id="stack"></a> `stack?` | `public` | `string` | - | `Error.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
452
+ | <a id="stacktracelimit"></a> `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured _after_ the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `Error.stackTraceLimit` | node\_modules/.pnpm/@types+node@25.2.3/node\_modules/@types/node/globals.d.ts:67 |
453
+
454
+ #### Methods
455
+
456
+ ##### captureStackTrace()
457
+
458
+ ```ts
459
+ static captureStackTrace(targetObject, constructorOpt?): void;
460
+ ```
461
+
462
+ Defined in: node\_modules/.pnpm/@types+node@25.2.3/node\_modules/@types/node/globals.d.ts:51
463
+
464
+ Creates a `.stack` property on `targetObject`, which when accessed returns
465
+ a string representing the location in the code at which
466
+ `Error.captureStackTrace()` was called.
467
+
468
+ ```js
469
+ const myObject = {};
470
+ Error.captureStackTrace(myObject);
471
+ myObject.stack; // Similar to `new Error().stack`
472
+ ```
473
+
474
+ The first line of the trace will be prefixed with
475
+ `${myObject.name}: ${myObject.message}`.
476
+
477
+ The optional `constructorOpt` argument accepts a function. If given, all frames
478
+ above `constructorOpt`, including `constructorOpt`, will be omitted from the
479
+ generated stack trace.
480
+
481
+ The `constructorOpt` argument is useful for hiding implementation
482
+ details of error generation from the user. For instance:
483
+
484
+ ```js
485
+ function a() {
486
+ b();
487
+ }
488
+
489
+ function b() {
490
+ c();
491
+ }
492
+
493
+ function c() {
494
+ // Create an error without stack trace to avoid calculating the stack trace twice.
495
+ const { stackTraceLimit } = Error;
496
+ Error.stackTraceLimit = 0;
497
+ const error = new Error();
498
+ Error.stackTraceLimit = stackTraceLimit;
499
+
500
+ // Capture the stack trace above function b
501
+ Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
502
+ throw error;
503
+ }
504
+
505
+ a();
506
+ ```
507
+
508
+ ###### Parameters
509
+
510
+ | Parameter | Type |
511
+ | ------ | ------ |
512
+ | `targetObject` | `object` |
513
+ | `constructorOpt?` | `Function` |
514
+
515
+ ###### Returns
516
+
517
+ `void`
518
+
519
+ ###### Inherited from
520
+
521
+ ```ts
522
+ Error.captureStackTrace
523
+ ```
524
+
525
+ ##### prepareStackTrace()
526
+
527
+ ```ts
528
+ static prepareStackTrace(err, stackTraces): any;
529
+ ```
530
+
531
+ Defined in: node\_modules/.pnpm/@types+node@25.2.3/node\_modules/@types/node/globals.d.ts:55
532
+
533
+ ###### Parameters
534
+
535
+ | Parameter | Type |
536
+ | ------ | ------ |
537
+ | `err` | `Error` |
538
+ | `stackTraces` | `CallSite`[] |
539
+
540
+ ###### Returns
541
+
542
+ `any`
543
+
544
+ ###### See
545
+
546
+ https://v8.dev/docs/stack-trace-api#customizing-stack-traces
547
+
548
+ ###### Inherited from
549
+
550
+ ```ts
551
+ Error.prepareStackTrace
552
+ ```
553
+
554
+ ***
555
+
394
556
  ### TechnicalError
395
557
 
396
- Defined in: [packages/core/src/errors.ts:7](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/errors.ts#L7)
558
+ Defined in: [packages/core/src/errors.ts:7](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/errors.ts#L7)
397
559
 
398
560
  Error for technical/runtime failures that cannot be prevented by TypeScript.
399
561
 
@@ -412,7 +574,7 @@ and other runtime errors. This error is shared across core, worker, and client p
412
574
  new TechnicalError(message, cause?): TechnicalError;
413
575
  ```
414
576
 
415
- Defined in: [packages/core/src/errors.ts:8](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/errors.ts#L8)
577
+ Defined in: [packages/core/src/errors.ts:8](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/errors.ts#L8)
416
578
 
417
579
  ###### Parameters
418
580
 
@@ -435,11 +597,11 @@ Error.constructor
435
597
 
436
598
  | Property | Modifier | Type | Description | Inherited from | Defined in |
437
599
  | ------ | ------ | ------ | ------ | ------ | ------ |
438
- | <a id="cause"></a> `cause?` | `readonly` | `unknown` | - | `Error.cause` | [packages/core/src/errors.ts:10](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/errors.ts#L10) |
439
- | <a id="message"></a> `message` | `public` | `string` | - | `Error.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
440
- | <a id="name"></a> `name` | `public` | `string` | - | `Error.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
441
- | <a id="stack"></a> `stack?` | `public` | `string` | - | `Error.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
442
- | <a id="stacktracelimit"></a> `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured _after_ the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `Error.stackTraceLimit` | node\_modules/.pnpm/@types+node@25.2.3/node\_modules/@types/node/globals.d.ts:67 |
600
+ | <a id="cause-1"></a> `cause?` | `readonly` | `unknown` | - | `Error.cause` | [packages/core/src/errors.ts:10](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/errors.ts#L10) |
601
+ | <a id="message-1"></a> `message` | `public` | `string` | - | `Error.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
602
+ | <a id="name-1"></a> `name` | `public` | `string` | - | `Error.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
603
+ | <a id="stack-1"></a> `stack?` | `public` | `string` | - | `Error.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
604
+ | <a id="stacktracelimit-1"></a> `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured _after_ the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `Error.stackTraceLimit` | node\_modules/.pnpm/@types+node@25.2.3/node\_modules/@types/node/globals.d.ts:67 |
443
605
 
444
606
  #### Methods
445
607
 
@@ -549,7 +711,7 @@ Error.prepareStackTrace
549
711
  type AmqpClientOptions = object;
550
712
  ```
551
713
 
552
- Defined in: [packages/core/src/amqp-client.ts:22](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L22)
714
+ Defined in: [packages/core/src/amqp-client.ts:45](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L45)
553
715
 
554
716
  Options for creating an AMQP client.
555
717
 
@@ -557,9 +719,9 @@ Options for creating an AMQP client.
557
719
 
558
720
  | Property | Type | Description | Defined in |
559
721
  | ------ | ------ | ------ | ------ |
560
- | <a id="channeloptions"></a> `channelOptions?` | `Partial`&lt;`CreateChannelOpts`&gt; | Optional channel configuration options. | [packages/core/src/amqp-client.ts:25](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L25) |
561
- | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | Optional connection configuration (heartbeat, reconnect settings, etc.). | [packages/core/src/amqp-client.ts:24](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L24) |
562
- | <a id="urls"></a> `urls` | `ConnectionUrl`[] | AMQP broker URL(s). Multiple URLs provide failover support. | [packages/core/src/amqp-client.ts:23](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L23) |
722
+ | <a id="channeloptions"></a> `channelOptions?` | `Partial`&lt;`CreateChannelOpts`&gt; | Optional channel configuration options. | [packages/core/src/amqp-client.ts:48](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L48) |
723
+ | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | Optional connection configuration (heartbeat, reconnect settings, etc.). | [packages/core/src/amqp-client.ts:47](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L47) |
724
+ | <a id="urls"></a> `urls` | `ConnectionUrl`[] | AMQP broker URL(s). Multiple URLs provide failover support. | [packages/core/src/amqp-client.ts:46](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L46) |
563
725
 
564
726
  ***
565
727
 
@@ -569,7 +731,7 @@ Options for creating an AMQP client.
569
731
  type ConsumeCallback = (msg) => void | Promise<void>;
570
732
  ```
571
733
 
572
- Defined in: [packages/core/src/amqp-client.ts:31](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/amqp-client.ts#L31)
734
+ Defined in: [packages/core/src/amqp-client.ts:54](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/amqp-client.ts#L54)
573
735
 
574
736
  Callback type for consuming messages.
575
737
 
@@ -591,7 +753,7 @@ Callback type for consuming messages.
591
753
  type Logger = object;
592
754
  ```
593
755
 
594
- Defined in: [packages/core/src/logger.ts:30](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/logger.ts#L30)
756
+ Defined in: [packages/core/src/logger.ts:30](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/logger.ts#L30)
595
757
 
596
758
  Logger interface for amqp-contract packages.
597
759
 
@@ -618,7 +780,7 @@ const logger: Logger = {
618
780
  debug(message, context?): void;
619
781
  ```
620
782
 
621
- Defined in: [packages/core/src/logger.ts:36](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/logger.ts#L36)
783
+ Defined in: [packages/core/src/logger.ts:36](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/logger.ts#L36)
622
784
 
623
785
  Log debug level messages
624
786
 
@@ -639,7 +801,7 @@ Log debug level messages
639
801
  error(message, context?): void;
640
802
  ```
641
803
 
642
- Defined in: [packages/core/src/logger.ts:57](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/logger.ts#L57)
804
+ Defined in: [packages/core/src/logger.ts:57](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/logger.ts#L57)
643
805
 
644
806
  Log error level messages
645
807
 
@@ -660,7 +822,7 @@ Log error level messages
660
822
  info(message, context?): void;
661
823
  ```
662
824
 
663
- Defined in: [packages/core/src/logger.ts:43](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/logger.ts#L43)
825
+ Defined in: [packages/core/src/logger.ts:43](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/logger.ts#L43)
664
826
 
665
827
  Log info level messages
666
828
 
@@ -681,7 +843,7 @@ Log info level messages
681
843
  warn(message, context?): void;
682
844
  ```
683
845
 
684
- Defined in: [packages/core/src/logger.ts:50](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/logger.ts#L50)
846
+ Defined in: [packages/core/src/logger.ts:50](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/logger.ts#L50)
685
847
 
686
848
  Log warning level messages
687
849
 
@@ -704,7 +866,7 @@ Log warning level messages
704
866
  type LoggerContext = Record<string, unknown> & object;
705
867
  ```
706
868
 
707
- Defined in: [packages/core/src/logger.ts:9](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/logger.ts#L9)
869
+ Defined in: [packages/core/src/logger.ts:9](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/logger.ts#L9)
708
870
 
709
871
  Context object for logger methods.
710
872
 
@@ -715,7 +877,7 @@ for common logging context properties.
715
877
 
716
878
  | Name | Type | Defined in |
717
879
  | ------ | ------ | ------ |
718
- | `error?` | `unknown` | [packages/core/src/logger.ts:10](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/logger.ts#L10) |
880
+ | `error?` | `unknown` | [packages/core/src/logger.ts:10](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/logger.ts#L10) |
719
881
 
720
882
  ***
721
883
 
@@ -725,7 +887,7 @@ for common logging context properties.
725
887
  type TelemetryProvider = object;
726
888
  ```
727
889
 
728
- Defined in: [packages/core/src/telemetry.ts:55](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L55)
890
+ Defined in: [packages/core/src/telemetry.ts:53](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L53)
729
891
 
730
892
  Telemetry provider for AMQP operations.
731
893
  Uses lazy loading to gracefully handle cases where OpenTelemetry is not installed.
@@ -734,11 +896,11 @@ Uses lazy loading to gracefully handle cases where OpenTelemetry is not installe
734
896
 
735
897
  | Property | Type | Description | Defined in |
736
898
  | ------ | ------ | ------ | ------ |
737
- | <a id="getconsumecounter"></a> `getConsumeCounter` | () => `Counter` \| `undefined` | Get a counter for messages consumed. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:72](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L72) |
738
- | <a id="getconsumelatencyhistogram"></a> `getConsumeLatencyHistogram` | () => `Histogram` \| `undefined` | Get a histogram for consume/process latency. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:84](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L84) |
739
- | <a id="getpublishcounter"></a> `getPublishCounter` | () => `Counter` \| `undefined` | Get a counter for messages published. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:66](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L66) |
740
- | <a id="getpublishlatencyhistogram"></a> `getPublishLatencyHistogram` | () => `Histogram` \| `undefined` | Get a histogram for publish latency. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:78](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L78) |
741
- | <a id="gettracer"></a> `getTracer` | () => `Tracer` \| `undefined` | Get a tracer instance for creating spans. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:60](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L60) |
899
+ | <a id="getconsumecounter"></a> `getConsumeCounter` | () => `Counter` \| `undefined` | Get a counter for messages consumed. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:70](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L70) |
900
+ | <a id="getconsumelatencyhistogram"></a> `getConsumeLatencyHistogram` | () => `Histogram` \| `undefined` | Get a histogram for consume/process latency. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:82](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L82) |
901
+ | <a id="getpublishcounter"></a> `getPublishCounter` | () => `Counter` \| `undefined` | Get a counter for messages published. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:64](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L64) |
902
+ | <a id="getpublishlatencyhistogram"></a> `getPublishLatencyHistogram` | () => `Histogram` \| `undefined` | Get a histogram for publish latency. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:76](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L76) |
903
+ | <a id="gettracer"></a> `getTracer` | () => `Tracer` \| `undefined` | Get a tracer instance for creating spans. Returns undefined if OpenTelemetry is not available. | [packages/core/src/telemetry.ts:58](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L58) |
742
904
 
743
905
  ## Variables
744
906
 
@@ -748,7 +910,7 @@ Uses lazy loading to gracefully handle cases where OpenTelemetry is not installe
748
910
  const defaultTelemetryProvider: TelemetryProvider;
749
911
  ```
750
912
 
751
- Defined in: [packages/core/src/telemetry.ts:196](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L196)
913
+ Defined in: [packages/core/src/telemetry.ts:194](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L194)
752
914
 
753
915
  Default telemetry provider that uses OpenTelemetry API if available.
754
916
 
@@ -760,7 +922,7 @@ Default telemetry provider that uses OpenTelemetry API if available.
760
922
  const MessagingSemanticConventions: object;
761
923
  ```
762
924
 
763
- Defined in: [packages/core/src/telemetry.ts:25](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L25)
925
+ Defined in: [packages/core/src/telemetry.ts:25](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L25)
764
926
 
765
927
  Semantic conventions for AMQP messaging following OpenTelemetry standards.
766
928
 
@@ -768,22 +930,20 @@ Semantic conventions for AMQP messaging following OpenTelemetry standards.
768
930
 
769
931
  | Name | Type | Default value | Defined in |
770
932
  | ------ | ------ | ------ | ------ |
771
- | <a id="property-error_type"></a> `ERROR_TYPE` | `"error.type"` | `"error.type"` | [packages/core/src/telemetry.ts:40](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L40) |
772
- | <a id="property-messaging_destination"></a> `MESSAGING_DESTINATION` | `"messaging.destination.name"` | `"messaging.destination.name"` | [packages/core/src/telemetry.ts:28](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L28) |
773
- | <a id="property-messaging_destination_kind"></a> `MESSAGING_DESTINATION_KIND` | `"messaging.destination.kind"` | `"messaging.destination.kind"` | [packages/core/src/telemetry.ts:29](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L29) |
774
- | <a id="property-messaging_destination_kind_exchange"></a> `MESSAGING_DESTINATION_KIND_EXCHANGE` | `"exchange"` | `"exchange"` | [packages/core/src/telemetry.ts:44](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L44) |
775
- | <a id="property-messaging_destination_kind_queue"></a> `MESSAGING_DESTINATION_KIND_QUEUE` | `"queue"` | `"queue"` | [packages/core/src/telemetry.ts:45](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L45) |
776
- | <a id="property-messaging_message_conversation_id"></a> `MESSAGING_MESSAGE_CONVERSATION_ID` | `"messaging.message.conversation_id"` | `"messaging.message.conversation_id"` | [packages/core/src/telemetry.ts:33](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L33) |
777
- | <a id="property-messaging_message_id"></a> `MESSAGING_MESSAGE_ID` | `"messaging.message.id"` | `"messaging.message.id"` | [packages/core/src/telemetry.ts:31](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L31) |
778
- | <a id="property-messaging_message_payload_size"></a> `MESSAGING_MESSAGE_PAYLOAD_SIZE` | `"messaging.message.body.size"` | `"messaging.message.body.size"` | [packages/core/src/telemetry.ts:32](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L32) |
779
- | <a id="property-messaging_operation"></a> `MESSAGING_OPERATION` | `"messaging.operation"` | `"messaging.operation"` | [packages/core/src/telemetry.ts:30](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L30) |
780
- | <a id="property-messaging_operation_process"></a> `MESSAGING_OPERATION_PROCESS` | `"process"` | `"process"` | [packages/core/src/telemetry.ts:48](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L48) |
781
- | <a id="property-messaging_operation_publish"></a> `MESSAGING_OPERATION_PUBLISH` | `"publish"` | `"publish"` | [packages/core/src/telemetry.ts:46](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L46) |
782
- | <a id="property-messaging_operation_receive"></a> `MESSAGING_OPERATION_RECEIVE` | `"receive"` | `"receive"` | [packages/core/src/telemetry.ts:47](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L47) |
783
- | <a id="property-messaging_rabbitmq_message_delivery_tag"></a> `MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG` | `"messaging.rabbitmq.message.delivery_tag"` | `"messaging.rabbitmq.message.delivery_tag"` | [packages/core/src/telemetry.ts:37](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L37) |
784
- | <a id="property-messaging_rabbitmq_routing_key"></a> `MESSAGING_RABBITMQ_ROUTING_KEY` | `"messaging.rabbitmq.destination.routing_key"` | `"messaging.rabbitmq.destination.routing_key"` | [packages/core/src/telemetry.ts:36](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L36) |
785
- | <a id="property-messaging_system"></a> `MESSAGING_SYSTEM` | `"messaging.system"` | `"messaging.system"` | [packages/core/src/telemetry.ts:27](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L27) |
786
- | <a id="property-messaging_system_rabbitmq"></a> `MESSAGING_SYSTEM_RABBITMQ` | `"rabbitmq"` | `"rabbitmq"` | [packages/core/src/telemetry.ts:43](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L43) |
933
+ | <a id="property-amqp_consumer_name"></a> `AMQP_CONSUMER_NAME` | `"amqp.consumer.name"` | `"amqp.consumer.name"` | [packages/core/src/telemetry.ts:36](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L36) |
934
+ | <a id="property-amqp_publisher_name"></a> `AMQP_PUBLISHER_NAME` | `"amqp.publisher.name"` | `"amqp.publisher.name"` | [packages/core/src/telemetry.ts:35](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L35) |
935
+ | <a id="property-error_type"></a> `ERROR_TYPE` | `"error.type"` | `"error.type"` | [packages/core/src/telemetry.ts:39](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L39) |
936
+ | <a id="property-messaging_destination"></a> `MESSAGING_DESTINATION` | `"messaging.destination.name"` | `"messaging.destination.name"` | [packages/core/src/telemetry.ts:28](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L28) |
937
+ | <a id="property-messaging_destination_kind"></a> `MESSAGING_DESTINATION_KIND` | `"messaging.destination.kind"` | `"messaging.destination.kind"` | [packages/core/src/telemetry.ts:29](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L29) |
938
+ | <a id="property-messaging_destination_kind_exchange"></a> `MESSAGING_DESTINATION_KIND_EXCHANGE` | `"exchange"` | `"exchange"` | [packages/core/src/telemetry.ts:43](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L43) |
939
+ | <a id="property-messaging_destination_kind_queue"></a> `MESSAGING_DESTINATION_KIND_QUEUE` | `"queue"` | `"queue"` | [packages/core/src/telemetry.ts:44](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L44) |
940
+ | <a id="property-messaging_operation"></a> `MESSAGING_OPERATION` | `"messaging.operation"` | `"messaging.operation"` | [packages/core/src/telemetry.ts:30](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L30) |
941
+ | <a id="property-messaging_operation_process"></a> `MESSAGING_OPERATION_PROCESS` | `"process"` | `"process"` | [packages/core/src/telemetry.ts:46](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L46) |
942
+ | <a id="property-messaging_operation_publish"></a> `MESSAGING_OPERATION_PUBLISH` | `"publish"` | `"publish"` | [packages/core/src/telemetry.ts:45](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L45) |
943
+ | <a id="property-messaging_rabbitmq_message_delivery_tag"></a> `MESSAGING_RABBITMQ_MESSAGE_DELIVERY_TAG` | `"messaging.rabbitmq.message.delivery_tag"` | `"messaging.rabbitmq.message.delivery_tag"` | [packages/core/src/telemetry.ts:34](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L34) |
944
+ | <a id="property-messaging_rabbitmq_routing_key"></a> `MESSAGING_RABBITMQ_ROUTING_KEY` | `"messaging.rabbitmq.destination.routing_key"` | `"messaging.rabbitmq.destination.routing_key"` | [packages/core/src/telemetry.ts:33](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L33) |
945
+ | <a id="property-messaging_system"></a> `MESSAGING_SYSTEM` | `"messaging.system"` | `"messaging.system"` | [packages/core/src/telemetry.ts:27](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L27) |
946
+ | <a id="property-messaging_system_rabbitmq"></a> `MESSAGING_SYSTEM_RABBITMQ` | `"rabbitmq"` | `"rabbitmq"` | [packages/core/src/telemetry.ts:42](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L42) |
787
947
 
788
948
  #### See
789
949
 
@@ -797,7 +957,7 @@ https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/
797
957
  function endSpanError(span, error): void;
798
958
  ```
799
959
 
800
- Defined in: [packages/core/src/telemetry.ts:290](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L290)
960
+ Defined in: [packages/core/src/telemetry.ts:288](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L288)
801
961
 
802
962
  End a span with error status.
803
963
 
@@ -820,7 +980,7 @@ End a span with error status.
820
980
  function endSpanSuccess(span): void;
821
981
  ```
822
982
 
823
- Defined in: [packages/core/src/telemetry.ts:275](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L275)
983
+ Defined in: [packages/core/src/telemetry.ts:273](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L273)
824
984
 
825
985
  End a span with success status.
826
986
 
@@ -847,7 +1007,7 @@ function recordConsumeMetric(
847
1007
  durationMs): void;
848
1008
  ```
849
1009
 
850
- Defined in: [packages/core/src/telemetry.ts:334](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L334)
1010
+ Defined in: [packages/core/src/telemetry.ts:332](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L332)
851
1011
 
852
1012
  Record a consume metric.
853
1013
 
@@ -878,7 +1038,7 @@ function recordPublishMetric(
878
1038
  durationMs): void;
879
1039
  ```
880
1040
 
881
- Defined in: [packages/core/src/telemetry.ts:307](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L307)
1041
+ Defined in: [packages/core/src/telemetry.ts:305](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L305)
882
1042
 
883
1043
  Record a publish metric.
884
1044
 
@@ -904,7 +1064,7 @@ Record a publish metric.
904
1064
  function setupAmqpTopology(channel, contract): Promise<void>;
905
1065
  ```
906
1066
 
907
- Defined in: [packages/core/src/setup.ts:25](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/setup.ts#L25)
1067
+ Defined in: [packages/core/src/setup.ts:26](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/setup.ts#L26)
908
1068
 
909
1069
  Setup AMQP topology (exchanges, queues, and bindings) from a contract definition.
910
1070
 
@@ -952,7 +1112,7 @@ function startConsumeSpan(
952
1112
  attributes?): Span | undefined;
953
1113
  ```
954
1114
 
955
- Defined in: [packages/core/src/telemetry.ts:243](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L243)
1115
+ Defined in: [packages/core/src/telemetry.ts:241](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L241)
956
1116
 
957
1117
  Create a span for a consume/process operation.
958
1118
  Returns undefined if OpenTelemetry is not available.
@@ -982,7 +1142,7 @@ function startPublishSpan(
982
1142
  attributes?): Span | undefined;
983
1143
  ```
984
1144
 
985
- Defined in: [packages/core/src/telemetry.ts:208](https://github.com/btravers/amqp-contract/blob/fc480811955c7c63b50aea18b1676c065870bfae/packages/core/src/telemetry.ts#L208)
1145
+ Defined in: [packages/core/src/telemetry.ts:206](https://github.com/btravers/amqp-contract/blob/a5ff0e58db355e3410ea3b765884871c3b44c87d/packages/core/src/telemetry.ts#L206)
986
1146
 
987
1147
  Create a span for a publish operation.
988
1148
  Returns undefined if OpenTelemetry is not available.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amqp-contract/core",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Core utilities for AMQP setup and management in amqp-contract",
5
5
  "keywords": [
6
6
  "amqp",
@@ -53,7 +53,7 @@
53
53
  "@swan-io/boxed": "3.2.1",
54
54
  "amqp-connection-manager": "5.0.0",
55
55
  "amqplib": "0.10.9",
56
- "@amqp-contract/contract": "0.18.0"
56
+ "@amqp-contract/contract": "0.19.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@opentelemetry/api": "1.9.0",
@@ -64,7 +64,7 @@
64
64
  "typescript": "5.9.3",
65
65
  "vitest": "4.0.18",
66
66
  "zod": "4.3.6",
67
- "@amqp-contract/testing": "0.18.0",
67
+ "@amqp-contract/testing": "0.19.0",
68
68
  "@amqp-contract/tsconfig": "0.1.0",
69
69
  "@amqp-contract/typedoc": "0.1.0"
70
70
  },