@zdavison/matador 2.0.9 → 2.0.11

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 (259) hide show
  1. package/dist/checkpoint/context.d.ts +59 -0
  2. package/dist/checkpoint/context.d.ts.map +1 -0
  3. package/dist/checkpoint/context.js +140 -0
  4. package/dist/checkpoint/context.test.d.ts +2 -0
  5. package/dist/checkpoint/context.test.d.ts.map +1 -0
  6. package/dist/checkpoint/context.test.js +424 -0
  7. package/dist/checkpoint/index.d.ts +7 -0
  8. package/dist/checkpoint/index.d.ts.map +1 -0
  9. package/dist/checkpoint/index.js +6 -0
  10. package/dist/checkpoint/stores/memory.d.ts +29 -0
  11. package/dist/checkpoint/stores/memory.d.ts.map +1 -0
  12. package/dist/checkpoint/stores/memory.js +39 -0
  13. package/{src/checkpoint/stores/noop.ts → dist/checkpoint/stores/noop.d.ts} +5 -13
  14. package/dist/checkpoint/stores/noop.d.ts.map +1 -0
  15. package/dist/checkpoint/stores/noop.js +18 -0
  16. package/dist/checkpoint/stores/stores.test.d.ts +2 -0
  17. package/dist/checkpoint/stores/stores.test.d.ts.map +1 -0
  18. package/dist/checkpoint/stores/stores.test.js +146 -0
  19. package/dist/checkpoint/types.d.ts +119 -0
  20. package/dist/checkpoint/types.d.ts.map +1 -0
  21. package/dist/checkpoint/types.js +1 -0
  22. package/dist/codec/codec.d.ts +29 -0
  23. package/dist/codec/codec.d.ts.map +1 -0
  24. package/dist/codec/codec.js +15 -0
  25. package/dist/codec/header-aware-codec.d.ts +36 -0
  26. package/dist/codec/header-aware-codec.d.ts.map +1 -0
  27. package/dist/codec/header-aware-codec.js +1 -0
  28. package/{src/codec/index.ts → dist/codec/index.d.ts} +2 -7
  29. package/dist/codec/index.d.ts.map +1 -0
  30. package/dist/codec/index.js +3 -0
  31. package/dist/codec/json-codec.d.ts +13 -0
  32. package/dist/codec/json-codec.d.ts.map +1 -0
  33. package/dist/codec/json-codec.js +64 -0
  34. package/dist/codec/rabbitmq-codec.d.ts +28 -0
  35. package/dist/codec/rabbitmq-codec.d.ts.map +1 -0
  36. package/dist/codec/rabbitmq-codec.js +242 -0
  37. package/dist/codec/rabbitmq-codec.test.d.ts +2 -0
  38. package/dist/codec/rabbitmq-codec.test.d.ts.map +1 -0
  39. package/dist/codec/rabbitmq-codec.test.js +433 -0
  40. package/dist/core/fanout.d.ts +59 -0
  41. package/dist/core/fanout.d.ts.map +1 -0
  42. package/dist/core/fanout.js +121 -0
  43. package/dist/core/fanout.test.d.ts +2 -0
  44. package/dist/core/fanout.test.d.ts.map +1 -0
  45. package/dist/core/fanout.test.js +1054 -0
  46. package/{src/core/index.ts → dist/core/index.d.ts} +2 -7
  47. package/dist/core/index.d.ts.map +1 -0
  48. package/dist/core/index.js +3 -0
  49. package/dist/core/matador.d.ts +133 -0
  50. package/dist/core/matador.d.ts.map +1 -0
  51. package/dist/core/matador.js +228 -0
  52. package/dist/core/matador.test.d.ts +2 -0
  53. package/dist/core/matador.test.d.ts.map +1 -0
  54. package/dist/core/matador.test.js +446 -0
  55. package/dist/core/shutdown.d.ts +78 -0
  56. package/dist/core/shutdown.d.ts.map +1 -0
  57. package/dist/core/shutdown.js +111 -0
  58. package/dist/core/shutdown.test.d.ts +2 -0
  59. package/dist/core/shutdown.test.d.ts.map +1 -0
  60. package/dist/core/shutdown.test.js +524 -0
  61. package/dist/errors/checkpoint-errors.d.ts +30 -0
  62. package/dist/errors/checkpoint-errors.d.ts.map +1 -0
  63. package/dist/errors/checkpoint-errors.js +49 -0
  64. package/dist/errors/has-description.d.ts +18 -0
  65. package/dist/errors/has-description.d.ts.map +1 -0
  66. package/dist/errors/has-description.js +9 -0
  67. package/dist/errors/index.d.ts +6 -0
  68. package/dist/errors/index.d.ts.map +1 -0
  69. package/dist/errors/index.js +22 -0
  70. package/dist/errors/matador-errors.d.ts +183 -0
  71. package/dist/errors/matador-errors.d.ts.map +1 -0
  72. package/dist/errors/matador-errors.js +376 -0
  73. package/dist/errors/retry-errors.d.ts +102 -0
  74. package/dist/errors/retry-errors.d.ts.map +1 -0
  75. package/dist/errors/retry-errors.js +155 -0
  76. package/dist/errors/retry-errors.test.d.ts +2 -0
  77. package/dist/errors/retry-errors.test.d.ts.map +1 -0
  78. package/dist/errors/retry-errors.test.js +136 -0
  79. package/dist/hooks/index.d.ts +4 -0
  80. package/dist/hooks/index.d.ts.map +1 -0
  81. package/dist/hooks/index.js +2 -0
  82. package/dist/hooks/safe-hooks.d.ts +32 -0
  83. package/dist/hooks/safe-hooks.d.ts.map +1 -0
  84. package/dist/hooks/safe-hooks.js +120 -0
  85. package/dist/hooks/types.d.ts +172 -0
  86. package/dist/hooks/types.d.ts.map +1 -0
  87. package/dist/hooks/types.js +9 -0
  88. package/dist/index.cjs +3228 -0
  89. package/dist/index.cjs.map +1 -0
  90. package/dist/index.d.cts +23 -0
  91. package/dist/index.d.ts +23 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +31 -0
  94. package/dist/index.js.map +1 -0
  95. package/{src/pipeline/index.ts → dist/pipeline/index.d.ts} +1 -0
  96. package/dist/pipeline/index.d.ts.map +1 -0
  97. package/dist/pipeline/index.js +1 -0
  98. package/dist/pipeline/pipeline.d.ts +63 -0
  99. package/dist/pipeline/pipeline.d.ts.map +1 -0
  100. package/dist/pipeline/pipeline.js +273 -0
  101. package/dist/pipeline/pipeline.test.d.ts +2 -0
  102. package/dist/pipeline/pipeline.test.d.ts.map +1 -0
  103. package/dist/pipeline/pipeline.test.js +1112 -0
  104. package/{src/retry/index.ts → dist/retry/index.d.ts} +1 -1
  105. package/dist/retry/index.d.ts.map +1 -0
  106. package/dist/retry/index.js +1 -0
  107. package/dist/retry/policy.d.ts +43 -0
  108. package/dist/retry/policy.d.ts.map +1 -0
  109. package/dist/retry/policy.js +1 -0
  110. package/dist/retry/standard-policy.d.ts +44 -0
  111. package/dist/retry/standard-policy.d.ts.map +1 -0
  112. package/dist/retry/standard-policy.js +102 -0
  113. package/dist/retry/standard-policy.test.d.ts +2 -0
  114. package/dist/retry/standard-policy.test.d.ts.map +1 -0
  115. package/dist/retry/standard-policy.test.js +196 -0
  116. package/dist/schema/index.d.ts +4 -0
  117. package/dist/schema/index.d.ts.map +1 -0
  118. package/dist/schema/index.js +2 -0
  119. package/dist/schema/registry.d.ts +63 -0
  120. package/dist/schema/registry.d.ts.map +1 -0
  121. package/dist/schema/registry.js +174 -0
  122. package/dist/schema/registry.test.d.ts +2 -0
  123. package/dist/schema/registry.test.d.ts.map +1 -0
  124. package/dist/schema/registry.test.js +278 -0
  125. package/{src/schema/types.ts → dist/schema/types.d.ts} +29 -88
  126. package/dist/schema/types.d.ts.map +1 -0
  127. package/dist/schema/types.js +74 -0
  128. package/dist/schema/types.test.d.ts +2 -0
  129. package/dist/schema/types.test.d.ts.map +1 -0
  130. package/dist/schema/types.test.js +242 -0
  131. package/dist/topology/builder.d.ts +80 -0
  132. package/dist/topology/builder.d.ts.map +1 -0
  133. package/dist/topology/builder.js +165 -0
  134. package/dist/topology/builder.test.d.ts +2 -0
  135. package/dist/topology/builder.test.d.ts.map +1 -0
  136. package/dist/topology/builder.test.js +360 -0
  137. package/dist/topology/index.d.ts +5 -0
  138. package/dist/topology/index.d.ts.map +1 -0
  139. package/dist/topology/index.js +2 -0
  140. package/dist/topology/types.d.ts +128 -0
  141. package/dist/topology/types.d.ts.map +1 -0
  142. package/dist/topology/types.js +28 -0
  143. package/dist/transport/capabilities.d.ts +66 -0
  144. package/dist/transport/capabilities.d.ts.map +1 -0
  145. package/dist/transport/capabilities.js +18 -0
  146. package/dist/transport/connection-manager.d.ts +95 -0
  147. package/dist/transport/connection-manager.d.ts.map +1 -0
  148. package/dist/transport/connection-manager.js +144 -0
  149. package/dist/transport/index.d.ts +11 -0
  150. package/dist/transport/index.d.ts.map +1 -0
  151. package/dist/transport/index.js +5 -0
  152. package/dist/transport/local/local-transport.d.ts +62 -0
  153. package/dist/transport/local/local-transport.d.ts.map +1 -0
  154. package/dist/transport/local/local-transport.js +241 -0
  155. package/dist/transport/local/local-transport.test.d.ts +2 -0
  156. package/dist/transport/local/local-transport.test.d.ts.map +1 -0
  157. package/dist/transport/local/local-transport.test.js +192 -0
  158. package/dist/transport/multi/multi-transport.d.ts +94 -0
  159. package/dist/transport/multi/multi-transport.d.ts.map +1 -0
  160. package/dist/transport/multi/multi-transport.js +184 -0
  161. package/dist/transport/multi/multi-transport.test.d.ts +2 -0
  162. package/dist/transport/multi/multi-transport.test.d.ts.map +1 -0
  163. package/dist/transport/multi/multi-transport.test.js +236 -0
  164. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts +83 -0
  165. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts.map +1 -0
  166. package/dist/transport/rabbitmq/rabbitmq-transport.js +541 -0
  167. package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts +2 -0
  168. package/dist/transport/rabbitmq/rabbitmq-transport.test.d.ts.map +1 -0
  169. package/dist/transport/rabbitmq/rabbitmq-transport.test.js +100 -0
  170. package/dist/transport/transport.d.ts +152 -0
  171. package/dist/transport/transport.d.ts.map +1 -0
  172. package/dist/transport/transport.js +1 -0
  173. package/{src/types/common.ts → dist/types/common.d.ts} +8 -20
  174. package/dist/types/common.d.ts.map +1 -0
  175. package/dist/types/common.js +12 -0
  176. package/dist/types/dispatcher.d.ts +14 -0
  177. package/dist/types/dispatcher.d.ts.map +1 -0
  178. package/dist/types/dispatcher.js +1 -0
  179. package/dist/types/envelope.d.ts +131 -0
  180. package/dist/types/envelope.d.ts.map +1 -0
  181. package/dist/types/envelope.js +99 -0
  182. package/dist/types/event.d.ts +92 -0
  183. package/dist/types/event.d.ts.map +1 -0
  184. package/dist/types/event.js +26 -0
  185. package/dist/types/event.test.d.ts +2 -0
  186. package/dist/types/event.test.d.ts.map +1 -0
  187. package/dist/types/event.test.js +130 -0
  188. package/dist/types/index.d.ts +11 -0
  189. package/dist/types/index.d.ts.map +1 -0
  190. package/dist/types/index.js +4 -0
  191. package/dist/types/subscriber.d.ts +227 -0
  192. package/dist/types/subscriber.d.ts.map +1 -0
  193. package/dist/types/subscriber.js +97 -0
  194. package/package.json +6 -2
  195. package/examples/config.ts +0 -126
  196. package/examples/event.ts +0 -26
  197. package/examples/order-event.json +0 -19
  198. package/src/checkpoint/context.test.ts +0 -510
  199. package/src/checkpoint/context.ts +0 -213
  200. package/src/checkpoint/index.ts +0 -30
  201. package/src/checkpoint/stores/memory.ts +0 -47
  202. package/src/checkpoint/stores/stores.test.ts +0 -177
  203. package/src/checkpoint/types.ts +0 -147
  204. package/src/codec/codec.ts +0 -42
  205. package/src/codec/header-aware-codec.ts +0 -41
  206. package/src/codec/json-codec.ts +0 -69
  207. package/src/codec/rabbitmq-codec.test.ts +0 -516
  208. package/src/codec/rabbitmq-codec.ts +0 -336
  209. package/src/core/fanout.test.ts +0 -1350
  210. package/src/core/fanout.ts +0 -184
  211. package/src/core/matador.test.ts +0 -575
  212. package/src/core/matador.ts +0 -357
  213. package/src/core/shutdown.test.ts +0 -853
  214. package/src/core/shutdown.ts +0 -165
  215. package/src/errors/checkpoint-errors.ts +0 -62
  216. package/src/errors/has-description.ts +0 -25
  217. package/src/errors/index.ts +0 -58
  218. package/src/errors/matador-errors.ts +0 -477
  219. package/src/errors/retry-errors.test.ts +0 -175
  220. package/src/errors/retry-errors.ts +0 -188
  221. package/src/hooks/index.ts +0 -14
  222. package/src/hooks/safe-hooks.ts +0 -200
  223. package/src/hooks/types.ts +0 -226
  224. package/src/index.ts +0 -242
  225. package/src/pipeline/pipeline.test.ts +0 -1377
  226. package/src/pipeline/pipeline.ts +0 -393
  227. package/src/retry/policy.ts +0 -46
  228. package/src/retry/standard-policy.test.ts +0 -290
  229. package/src/retry/standard-policy.ts +0 -156
  230. package/src/schema/index.ts +0 -16
  231. package/src/schema/registry.test.ts +0 -339
  232. package/src/schema/registry.ts +0 -229
  233. package/src/schema/types.test.ts +0 -280
  234. package/src/topology/builder.test.ts +0 -451
  235. package/src/topology/builder.ts +0 -238
  236. package/src/topology/index.ts +0 -19
  237. package/src/topology/types.ts +0 -183
  238. package/src/transport/capabilities.ts +0 -88
  239. package/src/transport/connection-manager.ts +0 -218
  240. package/src/transport/index.ts +0 -42
  241. package/src/transport/local/local-transport.test.ts +0 -262
  242. package/src/transport/local/local-transport.ts +0 -330
  243. package/src/transport/multi/multi-transport.test.ts +0 -320
  244. package/src/transport/multi/multi-transport.ts +0 -294
  245. package/src/transport/rabbitmq/rabbitmq-transport.test.ts +0 -120
  246. package/src/transport/rabbitmq/rabbitmq-transport.ts +0 -782
  247. package/src/transport/transport.ts +0 -200
  248. package/src/types/dispatcher.ts +0 -18
  249. package/src/types/envelope.ts +0 -244
  250. package/src/types/event.test.ts +0 -157
  251. package/src/types/event.ts +0 -112
  252. package/src/types/index.ts +0 -62
  253. package/src/types/subscriber.ts +0 -333
  254. package/test/e2e/multi-transport.e2e.test.ts +0 -237
  255. package/test/e2e/rabbitmq-transport.e2e.test.ts +0 -618
  256. package/test/e2e/transport-compliance.e2e.test.ts +0 -506
  257. package/test/integration/matador.integration.test.ts +0 -634
  258. package/tsconfig.json +0 -29
  259. package/tsup.config.ts +0 -13
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.d.ts","sourceRoot":"","sources":["../../src/schema/registry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,278 @@
1
+ import { beforeEach, describe, expect, it } from 'bun:test';
2
+ import { MatadorEvent, createSubscriber } from '../types/index.js';
3
+ import { SchemaError, SchemaRegistry } from './registry.js';
4
+ class TestEvent extends MatadorEvent {
5
+ data;
6
+ static key = 'test.event';
7
+ static description = 'A test event';
8
+ constructor(data) {
9
+ super();
10
+ this.data = data;
11
+ }
12
+ }
13
+ class AliasedEvent extends MatadorEvent {
14
+ data;
15
+ static key = 'user.created.v2';
16
+ static description = 'User created event with aliases';
17
+ static aliases = ['user.created', 'user.created.v1'];
18
+ constructor(data) {
19
+ super();
20
+ this.data = data;
21
+ }
22
+ }
23
+ describe('SchemaRegistry', () => {
24
+ let registry;
25
+ beforeEach(() => {
26
+ registry = new SchemaRegistry();
27
+ });
28
+ describe('register', () => {
29
+ it('should register an event with subscribers', () => {
30
+ const subscriber = createSubscriber({
31
+ name: 'test-subscriber',
32
+ description: 'Test subscriber',
33
+ callback: async () => { },
34
+ });
35
+ registry.register(TestEvent, [subscriber]);
36
+ expect(registry.hasEvent('test.event')).toBe(true);
37
+ expect(registry.getSubscribers('test.event')).toHaveLength(1);
38
+ });
39
+ it('should throw when registering duplicate event without override', () => {
40
+ const subscriber = createSubscriber({
41
+ name: 'test-subscriber',
42
+ description: 'Test subscriber',
43
+ callback: async () => { },
44
+ });
45
+ registry.register(TestEvent, [subscriber]);
46
+ expect(() => registry.register(TestEvent, [subscriber])).toThrow(SchemaError);
47
+ });
48
+ it('should allow override when option is set', () => {
49
+ const subscriber1 = createSubscriber({
50
+ name: 'sub-1',
51
+ description: 'Subscriber 1',
52
+ callback: async () => { },
53
+ });
54
+ const subscriber2 = createSubscriber({
55
+ name: 'sub-2',
56
+ description: 'Subscriber 2',
57
+ callback: async () => { },
58
+ });
59
+ registry.register(TestEvent, [subscriber1]);
60
+ registry.register(TestEvent, [subscriber2], { override: true });
61
+ const subscribers = registry.getSubscribers('test.event');
62
+ expect(subscribers).toHaveLength(1);
63
+ expect(subscribers[0]?.name).toBe('sub-2');
64
+ });
65
+ it('should register aliases', () => {
66
+ const subscriber = createSubscriber({
67
+ name: 'test-subscriber',
68
+ description: 'Test subscriber',
69
+ callback: async () => { },
70
+ });
71
+ registry.register(AliasedEvent, [subscriber]);
72
+ expect(registry.hasEvent('user.created.v2')).toBe(true);
73
+ expect(registry.hasEvent('user.created')).toBe(true);
74
+ expect(registry.hasEvent('user.created.v1')).toBe(true);
75
+ });
76
+ it('should throw on duplicate aliases without override', () => {
77
+ class EventWithSameAlias extends MatadorEvent {
78
+ data;
79
+ static key = 'another.event';
80
+ static description = 'Another event';
81
+ static aliases = ['user.created']; // conflicts with AliasedEvent
82
+ constructor(data) {
83
+ super();
84
+ this.data = data;
85
+ }
86
+ }
87
+ const sub1 = createSubscriber({
88
+ name: 'sub-1',
89
+ description: 'Subscriber 1',
90
+ callback: async () => { },
91
+ });
92
+ const sub2 = createSubscriber({
93
+ name: 'sub-2',
94
+ description: 'Subscriber 2',
95
+ callback: async () => { },
96
+ });
97
+ registry.register(AliasedEvent, [sub1]);
98
+ expect(() => registry.register(EventWithSameAlias, [sub2])).toThrow('Alias "user.created" is already registered');
99
+ });
100
+ });
101
+ describe('getEventClass', () => {
102
+ it('should return event class by key', () => {
103
+ const subscriber = createSubscriber({
104
+ name: 'test-subscriber',
105
+ description: 'Test subscriber',
106
+ callback: async () => { },
107
+ });
108
+ registry.register(TestEvent, [subscriber]);
109
+ const eventClass = registry.getEventClass('test.event');
110
+ expect(eventClass).toBeDefined();
111
+ expect(eventClass?.key).toBe('test.event');
112
+ });
113
+ it('should return event class by alias', () => {
114
+ const subscriber = createSubscriber({
115
+ name: 'test-subscriber',
116
+ description: 'Test subscriber',
117
+ callback: async () => { },
118
+ });
119
+ registry.register(AliasedEvent, [subscriber]);
120
+ const eventClass = registry.getEventClass('user.created');
121
+ expect(eventClass).toBeDefined();
122
+ expect(eventClass?.key).toBe('user.created.v2');
123
+ });
124
+ it('should return undefined for unknown key', () => {
125
+ expect(registry.getEventClass('unknown.event')).toBeUndefined();
126
+ });
127
+ });
128
+ describe('getSubscribers', () => {
129
+ it('should return all subscribers for an event', () => {
130
+ const sub1 = createSubscriber({
131
+ name: 'sub-1',
132
+ description: 'Subscriber 1',
133
+ callback: async () => { },
134
+ });
135
+ const sub2 = createSubscriber({
136
+ name: 'sub-2',
137
+ description: 'Subscriber 2',
138
+ callback: async () => { },
139
+ });
140
+ registry.register(TestEvent, [sub1, sub2]);
141
+ const subscribers = registry.getSubscribers('test.event');
142
+ expect(subscribers).toHaveLength(2);
143
+ expect(subscribers[0]?.name).toBe('sub-1');
144
+ expect(subscribers[1]?.name).toBe('sub-2');
145
+ });
146
+ it('should return empty array for unknown event', () => {
147
+ expect(registry.getSubscribers('unknown.event')).toEqual([]);
148
+ });
149
+ });
150
+ describe('getSubscriber', () => {
151
+ it('should return specific subscriber by name', () => {
152
+ const sub1 = createSubscriber({
153
+ name: 'sub-1',
154
+ description: 'Subscriber 1',
155
+ callback: async () => { },
156
+ });
157
+ const sub2 = createSubscriber({
158
+ name: 'sub-2',
159
+ description: 'Subscriber 2',
160
+ callback: async () => { },
161
+ });
162
+ registry.register(TestEvent, [sub1, sub2]);
163
+ const subscriber = registry.getSubscriber('test.event', 'sub-2');
164
+ expect(subscriber?.name).toBe('sub-2');
165
+ });
166
+ it('should return undefined for unknown subscriber', () => {
167
+ const sub = createSubscriber({
168
+ name: 'sub-1',
169
+ description: 'Subscriber 1',
170
+ callback: async () => { },
171
+ });
172
+ registry.register(TestEvent, [sub]);
173
+ expect(registry.getSubscriber('test.event', 'unknown')).toBeUndefined();
174
+ });
175
+ });
176
+ describe('getSubscriberDefinition', () => {
177
+ it('should return subscriber definition for pipeline', () => {
178
+ const sub = createSubscriber({
179
+ name: 'sub-1',
180
+ description: 'Subscriber 1',
181
+ callback: async () => { },
182
+ idempotent: 'yes',
183
+ importance: 'must-investigate',
184
+ targetQueue: 'custom-queue',
185
+ });
186
+ registry.register(TestEvent, [sub]);
187
+ const definition = registry.getSubscriberDefinition('test.event', 'sub-1');
188
+ expect(definition).toEqual({
189
+ name: 'sub-1',
190
+ description: 'Subscriber 1',
191
+ idempotent: 'yes',
192
+ importance: 'must-investigate',
193
+ targetQueue: 'custom-queue',
194
+ });
195
+ });
196
+ it('should return undefined for unknown subscriber', () => {
197
+ expect(registry.getSubscriberDefinition('unknown', 'unknown')).toBeUndefined();
198
+ });
199
+ });
200
+ describe('getExecutableSubscriber', () => {
201
+ it('should return subscriber with callback', () => {
202
+ const callback = async () => { };
203
+ const sub = createSubscriber({
204
+ name: 'sub-1',
205
+ description: 'Subscriber 1',
206
+ callback,
207
+ });
208
+ registry.register(TestEvent, [sub]);
209
+ const executable = registry.getExecutableSubscriber('test.event', 'sub-1');
210
+ expect(executable).toBeDefined();
211
+ expect(executable?.callback).toBe(callback);
212
+ });
213
+ });
214
+ describe('getEventKeys', () => {
215
+ it('should return all registered event keys', () => {
216
+ const sub1 = createSubscriber({
217
+ name: 'sub-1',
218
+ description: 'Subscriber 1',
219
+ callback: async () => { },
220
+ });
221
+ const sub2 = createSubscriber({
222
+ name: 'sub-2',
223
+ description: 'Subscriber 2',
224
+ callback: async () => { },
225
+ });
226
+ registry.register(TestEvent, [sub1]);
227
+ registry.register(AliasedEvent, [sub2]);
228
+ const keys = registry.getEventKeys();
229
+ expect(keys).toContain('test.event');
230
+ expect(keys).toContain('user.created.v2');
231
+ expect(keys).not.toContain('user.created'); // aliases not included
232
+ });
233
+ });
234
+ describe('validate', () => {
235
+ it('should pass validation for valid schema', () => {
236
+ const sub = createSubscriber({
237
+ name: 'sub-1',
238
+ description: 'Subscriber 1',
239
+ callback: async () => { },
240
+ });
241
+ registry.register(TestEvent, [sub]);
242
+ const result = registry.validate();
243
+ expect(result.valid).toBe(true);
244
+ expect(result.issues).toHaveLength(0);
245
+ });
246
+ it('should detect duplicate subscriber names', () => {
247
+ const sub1 = createSubscriber({
248
+ name: 'duplicate-name',
249
+ description: 'Duplicate subscriber',
250
+ callback: async () => { },
251
+ });
252
+ const sub2 = createSubscriber({
253
+ name: 'duplicate-name',
254
+ description: 'Duplicate subscriber',
255
+ callback: async () => { },
256
+ });
257
+ registry.register(TestEvent, [sub1, sub2]);
258
+ const result = registry.validate();
259
+ expect(result.valid).toBe(false);
260
+ expect(result.issues).toHaveLength(1);
261
+ expect(result.issues[0]?.severity).toBe('error');
262
+ expect(result.issues[0]?.message).toContain('Duplicate subscriber name');
263
+ });
264
+ });
265
+ describe('clear', () => {
266
+ it('should remove all entries', () => {
267
+ const sub = createSubscriber({
268
+ name: 'sub-1',
269
+ description: 'Subscriber 1',
270
+ callback: async () => { },
271
+ });
272
+ registry.register(TestEvent, [sub]);
273
+ registry.clear();
274
+ expect(registry.hasEvent('test.event')).toBe(false);
275
+ expect(registry.getEventKeys()).toHaveLength(0);
276
+ });
277
+ });
278
+ });
@@ -1,23 +1,14 @@
1
- import type {
2
- AnySubscriber,
3
- EventClass,
4
- MatadorEvent,
5
- Subscriber,
6
- SubscriberStub,
7
- } from '../types/index.js';
8
-
1
+ import type { AnySubscriber, EventClass, MatadorEvent, Subscriber, SubscriberStub } from '../types/index.js';
9
2
  /**
10
3
  * Type-safe schema entry for a single event type (object format).
11
4
  * The type parameter enforces that subscribers match the event type.
12
5
  */
