@nextage/era-lib 1.0.176 → 1.0.178

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.
Files changed (35) hide show
  1. package/build/events/base-event.controller.d.ts +56 -15
  2. package/build/events/base-event.controller.d.ts.map +1 -1
  3. package/build/events/base-event.controller.js +98 -32
  4. package/build/events/base-event.controller.js.map +1 -1
  5. package/build/events/event-relay.d.ts +26 -0
  6. package/build/events/event-relay.d.ts.map +1 -0
  7. package/build/events/event-relay.js +95 -0
  8. package/build/events/event-relay.js.map +1 -0
  9. package/build/events/field-map.d.ts +9 -0
  10. package/build/events/field-map.d.ts.map +1 -0
  11. package/build/events/field-map.js +26 -0
  12. package/build/events/field-map.js.map +1 -0
  13. package/build/events/index.d.ts +3 -0
  14. package/build/events/index.d.ts.map +1 -1
  15. package/build/events/index.js +3 -0
  16. package/build/events/index.js.map +1 -1
  17. package/build/events/publisher-registry.d.ts +21 -0
  18. package/build/events/publisher-registry.d.ts.map +1 -0
  19. package/build/events/publisher-registry.js +46 -0
  20. package/build/events/publisher-registry.js.map +1 -0
  21. package/build/events/types/index.d.ts +2 -0
  22. package/build/events/types/index.d.ts.map +1 -1
  23. package/build/events/types/index.js +2 -0
  24. package/build/events/types/index.js.map +1 -1
  25. package/build/events/types/outbox.interfaces.d.ts +10 -0
  26. package/build/events/types/outbox.interfaces.d.ts.map +1 -1
  27. package/build/events/types/relay.constants.d.ts +3 -0
  28. package/build/events/types/relay.constants.d.ts.map +1 -0
  29. package/build/events/types/relay.constants.js +9 -0
  30. package/build/events/types/relay.constants.js.map +1 -0
  31. package/build/events/types/relay.interfaces.d.ts +11 -0
  32. package/build/events/types/relay.interfaces.d.ts.map +1 -0
  33. package/build/events/types/relay.interfaces.js +5 -0
  34. package/build/events/types/relay.interfaces.js.map +1 -0
  35. package/package.json +1 -1
@@ -3,14 +3,42 @@ import { BaseMongoDoc } from '@nextage/nx-frame-be/build/common/base/base.interf
3
3
  import { BaseController } from '@nextage/nx-frame-be/build/common/base/base.controller';
4
4
  import { NxContext } from '@nextage/nx-frame-be';
5
5
  import { Event, IPublisher } from './interfaces';
6
+ import { PublisherProvider } from './types/relay.interfaces';
6
7
  import { QueueEventType } from './types/enums';
