@amqp-contract/worker 0.1.4 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,40 +1,188 @@
1
- import { Options } from "amqplib";
2
- import { ContractDefinition, WorkerInferConsumerHandlers } from "@amqp-contract/contract";
1
+ import { Future, Result } from "@swan-io/boxed";
2
+ import { ConsumerDefinition, ContractDefinition, InferConsumerNames } from "@amqp-contract/contract";
3
+ import { StandardSchemaV1 } from "@standard-schema/spec";
4
+ import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
3
5
 
6
+ //#region src/errors.d.ts
7
+ /**
8
+ * Base error class for worker errors
9
+ */
10
+ declare abstract class WorkerError extends Error {
11
+ protected constructor(message: string);
12
+ }
13
+ /**
14
+ * Error for technical/runtime failures in worker operations
15
+ * This includes validation failures, parsing failures, and processing failures
16
+ */
17
+ declare class TechnicalError extends WorkerError {
18
+ readonly cause?: unknown | undefined;
19
+ constructor(message: string, cause?: unknown | undefined);
20
+ }
21
+ /**
22
+ * Error thrown when message validation fails
23
+ */
24
+ declare class MessageValidationError extends WorkerError {
25
+ readonly consumerName: string;
26
+ readonly issues: unknown;
27
+ constructor(consumerName: string, issues: unknown);
28
+ }
29
+ //#endregion
30
+ //#region src/types.d.ts
31
+ /**
32
+ * Infer the TypeScript type from a schema
33
+ */
34
+ type InferSchemaInput<TSchema extends StandardSchemaV1> = TSchema extends StandardSchemaV1<infer TInput> ? TInput : never;
35
+ /**
36
+ * Infer consumer message input type
37
+ */
38
+ type ConsumerInferInput<TConsumer extends ConsumerDefinition> = InferSchemaInput<TConsumer["message"]["payload"]>;
39
+ /**
40
+ * Infer all consumers from contract
41
+ */
42
+ type InferConsumers<TContract extends ContractDefinition> = NonNullable<TContract["consumers"]>;
43
+ /**
44
+ * Get specific consumer definition from contract
45
+ */
46
+ type InferConsumer<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>> = InferConsumers<TContract>[TName];
47
+ /**
48
+ * Worker perspective types - for consuming messages
49
+ */
50
+ type WorkerInferConsumerInput<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>> = ConsumerInferInput<InferConsumer<TContract, TName>>;
51
+ /**
52
+ * Infer consumer handler type for a specific consumer
53
+ */
54
+ type WorkerInferConsumerHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>> = (message: WorkerInferConsumerInput<TContract, TName>) => Promise<void>;
55
+ /**
56
+ * Infer all consumer handlers for a contract
57
+ */
58
+ type WorkerInferConsumerHandlers<TContract extends ContractDefinition> = { [K in InferConsumerNames<TContract>]: WorkerInferConsumerHandler<TContract, K> };
59
+ //#endregion
4
60
  //#region src/worker.d.ts
5
-
6
61
  /**
7
- * Options for creating a worker
62
+ * Options for creating a type-safe AMQP worker.
63
+ *
64
+ * @typeParam TContract - The contract definition type
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const options: CreateWorkerOptions<typeof contract> = {
69
+ * contract: myContract,
70
+ * handlers: {
71
+ * processOrder: async (message) => {
72
+ * console.log('Processing order:', message.orderId);
73
+ * }
74
+ * },
75
+ * urls: ['amqp://localhost'],
76
+ * connectionOptions: {
77
+ * heartbeatIntervalInSeconds: 30
78
+ * }
79
+ * };
80
+ * ```
8
81
  */