13
6
  export interface SchemaEntry<T extends MatadorEvent = MatadorEvent> {
14
- /** The event class */
15
- readonly eventClass: EventClass<T['data']>;
16
-
17
- /** Subscribers for this event */
18
- readonly subscribers: readonly (Subscriber<T> | SubscriberStub)[];
7
+ /** The event class */
8
+ readonly eventClass: EventClass<T['data']>;
9
+ /** Subscribers for this event */
10
+ readonly subscribers: readonly (Subscriber<T> | SubscriberStub)[];
19
11
  }
20
-
21
12
  /**
22
13
  * Type-safe schema entry as a tuple: [EventClass, Subscribers[]]
23
14
  * The type parameter enforces that subscribers match the event type.
@@ -31,10 +22,9 @@ export interface SchemaEntry<T extends MatadorEvent = MatadorEvent> {
31
22
  * ```
32
23
  */
33
24
  export type SchemaEntryTuple<T extends MatadorEvent = MatadorEvent> = readonly [
34
- eventClass: EventClass<T['data']>,
35
- subscribers: readonly (Subscriber<T> | SubscriberStub)[],
25
+ eventClass: EventClass<T['data']>,
26
+ subscribers: readonly (Subscriber<T> | SubscriberStub)[]
36
27
  ];
