@linagora/rabbitmq-client 0.4.1 → 0.5.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.
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from 'events';
2
- import { d as RabbitMQMessageProperties } from '../types-D29GyoZX.cjs';
2
+ import { e as RabbitMQMessageProperties } from '../types-Cjg-65Ef.cjs';
3
3
 
4
4
  interface MockFn {
5
5
  (...args: unknown[]): unknown;
@@ -20,6 +20,7 @@ declare class MockRabbitMQChannel extends EventEmitter {
20
20
  private _consumeCallback;
21
21
  isClosed: boolean;
22
22
  readonly assertExchange: MockFn;
23
+ readonly checkExchange: MockFn;
23
24
  readonly assertQueue: MockFn;
24
25
  readonly bindQueue: MockFn;
25
26
  readonly ack: MockFn;
@@ -77,6 +78,8 @@ declare class MockRabbitMQConnection extends EventEmitter {
77
78
  * Creates a new channel (simulates a reconnection / new confirm-channel).
78
79
  */
79
80
  createConfirmChannel(): Promise<MockRabbitMQChannel>;
81
+ /** Creates an untracked plain channel, as used for passive exchange checks. */
82
+ createChannel(): Promise<MockRabbitMQChannel>;
80
83
  close(): Promise<void>;
81
84
  /** Emits a close event and marks the connection as disconnected. */
82
85
  simulateClose(): void;
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from 'events';
2
- import { d as RabbitMQMessageProperties } from '../types-D29GyoZX.js';
2
+ import { e as RabbitMQMessageProperties } from '../types-Cjg-65Ef.js';
3
3
 
4
4
  interface MockFn {
5
5
  (...args: unknown[]): unknown;
@@ -20,6 +20,7 @@ declare class MockRabbitMQChannel extends EventEmitter {
20
20
  private _consumeCallback;
21
21
  isClosed: boolean;
22
22
  readonly assertExchange: MockFn;
23
+ readonly checkExchange: MockFn;
23
24
  readonly assertQueue: MockFn;
24
25
  readonly bindQueue: MockFn;
25
26
  readonly ack: MockFn;
@@ -77,6 +78,8 @@ declare class MockRabbitMQConnection extends EventEmitter {
77
78
  * Creates a new channel (simulates a reconnection / new confirm-channel).
78
79
  */
79
80
  createConfirmChannel(): Promise<MockRabbitMQChannel>;
81
+ /** Creates an untracked plain channel, as used for passive exchange checks. */
82
+ createChannel(): Promise<MockRabbitMQChannel>;
80
83
  close(): Promise<void>;
81
84
  /** Emits a close event and marks the connection as disconnected. */
82
85
  simulateClose(): void;
@@ -24,6 +24,7 @@ var MockRabbitMQChannel = class extends EventEmitter {
24
24
  isClosed = false;
25
25
  // Stubs
26
26
  assertExchange = mockFn().mockResolvedValue({});
27
+ checkExchange = mockFn().mockResolvedValue({});
27
28
  assertQueue = mockFn().mockResolvedValue({ queue: "" });
28
29
  bindQueue = mockFn().mockResolvedValue({});
29
30
  ack = mockFn();
@@ -74,10 +75,11 @@ var MockRabbitMQChannel = class extends EventEmitter {
74
75
  }
75
76
  _deliver(content, properties = {}) {
76
77
  if (!this._consumeCallback) return;
78
+ const { exchange = "", routingKey = "", ...amqpProperties } = properties;
77
79
  this._consumeCallback({
78
80
  content,
79
- fields: { deliveryTag: 1, redelivered: false, exchange: "", routingKey: "", consumerTag: "mock-consumer" },
80
- properties: { headers: {}, ...properties }
81
+ fields: { deliveryTag: 1, redelivered: false, exchange, routingKey, consumerTag: "mock-consumer" },
82
+ properties: { headers: {}, ...amqpProperties }
81
83
  });
82
84
  }
83
85
  /** Emits a close event and marks the channel as closed. */
@@ -137,6 +139,10 @@ var MockRabbitMQConnection = class extends EventEmitter {
137
139
  this._channels.push(ch);
138
140
  return Promise.resolve(ch);
139
141
  }
142
+ /** Creates an untracked plain channel, as used for passive exchange checks. */
143
+ createChannel() {
144
+ return Promise.resolve(new MockRabbitMQChannel());
145
+ }
140
146
  close() {
141
147
  this.isConnected = false;
142
148
  return Promise.resolve();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["import { EventEmitter } from 'events'\nimport type { RabbitMQMessageProperties } from '../types.js'\n\n// ---------------------------------------------------------------------------\n// Framework-agnostic mock function factory\n// ---------------------------------------------------------------------------\n\ninterface MockFn {\n (...args: unknown[]): unknown\n mock: { calls: unknown[][] }\n mockResolvedValue: (val: unknown) => MockFn\n mockImplementation: (fn: (...args: unknown[]) => unknown) => MockFn\n}\n\nfunction mockFn(): MockFn {\n let impl: ((...args: unknown[]) => unknown) | null = null\n const calls: unknown[][] = []\n\n const fn = ((...args: unknown[]) => {\n calls.push(args)\n return impl ? impl(...args) : undefined\n }) as MockFn\n\n fn.mock = { calls }\n\n fn.mockResolvedValue = (val: unknown) => {\n impl = () => Promise.resolve(val)\n return fn\n }\n\n fn.mockImplementation = (newImpl: (...args: unknown[]) => unknown) => {\n impl = newImpl\n return fn\n }\n\n return fn\n}\n\n// ---------------------------------------------------------------------------\n// Published message record\n// ---------------------------------------------------------------------------\n\nexport interface PublishedMessage {\n exchange: string\n routingKey: string\n message: unknown\n options: unknown\n}\n\n// ---------------------------------------------------------------------------\n// MockRabbitMQChannel\n// ---------------------------------------------------------------------------\n\nexport class MockRabbitMQChannel extends EventEmitter {\n private _publishedMessages: PublishedMessage[] = []\n private _consumeCallback: ((msg: unknown) => void) | null = null\n\n isClosed = false\n\n // Stubs\n readonly assertExchange = mockFn().mockResolvedValue({})\n readonly assertQueue = mockFn().mockResolvedValue({ queue: '' })\n readonly bindQueue = mockFn().mockResolvedValue({})\n readonly ack = mockFn()\n readonly nack = mockFn()\n readonly close = mockFn().mockResolvedValue(undefined)\n readonly waitForConfirms = mockFn().mockResolvedValue(undefined)\n readonly prefetch = mockFn().mockResolvedValue(undefined)\n readonly deleteQueue = mockFn().mockResolvedValue({})\n readonly cancel = mockFn().mockResolvedValue(undefined)\n\n /**\n * Tracks all published messages and stores them for later inspection.\n */\n publish(exchange: string, routingKey: string, content: Buffer, options?: unknown): boolean {\n let message: unknown\n try {\n message = JSON.parse(content.toString())\n } catch {\n message = content.toString()\n }\n this._publishedMessages.push({ exchange, routingKey, message, options })\n return true\n }\n\n private _consumerCounter = 0\n\n /**\n * Stores the consumer callback for use with simulateMessage.\n * Returns a unique consumer tag per call.\n */\n consume(_queue: string, callback: (msg: unknown) => void): Promise<{ consumerTag: string }> {\n this._consumeCallback = callback\n const consumerTag = `mock-consumer-${++this._consumerCounter}`\n return Promise.resolve({ consumerTag })\n }\n\n // ---------------------------------------------------------------------------\n // Simulation helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Delivers a valid JSON message to the registered consume callback, with\n * optional AMQP properties such as `headers` or `timestamp`.\n */\n simulateMessage(content: unknown, properties: Partial<RabbitMQMessageProperties> = {}): void {\n this._deliver(Buffer.from(JSON.stringify(content)), properties)\n }\n\n /**\n * Delivers a message with content that is not valid JSON.\n */\n simulateInvalidJsonMessage(): void {\n this._deliver(Buffer.from('not valid json {'))\n }\n\n private _deliver(content: Buffer, properties: Partial<RabbitMQMessageProperties> = {}): void {\n if (!this._consumeCallback) return\n this._consumeCallback({\n content,\n fields: { deliveryTag: 1, redelivered: false, exchange: '', routingKey: '', consumerTag: 'mock-consumer' },\n properties: { headers: {}, ...properties },\n })\n }\n\n /** Emits a close event and marks the channel as closed. */\n simulateClose(): void {\n this.isClosed = true\n this.emit('close')\n }\n\n /** Emits an error event. */\n simulateError(error: Error): void {\n this.emit('error', error)\n }\n\n // ---------------------------------------------------------------------------\n // Inspection helpers\n // ---------------------------------------------------------------------------\n\n getPublishedMessages(): PublishedMessage[] {\n return [...this._publishedMessages]\n }\n\n clearMessages(): void {\n this._publishedMessages = []\n }\n\n /** Resets all state back to initial values. */\n reset(): void {\n this._publishedMessages = []\n this._consumeCallback = null\n this._consumerCounter = 0\n this.isClosed = false\n this.removeAllListeners()\n }\n}\n\n// ---------------------------------------------------------------------------\n// MockRabbitMQConnection\n// ---------------------------------------------------------------------------\n\nexport class MockRabbitMQConnection extends EventEmitter {\n private _channels: MockRabbitMQChannel[] = []\n\n isConnected = true\n\n constructor() {\n super()\n // Create the initial channel eagerly so `conn.channel` is defined\n // before the first createConfirmChannel call.\n this._channels.push(new MockRabbitMQChannel())\n }\n\n /**\n * Returns the most recently created channel.\n */\n get channel(): MockRabbitMQChannel {\n return this._channels[this._channels.length - 1]\n }\n\n /**\n * Returns all channels created so far (including the initial one).\n */\n get channels(): MockRabbitMQChannel[] {\n return [...this._channels]\n }\n\n get channelCount(): number {\n return this._channels.length\n }\n\n /**\n * Creates a new channel (simulates a reconnection / new confirm-channel).\n */\n createConfirmChannel(): Promise<MockRabbitMQChannel> {\n const ch = new MockRabbitMQChannel()\n this._channels.push(ch)\n return Promise.resolve(ch)\n }\n\n close(): Promise<void> {\n this.isConnected = false\n return Promise.resolve()\n }\n\n /** Emits a close event and marks the connection as disconnected. */\n simulateClose(): void {\n this.isConnected = false\n this.emit('close')\n }\n\n /** Emits an error event. */\n simulateError(error: Error): void {\n this.emit('error', error)\n }\n\n /** Resets to the initial connected state with a single fresh channel. */\n reset(): void {\n this._channels = [new MockRabbitMQChannel()]\n this.isConnected = true\n this.removeAllListeners()\n }\n}\n\n// ---------------------------------------------------------------------------\n// createMockAmqplib\n// ---------------------------------------------------------------------------\n\nexport interface AmqpMock {\n connect: MockFn\n}\n\nexport interface MockAmqplibResult {\n mockConnection: MockRabbitMQConnection\n amqpMock: AmqpMock\n}\n\n/**\n * Returns a pre-wired { mockConnection, amqpMock } pair that can be used as\n * a drop-in replacement for amqplib in tests (e.g. via vi.mock or jest.mock).\n */\nexport function createMockAmqplib(): MockAmqplibResult {\n const mockConnection = new MockRabbitMQConnection()\n const amqpMock: AmqpMock = {\n connect: mockFn().mockResolvedValue(mockConnection),\n }\n return { mockConnection, amqpMock }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["import { EventEmitter } from 'events'\nimport type { RabbitMQMessageProperties } from '../types.js'\n\n// ---------------------------------------------------------------------------\n// Framework-agnostic mock function factory\n// ---------------------------------------------------------------------------\n\ninterface MockFn {\n (...args: unknown[]): unknown\n mock: { calls: unknown[][] }\n mockResolvedValue: (val: unknown) => MockFn\n mockImplementation: (fn: (...args: unknown[]) => unknown) => MockFn\n}\n\nfunction mockFn(): MockFn {\n let impl: ((...args: unknown[]) => unknown) | null = null\n const calls: unknown[][] = []\n\n const fn = ((...args: unknown[]) => {\n calls.push(args)\n return impl ? impl(...args) : undefined\n }) as MockFn\n\n fn.mock = { calls }\n\n fn.mockResolvedValue = (val: unknown) => {\n impl = () => Promise.resolve(val)\n return fn\n }\n\n fn.mockImplementation = (newImpl: (...args: unknown[]) => unknown) => {\n impl = newImpl\n return fn\n }\n\n return fn\n}\n\n// ---------------------------------------------------------------------------\n// Published message record\n// ---------------------------------------------------------------------------\n\nexport interface PublishedMessage {\n exchange: string\n routingKey: string\n message: unknown\n options: unknown\n}\n\n// ---------------------------------------------------------------------------\n// MockRabbitMQChannel\n// ---------------------------------------------------------------------------\n\nexport class MockRabbitMQChannel extends EventEmitter {\n private _publishedMessages: PublishedMessage[] = []\n private _consumeCallback: ((msg: unknown) => void) | null = null\n\n isClosed = false\n\n // Stubs\n readonly assertExchange = mockFn().mockResolvedValue({})\n readonly checkExchange = mockFn().mockResolvedValue({})\n readonly assertQueue = mockFn().mockResolvedValue({ queue: '' })\n readonly bindQueue = mockFn().mockResolvedValue({})\n readonly ack = mockFn()\n readonly nack = mockFn()\n readonly close = mockFn().mockResolvedValue(undefined)\n readonly waitForConfirms = mockFn().mockResolvedValue(undefined)\n readonly prefetch = mockFn().mockResolvedValue(undefined)\n readonly deleteQueue = mockFn().mockResolvedValue({})\n readonly cancel = mockFn().mockResolvedValue(undefined)\n\n /**\n * Tracks all published messages and stores them for later inspection.\n */\n publish(exchange: string, routingKey: string, content: Buffer, options?: unknown): boolean {\n let message: unknown\n try {\n message = JSON.parse(content.toString())\n } catch {\n message = content.toString()\n }\n this._publishedMessages.push({ exchange, routingKey, message, options })\n return true\n }\n\n private _consumerCounter = 0\n\n /**\n * Stores the consumer callback for use with simulateMessage.\n * Returns a unique consumer tag per call.\n */\n consume(_queue: string, callback: (msg: unknown) => void): Promise<{ consumerTag: string }> {\n this._consumeCallback = callback\n const consumerTag = `mock-consumer-${++this._consumerCounter}`\n return Promise.resolve({ consumerTag })\n }\n\n // ---------------------------------------------------------------------------\n // Simulation helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Delivers a valid JSON message to the registered consume callback, with\n * optional AMQP properties such as `headers` or `timestamp`.\n */\n simulateMessage(content: unknown, properties: Partial<RabbitMQMessageProperties> = {}): void {\n this._deliver(Buffer.from(JSON.stringify(content)), properties)\n }\n\n /**\n * Delivers a message with content that is not valid JSON.\n */\n simulateInvalidJsonMessage(): void {\n this._deliver(Buffer.from('not valid json {'))\n }\n\n private _deliver(content: Buffer, properties: Partial<RabbitMQMessageProperties> = {}): void {\n if (!this._consumeCallback) return\n const { exchange = '', routingKey = '', ...amqpProperties } = properties\n this._consumeCallback({\n content,\n fields: { deliveryTag: 1, redelivered: false, exchange, routingKey, consumerTag: 'mock-consumer' },\n properties: { headers: {}, ...amqpProperties },\n })\n }\n\n /** Emits a close event and marks the channel as closed. */\n simulateClose(): void {\n this.isClosed = true\n this.emit('close')\n }\n\n /** Emits an error event. */\n simulateError(error: Error): void {\n this.emit('error', error)\n }\n\n // ---------------------------------------------------------------------------\n // Inspection helpers\n // ---------------------------------------------------------------------------\n\n getPublishedMessages(): PublishedMessage[] {\n return [...this._publishedMessages]\n }\n\n clearMessages(): void {\n this._publishedMessages = []\n }\n\n /** Resets all state back to initial values. */\n reset(): void {\n this._publishedMessages = []\n this._consumeCallback = null\n this._consumerCounter = 0\n this.isClosed = false\n this.removeAllListeners()\n }\n}\n\n// ---------------------------------------------------------------------------\n// MockRabbitMQConnection\n// ---------------------------------------------------------------------------\n\nexport class MockRabbitMQConnection extends EventEmitter {\n private _channels: MockRabbitMQChannel[] = []\n\n isConnected = true\n\n constructor() {\n super()\n // Create the initial channel eagerly so `conn.channel` is defined\n // before the first createConfirmChannel call.\n this._channels.push(new MockRabbitMQChannel())\n }\n\n /**\n * Returns the most recently created channel.\n */\n get channel(): MockRabbitMQChannel {\n return this._channels[this._channels.length - 1]\n }\n\n /**\n * Returns all channels created so far (including the initial one).\n */\n get channels(): MockRabbitMQChannel[] {\n return [...this._channels]\n }\n\n get channelCount(): number {\n return this._channels.length\n }\n\n /**\n * Creates a new channel (simulates a reconnection / new confirm-channel).\n */\n createConfirmChannel(): Promise<MockRabbitMQChannel> {\n const ch = new MockRabbitMQChannel()\n this._channels.push(ch)\n return Promise.resolve(ch)\n }\n\n /** Creates an untracked plain channel, as used for passive exchange checks. */\n createChannel(): Promise<MockRabbitMQChannel> {\n return Promise.resolve(new MockRabbitMQChannel())\n }\n\n close(): Promise<void> {\n this.isConnected = false\n return Promise.resolve()\n }\n\n /** Emits a close event and marks the connection as disconnected. */\n simulateClose(): void {\n this.isConnected = false\n this.emit('close')\n }\n\n /** Emits an error event. */\n simulateError(error: Error): void {\n this.emit('error', error)\n }\n\n /** Resets to the initial connected state with a single fresh channel. */\n reset(): void {\n this._channels = [new MockRabbitMQChannel()]\n this.isConnected = true\n this.removeAllListeners()\n }\n}\n\n// ---------------------------------------------------------------------------\n// createMockAmqplib\n// ---------------------------------------------------------------------------\n\nexport interface AmqpMock {\n connect: MockFn\n}\n\nexport interface MockAmqplibResult {\n mockConnection: MockRabbitMQConnection\n amqpMock: AmqpMock\n}\n\n/**\n * Returns a pre-wired { mockConnection, amqpMock } pair that can be used as\n * a drop-in replacement for amqplib in tests (e.g. via vi.mock or jest.mock).\n */\nexport function createMockAmqplib(): MockAmqplibResult {\n const mockConnection = new MockRabbitMQConnection()\n const amqpMock: AmqpMock = {\n connect: mockFn().mockResolvedValue(mockConnection),\n }\n return { mockConnection, amqpMock }\n}\n"],"mappings":";AAAA,SAAS,oBAAoB;AAc7B,SAAS,SAAiB;AACxB,MAAI,OAAiD;AACrD,QAAM,QAAqB,CAAC;AAE5B,QAAM,MAAM,IAAI,SAAoB;AAClC,UAAM,KAAK,IAAI;AACf,WAAO,OAAO,KAAK,GAAG,IAAI,IAAI;AAAA,EAChC;AAEA,KAAG,OAAO,EAAE,MAAM;AAElB,KAAG,oBAAoB,CAAC,QAAiB;AACvC,WAAO,MAAM,QAAQ,QAAQ,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,KAAG,qBAAqB,CAAC,YAA6C;AACpE,WAAO;AACP,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAiBO,IAAM,sBAAN,cAAkC,aAAa;AAAA,EAC5C,qBAAyC,CAAC;AAAA,EAC1C,mBAAoD;AAAA,EAE5D,WAAW;AAAA;AAAA,EAGF,iBAAiB,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAAA,EAC9C,gBAAgB,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAAA,EAC7C,cAAc,OAAO,EAAE,kBAAkB,EAAE,OAAO,GAAG,CAAC;AAAA,EACtD,YAAY,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAAA,EACzC,MAAM,OAAO;AAAA,EACb,OAAO,OAAO;AAAA,EACd,QAAQ,OAAO,EAAE,kBAAkB,MAAS;AAAA,EAC5C,kBAAkB,OAAO,EAAE,kBAAkB,MAAS;AAAA,EACtD,WAAW,OAAO,EAAE,kBAAkB,MAAS;AAAA,EAC/C,cAAc,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAAA,EAC3C,SAAS,OAAO,EAAE,kBAAkB,MAAS;AAAA;AAAA;AAAA;AAAA,EAKtD,QAAQ,UAAkB,YAAoB,SAAiB,SAA4B;AACzF,QAAI;AACJ,QAAI;AACF,gBAAU,KAAK,MAAM,QAAQ,SAAS,CAAC;AAAA,IACzC,QAAQ;AACN,gBAAU,QAAQ,SAAS;AAAA,IAC7B;AACA,SAAK,mBAAmB,KAAK,EAAE,UAAU,YAAY,SAAS,QAAQ,CAAC;AACvE,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA,EAM3B,QAAQ,QAAgB,UAAoE;AAC1F,SAAK,mBAAmB;AACxB,UAAM,cAAc,iBAAiB,EAAE,KAAK,gBAAgB;AAC5D,WAAO,QAAQ,QAAQ,EAAE,YAAY,CAAC;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,gBAAgB,SAAkB,aAAiD,CAAC,GAAS;AAC3F,SAAK,SAAS,OAAO,KAAK,KAAK,UAAU,OAAO,CAAC,GAAG,UAAU;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKA,6BAAmC;AACjC,SAAK,SAAS,OAAO,KAAK,kBAAkB,CAAC;AAAA,EAC/C;AAAA,EAEQ,SAAS,SAAiB,aAAiD,CAAC,GAAS;AAC3F,QAAI,CAAC,KAAK,iBAAkB;AAC5B,UAAM,EAAE,WAAW,IAAI,aAAa,IAAI,GAAG,eAAe,IAAI;AAC9D,SAAK,iBAAiB;AAAA,MACpB;AAAA,MACA,QAAQ,EAAE,aAAa,GAAG,aAAa,OAAO,UAAU,YAAY,aAAa,gBAAgB;AAAA,MACjG,YAAY,EAAE,SAAS,CAAC,GAAG,GAAG,eAAe;AAAA,IAC/C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,gBAAsB;AACpB,SAAK,WAAW;AAChB,SAAK,KAAK,OAAO;AAAA,EACnB;AAAA;AAAA,EAGA,cAAc,OAAoB;AAChC,SAAK,KAAK,SAAS,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAMA,uBAA2C;AACzC,WAAO,CAAC,GAAG,KAAK,kBAAkB;AAAA,EACpC;AAAA,EAEA,gBAAsB;AACpB,SAAK,qBAAqB,CAAC;AAAA,EAC7B;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,qBAAqB,CAAC;AAC3B,SAAK,mBAAmB;AACxB,SAAK,mBAAmB;AACxB,SAAK,WAAW;AAChB,SAAK,mBAAmB;AAAA,EAC1B;AACF;AAMO,IAAM,yBAAN,cAAqC,aAAa;AAAA,EAC/C,YAAmC,CAAC;AAAA,EAE5C,cAAc;AAAA,EAEd,cAAc;AACZ,UAAM;AAGN,SAAK,UAAU,KAAK,IAAI,oBAAoB,CAAC;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAA+B;AACjC,WAAO,KAAK,UAAU,KAAK,UAAU,SAAS,CAAC;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAkC;AACpC,WAAO,CAAC,GAAG,KAAK,SAAS;AAAA,EAC3B;AAAA,EAEA,IAAI,eAAuB;AACzB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAqD;AACnD,UAAM,KAAK,IAAI,oBAAoB;AACnC,SAAK,UAAU,KAAK,EAAE;AACtB,WAAO,QAAQ,QAAQ,EAAE;AAAA,EAC3B;AAAA;AAAA,EAGA,gBAA8C;AAC5C,WAAO,QAAQ,QAAQ,IAAI,oBAAoB,CAAC;AAAA,EAClD;AAAA,EAEA,QAAuB;AACrB,SAAK,cAAc;AACnB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA;AAAA,EAGA,gBAAsB;AACpB,SAAK,cAAc;AACnB,SAAK,KAAK,OAAO;AAAA,EACnB;AAAA;AAAA,EAGA,cAAc,OAAoB;AAChC,SAAK,KAAK,SAAS,KAAK;AAAA,EAC1B;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,YAAY,CAAC,IAAI,oBAAoB,CAAC;AAC3C,SAAK,cAAc;AACnB,SAAK,mBAAmB;AAAA,EAC1B;AACF;AAmBO,SAAS,oBAAuC;AACrD,QAAM,iBAAiB,IAAI,uBAAuB;AAClD,QAAM,WAAqB;AAAA,IACzB,SAAS,OAAO,EAAE,kBAAkB,cAAc;AAAA,EACpD;AACA,SAAO,EAAE,gBAAgB,SAAS;AACpC;","names":[]}
@@ -39,7 +39,7 @@ interface RabbitMQHooks {
39
39
  exchange: string;
40
40
  routingKey: string;
41
41
  duration: number;
42
- reason: 'invalid_json' | 'max_retries_exhausted';
42
+ reason: 'invalid_json' | 'max_retries_exhausted' | 'dead_letter_error';
43
43
  }) => void;
44
44
  /** Called after reconnection completes and subscriptions are re-established */
45
45
  onReconnect?: (info: {
@@ -60,6 +60,27 @@ interface SubscribeOptions {
60
60
  * at once, and only throttles when set below `prefetch`. `0` means no limit.
61
61
  */
62
62
  concurrency?: number;
63
+ /** More exchanges and routing keys to bind the same queue to, consumed by the same handler */
64
+ bindings?: RabbitMQBinding[];
65
+ /** Dead-letter exchange name (default: `<exchange>.dlx`) */
66
+ deadLetterExchange?: string;
67
+ /**
68
+ * Check that the source exchanges exist instead of declaring them, for
69
+ * exchanges another service owns. Subscribing fails when one is missing.
70
+ */
71
+ passiveExchanges?: boolean;
72
+ /** Max handler attempts before the DLQ for this queue (overrides the client default); `Infinity` retries until the handler succeeds */
73
+ maxRetries?: number;
74
+ /**
75
+ * Double the delay between handler attempts, from `retryDelay` up to this
76
+ * many ms. Without it the delay stays at `retryDelay`.
77
+ */
78
+ maxRetryDelay?: number;
79
+ }
80
+ /** An exchange and routing key a queue is bound to */
81
+ interface RabbitMQBinding {
82
+ exchange: string;
83
+ routingKey: string;
63
84
  }
64
85
  /**
65
86
  * Configuration options for the RabbitMQ client.
@@ -119,6 +140,10 @@ interface PublishOptions {
119
140
  type RabbitMQMessage = Record<string, unknown>;
120
141
  /** What the publisher and the broker attached to a consumed message */
121
142
  interface RabbitMQMessageProperties {
143
+ /** Exchange the message was published to */
144
+ exchange: string;
145
+ /** Routing key the message was published with */
146
+ routingKey: string;
122
147
  /** AMQP headers, including broker-added ones such as `x-death` on a dead-lettered message */
123
148
  headers: Record<string, unknown>;
124
149
  /** AMQP timestamp in seconds, if the publisher set one */
@@ -139,4 +164,4 @@ interface RabbitMQSubscription {
139
164
  options?: SubscribeOptions;
140
165
  }
141
166
 
142
- export type { ILogger as I, PublishOptions as P, RabbitMQClientOptions as R, SubscribeOptions as S, RabbitMQMessage as a, RabbitMQMessageHandler as b, RabbitMQHooks as c, RabbitMQMessageProperties as d, RabbitMQSubscription as e };
167
+ export type { ILogger as I, PublishOptions as P, RabbitMQClientOptions as R, SubscribeOptions as S, RabbitMQMessage as a, RabbitMQMessageHandler as b, RabbitMQBinding as c, RabbitMQHooks as d, RabbitMQMessageProperties as e, RabbitMQSubscription as f };
@@ -39,7 +39,7 @@ interface RabbitMQHooks {
39
39
  exchange: string;
40
40
  routingKey: string;
41
41
  duration: number;
42
- reason: 'invalid_json' | 'max_retries_exhausted';
42
+ reason: 'invalid_json' | 'max_retries_exhausted' | 'dead_letter_error';
43
43
  }) => void;
44
44
  /** Called after reconnection completes and subscriptions are re-established */
45
45
  onReconnect?: (info: {
@@ -60,6 +60,27 @@ interface SubscribeOptions {
60
60
  * at once, and only throttles when set below `prefetch`. `0` means no limit.
61
61
  */
62
62
  concurrency?: number;
63
+ /** More exchanges and routing keys to bind the same queue to, consumed by the same handler */
64
+ bindings?: RabbitMQBinding[];
65
+ /** Dead-letter exchange name (default: `<exchange>.dlx`) */
66
+ deadLetterExchange?: string;
67
+ /**
68
+ * Check that the source exchanges exist instead of declaring them, for
69
+ * exchanges another service owns. Subscribing fails when one is missing.
70
+ */
71
+ passiveExchanges?: boolean;
72
+ /** Max handler attempts before the DLQ for this queue (overrides the client default); `Infinity` retries until the handler succeeds */
73
+ maxRetries?: number;
74
+ /**
75
+ * Double the delay between handler attempts, from `retryDelay` up to this
76
+ * many ms. Without it the delay stays at `retryDelay`.
77
+ */
78
+ maxRetryDelay?: number;
79
+ }
80
+ /** An exchange and routing key a queue is bound to */
81
+ interface RabbitMQBinding {
82
+ exchange: string;
83
+ routingKey: string;
63
84
  }
64
85
  /**
65
86
  * Configuration options for the RabbitMQ client.
@@ -119,6 +140,10 @@ interface PublishOptions {
119
140
  type RabbitMQMessage = Record<string, unknown>;
120
141
  /** What the publisher and the broker attached to a consumed message */
121
142
  interface RabbitMQMessageProperties {
143
+ /** Exchange the message was published to */
144
+ exchange: string;
145
+ /** Routing key the message was published with */
146
+ routingKey: string;
122
147
  /** AMQP headers, including broker-added ones such as `x-death` on a dead-lettered message */
123
148
  headers: Record<string, unknown>;
124
149
  /** AMQP timestamp in seconds, if the publisher set one */
@@ -139,4 +164,4 @@ interface RabbitMQSubscription {
139
164
  options?: SubscribeOptions;
140
165
  }
141
166
 
142
- export type { ILogger as I, PublishOptions as P, RabbitMQClientOptions as R, SubscribeOptions as S, RabbitMQMessage as a, RabbitMQMessageHandler as b, RabbitMQHooks as c, RabbitMQMessageProperties as d, RabbitMQSubscription as e };
167
+ export type { ILogger as I, PublishOptions as P, RabbitMQClientOptions as R, SubscribeOptions as S, RabbitMQMessage as a, RabbitMQMessageHandler as b, RabbitMQBinding as c, RabbitMQHooks as d, RabbitMQMessageProperties as e, RabbitMQSubscription as f };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linagora/rabbitmq-client",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Production-grade RabbitMQ client with confirm channels, DLQ infrastructure, auto-reconnection, exponential backoff, graceful shutdown, and observability hooks",
5
5
  "type": "module",
6
6
  "exports": {