9
- interface CreateWorkerOptions<TContract extends ContractDefinition> {
82
+ type CreateWorkerOptions<TContract extends ContractDefinition> = {
83
+ /** The AMQP contract definition specifying consumers and their message schemas */
10
84
  contract: TContract;
85
+ /** Handlers for each consumer defined in the contract */
11
86
  handlers: WorkerInferConsumerHandlers<TContract>;
12
- connection: string | Options.Connect;
13
- }
87
+ /** AMQP broker URL(s). Multiple URLs provide failover support */
88
+ urls: ConnectionUrl[];
89
+ /** Optional connection configuration (heartbeat, reconnect settings, etc.) */
90
+ connectionOptions?: AmqpConnectionManagerOptions | undefined;
91
+ };
14
92
  /**
15
- * Type-safe AMQP worker for consuming messages
93
+ * Type-safe AMQP worker for consuming messages from RabbitMQ.
94
+ *
95
+ * This class provides automatic message validation, connection management,
96
+ * and error handling for consuming messages based on a contract definition.
97
+ *
98
+ * @typeParam TContract - The contract definition type
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * import { TypedAmqpWorker } from '@amqp-contract/worker';
103
+ * import { z } from 'zod';
104
+ *
105
+ * const contract = defineContract({
106
+ * queues: {
107
+ * orderProcessing: defineQueue('order-processing', { durable: true })
108
+ * },
109
+ * consumers: {
110
+ * processOrder: defineConsumer('order-processing', z.object({
111
+ * orderId: z.string(),
112
+ * amount: z.number()
113
+ * }))
114
+ * }
115
+ * });
116
+ *
117
+ * const worker = await TypedAmqpWorker.create({
118
+ * contract,
119
+ * handlers: {
120
+ * processOrder: async (message) => {
121
+ * console.log('Processing order', message.orderId);
122
+ * // Process the order...
123
+ * }
124
+ * },
125
+ * urls: ['amqp://localhost']
126
+ * }).resultToPromise();
127
+ *
128
+ * // Close when done
129
+ * await worker.close().resultToPromise();
130
+ * ```
16
131
  */
