@amqp-contract/worker 0.23.1 → 0.25.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 +41 -36
- package/dist/index.cjs +260 -188
- package/dist/index.d.cts +144 -105
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +144 -105
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +261 -190
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +618 -205
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConsumerDefinition, ConsumerEntry, ContractDefinition, InferConsumerNames, InferRpcNames, MessageDefinition, RpcDefinition } from "@amqp-contract/contract";
|
|
2
2
|
import { ConsumerOptions as ConsumerOptions$1, Logger, MessageValidationError, TechnicalError, TelemetryProvider } from "@amqp-contract/core";
|
|
3
|
-
import {
|
|
3
|
+
import { ResultAsync } from "neverthrow";
|
|
4
4
|
import * as amqp from "amqplib";
|
|
5
5
|
import { ConsumeMessage } from "amqplib";
|
|
6
6
|
import { TcpSocketConnectOpts } from "net";
|
|
@@ -49,6 +49,18 @@ interface AmqpConnectionManagerOptions {
|
|
|
49
49
|
}
|
|
50
50
|
//#endregion
|
|
51
51
|
//#region src/errors.d.ts
|
|
52
|
+
/**
|
|
53
|
+
* Abstract base class for all handler-signalled errors.
|
|
54
|
+
*
|
|
55
|
+
* Concrete subclasses (`RetryableError`, `NonRetryableError`) discriminate on
|
|
56
|
+
* the `name` property so exhaustive narrowing in user code keeps working.
|
|
57
|
+
* `error instanceof HandlerError` is true for any handler error.
|
|
58
|
+
*/
|
|
59
|
+
declare abstract class HandlerError extends Error {
|
|
60
|
+
readonly cause?: unknown | undefined;
|
|
61
|
+
abstract readonly name: "RetryableError" | "NonRetryableError";
|
|
62
|
+
constructor(message: string, cause?: unknown | undefined);
|
|
63
|
+
}
|
|
52
64
|
/**
|
|
53
65
|
* Retryable errors - transient failures that may succeed on retry
|
|
54
66
|
* Examples: network timeouts, rate limiting, temporary service unavailability
|
|
@@ -56,9 +68,8 @@ interface AmqpConnectionManagerOptions {
|
|
|
56
68
|
* Use this error type when the operation might succeed if retried.
|
|
57
69
|
* The worker will apply exponential backoff and retry the message.
|
|
58
70
|
*/
|
|
59
|
-
declare class RetryableError extends
|
|
60
|
-
readonly
|
|
61
|
-
constructor(message: string, cause?: unknown | undefined);
|
|
71
|
+
declare class RetryableError extends HandlerError {
|
|
72
|
+
readonly name: "RetryableError";
|
|
62
73
|
}
|
|
63
74
|
/**
|
|
64
75
|
* Non-retryable errors - permanent failures that should not be retried
|
|
@@ -67,15 +78,9 @@ declare class RetryableError extends Error {
|
|
|
67
78
|
* Use this error type when retrying would not help - the message will be
|
|
68
79
|
* immediately sent to the dead letter queue (DLQ) if configured.
|
|
69
80
|
*/
|
|
70
|
-
declare class NonRetryableError extends
|
|
71
|
-
readonly
|
|
72
|
-
constructor(message: string, cause?: unknown | undefined);
|
|
81
|
+
declare class NonRetryableError extends HandlerError {
|
|
82
|
+
readonly name: "NonRetryableError";
|
|
73
83
|
}
|
|
74
|
-
/**
|
|
75
|
-
* Union type representing all handler errors.
|
|
76
|
-
* Use this type when defining handlers that explicitly signal error outcomes.
|
|
77
|
-
*/
|
|
78
|
-
type HandlerError = RetryableError | NonRetryableError;
|
|
79
84
|
/**
|
|
80
85
|
* Type guard to check if an error is a RetryableError.
|
|
81
86
|
*
|
|
@@ -154,15 +159,16 @@ declare function isHandlerError(error: unknown): error is HandlerError;
|
|
|
154
159
|
* @example
|
|
155
160
|
* ```typescript
|
|
156
161
|
* import { retryable } from '@amqp-contract/worker';
|
|
157
|
-
* import {
|
|
162
|
+
* import { ResultAsync } from 'neverthrow';
|
|
158
163
|
*
|
|
159
164
|
* const handler = ({ payload }) =>
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
165
|
+
* ResultAsync.fromPromise(
|
|
166
|
+
* processPayment(payload),
|
|
167
|
+
* (e) => retryable('Payment service unavailable', e),
|
|
168
|
+
* ).map(() => undefined);
|
|
163
169
|
*
|
|
164
170
|
* // Equivalent to:
|
|
165
|
-
* // .
|
|
171
|
+
* // ResultAsync.fromPromise(processPayment(payload), (e) => new RetryableError('...', e))
|
|
166
172
|
* ```
|
|
167
173
|
*/
|
|
168
174
|
declare function retryable(message: string, cause?: unknown): RetryableError;
|
|
@@ -179,17 +185,17 @@ declare function retryable(message: string, cause?: unknown): RetryableError;
|
|
|
179
185
|
* @example
|
|
180
186
|
* ```typescript
|
|
181
187
|
* import { nonRetryable } from '@amqp-contract/worker';
|
|
182
|
-
* import {
|
|
188
|
+
* import { errAsync, okAsync } from 'neverthrow';
|
|
183
189
|
*
|
|
184
190
|
* const handler = ({ payload }) => {
|
|
185
191
|
* if (!isValidPayload(payload)) {
|
|
186
|
-
* return
|
|
192
|
+
* return errAsync(nonRetryable('Invalid payload format'));
|
|
187
193
|
* }
|
|
188
|
-
* return
|
|
194
|
+
* return okAsync(undefined);
|
|
189
195
|
* };
|
|
190
196
|
*
|
|
191
197
|
* // Equivalent to:
|
|
192
|
-
* // return
|
|
198
|
+
* // return errAsync(new NonRetryableError('Invalid payload format'));
|
|
193
199
|
* ```
|
|
194
200
|
*/
|
|
195
201
|
declare function nonRetryable(message: string, cause?: unknown): NonRetryableError;
|
|
@@ -240,7 +246,7 @@ type WorkerInferRpcRequest<TContract extends ContractDefinition, TName extends I
|
|
|
240
246
|
type WorkerInferRpcHeaders<TContract extends ContractDefinition, TName extends InferRpcNames<TContract>> = InferRpc<TContract, TName> extends RpcDefinition<infer TRequest, MessageDefinition> ? TRequest extends MessageDefinition<infer _TPayload, infer THeaders> ? THeaders extends StandardSchemaV1<Record<string, unknown>> ? InferSchemaOutput<THeaders> : undefined : undefined : undefined;
|
|
241
247
|
/**
|
|
242
248
|
* Infer the response payload type for an RPC. The handler must return a
|
|
243
|
-
* `
|
|
249
|
+
* `ResultAsync<TResponse, HandlerError>` matching this shape.
|
|
244
250
|
*/
|
|
245
251
|
type WorkerInferRpcResponse<TContract extends ContractDefinition, TName extends InferRpcNames<TContract>> = InferRpc<TContract, TName> extends RpcDefinition<MessageDefinition, infer TResponse> ? TResponse extends MessageDefinition ? InferSchemaOutput<TResponse["payload"]> : never : never;
|
|
246
252
|
/**
|
|
@@ -258,7 +264,7 @@ type WorkerInferRpcResponse<TContract extends ContractDefinition, TName extends
|
|
|
258
264
|
* console.log(message.payload.orderId); // Typed payload
|
|
259
265
|
* console.log(message.headers?.priority); // Typed headers (if defined)
|
|
260
266
|
* console.log(rawMessage.fields.deliveryTag); // Raw AMQP message
|
|
261
|
-
* return
|
|
267
|
+
* return okAsync(undefined);
|
|
262
268
|
* });
|
|
263
269
|
* ```
|
|
264
270
|
*/
|
|
@@ -277,17 +283,17 @@ type WorkerInferConsumedMessage<TContract extends ContractDefinition, TName exte
|
|
|
277
283
|
type WorkerInferRpcConsumedMessage<TContract extends ContractDefinition, TName extends InferRpcNames<TContract>> = WorkerConsumedMessage<WorkerInferRpcRequest<TContract, TName>, WorkerInferRpcHeaders<TContract, TName>>;
|
|
278
284
|
/**
|
|
279
285
|
* Handler signature for a regular consumer (event/command). Returns
|
|
280
|
-
* `
|
|
286
|
+
* `ResultAsync<void, HandlerError>` — there is no response message.
|
|
281
287
|
*/
|
|
282
|
-
type WorkerInferConsumerHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>> = (message: WorkerInferConsumedMessage<TContract, TName>, rawMessage: ConsumeMessage) =>
|
|
288
|
+
type WorkerInferConsumerHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>> = (message: WorkerInferConsumedMessage<TContract, TName>, rawMessage: ConsumeMessage) => ResultAsync<void, HandlerError>;
|
|
283
289
|
/**
|
|
284
290
|
* Handler signature for an RPC. Returns
|
|
285
|
-
* `
|
|
291
|
+
* `ResultAsync<TResponse, HandlerError>` where `TResponse` is the inferred
|
|
286
292
|
* response payload. The worker validates the response against the RPC's
|
|
287
293
|
* response schema and publishes it back to `msg.properties.replyTo` with the
|
|
288
294
|
* same `correlationId`.
|
|
289
295
|
*/
|
|
290
|
-
type WorkerInferRpcHandler<TContract extends ContractDefinition, TName extends InferRpcNames<TContract>> = (message: WorkerInferRpcConsumedMessage<TContract, TName>, rawMessage: ConsumeMessage) =>
|
|
296
|
+
type WorkerInferRpcHandler<TContract extends ContractDefinition, TName extends InferRpcNames<TContract>> = (message: WorkerInferRpcConsumedMessage<TContract, TName>, rawMessage: ConsumeMessage) => ResultAsync<WorkerInferRpcResponse<TContract, TName>, HandlerError>;
|
|
291
297
|
/**
|
|
292
298
|
* Handler entry for a regular consumer — function or `[handler, options]`.
|
|
293
299
|
*/
|
|
@@ -305,19 +311,15 @@ type WorkerInferRpcHandlerEntry<TContract extends ContractDefinition, TName exte
|
|
|
305
311
|
* ```typescript
|
|
306
312
|
* const handlers: WorkerInferHandlers<typeof contract> = {
|
|
307
313
|
* processOrder: ({ payload }) =>
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
314
|
+
* ResultAsync.fromPromise(
|
|
315
|
+
* processPayment(payload),
|
|
316
|
+
* (error) => new RetryableError('Payment failed', error),
|
|
317
|
+
* ).map(() => undefined),
|
|
318
|
+
* calculate: ({ payload }) => okAsync({ sum: payload.a + payload.b }),
|
|
313
319
|
* };
|
|
314
320
|
* ```
|
|
315
321
|
*/
|
|
316
322
|
type WorkerInferHandlers<TContract extends ContractDefinition> = ([InferConsumerNames<TContract>] extends [never] ? {} : { [K in InferConsumerNames<TContract>]: WorkerInferConsumerHandlerEntry<TContract, K> }) & ([InferRpcNames<TContract>] extends [never] ? {} : { [K in InferRpcNames<TContract>]: WorkerInferRpcHandlerEntry<TContract, K> });
|
|
317
|
-
/**
|
|
318
|
-
* @deprecated Use `WorkerInferHandlers` — handlers now span consumers ∪ rpcs.
|
|
319
|
-
*/
|
|
320
|
-
type WorkerInferConsumerHandlers<TContract extends ContractDefinition> = WorkerInferHandlers<TContract>;
|
|
321
323
|
//#endregion
|
|
322
324
|
//#region src/worker.d.ts
|
|
323
325
|
type ConsumerOptions = ConsumerOptions$1;
|
|
@@ -334,13 +336,13 @@ type ConsumerOptions = ConsumerOptions$1;
|
|
|
334
336
|
* // Simple handler
|
|
335
337
|
* processOrder: ({ payload }) => {
|
|
336
338
|
* console.log('Processing order:', payload.orderId);
|
|
337
|
-
* return
|
|
339
|
+
* return okAsync(undefined);
|
|
338
340
|
* },
|
|
339
341
|
* // Handler with prefetch configuration
|
|
340
342
|
* processPayment: [
|
|
341
343
|
* ({ payload }) => {
|
|
342
344
|
* console.log('Processing payment:', payload.paymentId);
|
|
343
|
-
* return
|
|
345
|
+
* return okAsync(undefined);
|
|
344
346
|
* },
|
|
345
347
|
* { prefetch: 10 }
|
|
346
348
|
* ]
|
|
@@ -364,8 +366,8 @@ type CreateWorkerOptions<TContract extends ContractDefinition> = {
|
|
|
364
366
|
/**
|
|
365
367
|
* Handlers for each `consumers` and `rpcs` entry in the contract.
|
|
366
368
|
*
|
|
367
|
-
* - Regular consumers return `
|
|
368
|
-
* - RPC handlers return `
|
|
369
|
+
* - Regular consumers return `ResultAsync<void, HandlerError>`.
|
|
370
|
+
* - RPC handlers return `ResultAsync<TResponse, HandlerError>` where
|
|
369
371
|
* `TResponse` is inferred from the RPC's response message schema.
|
|
370
372
|
*
|
|
371
373
|
* Use `defineHandler` / `defineHandlers` to create handlers with full type
|
|
@@ -388,7 +390,7 @@ type CreateWorkerOptions<TContract extends ContractDefinition> = {
|
|
|
388
390
|
defaultConsumerOptions?: ConsumerOptions | undefined;
|
|
389
391
|
/**
|
|
390
392
|
* Maximum time in ms to wait for the AMQP connection to become ready before
|
|
391
|
-
* `create()` resolves to `
|
|
393
|
+
* `create()` resolves to an `err(TechnicalError)`. Defaults to 30s
|
|
392
394
|
* (the {@link AmqpClient}'s `DEFAULT_CONNECT_TIMEOUT_MS`). Pass `null` to
|
|
393
395
|
* disable the timeout and let amqp-connection-manager retry indefinitely.
|
|
394
396
|
*/
|
|
@@ -406,6 +408,7 @@ type CreateWorkerOptions<TContract extends ContractDefinition> = {
|
|
|
406
408
|
* ```typescript
|
|
407
409
|
* import { TypedAmqpWorker } from '@amqp-contract/worker';
|
|
408
410
|
* import { defineQueue, defineMessage, defineContract, defineConsumer } from '@amqp-contract/contract';
|
|
411
|
+
* import { okAsync } from 'neverthrow';
|
|
409
412
|
* import { z } from 'zod';
|
|
410
413
|
*
|
|
411
414
|
* const orderQueue = defineQueue('order-processing');
|
|
@@ -420,19 +423,22 @@ type CreateWorkerOptions<TContract extends ContractDefinition> = {
|
|
|
420
423
|
* }
|
|
421
424
|
* });
|
|
422
425
|
*
|
|
423
|
-
* const
|
|
426
|
+
* const result = await TypedAmqpWorker.create({
|
|
424
427
|
* contract,
|
|
425
428
|
* handlers: {
|
|
426
|
-
* processOrder:
|
|
427
|
-
* console.log('Processing order',
|
|
428
|
-
*
|
|
429
|
-
* }
|
|
429
|
+
* processOrder: ({ payload }) => {
|
|
430
|
+
* console.log('Processing order', payload.orderId);
|
|
431
|
+
* return okAsync(undefined);
|
|
432
|
+
* },
|
|
430
433
|
* },
|
|
431
|
-
* urls: ['amqp://localhost']
|
|
432
|
-
* })
|
|
434
|
+
* urls: ['amqp://localhost'],
|
|
435
|
+
* });
|
|
436
|
+
*
|
|
437
|
+
* if (result.isErr()) throw result.error;
|
|
438
|
+
* const worker = result.value;
|
|
433
439
|
*
|
|
434
440
|
* // Close when done
|
|
435
|
-
* await worker.close()
|
|
441
|
+
* await worker.close();
|
|
436
442
|
* ```
|
|
437
443
|
*/
|
|
438
444
|
declare class TypedAmqpWorker<TContract extends ContractDefinition> {
|
|
@@ -470,18 +476,17 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
|
|
|
470
476
|
* Connections are automatically shared across clients and workers with the same
|
|
471
477
|
* URLs and connection options, following RabbitMQ best practices.
|
|
472
478
|
*
|
|
473
|
-
* @
|
|
474
|
-
* @returns A Future that resolves to a Result containing the worker or an error
|
|
479
|
+
* @returns A ResultAsync that resolves to the worker or a TechnicalError.
|
|
475
480
|
*
|
|
476
481
|
* @example
|
|
477
482
|
* ```typescript
|
|
478
|
-
* const
|
|
483
|
+
* const result = await TypedAmqpWorker.create({
|
|
479
484
|
* contract: myContract,
|
|
480
485
|
* handlers: {
|
|
481
|
-
* processOrder:
|
|
486
|
+
* processOrder: ({ payload }) => okAsync(undefined),
|
|
482
487
|
* },
|
|
483
|
-
* urls: ['amqp://localhost']
|
|
484
|
-
* })
|
|
488
|
+
* urls: ['amqp://localhost'],
|
|
489
|
+
* });
|
|
485
490
|
* ```
|
|
486
491
|
*/
|
|
487
492
|
static create<TContract extends ContractDefinition>({
|
|
@@ -493,24 +498,22 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
|
|
|
493
498
|
logger,
|
|
494
499
|
telemetry,
|
|
495
500
|
connectTimeoutMs
|
|
496
|
-
}: CreateWorkerOptions<TContract>):
|
|
501
|
+
}: CreateWorkerOptions<TContract>): ResultAsync<TypedAmqpWorker<TContract>, TechnicalError>;
|
|
497
502
|
/**
|
|
498
503
|
* Close the AMQP channel and connection.
|
|
499
504
|
*
|
|
500
505
|
* This gracefully closes the connection to the AMQP broker,
|
|
501
506
|
* stopping all message consumption and cleaning up resources.
|
|
502
507
|
*
|
|
503
|
-
* @returns A Future that resolves to a Result indicating success or failure
|
|
504
|
-
*
|
|
505
508
|
* @example
|
|
506
509
|
* ```typescript
|
|
507
|
-
* const closeResult = await worker.close()
|
|
510
|
+
* const closeResult = await worker.close();
|
|
508
511
|
* if (closeResult.isOk()) {
|
|
509
512
|
* console.log('Worker closed successfully');
|
|
510
513
|
* }
|
|
511
514
|
* ```
|
|
512
515
|
*/
|
|
513
|
-
close():
|
|
516
|
+
close(): ResultAsync<void, TechnicalError>;
|
|
514
517
|
/**
|
|
515
518
|
* Start consuming for every entry in `contract.consumers` and `contract.rpcs`.
|
|
516
519
|
*/
|
|
@@ -554,9 +557,42 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
|
|
|
554
557
|
* inbox.
|
|
555
558
|
*/
|
|
556
559
|
private publishRpcResponse;
|
|
560
|
+
/**
|
|
561
|
+
* Parse and validate the message; on failure, nack(requeue=false) so the
|
|
562
|
+
* queue's DLX (if configured) receives the poison message and bypass the
|
|
563
|
+
* retry pipeline — a malformed payload is deterministic and retrying it
|
|
564
|
+
* would burn the queue's retry budget on a guaranteed failure.
|
|
565
|
+
*/
|
|
566
|
+
private parseAndValidateOrNack;
|
|
567
|
+
/**
|
|
568
|
+
* Invoke the handler and ack the message on success. Returns the handler's
|
|
569
|
+
* response (RPC) or `undefined` (regular consumer). Errors propagate as
|
|
570
|
+
* `HandlerError` for downstream RPC reply publishing or routing via
|
|
571
|
+
* {@link handleError}.
|
|
572
|
+
*/
|
|
573
|
+
private runHandler;
|
|
574
|
+
/**
|
|
575
|
+
* For RPC handlers, validate and publish the reply on the caller's
|
|
576
|
+
* `replyTo` / `correlationId`. For non-RPC consumers, this is a no-op that
|
|
577
|
+
* resolves to `okAsync(undefined)`.
|
|
578
|
+
*/
|
|
579
|
+
private publishReplyIfRpc;
|
|
557
580
|
/**
|
|
558
581
|
* Process a single consumed message: validate, invoke handler, optionally
|
|
559
|
-
* publish the RPC response, record telemetry, and
|
|
582
|
+
* publish the RPC response, record telemetry, and route errors.
|
|
583
|
+
*
|
|
584
|
+
* The caller-supplied `state` is mutated as the message is ack'd/nack'd so
|
|
585
|
+
* the consume callback's catch-all guard can tell whether a defensive nack
|
|
586
|
+
* is still needed (see {@link consumeSingle}).
|
|
587
|
+
*
|
|
588
|
+
* Success-vs-failure telemetry is data-driven: the chain resolves to
|
|
589
|
+
* `ok(undefined)` only on handler success (and reply-publish success for
|
|
590
|
+
* RPC). Handler failures — even when {@link handleError} routes them
|
|
591
|
+
* successfully to retry/DLQ — are classified as failures for metrics by
|
|
592
|
+
* re-failing the chain with a `TechnicalError` whose `cause` is the
|
|
593
|
+
* original `HandlerError`. The terminal `orTee` unwraps the cause before
|
|
594
|
+
* recording the span exception so traces keep the original
|
|
595
|
+
* `RetryableError` / `NonRetryableError` class as the exception type.
|
|
560
596
|
*/
|
|
561
597
|
private processMessage;
|
|
562
598
|
/**
|
|
@@ -567,85 +603,88 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
|
|
|
567
603
|
//#endregion
|
|
568
604
|
//#region src/handlers.d.ts
|
|
569
605
|
/**
|
|
570
|
-
* Define a type-safe handler for a specific consumer in a contract.
|
|
606
|
+
* Define a type-safe handler for a specific consumer or RPC in a contract.
|
|
571
607
|
*
|
|
572
|
-
* **Recommended:** This function creates handlers that return
|
|
573
|
-
*
|
|
608
|
+
* **Recommended:** This function creates handlers that return
|
|
609
|
+
* `ResultAsync<void, HandlerError>` (consumers) or
|
|
610
|
+
* `ResultAsync<TResponse, HandlerError>` (RPCs), providing explicit error
|
|
611
|
+
* handling and better control over retry behavior.
|
|
574
612
|
*
|
|
575
613
|
* Supports two patterns:
|
|
576
614
|
* 1. Simple handler: just the function
|
|
577
|
-
* 2. Handler with options: [handler, { prefetch: 10 }]
|
|
615
|
+
* 2. Handler with options: `[handler, { prefetch: 10 }]`
|
|
578
616
|
*
|
|
579
617
|
* @template TContract - The contract definition type
|
|
580
|
-
* @template TName - The consumer name from the contract
|
|
581
|
-
* @param contract - The contract definition containing the consumer
|
|
582
|
-
* @param
|
|
583
|
-
* @param handler - The handler function
|
|
618
|
+
* @template TName - The consumer or RPC name from the contract
|
|
619
|
+
* @param contract - The contract definition containing the consumer or RPC
|
|
620
|
+
* @param name - The name of the consumer or RPC from the contract
|
|
621
|
+
* @param handler - The handler function — for consumers, returns
|
|
622
|
+
* `ResultAsync<void, HandlerError>`; for RPCs, returns
|
|
623
|
+
* `ResultAsync<TResponse, HandlerError>`.
|
|
584
624
|
* @param options - Optional consumer options (prefetch)
|
|
585
625
|
* @returns A type-safe handler that can be used with TypedAmqpWorker
|
|
586
626
|
*
|
|
587
|
-
* @example
|
|
627
|
+
* @example Consumer handler
|
|
588
628
|
* ```typescript
|
|
589
629
|
* import { defineHandler, RetryableError, NonRetryableError } from '@amqp-contract/worker';
|
|
590
|
-
* import {
|
|
591
|
-
* import { orderContract } from './contract';
|
|
630
|
+
* import { errAsync, okAsync, ResultAsync } from 'neverthrow';
|
|
592
631
|
*
|
|
593
|
-
* // Simple handler with explicit error handling using mapError
|
|
594
632
|
* const processOrderHandler = defineHandler(
|
|
595
633
|
* orderContract,
|
|
596
634
|
* 'processOrder',
|
|
597
635
|
* ({ payload }) =>
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
636
|
+
* ResultAsync.fromPromise(
|
|
637
|
+
* processPayment(payload),
|
|
638
|
+
* (error) => new RetryableError('Payment failed', error),
|
|
639
|
+
* ).map(() => undefined),
|
|
601
640
|
* );
|
|
641
|
+
* ```
|
|
602
642
|
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
* // Won't be retried - goes directly to DLQ
|
|
610
|
-
* return Future.value(Result.Error(new NonRetryableError('Invalid order amount')));
|
|
611
|
-
* }
|
|
612
|
-
* return Future.value(Result.Ok(undefined));
|
|
613
|
-
* }
|
|
643
|
+
* @example RPC handler
|
|
644
|
+
* ```typescript
|
|
645
|
+
* const calculateHandler = defineHandler(
|
|
646
|
+
* rpcContract,
|
|
647
|
+
* 'calculate',
|
|
648
|
+
* ({ payload }) => okAsync({ sum: payload.a + payload.b }),
|
|
614
649
|
* );
|
|
615
650
|
* ```
|
|
616
651
|
*/
|
|
617
|
-
declare function defineHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>>(contract: TContract,
|
|
618
|
-
declare function defineHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>>(contract: TContract,
|
|
652
|
+
declare function defineHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>>(contract: TContract, name: TName, handler: WorkerInferConsumerHandler<TContract, TName>): WorkerInferConsumerHandlerEntry<TContract, TName>;
|
|
653
|
+
declare function defineHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>>(contract: TContract, name: TName, handler: WorkerInferConsumerHandler<TContract, TName>, options: ConsumerOptions): WorkerInferConsumerHandlerEntry<TContract, TName>;
|
|
654
|
+
declare function defineHandler<TContract extends ContractDefinition, TName extends InferRpcNames<TContract>>(contract: TContract, name: TName, handler: WorkerInferRpcHandler<TContract, TName>): WorkerInferRpcHandlerEntry<TContract, TName>;
|
|
655
|
+
declare function defineHandler<TContract extends ContractDefinition, TName extends InferRpcNames<TContract>>(contract: TContract, name: TName, handler: WorkerInferRpcHandler<TContract, TName>, options: ConsumerOptions): WorkerInferRpcHandlerEntry<TContract, TName>;
|
|
619
656
|
/**
|
|
620
|
-
* Define multiple type-safe handlers for consumers in a contract.
|
|
657
|
+
* Define multiple type-safe handlers for consumers and RPCs in a contract.
|
|
658
|
+
*
|
|
659
|
+
* **Recommended:** This function creates handlers that return
|
|
660
|
+
* `ResultAsync<void, HandlerError>` (consumers) or
|
|
661
|
+
* `ResultAsync<TResponse, HandlerError>` (RPCs), providing explicit error
|
|
662
|
+
* handling and better control over retry behavior.
|
|
621
663
|
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
664
|
+
* The handlers object must contain exactly one entry per `consumers` and
|
|
665
|
+
* `rpcs` key in the contract — see {@link WorkerInferHandlers}.
|
|
624
666
|
*
|
|
625
667
|
* @template TContract - The contract definition type
|
|
626
|
-
* @param contract - The contract definition containing the consumers
|
|
627
|
-
* @param handlers - An object with handler functions for each consumer
|
|
668
|
+
* @param contract - The contract definition containing the consumers and RPCs
|
|
669
|
+
* @param handlers - An object with handler functions for each consumer and RPC
|
|
628
670
|
* @returns A type-safe handlers object that can be used with TypedAmqpWorker
|
|
629
671
|
*
|
|
630
672
|
* @example
|
|
631
673
|
* ```typescript
|
|
632
674
|
* import { defineHandlers, RetryableError } from '@amqp-contract/worker';
|
|
633
|
-
* import {
|
|
634
|
-
* import { orderContract } from './contract';
|
|
675
|
+
* import { okAsync, ResultAsync } from 'neverthrow';
|
|
635
676
|
*
|
|
636
677
|
* const handlers = defineHandlers(orderContract, {
|
|
637
678
|
* processOrder: ({ payload }) =>
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
* .mapOk(() => undefined)
|
|
644
|
-
* .mapError((error) => new RetryableError('Notification failed', error)),
|
|
679
|
+
* ResultAsync.fromPromise(
|
|
680
|
+
* processPayment(payload),
|
|
681
|
+
* (error) => new RetryableError('Payment failed', error),
|
|
682
|
+
* ).map(() => undefined),
|
|
683
|
+
* calculate: ({ payload }) => okAsync({ sum: payload.a + payload.b }),
|
|
645
684
|
* });
|
|
646
685
|
* ```
|
|
647
686
|
*/
|
|
648
|
-
declare function defineHandlers<TContract extends ContractDefinition>(contract: TContract, handlers:
|
|
687
|
+
declare function defineHandlers<TContract extends ContractDefinition>(contract: TContract, handlers: WorkerInferHandlers<TContract>): WorkerInferHandlers<TContract>;
|
|
649
688
|
//#endregion
|
|
650
|
-
export { type ConsumerOptions, type CreateWorkerOptions,
|
|
689
|
+
export { type ConsumerOptions, type CreateWorkerOptions, HandlerError, MessageValidationError, NonRetryableError, RetryableError, TypedAmqpWorker, type WorkerConsumedMessage, type WorkerInferConsumedMessage, type WorkerInferConsumerHandler, type WorkerInferConsumerHandlerEntry, type WorkerInferConsumerHeaders, type WorkerInferHandlers, type WorkerInferRpcConsumedMessage, type WorkerInferRpcHandler, type WorkerInferRpcHandlerEntry, type WorkerInferRpcHeaders, type WorkerInferRpcRequest, type WorkerInferRpcResponse, defineHandler, defineHandlers, isHandlerError, isNonRetryableError, isRetryableError, nonRetryable, retryable };
|
|
651
690
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","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/worker.ts","../src/handlers.ts"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;KAKYM,aAAAA,YAAyBN,IAAAA,CAAKO,OAAAA,CAAQC,OAAAA;EAC9CE,GAAAA;EACAC,iBAAAA,GAAoBF,qBAAAA;AAAAA;AAAAA,KAcZA,qBAAAA,IAAyBN,iBAAAA,GAAoBD,oBAAAA;EACrDkB,OAAAA;EACAC,OAAAA;EACAC,SAAAA;EACAC,cAAAA;EACAC,gBAAAA;EACAC,WAAAA;IACIC,SAAAA;IACAC,QAAAA;IACAC,QAAAA;IACAC,QAAAA,QAAgBV,MAAAA;EAAAA;IAEhBO,SAAAA;IACAG,QAAAA,QAAgBV,MAAAA;EAAAA;AAAAA;AAAAA,UAGPW,4BAAAA;EAVbL;EAYAO,0BAAAA;EAVIL;;;;EAeJM,sBAAAA;EAVIJ;;;;AAGR;;;EAeIK,WAAAA,KAAgBE,QAAAA,GAAWD,IAAAA,EAAM7B,aAAAA,GAAgBA,aAAAA,+BAA4CyB,OAAAA,CAAQzB,aAAAA,GAAgBA,aAAAA;EAApEA;EAEjDK,iBAAAA,GAAoBF,qBAAAA;AAAAA;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","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/worker.ts","../src/handlers.ts"],"x_google_ignoreList":[0],"mappings":"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"}
|