37
-
38
28
  /**
39
29
  * Creates a type-safe schema entry tuple.
40
30
  * Ensures that subscribers are compatible with the event class at compile time.
@@ -50,44 +40,34 @@ export type SchemaEntryTuple<T extends MatadorEvent = MatadorEvent> = readonly [
50
40
  * } satisfies MatadorSchema;
51
41
  * ```
52
42
  */
53
- export function bind<T extends MatadorEvent>(
54
- eventClass: EventClass<T['data']>,
55
- subscribers: readonly (Subscriber<T> | SubscriberStub)[],
56
- ): SchemaEntryTuple<T> {
57
- return [eventClass, subscribers] as const;
58
- }
59
-
43
+ export declare function bind<T extends MatadorEvent>(eventClass: EventClass<T['data']>, subscribers: readonly (Subscriber<T> | SubscriberStub)[]): SchemaEntryTuple<T>;
60
44
  /**
61
45
  * Minimal type for event class in schema storage.
62
46
  * Only requires the static `key` property for routing.
63
47
  * Constructor constraint is omitted to allow heterogeneous event types.
64
48
  */
65
- // biome-ignore lint/suspicious/noExplicitAny: Constructor accepts any data type for variance compatibility
66
49
  export type AnyEventClass = {
67
- readonly key: string;
68
- new (data: any): MatadorEvent;
50
+ readonly key: string;
51
+ new (data: any): MatadorEvent;
69
52
  };