17
132
  declare class TypedAmqpWorker<TContract extends ContractDefinition> {
18
133
  private readonly contract;
134
+ private readonly amqpClient;
19
135
  private readonly handlers;
20
- private readonly connectionOptions;
21
- private channel;
22
- private connection;
23
- private consumerTags;
24
136
  private constructor();
25
137
  /**
26
- * Create a type-safe AMQP worker from a contract
27
- * The worker will automatically connect and start consuming all messages
28
- */
29
- static create<TContract extends ContractDefinition>(options: CreateWorkerOptions<TContract>): Promise<TypedAmqpWorker<TContract>>;
30
- /**
31
- * Close the connection
138
+ * Create a type-safe AMQP worker from a contract.
139
+ *
140
+ * Connection management (including automatic reconnection) is handled internally
141
+ * by amqp-connection-manager via the {@link AmqpClient}. The worker will set up
142
+ * consumers for all contract-defined handlers asynchronously in the background
143
+ * once the underlying connection and channels are ready.
144
+ *
145
+ * @param options - Configuration options for the worker
146
+ * @returns A Future that resolves to a Result containing the worker or an error
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const workerResult = await TypedAmqpWorker.create({
151
+ * contract: myContract,
152
+ * handlers: {
153
+ * processOrder: async (msg) => console.log('Order:', msg.orderId)
154
+ * },
155
+ * urls: ['amqp://localhost']
156
+ * }).resultToPromise();
157
+ *
158
+ * if (workerResult.isError()) {
159
+ * console.error('Failed to create worker:', workerResult.error);
160
+ * }
161
+ * ```
32
162
  */
33
- close(): Promise<void>;
163
+ static create<TContract extends ContractDefinition>({
164
+ contract,
165
+ handlers,
166
+ urls,
167
+ connectionOptions
168
+ }: CreateWorkerOptions<TContract>): Future<Result<TypedAmqpWorker<TContract>, TechnicalError>>;
34
169
  /**
35
- * Connect to AMQP broker
170
+ * Close the AMQP channel and connection.
171
+ *
172
+ * This gracefully closes the connection to the AMQP broker,
173
+ * stopping all message consumption and cleaning up resources.
174
+ *
175
+ * @returns A Future that resolves to a Result indicating success or failure
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * const closeResult = await worker.close().resultToPromise();
180
+ * if (closeResult.isOk()) {
181
+ * console.log('Worker closed successfully');
182
+ * }
183
+ * ```
36
184
  */
37
- private init;
185
+ close(): Future<Result<void, TechnicalError>>;
38
186
  /**
39
187
  * Start consuming messages for all consumers
40
188
  */
@@ -43,35 +191,136 @@ declare class TypedAmqpWorker<TContract extends ContractDefinition> {
43
191
  * Start consuming messages for a specific consumer
44
192
  */
45
193
  private consume;
46
- /**
47
- * Stop consuming messages
48
- */
49
- private stopConsuming;
50
194
  }
51
195
  //#endregion
52
- //#region src/errors.d.ts
53
- /**
54
- * Base error class for worker errors
55
- */
56
- declare abstract class WorkerError extends Error {
57
- protected constructor(message: string);
58
- }
196
+ //#region src/handlers.d.ts
59
197
  /**
60
- * Error for technical/runtime failures in worker operations
61
- * This includes validation failures, parsing failures, and processing failures
198
+ * Define a type-safe handler for a specific consumer in a contract.
199
+ *
200
+ * This utility allows you to define handlers outside of the worker creation,
201
+ * providing better code organization and reusability.
202
+ *
203
+ * @template TContract - The contract definition type
204
+ * @template TName - The consumer name from the contract
205
+ * @param contract - The contract definition containing the consumer
206
+ * @param consumerName - The name of the consumer from the contract
207
+ * @param handler - The async handler function that processes messages
208
+ * @returns A type-safe handler that can be used with TypedAmqpWorker
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * import { defineHandler } from '@amqp-contract/worker';
213
+ * import { orderContract } from './contract';
214
+ *
215
+ * // Define handler outside of worker creation
216
+ * const processOrderHandler = defineHandler(
217
+ * orderContract,
218
+ * 'processOrder',
219
+ * async (message) => {
220
+ * // message is fully typed based on the contract
221
+ * console.log('Processing order:', message.orderId);
222
+ * await processPayment(message);
223
+ * }
224
+ * );
225
+ *
226
+ * // Use the handler in worker
227
+ * const worker = await TypedAmqpWorker.create({
228
+ * contract: orderContract,
229
+ * handlers: {
230
+ * processOrder: processOrderHandler,
231
+ * },
232
+ * connection: 'amqp://localhost',
233
+ * });
234
+ * ```
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * // Define multiple handlers
239
+ * const processOrderHandler = defineHandler(
240
+ * orderContract,
241
+ * 'processOrder',
242
+ * async (message) => {
243
+ * await processOrder(message);
244
+ * }
245
+ * );
246
+ *
247
+ * const notifyOrderHandler = defineHandler(
248
+ * orderContract,
249
+ * 'notifyOrder',
250
+ * async (message) => {
251
+ * await sendNotification(message);
252
+ * }
253
+ * );
254
+ *
255
+ * // Compose handlers
256
+ * const worker = await TypedAmqpWorker.create({
257
+ * contract: orderContract,
258
+ * handlers: {
259
+ * processOrder: processOrderHandler,
260
+ * notifyOrder: notifyOrderHandler,
261
+ * },
262
+ * connection: 'amqp://localhost',
263
+ * });
264
+ * ```
62
265
  */
63
- declare class TechnicalError extends WorkerError {
64
- readonly cause?: unknown | undefined;
65
- constructor(message: string, cause?: unknown | undefined);
66
- }
266
+ declare function defineHandler<TContract extends ContractDefinition, TName extends InferConsumerNames<TContract>>(contract: TContract, consumerName: TName, handler: WorkerInferConsumerHandler<TContract, TName>): WorkerInferConsumerHandler<TContract, TName>;
67
267
  /**
68
- * Error thrown when message validation fails
268
+ * Define multiple type-safe handlers for consumers in a contract.
269
+ *
270
+ * This utility allows you to define all handlers at once outside of the worker creation,
271
+ * ensuring type safety and providing better code organization.
272
+ *
273
+ * @template TContract - The contract definition type
274
+ * @param contract - The contract definition containing the consumers
275
+ * @param handlers - An object with async handler functions for each consumer
276
+ * @returns A type-safe handlers object that can be used with TypedAmqpWorker
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * import { defineHandlers } from '@amqp-contract/worker';
281
+ * import { orderContract } from './contract';
282
+ *
283
+ * // Define all handlers at once
284
+ * const handlers = defineHandlers(orderContract, {
285
+ * processOrder: async (message) => {
286
+ * // message is fully typed based on the contract
287
+ * console.log('Processing order:', message.orderId);
288
+ * await processPayment(message);
289
+ * },
290
+ * notifyOrder: async (message) => {
291
+ * await sendNotification(message);
292
+ * },
293
+ * shipOrder: async (message) => {
294
+ * await prepareShipment(message);
295
+ * },
296
+ * });
297
+ *
298
+ * // Use the handlers in worker
299
+ * const worker = await TypedAmqpWorker.create({
300
+ * contract: orderContract,
301
+ * handlers,
302
+ * connection: 'amqp://localhost',
303
+ * });
304
+ * ```
305
+ *
306
+ * @example
307
+ * ```typescript
308
+ * // Separate handler definitions for better organization
309
+ * async function handleProcessOrder(message: WorkerInferConsumerInput<typeof orderContract, 'processOrder'>) {
310
+ * await processOrder(message);
311
+ * }
312
+ *
313
+ * async function handleNotifyOrder(message: WorkerInferConsumerInput<typeof orderContract, 'notifyOrder'>) {
314
+ * await sendNotification(message);
315
+ * }
316
+ *
317
+ * const handlers = defineHandlers(orderContract, {
318
+ * processOrder: handleProcessOrder,
319
+ * notifyOrder: handleNotifyOrder,
320
+ * });
321
+ * ```
69
322
  */
70
- declare class MessageValidationError extends WorkerError {
71
- readonly consumerName: string;
72
- readonly issues: unknown;
73
- constructor(consumerName: string, issues: unknown);
74
- }
323
+ declare function defineHandlers<TContract extends ContractDefinition>(contract: TContract, handlers: WorkerInferConsumerHandlers<TContract>): WorkerInferConsumerHandlers<TContract>;
75
324
  //#endregion
76
- export { type CreateWorkerOptions, MessageValidationError, TechnicalError, TypedAmqpWorker };
325
+ export { type CreateWorkerOptions, MessageValidationError, TechnicalError, TypedAmqpWorker, type WorkerInferConsumerHandler, type WorkerInferConsumerHandlers, type WorkerInferConsumerInput, defineHandler, defineHandlers };
77
326
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/worker.ts","../src/errors.ts"],"sourcesContent":[],"mappings":";;;;;;;AAcA;AAAuD,UAAtC,mBAAsC,CAAA,kBAAA,kBAAA,CAAA,CAAA;EAC3C,QAAA,EAAA,SAAA;EAC4B,QAAA,EAA5B,2BAA4B,CAAA,SAAA,CAAA;EAA5B,UAAA,EAAA,MAAA,GACW,OAAA,CAAQ,OADnB;;;AAOZ;;AAewC,cAf3B,eAe2B,CAAA,kBAfO,kBAeP,CAAA,CAAA;EACP,iBAAA,QAAA;EAApB,iBAAA,QAAA;EACgB,iBAAA,iBAAA;EAAhB,QAAA,OAAA;EAAR,QAAA,UAAA;EAUY,QAAA,YAAA;EAAO,QAAA,WAAA,CAAA;;;;;EC7BX,OAAA,MAAA,CAAA,kBDiB2B,kBCjBO,CAAA,CAAA,OAAA,EDkBlC,mBClBkC,CDkBd,SClBc,CAAA,CAAA,EDmB1C,OCnB0C,CDmBlC,eCnBkC,CDmBlB,SCnBkB,CAAA,CAAA;EAalC;;;WDgBI;;;;;;;;;;;;;;;;;;;;;;;uBC/CF,WAAA,SAAoB,KAAA;EDWlB,UAAA,WAAA,CAAmB,OAAA,EAAA,MAAA;;;;;;AAGE,cCIzB,cAAA,SAAuB,WAAA,CDJE;EAMzB,SAAA,KAAA,CAAA,EAAA,OAAe,GAAA,SAAA;EAAmB,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EAAA,OAAA,GAAA,SAAA;;;;;AAiBlC,cCNA,sBAAA,SAA+B,WAAA,CDM/B;EAAR,SAAA,YAAA,EAAA,MAAA;EAUY,SAAA,MAAA,EAAA,OAAA;EAAO,WAAA,CAAA,YAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":[],"mappings":"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"}