7
- export declare abstract class BaseEventCtrl<TCreate extends Event, TUpdate extends Event, TRemove extends Event, TAttrs, TDoc extends BaseMongoDoc, TModel extends BaseModel<TAttrs, TDoc, any>> extends BaseController<TAttrs, TDoc, TModel> {
8
- protected abstract parsePubCreateItem(item: TAttrs, type: QueueEventType): TCreate['data'];
9
- protected abstract parsePubUpdateItem(item: TAttrs, type: QueueEventType): TUpdate['data'];
10
- protected abstract parsePubRemoveItem(item: TAttrs, type: QueueEventType): TRemove['data'];
8
+ export declare abstract class BaseEventCtrl<TCreate extends Event, TUpdate extends Event, TRemove extends Event, TAttrs, TDoc extends BaseMongoDoc, TModel extends BaseModel<TAttrs, TDoc, any>> extends BaseController<TAttrs, TDoc, TModel> implements PublisherProvider {
9
+ /**
10
+ * Declarative publish field-map (Step 3.4c). The default parsePub* methods pick
11
+ * exactly these keys from the entity, replacing the ~57 hand-written per-controller
12
+ * parsers. `pubFields` drives BOTH create and update; set `pubUpdateFields` only
13
+ * for the rare create ≠ update case; `pubRemoveFields` is the leaner remove subset.
14
+ * A subclass may still OVERRIDE parsePub* directly for non-pick (computed) payloads.
15
+ */
16
+ protected pubFields: (keyof TAttrs)[];
17
+ protected pubUpdateFields?: (keyof TAttrs)[];
18
+ protected pubRemoveFields: (keyof TAttrs)[];
19
+ /**
20
+ * Default create/update/remove parsers: a pure pick over the declared field-map.
21
+ * Overridable when a payload needs computed values (see e.g. i18n-shaped events).
22
+ *
23
+ * @param item
24
+ * @param type
25
+ */
26
+ protected parsePubCreateItem(item: TAttrs, type: QueueEventType): TCreate['data'];
27
+ protected parsePubUpdateItem(item: TAttrs, type: QueueEventType): TUpdate['data'];
28
+ protected parsePubRemoveItem(item: TAttrs, type: QueueEventType): TRemove['data'];
11
29
  protected abstract createPublisher: IPublisher<TCreate>[];
12
30
  protected abstract updatePublisher: IPublisher<TUpdate>[];
13
31
  protected abstract removePublisher: IPublisher<TRemove>[];
32
+ constructor(config: {
33
+ model: TModel;
34
+ mergeUpdate?: boolean;
35
+ });
36
+ /**
37
+ * All publishers this controller owns (create + update + remove). Read LAZILY by
38
+ * the relay's publisher registry to route a `sent:false` outbox row back to its
39
+ * publisher family by subject — so it runs after the subclass field initialisers.
40
+ */
41
+ eventPublishers(): IPublisher<Event>[];
14
42
  private publishConfig?;
15
43
  /**
16
44
  * Inizializza la configurazione dei publisher (lazy initialization)
@@ -23,12 +51,24 @@ export declare abstract class BaseEventCtrl<TCreate extends Event, TUpdate exten
23
51
  * @param context
24
52
  */
25
53
  /**
54
+ * Build the parsed, ready-to-publish message for a write: parse the payload,
55
+ * resolve the subject (shared by every publisher of the type — same event on
56
+ * NATS + msg) and stamp the OUTGOING cascade meta from `context._event` (root
57
+ * when absent). Returns undefined when the type has no publisher/parser. Built
58
+ * ONCE and reused for both the outbox row and the immediate dispatch.
26
59
  *
27
60
  * @param item
28
61
  * @param type
29
62
  * @param context
30
63
  */
31
- publish(item: TAttrs, type: QueueEventType, context: NxContext): Promise<void>;
64
+ private buildMessage;
65
+ /**
66
+ * Dispatch a prepared message on every publisher of its type. Shared by the
67
+ * immediate post-commit dispatch and the relay replay.
68
+ *
69
+ * @param msg
70
+ */
71
+ private publishMessage;
32
72
  /**
33
73
  * Overridable post-write / post-read enrichment of the RETURNED document (e.g.
34
74
  * populate references, attach a joined aggregate). Runs AFTER the atomic write
@@ -81,22 +121,23 @@ export declare abstract class BaseEventCtrl<TCreate extends Event, TUpdate exten
81
121
  */
82
122
  remove(id: string, context: NxContext): Promise<TDoc>;
83
123
  /**
84
- * Persist an outbox row (sent:false) for `item` inside the caller's transaction.
85
- * Returns the row id, or undefined when no outbox is registered (the event is
86
- * then still published, just not tracked).
124
+ * Persist an outbox row (sent:false) for the prepared message inside the
125
+ * caller's transaction. The row carries the subject + parsed payload + cascade
126
+ * meta, so the relay can replay it faithfully. Returns the row id, or undefined
127
+ * when there is no message or no outbox registered (the event is then still
128
+ * dispatched, just not tracked).
87
129
  *
88
- * @param item
89
- * @param type
130
+ * @param msg
90
131
  * @param context
91
132
  */
92
133
  private enqueueOutbox;
93
134
  /**
94
- * Dispatch the event to the broker, then mark the outbox row as sent. Runs AFTER
95
- * the transaction commits, so `publish` (a non-DB side effect) is never retried
96
- * by `withTransaction` and a broker failure leaves a recoverable sent:false row.
135
+ * Dispatch the prepared message to the broker, then mark the outbox row as sent.
136
+ * Runs AFTER the transaction commits, so `publish` (a non-DB side effect) is
137
+ * never retried by `withTransaction` and a broker failure leaves a recoverable
138
+ * sent:false row for the relay (Step 3.5).
97
139
  *
98
- * @param item
99
- * @param type
140
+ * @param msg
100
141
  * @param outboxId
101
142
  * @param context
102
143
  */
@@ -1 +1 @@
1
- {"version":3,"file":"base-event.controller.d.ts","sourceRoot":"","sources":["../../src/events/base-event.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAc,mDAAmD,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAW,wDAAwD,CAAC;AAC3F,OAAO,EAAE,cAAc,EAAE,MAAS,wDAAwD,CAAC;AAE3F,OAAO,EAAE,SAAS,EAAE,MAAc,sBAAsB,CAAC;AAGzD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAKjD,OAAO,EAAE,cAAc,EAAE,MAAS,eAAe,CAAC;AAOlD,8BAAsB,aAAa,CAAC,OAAO,SAAS,KAAK,EAAE,OAAO,SAAS,KAAK,EAAE,OAAO,SAAS,KAAK,EAAE,MAAM,EAAE,IAAI,SAAS,YAAY,EAAE,MAAM,SAAS,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAE,SAAQ,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;IAMnO,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAI,OAAO,CAAC,MAAM,CAAC;IAC3F,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAI,OAAO,CAAC,MAAM,CAAC;IAC3F,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAI,OAAO,CAAC,MAAM,CAAC;IAE3F,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1D,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1D,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IAK1D,OAAO,CAAC,aAAa,CAAC,CAAmD;IAEzE;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;;;;OAKG;IAoBH;;;;;OAKG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpF;;;;;;;;;OASG;cACa,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzE;;;;;OAKG;IACY,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAMzE;;;;;OAKG;IACH;;;;;;;;;;OAUG;IACY,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBtE;;;;;;OAMG;IACY,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlF;;;;;OAKG;IACY,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBpE;;;;;;;;OAQG;YACW,aAAa;IAY3B;;;;;;;;;OASG;YACW,cAAc;CAQ7B"}
1
+ {"version":3,"file":"base-event.controller.d.ts","sourceRoot":"","sources":["../../src/events/base-event.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAuB,mDAAmD,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAoB,wDAAwD,CAAC;AACpG,OAAO,EAAE,cAAc,EAAE,MAAkB,wDAAwD,CAAC;AAEpG,OAAO,EAAE,SAAS,EAAE,MAAuB,sBAAsB,CAAC;AAGlE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAe,cAAc,CAAC;AAO1D,OAAO,EAAE,iBAAiB,EAAE,MAAe,0BAA0B,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAkB,eAAe,CAAC;AAO3D,8BAAsB,aAAa,CAAC,OAAO,SAAS,KAAK,EAAE,OAAO,SAAS,KAAK,EAAE,OAAO,SAAS,KAAK,EAAE,MAAM,EAAE,IAAI,SAAS,YAAY,EAAE,MAAM,SAAS,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAE,SAAQ,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAE,YAAW,iBAAiB;IAMhQ;;;;;;OAMG;IACH,SAAS,CAAC,SAAS,EAAS,CAAC,MAAM,MAAM,CAAC,EAAE,CAAM;IAClD,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,EAAE,CAAC;IAC7C,SAAS,CAAC,eAAe,EAAG,CAAC,MAAM,MAAM,CAAC,EAAE,CAAM;IAElD;;;;;;OAMG;IACH,SAAS,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAI,OAAO,CAAC,MAAM,CAAC;IAIlF,SAAS,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAI,OAAO,CAAC,MAAM,CAAC;IAIlF,SAAS,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAI,OAAO,CAAC,MAAM,CAAC;IAIlF,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1D,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1D,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAK9C,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE;IAM5D;;;;OAIG;IACH,eAAe,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE;IAKtC,OAAO,CAAC,aAAa,CAAC,CAAmD;IAEzE;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;;;;OAKG;IAoBH;;;;;;;;;;OAUG;IACH,OAAO,CAAC,YAAY;IAcpB;;;;;OAKG;YACW,cAAc;IAM5B;;;;;;;;;OASG;cACa,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzE;;;;;OAKG;IACY,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAMzE;;;;;OAKG;IACH;;;;;;;;;;OAUG;IACY,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBtE;;;;;;OAMG;IACY,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlF;;;;;OAKG;IACY,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBpE;;;;;;;;;OASG;YACW,aAAa;IAY3B;;;;;;;;;OASG;YACW,cAAc;CAU7B"}
@@ -5,8 +5,53 @@ const base_controller_1 = require("@nextage/nx-frame-be/build/common/base/base.c
5
5
  const mongo_utils_1 = require("@nextage/nx-frame-be/build/common/base/mongo-utils");
6
6
  const outbox_1 = require("./outbox");
7
7
  const cascade_1 = require("./cascade");
8
+ const field_map_1 = require("./field-map");
9
+ const publisher_registry_1 = require("./publisher-registry");
8
10
  const enums_1 = require("./types/enums");
9
11
  class BaseEventCtrl extends base_controller_1.BaseController {
12
+ /**
13
+ * Default create/update/remove parsers: a pure pick over the declared field-map.
14
+ * Overridable when a payload needs computed values (see e.g. i18n-shaped events).
15
+ *
16
+ * @param item
17
+ * @param type
18
+ */
19
+ parsePubCreateItem(item, type) {
20
+ return (0, field_map_1.pickPubFields)(item, this.pubFields);
21
+ }
22
+ parsePubUpdateItem(item, type) {
23
+ return (0, field_map_1.pickPubFields)(item, this.pubUpdateFields ?? this.pubFields);
24
+ }
25
+ parsePubRemoveItem(item, type) {
26
+ return (0, field_map_1.pickPubFields)(item, this.pubRemoveFields);
27
+ }
28
+ // protected abstract createPublisher: Publisher<TCreate> | NatsPublisher<TCreate>;
29
+ // protected abstract updatePublisher: Publisher<TUpdate> | NatsPublisher<TUpdate>;
30
+ // protected abstract removePublisher: Publisher<TRemove> | NatsPublisher<TRemove>;
31
+ constructor(config) {
32
+ super(config);
33
+ // protected abstract CreatePublisher: new (client: MsgClientInterface) => Publisher<TCreate> | NatsPublisher<TCreate>;
34
+ // protected abstract UpdatePublisher: new (client: MsgClientInterface) => Publisher<TUpdate> | NatsPublisher<TUpdate>;
35
+ // protected abstract RemovePublisher: new (client: MsgClientInterface) => Publisher<TRemove> | NatsPublisher<TRemove>;
36
+ /**
37
+ * Declarative publish field-map (Step 3.4c). The default parsePub* methods pick
38
+ * exactly these keys from the entity, replacing the ~57 hand-written per-controller
39
+ * parsers. `pubFields` drives BOTH create and update; set `pubUpdateFields` only
40
+ * for the rare create ≠ update case; `pubRemoveFields` is the leaner remove subset.
41
+ * A subclass may still OVERRIDE parsePub* directly for non-pick (computed) payloads.
42
+ */
43
+ this.pubFields = [];
44
+ this.pubRemoveFields = [];
45
+ (0, publisher_registry_1.registerPublisherProvider)(this);
46
+ }
47
+ /**
48
+ * All publishers this controller owns (create + update + remove). Read LAZILY by
49
+ * the relay's publisher registry to route a `sent:false` outbox row back to its
50
+ * publisher family by subject — so it runs after the subclass field initialisers.
51
+ */
52
+ eventPublishers() {
53
+ return [...this.createPublisher, ...this.updatePublisher, ...this.removePublisher];
54
+ }
10
55
  /**
11
56
  * Inizializza la configurazione dei publisher (lazy initialization)
12
57
  */
@@ -52,18 +97,36 @@ class BaseEventCtrl extends base_controller_1.BaseController {
52
97
  // }
53
98
  // }
54
99
  /**
100
+ * Build the parsed, ready-to-publish message for a write: parse the payload,
101
+ * resolve the subject (shared by every publisher of the type — same event on
102
+ * NATS + msg) and stamp the OUTGOING cascade meta from `context._event` (root
103
+ * when absent). Returns undefined when the type has no publisher/parser. Built
104
+ * ONCE and reused for both the outbox row and the immediate dispatch.
55
105
  *
56
106
  * @param item
57
107
  * @param type
58
108
  * @param context
59
109
  */
60
- async publish(item, type, context) {
110
+ buildMessage(item, type, context) {
61
111
  const { publishers, parser } = this.getPublishConfig()[type] ?? {};
62
112
  if (!publishers?.length || !parser)
63
- return;
64
- const data = parser(item, type);
65
- const meta = (0, cascade_1.outgoingMeta)(context?._event);
66
- await Promise.all(publishers.map(pub => pub.publish(data, meta)));
113
+ return undefined;
114
+ return {
115
+ type,
116
+ subject: publishers[0].subject,
117
+ data: parser(item, type),
118
+ meta: (0, cascade_1.outgoingMeta)(context?._event),
119
+ };
120
+ }
121
+ /**
122
+ * Dispatch a prepared message on every publisher of its type. Shared by the
123
+ * immediate post-commit dispatch and the relay replay.
124
+ *
125
+ * @param msg
126
+ */
127
+ async publishMessage(msg) {
128
+ const publishers = this.getPublishConfig()[msg.type]?.publishers ?? [];
129
+ await Promise.all(publishers.map(pub => pub.publish(msg.data, msg.meta)));
67
130
  }
68
131
  /**
69
132
  * Overridable post-write / post-read enrichment of the RETURNED document (e.g.
@@ -106,15 +169,15 @@ class BaseEventCtrl extends base_controller_1.BaseController {
106
169
  * @returns
107
170
  */
108
171
  async create(item, context) {
109
- let payload;
172
+ let msg;
110
173
  let outboxId;
111
174
  const res = await this.withTransaction(context, async (ctx) => {
112
175
  const created = await super.create(item, ctx);
113
- payload = created.toJSON();
114
- outboxId = await this.enqueueOutbox(payload, enums_1.QueueEventType.create, ctx);
176
+ msg = this.buildMessage(created.toJSON(), enums_1.QueueEventType.create, context);
177
+ outboxId = await this.enqueueOutbox(msg, ctx);
115
178
  return created;
116
179
  });
117
- await this.dispatchOutbox(payload, enums_1.QueueEventType.create, outboxId, context);
180
+ await this.dispatchOutbox(msg, outboxId, context);
118
181
  return this.decorateDoc(res, context);
119
182
  }
120
183
  /**
@@ -125,15 +188,15 @@ class BaseEventCtrl extends base_controller_1.BaseController {
125
188
  * @returns
126
189
  */
127
190
  async update(id, item, context) {
128
- let payload;
191
+ let msg;
129
192
  let outboxId;
130
193
  const res = await this.withTransaction(context, async (ctx) => {
131
194
  const updated = await super.update(id, item, ctx);
132
- payload = { id, ...updated.toObject() };
133
- outboxId = await this.enqueueOutbox(payload, enums_1.QueueEventType.update, ctx);
195
+ msg = this.buildMessage({ id, ...updated.toObject() }, enums_1.QueueEventType.update, context);
196
+ outboxId = await this.enqueueOutbox(msg, ctx);
134
197
  return updated;
135
198
  });
136
- await this.dispatchOutbox(payload, enums_1.QueueEventType.update, outboxId, context);
199
+ await this.dispatchOutbox(msg, outboxId, context);
137
200
  return this.decorateDoc(res, context);
138
201
  }
139
202
  /**
@@ -143,47 +206,50 @@ class BaseEventCtrl extends base_controller_1.BaseController {
143
206
  * @returns
144
207
  */
145
208
  async remove(id, context) {
146
- let payload;
209
+ let msg;
147
210
  let outboxId;
148
211
  const res = await this.withTransaction(context, async (ctx) => {
149
212
  const removed = await this.model.remove(id, ctx);
150
- payload = { id, ...removed.toObject() };
151
- outboxId = await this.enqueueOutbox(payload, enums_1.QueueEventType.remove, ctx);
213
+ msg = this.buildMessage({ id, ...removed.toObject() }, enums_1.QueueEventType.remove, context);
214
+ outboxId = await this.enqueueOutbox(msg, ctx);
152
215
  return removed;
153
216
  });
154
- await this.dispatchOutbox(payload, enums_1.QueueEventType.remove, outboxId, context);
217
+ await this.dispatchOutbox(msg, outboxId, context);
155
218
  return res;
156
219
  }
157
220
  /**
158
- * Persist an outbox row (sent:false) for `item` inside the caller's transaction.
159
- * Returns the row id, or undefined when no outbox is registered (the event is
160
- * then still published, just not tracked).
221
+ * Persist an outbox row (sent:false) for the prepared message inside the
222
+ * caller's transaction. The row carries the subject + parsed payload + cascade
223
+ * meta, so the relay can replay it faithfully. Returns the row id, or undefined
224
+ * when there is no message or no outbox registered (the event is then still
225
+ * dispatched, just not tracked).
161
226
  *
162
- * @param item
163
- * @param type
227
+ * @param msg
164
228
  * @param context
165
229
  */
166
- async enqueueOutbox(item, type, context) {
230
+ async enqueueOutbox(msg, context) {
167
231
  const outbox = (0, outbox_1.getOutbox)();
168
- if (!outbox)
232
+ if (!outbox || !msg)
169
233
  return undefined;
170
234
  const id = (0, mongo_utils_1.genObjectId)().toString();
171
- const evt = { id, type, data: item };
235
+ const evt = { id, type: msg.type, subject: msg.subject, data: msg.data, meta: msg.meta };
172
236
  await outbox.create(evt, context);
173
237
  return id;
174
238
  }
175
239
  /**
176
- * Dispatch the event to the broker, then mark the outbox row as sent. Runs AFTER
177
- * the transaction commits, so `publish` (a non-DB side effect) is never retried
178
- * by `withTransaction` and a broker failure leaves a recoverable sent:false row.
240
+ * Dispatch the prepared message to the broker, then mark the outbox row as sent.
241
+ * Runs AFTER the transaction commits, so `publish` (a non-DB side effect) is
242
+ * never retried by `withTransaction` and a broker failure leaves a recoverable
243
+ * sent:false row for the relay (Step 3.5).
179
244
  *
180
- * @param item
181
- * @param type
245
+ * @param msg
182
246
  * @param outboxId
183
247
  * @param context
184
248
  */
185
- async dispatchOutbox(item, type, outboxId, context) {
186
- await this.publish(item, type, context);
249
+ async dispatchOutbox(msg, outboxId, context) {
250
+ if (!msg)
251
+ return;
252
+ await this.publishMessage(msg);
187
253
  const outbox = (0, outbox_1.getOutbox)();
188
254
  if (outbox && outboxId)
189
255
  await outbox.markSent(outboxId, context);
@@ -1 +1 @@
1
- {"version":3,"file":"base-event.controller.js","sourceRoot":"","sources":["../../src/events/base-event.controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base-event.controller.js","sourceRoot":"","sources":["../../src/events/base-event.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { EventRelayOptions } from './types/relay.interfaces';
2
+ export declare class EventRelay {
3
+ private readonly batchSize;
4
+ private readonly intervalMs;
5
+ private readonly onError;
6
+ private readonly onSkip;
7
+ private timer?;
8
+ private draining;
9
+ constructor(opts?: EventRelayOptions);
10
+ /**
11
+ * Drain one batch: the oldest `sent:false` rows → re-publish each on every
12
+ * publisher registered for its subject → mark it sent. A row whose subject has
13
+ * no registered publisher (controller not loaded) is skipped and retried on the
14
+ * next tick. Returns the number of rows successfully re-published. Never throws
15
+ * for a single row/broker failure — that row simply stays `sent:false`.
16
+ */
17
+ drainOnce(): Promise<number>;
18
+ /**
19
+ * Start the relay: an immediate startup drain, then a periodic sweep every
20
+ * `intervalMs`. The timer is `unref`'d so it never keeps the process alive.
21
+ */
22
+ start(): void;
23
+ /** Stop the periodic sweep (graceful shutdown / test teardown). */
24
+ stop(): void;
25
+ }
26
+ //# sourceMappingURL=event-relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-relay.d.ts","sourceRoot":"","sources":["../../src/events/event-relay.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,iBAAiB,EAAE,MAAwC,0BAA0B,CAAC;AAG/F,qBAAa,UAAU;IAErB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;IAEnE,OAAO,CAAC,KAAK,CAAC,CAAmC;IACjD,OAAO,CAAC,QAAQ,CAAS;gBAEb,IAAI,GAAE,iBAAsB;IAQxC;;;;;;OAMG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IA2ClC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAab,mEAAmE;IACnE,IAAI,IAAI,IAAI;CAOb"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /* ────────────────────────────────────────────────────────────────────────────
3
+ * EVENT RELAY — at-least-once redelivery of `sent:false` outbox rows (Step 3.5)
4
+ *
5
+ * Closes finding E1: with the atomic outbox (3.4) an entity + its outbox row are
6
+ * committed together, then published post-commit; if the broker is down or the
7
+ * process crashes in that window the row stays `sent:false` and — until now — was
8
+ * never re-published. The relay drains those rows:
9
+ * • at startup → recover events accumulated while THIS service was down;
10
+ * • periodically → recover from a transient broker/network outage while the
11
+ * process stays up (the publish failed but we did not crash).
12
+ *
13
+ * Re-publish is safe (at-least-once): downstream consumers are version-guarded
14
+ * (3.3), so a duplicate delivery is idempotent. Routing back to the publisher is
15
+ * via the subject persisted on the row + the publisher registry.
16
+ * ──────────────────────────────────────────────────────────────────────────── */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.EventRelay = void 0;
19
+ const outbox_1 = require("./outbox");
20
+ const publisher_registry_1 = require("./publisher-registry");
21
+ const relay_constants_1 = require("./types/relay.constants");
22
+ class EventRelay {
23
+ constructor(opts = {}) {
24
+ this.draining = false;
25
+ this.batchSize = opts.batchSize ?? relay_constants_1.DEFAULT_RELAY_BATCH_SIZE;
26
+ this.intervalMs = opts.intervalMs ?? relay_constants_1.DEFAULT_RELAY_INTERVAL_MS;
27
+ this.onError = opts.onError ?? (() => { });
28
+ this.onSkip = opts.onSkip ?? (() => { });
29
+ }
30
+ /**
31
+ * Drain one batch: the oldest `sent:false` rows → re-publish each on every
32
+ * publisher registered for its subject → mark it sent. A row whose subject has
33
+ * no registered publisher (controller not loaded) is skipped and retried on the
34
+ * next tick. Returns the number of rows successfully re-published. Never throws
35
+ * for a single row/broker failure — that row simply stays `sent:false`.
36
+ */
37
+ async drainOnce() {
38
+ const outbox = (0, outbox_1.getOutbox)();
39
+ if (!outbox)
40
+ return 0;
41
+ // Re-entrancy guard: a slow batch must not overlap the periodic tick.
42
+ if (this.draining)
43
+ return 0;
44
+ this.draining = true;
45
+ let sent = 0;
46
+ try {
47
+ const rows = await outbox.findUnsent(this.batchSize);
48
+ for (const row of rows) {
49
+ const publishers = (0, publisher_registry_1.resolvePublishers)(row.subject);
50
+ if (!publishers.length) {
51
+ this.onSkip(row.subject, row.id);
52
+ continue;
53
+ }
54
+ try {
55
+ await Promise.all(publishers.map(pub => pub.publish(row.data, row.meta)));
56
+ await outbox.markSent(row.id, {});
57
+ sent++;
58
+ }
59
+ catch (err) {
60
+ // Leave the row sent:false for the next tick; do not abort the batch.
61
+ this.onError(err);
62
+ }
63
+ }
64
+ }
65
+ catch (err) {
66
+ this.onError(err);
67
+ }
68
+ finally {
69
+ this.draining = false;
70
+ }
71
+ return sent;
72
+ }
73
+ /**
74
+ * Start the relay: an immediate startup drain, then a periodic sweep every
75
+ * `intervalMs`. The timer is `unref`'d so it never keeps the process alive.
76
+ */
77
+ start() {
78
+ if (this.timer)
79
+ return;
80
+ void this.drainOnce().catch(err => this.onError(err));
81
+ this.timer = setInterval(() => {
82
+ void this.drainOnce().catch(err => this.onError(err));
83
+ }, this.intervalMs);
84
+ this.timer.unref?.();
85
+ }
86
+ /** Stop the periodic sweep (graceful shutdown / test teardown). */
87
+ stop() {
88
+ if (this.timer) {
89
+ clearInterval(this.timer);
90
+ this.timer = undefined;
91
+ }
92
+ }
93
+ }
94
+ exports.EventRelay = EventRelay;
95
+ //# sourceMappingURL=event-relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-relay.js","sourceRoot":"","sources":["../../src/events/event-relay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Build a new object holding exactly `keys` picked from `item`, preserving
3
+ * `undefined` values for absent fields (parity with a hand-written literal).
4
+ *
5
+ * @param item source entity
6
+ * @param keys published field set
7
+ */
8
+ export declare function pickPubFields<T>(item: T, keys: readonly (keyof T)[]): Record<string, unknown>;
9
+ //# sourceMappingURL=field-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-map.d.ts","sourceRoot":"","sources":["../../src/events/field-map.ts"],"names":[],"mappings":"AASA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAS7F"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /* ────────────────────────────────────────────────────────────────────────────
3
+ * FIELD-MAP — declarative publish payload picker (Step 3.4c)
4
+ *
5
+ * Backs the default parsePub{Create,Update,Remove}Item of BaseEventCtrl: a pure
6
+ * key-pick that replaces ~57 hand-written per-controller parsers. Keys are copied
7
+ * UNCONDITIONALLY (a missing value lands as `undefined`) so the produced payload
8
+ * is byte-for-byte identical to the old `{ a: item.a, b: item.b }` object literal.
9
+ * ──────────────────────────────────────────────────────────────────────────── */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.pickPubFields = pickPubFields;
12
+ /**
13
+ * Build a new object holding exactly `keys` picked from `item`, preserving
14
+ * `undefined` values for absent fields (parity with a hand-written literal).
15
+ *
16
+ * @param item source entity
17
+ * @param keys published field set
18
+ */
19
+ function pickPubFields(item, keys) {
20
+ const out = {};
21
+ for (const key of keys) {
22
+ out[key] = item?.[key];
23
+ }
24
+ return out;
25
+ }
26
+ //# sourceMappingURL=field-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-map.js","sourceRoot":"","sources":["../../src/events/field-map.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;AASlF,sCASC;AAhBD;;;;;;GAMG;AACH,SAAgB,aAAa,CAAI,IAAO,EAAE,IAA0B;IAElE,MAAM,GAAG,GAA4B,EAAE,CAAC;IAExC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,GAAG,CAAC,GAAa,CAAC,GAAI,IAAY,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -3,7 +3,10 @@ export * from './interfaces';
3
3
  export * from './types';
4
4
  export * from './base-event.controller';
5
5
  export * from './cascade';
6
+ export * from './event-relay';
7
+ export * from './field-map';
6
8
  export * from './outbox';
9
+ export * from './publisher-registry';
7
10
  export * from './msg-client-manager';
8
11
  export * from './msg-wrapper';
9
12
  export * from './base-listener';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AAExB,cAAc,yBAAyB,CAAC;AACxC,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AAGzB,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AAGvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAGhC,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AAExB,cAAc,yBAAyB,CAAC;AACxC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,sBAAsB,CAAC;AAGrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AAGvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAGhC,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
@@ -19,7 +19,10 @@ __exportStar(require("./interfaces"), exports);
19
19
  __exportStar(require("./types"), exports);
20
20
  __exportStar(require("./base-event.controller"), exports);
21
21
  __exportStar(require("./cascade"), exports);
22
+ __exportStar(require("./event-relay"), exports);
23
+ __exportStar(require("./field-map"), exports);
22
24
  __exportStar(require("./outbox"), exports);
25
+ __exportStar(require("./publisher-registry"), exports);
23
26
  // messages on memory
24
27
  __exportStar(require("./msg-client-manager"), exports);
25
28
  __exportStar(require("./msg-wrapper"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,+CAA6B;AAC7B,0CAAwB;AAExB,0DAAwC;AACxC,4CAA0B;AAC1B,2CAAyB;AAEzB,qBAAqB;AACrB,uDAAqC;AACrC,gDAA8B;AAC9B,kDAAgC;AAChC,mDAAiC;AAEjC,mBAAmB;AACnB,wDAAsC;AACtC,iDAA+B;AAC/B,uDAAqC;AACrC,wDAAsC;AAEtC,YAAY;AACZ,iDAA+B;AAC/B,yCAAuB;AAEvB,aAAa;AACb,kDAAgC;AAChC,gDAA8B;AAC9B,6CAA2B;AAC3B,mDAAiC;AACjC,iDAA+B;AAC/B,4CAA0B;AAC1B,sDAAoC;AACpC,2CAAyB;AACzB,kDAAgC;AAEhC,cAAc;AACd,4CAA0B;AAC1B,kDAAgC;AAChC,oDAAkC;AAClC,qDAAmC;AACnC,qDAAmC;AACnC,oDAAkC;AAClC,iDAA+B;AAC/B,mDAAiC;AAEjC,oBAAoB;AACpB,kDAAgC;AAChC,+CAA6B;AAE7B,kBAAkB;AAClB,mCAAmC;AAEnC,cAAc"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,+CAA6B;AAC7B,0CAAwB;AAExB,0DAAwC;AACxC,4CAA0B;AAC1B,gDAA8B;AAC9B,8CAA4B;AAC5B,2CAAyB;AACzB,uDAAqC;AAErC,qBAAqB;AACrB,uDAAqC;AACrC,gDAA8B;AAC9B,kDAAgC;AAChC,mDAAiC;AAEjC,mBAAmB;AACnB,wDAAsC;AACtC,iDAA+B;AAC/B,uDAAqC;AACrC,wDAAsC;AAEtC,YAAY;AACZ,iDAA+B;AAC/B,yCAAuB;AAEvB,aAAa;AACb,kDAAgC;AAChC,gDAA8B;AAC9B,6CAA2B;AAC3B,mDAAiC;AACjC,iDAA+B;AAC/B,4CAA0B;AAC1B,sDAAoC;AACpC,2CAAyB;AACzB,kDAAgC;AAEhC,cAAc;AACd,4CAA0B;AAC1B,kDAAgC;AAChC,oDAAkC;AAClC,qDAAmC;AACnC,qDAAmC;AACnC,oDAAkC;AAClC,iDAA+B;AAC/B,mDAAiC;AAEjC,oBAAoB;AACpB,kDAAgC;AAChC,+CAA6B;AAE7B,kBAAkB;AAClB,mCAAmC;AAEnC,cAAc"}
@@ -0,0 +1,21 @@
1
+ import { Event, IPublisher } from './interfaces';
2
+ import { PublisherProvider } from './types/relay.interfaces';
3
+ /**
4
+ * Register a controller as a publisher provider. Idempotent (Set-backed): a
5
+ * singleton controller constructed once registers once. Called from the
6
+ * BaseEventCtrl constructor with `this`.
7
+ *
8
+ * @param provider
9
+ */
10
+ export declare function registerPublisherProvider(provider: PublisherProvider): void;
11
+ /**
12
+ * All registered publishers whose `subject` matches, gathered across every
13
+ * provider. Read lazily at call time, so a provider registered in a constructor
14
+ * (before its publisher fields are initialised) still resolves correctly later.
15
+ *
16
+ * @param subject
17
+ */
18
+ export declare function resolvePublishers(subject: string): IPublisher<Event>[];
19
+ /** Clear all registered providers (test isolation). */
20
+ export declare function clearPublisherProviders(): void;
21
+ //# sourceMappingURL=publisher-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher-registry.d.ts","sourceRoot":"","sources":["../../src/events/publisher-registry.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAI7D;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAG3E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,CAStE;AAED,uDAAuD;AACvD,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /* ────────────────────────────────────────────────────────────────────────────
3
+ * PUBLISHER REGISTRY — subject → publisher resolution for the relay (Step 3.5)
4
+ *
5
+ * The relay reads a `sent:false` outbox row and must re-publish it, but the
6
+ * concrete publisher lives PER-CONTROLLER (create/update/removePublisher on each
7
+ * BaseEventCtrl). A controller registers ITSELF as a provider in its constructor;
8
+ * the relay later asks `resolvePublishers(subject)`, which reads each provider's
9
+ * `eventPublishers()` LAZILY — so it runs at relay-time (fields initialised), not
10
+ * at construction-time (subclass field initialisers run AFTER super()).
11
+ * ──────────────────────────────────────────────────────────────────────────── */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.registerPublisherProvider = registerPublisherProvider;
14
+ exports.resolvePublishers = resolvePublishers;
15
+ exports.clearPublisherProviders = clearPublisherProviders;
16
+ const _providers = new Set();
17
+ /**
18
+ * Register a controller as a publisher provider. Idempotent (Set-backed): a
19
+ * singleton controller constructed once registers once. Called from the
20
+ * BaseEventCtrl constructor with `this`.
21
+ *
22
+ * @param provider
23
+ */
24
+ function registerPublisherProvider(provider) {
25
+ _providers.add(provider);
26
+ }
27
+ /**
28
+ * All registered publishers whose `subject` matches, gathered across every
29
+ * provider. Read lazily at call time, so a provider registered in a constructor
30
+ * (before its publisher fields are initialised) still resolves correctly later.
31
+ *
32
+ * @param subject
33
+ */
34
+ function resolvePublishers(subject) {
35
+ const out = [];
36
+ for (const provider of _providers)
37
+ for (const pub of provider.eventPublishers())
38
+ if (pub.subject === subject)
39
+ out.push(pub);
40
+ return out;
41
+ }
42
+ /** Clear all registered providers (test isolation). */
43
+ function clearPublisherProviders() {
44
+ _providers.clear();
45
+ }
46
+ //# sourceMappingURL=publisher-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher-registry.js","sourceRoot":"","sources":["../../src/events/publisher-registry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;kFASkF;;AAclF,8DAGC;AASD,8CASC;AAGD,0DAGC;AApCD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;AAEhD;;;;;;GAMG;AACH,SAAgB,yBAAyB,CAAC,QAA2B;IAEnE,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAE/C,MAAM,GAAG,GAAwB,EAAE,CAAC;IAEpC,KAAK,MAAM,QAAQ,IAAI,UAAU;QAC/B,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,eAAe,EAAE;YAC1C,IAAI,GAAG,CAAC,OAAO,KAAK,OAAO;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE/C,OAAO,GAAG,CAAC;AACb,CAAC;AAED,uDAAuD;AACvD,SAAgB,uBAAuB;IAErC,UAAU,CAAC,KAAK,EAAE,CAAC;AACrB,CAAC"}
@@ -15,12 +15,14 @@ export * from './vulnerability.enums';
15
15
  export * from './asset.constants';
16
16
  export * from './dlq.constants';
17
17
  export * from './event-envelope.constants';
18
+ export * from './relay.constants';
18
19
  export * from './asset.interfaces';
19
20
  export * from './control.interfaces';
20
21
  export * from './dlq.interfaces';
21
22
  export * from './event-envelope.interfaces';
22
23
  export * from './events.interfaces';
23
24
  export * from './outbox.interfaces';
25
+ export * from './relay.interfaces';
24
26
  export * from './risk-analysis.interfaces';
25
27
  export * from './threat.interfaces';
26
28
  export * from './vulnerability.interfaces';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/events/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AAEtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAE3C,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAG3C,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/events/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AAEtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAElC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAG3C,cAAc,kBAAkB,CAAC"}
@@ -31,12 +31,14 @@ __exportStar(require("./vulnerability.enums"), exports);
31
31
  __exportStar(require("./asset.constants"), exports);
32
32
  __exportStar(require("./dlq.constants"), exports);
33
33
  __exportStar(require("./event-envelope.constants"), exports);
34
+ __exportStar(require("./relay.constants"), exports);
34
35
  __exportStar(require("./asset.interfaces"), exports);
35
36
  __exportStar(require("./control.interfaces"), exports);
36
37
  __exportStar(require("./dlq.interfaces"), exports);
37
38
  __exportStar(require("./event-envelope.interfaces"), exports);
38
39
  __exportStar(require("./events.interfaces"), exports);
39
40
  __exportStar(require("./outbox.interfaces"), exports);
41
+ __exportStar(require("./relay.interfaces"), exports);
40
42
  __exportStar(require("./risk-analysis.interfaces"), exports);
41
43
  __exportStar(require("./threat.interfaces"), exports);
42
44
  __exportStar(require("./vulnerability.interfaces"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/events/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AAExB,wDAAsC;AACtC,gDAA8B;AAC9B,sDAAoC;AACpC,wDAAsC;AACtC,uDAAqC;AACrC,kDAAgC;AAChC,4DAA0C;AAC1C,iDAA+B;AAC/B,uDAAqC;AACrC,wDAAsC;AACtC,iDAA+B;AAC/B,oDAAkC;AAClC,wDAAsC;AAEtC,oDAAkC;AAClC,kDAAgC;AAChC,6DAA2C;AAE3C,qDAAmC;AACnC,uDAAqC;AACrC,mDAAiC;AACjC,8DAA4C;AAC5C,sDAAoC;AACpC,sDAAoC;AACpC,6DAA2C;AAC3C,sDAAoC;AACpC,6DAA2C;AAE3C,YAAY;AACZ,mDAAiC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/events/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AAExB,wDAAsC;AACtC,gDAA8B;AAC9B,sDAAoC;AACpC,wDAAsC;AACtC,uDAAqC;AACrC,kDAAgC;AAChC,4DAA0C;AAC1C,iDAA+B;AAC/B,uDAAqC;AACrC,wDAAsC;AACtC,iDAA+B;AAC/B,oDAAkC;AAClC,wDAAsC;AAEtC,oDAAkC;AAClC,kDAAgC;AAChC,6DAA2C;AAC3C,oDAAkC;AAElC,qDAAmC;AACnC,uDAAqC;AACrC,mDAAiC;AACjC,8DAA4C;AAC5C,sDAAoC;AACpC,sDAAoC;AACpC,qDAAmC;AACnC,6DAA2C;AAC3C,sDAAoC;AACpC,6DAA2C;AAE3C,YAAY;AACZ,mDAAiC"}
@@ -1,12 +1,22 @@
1
1
  import { NxContext } from '@nextage/nx-frame-be';
2
2
  import { QueueEventType } from './enums';
3
+ import { EventMeta } from './event-envelope.interfaces';
3
4
  export interface OutboxEvent {
4
5
  id: string;
5
6
  type: QueueEventType;
7
+ subject: string;
6
8
  data: any;
9
+ meta?: EventMeta;
10
+ }
11
+ export interface OutboxMessage {
12
+ type: QueueEventType;
13
+ subject: string;
14
+ data: any;
15
+ meta: EventMeta;
7
16
  }
8
17
  export interface OutboxPort {
9
18
  create(evt: OutboxEvent, context: NxContext): Promise<void>;
10
19
  markSent(id: string, context: NxContext): Promise<void>;
20
+ findUnsent(limit: number): Promise<OutboxEvent[]>;
11
21
  }
12
22
  //# sourceMappingURL=outbox.interfaces.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"outbox.interfaces.d.ts","sourceRoot":"","sources":["../../../src/events/types/outbox.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAW,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAKzC,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAI,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,GAAG,CAAC;CACX;AASD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,GAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAQ,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D"}
1
+ {"version":3,"file":"outbox.interfaces.d.ts","sourceRoot":"","sources":["../../../src/events/types/outbox.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAW,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAW,6BAA6B,CAAC;AAS7D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAO,MAAM,CAAC;IAChB,IAAI,EAAK,cAAc,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAK,GAAG,CAAC;IACb,IAAI,CAAC,EAAI,SAAS,CAAC;CACpB;AAQD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAK,cAAc,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAK,GAAG,CAAC;IACb,IAAI,EAAK,SAAS,CAAC;CACpB;AAUD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,GAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAQ,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,UAAU,CAAC,KAAK,EAAE,MAAM,GAAuB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CACvE"}
@@ -0,0 +1,3 @@
1
+ export declare const DEFAULT_RELAY_BATCH_SIZE = 100;
2
+ export declare const DEFAULT_RELAY_INTERVAL_MS = 30000;
3
+ //# sourceMappingURL=relay.constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.constants.d.ts","sourceRoot":"","sources":["../../../src/events/types/relay.constants.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,MAAO,CAAC;AAC7C,eAAO,MAAM,yBAAyB,QAAS,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ // Relay (Step 3.5) tuning defaults. The relay redelivers `sent:false` outbox rows
3
+ // at startup (recover from a previous crash) and periodically (recover from a
4
+ // transient broker/network outage while the process stays up).
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_RELAY_INTERVAL_MS = exports.DEFAULT_RELAY_BATCH_SIZE = void 0;
7
+ exports.DEFAULT_RELAY_BATCH_SIZE = 100; // rows drained per tick
8
+ exports.DEFAULT_RELAY_INTERVAL_MS = 30000; // 30s periodic sweep
9
+ //# sourceMappingURL=relay.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.constants.js","sourceRoot":"","sources":["../../../src/events/types/relay.constants.ts"],"names":[],"mappings":";AAAA,kFAAkF;AAClF,8EAA8E;AAC9E,+DAA+D;;;AAElD,QAAA,wBAAwB,GAAI,GAAG,CAAC,CAAI,wBAAwB;AAC5D,QAAA,yBAAyB,GAAG,KAAM,CAAC,CAAC,qBAAqB"}
@@ -0,0 +1,11 @@
1
+ import { Event, IPublisher } from '../interfaces';
2
+ export interface EventRelayOptions {
3
+ batchSize?: number;
4
+ intervalMs?: number;
5
+ onError?: (err: unknown) => void;
6
+ onSkip?: (subject: string, id: string) => void;
7
+ }
8
+ export interface PublisherProvider {
9
+ eventPublishers(): IPublisher<Event>[];
10
+ }
11
+ //# sourceMappingURL=relay.interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.interfaces.d.ts","sourceRoot":"","sources":["../../../src/events/types/relay.interfaces.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAIlD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAG,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAK,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,MAAM,CAAC,EAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AAKD,MAAM,WAAW,iBAAiB;IAChC,eAAe,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;CACxC"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // Relay (Step 3.5) contracts. Kept separate from the relay/registry logic that
3
+ // consumes them (house rule: types live in `<concern>.interfaces.ts`).
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ //# sourceMappingURL=relay.interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.interfaces.js","sourceRoot":"","sources":["../../../src/events/types/relay.interfaces.ts"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,uEAAuE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextage/era-lib",
3
- "version": "1.0.176",
3
+ "version": "1.0.178",
4
4
  "main": "./build/index.js",
5
5
  "types": "./build/index.d.ts",
6
6
  "files": [