@amqp-contract/core 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.cjs +105 -41
- package/dist/index.d.cts +105 -62
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +103 -60
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +98 -29
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +361 -81
- package/package.json +25 -25
package/README.md
CHANGED
|
@@ -41,8 +41,8 @@ import {
|
|
|
41
41
|
import { z } from "zod";
|
|
42
42
|
|
|
43
43
|
// Define resources
|
|
44
|
-
const ordersExchange = defineExchange("orders"
|
|
45
|
-
const orderProcessingQueue = defineQueue("order-processing"
|
|
44
|
+
const ordersExchange = defineExchange("orders");
|
|
45
|
+
const orderProcessingQueue = defineQueue("order-processing");
|
|
46
46
|
const orderMessage = defineMessage(z.object({ orderId: z.string() }));
|
|
47
47
|
|
|
48
48
|
const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value:
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
//#region \0rolldown/runtime.js
|
|
3
3
|
var __create = Object.create;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -7,16 +7,12 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
9
|
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
}
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
20
16
|
}
|
|
21
17
|
return to;
|
|
22
18
|
};
|
|
@@ -24,13 +20,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
20
|
value: mod,
|
|
25
21
|
enumerable: true
|
|
26
22
|
}) : target, mod));
|
|
27
|
-
|
|
28
23
|
//#endregion
|
|
29
24
|
let _swan_io_boxed = require("@swan-io/boxed");
|
|
30
25
|
let amqp_connection_manager = require("amqp-connection-manager");
|
|
31
|
-
amqp_connection_manager = __toESM(amqp_connection_manager);
|
|
26
|
+
amqp_connection_manager = __toESM(amqp_connection_manager, 1);
|
|
32
27
|
let _amqp_contract_contract = require("@amqp-contract/contract");
|
|
33
|
-
|
|
34
28
|
//#region src/connection-manager.ts
|
|
35
29
|
/**
|
|
36
30
|
* Connection manager singleton for sharing AMQP connections across clients.
|
|
@@ -145,6 +139,14 @@ var ConnectionManagerSingleton = class ConnectionManagerSingleton {
|
|
|
145
139
|
return value;
|
|
146
140
|
}
|
|
147
141
|
/**
|
|
142
|
+
* Get the number of active pooled connections.
|
|
143
|
+
*
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
_getConnectionCountForTesting() {
|
|
147
|
+
return this.connections.size;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
148
150
|
* Reset all cached connections (for testing purposes)
|
|
149
151
|
* @internal
|
|
150
152
|
*/
|
|
@@ -155,7 +157,6 @@ var ConnectionManagerSingleton = class ConnectionManagerSingleton {
|
|
|
155
157
|
this.refCounts.clear();
|
|
156
158
|
}
|
|
157
159
|
};
|
|
158
|
-
|
|
159
160
|
//#endregion
|
|
160
161
|
//#region src/errors.ts
|
|
161
162
|
/**
|
|
@@ -192,7 +193,6 @@ var MessageValidationError = class extends Error {
|
|
|
192
193
|
if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
|
|
193
194
|
}
|
|
194
195
|
};
|
|
195
|
-
|
|
196
196
|
//#endregion
|
|
197
197
|
//#region src/setup.ts
|
|
198
198
|
/**
|
|
@@ -216,13 +216,20 @@ var MessageValidationError = class extends Error {
|
|
|
216
216
|
* ```
|
|
217
217
|
*/
|
|
218
218
|
async function setupAmqpTopology(channel, contract) {
|
|
219
|
-
const
|
|
219
|
+
const exchanges = Object.values(contract.exchanges ?? {}).filter((e) => e.name !== "");
|
|
220
|
+
const exchangeErrors = (await Promise.allSettled(exchanges.map((exchange) => channel.assertExchange(exchange.name, exchange.type, {
|
|
220
221
|
durable: exchange.durable,
|
|
221
222
|
autoDelete: exchange.autoDelete,
|
|
222
223
|
internal: exchange.internal,
|
|
223
224
|
arguments: exchange.arguments
|
|
224
|
-
})))).
|
|
225
|
-
|
|
225
|
+
})))).map((result, i) => ({
|
|
226
|
+
result,
|
|
227
|
+
name: exchanges[i].name
|
|
228
|
+
})).filter((entry) => entry.result.status === "rejected");
|
|
229
|
+
if (exchangeErrors.length > 0) {
|
|
230
|
+
const names = exchangeErrors.map((e) => e.name).join(", ");
|
|
231
|
+
throw new AggregateError(exchangeErrors.map(({ result }) => result.reason), `Failed to setup exchanges: ${names}`);
|
|
232
|
+
}
|
|
226
233
|
for (const queueEntry of Object.values(contract.queues ?? {})) {
|
|
227
234
|
const queue = (0, _amqp_contract_contract.extractQueue)(queueEntry);
|
|
228
235
|
if (queue.deadLetter) {
|
|
@@ -230,7 +237,8 @@ async function setupAmqpTopology(channel, contract) {
|
|
|
230
237
|
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.`);
|
|
231
238
|
}
|
|
232
239
|
}
|
|
233
|
-
const
|
|
240
|
+
const queueEntries = Object.values(contract.queues ?? {});
|
|
241
|
+
const queueErrors = (await Promise.allSettled(queueEntries.map((queueEntry) => {
|
|
234
242
|
const queue = (0, _amqp_contract_contract.extractQueue)(queueEntry);
|
|
235
243
|
const queueArguments = { ...queue.arguments };
|
|
236
244
|
queueArguments["x-queue-type"] = queue.type;
|
|
@@ -238,29 +246,41 @@ async function setupAmqpTopology(channel, contract) {
|
|
|
238
246
|
queueArguments["x-dead-letter-exchange"] = queue.deadLetter.exchange.name;
|
|
239
247
|
if (queue.deadLetter.routingKey) queueArguments["x-dead-letter-routing-key"] = queue.deadLetter.routingKey;
|
|
240
248
|
}
|
|
241
|
-
if (queue.type === "quorum") {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
arguments: queueArguments
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
+
if (queue.type === "quorum") return channel.assertQueue(queue.name, {
|
|
250
|
+
durable: true,
|
|
251
|
+
arguments: queueArguments
|
|
252
|
+
});
|
|
253
|
+
if (queue.maxPriority !== void 0) queueArguments["x-max-priority"] = queue.maxPriority;
|
|
249
254
|
return channel.assertQueue(queue.name, {
|
|
250
255
|
durable: queue.durable,
|
|
251
256
|
exclusive: queue.exclusive,
|
|
252
257
|
autoDelete: queue.autoDelete,
|
|
253
258
|
arguments: queueArguments
|
|
254
259
|
});
|
|
255
|
-
}))).
|
|
256
|
-
|
|
257
|
-
|
|
260
|
+
}))).map((result, i) => ({
|
|
261
|
+
result,
|
|
262
|
+
name: (0, _amqp_contract_contract.extractQueue)(queueEntries[i]).name
|
|
263
|
+
})).filter((entry) => entry.result.status === "rejected");
|
|
264
|
+
if (queueErrors.length > 0) {
|
|
265
|
+
const names = queueErrors.map((e) => e.name).join(", ");
|
|
266
|
+
throw new AggregateError(queueErrors.map(({ result }) => result.reason), `Failed to setup queues: ${names}`);
|
|
267
|
+
}
|
|
268
|
+
const bindings = Object.values(contract.bindings ?? {});
|
|
269
|
+
const bindingErrors = (await Promise.allSettled(bindings.map((binding) => {
|
|
258
270
|
if (binding.type === "queue") return channel.bindQueue(binding.queue.name, binding.exchange.name, binding.routingKey ?? "", binding.arguments);
|
|
259
271
|
return channel.bindExchange(binding.destination.name, binding.source.name, binding.routingKey ?? "", binding.arguments);
|
|
260
|
-
}))).
|
|
261
|
-
|
|
272
|
+
}))).map((result, i) => {
|
|
273
|
+
const binding = bindings[i];
|
|
274
|
+
return {
|
|
275
|
+
result,
|
|
276
|
+
name: binding.type === "queue" ? `${binding.exchange.name} -> ${binding.queue.name}` : `${binding.source.name} -> ${binding.destination.name}`
|
|
277
|
+
};
|
|
278
|
+
}).filter((entry) => entry.result.status === "rejected");
|
|
279
|
+
if (bindingErrors.length > 0) {
|
|
280
|
+
const names = bindingErrors.map((e) => e.name).join(", ");
|
|
281
|
+
throw new AggregateError(bindingErrors.map(({ result }) => result.reason), `Failed to setup bindings: ${names}`);
|
|
282
|
+
}
|
|
262
283
|
}
|
|
263
|
-
|
|
264
284
|
//#endregion
|
|
265
285
|
//#region src/amqp-client.ts
|
|
266
286
|
/**
|
|
@@ -310,6 +330,7 @@ var AmqpClient = class {
|
|
|
310
330
|
channelWrapper;
|
|
311
331
|
urls;
|
|
312
332
|
connectionOptions;
|
|
333
|
+
connectTimeoutMs;
|
|
313
334
|
/**
|
|
314
335
|
* Create a new AMQP client instance.
|
|
315
336
|
*
|
|
@@ -325,10 +346,13 @@ var AmqpClient = class {
|
|
|
325
346
|
this.contract = contract;
|
|
326
347
|
this.urls = options.urls;
|
|
327
348
|
if (options.connectionOptions !== void 0) this.connectionOptions = options.connectionOptions;
|
|
328
|
-
|
|
349
|
+
if (options.connectTimeoutMs !== void 0) this.connectTimeoutMs = options.connectTimeoutMs;
|
|
350
|
+
const singleton = ConnectionManagerSingleton.getInstance();
|
|
351
|
+
this.connection = singleton.getConnection(options.urls, options.connectionOptions);
|
|
329
352
|
const defaultSetup = (channel) => setupAmqpTopology(channel, this.contract);
|
|
330
353
|
const { setup: userSetup, ...otherChannelOptions } = options.channelOptions ?? {};
|
|
331
354
|
const channelOpts = {
|
|
355
|
+
confirm: true,
|
|
332
356
|
json: true,
|
|
333
357
|
setup: defaultSetup,
|
|
334
358
|
...otherChannelOptions
|
|
@@ -354,10 +378,36 @@ var AmqpClient = class {
|
|
|
354
378
|
/**
|
|
355
379
|
* Wait for the channel to be connected and ready.
|
|
356
380
|
*
|
|
357
|
-
*
|
|
381
|
+
* If `connectTimeoutMs` was provided in the constructor options, the returned
|
|
382
|
+
* Future resolves to `Result.Error<TechnicalError>` once the timeout elapses.
|
|
383
|
+
* Without a timeout, this waits forever — amqp-connection-manager retries
|
|
384
|
+
* connections indefinitely and never errors on its own.
|
|
385
|
+
*
|
|
386
|
+
* NOTE: When using `AmqpClient` directly (not via `TypedAmqpClient` /
|
|
387
|
+
* `TypedAmqpWorker`), the constructor has already incremented the pooled
|
|
388
|
+
* connection's reference count. Callers must invoke `close()` on the error
|
|
389
|
+
* path to release the connection — `waitForConnect` does not do this
|
|
390
|
+
* automatically. The typed factories handle this cleanup for you.
|
|
391
|
+
*
|
|
392
|
+
* @returns A Future resolving to `Result.Ok(void)` on connect, or
|
|
393
|
+
* `Result.Error(TechnicalError)` on timeout / connection failure.
|
|
358
394
|
*/
|
|
359
395
|
waitForConnect() {
|
|
360
|
-
|
|
396
|
+
const connectPromise = this.channelWrapper.waitForConnect();
|
|
397
|
+
const racedPromise = this.connectTimeoutMs === void 0 ? connectPromise : new Promise((resolve, reject) => {
|
|
398
|
+
const timeoutMs = this.connectTimeoutMs;
|
|
399
|
+
const handle = setTimeout(() => {
|
|
400
|
+
reject(/* @__PURE__ */ new Error(`Timed out waiting for AMQP connection after ${timeoutMs}ms`));
|
|
401
|
+
}, timeoutMs);
|
|
402
|
+
connectPromise.then(() => {
|
|
403
|
+
clearTimeout(handle);
|
|
404
|
+
resolve();
|
|
405
|
+
}, (error) => {
|
|
406
|
+
clearTimeout(handle);
|
|
407
|
+
reject(error);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
return _swan_io_boxed.Future.fromPromise(racedPromise).mapError((error) => new TechnicalError("Failed to connect to AMQP broker", error));
|
|
361
411
|
}
|
|
362
412
|
/**
|
|
363
413
|
* Publish a message to an exchange.
|
|
@@ -372,6 +422,17 @@ var AmqpClient = class {
|
|
|
372
422
|
return _swan_io_boxed.Future.fromPromise(this.channelWrapper.publish(exchange, routingKey, content, options)).mapError((error) => new TechnicalError("Failed to publish message", error));
|
|
373
423
|
}
|
|
374
424
|
/**
|
|
425
|
+
* Publish a message directly to a queue.
|
|
426
|
+
*
|
|
427
|
+
* @param queue - The queue name
|
|
428
|
+
* @param content - The message content (will be JSON serialized if json: true)
|
|
429
|
+
* @param options - Optional publish options
|
|
430
|
+
* @returns A Future with `Result<boolean>` - true if message was sent, false if channel buffer is full
|
|
431
|
+
*/
|
|
432
|
+
sendToQueue(queue, content, options) {
|
|
433
|
+
return _swan_io_boxed.Future.fromPromise(this.channelWrapper.sendToQueue(queue, content, options)).mapError((error) => new TechnicalError("Failed to publish message to queue", error));
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
375
436
|
* Start consuming messages from a queue.
|
|
376
437
|
*
|
|
377
438
|
* @param queue - The queue name
|
|
@@ -445,7 +506,10 @@ var AmqpClient = class {
|
|
|
445
506
|
* @returns A Future that resolves when the channel and connection are closed
|
|
446
507
|
*/
|
|
447
508
|
close() {
|
|
448
|
-
return _swan_io_boxed.Future.fromPromise(this.channelWrapper.close()).mapError((error) => new TechnicalError("Failed to close channel", error)).
|
|
509
|
+
return _swan_io_boxed.Future.fromPromise(this.channelWrapper.close()).mapError((error) => new TechnicalError("Failed to close channel", error)).flatMap((channelResult) => _swan_io_boxed.Future.fromPromise(ConnectionManagerSingleton.getInstance().releaseConnection(this.urls, this.connectionOptions)).mapError((error) => new TechnicalError("Failed to release connection", error)).map((releaseResult) => {
|
|
510
|
+
if (channelResult.isError() && releaseResult.isError()) return _swan_io_boxed.Result.Error(new TechnicalError("Failed to close channel and release connection", new AggregateError([channelResult.error, releaseResult.error], "Failed to close channel and release connection")));
|
|
511
|
+
return channelResult.isError() ? channelResult : releaseResult;
|
|
512
|
+
}));
|
|
449
513
|
}
|
|
450
514
|
/**
|
|
451
515
|
* Reset connection singleton cache (for testing only)
|
|
@@ -455,7 +519,6 @@ var AmqpClient = class {
|
|
|
455
519
|
await ConnectionManagerSingleton.getInstance()._resetForTesting();
|
|
456
520
|
}
|
|
457
521
|
};
|
|
458
|
-
|
|
459
522
|
//#endregion
|
|
460
523
|
//#region src/telemetry.ts
|
|
461
524
|
/**
|
|
@@ -464,7 +527,9 @@ var AmqpClient = class {
|
|
|
464
527
|
* @see https://opentelemetry.io/docs/specs/otel/trace/api/#spankind
|
|
465
528
|
*/
|
|
466
529
|
const SpanKind = {
|
|
530
|
+
/** Producer span represents a message producer */
|
|
467
531
|
PRODUCER: 3,
|
|
532
|
+
/** Consumer span represents a message consumer */
|
|
468
533
|
CONSUMER: 4
|
|
469
534
|
};
|
|
470
535
|
/**
|
|
@@ -679,7 +744,6 @@ function _resetTelemetryCacheForTesting() {
|
|
|
679
744
|
cachedPublishLatencyHistogram = void 0;
|
|
680
745
|
cachedConsumeLatencyHistogram = void 0;
|
|
681
746
|
}
|
|
682
|
-
|
|
683
747
|
//#endregion
|
|
684
748
|
exports.AmqpClient = AmqpClient;
|
|
685
749
|
exports.ConnectionManagerSingleton = ConnectionManagerSingleton;
|
|
@@ -694,4 +758,4 @@ exports.recordConsumeMetric = recordConsumeMetric;
|
|
|
694
758
|
exports.recordPublishMetric = recordPublishMetric;
|
|
695
759
|
exports.setupAmqpTopology = setupAmqpTopology;
|
|
696
760
|
exports.startConsumeSpan = startConsumeSpan;
|
|
697
|
-
exports.startPublishSpan = startPublishSpan;
|
|
761
|
+
exports.startPublishSpan = startPublishSpan;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,65 +1,9 @@
|
|
|
1
|
+
import { ContractDefinition } from "@amqp-contract/contract";
|
|
2
|
+
import { Future, Result } from "@swan-io/boxed";
|
|
1
3
|
import { AmqpConnectionManager, AmqpConnectionManagerOptions, ConnectionUrl, CreateChannelOpts } from "amqp-connection-manager";
|
|
2
4
|
import { Channel, ConsumeMessage, Options } from "amqplib";
|
|
3
|
-
import { Future, Result } from "@swan-io/boxed";
|
|
4
|
-
import { ContractDefinition } from "@amqp-contract/contract";
|
|
5
5
|
import { Attributes, Counter, Histogram, Span, Tracer } from "@opentelemetry/api";
|
|
6
6
|
|
|
7
|
-
//#region src/logger.d.ts
|
|
8
|
-
/**
|
|
9
|
-
* Context object for logger methods.
|
|
10
|
-
*
|
|
11
|
-
* This type includes reserved keys that provide consistent naming
|
|
12
|
-
* for common logging context properties.
|
|
13
|
-
*
|
|
14
|
-
* @property error - Error object or error details
|
|
15
|
-
*/
|
|
16
|
-
type LoggerContext = Record<string, unknown> & {
|
|
17
|
-
error?: unknown;
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Logger interface for amqp-contract packages.
|
|
21
|
-
*
|
|
22
|
-
* Provides a simple logging abstraction that can be implemented by users
|
|
23
|
-
* to integrate with their preferred logging framework.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* // Simple console logger implementation
|
|
28
|
-
* const logger: Logger = {
|
|
29
|
-
* debug: (message, context) => console.debug(message, context),
|
|
30
|
-
* info: (message, context) => console.info(message, context),
|
|
31
|
-
* warn: (message, context) => console.warn(message, context),
|
|
32
|
-
* error: (message, context) => console.error(message, context),
|
|
33
|
-
* };
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
type Logger = {
|
|
37
|
-
/**
|
|
38
|
-
* Log debug level messages
|
|
39
|
-
* @param message - The log message
|
|
40
|
-
* @param context - Optional context to include with the log
|
|
41
|
-
*/
|
|
42
|
-
debug(message: string, context?: LoggerContext): void;
|
|
43
|
-
/**
|
|
44
|
-
* Log info level messages
|
|
45
|
-
* @param message - The log message
|
|
46
|
-
* @param context - Optional context to include with the log
|
|
47
|
-
*/
|
|
48
|
-
info(message: string, context?: LoggerContext): void;
|
|
49
|
-
/**
|
|
50
|
-
* Log warning level messages
|
|
51
|
-
* @param message - The log message
|
|
52
|
-
* @param context - Optional context to include with the log
|
|
53
|
-
*/
|
|
54
|
-
warn(message: string, context?: LoggerContext): void;
|
|
55
|
-
/**
|
|
56
|
-
* Log error level messages
|
|
57
|
-
* @param message - The log message
|
|
58
|
-
* @param context - Optional context to include with the log
|
|
59
|
-
*/
|
|
60
|
-
error(message: string, context?: LoggerContext): void;
|
|
61
|
-
};
|
|
62
|
-
//#endregion
|
|
63
7
|
//#region src/errors.d.ts
|
|
64
8
|
/**
|
|
65
9
|
* Error for technical/runtime failures that cannot be prevented by TypeScript.
|
|
@@ -93,16 +37,31 @@ declare class MessageValidationError extends Error {
|
|
|
93
37
|
* @property urls - AMQP broker URL(s). Multiple URLs provide failover support.
|
|
94
38
|
* @property connectionOptions - Optional connection configuration (heartbeat, reconnect settings, etc.).
|
|
95
39
|
* @property channelOptions - Optional channel configuration options.
|
|
40
|
+
* @property connectTimeoutMs - Maximum time in ms to wait for the channel to become ready
|
|
41
|
+
* in `waitForConnect`. If unset, waits forever (amqp-connection-manager retries indefinitely).
|
|
96
42
|
*/
|
|
97
43
|
type AmqpClientOptions = {
|
|
98
44
|
urls: ConnectionUrl[];
|
|
99
45
|
connectionOptions?: AmqpConnectionManagerOptions | undefined;
|
|
100
46
|
channelOptions?: Partial<CreateChannelOpts> | undefined;
|
|
47
|
+
connectTimeoutMs?: number | undefined;
|
|
101
48
|
};
|
|
102
49
|
/**
|
|
103
50
|
* Callback type for consuming messages.
|
|
104
51
|
*/
|
|
105
52
|
type ConsumeCallback = (msg: ConsumeMessage | null) => void | Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Publish options that extend amqplib's Options.Publish with optional timeout support.
|
|
55
|
+
*/
|
|
56
|
+
type PublishOptions = Options.Publish & {
|
|
57
|
+
/** Message will be rejected after timeout ms */timeout?: number;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Consume options that extend amqplib's Options.Consume with optional prefetch support.
|
|
61
|
+
*/
|
|
62
|
+
type ConsumerOptions = Options.Consume & {
|
|
63
|
+
/** Number of messages to prefetch */prefetch?: number;
|
|
64
|
+
};
|
|
106
65
|
/**
|
|
107
66
|
* AMQP client that manages connections and channels with automatic topology setup.
|
|
108
67
|
*
|
|
@@ -137,6 +96,7 @@ declare class AmqpClient {
|
|
|
137
96
|
private readonly channelWrapper;
|
|
138
97
|
private readonly urls;
|
|
139
98
|
private readonly connectionOptions?;
|
|
99
|
+
private readonly connectTimeoutMs?;
|
|
140
100
|
/**
|
|
141
101
|
* Create a new AMQP client instance.
|
|
142
102
|
*
|
|
@@ -162,7 +122,19 @@ declare class AmqpClient {
|
|
|
162
122
|
/**
|
|
163
123
|
* Wait for the channel to be connected and ready.
|
|
164
124
|
*
|
|
165
|
-
*
|
|
125
|
+
* If `connectTimeoutMs` was provided in the constructor options, the returned
|
|
126
|
+
* Future resolves to `Result.Error<TechnicalError>` once the timeout elapses.
|
|
127
|
+
* Without a timeout, this waits forever — amqp-connection-manager retries
|
|
128
|
+
* connections indefinitely and never errors on its own.
|
|
129
|
+
*
|
|
130
|
+
* NOTE: When using `AmqpClient` directly (not via `TypedAmqpClient` /
|
|
131
|
+
* `TypedAmqpWorker`), the constructor has already incremented the pooled
|
|
132
|
+
* connection's reference count. Callers must invoke `close()` on the error
|
|
133
|
+
* path to release the connection — `waitForConnect` does not do this
|
|
134
|
+
* automatically. The typed factories handle this cleanup for you.
|
|
135
|
+
*
|
|
136
|
+
* @returns A Future resolving to `Result.Ok(void)` on connect, or
|
|
137
|
+
* `Result.Error(TechnicalError)` on timeout / connection failure.
|
|
166
138
|
*/
|
|
167
139
|
waitForConnect(): Future<Result<void, TechnicalError>>;
|
|
168
140
|
/**
|
|
@@ -174,7 +146,16 @@ declare class AmqpClient {
|
|
|
174
146
|
* @param options - Optional publish options
|
|
175
147
|
* @returns A Future with `Result<boolean>` - true if message was sent, false if channel buffer is full
|
|
176
148
|
*/
|
|
177
|
-
publish(exchange: string, routingKey: string, content: Buffer | unknown, options?:
|
|
149
|
+
publish(exchange: string, routingKey: string, content: Buffer | unknown, options?: PublishOptions): Future<Result<boolean, TechnicalError>>;
|
|
150
|
+
/**
|
|
151
|
+
* Publish a message directly to a queue.
|
|
152
|
+
*
|
|
153
|
+
* @param queue - The queue name
|
|
154
|
+
* @param content - The message content (will be JSON serialized if json: true)
|
|
155
|
+
* @param options - Optional publish options
|
|
156
|
+
* @returns A Future with `Result<boolean>` - true if message was sent, false if channel buffer is full
|
|
157
|
+
*/
|
|
158
|
+
sendToQueue(queue: string, content: Buffer | unknown, options?: PublishOptions): Future<Result<boolean, TechnicalError>>;
|
|
178
159
|
/**
|
|
179
160
|
* Start consuming messages from a queue.
|
|
180
161
|
*
|
|
@@ -183,7 +164,7 @@ declare class AmqpClient {
|
|
|
183
164
|
* @param options - Optional consume options
|
|
184
165
|
* @returns A Future with `Result<string>` - the consumer tag
|
|
185
166
|
*/
|
|
186
|
-
consume(queue: string, callback: ConsumeCallback, options?:
|
|
167
|
+
consume(queue: string, callback: ConsumeCallback, options?: ConsumerOptions): Future<Result<string, TechnicalError>>;
|
|
187
168
|
/**
|
|
188
169
|
* Cancel a consumer by its consumer tag.
|
|
189
170
|
*
|
|
@@ -319,6 +300,12 @@ declare class ConnectionManagerSingleton {
|
|
|
319
300
|
* @returns The value with all object keys sorted alphabetically
|
|
320
301
|
*/
|
|
321
302
|
private deepSort;
|
|
303
|
+
/**
|
|
304
|
+
* Get the number of active pooled connections.
|
|
305
|
+
*
|
|
306
|
+
* @internal
|
|
307
|
+
*/
|
|
308
|
+
_getConnectionCountForTesting(): number;
|
|
322
309
|
/**
|
|
323
310
|
* Reset all cached connections (for testing purposes)
|
|
324
311
|
* @internal
|
|
@@ -326,6 +313,62 @@ declare class ConnectionManagerSingleton {
|
|
|
326
313
|
_resetForTesting(): Promise<void>;
|
|
327
314
|
}
|
|
328
315
|
//#endregion
|
|
316
|
+
//#region src/logger.d.ts
|
|
317
|
+
/**
|
|
318
|
+
* Context object for logger methods.
|
|
319
|
+
*
|
|
320
|
+
* This type includes reserved keys that provide consistent naming
|
|
321
|
+
* for common logging context properties.
|
|
322
|
+
*
|
|
323
|
+
* @property error - Error object or error details
|
|
324
|
+
*/
|
|
325
|
+
type LoggerContext = Record<string, unknown> & {
|
|
326
|
+
error?: unknown;
|
|
327
|
+
};
|
|
328
|
+
/**
|
|
329
|
+
* Logger interface for amqp-contract packages.
|
|
330
|
+
*
|
|
331
|
+
* Provides a simple logging abstraction that can be implemented by users
|
|
332
|
+
* to integrate with their preferred logging framework.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```typescript
|
|
336
|
+
* // Simple console logger implementation
|
|
337
|
+
* const logger: Logger = {
|
|
338
|
+
* debug: (message, context) => console.debug(message, context),
|
|
339
|
+
* info: (message, context) => console.info(message, context),
|
|
340
|
+
* warn: (message, context) => console.warn(message, context),
|
|
341
|
+
* error: (message, context) => console.error(message, context),
|
|
342
|
+
* };
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
type Logger = {
|
|
346
|
+
/**
|
|
347
|
+
* Log debug level messages
|
|
348
|
+
* @param message - The log message
|
|
349
|
+
* @param context - Optional context to include with the log
|
|
350
|
+
*/
|
|
351
|
+
debug(message: string, context?: LoggerContext): void;
|
|
352
|
+
/**
|
|
353
|
+
* Log info level messages
|
|
354
|
+
* @param message - The log message
|
|
355
|
+
* @param context - Optional context to include with the log
|
|
356
|
+
*/
|
|
357
|
+
info(message: string, context?: LoggerContext): void;
|
|
358
|
+
/**
|
|
359
|
+
* Log warning level messages
|
|
360
|
+
* @param message - The log message
|
|
361
|
+
* @param context - Optional context to include with the log
|
|
362
|
+
*/
|
|
363
|
+
warn(message: string, context?: LoggerContext): void;
|
|
364
|
+
/**
|
|
365
|
+
* Log error level messages
|
|
366
|
+
* @param message - The log message
|
|
367
|
+
* @param context - Optional context to include with the log
|
|
368
|
+
*/
|
|
369
|
+
error(message: string, context?: LoggerContext): void;
|
|
370
|
+
};
|
|
371
|
+
//#endregion
|
|
329
372
|
//#region src/setup.d.ts
|
|
330
373
|
/**
|
|
331
374
|
* Setup AMQP topology (exchanges, queues, and bindings) from a contract definition.
|
|
@@ -438,5 +481,5 @@ declare function recordConsumeMetric(provider: TelemetryProvider, queueName: str
|
|
|
438
481
|
*/
|
|
439
482
|
declare function _resetTelemetryCacheForTesting(): void;
|
|
440
483
|
//#endregion
|
|
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 };
|
|
484
|
+
export { AmqpClient, type AmqpClientOptions, ConnectionManagerSingleton, type ConsumeCallback, type ConsumerOptions, type Logger, type LoggerContext, MessageValidationError, MessagingSemanticConventions, type PublishOptions, TechnicalError, type TelemetryProvider, _resetTelemetryCacheForTesting, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordConsumeMetric, recordPublishMetric, setupAmqpTopology, startConsumeSpan, startPublishSpan };
|
|
442
485
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/amqp-client.ts","../src/connection-manager.ts","../src/logger.ts","../src/setup.ts","../src/telemetry.ts"],"mappings":"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"}
|