@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/README.md +14 -54
- package/dist/index.cjs +257 -89
- package/dist/index.d.cts +294 -45
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +294 -45
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +256 -90
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +719 -0
- package/package.json +14 -9
package/dist/index.d.cts
CHANGED
|
@@ -1,40 +1,188 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ConsumerDefinition, ContractDefinition, InferConsumerNames } from "@amqp-contract/contract";
|
|
2
|
+
import { Future, Result } from "@swan-io/boxed";
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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/
|
|
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
|
-
*
|
|
61
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/worker.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":[],"mappings":"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"}
|