70
-
71
53
  /**
72
54
  * Runtime schema entry stored in MatadorSchema (object format).
73
55
  * Uses AnySubscriber and AnyEventClass to allow heterogeneous event types.
74
56
  * Type safety is enforced at definition time via `schemaEntry()` helper.
75
57
  */
76
58
  export interface RuntimeSchemaEntry {
77
- readonly eventClass: AnyEventClass;
78
- readonly subscribers: readonly AnySubscriber[];
59
+ readonly eventClass: AnyEventClass;
60
+ readonly subscribers: readonly AnySubscriber[];
79
61
  }
80
-
81
62
  /**
82
63
  * Runtime schema tuple stored in MatadorSchema.
83
64
  * Uses AnySubscriber and AnyEventClass to allow heterogeneous event types.
84
65
  * Type safety is enforced at definition time via `schemaEntry()` helper.
85
66
  */
86
67
  export type RuntimeSchemaEntryTuple = readonly [
87
- eventClass: AnyEventClass,
88
- subscribers: readonly AnySubscriber[],
68
+ eventClass: AnyEventClass,
69
+ subscribers: readonly AnySubscriber[]
89
70
  ];
90
-
91
71
  /**
92
72
  * Matador schema mapping event keys to their definitions.
93
73
  * Supports both object format (SchemaEntry) and tuple format (SchemaEntryTuple).
@@ -109,54 +89,43 @@ export type RuntimeSchemaEntryTuple = readonly [
109
89
  * ```
110
90
  */
