@miiajs/messaging 0.1.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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/decorators.d.ts +149 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +112 -0
- package/dist/decorators.js.map +1 -0
- package/dist/group-name.d.ts +33 -0
- package/dist/group-name.d.ts.map +1 -0
- package/dist/group-name.js +25 -0
- package/dist/group-name.js.map +1 -0
- package/dist/idempotency.d.ts +66 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +42 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/in-memory-transport.d.ts +60 -0
- package/dist/in-memory-transport.d.ts.map +1 -0
- package/dist/in-memory-transport.js +143 -0
- package/dist/in-memory-transport.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/message-bus.d.ts +83 -0
- package/dist/message-bus.d.ts.map +1 -0
- package/dist/message-bus.js +218 -0
- package/dist/message-bus.js.map +1 -0
- package/dist/messaging.module.d.ts +76 -0
- package/dist/messaging.module.d.ts.map +1 -0
- package/dist/messaging.module.js +74 -0
- package/dist/messaging.module.js.map +1 -0
- package/dist/retry.d.ts +7 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +10 -0
- package/dist/retry.js.map +1 -0
- package/dist/tokens.d.ts +19 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +26 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +165 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { resolveOptions } from '@miiajs/core';
|
|
2
|
+
import { MessageBus } from './message-bus.js';
|
|
3
|
+
import {} from './idempotency.js';
|
|
4
|
+
import { getMessageBusToken, getMessageTransportToken, getIdempotencyStoreToken } from './tokens.js';
|
|
5
|
+
import {} from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Dynamic module that registers a message transport, optional idempotency
|
|
8
|
+
* store, and `MessageBus` in the container.
|
|
9
|
+
*
|
|
10
|
+
* Pass an optional `name` to register a **named bus** alongside the default
|
|
11
|
+
* one - useful when an app needs more than one transport (Kafka + Redis,
|
|
12
|
+
* internal in-memory bus + external Redis, etc.). Handlers target a specific
|
|
13
|
+
* bus via `@On(topic, { bus: name })`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* // Static form, default bus
|
|
18
|
+
* MessagingModule.configure({ transport: inMemoryTransport() })
|
|
19
|
+
*
|
|
20
|
+
* // Factory form with DI access
|
|
21
|
+
* MessagingModule.configure((resolve) => ({
|
|
22
|
+
* transport: redisStreamsTransport({
|
|
23
|
+
* url: resolve(ConfigService).getOrThrow('REDIS_URL'),
|
|
24
|
+
* }),
|
|
25
|
+
* }))
|
|
26
|
+
*
|
|
27
|
+
* // Multi-bus: default + named
|
|
28
|
+
* MessagingModule.configure({ transport: redisStreamsTransport({ url: '...' }) })
|
|
29
|
+
* MessagingModule.configure({ transport: kafkaTransport({ ... }) }, 'kafka')
|
|
30
|
+
*
|
|
31
|
+
* // In a handler
|
|
32
|
+
* @On('order.placed') // default bus
|
|
33
|
+
* @On('legacy.user', { bus: 'kafka' }) // named bus
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export class MessagingModule {
|
|
37
|
+
static configure(optionsOrFactory, name) {
|
|
38
|
+
const transportToken = getMessageTransportToken(name);
|
|
39
|
+
const storeToken = getIdempotencyStoreToken(name);
|
|
40
|
+
const busToken = getMessageBusToken(name);
|
|
41
|
+
// Anonymous module class per name so the DI module loader does not flag
|
|
42
|
+
// a duplicate when configure() is called twice with different names.
|
|
43
|
+
const ModuleClass = name ? class MessagingNamedModule {
|
|
44
|
+
} : MessagingModule;
|
|
45
|
+
return {
|
|
46
|
+
module: ModuleClass,
|
|
47
|
+
providers: [
|
|
48
|
+
{
|
|
49
|
+
token: transportToken,
|
|
50
|
+
factory: (resolve) => resolveOptions(optionsOrFactory, { resolve }).transport,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
// Always registered so MessageBus's optional read resolves cleanly.
|
|
54
|
+
// Value is `null` when the user did not configure a store.
|
|
55
|
+
token: storeToken,
|
|
56
|
+
factory: (resolve) => resolveOptions(optionsOrFactory, { resolve }).idempotency ?? null,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
token: busToken,
|
|
60
|
+
factory: (resolve) => {
|
|
61
|
+
const transport = resolve(transportToken);
|
|
62
|
+
const store = resolve(storeToken);
|
|
63
|
+
const opts = resolveOptions(optionsOrFactory, { resolve });
|
|
64
|
+
return new MessageBus(transport, store, name ?? null, {
|
|
65
|
+
dispatch: opts.dispatch ?? null,
|
|
66
|
+
appName: opts.appName ?? null,
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=messaging.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messaging.module.js","sourceRoot":"","sources":["../src/messaging.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAyB,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AACpG,OAAO,EAA4C,MAAM,YAAY,CAAA;AA2CrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,OAAO,eAAe;IAC1B,MAAM,CAAC,SAAS,CAAC,gBAA0D,EAAE,IAAa;QACxF,MAAM,cAAc,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAA;QACrD,MAAM,UAAU,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAA;QACjD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAEzC,wEAAwE;QACxE,qEAAqE;QACrE,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAE,MAAM,oBAAoB;SAAmB,CAAC,CAAC,CAAC,eAAe,CAAA;QAE3F,OAAO;YACL,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE;gBACT;oBACE,KAAK,EAAE,cAAc;oBACrB,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS;iBAC9E;gBACD;oBACE,oEAAoE;oBACpE,2DAA2D;oBAC3D,KAAK,EAAE,UAAU;oBACjB,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;iBACxF;gBACD;oBACE,KAAK,EAAE,QAAQ;oBACf,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE;wBACnB,MAAM,SAAS,GAAG,OAAO,CAAmB,cAAc,CAAC,CAAA;wBAC3D,MAAM,KAAK,GAAG,OAAO,CAA0B,UAAU,CAAC,CAAA;wBAC1D,MAAM,IAAI,GAAG,cAAc,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;wBAC1D,OAAO,IAAI,UAAU,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,IAAI,IAAI,EAAE;4BACpD,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;4BAC/B,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;yBAC9B,CAAC,CAAA;oBACJ,CAAC;iBACF;aACF;SACF,CAAA;IACH,CAAC;CACF"}
|
package/dist/retry.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RetryConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Exponential backoff: attempt=1 → base, attempt=2 → base*mult, ...
|
|
4
|
+
*/
|
|
5
|
+
export declare function nextBackoffMs(attempt: number, config: RetryConfig): number;
|
|
6
|
+
export declare function dlqTopic(topic: string): string;
|
|
7
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,CAE1E;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|
package/dist/retry.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exponential backoff: attempt=1 → base, attempt=2 → base*mult, ...
|
|
3
|
+
*/
|
|
4
|
+
export function nextBackoffMs(attempt, config) {
|
|
5
|
+
return config.backoffMs * Math.pow(config.backoffMultiplier, attempt - 1);
|
|
6
|
+
}
|
|
7
|
+
export function dlqTopic(topic) {
|
|
8
|
+
return `${topic}.dlq`;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,MAAmB;IAChE,OAAO,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,GAAG,KAAK,MAAM,CAAA;AACvB,CAAC"}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Constructor } from '@miiajs/core';
|
|
2
|
+
import { MessageBus } from './message-bus.js';
|
|
3
|
+
/**
|
|
4
|
+
* DI token for the message transport of a (default or named) bus.
|
|
5
|
+
* Returns the default `MESSAGE_TRANSPORT` constant when called without name.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getMessageTransportToken(name?: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* DI token for the optional idempotency store of a (default or named) bus.
|
|
10
|
+
* Returns the default `IDEMPOTENCY_STORE` constant when called without name.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getIdempotencyStoreToken(name?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* DI token for the MessageBus instance of a (default or named) bus.
|
|
15
|
+
* - default: returns the `MessageBus` class itself, so `inject(MessageBus)` works.
|
|
16
|
+
* - named: returns a string token; use `inject<MessageBus>(getMessageBusToken('kafka'))`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getMessageBusToken(name?: string): string | Constructor<MessageBus>;
|
|
19
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAI7C;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,CAElF"}
|
package/dist/tokens.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MessageBus } from './message-bus.js';
|
|
2
|
+
import { IDEMPOTENCY_STORE } from './idempotency.js';
|
|
3
|
+
import { MESSAGE_TRANSPORT } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* DI token for the message transport of a (default or named) bus.
|
|
6
|
+
* Returns the default `MESSAGE_TRANSPORT` constant when called without name.
|
|
7
|
+
*/
|
|
8
|
+
export function getMessageTransportToken(name) {
|
|
9
|
+
return name ? `miia:messaging:transport:${name}` : MESSAGE_TRANSPORT;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* DI token for the optional idempotency store of a (default or named) bus.
|
|
13
|
+
* Returns the default `IDEMPOTENCY_STORE` constant when called without name.
|
|
14
|
+
*/
|
|
15
|
+
export function getIdempotencyStoreToken(name) {
|
|
16
|
+
return name ? `miia:messaging:idempotency-store:${name}` : IDEMPOTENCY_STORE;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* DI token for the MessageBus instance of a (default or named) bus.
|
|
20
|
+
* - default: returns the `MessageBus` class itself, so `inject(MessageBus)` works.
|
|
21
|
+
* - named: returns a string token; use `inject<MessageBus>(getMessageBusToken('kafka'))`.
|
|
22
|
+
*/
|
|
23
|
+
export function getMessageBusToken(name) {
|
|
24
|
+
return name ? `miia:messaging:bus:${name}` : MessageBus;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE9C;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAa;IACpD,OAAO,IAAI,CAAC,CAAC,CAAC,4BAA4B,IAAI,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAA;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAa;IACpD,OAAO,IAAI,CAAC,CAAC,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAA;AAC9E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAa;IAC9C,OAAO,IAAI,CAAC,CAAC,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAA;AACzD,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full envelope shape that transports publish and deliver. All fields
|
|
3
|
+
* except `payload` are framework-managed. User code only sees `payload`
|
|
4
|
+
* (and optionally `meta`) inside `@On` handlers.
|
|
5
|
+
*/
|
|
6
|
+
export interface MessageEnvelope<T = unknown> {
|
|
7
|
+
id: string;
|
|
8
|
+
topic: string;
|
|
9
|
+
payload: T;
|
|
10
|
+
meta: MessageMeta;
|
|
11
|
+
}
|
|
12
|
+
export interface MessageMeta {
|
|
13
|
+
/** Epoch milliseconds at first publish. Does not change on retry. */
|
|
14
|
+
timestamp: number;
|
|
15
|
+
/** 1 on first delivery, incremented by the transport on each retry. */
|
|
16
|
+
attempt: number;
|
|
17
|
+
correlationId?: string;
|
|
18
|
+
causationId?: string;
|
|
19
|
+
/**
|
|
20
|
+
* W3C Trace Context traceparent header value.
|
|
21
|
+
* Format: `00-<traceId>-<spanId>-<flags>` (e.g. `00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01`).
|
|
22
|
+
*
|
|
23
|
+
* Populate at publish time from your tracing library (OpenTelemetry, Datadog,
|
|
24
|
+
* Sentry, etc.). Consumers can restore span context to continue the
|
|
25
|
+
* distributed trace across service boundaries.
|
|
26
|
+
*
|
|
27
|
+
* Pass `undefined` to skip; do not pass an empty string (it would serialize
|
|
28
|
+
* as a truthy-looking invalid value on the consumer side).
|
|
29
|
+
*
|
|
30
|
+
* @see https://www.w3.org/TR/trace-context/#traceparent-header
|
|
31
|
+
*/
|
|
32
|
+
traceparent?: string;
|
|
33
|
+
/**
|
|
34
|
+
* W3C Trace Context tracestate header. Vendor-specific key/value pairs that
|
|
35
|
+
* accompany `traceparent`.
|
|
36
|
+
*
|
|
37
|
+
* @see https://www.w3.org/TR/trace-context/#tracestate-header
|
|
38
|
+
*/
|
|
39
|
+
tracestate?: string;
|
|
40
|
+
/** Populated only when the envelope is moved to the DLQ. */
|
|
41
|
+
lastError?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Dispatch behavior for a subscription's message-pump loop.
|
|
45
|
+
*
|
|
46
|
+
* - `'batch'` - read up to `concurrency` messages, run them through
|
|
47
|
+
* `Promise.allSettled`, then read again. The slowest handler in the batch
|
|
48
|
+
* blocks the next read (head-of-line). Best for high-throughput uniform
|
|
49
|
+
* workloads with negligible per-message variance.
|
|
50
|
+
* - `'sliding'` - each in-flight message progresses independently; the
|
|
51
|
+
* subscription pulls the next message as soon as a slot frees, without
|
|
52
|
+
* waiting for the rest of the batch. Best when handler runtimes vary.
|
|
53
|
+
*
|
|
54
|
+
* Each transport declares its `supportedModes` and `defaultMode`; the bus
|
|
55
|
+
* validates handler-requested modes against that capability set on startup.
|
|
56
|
+
*/
|
|
57
|
+
export type DispatchMode = 'batch' | 'sliding';
|
|
58
|
+
export interface SubscribeOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Consumer group for load-balancing between replicas/processes.
|
|
61
|
+
* Identical `group` across replicas = broker delivers each message to
|
|
62
|
+
* exactly one replica in the group. Different groups = fan-out (every
|
|
63
|
+
* group gets a copy). In-memory transport ignores this - within a single
|
|
64
|
+
* process local fan-out always runs every matching handler.
|
|
65
|
+
*/
|
|
66
|
+
group?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Prefetch-style: how many messages the transport may pull / process
|
|
69
|
+
* in parallel within one subscription. Redis Streams: XREADGROUP COUNT
|
|
70
|
+
* (batch) or number of sliding lanes. RabbitMQ: basic.qos prefetch.
|
|
71
|
+
* NATS: max_in_flight. Ignored by in-memory.
|
|
72
|
+
*/
|
|
73
|
+
concurrency?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Resolved effective dispatch mode for this subscription. The bus
|
|
76
|
+
* resolves this from `@On({ mode })` > bus default > `transport.defaultMode`
|
|
77
|
+
* and validates against `transport.supportedModes` before calling
|
|
78
|
+
* `subscribe()`. Transports may assume the value is in `supportedModes`.
|
|
79
|
+
*/
|
|
80
|
+
mode?: DispatchMode;
|
|
81
|
+
/**
|
|
82
|
+
* Marker that the group name encodes a per-process suffix (`@On({ broadcast: true })`).
|
|
83
|
+
* Transports that maintain stateful broker-side groups (Redis Streams, Kafka)
|
|
84
|
+
* use this flag to clean up orphaned groups from previous process incarnations
|
|
85
|
+
* on subscribe and to destroy the current group on shutdown. Transports
|
|
86
|
+
* without broker state (in-memory) ignore it.
|
|
87
|
+
*/
|
|
88
|
+
broadcast?: boolean;
|
|
89
|
+
}
|
|
90
|
+
export type HandlerResult = {
|
|
91
|
+
status: 'ack';
|
|
92
|
+
} | {
|
|
93
|
+
status: 'nack';
|
|
94
|
+
error: Error;
|
|
95
|
+
};
|
|
96
|
+
export interface Subscription {
|
|
97
|
+
unsubscribe(): Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
export interface RetryConfig {
|
|
100
|
+
/** Maximum delivery attempts before moving to DLQ (or dropping). Default 5. */
|
|
101
|
+
maxAttempts: number;
|
|
102
|
+
/** Base delay in ms for the first retry. Default 1000. */
|
|
103
|
+
backoffMs: number;
|
|
104
|
+
/** Exponential multiplier applied per attempt. Default 2 (1s, 2s, 4s, 8s...). */
|
|
105
|
+
backoffMultiplier: number;
|
|
106
|
+
/**
|
|
107
|
+
* When true, exhausted messages are published to `<topic>.dlq` with the
|
|
108
|
+
* last error recorded in `meta.lastError`. When false, exhausted messages
|
|
109
|
+
* are acked and logged as errors. Default true.
|
|
110
|
+
*/
|
|
111
|
+
dlq: boolean;
|
|
112
|
+
}
|
|
113
|
+
export declare const DEFAULT_RETRY: RetryConfig;
|
|
114
|
+
/**
|
|
115
|
+
* Transport contract. Concrete implementations:
|
|
116
|
+
* - `InMemoryTransport` (shipped in this package; default for dev and tests)
|
|
117
|
+
* - `RedisStreamsTransport` from `@miiajs/messaging-redis`
|
|
118
|
+
* - Future: NATS, RabbitMQ, Kafka
|
|
119
|
+
*
|
|
120
|
+
* Retry/DLQ logic lives INSIDE each transport - different brokers have
|
|
121
|
+
* different primitives (Redis ZSET scheduler, RabbitMQ DLX, NATS max_deliver).
|
|
122
|
+
* Handlers simply return ack/nack; transport decides what to do next.
|
|
123
|
+
*/
|
|
124
|
+
export interface MessageTransport {
|
|
125
|
+
/**
|
|
126
|
+
* Dispatch modes this transport can implement. The bus reads this list to
|
|
127
|
+
* validate handler-requested modes during `MessageBus.onReady()`. Transports
|
|
128
|
+
* declare only modes for which they have a meaningful primitive - emulating
|
|
129
|
+
* a missing primitive (e.g. fake batch on a single-process transport) just
|
|
130
|
+
* adds an artificial barrier without value.
|
|
131
|
+
*/
|
|
132
|
+
readonly supportedModes: readonly DispatchMode[];
|
|
133
|
+
/**
|
|
134
|
+
* Mode used when neither the handler nor the bus configuration specifies
|
|
135
|
+
* one. Must be a member of `supportedModes`.
|
|
136
|
+
*/
|
|
137
|
+
readonly defaultMode: DispatchMode;
|
|
138
|
+
/**
|
|
139
|
+
* Whether the broker supports competing consumers within a single group:
|
|
140
|
+
* a single message is delivered to exactly one consumer in the group
|
|
141
|
+
* (round-robin / load balancing). When `true`, users can pass an explicit
|
|
142
|
+
* `@On({ group: '...' })` to share work between multiple handlers or
|
|
143
|
+
* replicas. When `false`, only fan-out semantics work; bus rejects explicit
|
|
144
|
+
* `group` at startup with a helpful error.
|
|
145
|
+
*
|
|
146
|
+
* Examples:
|
|
147
|
+
* - `true`: Redis Streams, Kafka, RabbitMQ, NATS Core queue groups, JetStream
|
|
148
|
+
* - `false`: InMemoryTransport (single process, no broker), Redis Pub/Sub
|
|
149
|
+
* (no durable groups)
|
|
150
|
+
*/
|
|
151
|
+
readonly supportsCompetingConsumers: boolean;
|
|
152
|
+
publish(envelope: MessageEnvelope): Promise<void>;
|
|
153
|
+
subscribe(topic: string, handler: (envelope: MessageEnvelope) => Promise<HandlerResult>, options: SubscribeOptions): Promise<Subscription>;
|
|
154
|
+
onInit?(): Promise<void>;
|
|
155
|
+
onDestroy?(): Promise<void>;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* DI token for the message transport. String token because an abstract class
|
|
159
|
+
* is not type-compatible with core's `Constructor<T>` (abstract `new` vs
|
|
160
|
+
* plain `new`). Matches the `JWT_OPTIONS` pattern in `@miiajs/jwt`.
|
|
161
|
+
*
|
|
162
|
+
* Usage: `private transport = inject<MessageTransport>(MESSAGE_TRANSPORT)`.
|
|
163
|
+
*/
|
|
164
|
+
export declare const MESSAGE_TRANSPORT = "miia:messaging:transport";
|
|
165
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,CAAC,CAAA;IACV,IAAI,EAAE,WAAW,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAA;IACjB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,CAAA;AAE9C,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,YAAY,CAAA;IAEnB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAA;AAEhF,MAAM,WAAW,YAAY;IAC3B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAA;IACnB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,iBAAiB,EAAE,MAAM,CAAA;IACzB;;;;OAIG;IACH,GAAG,EAAE,OAAO,CAAA;CACb;AAED,eAAO,MAAM,aAAa,EAAE,WAK3B,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,YAAY,EAAE,CAAA;IAEhD;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAA;IAElC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,0BAA0B,EAAE,OAAO,CAAA;IAE5C,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjD,SAAS,CACP,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAC,aAAa,CAAC,EAC9D,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,YAAY,CAAC,CAAA;IAExB,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,SAAS,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,6BAA6B,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const DEFAULT_RETRY = {
|
|
2
|
+
maxAttempts: 5,
|
|
3
|
+
backoffMs: 1000,
|
|
4
|
+
backoffMultiplier: 2,
|
|
5
|
+
dlq: true,
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* DI token for the message transport. String token because an abstract class
|
|
9
|
+
* is not type-compatible with core's `Constructor<T>` (abstract `new` vs
|
|
10
|
+
* plain `new`). Matches the `JWT_OPTIONS` pattern in `@miiajs/jwt`.
|
|
11
|
+
*
|
|
12
|
+
* Usage: `private transport = inject<MessageTransport>(MESSAGE_TRANSPORT)`.
|
|
13
|
+
*/
|
|
14
|
+
export const MESSAGE_TRANSPORT = 'miia:messaging:transport';
|
|
15
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAqHA,MAAM,CAAC,MAAM,aAAa,GAAgB;IACxC,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,IAAI;IACf,iBAAiB,EAAE,CAAC;IACpB,GAAG,EAAE,IAAI;CACV,CAAA;AAuDD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,0BAA0B,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miiajs/messaging",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"author": "Ruslan Matiushev",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "Messaging for MiiaJS - decorator-driven event bus, retry with auto-DLQ, idempotency, named buses, pluggable transports.",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/miiajs/miia.git",
|
|
10
|
+
"directory": "packages/messaging"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/miiajs/miia/tree/main/packages/messaging#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/miiajs/miia/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"miiajs",
|
|
18
|
+
"miia",
|
|
19
|
+
"messaging",
|
|
20
|
+
"events",
|
|
21
|
+
"event-bus",
|
|
22
|
+
"pubsub",
|
|
23
|
+
"decorator"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"main": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22.22.1",
|
|
45
|
+
"bun": ">=1.3.11",
|
|
46
|
+
"deno": ">=2.6.1"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@miiajs/core": "workspace:*"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc --build",
|
|
53
|
+
"clean": "tsc --build --clean"
|
|
54
|
+
}
|
|
55
|
+
}
|