@kronos-ts/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.
Files changed (266) hide show
  1. package/dist/command-bus.d.ts +30 -0
  2. package/dist/command-bus.d.ts.map +1 -0
  3. package/dist/command-bus.js +2 -0
  4. package/dist/command-bus.js.map +1 -0
  5. package/dist/command-handler.d.ts +58 -0
  6. package/dist/command-handler.d.ts.map +1 -0
  7. package/dist/command-handler.js +12 -0
  8. package/dist/command-handler.js.map +1 -0
  9. package/dist/command-handling-module.d.ts +53 -0
  10. package/dist/command-handling-module.d.ts.map +1 -0
  11. package/dist/command-handling-module.js +130 -0
  12. package/dist/command-handling-module.js.map +1 -0
  13. package/dist/correlation-data.d.ts +79 -0
  14. package/dist/correlation-data.d.ts.map +1 -0
  15. package/dist/correlation-data.js +133 -0
  16. package/dist/correlation-data.js.map +1 -0
  17. package/dist/dead-letter-queue.d.ts +134 -0
  18. package/dist/dead-letter-queue.d.ts.map +1 -0
  19. package/dist/dead-letter-queue.js +176 -0
  20. package/dist/dead-letter-queue.js.map +1 -0
  21. package/dist/dead-lettering-handler.d.ts +42 -0
  22. package/dist/dead-lettering-handler.d.ts.map +1 -0
  23. package/dist/dead-lettering-handler.js +67 -0
  24. package/dist/dead-lettering-handler.js.map +1 -0
  25. package/dist/descriptor.d.ts +135 -0
  26. package/dist/descriptor.d.ts.map +1 -0
  27. package/dist/descriptor.js +36 -0
  28. package/dist/descriptor.js.map +1 -0
  29. package/dist/emit-update.d.ts +22 -0
  30. package/dist/emit-update.d.ts.map +1 -0
  31. package/dist/emit-update.js +23 -0
  32. package/dist/emit-update.js.map +1 -0
  33. package/dist/event-bus.d.ts +29 -0
  34. package/dist/event-bus.d.ts.map +1 -0
  35. package/dist/event-bus.js +22 -0
  36. package/dist/event-bus.js.map +1 -0
  37. package/dist/event-criteria.d.ts +87 -0
  38. package/dist/event-criteria.d.ts.map +1 -0
  39. package/dist/event-criteria.js +90 -0
  40. package/dist/event-criteria.js.map +1 -0
  41. package/dist/event-gateway.d.ts +19 -0
  42. package/dist/event-gateway.d.ts.map +1 -0
  43. package/dist/event-gateway.js +22 -0
  44. package/dist/event-gateway.js.map +1 -0
  45. package/dist/event-handler.d.ts +30 -0
  46. package/dist/event-handler.d.ts.map +1 -0
  47. package/dist/event-handler.js +18 -0
  48. package/dist/event-handler.js.map +1 -0
  49. package/dist/event-processor-builder.d.ts +148 -0
  50. package/dist/event-processor-builder.d.ts.map +1 -0
  51. package/dist/event-processor-builder.js +175 -0
  52. package/dist/event-processor-builder.js.map +1 -0
  53. package/dist/event-processor.d.ts +10 -0
  54. package/dist/event-processor.d.ts.map +1 -0
  55. package/dist/event-processor.js +2 -0
  56. package/dist/event-processor.js.map +1 -0
  57. package/dist/event-sink.d.ts +23 -0
  58. package/dist/event-sink.d.ts.map +1 -0
  59. package/dist/event-sink.js +2 -0
  60. package/dist/event-sink.js.map +1 -0
  61. package/dist/event-source.d.ts +98 -0
  62. package/dist/event-source.d.ts.map +1 -0
  63. package/dist/event-source.js +191 -0
  64. package/dist/event-source.js.map +1 -0
  65. package/dist/gateway.d.ts +68 -0
  66. package/dist/gateway.d.ts.map +1 -0
  67. package/dist/gateway.js +62 -0
  68. package/dist/gateway.js.map +1 -0
  69. package/dist/handler-enhancer.d.ts +53 -0
  70. package/dist/handler-enhancer.d.ts.map +1 -0
  71. package/dist/handler-enhancer.js +17 -0
  72. package/dist/handler-enhancer.js.map +1 -0
  73. package/dist/handler.d.ts +51 -0
  74. package/dist/handler.d.ts.map +1 -0
  75. package/dist/handler.js +26 -0
  76. package/dist/handler.js.map +1 -0
  77. package/dist/index.d.ts +53 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +103 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/intercepting-command-bus.d.ts +17 -0
  82. package/dist/intercepting-command-bus.d.ts.map +1 -0
  83. package/dist/intercepting-command-bus.js +54 -0
  84. package/dist/intercepting-command-bus.js.map +1 -0
  85. package/dist/intercepting-event-bus.d.ts +8 -0
  86. package/dist/intercepting-event-bus.d.ts.map +1 -0
  87. package/dist/intercepting-event-bus.js +22 -0
  88. package/dist/intercepting-event-bus.js.map +1 -0
  89. package/dist/intercepting-query-bus.d.ts +17 -0
  90. package/dist/intercepting-query-bus.d.ts.map +1 -0
  91. package/dist/intercepting-query-bus.js +68 -0
  92. package/dist/intercepting-query-bus.js.map +1 -0
  93. package/dist/interceptor.d.ts +46 -0
  94. package/dist/interceptor.d.ts.map +1 -0
  95. package/dist/interceptor.js +2 -0
  96. package/dist/interceptor.js.map +1 -0
  97. package/dist/message-monitor-registry.d.ts +28 -0
  98. package/dist/message-monitor-registry.d.ts.map +1 -0
  99. package/dist/message-monitor-registry.js +37 -0
  100. package/dist/message-monitor-registry.js.map +1 -0
  101. package/dist/message-monitor.d.ts +36 -0
  102. package/dist/message-monitor.d.ts.map +1 -0
  103. package/dist/message-monitor.js +39 -0
  104. package/dist/message-monitor.js.map +1 -0
  105. package/dist/message.d.ts +42 -0
  106. package/dist/message.d.ts.map +1 -0
  107. package/dist/message.js +2 -0
  108. package/dist/message.js.map +1 -0
  109. package/dist/processing-state.d.ts +115 -0
  110. package/dist/processing-state.d.ts.map +1 -0
  111. package/dist/processing-state.js +205 -0
  112. package/dist/processing-state.js.map +1 -0
  113. package/dist/processor-configuration.d.ts +51 -0
  114. package/dist/processor-configuration.d.ts.map +1 -0
  115. package/dist/processor-configuration.js +2 -0
  116. package/dist/processor-configuration.js.map +1 -0
  117. package/dist/query-bus.d.ts +51 -0
  118. package/dist/query-bus.d.ts.map +1 -0
  119. package/dist/query-bus.js +2 -0
  120. package/dist/query-bus.js.map +1 -0
  121. package/dist/query-handler.d.ts +35 -0
  122. package/dist/query-handler.d.ts.map +1 -0
  123. package/dist/query-handler.js +19 -0
  124. package/dist/query-handler.js.map +1 -0
  125. package/dist/query-handling-module.d.ts +24 -0
  126. package/dist/query-handling-module.d.ts.map +1 -0
  127. package/dist/query-handling-module.js +32 -0
  128. package/dist/query-handling-module.js.map +1 -0
  129. package/dist/replay-token.d.ts +31 -0
  130. package/dist/replay-token.d.ts.map +1 -0
  131. package/dist/replay-token.js +37 -0
  132. package/dist/replay-token.js.map +1 -0
  133. package/dist/retrying-command-bus.d.ts +32 -0
  134. package/dist/retrying-command-bus.d.ts.map +1 -0
  135. package/dist/retrying-command-bus.js +58 -0
  136. package/dist/retrying-command-bus.js.map +1 -0
  137. package/dist/routing-strategy.d.ts +30 -0
  138. package/dist/routing-strategy.d.ts.map +1 -0
  139. package/dist/routing-strategy.js +37 -0
  140. package/dist/routing-strategy.js.map +1 -0
  141. package/dist/segment.d.ts +72 -0
  142. package/dist/segment.d.ts.map +1 -0
  143. package/dist/segment.js +103 -0
  144. package/dist/segment.js.map +1 -0
  145. package/dist/send.d.ts +28 -0
  146. package/dist/send.d.ts.map +1 -0
  147. package/dist/send.js +36 -0
  148. package/dist/send.js.map +1 -0
  149. package/dist/serializer.d.ts +40 -0
  150. package/dist/serializer.d.ts.map +1 -0
  151. package/dist/serializer.js +90 -0
  152. package/dist/serializer.js.map +1 -0
  153. package/dist/simple-command-bus.d.ts +23 -0
  154. package/dist/simple-command-bus.d.ts.map +1 -0
  155. package/dist/simple-command-bus.js +49 -0
  156. package/dist/simple-command-bus.js.map +1 -0
  157. package/dist/simple-query-bus.d.ts +16 -0
  158. package/dist/simple-query-bus.d.ts.map +1 -0
  159. package/dist/simple-query-bus.js +122 -0
  160. package/dist/simple-query-bus.js.map +1 -0
  161. package/dist/span-factory.d.ts +58 -0
  162. package/dist/span-factory.d.ts.map +1 -0
  163. package/dist/span-factory.js +19 -0
  164. package/dist/span-factory.js.map +1 -0
  165. package/dist/streaming-event-processor.d.ts +65 -0
  166. package/dist/streaming-event-processor.d.ts.map +1 -0
  167. package/dist/streaming-event-processor.js +239 -0
  168. package/dist/streaming-event-processor.js.map +1 -0
  169. package/dist/subscribing-event-processor.d.ts +57 -0
  170. package/dist/subscribing-event-processor.d.ts.map +1 -0
  171. package/dist/subscribing-event-processor.js +100 -0
  172. package/dist/subscribing-event-processor.js.map +1 -0
  173. package/dist/subscription-query.d.ts +63 -0
  174. package/dist/subscription-query.d.ts.map +1 -0
  175. package/dist/subscription-query.js +119 -0
  176. package/dist/subscription-query.js.map +1 -0
  177. package/dist/token-store.d.ts +83 -0
  178. package/dist/token-store.d.ts.map +1 -0
  179. package/dist/token-store.js +112 -0
  180. package/dist/token-store.js.map +1 -0
  181. package/dist/tracing-command-bus.d.ts +16 -0
  182. package/dist/tracing-command-bus.d.ts.map +1 -0
  183. package/dist/tracing-command-bus.js +44 -0
  184. package/dist/tracing-command-bus.js.map +1 -0
  185. package/dist/tracing-handler-enhancer.d.ts +11 -0
  186. package/dist/tracing-handler-enhancer.d.ts.map +1 -0
  187. package/dist/tracing-handler-enhancer.js +27 -0
  188. package/dist/tracing-handler-enhancer.js.map +1 -0
  189. package/dist/tracking-event-processor.d.ts +72 -0
  190. package/dist/tracking-event-processor.d.ts.map +1 -0
  191. package/dist/tracking-event-processor.js +223 -0
  192. package/dist/tracking-event-processor.js.map +1 -0
  193. package/dist/tracking-token.d.ts +120 -0
  194. package/dist/tracking-token.d.ts.map +1 -0
  195. package/dist/tracking-token.js +132 -0
  196. package/dist/tracking-token.js.map +1 -0
  197. package/dist/transaction.d.ts +60 -0
  198. package/dist/transaction.d.ts.map +1 -0
  199. package/dist/transaction.js +74 -0
  200. package/dist/transaction.js.map +1 -0
  201. package/dist/unit-of-work.d.ts +41 -0
  202. package/dist/unit-of-work.d.ts.map +1 -0
  203. package/dist/unit-of-work.js +96 -0
  204. package/dist/unit-of-work.js.map +1 -0
  205. package/dist/upcaster.d.ts +91 -0
  206. package/dist/upcaster.d.ts.map +1 -0
  207. package/dist/upcaster.js +114 -0
  208. package/dist/upcaster.js.map +1 -0
  209. package/dist/with-namespace.d.ts +59 -0
  210. package/dist/with-namespace.d.ts.map +1 -0
  211. package/dist/with-namespace.js +42 -0
  212. package/dist/with-namespace.js.map +1 -0
  213. package/package.json +65 -0
  214. package/src/command-bus.ts +34 -0
  215. package/src/command-handler.ts +116 -0
  216. package/src/command-handling-module.ts +183 -0
  217. package/src/correlation-data.ts +169 -0
  218. package/src/dead-letter-queue.ts +330 -0
  219. package/src/dead-lettering-handler.ts +109 -0
  220. package/src/descriptor.ts +176 -0
  221. package/src/emit-update.ts +35 -0
  222. package/src/event-bus.ts +45 -0
  223. package/src/event-criteria.ts +141 -0
  224. package/src/event-gateway.ts +42 -0
  225. package/src/event-handler.ts +44 -0
  226. package/src/event-processor-builder.ts +246 -0
  227. package/src/event-processor.ts +9 -0
  228. package/src/event-sink.ts +23 -0
  229. package/src/event-source.ts +301 -0
  230. package/src/gateway.ts +144 -0
  231. package/src/handler-enhancer.ts +70 -0
  232. package/src/handler.ts +133 -0
  233. package/src/index.ts +356 -0
  234. package/src/intercepting-command-bus.ts +73 -0
  235. package/src/intercepting-event-bus.ts +29 -0
  236. package/src/intercepting-query-bus.ts +104 -0
  237. package/src/interceptor.ts +48 -0
  238. package/src/message-monitor-registry.ts +64 -0
  239. package/src/message-monitor.ts +68 -0
  240. package/src/message.ts +41 -0
  241. package/src/processing-state.ts +258 -0
  242. package/src/processor-configuration.ts +59 -0
  243. package/src/query-bus.ts +69 -0
  244. package/src/query-handler.ts +49 -0
  245. package/src/query-handling-module.ts +44 -0
  246. package/src/replay-token.ts +53 -0
  247. package/src/retrying-command-bus.ts +80 -0
  248. package/src/routing-strategy.ts +59 -0
  249. package/src/segment.ts +136 -0
  250. package/src/send.ts +44 -0
  251. package/src/serializer.ts +122 -0
  252. package/src/simple-command-bus.ts +59 -0
  253. package/src/simple-query-bus.ts +158 -0
  254. package/src/span-factory.ts +81 -0
  255. package/src/streaming-event-processor.ts +351 -0
  256. package/src/subscribing-event-processor.ts +169 -0
  257. package/src/subscription-query.ts +173 -0
  258. package/src/token-store.ts +211 -0
  259. package/src/tracing-command-bus.ts +52 -0
  260. package/src/tracing-handler-enhancer.ts +34 -0
  261. package/src/tracking-event-processor.ts +336 -0
  262. package/src/tracking-token.ts +231 -0
  263. package/src/transaction.ts +98 -0
  264. package/src/unit-of-work.ts +138 -0
  265. package/src/upcaster.ts +174 -0
  266. package/src/with-namespace.ts +75 -0
