@rocketmq/core 0.1.1 → 0.1.3
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/.turbo/turbo-build.log +10 -8
- package/CHANGELOG.md +14 -0
- package/README.md +83 -1
- package/dist/index.cjs +4829 -163
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +255 -33
- package/dist/index.d.ts +255 -33
- package/dist/index.js +4825 -165
- package/dist/index.js.map +1 -0
- package/package.json +6 -5
- package/src/client.test.ts +256 -13
- package/src/client.ts +195 -81
- package/src/error-codes.ts +30 -0
- package/src/error-parser.test.ts +223 -0
- package/src/error-parser.ts +189 -0
- package/src/errors.test.ts +14 -11
- package/src/errors.ts +40 -3
- package/src/index.ts +31 -1
- package/src/queue-handle.test.ts +14 -140
- package/src/queue-handle.ts +8 -66
- package/src/schema-resolver.test.ts +112 -0
- package/src/schema-resolver.ts +99 -0
- package/tsup.config.ts +1 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
|
-
import { SchemaRegistry } from '@rocketmq/schema';
|
|
1
|
+
import { Constructor, SchemaRegistry } from '@rocketmq/schema';
|
|
2
2
|
export { Field, FieldMeta, ProtoType, Schema, SchemaEntry } from '@rocketmq/schema';
|
|
3
|
+
import { ZodSchemaInput } from '@rocketmq/zod';
|
|
4
|
+
export { ZodSchemaInput, isRawZodObject, isZodSchemaInput, zodToFields, zodToProto } from '@rocketmq/zod';
|
|
5
|
+
import { z } from 'zod';
|
|
3
6
|
import { Serializer } from '@rocketmq/serializer';
|
|
4
7
|
export { Serializer } from '@rocketmq/serializer';
|
|
5
|
-
import
|
|
6
|
-
import { AmqpChannel, PublishOptions, ConsumeMessage, ConsumeOptions, AmqpConnection, AssertQueueOptions, AssertQueueReply, AssertExchangeOptions, AssertExchangeReply, EmptyReply } from '@rocketmq/amqp';
|
|
8
|
+
import { PublishOptions, ConsumeOptions, AmqpConnection, AmqpChannel, AssertQueueOptions, AssertQueueReply, AssertExchangeOptions, AssertExchangeReply, EmptyReply, ConsumeMessage } from '@rocketmq/amqp';
|
|
7
9
|
export { ConsumeMessage } from '@rocketmq/amqp';
|
|
8
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Resolves proto3 definitions from decorator classes, Zod wrappers, or raw ZodObjects.
|
|
13
|
+
*
|
|
14
|
+
* Centralizes the tri-input logic so client.ts and queue-handle.ts stay
|
|
15
|
+
* clean — they just call `resolveProto(input, queueName)` without caring
|
|
16
|
+
* which path produced it.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* resolveProto(NotificationClass, 'q');
|
|
20
|
+
* resolveProto({ name: 'Notif', schema: zodSchema }, 'q');
|
|
21
|
+
* resolveProto(zodSchema, 'q'); // message name derived from queue name
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Union type accepted by assertQueue/consume as the schema parameter.
|
|
26
|
+
*
|
|
27
|
+
* Three shapes:
|
|
28
|
+
* - `Constructor<T>` — decorator class
|
|
29
|
+
* - `ZodSchemaInput` — `{ name, schema }` wrapper with explicit message name
|
|
30
|
+
* - `z.ZodType<T>` — bare Zod schema, message name derived from queue name
|
|
31
|
+
*
|
|
32
|
+
* WHY z.ZodType<T> instead of z.ZodObject: ZodObject<ZodRawShape> erases T,
|
|
33
|
+
* so TS can't infer the message type in consume(). ZodType<T> preserves
|
|
34
|
+
* the output type. Runtime still validates it's a ZodObject via isRawZodObject.
|
|
35
|
+
*/
|
|
36
|
+
type SchemaInput<T = unknown> = Constructor<T> | ZodSchemaInput | z.ZodType<T>;
|
|
37
|
+
|
|
9
38
|
/**
|
|
10
39
|
* Typed queue handle — the core DX innovation.
|
|
11
40
|
*
|
|
@@ -21,10 +50,9 @@ export { ConsumeMessage } from '@rocketmq/amqp';
|
|
|
21
50
|
|
|
22
51
|
declare class QueueHandle<T> {
|
|
23
52
|
private readonly queueName;
|
|
24
|
-
private readonly
|
|
25
|
-
private readonly
|
|
26
|
-
|
|
27
|
-
constructor(queueName: string, channel: AmqpChannel, registry: SchemaRegistry, serializer: Serializer);
|
|
53
|
+
private readonly client;
|
|
54
|
+
private readonly schema;
|
|
55
|
+
constructor(queueName: string, client: RocketMQ, schema: SchemaInput<T>);
|
|
28
56
|
/**
|
|
29
57
|
* Publishes a typed payload to this queue.
|
|
30
58
|
*
|
|
@@ -38,24 +66,62 @@ declare class QueueHandle<T> {
|
|
|
38
66
|
* arguments so the broker can verify schema subset compatibility.
|
|
39
67
|
* Malformed messages are logged but not re-thrown to keep the loop alive.
|
|
40
68
|
*/
|
|
41
|
-
consume(handler:
|
|
42
|
-
/** Builds AMQP arguments for consumer schema subset checking. */
|
|
43
|
-
private buildConsumerSchemaArgs;
|
|
69
|
+
consume(handler: TypedConsumeHandler<T>, opts?: ConsumeOptions): Promise<string>;
|
|
44
70
|
}
|
|
45
71
|
|
|
72
|
+
/**
|
|
73
|
+
* RocketMQ TypeScript client — schema-aware AMQP wrapper.
|
|
74
|
+
*
|
|
75
|
+
* Composes schema, validation, serialization, and AMQP packages into
|
|
76
|
+
* a single user-facing API. Hides all internal wiring behind `connect()`
|
|
77
|
+
* and `mq.queue()`.
|
|
78
|
+
*
|
|
79
|
+
* Supports two schema input styles:
|
|
80
|
+
* - Decorator classes: `mq.assertQueue('q', MyClass)`
|
|
81
|
+
* - Zod schemas: `mq.assertQueue('q', { name: 'Msg', schema: zodObj })`
|
|
82
|
+
*
|
|
83
|
+
* Usage:
|
|
84
|
+
* const mq = await connect();
|
|
85
|
+
* const orders = mq.queue("orders", Order);
|
|
86
|
+
* orders.send({ id: "1", customerId: "c1", qty: 5 });
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
type TypedConsumeHandler<T> = (msg: T, raw: ConsumeMessage) => void | Promise<void>;
|
|
90
|
+
interface RocketAssertQueueOptions extends AssertQueueOptions {
|
|
91
|
+
/** Force update an existing queue's schema even if it conflicts. */
|
|
92
|
+
schemaOverride?: boolean;
|
|
93
|
+
/** Remove the schema binding from an existing queue. */
|
|
94
|
+
schemaDelete?: boolean;
|
|
95
|
+
}
|
|
96
|
+
interface RocketConsumeOptions extends ConsumeOptions {
|
|
97
|
+
/**
|
|
98
|
+
* Explicit schema class for consumer compatibility validation.
|
|
99
|
+
*
|
|
100
|
+
* TypeScript generics are erased at runtime, so `consume<T>` alone
|
|
101
|
+
* cannot send `T`'s proto to the broker. Pass the class here so the
|
|
102
|
+
* broker can verify the consumer's expected fields match the queue's
|
|
103
|
+
* declared schema.
|
|
104
|
+
*
|
|
105
|
+
* Example:
|
|
106
|
+
* await mq.consume<Order>('orders', handler, { consumerSchema: Order });
|
|
107
|
+
*/
|
|
108
|
+
consumerSchema?: Constructor;
|
|
109
|
+
}
|
|
46
110
|
interface RocketOptions {
|
|
47
|
-
/** AMQP connection URL.
|
|
48
|
-
url
|
|
111
|
+
/** AMQP connection URL. */
|
|
112
|
+
url: string;
|
|
49
113
|
/** Custom serializer. Default: JsonSerializer. */
|
|
50
114
|
serializer?: Serializer;
|
|
51
115
|
}
|
|
52
116
|
/** Opens a connection + channel ready for schema-aware operations. */
|
|
53
|
-
declare function connect(opts
|
|
117
|
+
declare function connect(opts: RocketOptions): Promise<RocketMQ>;
|
|
54
118
|
declare class RocketMQ {
|
|
55
119
|
private readonly conn;
|
|
56
120
|
private readonly ch;
|
|
57
121
|
private readonly registry;
|
|
58
122
|
private readonly serializer;
|
|
123
|
+
private lastChannelError;
|
|
124
|
+
private readonly errorListener;
|
|
59
125
|
constructor(conn: AmqpConnection, ch: AmqpChannel, registry: SchemaRegistry, serializer: Serializer);
|
|
60
126
|
/** Exposes the raw AmqpChannel for event listeners (e.g. broker errors). */
|
|
61
127
|
get channel(): AmqpChannel;
|
|
@@ -65,16 +131,28 @@ declare class RocketMQ {
|
|
|
65
131
|
* Declares the queue with schema metadata in AMQP arguments so the
|
|
66
132
|
* broker compiles and validates messages. Returns a QueueHandle<T>
|
|
67
133
|
* for type-safe send/consume.
|
|
134
|
+
*
|
|
135
|
+
* Usage:
|
|
136
|
+
* const orders = await mq.queue('orders', OrderClass);
|
|
137
|
+
* const orders = await mq.queue('orders', zodSchema);
|
|
68
138
|
*/
|
|
69
|
-
queue<T>(name: string, schema:
|
|
139
|
+
queue<T>(name: string, schema: SchemaInput<T>, opts?: RocketAssertQueueOptions): Promise<QueueHandle<T>>;
|
|
70
140
|
/**
|
|
71
|
-
* Declares a queue with an optional schema class.
|
|
141
|
+
* Declares a queue with an optional schema (decorator class or Zod).
|
|
72
142
|
*
|
|
73
143
|
* When a schema is provided the proto3 definition is sent as AMQP
|
|
74
144
|
* queue arguments (`x-schema`, `x-schema-type`, `x-schema-message`)
|
|
75
145
|
* so the broker compiles and validates messages inline.
|
|
146
|
+
*
|
|
147
|
+
* Usage:
|
|
148
|
+
* await mq.assertQueue('orders', OrderClass);
|
|
149
|
+
* await mq.assertQueue('orders', { name: 'Order', schema: zodSchema });
|
|
150
|
+
* await mq.assertQueue('orders', zodSchema); // message name derived from queue name
|
|
76
151
|
*/
|
|
77
|
-
assertQueue(name: string, schema?:
|
|
152
|
+
assertQueue(name: string, schema?: SchemaInput, opts?: RocketAssertQueueOptions): Promise<AssertQueueReply>;
|
|
153
|
+
private buildSchemaQueueArgs;
|
|
154
|
+
/** Stores decorator class metadata in the registry for consumer lookups. */
|
|
155
|
+
private registerConstructorSchema;
|
|
78
156
|
/** Declares an exchange (passthrough to AMQP layer). */
|
|
79
157
|
assertExchange(name: string, type: string, opts?: AssertExchangeOptions): Promise<AssertExchangeReply>;
|
|
80
158
|
/** Binds a queue to an exchange (passthrough to AMQP layer). */
|
|
@@ -91,25 +169,27 @@ declare class RocketMQ {
|
|
|
91
169
|
*/
|
|
92
170
|
publish(exchange: string, routingKey: string, payload: Record<string, unknown>, opts?: PublishOptions): boolean;
|
|
93
171
|
/**
|
|
94
|
-
* Subscribes to a queue with JSON deserialization
|
|
172
|
+
* Subscribes to a queue with JSON deserialization and broker-side
|
|
173
|
+
* consumer schema validation.
|
|
95
174
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
175
|
+
* Accepts either a decorator class or a ZodSchemaInput for the schema
|
|
176
|
+
* parameter. The schema serves two purposes:
|
|
177
|
+
* - **Compile-time**: TypeScript infers `T`, so `msg` is fully typed.
|
|
178
|
+
* - **Runtime**: Its proto definition is sent to the broker as AMQP
|
|
179
|
+
* arguments so the broker can verify subset compatibility.
|
|
100
180
|
*
|
|
101
181
|
* Usage:
|
|
102
|
-
* await mq.
|
|
103
|
-
* await mq.consume("orders",
|
|
104
|
-
|
|
105
|
-
consume<T = Record<string, unknown>>(queue: string, handler: (msg: T, raw: ConsumeMessage) => void, opts?: _rocketmq_amqp.ConsumeOptions): Promise<string>;
|
|
106
|
-
/**
|
|
107
|
-
* Builds AMQP arguments for consumer schema compatibility checking.
|
|
108
|
-
*
|
|
109
|
-
* Returns `x-consumer-schema` + `x-consumer-schema-message` if the
|
|
110
|
-
* queue has a registered schema, otherwise an empty object.
|
|
182
|
+
* await mq.consume("orders", Order, (msg) => console.log(msg.id));
|
|
183
|
+
* await mq.consume("orders", { name: "Order", schema: zodSchema }, handler);
|
|
184
|
+
* await mq.consume("orders", zodSchema, handler);
|
|
111
185
|
*/
|
|
186
|
+
consume<T>(queue: string, schema: SchemaInput<T>, handler: TypedConsumeHandler<T>, opts?: RocketConsumeOptions): Promise<string>;
|
|
187
|
+
private createConsumeCallback;
|
|
112
188
|
private buildConsumerSchemaArgs;
|
|
189
|
+
/** Resolves consumer schema args from an explicit SchemaInput. */
|
|
190
|
+
private resolveConsumerArgs;
|
|
191
|
+
/** Falls back to registry lookup when no explicit schema is provided. */
|
|
192
|
+
private fallbackConsumerArgs;
|
|
113
193
|
/** Acknowledges a message. */
|
|
114
194
|
ack(msg: ConsumeMessage): void;
|
|
115
195
|
/** Negative-acknowledges a message. */
|
|
@@ -142,19 +222,161 @@ declare class QueueError extends RocketMQError {
|
|
|
142
222
|
}
|
|
143
223
|
declare class PublishError extends RocketMQError {
|
|
144
224
|
readonly queue: string;
|
|
145
|
-
|
|
225
|
+
readonly payload: unknown;
|
|
226
|
+
constructor(queue: string, payload: unknown, cause?: unknown);
|
|
146
227
|
}
|
|
147
228
|
declare class ConsumeError extends RocketMQError {
|
|
148
229
|
constructor(message: string, cause?: unknown);
|
|
149
230
|
}
|
|
150
231
|
declare class SerializationError extends RocketMQError {
|
|
151
|
-
|
|
232
|
+
readonly payload: unknown;
|
|
233
|
+
constructor(payload: unknown, cause?: unknown);
|
|
152
234
|
}
|
|
153
235
|
declare class SchemaError extends RocketMQError {
|
|
154
236
|
constructor(message: string, cause?: unknown);
|
|
155
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Schema-specific error with structured details from the broker.
|
|
240
|
+
*
|
|
241
|
+
* Contains the error code, queue name, and per-field details
|
|
242
|
+
* so callers can programmatically inspect what went wrong.
|
|
243
|
+
* Field types use TypeScript names (number, string, boolean).
|
|
244
|
+
*
|
|
245
|
+
* Usage:
|
|
246
|
+
* catch (err) {
|
|
247
|
+
* if (err instanceof SchemaValidationError) {
|
|
248
|
+
* console.log(err.code); // 'SchemaTypeMismatch'
|
|
249
|
+
* console.log(err.queue); // 'zod-notifications'
|
|
250
|
+
* console.log(err.fields); // [{ name: 'id', expected: 'number', got: 'string' }]
|
|
251
|
+
* }
|
|
252
|
+
* }
|
|
253
|
+
*/
|
|
254
|
+
declare class SchemaValidationError extends SchemaError {
|
|
255
|
+
readonly code: string;
|
|
256
|
+
readonly queue: string;
|
|
257
|
+
readonly fields: ReadonlyArray<{
|
|
258
|
+
readonly name: string;
|
|
259
|
+
readonly expected: string;
|
|
260
|
+
readonly got: string;
|
|
261
|
+
}>;
|
|
262
|
+
constructor(code: string, queue: string, fields: ReadonlyArray<{
|
|
263
|
+
readonly name: string;
|
|
264
|
+
readonly expected: string;
|
|
265
|
+
readonly got: string;
|
|
266
|
+
}>, message: string, cause?: unknown);
|
|
267
|
+
}
|
|
156
268
|
declare class TimeoutError extends RocketMQError {
|
|
157
269
|
constructor(message: string, cause?: unknown);
|
|
158
270
|
}
|
|
159
271
|
|
|
160
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Machine-readable error codes returned by the broker.
|
|
274
|
+
*
|
|
275
|
+
* These mirror the Rust `ErrorCode` enum 1:1. The client uses them
|
|
276
|
+
* to construct specific exception subclasses and provide programmatic
|
|
277
|
+
* access to the error category.
|
|
278
|
+
*
|
|
279
|
+
* Usage:
|
|
280
|
+
* if (parsed.code === BrokerErrorCode.SchemaTypeMismatch) { ... }
|
|
281
|
+
*/
|
|
282
|
+
declare enum BrokerErrorCode {
|
|
283
|
+
/** Consumer/publisher field type doesn't match queue schema. */
|
|
284
|
+
SchemaTypeMismatch = "SchemaTypeMismatch",
|
|
285
|
+
/** Consumer has fields not present in queue schema. */
|
|
286
|
+
SchemaExtraFields = "SchemaExtraFields",
|
|
287
|
+
/** JSON payload is missing required schema fields. */
|
|
288
|
+
SchemaMissingFields = "SchemaMissingFields",
|
|
289
|
+
/** Re-declaration schema conflicts with existing queue schema. */
|
|
290
|
+
SchemaConflict = "SchemaConflict",
|
|
291
|
+
/** Proto compilation failed (syntax error, etc.). */
|
|
292
|
+
SchemaCompileFailed = "SchemaCompileFailed",
|
|
293
|
+
/** Unsupported schema type (not protobuf). */
|
|
294
|
+
SchemaUnsupportedType = "SchemaUnsupportedType",
|
|
295
|
+
/** Schema validation on publish: wrong JSON value types. */
|
|
296
|
+
ValidationTypeMismatch = "ValidationTypeMismatch",
|
|
297
|
+
/** Payload is not valid JSON. */
|
|
298
|
+
ValidationInvalidJson = "ValidationInvalidJson",
|
|
299
|
+
/** Required AMQP argument missing (x-schema-type, x-schema-message). */
|
|
300
|
+
MissingArgument = "MissingArgument"
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Parses structured JSON errors from AMQP Channel.Close reply_text.
|
|
305
|
+
*
|
|
306
|
+
* The broker encodes a `BrokerError` JSON object into the reply_text
|
|
307
|
+
* field. This module detects JSON (starts with `{`), validates the shape,
|
|
308
|
+
* and returns a typed `BrokerErrorPayload`.
|
|
309
|
+
*
|
|
310
|
+
* It also handles proto → TypeScript type name mapping, since the broker
|
|
311
|
+
* returns raw proto names (e.g. "double") and the client translates them
|
|
312
|
+
* to language-specific names (e.g. "number").
|
|
313
|
+
*
|
|
314
|
+
* Usage:
|
|
315
|
+
* const parsed = parseBrokerError(replyText);
|
|
316
|
+
* if (parsed) throw SchemaValidationError.fromBrokerError(parsed);
|
|
317
|
+
*/
|
|
318
|
+
|
|
319
|
+
/** Structured error payload deserialized from broker JSON. */
|
|
320
|
+
interface BrokerErrorPayload {
|
|
321
|
+
code: BrokerErrorCode;
|
|
322
|
+
queue: string;
|
|
323
|
+
fields: FieldErrorDetail[];
|
|
324
|
+
truncated: boolean;
|
|
325
|
+
}
|
|
326
|
+
/** Per-field error detail from the broker. */
|
|
327
|
+
interface FieldErrorDetail {
|
|
328
|
+
/** Field name in the schema. */
|
|
329
|
+
name: string;
|
|
330
|
+
/** Proto type name that the queue schema expects (e.g. "double"). */
|
|
331
|
+
expected: string;
|
|
332
|
+
/** Proto type name that was actually received (e.g. "string"). */
|
|
333
|
+
got: string;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Maps proto3 type names to TypeScript-friendly equivalents.
|
|
337
|
+
*
|
|
338
|
+
* WHY here and not in the broker: the broker is language-agnostic.
|
|
339
|
+
* It returns raw proto kind names. Each client SDK maps them to the
|
|
340
|
+
* target language's type system.
|
|
341
|
+
*
|
|
342
|
+
* Usage:
|
|
343
|
+
* protoToTsType('double') // => 'number'
|
|
344
|
+
* protoToTsType('int32') // => 'number'
|
|
345
|
+
* protoToTsType('bool') // => 'boolean'
|
|
346
|
+
*/
|
|
347
|
+
declare function protoToTsType(protoType: string): string;
|
|
348
|
+
/**
|
|
349
|
+
* Attempts to parse a structured broker error from AMQP reply_text.
|
|
350
|
+
*
|
|
351
|
+
* Returns `null` if the reply_text is a plain string (not JSON)
|
|
352
|
+
* or doesn't match the expected `BrokerErrorPayload` shape.
|
|
353
|
+
*
|
|
354
|
+
* Usage:
|
|
355
|
+
* const payload = parseBrokerError('{"code":"SchemaTypeMismatch",...}');
|
|
356
|
+
*/
|
|
357
|
+
declare function parseBrokerError(replyText: string): BrokerErrorPayload | null;
|
|
358
|
+
/**
|
|
359
|
+
* Extracts the reply_text from an amqplib channel error message.
|
|
360
|
+
*
|
|
361
|
+
* amqplib formats errors as:
|
|
362
|
+
* 'Channel closed by server: 406 (PRECONDITION-FAILED) with message "..."'
|
|
363
|
+
*
|
|
364
|
+
* We extract the content between the last pair of double quotes.
|
|
365
|
+
*
|
|
366
|
+
* Usage:
|
|
367
|
+
* extractReplyText(new Error('...with message "{\"code\":...}"'))
|
|
368
|
+
*/
|
|
369
|
+
declare function extractReplyText(err: unknown): string | null;
|
|
370
|
+
/**
|
|
371
|
+
* Formats a `BrokerErrorPayload` into a developer-friendly message.
|
|
372
|
+
*
|
|
373
|
+
* Uses TypeScript type names (via `protoToTsType`) so the error
|
|
374
|
+
* reads naturally to TS developers.
|
|
375
|
+
*
|
|
376
|
+
* Usage:
|
|
377
|
+
* formatBrokerError(payload)
|
|
378
|
+
* // => "Queue 'orders': field 'id' is number in queue but got string"
|
|
379
|
+
*/
|
|
380
|
+
declare function formatBrokerError(payload: BrokerErrorPayload): string;
|
|
381
|
+
|
|
382
|
+
export { BrokerErrorCode, type BrokerErrorPayload, ConnectionError, ConsumeError, type FieldErrorDetail, PublishError, QueueError, QueueHandle, type RocketAssertQueueOptions, type RocketConsumeOptions, RocketMQ, RocketMQError, type RocketOptions, SchemaError, type SchemaInput, SchemaValidationError, SerializationError, TimeoutError, connect, extractReplyText, formatBrokerError, parseBrokerError, protoToTsType };
|