@amqp-contract/client 0.25.0 → 2.0.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 CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  **Type-safe AMQP client for publishing messages using amqp-contract with explicit error handling via `Result` types.**
4
4
 
5
- [![CI](https://github.com/btravers/amqp-contract/actions/workflows/ci.yml/badge.svg)](https://github.com/btravers/amqp-contract/actions/workflows/ci.yml)
5
+ [![CI](https://github.com/btravstack/amqp-contract/actions/workflows/ci.yml/badge.svg)](https://github.com/btravstack/amqp-contract/actions/workflows/ci.yml)
6
6
  [![npm version](https://img.shields.io/npm/v/@amqp-contract/client.svg?logo=npm)](https://www.npmjs.com/package/@amqp-contract/client)
7
7
  [![npm downloads](https://img.shields.io/npm/dm/@amqp-contract/client.svg)](https://www.npmjs.com/package/@amqp-contract/client)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-6.0-blue?logo=typescript)](https://www.typescriptlang.org/)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
10
 
11
- 📖 **[Full documentation →](https://btravers.github.io/amqp-contract/api/client)**
11
+ 📖 **[Full documentation →](https://btravstack.github.io/amqp-contract/api/client)**
12
12
 
13
13
  ## Installation
14
14
 
@@ -28,17 +28,20 @@ const client = (
28
28
  contract,
29
29
  urls: ["amqp://localhost"],
30
30
  })
31
- )._unsafeUnwrap();
31
+ ).unwrap();
32
32
 
33
33
  // Publish message with explicit error handling
34
34
  const result = await client.publish("orderCreated", {
35
35
  orderId: "ORD-123",
36
36
  amount: 99.99,
37
37
  });
38
- result.match(
39
- () => console.log("Published successfully"),
40
- (error) => console.error("Publish failed:", error),
41
- );
38
+ result.match({
39
+ ok: () => console.log("Published successfully"),
40
+ err: (error) => console.error("Publish failed:", error),
41
+ defect: (cause) => {
42
+ throw cause;
43
+ },
44
+ });
42
45
 
43
46
  // Clean up
44
47
  await client.close();
@@ -46,7 +49,7 @@ await client.close();
46
49
 
47
50
  ## Error Handling
48
51
 
49
- The client uses `Result` types from [neverthrow](https://github.com/supermacro/neverthrow) for explicit error handling. Runtime errors are part of the type signature:
52
+ The client uses `Result` types from [unthrown](https://github.com/btravstack/unthrown) for explicit error handling. Runtime errors are part of the type signature:
50
53
 
51
54
  ```typescript
52
55
  publish(): Result<boolean, TechnicalError | MessageValidationError>
@@ -61,11 +64,11 @@ publish(): Result<boolean, TechnicalError | MessageValidationError>
61
64
 
62
65
  ## API
63
66
 
64
- For complete API documentation, see the [Client API Reference](https://btravers.github.io/amqp-contract/api/client).
67
+ For complete API documentation, see the [Client API Reference](https://btravstack.github.io/amqp-contract/api/client).
65
68
 
66
69
  ## Documentation
67
70
 
68
- 📖 **[Read the full documentation →](https://btravers.github.io/amqp-contract)**
71
+ 📖 **[Read the full documentation →](https://btravstack.github.io/amqp-contract)**
69
72
 
70
73
  ## License
71
74
 
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _amqp_contract_contract = require("@amqp-contract/contract");
3
3
  let _amqp_contract_core = require("@amqp-contract/core");
4
- let neverthrow = require("neverthrow");
4
+ let unthrown = require("unthrown");
5
5
  let node_crypto = require("node:crypto");
6
6
  let node_zlib = require("node:zlib");
7
7
  let node_util = require("node:util");
@@ -14,50 +14,47 @@ const deflateAsync = (0, node_util.promisify)(node_zlib.deflate);
14
14
  *
15
15
  * @param buffer - The buffer to compress
16
16
  * @param algorithm - The compression algorithm to use
17
- * @returns A ResultAsync resolving to the compressed buffer or a TechnicalError
17
+ * @returns An AsyncResult resolving to the compressed buffer or a TechnicalError
18
18
  *
19
19
  * @internal
20
20
  */
21
21
  function compressBuffer(buffer, algorithm) {
22
- return (0, ts_pattern.match)(algorithm).with("gzip", () => neverthrow.ResultAsync.fromPromise(gzipAsync(buffer), (error) => new _amqp_contract_core.TechnicalError("Failed to compress with gzip", error))).with("deflate", () => neverthrow.ResultAsync.fromPromise(deflateAsync(buffer), (error) => new _amqp_contract_core.TechnicalError("Failed to compress with deflate", error))).exhaustive();
22
+ return (0, ts_pattern.match)(algorithm).with("gzip", () => (0, unthrown.fromPromise)(gzipAsync(buffer), (error) => new _amqp_contract_core.TechnicalError("Failed to compress with gzip", error))).with("deflate", () => (0, unthrown.fromPromise)(deflateAsync(buffer), (error) => new _amqp_contract_core.TechnicalError("Failed to compress with deflate", error))).exhaustive();
23
23
  }
24
24
  //#endregion
25
25
  //#region src/errors.ts
26
26
  /**
27
- * Captured `Error.captureStackTrace` shim — only present on Node.js.
28
- */
29
- function captureStack(target, ctor) {
30
- const ErrorConstructor = Error;
31
- if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(target, ctor);
32
- }
33
- /**
34
27
  * Returned from `TypedAmqpClient.call()` when the configured `timeoutMs` elapses
35
28
  * before the RPC server publishes a reply with the matching `correlationId`.
36
29
  *
37
30
  * The pending call is removed from the in-memory correlation map; if a reply
38
31
  * arrives after the timeout it is dropped (and a debug log is emitted by the
39
- * client if a logger is configured).
32
+ * client if a logger is configured). Carries a namespaced `_tag` of
33
+ * `"@amqp-contract/RpcTimeoutError"`; the `Error.name` is kept bare
34
+ * (`"RpcTimeoutError"`).
40
35
  */
41
- var RpcTimeoutError = class extends Error {
36
+ var RpcTimeoutError = class extends (0, unthrown.TaggedError)("@amqp-contract/RpcTimeoutError", { name: "RpcTimeoutError" }) {
42
37
  constructor(rpcName, timeoutMs) {
43
- super(`RPC call to "${rpcName}" timed out after ${timeoutMs}ms with no reply received`);
44
- this.rpcName = rpcName;
45
- this.timeoutMs = timeoutMs;
46
- this.name = "RpcTimeoutError";
47
- captureStack(this, this.constructor);
38
+ super({
39
+ message: `RPC call to "${rpcName}" timed out after ${timeoutMs}ms with no reply received`,
40
+ rpcName,
41
+ timeoutMs
42
+ });
48
43
  }
49
44
  };
50
45
  /**
51
46
  * Returned from any in-flight RPC call when the client is closed before the
52
47
  * reply is received. The correlation map is cleared on close and every pending
53
- * caller's promise resolves with `err(RpcCancelledError)`.
48
+ * caller's promise resolves with `Err(RpcCancelledError)`. Carries a namespaced
49
+ * `_tag` of `"@amqp-contract/RpcCancelledError"`; the `Error.name` is kept bare
50
+ * (`"RpcCancelledError"`).
54
51
  */
55
- var RpcCancelledError = class extends Error {
52
+ var RpcCancelledError = class extends (0, unthrown.TaggedError)("@amqp-contract/RpcCancelledError", { name: "RpcCancelledError" }) {
56
53
  constructor(rpcName) {
57
- super(`RPC call to "${rpcName}" was cancelled because the client was closed`);
58
- this.rpcName = rpcName;
59
- this.name = "RpcCancelledError";
60
- captureStack(this, this.constructor);
54
+ super({
55
+ message: `RPC call to "${rpcName}" was cancelled because the client was closed`,
56
+ rpcName
57
+ });
61
58
  }
62
59
  };
63
60
  //#endregion
@@ -75,6 +72,11 @@ const DIRECT_REPLY_TO = "amq.rabbitmq.reply-to";
75
72
  * Type-safe AMQP client for publishing messages
76
73
  */
77
74
  var TypedAmqpClient = class TypedAmqpClient {
75
+ contract;
76
+ amqpClient;
77
+ defaultPublishOptions;
78
+ logger;
79
+ telemetry;
78
80
  /**
79
81
  * In-flight RPC calls keyed by `correlationId`. Cleared when a reply is
80
82
  * received, when the call times out, or when the client is closed.
@@ -111,14 +113,15 @@ var TypedAmqpClient = class TypedAmqpClient {
111
113
  persistent: true,
112
114
  ...defaultPublishOptions
113
115
  }, logger, telemetry ?? _amqp_contract_core.defaultTelemetryProvider);
114
- const setup = client.waitForConnectionReady().andThen(() => client.setupReplyConsumerIfNeeded());
115
- return new neverthrow.ResultAsync((async () => {
116
+ const setup = client.waitForConnectionReady().flatMap(() => client.setupReplyConsumerIfNeeded());
117
+ return (0, unthrown.fromSafePromise)((async () => {
116
118
  const setupResult = await setup;
117
- if (setupResult.isOk()) return (0, neverthrow.ok)(client);
118
- const closeResult = await client.close();
119
- if (closeResult.isErr()) logger?.warn("Failed to close client after connection failure", { error: closeResult.error });
120
- return (0, neverthrow.err)(setupResult.error);
121
- })());
119
+ if (!setupResult.isOk()) {
120
+ const closeResult = await client.close();
121
+ if (closeResult.isErr()) logger?.warn("Failed to close client after connection failure", { error: closeResult.error });
122
+ }
123
+ return setupResult.map(() => client);
124
+ })()).flatMap((result) => result);
122
125
  }
123
126
  /**
124
127
  * If the contract has any RPC entry, subscribe to `amq.rabbitmq.reply-to`
@@ -127,8 +130,8 @@ var TypedAmqpClient = class TypedAmqpClient {
127
130
  */
128
131
  setupReplyConsumerIfNeeded() {
129
132
  const rpcs = this.contract.rpcs ?? {};
130
- if (Object.keys(rpcs).length === 0) return (0, neverthrow.okAsync)(void 0);
131
- return this.amqpClient.consume(DIRECT_REPLY_TO, (msg) => this.handleRpcReply(msg), { noAck: true }).andTee((tag) => {
133
+ if (Object.keys(rpcs).length === 0) return (0, unthrown.Ok)(void 0).toAsync();
134
+ return this.amqpClient.consume(DIRECT_REPLY_TO, (msg) => this.handleRpcReply(msg), { noAck: true }).tap((tag) => {
132
135
  this.replyConsumerTag = tag;
133
136
  }).map(() => void 0);
134
137
  }
@@ -158,8 +161,8 @@ var TypedAmqpClient = class TypedAmqpClient {
158
161
  this.pendingCalls.delete(correlationId);
159
162
  clearTimeout(pending.timer);
160
163
  const parseResult = (0, _amqp_contract_core.safeJsonParse)(msg.content, (error) => new _amqp_contract_core.TechnicalError(`Failed to parse RPC reply JSON for "${pending.rpcName}"`, error));
161
- if (parseResult.isErr()) {
162
- pending.resolve((0, neverthrow.err)(parseResult.error));
164
+ if (!parseResult.isOk()) {
165
+ pending.resolve((0, unthrown.Err)(parseResult.isErr() ? parseResult.error : new _amqp_contract_core.TechnicalError(`Failed to parse RPC reply JSON for "${pending.rpcName}"`, parseResult.cause)));
163
166
  return;
164
167
  }
165
168
  const parsed = parseResult.value;
@@ -167,17 +170,17 @@ var TypedAmqpClient = class TypedAmqpClient {
167
170
  try {
168
171
  rawValidation = pending.responseSchema["~standard"].validate(parsed);
169
172
  } catch (error) {
170
- pending.resolve((0, neverthrow.err)(new _amqp_contract_core.TechnicalError(`RPC reply validation threw for "${pending.rpcName}"`, error)));
173
+ pending.resolve((0, unthrown.Err)(new _amqp_contract_core.TechnicalError(`RPC reply validation threw for "${pending.rpcName}"`, error)));
171
174
  return;
172
175
  }
173
176
  (rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation)).then((validation) => {
174
177
  if (validation.issues) {
175
- pending.resolve((0, neverthrow.err)(new _amqp_contract_core.MessageValidationError(pending.rpcName, validation.issues)));
178
+ pending.resolve((0, unthrown.Err)(new _amqp_contract_core.MessageValidationError(pending.rpcName, validation.issues)));
176
179
  return;
177
180
  }
178
- pending.resolve((0, neverthrow.ok)(validation.value));
181
+ pending.resolve((0, unthrown.Ok)(validation.value));
179
182
  }, (error) => {
180
- pending.resolve((0, neverthrow.err)(new _amqp_contract_core.TechnicalError(`RPC reply validation threw for "${pending.rpcName}"`, error)));
183
+ pending.resolve((0, unthrown.Err)(new _amqp_contract_core.TechnicalError(`RPC reply validation threw for "${pending.rpcName}"`, error)));
181
184
  });
182
185
  }
183
186
  /**
@@ -199,10 +202,9 @@ var TypedAmqpClient = class TypedAmqpClient {
199
202
  const span = (0, _amqp_contract_core.startPublishSpan)(this.telemetry, exchange.name, routingKey, { [_amqp_contract_core.MessagingSemanticConventions.AMQP_PUBLISHER_NAME]: String(publisherName) });
200
203
  const validateMessage = () => {
201
204
  const validationResult = publisher.message.payload["~standard"].validate(message);
202
- const promise = validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult);
203
- return neverthrow.ResultAsync.fromPromise(promise, (error) => new _amqp_contract_core.TechnicalError("Validation failed", error)).andThen((validation) => {
204
- if (validation.issues) return (0, neverthrow.err)(new _amqp_contract_core.MessageValidationError(String(publisherName), validation.issues));
205
- return (0, neverthrow.ok)(validation.value);
205
+ return (0, unthrown.fromPromise)(validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult), (error) => new _amqp_contract_core.TechnicalError("Validation failed", error)).flatMap((validation) => {
206
+ if (validation.issues) return (0, unthrown.Err)(new _amqp_contract_core.MessageValidationError(String(publisherName), validation.issues));
207
+ return (0, unthrown.Ok)(validation.value);
206
208
  });
207
209
  };
208
210
  const publishMessage = (validatedMessage) => {
@@ -217,24 +219,24 @@ var TypedAmqpClient = class TypedAmqpClient {
217
219
  publishOptions.contentEncoding = compression;
218
220
  return compressBuffer(messageBuffer, compression);
219
221
  }
220
- return (0, neverthrow.okAsync)(validatedMessage);
222
+ return (0, unthrown.Ok)(validatedMessage).toAsync();
221
223
  };
222
- return preparePayload().andThen((payload) => this.amqpClient.publish(publisher.exchange.name, publisher.routingKey ?? "", payload, publishOptions).andThen((published) => {
223
- if (!published) return (0, neverthrow.err)(new _amqp_contract_core.TechnicalError(`Failed to publish message for publisher "${String(publisherName)}": Channel rejected the message (buffer full or other channel issue)`));
224
+ return preparePayload().flatMap((payload) => this.amqpClient.publish(publisher.exchange.name, publisher.routingKey ?? "", payload, publishOptions).flatMap((published) => {
225
+ if (!published) return (0, unthrown.Err)(new _amqp_contract_core.TechnicalError(`Failed to publish message for publisher "${String(publisherName)}": Channel rejected the message (buffer full or other channel issue)`));
224
226
  this.logger?.info("Message published successfully", {
225
227
  publisherName: String(publisherName),
226
228
  exchange: publisher.exchange.name,
227
229
  routingKey: publisher.routingKey,
228
230
  compressed: !!compression
229
231
  });
230
- return (0, neverthrow.ok)(void 0);
232
+ return (0, unthrown.Ok)(void 0);
231
233
  }));
232
234
  };
233
- return validateMessage().andThen((validatedMessage) => publishMessage(validatedMessage)).andTee(() => {
235
+ return validateMessage().flatMap((validatedMessage) => publishMessage(validatedMessage)).tap(() => {
234
236
  const durationMs = Date.now() - startTime;
235
237
  (0, _amqp_contract_core.endSpanSuccess)(span);
236
238
  (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, exchange.name, routingKey, true, durationMs);
237
- }).orTee((error) => {
239
+ }).tapErr((error) => {
238
240
  const durationMs = Date.now() - startTime;
239
241
  (0, _amqp_contract_core.endSpanError)(span, error);
240
242
  (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, exchange.name, routingKey, false, durationMs);
@@ -246,19 +248,23 @@ var TypedAmqpClient = class TypedAmqpClient {
246
248
  * The request payload is validated against the RPC's request schema, then
247
249
  * published to the AMQP default exchange with the server's queue name as
248
250
  * routing key, `replyTo` set to `amq.rabbitmq.reply-to`, and a fresh UUID
249
- * `correlationId`. The returned ResultAsync resolves once a matching reply
251
+ * `correlationId`. The returned AsyncResult resolves once a matching reply
250
252
  * arrives and validates against the response schema, or once `timeoutMs`
251
253
  * elapses (whichever comes first).
252
254
  *
253
255
  * @example
254
256
  * ```typescript
255
257
  * const result = await client.call('calculate', { a: 1, b: 2 }, { timeoutMs: 5_000 });
256
- * if (result.isOk()) console.log(result.value.sum); // 3
258
+ * result.match({
259
+ * ok: (value) => console.log(value.sum), // 3
260
+ * err: (error) => console.error(error),
261
+ * defect: (cause) => console.error(cause),
262
+ * });
257
263
  * ```
258
264
  */
259
265
  call(rpcName, request, options) {
260
266
  const TIMEOUT_MAX_MS = 2147483647;
261
- if (typeof options.timeoutMs !== "number" || !Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0 || options.timeoutMs > TIMEOUT_MAX_MS) return (0, neverthrow.errAsync)(new _amqp_contract_core.TechnicalError(`Invalid timeoutMs for RPC call to "${String(rpcName)}": expected a finite positive number ≤ ${TIMEOUT_MAX_MS}, got ${String(options.timeoutMs)}`));
267
+ if (typeof options.timeoutMs !== "number" || !Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0 || options.timeoutMs > TIMEOUT_MAX_MS) return (0, unthrown.Err)(new _amqp_contract_core.TechnicalError(`Invalid timeoutMs for RPC call to "${String(rpcName)}": expected a finite positive number ≤ ${TIMEOUT_MAX_MS}, got ${String(options.timeoutMs)}`)).toAsync();
262
268
  const startTime = Date.now();
263
269
  const rpc = this.contract.rpcs[rpcName];
264
270
  const requestSchema = rpc.request.payload;
@@ -267,13 +273,13 @@ var TypedAmqpClient = class TypedAmqpClient {
267
273
  const span = (0, _amqp_contract_core.startPublishSpan)(this.telemetry, "", queueName, { [_amqp_contract_core.MessagingSemanticConventions.AMQP_PUBLISHER_NAME]: String(rpcName) });
268
274
  const correlationId = (0, node_crypto.randomUUID)();
269
275
  let resolveCall;
270
- const callResultAsync = new neverthrow.ResultAsync(new Promise((res) => {
276
+ const callResultAsync = (0, unthrown.fromSafePromise)(new Promise((res) => {
271
277
  resolveCall = res;
272
- }));
278
+ })).flatMap((result) => result);
273
279
  const timer = setTimeout(() => {
274
280
  if (!this.pendingCalls.has(correlationId)) return;
275
281
  this.pendingCalls.delete(correlationId);
276
- resolveCall((0, neverthrow.err)(new RpcTimeoutError(String(rpcName), options.timeoutMs)));
282
+ resolveCall((0, unthrown.Err)(new RpcTimeoutError(String(rpcName), options.timeoutMs)));
277
283
  }, options.timeoutMs);
278
284
  this.pendingCalls.set(correlationId, {
279
285
  rpcName: String(rpcName),
@@ -286,10 +292,9 @@ var TypedAmqpClient = class TypedAmqpClient {
286
292
  try {
287
293
  rawValidation = requestSchema["~standard"].validate(request);
288
294
  } catch (error) {
289
- return (0, neverthrow.errAsync)(new _amqp_contract_core.TechnicalError("RPC request validation threw", error));
295
+ return (0, unthrown.Err)(new _amqp_contract_core.TechnicalError("RPC request validation threw", error)).toAsync();
290
296
  }
291
- const validationPromise = rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation);
292
- return neverthrow.ResultAsync.fromPromise(validationPromise, (error) => new _amqp_contract_core.TechnicalError("RPC request validation threw", error)).andThen((validation) => validation.issues ? (0, neverthrow.err)(new _amqp_contract_core.MessageValidationError(String(rpcName), validation.issues)) : (0, neverthrow.ok)(validation.value));
297
+ return (0, unthrown.fromPromise)(rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation), (error) => new _amqp_contract_core.TechnicalError("RPC request validation threw", error)).flatMap((validation) => validation.issues ? (0, unthrown.Err)(new _amqp_contract_core.MessageValidationError(String(rpcName), validation.issues)) : (0, unthrown.Ok)(validation.value));
293
298
  };
294
299
  const publishRequest = (validatedRequest) => {
295
300
  const { compression: _ignoredCompression, ...defaultsWithoutCompression } = this.defaultPublishOptions;
@@ -300,19 +305,19 @@ var TypedAmqpClient = class TypedAmqpClient {
300
305
  correlationId,
301
306
  contentType: "application/json"
302
307
  };
303
- return this.amqpClient.publish("", queueName, validatedRequest, publishOptions).andThen((published) => published ? (0, neverthrow.ok)(void 0) : (0, neverthrow.err)(new _amqp_contract_core.TechnicalError(`Failed to publish RPC request for "${String(rpcName)}": channel buffer full`)));
308
+ return this.amqpClient.publish("", queueName, validatedRequest, publishOptions).flatMap((published) => published ? (0, unthrown.Ok)(void 0) : (0, unthrown.Err)(new _amqp_contract_core.TechnicalError(`Failed to publish RPC request for "${String(rpcName)}": channel buffer full`)));
304
309
  };
305
- return validateRequest().andThen((validated) => publishRequest(validated)).andThen(() => callResultAsync).orElse((error) => {
310
+ return validateRequest().flatMap((validated) => publishRequest(validated)).flatMap(() => callResultAsync).orElse((error) => {
306
311
  if (this.pendingCalls.has(correlationId)) {
307
312
  clearTimeout(timer);
308
313
  this.pendingCalls.delete(correlationId);
309
314
  }
310
- return (0, neverthrow.errAsync)(error);
311
- }).andTee(() => {
315
+ return (0, unthrown.Err)(error).toAsync();
316
+ }).tap(() => {
312
317
  const durationMs = Date.now() - startTime;
313
318
  (0, _amqp_contract_core.endSpanSuccess)(span);
314
319
  (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, "", queueName, true, durationMs);
315
- }).orTee((error) => {
320
+ }).tapErr((error) => {
316
321
  const durationMs = Date.now() - startTime;
317
322
  (0, _amqp_contract_core.endSpanError)(span, error);
318
323
  (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, "", queueName, false, durationMs);
@@ -325,13 +330,13 @@ var TypedAmqpClient = class TypedAmqpClient {
325
330
  close() {
326
331
  for (const [, pending] of this.pendingCalls) {
327
332
  clearTimeout(pending.timer);
328
- pending.resolve((0, neverthrow.err)(new RpcCancelledError(pending.rpcName)));
333
+ pending.resolve((0, unthrown.Err)(new RpcCancelledError(pending.rpcName)));
329
334
  }
330
335
  this.pendingCalls.clear();
331
336
  return (this.replyConsumerTag ? this.amqpClient.cancel(this.replyConsumerTag).orElse((error) => {
332
337
  this.logger?.warn("Failed to cancel RPC reply consumer during close", { error });
333
- return (0, neverthrow.ok)(void 0);
334
- }) : (0, neverthrow.okAsync)(void 0)).andThen(() => this.amqpClient.close());
338
+ return (0, unthrown.Ok)(void 0);
339
+ }) : (0, unthrown.Ok)(void 0).toAsync()).flatMap(() => this.amqpClient.close());
335
340
  }
336
341
  waitForConnectionReady() {
337
342
  return this.amqpClient.waitForConnect();
package/dist/index.d.cts CHANGED
@@ -1,13 +1,92 @@
1
1
  import { CompressionAlgorithm, ContractDefinition, InferPublisherNames, InferRpcNames, MessageDefinition, PublisherEntry, RpcDefinition } from "@amqp-contract/contract";
2
2
  import { Logger, MessageValidationError, PublishOptions as PublishOptions$1, TechnicalError, TelemetryProvider } from "@amqp-contract/core";
3
- import * as amqp from "amqplib";
4
- import { TcpSocketConnectOpts } from "net";
5
3
  import { ConnectionOptions } from "tls";
6
- import { ResultAsync } from "neverthrow";
4
+ import { TcpSocketConnectOpts } from "net";
5
+ import { AsyncResult } from "unthrown";
7
6
  import { StandardSchemaV1 } from "@standard-schema/spec";
8
7
 
9
- //#region ../../node_modules/.pnpm/amqp-connection-manager@5.0.0_amqplib@0.10.9/node_modules/amqp-connection-manager/dist/types/AmqpConnectionManager.d.ts
10
- type ConnectionUrl = string | amqp.Options.Connect | {
8
+ //#region ../../node_modules/.pnpm/amqplib@2.0.1/node_modules/amqplib/lib/properties.d.ts
9
+ declare namespace Options {
10
+ interface Connect {
11
+ protocol?: string;
12
+ hostname?: string;
13
+ port?: number;
14
+ username?: string;
15
+ password?: string;
16
+ locale?: string;
17
+ frameMax?: number;
18
+ heartbeat?: number;
19
+ vhost?: string;
20
+ channelMax?: number;
21
+ credentials?: {
22
+ mechanism: string;
23
+ response(): Buffer;
24
+ username?: string;
25
+ password?: string;
26
+ };
27
+ }
28
+ interface AssertQueue {
29
+ exclusive?: boolean;
30
+ durable?: boolean;
31
+ autoDelete?: boolean;
32
+ arguments?: any;
33
+ messageTtl?: number;
34
+ expires?: number;
35
+ deadLetterExchange?: string;
36
+ deadLetterRoutingKey?: string;
37
+ maxLength?: number;
38
+ maxPriority?: number;
39
+ overflow?: string;
40
+ queueMode?: string;
41
+ }
42
+ interface DeleteQueue {
43
+ ifUnused?: boolean;
44
+ ifEmpty?: boolean;
45
+ }
46
+ interface AssertExchange {
47
+ durable?: boolean;
48
+ internal?: boolean;
49
+ autoDelete?: boolean;
50
+ alternateExchange?: string;
51
+ arguments?: any;
52
+ }
53
+ interface DeleteExchange {
54
+ ifUnused?: boolean;
55
+ }
56
+ interface Publish {
57
+ expiration?: string | number;
58
+ userId?: string;
59
+ CC?: string | string[];
60
+ mandatory?: boolean;
61
+ persistent?: boolean;
62
+ deliveryMode?: boolean | number;
63
+ BCC?: string | string[];
64
+ contentType?: string;
65
+ contentEncoding?: string;
66
+ headers?: any;
67
+ priority?: number;
68
+ correlationId?: string;
69
+ replyTo?: string;
70
+ messageId?: string;
71
+ timestamp?: number;
72
+ type?: string;
73
+ appId?: string;
74
+ }
75
+ interface Consume {
76
+ consumerTag?: string;
77
+ noLocal?: boolean;
78
+ noAck?: boolean;
79
+ exclusive?: boolean;
80
+ priority?: number;
81
+ arguments?: any;
82
+ }
83
+ interface Get {
84
+ noAck?: boolean;
85
+ }
86
+ }
87
+ //#endregion
88
+ //#region ../../node_modules/.pnpm/amqp-connection-manager@5.0.0_amqplib@2.0.1/node_modules/amqp-connection-manager/dist/types/AmqpConnectionManager.d.ts
89
+ type ConnectionUrl = string | Options.Connect | {
11
90
  url: string;
12
91
  connectionOptions?: AmqpConnectionOptions;
13
92
  };
@@ -48,26 +127,36 @@ interface AmqpConnectionManagerOptions {
48
127
  }
49
128
  //#endregion
50
129
  //#region src/errors.d.ts
130
+ declare const RpcTimeoutError_base: import("unthrown").TaggedErrorConstructor<"@amqp-contract/RpcTimeoutError">;
51
131
  /**
52
132
  * Returned from `TypedAmqpClient.call()` when the configured `timeoutMs` elapses
53
133
  * before the RPC server publishes a reply with the matching `correlationId`.
54
134
  *
55
135
  * The pending call is removed from the in-memory correlation map; if a reply
56
136
  * arrives after the timeout it is dropped (and a debug log is emitted by the
57
- * client if a logger is configured).
137
+ * client if a logger is configured). Carries a namespaced `_tag` of
138
+ * `"@amqp-contract/RpcTimeoutError"`; the `Error.name` is kept bare
139
+ * (`"RpcTimeoutError"`).
58
140
  */
59
- declare class RpcTimeoutError extends Error {
60
- readonly rpcName: string;
61
- readonly timeoutMs: number;
141
+ declare class RpcTimeoutError extends RpcTimeoutError_base<{
142
+ message: string;
143
+ rpcName: string;
144
+ timeoutMs: number;
145
+ }> {
62
146
  constructor(rpcName: string, timeoutMs: number);
63
147
  }
148
+ declare const RpcCancelledError_base: import("unthrown").TaggedErrorConstructor<"@amqp-contract/RpcCancelledError">;
64
149
  /**
65
150
  * Returned from any in-flight RPC call when the client is closed before the
66
151
  * reply is received. The correlation map is cleared on close and every pending
67
- * caller's promise resolves with `err(RpcCancelledError)`.
152
+ * caller's promise resolves with `Err(RpcCancelledError)`. Carries a namespaced
153
+ * `_tag` of `"@amqp-contract/RpcCancelledError"`; the `Error.name` is kept bare
154
+ * (`"RpcCancelledError"`).
68
155
  */
69
- declare class RpcCancelledError extends Error {
70
- readonly rpcName: string;
156
+ declare class RpcCancelledError extends RpcCancelledError_base<{
157
+ message: string;
158
+ rpcName: string;
159
+ }> {
71
160
  constructor(rpcName: string);
72
161
  }
73
162
  //#endregion
@@ -141,7 +230,7 @@ type CreateClientOptions<TContract extends ContractDefinition> = {
141
230
  defaultPublishOptions?: PublishOptions | undefined;
142
231
  /**
143
232
  * Maximum time in ms to wait for the AMQP connection to become ready before
144
- * `create()` resolves to an `err(TechnicalError)`. Defaults to 30s
233
+ * `create()` resolves to an `Err(TechnicalError)`. Defaults to 30s
145
234
  * (the {@link AmqpClient}'s `DEFAULT_CONNECT_TIMEOUT_MS`). Pass `null` to
146
235
  * disable the timeout and let amqp-connection-manager retry indefinitely.
147
236
  */
@@ -153,7 +242,7 @@ type CreateClientOptions<TContract extends ContractDefinition> = {
153
242
  type CallOptions = {
154
243
  /**
155
244
  * Maximum time in ms to wait for an RPC reply. If exceeded, the call resolves
156
- * to `err(RpcTimeoutError)` and the in-memory correlation entry is cleared.
245
+ * to `Err(RpcTimeoutError)` and the in-memory correlation entry is cleared.
157
246
  * A late reply arriving after the timeout is silently dropped.
158
247
  *
159
248
  * Required: RPC without a timeout is a footgun.
@@ -203,7 +292,7 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
203
292
  logger,
204
293
  telemetry,
205
294
  connectTimeoutMs
206
- }: CreateClientOptions<TContract>): ResultAsync<TypedAmqpClient<TContract>, TechnicalError>;
295
+ }: CreateClientOptions<TContract>): AsyncResult<TypedAmqpClient<TContract>, TechnicalError>;
207
296
  /**
208
297
  * If the contract has any RPC entry, subscribe to `amq.rabbitmq.reply-to`
209
298
  * once. Replies for every in-flight call arrive on this single consumer and
@@ -232,29 +321,33 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
232
321
  * and the `contentEncoding` property will be set automatically. Any `contentEncoding`
233
322
  * value already in options will be overwritten by the compression algorithm.
234
323
  */
235
- publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: PublishOptions): ResultAsync<void, TechnicalError | MessageValidationError>;
324
+ publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: PublishOptions): AsyncResult<void, TechnicalError | MessageValidationError>;
236
325
  /**
237
326
  * Invoke an RPC defined via `defineRpc` and await the typed response.
238
327
  *
239
328
  * The request payload is validated against the RPC's request schema, then
240
329
  * published to the AMQP default exchange with the server's queue name as
241
330
  * routing key, `replyTo` set to `amq.rabbitmq.reply-to`, and a fresh UUID
242
- * `correlationId`. The returned ResultAsync resolves once a matching reply
331
+ * `correlationId`. The returned AsyncResult resolves once a matching reply
243
332
  * arrives and validates against the response schema, or once `timeoutMs`
244
333
  * elapses (whichever comes first).
245
334
  *
246
335
  * @example
247
336
  * ```typescript
248
337
  * const result = await client.call('calculate', { a: 1, b: 2 }, { timeoutMs: 5_000 });
249
- * if (result.isOk()) console.log(result.value.sum); // 3
338
+ * result.match({
339
+ * ok: (value) => console.log(value.sum), // 3
340
+ * err: (error) => console.error(error),
341
+ * defect: (cause) => console.error(cause),
342
+ * });
250
343
  * ```
251
344
  */
252
- call<TName extends InferRpcNames<TContract>>(rpcName: TName, request: ClientInferRpcRequestInput<TContract, TName>, options: CallOptions): ResultAsync<ClientInferRpcResponseOutput<TContract, TName>, TechnicalError | MessageValidationError | RpcTimeoutError | RpcCancelledError>;
345
+ call<TName extends InferRpcNames<TContract>>(rpcName: TName, request: ClientInferRpcRequestInput<TContract, TName>, options: CallOptions): AsyncResult<ClientInferRpcResponseOutput<TContract, TName>, TechnicalError | MessageValidationError | RpcTimeoutError | RpcCancelledError>;
253
346
  /**
254
347
  * Close the channel and connection. Cancels the reply consumer (if any) and
255
348
  * rejects every in-flight RPC call with `RpcCancelledError`.
256
349
  */
257
- close(): ResultAsync<void, TechnicalError>;
350
+ close(): AsyncResult<void, TechnicalError>;
258
351
  private waitForConnectionReady;
259
352
  }
260
353
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":["amqp","EventEmitter","TcpSocketConnectOpts","ConnectionOptions","ChannelWrapper","CreateChannelOpts","ConnectionUrl","Options","Connect","AmqpConnectionOptions","url","connectionOptions","ConnectListener","Connection","connection","arg","ConnectFailedListener","Error","err","Buffer","noDelay","timeout","keepAlive","keepAliveDelay","clientProperties","credentials","mechanism","username","password","response","AmqpConnectionManagerOptions","Promise","heartbeatIntervalInSeconds","reconnectTimeInSeconds","findServers","urls","callback","IAmqpConnectionManager","Function","ChannelModel","addListener","event","args","listener","reason","listeners","eventName","on","once","prependListener","prependOnceListener","removeListener","connect","options","reconnect","createChannel","close","isConnected","channelCount","AmqpConnectionManager","_channels","_currentUrl","_closed","_cancelRetriesHandler","_connectPromise","_currentConnection","_findServers","_urls","constructor","_connect","default"],"sources":["../../../node_modules/.pnpm/amqp-connection-manager@5.0.0_amqplib@0.10.9/node_modules/amqp-connection-manager/dist/types/AmqpConnectionManager.d.ts","../src/errors.ts","../src/types.ts","../src/client.ts"],"x_google_ignoreList":[0],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":["Empty","AssertQueue","queue","messageCount","consumerCount","PurgeQueue","DeleteQueue","AssertExchange","exchange","Consume","consumerTag","Connect","protocol","hostname","port","username","password","locale","frameMax","heartbeat","vhost","channelMax","credentials","mechanism","response","Buffer","exclusive","durable","autoDelete","arguments","messageTtl","expires","deadLetterExchange","deadLetterRoutingKey","maxLength","maxPriority","overflow","queueMode","ifUnused","ifEmpty","internal","alternateExchange","DeleteExchange","Publish","expiration","userId","CC","mandatory","persistent","deliveryMode","BCC","contentType","contentEncoding","headers","priority","correlationId","replyTo","messageId","timestamp","type","appId","noLocal","noAck","Get","tls","ConnectionOptions","noDelay","timeout","keepAlive","keepAliveDelay","clientProperties","Record","highWaterMark","content","fields","MessageFields","properties","MessageProperties","Message","GetMessageFields","ConsumeMessageFields","deliveryTag","redelivered","routingKey","CommonMessageFields","MessagePropertyHeaders","clusterId","XDeath","key","count","reason","time","value","host","product","version","platform","copyright","information","amqp","Options","Connect","url","connectionOptions","AmqpConnectionOptions","connection","Connection","arg","err","Error","ConnectionOptions","TcpSocketConnectOpts","noDelay","timeout","keepAlive","keepAliveDelay","clientProperties","credentials","mechanism","username","password","response","Buffer","heartbeatIntervalInSeconds","reconnectTimeInSeconds","findServers","ConnectionUrl","urls","callback","Promise","EventEmitter","addListener","event","args","listener","ConnectListener","ConnectFailedListener","reason","listeners","eventName","Function","on","once","prependListener","prependOnceListener","removeListener","connect","options","reconnect","createChannel","CreateChannelOpts","ChannelWrapper","close","isConnected","ChannelModel","channelCount","IAmqpConnectionManager","_channels","_currentUrl","_closed","_cancelRetriesHandler","_connectPromise","_currentConnection","_findServers","_urls","constructor","AmqpConnectionManagerOptions","_connect"],"sources":["../../../node_modules/.pnpm/amqplib@2.0.1/node_modules/amqplib/lib/properties.d.ts","../../../node_modules/.pnpm/amqp-connection-manager@5.0.0_amqplib@2.0.1/node_modules/amqp-connection-manager/dist/types/AmqpConnectionManager.d.ts","../src/errors.ts","../src/types.ts","../src/client.ts"],"x_google_ignoreList":[0,1],"mappings":"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"}