@@ -0,0 +1,134 @@
1
+ import type { EventMessage } from "./message.js";
2
+ /**
3
+ * A dead letter — an event that failed processing and was parked
4
+ * for later retry or manual intervention.
5
+ */
6
+ export interface DeadLetter {
7
+ /** The original event message that failed. */
8
+ readonly message: EventMessage;
9
+ /** The error that caused the failure. */
10
+ readonly cause: Error;
11
+ /** When this letter was first enqueued. */
12
+ readonly enqueuedAt: number;
13
+ /** When this letter was last touched (enqueued or requeued). */
14
+ readonly lastTouched: number;
15
+ /** Additional diagnostics metadata about the failure. */
16
+ readonly diagnostics: Record<string, unknown>;
17
+ /** The sequence identifier this letter belongs to. */
18
+ readonly sequenceIdentifier: string;
19
+ }
20
+ /**
21
+ * Decision on whether to enqueue a failed event as a dead letter.
22
+ */
23
+ export interface EnqueueDecision {
24
+ /** Whether to enqueue the failed event. */
25
+ readonly shouldEnqueue: boolean;
26
+ /** Optional updated cause (may differ from original). */
27
+ readonly cause?: Error;
28
+ /** Additional diagnostics to attach. */
29
+ readonly diagnostics?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * Policy that determines whether a failed event should be dead-lettered.
33
+ */
34
+ export interface EnqueuePolicy {
35
+ /**
36
+ * Decide whether to enqueue a failed event.
37
+ * @param letter The dead letter candidate
38
+ * @param cause The error that caused the failure
39
+ */
40
+ decide(letter: DeadLetter, cause: Error): EnqueueDecision;
41
+ }
42
+ /**
43
+ * Default policy: always enqueue with the original cause.
44
+ */
45
+ export declare function alwaysEnqueuePolicy(): EnqueuePolicy;
46
+ /**
47
+ * A sequenced dead letter queue that maintains ordering within sequences.
48
+ *
49
+ * Events in the same sequence (identified by `sequenceIdentifier`) are
50
+ * ordered by insertion. When a sequence has dead letters, subsequent
51
+ * events in that sequence are also dead-lettered to preserve ordering.
52
+ *
53
+ * Typical sequence identifier: aggregate ID or correlation ID.
54
+ *
55
+ * Database-backed implementations participate in the active UnitOfWork via
56
+ * the ALS-managed transaction (read through `getActiveTransaction()` /
57
+ * `getResource(TRANSACTION_KEY)`); no `ProcessingContext` parameter is
58
+ * threaded through the public surface.
59
+ */
60
+ export interface SequencedDeadLetterQueue {
61
+ /**
62
+ * Enqueue a dead letter into the given sequence.
63
+ */
64
+ enqueue(letter: DeadLetter): Promise<void>;
65
+ /**
66
+ * Enqueue a dead letter only if the sequence already has dead letters.
67
+ * Used to block subsequent events in a failed sequence.
68
+ * The supplier is only called if the sequence exists (avoids creating
69
+ * unnecessary objects).
70
+ * Returns true if the letter was enqueued (sequence existed).
71
+ */
72
+ enqueueIfPresent(sequenceIdentifier: string, letterSupplier: () => DeadLetter): Promise<boolean>;
73
+ /**
74
+ * Remove a dead letter from the queue (successfully reprocessed).
75
+ */
76
+ evict(sequenceIdentifier: string, letter: DeadLetter): Promise<void>;
77
+ /**
78
+ * Re-insert a dead letter at the front of its sequence with updated properties.
79
+ */
80
+ requeue(letter: DeadLetter, update?: Partial<Pick<DeadLetter, "cause" | "diagnostics">>): Promise<void>;
81
+ /**
82
+ * Check if a sequence has any dead letters.
83
+ */
84
+ contains(sequenceIdentifier: string): Promise<boolean>;
85
+ /**
86
+ * Get all dead letters in a sequence, in insertion order.
87
+ */
88
+ deadLetterSequence(sequenceIdentifier: string): Promise<DeadLetter[]>;
89
+ /**
90
+ * Get all sequence identifiers that have dead letters.
91
+ */
92
+ sequenceIdentifiers(): Promise<string[]>;
93
+ /**
94
+ * Process the oldest dead letter sequence matching the filter.
95
+ * For each letter in the sequence:
96
+ * - If processingTask returns `{ shouldEnqueue: false }`: letter is evicted, continue
97
+ * - If processingTask returns `{ shouldEnqueue: true }`: letter is requeued, stop
98
+ *
99
+ * Returns true if a sequence was processed.
100
+ */
101
+ process(sequenceFilter: (sequenceId: string) => boolean, processingTask: (letter: DeadLetter) => Promise<EnqueueDecision>): Promise<boolean>;
102
+ /** Total number of dead letters across all sequences. */
103
+ size(): number;
104
+ /** Number of sequences with dead letters. */
105
+ amountOfSequences(): number;
106
+ /** Clear all dead letters. */
107
+ clear(): Promise<void>;
108
+ /**
109
+ * Check if the queue is full for the given sequence.
110
+ * Returns true if max sequences or max sequence size is reached.
111
+ */
112
+ isFull(sequenceIdentifier: string): boolean;
113
+ }
114
+ /**
115
+ * Creates an in-memory dead letter queue.
116
+ *
117
+ * @param options.maxSequences Maximum number of sequences (default: 1024)
118
+ * @param options.maxSequenceSize Maximum letters per sequence (default: 1024)
119
+ */
120
+ export declare function createInMemoryDeadLetterQueue(options?: {
121
+ maxSequences?: number;
122
+ maxSequenceSize?: number;
123
+ }): SequencedDeadLetterQueue;
124
+ /**
125
+ * Thrown when the dead letter queue is full.
126
+ */
127
+ export declare class DeadLetterQueueOverflowError extends Error {
128
+ constructor(message: string);
129
+ }
130
+ /**
131
+ * Creates a DeadLetter from a failed event.
132
+ */
133
+ export declare function createDeadLetter(message: EventMessage, cause: Error, sequenceIdentifier: string, diagnostics?: Record<string, unknown>): DeadLetter;
134
+ //# sourceMappingURL=dead-letter-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-letter-queue.d.ts","sourceRoot":"","sources":["../src/dead-letter-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Default policy: always enqueue with the original cause.
3
+ */
4
+ export function alwaysEnqueuePolicy() {
5
+ return {
6
+ decide() {
7
+ return { shouldEnqueue: true };
8
+ },
9
+ };
10
+ }
11
+ /**
12
+ * Creates an in-memory dead letter queue.
13
+ *
14
+ * @param options.maxSequences Maximum number of sequences (default: 1024)
15
+ * @param options.maxSequenceSize Maximum letters per sequence (default: 1024)
16
+ */
17
+ export function createInMemoryDeadLetterQueue(options) {
18
+ const maxSequences = options?.maxSequences ?? 1024;
19
+ const maxSequenceSize = options?.maxSequenceSize ?? 1024;
20
+ const sequences = new Map();
21
+ const processing = new Set();
22
+ return {
23
+ async enqueue(letter) {
24
+ const seq = sequences.get(letter.sequenceIdentifier);
25
+ if (seq) {
26
+ if (seq.length >= maxSequenceSize) {
27
+ throw new DeadLetterQueueOverflowError(`sequence "${letter.sequenceIdentifier}" has reached max size ${maxSequenceSize}`);
28
+ }
29
+ seq.push(letter);
30
+ }
31
+ else {
32
+ if (sequences.size >= maxSequences) {
33
+ throw new DeadLetterQueueOverflowError(`max sequences ${maxSequences} reached`);
34
+ }
35
+ sequences.set(letter.sequenceIdentifier, [letter]);
36
+ }
37
+ },
38
+ async enqueueIfPresent(sequenceIdentifier, letterSupplier) {
39
+ const seq = sequences.get(sequenceIdentifier);
40
+ if (!seq)
41
+ return false;
42
+ if (seq.length >= maxSequenceSize) {
43
+ throw new DeadLetterQueueOverflowError(`sequence "${sequenceIdentifier}" has reached max size ${maxSequenceSize}`);
44
+ }
45
+ seq.push(letterSupplier());
46
+ return true;
47
+ },
48
+ async evict(sequenceIdentifier, letter) {
49
+ const seq = sequences.get(sequenceIdentifier);
50
+ if (!seq)
51
+ return;
52
+ const idx = seq.indexOf(letter);
53
+ if (idx >= 0)
54
+ seq.splice(idx, 1);
55
+ if (seq.length === 0)
56
+ sequences.delete(sequenceIdentifier);
57
+ },
58
+ async requeue(letter, update) {
59
+ const seq = sequences.get(letter.sequenceIdentifier);
60
+ if (!seq)
61
+ return;
62
+ const updated = {
63
+ ...letter,
64
+ lastTouched: Date.now(),
65
+ cause: update?.cause ?? letter.cause,
66
+ diagnostics: update?.diagnostics
67
+ ? { ...letter.diagnostics, ...update.diagnostics }
68
+ : letter.diagnostics,
69
+ };
70
+ const idx = seq.indexOf(letter);
71
+ if (idx >= 0)
72
+ seq.splice(idx, 1);
73
+ seq.unshift(updated);
74
+ },
75
+ async contains(sequenceIdentifier) {
76
+ const seq = sequences.get(sequenceIdentifier);
77
+ return seq !== undefined && seq.length > 0;
78
+ },
79
+ async deadLetterSequence(sequenceIdentifier) {
80
+ return sequences.get(sequenceIdentifier) ?? [];
81
+ },
82
+ async sequenceIdentifiers() {
83
+ return [...sequences.keys()];
84
+ },
85
+ async process(sequenceFilter, processingTask) {
86
+ // Find oldest untaken sequence matching filter
87
+ let oldestId;
88
+ let oldestTime = Infinity;
89
+ for (const [id, letters] of sequences) {
90
+ if (processing.has(id))
91
+ continue;
92
+ if (letters.length === 0)
93
+ continue;
94
+ if (!sequenceFilter(id))
95
+ continue;
96
+ const firstTouched = letters[0].lastTouched;
97
+ if (firstTouched < oldestTime) {
98
+ oldestTime = firstTouched;
99
+ oldestId = id;
100
+ }
101
+ }
102
+ if (!oldestId)
103
+ return false;
104
+ processing.add(oldestId);
105
+ try {
106
+ const letters = sequences.get(oldestId);
107
+ if (!letters)
108
+ return false;
109
+ // Process letters in order — take a snapshot of current letters
110
+ const snapshot = [...letters];
111
+ for (const letter of snapshot) {
112
+ const decision = await processingTask(letter);
113
+ if (decision.shouldEnqueue) {
114
+ // Requeue and stop — sequence is still blocked
115
+ await this.requeue(letter, {
116
+ cause: decision.cause,
117
+ diagnostics: decision.diagnostics,
118
+ });
119
+ return true;
120
+ }
121
+ // Evict — successfully reprocessed
122
+ await this.evict(oldestId, letter);
123
+ }
124
+ return true;
125
+ }
126
+ finally {
127
+ processing.delete(oldestId);
128
+ }
129
+ },
130
+ size() {
131
+ let total = 0;
132
+ for (const letters of sequences.values()) {
133
+ total += letters.length;
134
+ }
135
+ return total;
136
+ },
137
+ amountOfSequences() {
138
+ return sequences.size;
139
+ },
140
+ async clear() {
141
+ sequences.clear();
142
+ processing.clear();
143
+ },
144
+ isFull(sequenceIdentifier) {
145
+ const seq = sequences.get(sequenceIdentifier);
146
+ if (seq) {
147
+ return seq.length >= maxSequenceSize;
148
+ }
149
+ return sequences.size >= maxSequences;
150
+ },
151
+ };
152
+ }
153
+ /**
154
+ * Thrown when the dead letter queue is full.
155
+ */
156
+ export class DeadLetterQueueOverflowError extends Error {
157
+ constructor(message) {
158
+ super(`Dead letter queue overflow: ${message}`);
159
+ this.name = "DeadLetterQueueOverflowError";
160
+ }
161
+ }
162
+ /**
163
+ * Creates a DeadLetter from a failed event.
164
+ */
165
+ export function createDeadLetter(message, cause, sequenceIdentifier, diagnostics) {
166
+ const now = Date.now();
167
+ return {
168
+ message,
169
+ cause,
170
+ enqueuedAt: now,
171
+ lastTouched: now,
172
+ diagnostics: diagnostics ?? {},
173
+ sequenceIdentifier,
174
+ };
175
+ }
176
+ //# sourceMappingURL=dead-letter-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-letter-queue.js","sourceRoot":"","sources":["../src/dead-letter-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { EventMessage } from "./message.js";
2
+ import type { EventHandlerRegistration } from "./handler.js";
3
+ import type { SequencedEvent } from "./event-source.js";
4
+ import { type SequencedDeadLetterQueue, type EnqueuePolicy } from "./dead-letter-queue.js";
5
+ /**
6
+ * Options for dead-lettering event handler wrapper.
7
+ */
8
+ export interface DeadLetteringOptions {
9
+ /** The dead letter queue to use. */
10
+ queue: SequencedDeadLetterQueue;
11
+ /** Policy deciding whether to dead-letter a failed event. Default: always. */
12
+ policy?: EnqueuePolicy;
13
+ /**
14
+ * Extract a sequence identifier from an event. Events in the same
15
+ * sequence are ordered — if one fails, subsequent ones are blocked.
16
+ * Default: uses the first tag value or event name.
17
+ */
18
+ sequenceIdentifier?: (event: EventMessage) => string;
19
+ }
20
+ /**
21
+ * Wraps event delivery with dead-letter support.
22
+ *
23
+ * When a handler fails:
24
+ * 1. Creates a DeadLetter and consults the EnqueuePolicy
25
+ * 2. If policy says enqueue: adds to DLQ, continues with next event
26
+ * 3. If policy says don't enqueue: error is swallowed
27
+ *
28
+ * When processing an event whose sequence already has dead letters:
29
+ * - The event is automatically dead-lettered (sequence is blocked)
30
+ * - This preserves ordering within the sequence
31
+ */
32
+ export declare function createDeadLetteringDelivery(options: DeadLetteringOptions): {
33
+ /**
34
+ * Deliver an event to handlers, with dead-letter support.
35
+ *
36
+ * The DLQ participates in any active transaction via ALS — both the
37
+ * caller and the DLQ implementation read transactional state from the
38
+ * UnitOfWork ALS store, no explicit ProcessingContext is threaded.
39
+ */
40
+ deliver(sequencedEvent: SequencedEvent, handlers: Array<EventHandlerRegistration<any>>): Promise<void>;
41
+ };
42
+ //# sourceMappingURL=dead-lettering-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-lettering-handler.d.ts","sourceRoot":"","sources":["../src/dead-lettering-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,aAAa,EAGnB,MAAM,wBAAwB,CAAA;AAE/B;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oCAAoC;IACpC,KAAK,EAAE,wBAAwB,CAAA;IAC/B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,MAAM,CAAA;CACrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,oBAAoB;IAQrE;;;;;;OAMG;4BAEe,cAAc,YACpB,KAAK,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC,GAC7C,OAAO,CAAC,IAAI,CAAC;EA2CnB"}
@@ -0,0 +1,67 @@
1
+ import { qualifiedNameToString } from "@kronos-ts/common";
2
+ import { alwaysEnqueuePolicy, createDeadLetter, } from "./dead-letter-queue.js";
3
+ /**
4
+ * Wraps event delivery with dead-letter support.
5
+ *
6
+ * When a handler fails:
7
+ * 1. Creates a DeadLetter and consults the EnqueuePolicy
8
+ * 2. If policy says enqueue: adds to DLQ, continues with next event
9
+ * 3. If policy says don't enqueue: error is swallowed
10
+ *
11
+ * When processing an event whose sequence already has dead letters:
12
+ * - The event is automatically dead-lettered (sequence is blocked)
13
+ * - This preserves ordering within the sequence
14
+ */
15
+ export function createDeadLetteringDelivery(options) {
16
+ const { queue, policy = alwaysEnqueuePolicy(), sequenceIdentifier = defaultSequenceIdentifier, } = options;
17
+ return {
18
+ /**
19
+ * Deliver an event to handlers, with dead-letter support.
20
+ *
21
+ * The DLQ participates in any active transaction via ALS — both the
22
+ * caller and the DLQ implementation read transactional state from the
23
+ * UnitOfWork ALS store, no explicit ProcessingContext is threaded.
24
+ */
25
+ async deliver(sequencedEvent, handlers) {
26
+ const event = sequencedEvent.event;
27
+ const seqId = sequenceIdentifier(event);
28
+ // If this sequence already has dead letters, block this event too
29
+ const blocked = await queue.enqueueIfPresent(seqId, () => createDeadLetter(event, new Error("Blocked: previous event in sequence failed"), seqId, { blocked: true, position: Number(sequencedEvent.sequence) }));
30
+ if (blocked)
31
+ return;
32
+ // Try to deliver to all handlers
33
+ for (const reg of handlers) {
34
+ try {
35
+ await reg.handler(event.payload, event.metadata);
36
+ }
37
+ catch (err) {
38
+ const error = err instanceof Error ? err : new Error(String(err));
39
+ const letter = createDeadLetter(event, error, seqId, {
40
+ position: Number(sequencedEvent.sequence),
41
+ handlerName: qualifiedNameToString(reg.descriptor.name),
42
+ });
43
+ const decision = policy.decide(letter, error);
44
+ if (decision.shouldEnqueue) {
45
+ await queue.enqueue({
46
+ ...letter,
47
+ cause: decision.cause ?? letter.cause,
48
+ diagnostics: decision.diagnostics
49
+ ? { ...letter.diagnostics, ...decision.diagnostics }
50
+ : letter.diagnostics,
51
+ });
52
+ }
53
+ // Error is consumed by DLQ — don't propagate
54
+ return;
55
+ }
56
+ }
57
+ },
58
+ };
59
+ }
60
+ function defaultSequenceIdentifier(event) {
61
+ // Use first tag value if available, otherwise event name
62
+ if (event.tags && event.tags.length > 0) {
63
+ return event.tags[0].value;
64
+ }
65
+ return qualifiedNameToString(event.name);
66
+ }
67
+ //# sourceMappingURL=dead-lettering-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-lettering-handler.js","sourceRoot":"","sources":["../src/dead-lettering-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAIzD,OAAO,EAGL,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,wBAAwB,CAAA;AAkB/B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAA6B;IACvE,MAAM,EACJ,KAAK,EACL,MAAM,GAAG,mBAAmB,EAAE,EAC9B,kBAAkB,GAAG,yBAAyB,GAC/C,GAAG,OAAO,CAAA;IAEX,OAAO;QACL;;;;;;WAMG;QACH,KAAK,CAAC,OAAO,CACX,cAA8B,EAC9B,QAA8C;YAE9C,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAA;YAClC,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;YAEvC,kEAAkE;YAClE,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAC1C,KAAK,EACL,GAAG,EAAE,CAAC,gBAAgB,CACpB,KAAK,EACL,IAAI,KAAK,CAAC,4CAA4C,CAAC,EACvD,KAAK,EACL,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAC7D,CACF,CAAA;YACD,IAAI,OAAO;gBAAE,OAAM;YAEnB,iCAAiC;YACjC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,IAAI,CAAC;oBACH,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;gBAClD,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;oBACjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;wBACnD,QAAQ,EAAE,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC;wBACzC,WAAW,EAAE,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;qBACxD,CAAC,CAAA;oBAEF,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;oBAC7C,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;wBAC3B,MAAM,KAAK,CAAC,OAAO,CAAC;4BAClB,GAAG,MAAM;4BACT,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK;4BACrC,WAAW,EAAE,QAAQ,CAAC,WAAW;gCAC/B,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,WAAW,EAAE,GAAG,QAAQ,CAAC,WAAW,EAAE;gCACpD,CAAC,CAAC,MAAM,CAAC,WAAW;yBACvB,CAAC,CAAA;oBACJ,CAAC;oBACD,6CAA6C;oBAC7C,OAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAmB;IACpD,yDAAyD;IACzD,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,KAAK,CAAA;IAC7B,CAAC;IACD,OAAO,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,135 @@
1
+ import type { z } from "zod";
2
+ import type { QualifiedName, Tag } from "@kronos-ts/common";
3
+ /**
4
+ * Describes a command message type — its name, payload schema,
5
+ * and optional result schema for typed gateway returns.
6
+ */
7
+ export interface CommandDescriptor<P extends z.ZodType = z.ZodType, R extends z.ZodType | undefined = undefined> {
8
+ readonly kind: "command";
9
+ readonly name: QualifiedName;
10
+ /** Version of the command. Default: "1.0". */
11
+ readonly version: string;
12
+ readonly payload: P;
13
+ /** Optional result schema — enables typed return from `commandGateway.send()`. */
14
+ readonly result?: R;
15
+ /**
16
+ * The payload field that contains the routing key for distributed command routing.
17
+ *
18
+ * Used by the command gateway to extract the routing key before dispatch.
19
+ * Commands with the same routing key are routed to the same handler instance.
20
+ */
21
+ readonly routingKey?: string;
22
+ }
23
+ /**
24
+ * Describes an event message type — its name, payload schema, and tag derivation.
25
+ * Tags define how events are indexed for criteria-based sourcing.
26
+ */
27
+ export interface EventDescriptor<P extends z.ZodType = z.ZodType> {
28
+ readonly kind: "event";
29
+ readonly name: QualifiedName;
30
+ readonly version: string;
31
+ readonly payload: P;
32
+ readonly tags?: (payload: z.infer<P>) => Tag[];
33
+ }
34
+ /**
35
+ * Describes a query message type — its name, payload schema,
36
+ * and optional result schema for typed gateway returns.
37
+ */
38
+ export interface QueryDescriptor<P extends z.ZodType = z.ZodType, R extends z.ZodType | undefined = undefined> {
39
+ readonly kind: "query";
40
+ readonly name: QualifiedName;
41
+ /** Version of the query. Default: "1.0". */
42
+ readonly version: string;
43
+ readonly payload: P;
44
+ /** Optional result schema — enables typed return from `queryGateway.query()`. */
45
+ readonly result?: R;
46
+ }
47
+ /** Any message descriptor. */
48
+ export type MessageDescriptor = CommandDescriptor | EventDescriptor | QueryDescriptor;
49
+ /**
50
+ * Creates a command descriptor.
51
+ *
52
+ * Without result schema (void command):
53
+ * ```
54
+ * const CreateCourse = command({
55
+ * name: qn("university", "CreateCourse"),
56
+ * payload: z.object({ courseId: z.string(), name: z.string() }),
57
+ * routingKey: "courseId",
58
+ * })
59
+ * ```
60
+ *
61
+ * With result schema (typed return):
62
+ * ```
63
+ * const CreateCourse = command({
64
+ * name: qn("university", "CreateCourse"),
65
+ * payload: z.object({ courseId: z.string() }),
66
+ * result: z.object({ courseId: z.string() }),
67
+ * routingKey: "courseId",
68
+ * })
69
+ * // commandGateway.send(CreateCourse, { courseId: "cs-101" }) → Promise<{ courseId: string }>
70
+ * ```
71
+ */
72
+ export declare function command<P extends z.ZodType>(def: {
73
+ name: QualifiedName;
74
+ version?: string;
75
+ payload: P;
76
+ routingKey?: string;
77
+ }): CommandDescriptor<P, undefined>;
78
+ export declare function command<P extends z.ZodType, R extends z.ZodType>(def: {
79
+ name: QualifiedName;
80
+ version?: string;
81
+ payload: P;
82
+ result: R;
83
+ routingKey?: string;
84
+ }): CommandDescriptor<P, R>;
85
+ /**
86
+ * Creates an event descriptor.
87
+ *
88
+ * Tags can return `Tag[]` or a `Record<string, string>`:
89
+ * ```typescript
90
+ * event({
91
+ * name: qn("university", "CourseCreated"),
92
+ * payload: z.object({ courseId: z.string(), name: z.string() }),
93
+ * tags: (p) => ({ courseId: p.courseId }),
94
+ * })
95
+ * ```
96
+ */
97
+ export declare function event<P extends z.ZodType>(def: {
98
+ name: QualifiedName;
99
+ version?: string;
100
+ payload: P;
101
+ tags?: (payload: z.infer<P>) => Tag[] | Record<string, string>;
102
+ }): EventDescriptor<P>;
103
+ /**
104
+ * Creates a query descriptor.
105
+ *
106
+ * Without result schema:
107
+ * ```
108
+ * const GetCourse = query({
109
+ * name: qn("university", "GetCourseView"),
110
+ * payload: z.object({ courseId: z.string() }),
111
+ * })
112
+ * ```
113
+ *
114
+ * With result schema (typed return):
115
+ * ```
116
+ * const GetCourse = query({
117
+ * name: qn("university", "GetCourseView"),
118
+ * payload: z.object({ courseId: z.string() }),
119
+ * result: z.object({ courseId: z.string(), name: z.string() }),
120
+ * })
121
+ * // queryGateway.query(GetCourse, { courseId: "cs-101" }) → Promise<{ courseId: string, name: string }>
122
+ * ```
123
+ */
124
+ export declare function query<P extends z.ZodType>(def: {
125
+ name: QualifiedName;
126
+ version?: string;
127
+ payload: P;
128
+ }): QueryDescriptor<P, undefined>;
129
+ export declare function query<P extends z.ZodType, R extends z.ZodType>(def: {
130
+ name: QualifiedName;
131
+ version?: string;
132
+ payload: P;
133
+ result: R;
134
+ }): QueryDescriptor<P, R>;
135
+ //# sourceMappingURL=descriptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.d.ts","sourceRoot":"","sources":["../src/descriptor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { tagsFromRecord } from "@kronos-ts/common";
2
+ export function command(def) {
3
+ return { kind: "command", version: def.version ?? "1.0", ...def };
4
+ }
5
+ /**
6
+ * Creates an event descriptor.
7
+ *
8
+ * Tags can return `Tag[]` or a `Record<string, string>`:
9
+ * ```typescript
10
+ * event({
11
+ * name: qn("university", "CourseCreated"),
12
+ * payload: z.object({ courseId: z.string(), name: z.string() }),
13
+ * tags: (p) => ({ courseId: p.courseId }),
14
+ * })
15
+ * ```
16
+ */
17
+ export function event(def) {
18
+ const rawTags = def.tags;
19
+ const tags = rawTags
20
+ ? (payload) => {
21
+ const result = rawTags(payload);
22
+ return Array.isArray(result) ? result : tagsFromRecord(result);
23
+ }
24
+ : undefined;
25
+ return {
26
+ kind: "event",
27
+ name: def.name,
28
+ version: def.version ?? "1.0",
29
+ payload: def.payload,
30
+ ...(tags ? { tags } : {}),
31
+ };
32
+ }
33
+ export function query(def) {
34
+ return { kind: "query", version: def.version ?? "1.0", ...def };
35
+ }
36
+ //# sourceMappingURL=descriptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../src/descriptor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAmGlD,MAAM,UAAU,OAAO,CAAC,GAAQ;IAC9B,OAAO,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,KAAK,EAAE,GAAG,GAAG,EAAE,CAAA;AAC5E,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,KAAK,CAAsB,GAK1C;IACC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAA;IACxB,MAAM,IAAI,GAAiD,OAAO;QAChE,CAAC,CAAC,CAAC,OAAmB,EAAS,EAAE;YAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;YAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;QAChE,CAAC;QACH,CAAC,CAAC,SAAS,CAAA;IACb,OAAO;QACL,IAAI,EAAE,OAAgB;QACtB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,KAAK;QAC7B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1B,CAAA;AACH,CAAC;AAoCD,MAAM,UAAU,KAAK,CAAC,GAAQ;IAC5B,OAAO,EAAE,IAAI,EAAE,OAAgB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,KAAK,EAAE,GAAG,GAAG,EAAE,CAAA;AAC1E,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { z } from "zod";
2
+ import { type ResourceKey } from "@kronos-ts/common";
3
+ import type { QueryBus } from "./query-bus.js";
4
+ import type { QueryDescriptor } from "./descriptor.js";
5
+ /** Emit a subscription-query update from within the current processing context. */
6
+ export interface EmitUpdateFunction {
7
+ <Q extends z.ZodType>(query: QueryDescriptor<Q>, filter: (query: z.infer<Q>) => boolean, update: unknown): void;
8
+ }
9
+ /**
10
+ * Resource key for the query bus component.
11
+ * Written by handling modules + processors at handler-invocation entry (D-44).
12
+ */
13
+ export declare const QUERY_BUS_KEY: ResourceKey<QueryBus>;
14
+ /**
15
+ * Plan 04-01 (HDL-02 / D-42): module-level emitUpdate.
16
+ *
17
+ * Throws NoActiveUnitOfWork outside a UoW; throws WrongUoWPhase outside
18
+ * INVOCATION phase (D-43 mutator guard). Emits a subscription query update
19
+ * through the active query bus.
20
+ */
21
+ export declare const emitUpdate: EmitUpdateFunction;
22
+ //# sourceMappingURL=emit-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-update.d.ts","sourceRoot":"","sources":["../src/emit-update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAsC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAExF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAClB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EACzB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,EACtC,MAAM,EAAE,OAAO,GACd,IAAI,CAAA;CACR;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,QAAQ,CAA2B,CAAA;AAE3E;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,kBAMxB,CAAA"}