111
91
  export type MatadorSchema = {
112
- readonly [eventKey: string]: RuntimeSchemaEntry | RuntimeSchemaEntryTuple;
92
+ readonly [eventKey: string]: RuntimeSchemaEntry | RuntimeSchemaEntryTuple;
113
93
  };
114
-
115
94
  /**
116
95
  * Type guard to check if a schema entry is in tuple format.
117
96
  */
118
- export function isSchemaEntryTuple(
119
- entry: RuntimeSchemaEntry | RuntimeSchemaEntryTuple,
120
- ): entry is RuntimeSchemaEntryTuple {
121
- return Array.isArray(entry);
122
- }
123
-
97
+ export declare function isSchemaEntryTuple(entry: RuntimeSchemaEntry | RuntimeSchemaEntryTuple): entry is RuntimeSchemaEntryTuple;
124
98
  /**
125
99
  * Options for schema registration.
126
100
  */
127
101
  export interface RegisterOptions {
128
- /** Override existing registration if present */
129
- readonly override?: boolean;
102
+ /** Override existing registration if present */
103
+ readonly override?: boolean;
130
104
  }
131
-
132
105
  /**
133
106
  * Result of schema validation.
134
107
  */
135
108
  export interface SchemaValidationResult {
136
- readonly valid: boolean;
137
- readonly issues: readonly SchemaIssue[];
109
+ readonly valid: boolean;
110
+ readonly issues: readonly SchemaIssue[];
138
111
  }
