@amqp-contract/worker 0.2.0 → 0.3.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 +11 -1
- package/dist/index.cjs +115 -78
- package/dist/index.d.cts +171 -50
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +171 -50
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +117 -80
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +719 -0
- package/package.json +14 -10
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# @amqp-contract/worker
|
|
2
2
|
|
|
3
|
-
Type-safe AMQP worker for consuming messages using amqp-contract with standard async/await error handling
|
|
3
|
+
**Type-safe AMQP worker for consuming messages using amqp-contract with standard async/await error handling.**
|
|
4
|
+
|
|
5
|
+
[](https://github.com/btravers/amqp-contract/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/@amqp-contract/worker)
|
|
7
|
+
[](https://www.npmjs.com/package/@amqp-contract/worker)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
10
|
|
|
5
11
|
📖 **[Full documentation →](https://btravers.github.io/amqp-contract/api/worker)**
|
|
6
12
|
|
|
@@ -76,6 +82,10 @@ These errors are logged but **handlers don't need to use them** - just throw sta
|
|
|
76
82
|
|
|
77
83
|
See the [Worker API documentation](https://btravers.github.io/amqp-contract/api/worker) for complete API reference.
|
|
78
84
|
|
|
85
|
+
## Documentation
|
|
86
|
+
|
|
87
|
+
📖 **[Read the full documentation →](https://btravers.github.io/amqp-contract)**
|
|
88
|
+
|
|
79
89
|
## License
|
|
80
90
|
|
|
81
91
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
let amqplib = require("amqplib");
|
|
2
1
|
let _amqp_contract_core = require("@amqp-contract/core");
|
|
3
2
|
let _swan_io_boxed = require("@swan-io/boxed");
|
|
4
3
|
|
|
@@ -40,109 +39,149 @@ var MessageValidationError = class extends WorkerError {
|
|
|
40
39
|
//#endregion
|
|
41
40
|
//#region src/worker.ts
|
|
42
41
|
/**
|
|
43
|
-
* Type-safe AMQP worker for consuming messages
|
|
42
|
+
* Type-safe AMQP worker for consuming messages from RabbitMQ.
|
|
43
|
+
*
|
|
44
|
+
* This class provides automatic message validation, connection management,
|
|
45
|
+
* and error handling for consuming messages based on a contract definition.
|
|
46
|
+
*
|
|
47
|
+
* @typeParam TContract - The contract definition type
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { TypedAmqpWorker } from '@amqp-contract/worker';
|
|
52
|
+
* import { z } from 'zod';
|
|
53
|
+
*
|
|
54
|
+
* const contract = defineContract({
|
|
55
|
+
* queues: {
|
|
56
|
+
* orderProcessing: defineQueue('order-processing', { durable: true })
|
|
57
|
+
* },
|
|
58
|
+
* consumers: {
|
|
59
|
+
* processOrder: defineConsumer('order-processing', z.object({
|
|
60
|
+
* orderId: z.string(),
|
|
61
|
+
* amount: z.number()
|
|
62
|
+
* }))
|
|
63
|
+
* }
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* const worker = await TypedAmqpWorker.create({
|
|
67
|
+
* contract,
|
|
68
|
+
* handlers: {
|
|
69
|
+
* processOrder: async (message) => {
|
|
70
|
+
* console.log('Processing order', message.orderId);
|
|
71
|
+
* // Process the order...
|
|
72
|
+
* }
|
|
73
|
+
* },
|
|
74
|
+
* urls: ['amqp://localhost']
|
|
75
|
+
* }).resultToPromise();
|
|
76
|
+
*
|
|
77
|
+
* // Close when done
|
|
78
|
+
* await worker.close().resultToPromise();
|
|
79
|
+
* ```
|
|
44
80
|
*/
|
|
45
81
|
var TypedAmqpWorker = class TypedAmqpWorker {
|
|
46
|
-
|
|
47
|
-
connection = null;
|
|
48
|
-
consumerTags = [];
|
|
49
|
-
constructor(contract, handlers, connectionOptions) {
|
|
82
|
+
constructor(contract, amqpClient, handlers) {
|
|
50
83
|
this.contract = contract;
|
|
84
|
+
this.amqpClient = amqpClient;
|
|
51
85
|
this.handlers = handlers;
|
|
52
|
-
this.connectionOptions = connectionOptions;
|
|
53
86
|
}
|
|
54
87
|
/**
|
|
55
|
-
* Create a type-safe AMQP worker from a contract
|
|
56
|
-
*
|
|
88
|
+
* Create a type-safe AMQP worker from a contract.
|
|
89
|
+
*
|
|
90
|
+
* Connection management (including automatic reconnection) is handled internally
|
|
91
|
+
* by amqp-connection-manager via the {@link AmqpClient}. The worker will set up
|
|
92
|
+
* consumers for all contract-defined handlers asynchronously in the background
|
|
93
|
+
* once the underlying connection and channels are ready.
|
|
94
|
+
*
|
|
95
|
+
* @param options - Configuration options for the worker
|
|
96
|
+
* @returns A Future that resolves to a Result containing the worker or an error
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const workerResult = await TypedAmqpWorker.create({
|
|
101
|
+
* contract: myContract,
|
|
102
|
+
* handlers: {
|
|
103
|
+
* processOrder: async (msg) => console.log('Order:', msg.orderId)
|
|
104
|
+
* },
|
|
105
|
+
* urls: ['amqp://localhost']
|
|
106
|
+
* }).resultToPromise();
|
|
107
|
+
*
|
|
108
|
+
* if (workerResult.isError()) {
|
|
109
|
+
* console.error('Failed to create worker:', workerResult.error);
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
57
112
|
*/
|
|
58
|
-
static
|
|
59
|
-
const worker = new TypedAmqpWorker(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
113
|
+
static create({ contract, handlers, urls, connectionOptions }) {
|
|
114
|
+
const worker = new TypedAmqpWorker(contract, new _amqp_contract_core.AmqpClient(contract, {
|
|
115
|
+
urls,
|
|
116
|
+
connectionOptions
|
|
117
|
+
}), handlers);
|
|
118
|
+
return worker.waitForConnectionReady().flatMapOk(() => worker.consumeAll()).mapOk(() => worker);
|
|
63
119
|
}
|
|
64
120
|
/**
|
|
65
|
-
* Close the connection
|
|
121
|
+
* Close the AMQP channel and connection.
|
|
122
|
+
*
|
|
123
|
+
* This gracefully closes the connection to the AMQP broker,
|
|
124
|
+
* stopping all message consumption and cleaning up resources.
|
|
125
|
+
*
|
|
126
|
+
* @returns A Future that resolves to a Result indicating success or failure
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const closeResult = await worker.close().resultToPromise();
|
|
131
|
+
* if (closeResult.isOk()) {
|
|
132
|
+
* console.log('Worker closed successfully');
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
66
135
|
*/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (this.channel) {
|
|
70
|
-
await this.channel.close();
|
|
71
|
-
this.channel = null;
|
|
72
|
-
}
|
|
73
|
-
if (this.connection) {
|
|
74
|
-
await this.connection.close();
|
|
75
|
-
this.connection = null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Connect to AMQP broker
|
|
80
|
-
*/
|
|
81
|
-
async init() {
|
|
82
|
-
this.connection = await (0, amqplib.connect)(this.connectionOptions);
|
|
83
|
-
this.channel = await this.connection.createChannel();
|
|
84
|
-
await (0, _amqp_contract_core.setupInfra)(this.channel, this.contract);
|
|
136
|
+
close() {
|
|
137
|
+
return _swan_io_boxed.Future.fromPromise(this.amqpClient.close()).mapError((error) => new TechnicalError("Failed to close AMQP connection", error)).mapOk(() => void 0);
|
|
85
138
|
}
|
|
86
139
|
/**
|
|
87
140
|
* Start consuming messages for all consumers
|
|
88
141
|
*/
|
|
89
|
-
|
|
90
|
-
if (!this.contract.consumers)
|
|
142
|
+
consumeAll() {
|
|
143
|
+
if (!this.contract.consumers) return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Error(new TechnicalError("No consumers defined in contract")));
|
|
91
144
|
const consumerNames = Object.keys(this.contract.consumers);
|
|
92
|
-
|
|
145
|
+
return _swan_io_boxed.Future.all(consumerNames.map((consumerName) => this.consume(consumerName))).map(_swan_io_boxed.Result.all).mapOk(() => void 0);
|
|
146
|
+
}
|
|
147
|
+
waitForConnectionReady() {
|
|
148
|
+
return _swan_io_boxed.Future.fromPromise(this.amqpClient.channel.waitForConnect()).mapError((error) => new TechnicalError("Failed to wait for connection ready", error));
|
|
93
149
|
}
|
|
94
150
|
/**
|
|
95
151
|
* Start consuming messages for a specific consumer
|
|
96
152
|
*/
|
|
97
|
-
|
|
98
|
-
if (!this.channel) throw new Error("Worker not initialized. Use TypedAmqpWorker.create() to obtain an initialized worker instance.");
|
|
153
|
+
consume(consumerName) {
|
|
99
154
|
const consumers = this.contract.consumers;
|
|
100
|
-
if (!consumers)
|
|
155
|
+
if (!consumers) return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Error(new TechnicalError("No consumers defined in contract")));
|
|
101
156
|
const consumer = consumers[consumerName];
|
|
102
|
-
if (!consumer
|
|
157
|
+
if (!consumer) {
|
|
103
158
|
const availableConsumers = Object.keys(consumers);
|
|
104
159
|
const available = availableConsumers.length > 0 ? availableConsumers.join(", ") : "none";
|
|
105
|
-
|
|
160
|
+
return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Error(new TechnicalError(`Consumer not found: "${String(consumerName)}". Available consumers: ${available}`)));
|
|
106
161
|
}
|
|
107
|
-
const consumerDef = consumer;
|
|
108
162
|
const handler = this.handlers[consumerName];
|
|
109
|
-
if (!handler)
|
|
110
|
-
|
|
111
|
-
const result = await this.channel.consume(consumerDef.queue.name, async (msg) => {
|
|
112
|
-
if (!msg) return;
|
|
163
|
+
if (!handler) return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Error(new TechnicalError(`Handler for "${String(consumerName)}" not provided`)));
|
|
164
|
+
return _swan_io_boxed.Future.fromPromise(this.amqpClient.channel.consume(consumer.queue.name, async (msg) => {
|
|
113
165
|
const parseResult = _swan_io_boxed.Result.fromExecution(() => JSON.parse(msg.content.toString()));
|
|
114
166
|
if (parseResult.isError()) {
|
|
115
167
|
console.error(new TechnicalError(`Error parsing message for consumer "${String(consumerName)}"`, parseResult.error));
|
|
116
|
-
this.channel
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const content = parseResult.value;
|
|
120
|
-
const rawValidation = consumerDef.message.payload["~standard"].validate(content);
|
|
121
|
-
const resolvedValidation = rawValidation instanceof Promise ? await rawValidation : rawValidation;
|
|
122
|
-
const validationResult = typeof resolvedValidation === "object" && resolvedValidation !== null && "issues" in resolvedValidation && resolvedValidation.issues ? _swan_io_boxed.Result.Error(new MessageValidationError(String(consumerName), resolvedValidation.issues)) : _swan_io_boxed.Result.Ok(typeof resolvedValidation === "object" && resolvedValidation !== null && "value" in resolvedValidation ? resolvedValidation.value : content);
|
|
123
|
-
if (validationResult.isError()) {
|
|
124
|
-
console.error(validationResult.error);
|
|
125
|
-
this.channel?.nack(msg, false, false);
|
|
168
|
+
this.amqpClient.channel.nack(msg, false, false);
|
|
126
169
|
return;
|
|
127
170
|
}
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
171
|
+
const rawValidation = consumer.message.payload["~standard"].validate(parseResult.value);
|
|
172
|
+
await _swan_io_boxed.Future.fromPromise(rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation)).mapOkToResult((validationResult) => {
|
|
173
|
+
if (validationResult.issues) return _swan_io_boxed.Result.Error(new MessageValidationError(String(consumerName), validationResult.issues));
|
|
174
|
+
return _swan_io_boxed.Result.Ok(validationResult.value);
|
|
175
|
+
}).tapError((error) => {
|
|
176
|
+
console.error(error);
|
|
177
|
+
this.amqpClient.channel.nack(msg, false, false);
|
|
178
|
+
}).flatMapOk((validatedMessage) => _swan_io_boxed.Future.fromPromise(handler(validatedMessage)).tapError((error) => {
|
|
133
179
|
console.error(new TechnicalError(`Error processing message for consumer "${String(consumerName)}"`, error));
|
|
134
|
-
this.channel
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Stop consuming messages
|
|
141
|
-
*/
|
|
142
|
-
async stopConsuming() {
|
|
143
|
-
if (!this.channel) return;
|
|
144
|
-
for (const tag of this.consumerTags) await this.channel.cancel(tag);
|
|
145
|
-
this.consumerTags = [];
|
|
180
|
+
this.amqpClient.channel.nack(msg, false, true);
|
|
181
|
+
})).tapOk(() => {
|
|
182
|
+
this.amqpClient.channel.ack(msg);
|
|
183
|
+
}).toPromise();
|
|
184
|
+
})).mapError((error) => new TechnicalError(`Failed to start consuming for "${String(consumerName)}"`, error)).mapOk(() => void 0);
|
|
146
185
|
}
|
|
147
186
|
};
|
|
148
187
|
|
|
@@ -284,11 +323,9 @@ function defineHandler(contract, consumerName, handler) {
|
|
|
284
323
|
*/
|
|
285
324
|
function defineHandlers(contract, handlers) {
|
|
286
325
|
const consumers = contract.consumers;
|
|
287
|
-
const availableConsumers =
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
throw new Error(`Consumer "${handlerName}" not found in contract. Available consumers: ${available}`);
|
|
291
|
-
}
|
|
326
|
+
const availableConsumers = Object.keys(consumers ?? {});
|
|
327
|
+
const availableConsumerNames = availableConsumers.length > 0 ? availableConsumers.join(", ") : "none";
|
|
328
|
+
for (const handlerName of Object.keys(handlers)) if (!consumers || !(handlerName in consumers)) throw new Error(`Consumer "${handlerName}" not found in contract. Available consumers: ${availableConsumerNames}`);
|
|
292
329
|
return handlers;
|
|
293
330
|
}
|
|
294
331
|
|
package/dist/index.d.cts
CHANGED
|
@@ -1,76 +1,197 @@
|
|
|
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
|
-
*
|
|
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
|
+
* ```
|
|
28
162
|
*/
|
|
29
|
-
static create<TContract extends ContractDefinition>(
|
|
163
|
+
static create<TContract extends ContractDefinition>({
|
|
164
|
+
contract,
|
|
165
|
+
handlers,
|
|
166
|
+
urls,
|
|
167
|
+
connectionOptions
|
|
168
|
+
}: CreateWorkerOptions<TContract>): Future<Result<TypedAmqpWorker<TContract>, TechnicalError>>;
|
|
30
169
|
/**
|
|
31
|
-
* Close the connection
|
|
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
|
+
* ```
|
|
32
184
|
*/
|
|
33
|
-
close():
|
|
34
|
-
/**
|
|
35
|
-
* Connect to AMQP broker
|
|
36
|
-
*/
|
|
37
|
-
private init;
|
|
185
|
+
close(): Future<Result<void, TechnicalError>>;
|
|
38
186
|
/**
|
|
39
187
|
* Start consuming messages for all consumers
|
|
40
188
|
*/
|
|
41
189
|
private consumeAll;
|
|
190
|
+
private waitForConnectionReady;
|
|
42
191
|
/**
|
|
43
192
|
* Start consuming messages for a specific consumer
|
|
44
193
|
*/
|
|
45
194
|
private consume;
|
|
46
|
-
/**
|
|
47
|
-
* Stop consuming messages
|
|
48
|
-
*/
|
|
49
|
-
private stopConsuming;
|
|
50
|
-
}
|
|
51
|
-
//#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
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Error for technical/runtime failures in worker operations
|
|
61
|
-
* This includes validation failures, parsing failures, and processing failures
|
|
62
|
-
*/
|
|
63
|
-
declare class TechnicalError extends WorkerError {
|
|
64
|
-
readonly cause?: unknown | undefined;
|
|
65
|
-
constructor(message: string, cause?: unknown | undefined);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Error thrown when message validation fails
|
|
69
|
-
*/
|
|
70
|
-
declare class MessageValidationError extends WorkerError {
|
|
71
|
-
readonly consumerName: string;
|
|
72
|
-
readonly issues: unknown;
|
|
73
|
-
constructor(consumerName: string, issues: unknown);
|
|
74
195
|
}
|
|
75
196
|
//#endregion
|
|
76
197
|
//#region src/handlers.d.ts
|
|
@@ -202,5 +323,5 @@ declare function defineHandler<TContract extends ContractDefinition, TName exten
|
|
|
202
323
|
*/
|
|
203
324
|
declare function defineHandlers<TContract extends ContractDefinition>(contract: TContract, handlers: WorkerInferConsumerHandlers<TContract>): WorkerInferConsumerHandlers<TContract>;
|
|
204
325
|
//#endregion
|
|
205
|
-
export { type CreateWorkerOptions, MessageValidationError, TechnicalError, TypedAmqpWorker, defineHandler, defineHandlers };
|
|
326
|
+
export { type CreateWorkerOptions, MessageValidationError, TechnicalError, TypedAmqpWorker, type WorkerInferConsumerHandler, type WorkerInferConsumerHandlers, type WorkerInferConsumerInput, defineHandler, defineHandlers };
|
|
206
327
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/worker.ts","../src/handlers.ts"],"sourcesContent":[],"mappings":"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"}
|