@zdavison/matador 2.0.12 → 3.0.2
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/checkpoint/context.d.ts +1 -1
- package/dist/checkpoint/context.d.ts.map +1 -1
- package/dist/checkpoint/types.d.ts +1 -1
- package/dist/checkpoint/types.d.ts.map +1 -1
- package/dist/codec/json-codec.js +8 -8
- package/dist/codec/rabbitmq-codec.js +4 -4
- package/dist/core/fanout.test.js +22 -22
- package/dist/core/matador.d.ts.map +1 -1
- package/dist/core/matador.js +5 -7
- package/dist/errors/checkpoint-errors.d.ts.map +1 -1
- package/dist/errors/checkpoint-errors.js +1 -2
- package/dist/errors/matador-errors.d.ts.map +1 -1
- package/dist/errors/matador-errors.js +13 -23
- package/dist/errors/retry-errors.test.js +1 -1
- package/dist/index.cjs +61 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/retry/standard-policy.d.ts.map +1 -1
- package/dist/retry/standard-policy.js +1 -2
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/transport/connection-manager.js +1 -1
- package/dist/transport/rabbitmq/rabbitmq-transport.d.ts.map +1 -1
- package/dist/transport/rabbitmq/rabbitmq-transport.js +7 -2
- package/dist/types/subscriber.d.ts +2 -2
- package/dist/types/subscriber.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -134,6 +134,7 @@ var TransportNotConnectedError = class extends MatadorError {
|
|
|
134
134
|
);
|
|
135
135
|
this.transportName = transportName;
|
|
136
136
|
}
|
|
137
|
+
transportName;
|
|
137
138
|
description = "The transport is not connected to the message broker. ACTION: Ensure the transport is connected by calling transport.connect() or matador.start(). Check that the broker (e.g., RabbitMQ) is running and accessible. Verify connection settings (URL, credentials, network access).";
|
|
138
139
|
};
|
|
139
140
|
var TransportClosedError = class extends MatadorError {
|
|
@@ -143,6 +144,7 @@ var TransportClosedError = class extends MatadorError {
|
|
|
143
144
|
);
|
|
144
145
|
this.transportName = transportName;
|
|
145
146
|
}
|
|
147
|
+
transportName;
|
|
146
148
|
description = "The transport has been closed and will not accept new operations. ACTION: This typically occurs during application shutdown. If unexpected, check for early shutdown triggers. Events sent after transport closure will be lost.";
|
|
147
149
|
};
|
|
148
150
|
var AllTransportsFailedError = class extends MatadorError {
|
|
@@ -153,6 +155,8 @@ var AllTransportsFailedError = class extends MatadorError {
|
|
|
153
155
|
this.queue = queue;
|
|
154
156
|
this.errors = errors;
|
|
155
157
|
}
|
|
158
|
+
queue;
|
|
159
|
+
errors;
|
|
156
160
|
description = "All transports failed to send the message. ACTION: Check the health of all configured transports (primary and fallbacks). Review the errors array for specific failure reasons. Ensure at least one transport is properly configured and reachable. Consider adding a LocalTransport as a last-resort fallback.";
|
|
157
161
|
};
|
|
158
162
|
var TransportSendError = class extends MatadorError {
|
|
@@ -161,6 +165,8 @@ var TransportSendError = class extends MatadorError {
|
|
|
161
165
|
this.queue = queue;
|
|
162
166
|
this.cause = cause;
|
|
163
167
|
}
|
|
168
|
+
queue;
|
|
169
|
+
cause;
|
|
164
170
|
description = "Failed to send a message through the transport. ACTION: Check the underlying error for details. Common causes: (1) Transport disconnected during send, (2) Network issues between application and broker, (3) Broker rejected the message (size, permissions, queue limits). The message was NOT delivered and should be retried or logged.";
|
|
165
171
|
toJSON() {
|
|
166
172
|
return {
|
|
@@ -176,10 +182,11 @@ var TransportSendError = class extends MatadorError {
|
|
|
176
182
|
var DelayedMessagesNotSupportedError = class extends MatadorError {
|
|
177
183
|
constructor(transportName) {
|
|
178
184
|
super(
|
|
179
|
-
|
|
185
|
+
"Delayed messages require the RabbitMQ delayed message exchange plugin. Install rabbitmq_delayed_message_exchange or remove delayMs from event options."
|
|
180
186
|
);
|
|
181
187
|
this.transportName = transportName;
|
|
182
188
|
}
|
|
189
|
+
transportName;
|
|
183
190
|
description = "Delayed messages were requested but the transport does not support them. ACTION: For RabbitMQ, install the rabbitmq_delayed_message_exchange plugin. Run: rabbitmq-plugins enable rabbitmq_delayed_message_exchange Then restart RabbitMQ and reconnect. Alternatively, remove delayMs from your event options if delays are not required.";
|
|
184
191
|
};
|
|
185
192
|
var EventNotRegisteredError = class extends MatadorError {
|
|
@@ -189,16 +196,19 @@ var EventNotRegisteredError = class extends MatadorError {
|
|
|
189
196
|
);
|
|
190
197
|
this.eventKey = eventKey;
|
|
191
198
|
}
|
|
199
|
+
eventKey;
|
|
192
200
|
description = "The event type is not registered in the schema. ACTION: Register the event using matador.register(EventClass, subscribers) before dispatching. If this occurs during message consumption, it may indicate schema drift between services. Ensure all services have matching schema registrations for shared events.";
|
|
193
201
|
};
|
|
194
202
|
var SubscriberNotRegisteredError = class extends MatadorError {
|
|
195
203
|
constructor(subscriberName, eventKey) {
|
|
196
204
|
super(
|
|
197
|
-
`Subscriber "${subscriberName}" is not registered
|
|
205
|
+
`Subscriber "${subscriberName}" is not registered${eventKey ? ` for event "${eventKey}"` : ""}. Check schema registration.`
|
|
198
206
|
);
|
|
199
207
|
this.subscriberName = subscriberName;
|
|
200
208
|
this.eventKey = eventKey;
|
|
201
209
|
}
|
|
210
|
+
subscriberName;
|
|
211
|
+
eventKey;
|
|
202
212
|
description = "The subscriber is not registered for this event in the schema. ACTION: Ensure the subscriber is included in the registration for this event. This may occur if: (1) The subscriber was removed from the schema but messages still exist, (2) Schema drift between producer and consumer services, (3) A deployment is in progress with different schema versions. Check the dead-letter queue for affected messages.";
|
|
203
213
|
};
|
|
204
214
|
var NoSubscribersExistError = class extends MatadorError {
|
|
@@ -208,13 +218,15 @@ var NoSubscribersExistError = class extends MatadorError {
|
|
|
208
218
|
);
|
|
209
219
|
this.eventKey = eventKey;
|
|
210
220
|
}
|
|
221
|
+
eventKey;
|
|
211
222
|
description = "The event has no subscribers registered. ACTION: Register at least one subscriber for this event type. If subscribers were intentionally removed, consider also removing the event dispatch. Events without subscribers are not useful and may indicate configuration issues.";
|
|
212
223
|
};
|
|
213
224
|
var InvalidSchemaError = class extends MatadorError {
|
|
214
225
|
constructor(message, cause) {
|
|
215
|
-
super(`Invalid schema: ${message}
|
|
226
|
+
super(`Invalid schema: ${message}${cause ? `. Cause: ${cause}` : ""}`);
|
|
216
227
|
this.cause = cause;
|
|
217
228
|
}
|
|
229
|
+
cause;
|
|
218
230
|
description = "The schema configuration is invalid. ACTION: Review the schema registration for issues. Common problems: (1) Duplicate subscriber names for the same event, (2) Missing required fields on event class (key, description), (3) Invalid alias configuration. Check the cause property for specific details.";
|
|
219
231
|
};
|
|
220
232
|
var SubscriberIsStubError = class extends MatadorError {
|
|
@@ -224,6 +236,7 @@ var SubscriberIsStubError = class extends MatadorError {
|
|
|
224
236
|
);
|
|
225
237
|
this.subscriberName = subscriberName;
|
|
226
238
|
}
|
|
239
|
+
subscriberName;
|
|
227
240
|
description = "A SubscriberStub was registered in a consuming schema. ACTION: SubscriberStubs should only be used in producer schemas to declare that a subscriber exists in another service. In the consumer service, provide a full Subscriber with a callback function. Remove the stub from the consumer schema and add the actual implementation.";
|
|
228
241
|
};
|
|
229
242
|
var LocalTransportCannotProcessStubError = class extends MatadorError {
|
|
@@ -233,6 +246,7 @@ var LocalTransportCannotProcessStubError = class extends MatadorError {
|
|
|
233
246
|
);
|
|
234
247
|
this.subscriberName = subscriberName;
|
|
235
248
|
}
|
|
249
|
+
subscriberName;
|
|
236
250
|
description = "The LocalTransport cannot process events for SubscriberStubs. ACTION: SubscriberStubs represent remote implementations that only RabbitMQ can route. If using LocalTransport for testing, provide mock implementations instead of stubs. For production fallback scenarios, be aware that stub-targeted events will be dropped.";
|
|
237
251
|
};
|
|
238
252
|
var QueueNotFoundError = class extends MatadorError {
|
|
@@ -242,13 +256,15 @@ var QueueNotFoundError = class extends MatadorError {
|
|
|
242
256
|
);
|
|
243
257
|
this.queueName = queueName;
|
|
244
258
|
}
|
|
259
|
+
queueName;
|
|
245
260
|
description = "The specified queue does not exist or has not been created. ACTION: Ensure the queue is defined in the topology configuration. Call transport.applyTopology() or matador.start() to create queues. Check that the queue name matches the topology definition.";
|
|
246
261
|
};
|
|
247
262
|
var InvalidEventError = class extends MatadorError {
|
|
248
263
|
constructor(message, cause) {
|
|
249
|
-
super(`Invalid event: ${message}
|
|
264
|
+
super(`Invalid event: ${message}${cause ? `. Cause: ${cause}` : ""}`);
|
|
250
265
|
this.cause = cause;
|
|
251
266
|
}
|
|
267
|
+
cause;
|
|
252
268
|
description = "The event is invalid or missing required fields. ACTION: Ensure the event has all required properties. Common issues: missing targetSubscriber during processing, null/undefined data when the event type requires data, malformed event structure from codec decode failure.";
|
|
253
269
|
};
|
|
254
270
|
var MessageMaybePoisonedError = class extends MatadorError {
|
|
@@ -260,6 +276,9 @@ var MessageMaybePoisonedError = class extends MatadorError {
|
|
|
260
276
|
this.deliveryCount = deliveryCount;
|
|
261
277
|
this.maxDeliveries = maxDeliveries;
|
|
262
278
|
}
|
|
279
|
+
eventId;
|
|
280
|
+
deliveryCount;
|
|
281
|
+
maxDeliveries;
|
|
263
282
|
description = "A message was redelivered multiple times without successful processing. This usually indicates the message causes a crash or timeout during processing. ACTION: (1) Check application logs for errors/crashes during message processing, (2) Inspect the message in the dead-letter queue for malformed data, (3) Review the subscriber code for bugs that cause crashes, (4) Consider increasing processing timeout if the operation is legitimately slow. This message will NOT be retried to prevent crash loops.";
|
|
264
283
|
};
|
|
265
284
|
var IdempotentMessageCannotRetryError = class extends MatadorError {
|
|
@@ -270,6 +289,8 @@ var IdempotentMessageCannotRetryError = class extends MatadorError {
|
|
|
270
289
|
this.eventId = eventId;
|
|
271
290
|
this.subscriberName = subscriberName;
|
|
272
291
|
}
|
|
292
|
+
eventId;
|
|
293
|
+
subscriberName;
|
|
273
294
|
description = "A non-idempotent subscriber received a redelivered message. Retrying would risk duplicate side effects (e.g., double payments, duplicate emails). ACTION: (1) Mark the subscriber as idempotent if it safely handles duplicates, (2) Implement idempotency keys in the subscriber logic, (3) Manually inspect and replay the message from the dead-letter queue after verification. The message will be sent to the dead-letter queue for manual review.";
|
|
274
295
|
};
|
|
275
296
|
var TimeoutError = class extends MatadorError {
|
|
@@ -278,6 +299,8 @@ var TimeoutError = class extends MatadorError {
|
|
|
278
299
|
this.operation = operation;
|
|
279
300
|
this.timeoutMs = timeoutMs;
|
|
280
301
|
}
|
|
302
|
+
operation;
|
|
303
|
+
timeoutMs;
|
|
281
304
|
description = "An operation timed out before completing. ACTION: (1) Increase the timeout if the operation legitimately needs more time, (2) Optimize the operation to complete faster, (3) Check for deadlocks or blocking operations, (4) Verify external service dependencies are responsive.";
|
|
282
305
|
};
|
|
283
306
|
function isMatadorError(error) {
|
|
@@ -311,6 +334,8 @@ var DuplicateIoKeyError = class extends MatadorError {
|
|
|
311
334
|
this.key = key;
|
|
312
335
|
this.subscriberName = subscriberName;
|
|
313
336
|
}
|
|
337
|
+
key;
|
|
338
|
+
subscriberName;
|
|
314
339
|
description = "The same io() key was used multiple times in a single subscriber execution. Each io() call must have a unique key to ensure correct checkpoint behavior. ACTION: Ensure all io() keys are unique within the subscriber. For dynamic operations (e.g., loops), include a unique identifier in the key (e.g., `process-item-${item.id}`).";
|
|
315
340
|
};
|
|
316
341
|
var CheckpointStoreError = class extends MatadorError {
|
|
@@ -322,6 +347,9 @@ var CheckpointStoreError = class extends MatadorError {
|
|
|
322
347
|
this.envelopeId = envelopeId;
|
|
323
348
|
this.cause = cause;
|
|
324
349
|
}
|
|
350
|
+
operation;
|
|
351
|
+
envelopeId;
|
|
352
|
+
cause;
|
|
325
353
|
description = "A checkpoint store operation failed. This may cause issues with resumable subscribers. ACTION: Check the underlying storage system (Redis, etc.) for connectivity issues. The subscriber may re-execute operations that were already completed.";
|
|
326
354
|
};
|
|
327
355
|
function isDuplicateIoKeyError(error) {
|
|
@@ -358,6 +386,7 @@ var TopologyValidationError = class extends Error {
|
|
|
358
386
|
this.issues = issues;
|
|
359
387
|
this.name = "TopologyValidationError";
|
|
360
388
|
}
|
|
389
|
+
issues;
|
|
361
390
|
description = "The topology configuration is invalid. Check the issues array for specific validation failures such as missing namespace, invalid queue names, or conflicting settings. This error occurs during Matador initialization and must be fixed in the configuration.";
|
|
362
391
|
};
|
|
363
392
|
var TopologyBuilder = class _TopologyBuilder {
|
|
@@ -902,6 +931,9 @@ var ShutdownManager = class {
|
|
|
902
931
|
this.disconnectTransport = disconnectTransport;
|
|
903
932
|
this.config = { ...defaultShutdownConfig, ...config };
|
|
904
933
|
}
|
|
934
|
+
getEnqueueCount;
|
|
935
|
+
stopReceiving;
|
|
936
|
+
disconnectTransport;
|
|
905
937
|
_state = "running";
|
|
906
938
|
config;
|
|
907
939
|
eventsBeingProcessed = 0;
|
|
@@ -1012,6 +1044,7 @@ var CodecDecodeError = class extends Error {
|
|
|
1012
1044
|
this.cause = cause;
|
|
1013
1045
|
this.name = "CodecDecodeError";
|
|
1014
1046
|
}
|
|
1047
|
+
cause;
|
|
1015
1048
|
description = "Failed to decode a message from the transport. This typically indicates corrupted data, incompatible codec versions, or messages from a different system. Check the cause property for the underlying parsing error. The message will be sent to the dead-letter queue for investigation.";
|
|
1016
1049
|
};
|
|
1017
1050
|
|
|
@@ -1048,16 +1081,16 @@ var JsonCodec = class {
|
|
|
1048
1081
|
return false;
|
|
1049
1082
|
}
|
|
1050
1083
|
const envelope = value;
|
|
1051
|
-
if (typeof envelope
|
|
1084
|
+
if (typeof envelope.id !== "string") return false;
|
|
1052
1085
|
if (!("data" in envelope)) return false;
|
|
1053
|
-
if (typeof envelope
|
|
1086
|
+
if (typeof envelope.docket !== "object" || envelope.docket === null)
|
|
1054
1087
|
return false;
|
|
1055
|
-
const docket = envelope
|
|
1056
|
-
if (typeof docket
|
|
1057
|
-
if (typeof docket
|
|
1058
|
-
if (typeof docket
|
|
1059
|
-
if (typeof docket
|
|
1060
|
-
if (typeof docket
|
|
1088
|
+
const docket = envelope.docket;
|
|
1089
|
+
if (typeof docket.eventKey !== "string") return false;
|
|
1090
|
+
if (typeof docket.targetSubscriber !== "string") return false;
|
|
1091
|
+
if (typeof docket.attempts !== "number") return false;
|
|
1092
|
+
if (typeof docket.createdAt !== "string") return false;
|
|
1093
|
+
if (typeof docket.importance !== "string") return false;
|
|
1061
1094
|
return true;
|
|
1062
1095
|
}
|
|
1063
1096
|
};
|
|
@@ -1147,12 +1180,12 @@ var RabbitMQCodec = class {
|
|
|
1147
1180
|
isV1Body(value) {
|
|
1148
1181
|
if (typeof value !== "object" || value === null) return false;
|
|
1149
1182
|
const obj = value;
|
|
1150
|
-
return typeof obj
|
|
1183
|
+
return typeof obj.key === "string" && typeof obj.targetSubscriber === "string" && "data" in obj && !("payload" in obj);
|
|
1151
1184
|
}
|
|
1152
1185
|
isV2Body(value) {
|
|
1153
1186
|
if (typeof value !== "object" || value === null) return false;
|
|
1154
1187
|
const obj = value;
|
|
1155
|
-
return typeof obj
|
|
1188
|
+
return typeof obj.id === "string" && "data" in obj && !("key" in obj);
|
|
1156
1189
|
}
|
|
1157
1190
|
decodeV2(body, headers) {
|
|
1158
1191
|
const eventKey = this.requireStringHeader(headers, HEADERS.EVENT_KEY);
|
|
@@ -1210,7 +1243,7 @@ var RabbitMQCodec = class {
|
|
|
1210
1243
|
Object.assign(mergedMetadata, body.metadata);
|
|
1211
1244
|
}
|
|
1212
1245
|
if (user_id !== void 0 && user_id !== null) {
|
|
1213
|
-
mergedMetadata
|
|
1246
|
+
mergedMetadata.user_id = user_id;
|
|
1214
1247
|
}
|
|
1215
1248
|
Object.assign(mergedMetadata, otherUniversal);
|
|
1216
1249
|
const attempts = typeof headers[HEADERS.ATTEMPTS] === "number" ? headers[HEADERS.ATTEMPTS] : 1;
|
|
@@ -1774,7 +1807,7 @@ var StandardRetryPolicy = class {
|
|
|
1774
1807
|
}
|
|
1775
1808
|
getDelay(context) {
|
|
1776
1809
|
const attempt = context.receipt.attemptNumber;
|
|
1777
|
-
const delay = this.config.baseDelay *
|
|
1810
|
+
const delay = this.config.baseDelay * this.config.backoffMultiplier ** (attempt - 1);
|
|
1778
1811
|
return Math.min(delay, this.config.maxDelay);
|
|
1779
1812
|
}
|
|
1780
1813
|
};
|
|
@@ -2111,17 +2144,16 @@ var Matador = class {
|
|
|
2111
2144
|
}
|
|
2112
2145
|
const isEventClass = typeof eventOrClass === "function" && "key" in eventOrClass;
|
|
2113
2146
|
if (isEventClass) {
|
|
2114
|
-
const
|
|
2147
|
+
const eventClass2 = eventOrClass;
|
|
2115
2148
|
const data = dataOrOptions;
|
|
2116
|
-
const
|
|
2117
|
-
const
|
|
2118
|
-
return this.fanout.send(
|
|
2119
|
-
} else {
|
|
2120
|
-
const event = eventOrClass;
|
|
2121
|
-
const options = dataOrOptions;
|
|
2122
|
-
const eventClass = event.constructor;
|
|
2123
|
-
return this.fanout.send(eventClass, event, options);
|
|
2149
|
+
const options2 = maybeOptions;
|
|
2150
|
+
const event2 = new eventClass2(data);
|
|
2151
|
+
return this.fanout.send(eventClass2, event2, options2);
|
|
2124
2152
|
}
|
|
2153
|
+
const event = eventOrClass;
|
|
2154
|
+
const options = dataOrOptions;
|
|
2155
|
+
const eventClass = event.constructor;
|
|
2156
|
+
return this.fanout.send(eventClass, event, options);
|
|
2125
2157
|
}
|
|
2126
2158
|
/**
|
|
2127
2159
|
* Gets current handler state.
|
|
@@ -2215,6 +2247,8 @@ var ConnectionManager = class {
|
|
|
2215
2247
|
this.disconnectFn = disconnectFn;
|
|
2216
2248
|
this.config = { ...defaultConnectionConfig, ...config };
|
|
2217
2249
|
}
|
|
2250
|
+
connectFn;
|
|
2251
|
+
disconnectFn;
|
|
2218
2252
|
_state = { status: "disconnected" };
|
|
2219
2253
|
listeners = /* @__PURE__ */ new Set();
|
|
2220
2254
|
reconnectTimer = null;
|
|
@@ -2282,7 +2316,7 @@ var ConnectionManager = class {
|
|
|
2282
2316
|
* Calculate delay for a given attempt using exponential backoff.
|
|
2283
2317
|
*/
|
|
2284
2318
|
calculateDelay(attempt) {
|
|
2285
|
-
const delay = this.config.initialReconnectDelay *
|
|
2319
|
+
const delay = this.config.initialReconnectDelay * this.config.backoffMultiplier ** (attempt - 1);
|
|
2286
2320
|
return Math.min(delay, this.config.maxReconnectDelay);
|
|
2287
2321
|
}
|
|
2288
2322
|
setState(state) {
|
|
@@ -3093,7 +3127,7 @@ var RabbitMQTransport = class {
|
|
|
3093
3127
|
const delayedExchange = this.getDelayedExchangeName(topology.namespace);
|
|
3094
3128
|
await channel.bindQueue(queueName, delayedExchange, queueName);
|
|
3095
3129
|
}
|
|
3096
|
-
if (topology.retry.enabled) {
|
|
3130
|
+
if (topology.retry.enabled && !queueDef.exact) {
|
|
3097
3131
|
await this.assertRetryQueue(channel, topology, queueName);
|
|
3098
3132
|
}
|
|
3099
3133
|
}
|