139
-
140
112
  /**
141
113
  * Individual schema issue.
142
114
  */
143
115
  export interface SchemaIssue {
144
- readonly severity: 'error' | 'warning';
145
- readonly eventKey: string;
146
- readonly message: string;
116
+ readonly severity: 'error' | 'warning';
117
+ readonly eventKey: string;
118
+ readonly message: string;
147
119
  }
148
-
149
120
  /**
150
121
  * Plugin definition for adding subscribers to multiple events.
151
122
  */
152
123
  export interface SchemaPlugin {
153
- /** The subscriber to add to events */
154
- readonly subscriber: AnySubscriber;
155
-
156
- /** Event keys to exclude from this plugin */
157
- readonly exclusions?: readonly string[];
124
+ /** The subscriber to add to events */
125
+ readonly subscriber: AnySubscriber;
126
+ /** Event keys to exclude from this plugin */
127
+ readonly exclusions?: readonly string[];
158
128
  }
159
-
160
129
  /**
161
130
  * Installs plugins (global subscribers) into a schema.
162
131
  * Each plugin subscriber is added to all events except those in its exclusions list.
@@ -185,33 +154,5 @@ export interface SchemaPlugin {
185
154
  * ]);
186
155
  * ```
187
156
  */
188
- export function installPlugins(
189
- schema: MatadorSchema,
190
- plugins: readonly SchemaPlugin[],
191
- ): MatadorSchema {
192
- const result: Record<string, RuntimeSchemaEntry | RuntimeSchemaEntryTuple> =
193
- {};
194
-
195
- for (const [eventKey, entry] of Object.entries(schema)) {
196
- // Get existing event class and subscribers
197
- const [eventClass, existingSubscribers] = isSchemaEntryTuple(entry)
198
- ? [entry[0], entry[1]]
199
- : [entry.eventClass, entry.subscribers];
200
-
201
- // Collect subscribers to add from plugins
202
- const pluginSubscribers: AnySubscriber[] = [];
203
- for (const plugin of plugins) {
204
- if (!plugin.exclusions?.includes(eventKey)) {
205
- pluginSubscribers.push(plugin.subscriber);
206
- }
207
- }
208
-
209
- // Create new entry with combined subscribers
210
- result[eventKey] = [
211
- eventClass,
212
- [...existingSubscribers, ...pluginSubscribers],
213
- ];
214
- }
215
-
216
- return result;
217
- }
157
+ export declare function installPlugins(schema: MatadorSchema, plugins: readonly SchemaPlugin[]): MatadorSchema;
158
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,YAAY,EACZ,UAAU,EACV,cAAc,EACf,MAAM,mBAAmB,CAAC;AAE3B;;;GAGG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY;IAChE,sBAAsB;IACtB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAE3C,iCAAiC;IACjC,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,EAAE,CAAC;CACnE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI,SAAS;IAC7E,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjC,WAAW,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,EAAE;CACzD,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,YAAY,EACzC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EACjC,WAAW,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,EAAE,GACvD,gBAAgB,CAAC,CAAC,CAAC,CAErB;AAED;;;;GAIG;AAEH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,KAAK,IAAI,EAAE,GAAG,GAAG,YAAY,CAAC;CAC/B,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,SAAS,aAAa,EAAE,CAAC;CAChD;AAED;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS;IAC7C,UAAU,EAAE,aAAa;IACzB,WAAW,EAAE,SAAS,aAAa,EAAE;CACtC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,uBAAuB,CAAC;CAC3E,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,kBAAkB,GAAG,uBAAuB,GAClD,KAAK,IAAI,uBAAuB,CAElC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IAEnC,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,SAAS,YAAY,EAAE,GAC/B,aAAa,CA0Bf"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Creates a type-safe schema entry tuple.
3
+ * Ensures that subscribers are compatible with the event class at compile time.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * const schema = {
8
+ * [UserCreatedEvent.key]: bind(UserCreatedEvent, [
9
+ * createSubscriber<UserCreatedEvent>('send-email', async (env) => {
10
+ * console.log(env.data.email); // Type-safe access
11
+ * }),
12
+ * ]),
13
+ * } satisfies MatadorSchema;
14
+ * ```
15
+ */
16
+ export function bind(eventClass, subscribers) {
17
+ return [eventClass, subscribers];
18
+ }
19
+ /**
20
+ * Type guard to check if a schema entry is in tuple format.
21
+ */
22
+ export function isSchemaEntryTuple(entry) {
23
+ return Array.isArray(entry);
24
+ }
25
+ /**
26
+ * Installs plugins (global subscribers) into a schema.
27
+ * Each plugin subscriber is added to all events except those in its exclusions list.
28
+ *
29
+ * @param schema - The base schema to extend
30
+ * @param plugins - Array of plugins to install
31
+ * @returns A new schema with plugin subscribers added
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const baseSchema: MatadorSchema = {
36
+ * [UserCreatedEvent.key]: [UserCreatedEvent, [sendWelcomeEmail]],
37
+ * [OrderPlacedEvent.key]: [OrderPlacedEvent, [processOrder]],
38
+ * [ChatMessageSent.key]: [ChatMessageSent, [notifyRecipient]],
39
+ * };
40
+ *
41
+ * const schema = installPlugins(baseSchema, [
42
+ * {
43
+ * subscriber: logToBigQuery,
44
+ * exclusions: [ChatMessageSent.key], // Don't log chat messages
45
+ * },
46
+ * {
47
+ * subscriber: trackAnalytics,
48
+ * // No exclusions - added to all events
49
+ * },
50
+ * ]);
51
+ * ```
52
+ */
53
+ export function installPlugins(schema, plugins) {
54
+ const result = {};
55
+ for (const [eventKey, entry] of Object.entries(schema)) {
56
+ // Get existing event class and subscribers
57
+ const [eventClass, existingSubscribers] = isSchemaEntryTuple(entry)
58
+ ? [entry[0], entry[1]]
59
+ : [entry.eventClass, entry.subscribers];
60
+ // Collect subscribers to add from plugins
61
+ const pluginSubscribers = [];
62
+ for (const plugin of plugins) {
63
+ if (!plugin.exclusions?.includes(eventKey)) {
64
+ pluginSubscribers.push(plugin.subscriber);
65
+ }
66
+ }
67
+ // Create new entry with combined subscribers
68
+ result[eventKey] = [
69
+ eventClass,
70
+ [...existingSubscribers, ...pluginSubscribers],
71
+ ];
72
+ }
73
+ return result;
74
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../src/schema/types.test.ts"],"names":[],"mappings":""}