@zdavison/matador 2.0.1

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 (256) hide show
  1. package/cli.ts +453 -0
  2. package/dist/checkpoint/context.d.ts +59 -0
  3. package/dist/checkpoint/context.d.ts.map +1 -0
  4. package/dist/checkpoint/context.js +140 -0
  5. package/dist/checkpoint/context.test.d.ts +2 -0
  6. package/dist/checkpoint/context.test.d.ts.map +1 -0
  7. package/dist/checkpoint/context.test.js +424 -0
  8. package/dist/checkpoint/index.d.ts +7 -0
  9. package/dist/checkpoint/index.d.ts.map +1 -0
  10. package/dist/checkpoint/index.js +6 -0
  11. package/dist/checkpoint/stores/memory.d.ts +29 -0
  12. package/dist/checkpoint/stores/memory.d.ts.map +1 -0
  13. package/dist/checkpoint/stores/memory.js +39 -0
  14. package/dist/checkpoint/stores/noop.d.ts +14 -0
  15. package/dist/checkpoint/stores/noop.d.ts.map +1 -0
  16. package/dist/checkpoint/stores/noop.js +18 -0
  17. package/dist/checkpoint/stores/stores.test.d.ts +2 -0
  18. package/dist/checkpoint/stores/stores.test.d.ts.map +1 -0
  19. package/dist/checkpoint/stores/stores.test.js +146 -0
  20. package/dist/checkpoint/types.d.ts +119 -0
  21. package/dist/checkpoint/types.d.ts.map +1 -0
  22. package/dist/checkpoint/types.js +1 -0
  23. package/dist/codec/codec.d.ts +29 -0
  24. package/dist/codec/codec.d.ts.map +1 -0
  25. package/dist/codec/codec.js +15 -0
  26. package/dist/codec/header-aware-codec.d.ts +36 -0
  27. package/dist/codec/header-aware-codec.d.ts.map +1 -0
  28. package/dist/codec/header-aware-codec.js +1 -0
  29. package/dist/codec/index.d.ts +6 -0
  30. package/dist/codec/index.d.ts.map +1 -0
  31. package/dist/codec/index.js +3 -0
  32. package/dist/codec/json-codec.d.ts +13 -0
  33. package/dist/codec/json-codec.d.ts.map +1 -0
  34. package/dist/codec/json-codec.js +64 -0
  35. package/dist/codec/rabbitmq-codec.d.ts +28 -0
  36. package/dist/codec/rabbitmq-codec.d.ts.map +1 -0
  37. package/dist/codec/rabbitmq-codec.js +242 -0
  38. package/dist/codec/rabbitmq-codec.test.d.ts +2 -0
  39. package/dist/codec/rabbitmq-codec.test.d.ts.map +1 -0
  40. package/dist/codec/rabbitmq-codec.test.js +433 -0
  41. package/dist/core/fanout.d.ts +59 -0
  42. package/dist/core/fanout.d.ts.map +1 -0
  43. package/dist/core/fanout.js +121 -0
  44. package/dist/core/fanout.test.d.ts +2 -0
  45. package/dist/core/fanout.test.d.ts.map +1 -0
  46. package/dist/core/fanout.test.js +1055 -0
  47. package/dist/core/index.d.ts +7 -0
  48. package/dist/core/index.d.ts.map +1 -0
  49. package/dist/core/index.js +3 -0
  50. package/dist/core/matador.d.ts +133 -0
  51. package/dist/core/matador.d.ts.map +1 -0
  52. package/dist/core/matador.js +222 -0
  53. package/dist/core/matador.test.d.ts +2 -0
  54. package/dist/core/matador.test.d.ts.map +1 -0
  55. package/dist/core/matador.test.js +446 -0
  56. package/dist/core/shutdown.d.ts +78 -0
  57. package/dist/core/shutdown.d.ts.map +1 -0
  58. package/dist/core/shutdown.js +111 -0
  59. package/dist/core/shutdown.test.d.ts +2 -0
  60. package/dist/core/shutdown.test.d.ts.map +1 -0
  61. package/dist/core/shutdown.test.js +524 -0
  62. package/dist/errors/checkpoint-errors.d.ts +30 -0
  63. package/dist/errors/checkpoint-errors.d.ts.map +1 -0
  64. package/dist/errors/checkpoint-errors.js +49 -0
  65. package/dist/errors/has-description.d.ts +18 -0
  66. package/dist/errors/has-description.d.ts.map +1 -0
  67. package/dist/errors/has-description.js +9 -0
  68. package/dist/errors/index.d.ts +6 -0
  69. package/dist/errors/index.d.ts.map +1 -0
  70. package/dist/errors/index.js +22 -0
  71. package/dist/errors/matador-errors.d.ts +183 -0
  72. package/dist/errors/matador-errors.d.ts.map +1 -0
  73. package/dist/errors/matador-errors.js +376 -0
  74. package/dist/errors/retry-errors.d.ts +67 -0
  75. package/dist/errors/retry-errors.d.ts.map +1 -0
  76. package/dist/errors/retry-errors.js +108 -0
  77. package/dist/hooks/index.d.ts +4 -0
  78. package/dist/hooks/index.d.ts.map +1 -0
  79. package/dist/hooks/index.js +2 -0
  80. package/dist/hooks/safe-hooks.d.ts +34 -0
  81. package/dist/hooks/safe-hooks.d.ts.map +1 -0
  82. package/dist/hooks/safe-hooks.js +135 -0
  83. package/dist/hooks/types.d.ts +189 -0
  84. package/dist/hooks/types.d.ts.map +1 -0
  85. package/dist/hooks/types.js +9 -0
  86. package/dist/index.cjs +3156 -0
  87. package/dist/index.cjs.map +1 -0
  88. package/dist/index.d.cts +23 -0
  89. package/dist/index.d.ts +23 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +31 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/pipeline/index.d.ts +3 -0
  94. package/dist/pipeline/index.d.ts.map +1 -0
  95. package/dist/pipeline/index.js +1 -0
  96. package/dist/pipeline/pipeline.d.ts +60 -0
  97. package/dist/pipeline/pipeline.d.ts.map +1 -0
  98. package/dist/pipeline/pipeline.js +261 -0
  99. package/dist/pipeline/pipeline.test.d.ts +2 -0
  100. package/dist/pipeline/pipeline.test.d.ts.map +1 -0
  101. package/dist/pipeline/pipeline.test.js +1065 -0
  102. package/dist/retry/index.d.ts +4 -0
  103. package/dist/retry/index.d.ts.map +1 -0
  104. package/dist/retry/index.js +1 -0
  105. package/dist/retry/policy.d.ts +43 -0
  106. package/dist/retry/policy.d.ts.map +1 -0
  107. package/dist/retry/policy.js +1 -0
  108. package/dist/retry/standard-policy.d.ts +44 -0
  109. package/dist/retry/standard-policy.d.ts.map +1 -0
  110. package/dist/retry/standard-policy.js +102 -0
  111. package/dist/retry/standard-policy.test.d.ts +2 -0
  112. package/dist/retry/standard-policy.test.d.ts.map +1 -0
  113. package/dist/retry/standard-policy.test.js +190 -0
  114. package/dist/schema/index.d.ts +4 -0
  115. package/dist/schema/index.d.ts.map +1 -0
  116. package/dist/schema/index.js +2 -0
  117. package/dist/schema/registry.d.ts +63 -0
  118. package/dist/schema/registry.d.ts.map +1 -0
  119. package/dist/schema/registry.js +171 -0
  120. package/dist/schema/registry.test.d.ts +2 -0
  121. package/dist/schema/registry.test.d.ts.map +1 -0
  122. package/dist/schema/registry.test.js +278 -0
  123. package/dist/schema/types.d.ts +158 -0
  124. package/dist/schema/types.d.ts.map +1 -0
  125. package/dist/schema/types.js +74 -0
  126. package/dist/schema/types.test.d.ts +2 -0
  127. package/dist/schema/types.test.d.ts.map +1 -0
  128. package/dist/schema/types.test.js +243 -0
  129. package/dist/topology/builder.d.ts +66 -0
  130. package/dist/topology/builder.d.ts.map +1 -0
  131. package/dist/topology/builder.js +156 -0
  132. package/dist/topology/builder.test.d.ts +2 -0
  133. package/dist/topology/builder.test.d.ts.map +1 -0
  134. package/dist/topology/builder.test.js +222 -0
  135. package/dist/topology/index.d.ts +5 -0
  136. package/dist/topology/index.d.ts.map +1 -0
  137. package/dist/topology/index.js +2 -0
  138. package/dist/topology/types.d.ts +76 -0
  139. package/dist/topology/types.d.ts.map +1 -0
  140. package/dist/topology/types.js +18 -0
  141. package/dist/transport/capabilities.d.ts +66 -0
  142. package/dist/transport/capabilities.d.ts.map +1 -0
  143. package/dist/transport/capabilities.js +18 -0
  144. package/dist/transport/connection-manager.d.ts +95 -0
  145. package/dist/transport/connection-manager.d.ts.map +1 -0
  146. package/dist/transport/connection-manager.js +144 -0
  147. package/dist/transport/index.d.ts +11 -0
  148. package/dist/transport/index.d.ts.map +1 -0
  149. package/dist/transport/index.js +5 -0
  150. package/dist/transport/local/local-transport.d.ts +62 -0
  151. package/dist/transport/local/local-transport.d.ts.map +1 -0
  152. package/dist/transport/local/local-transport.js +241 -0
  153. package/dist/transport/local/local-transport.test.d.ts +2 -0
  154. package/dist/transport/local/local-transport.test.d.ts.map +1 -0
  155. package/dist/transport/local/local-transport.test.js +192 -0
  156. package/dist/transport/multi/multi-transport.d.ts +94 -0
  157. package/dist/transport/multi/multi-transport.d.ts.map +1 -0
  158. package/dist/transport/multi/multi-transport.js +184 -0
  159. package/dist/transport/multi/multi-transport.test.d.ts +2 -0
  160. package/dist/transport/multi/multi-transport.test.d.ts.map +1 -0
  161. package/dist/transport/multi/multi-transport.test.js +236 -0
  162. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts +73 -0
  163. package/dist/transport/rabbitmq/rabbitmq-transport.d.ts.map +1 -0
  164. package/dist/transport/rabbitmq/rabbitmq-transport.js +518 -0
  165. package/dist/transport/transport.d.ts +152 -0
  166. package/dist/transport/transport.d.ts.map +1 -0
  167. package/dist/transport/transport.js +1 -0
  168. package/dist/types/common.d.ts +41 -0
  169. package/dist/types/common.d.ts.map +1 -0
  170. package/dist/types/common.js +12 -0
  171. package/dist/types/envelope.d.ts +82 -0
  172. package/dist/types/envelope.d.ts.map +1 -0
  173. package/dist/types/envelope.js +36 -0
  174. package/dist/types/event.d.ts +96 -0
  175. package/dist/types/event.d.ts.map +1 -0
  176. package/dist/types/event.js +26 -0
  177. package/dist/types/event.test.d.ts +2 -0
  178. package/dist/types/event.test.d.ts.map +1 -0
  179. package/dist/types/event.test.js +130 -0
  180. package/dist/types/index.d.ts +9 -0
  181. package/dist/types/index.d.ts.map +1 -0
  182. package/dist/types/index.js +4 -0
  183. package/dist/types/subscriber.d.ts +207 -0
  184. package/dist/types/subscriber.d.ts.map +1 -0
  185. package/dist/types/subscriber.js +99 -0
  186. package/examples/config.ts +126 -0
  187. package/examples/event.ts +26 -0
  188. package/examples/order-event.json +19 -0
  189. package/package.json +66 -0
  190. package/src/checkpoint/context.test.ts +510 -0
  191. package/src/checkpoint/context.ts +213 -0
  192. package/src/checkpoint/index.ts +30 -0
  193. package/src/checkpoint/stores/memory.ts +47 -0
  194. package/src/checkpoint/stores/noop.ts +22 -0
  195. package/src/checkpoint/stores/stores.test.ts +177 -0
  196. package/src/checkpoint/types.ts +147 -0
  197. package/src/codec/codec.ts +42 -0
  198. package/src/codec/header-aware-codec.ts +41 -0
  199. package/src/codec/index.ts +11 -0
  200. package/src/codec/json-codec.ts +69 -0
  201. package/src/codec/rabbitmq-codec.test.ts +516 -0
  202. package/src/codec/rabbitmq-codec.ts +336 -0
  203. package/src/core/fanout.test.ts +1351 -0
  204. package/src/core/fanout.ts +184 -0
  205. package/src/core/index.ts +12 -0
  206. package/src/core/matador.test.ts +575 -0
  207. package/src/core/matador.ts +344 -0
  208. package/src/core/shutdown.test.ts +853 -0
  209. package/src/core/shutdown.ts +165 -0
  210. package/src/errors/checkpoint-errors.ts +62 -0
  211. package/src/errors/has-description.ts +25 -0
  212. package/src/errors/index.ts +57 -0
  213. package/src/errors/matador-errors.ts +477 -0
  214. package/src/errors/retry-errors.ts +134 -0
  215. package/src/hooks/index.ts +15 -0
  216. package/src/hooks/safe-hooks.ts +223 -0
  217. package/src/hooks/types.ts +248 -0
  218. package/src/index.ts +231 -0
  219. package/src/pipeline/index.ts +2 -0
  220. package/src/pipeline/pipeline.test.ts +1317 -0
  221. package/src/pipeline/pipeline.ts +371 -0
  222. package/src/retry/index.ts +4 -0
  223. package/src/retry/policy.ts +46 -0
  224. package/src/retry/standard-policy.test.ts +282 -0
  225. package/src/retry/standard-policy.ts +156 -0
  226. package/src/schema/index.ts +16 -0
  227. package/src/schema/registry.test.ts +339 -0
  228. package/src/schema/registry.ts +226 -0
  229. package/src/schema/types.test.ts +281 -0
  230. package/src/schema/types.ts +217 -0
  231. package/src/topology/builder.test.ts +275 -0
  232. package/src/topology/builder.ts +199 -0
  233. package/src/topology/index.ts +15 -0
  234. package/src/topology/types.ts +109 -0
  235. package/src/transport/capabilities.ts +88 -0
  236. package/src/transport/connection-manager.ts +218 -0
  237. package/src/transport/index.ts +42 -0
  238. package/src/transport/local/local-transport.test.ts +262 -0
  239. package/src/transport/local/local-transport.ts +327 -0
  240. package/src/transport/multi/multi-transport.test.ts +320 -0
  241. package/src/transport/multi/multi-transport.ts +294 -0
  242. package/src/transport/rabbitmq/rabbitmq-transport.ts +753 -0
  243. package/src/transport/transport.ts +200 -0
  244. package/src/types/common.ts +53 -0
  245. package/src/types/envelope.ts +152 -0
  246. package/src/types/event.test.ts +157 -0
  247. package/src/types/event.ts +118 -0
  248. package/src/types/index.ts +52 -0
  249. package/src/types/subscriber.ts +310 -0
  250. package/test/e2e/multi-transport.e2e.test.ts +236 -0
  251. package/test/e2e/rabbitmq-transport.e2e.test.ts +327 -0
  252. package/test/e2e/transport-compliance.e2e.test.ts +505 -0
  253. package/test/integration/matador.integration.test.ts +634 -0
  254. package/tsconfig.json +29 -0
  255. package/tsconfig.tsbuildinfo +1 -0
  256. package/tsup.config.ts +13 -0
@@ -0,0 +1,11 @@
1
+ export type { TransportCapabilities } from './capabilities.js';
2
+ export { hasNativeDeadLetter, supportsDeliveryMode, supportsDelayedMessages, } from './capabilities.js';
3
+ export type { MessageHandler, MessageReceipt, RabbitMQSendOptions, RabbitMQSubscribeOptions, SendOptions, SubscribeOptions, Subscription, Transport, TransportSendOptions, TransportSubscribeOptions, } from './transport.js';
4
+ export type { ConnectFn, ConnectionManagerConfig, ConnectionState, DisconnectFn, StateChangeCallback, } from './connection-manager.js';
5
+ export { ConnectionManager, defaultConnectionConfig, } from './connection-manager.js';
6
+ export { LocalTransport } from './local/local-transport.js';
7
+ export type { MultiTransportConfig, MultiTransportHooks, } from './multi/multi-transport.js';
8
+ export { MultiTransport } from './multi/multi-transport.js';
9
+ export type { RabbitMQTransportConfig } from './rabbitmq/rabbitmq-transport.js';
10
+ export { RabbitMQTransport } from './rabbitmq/rabbitmq-transport.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,SAAS,EACT,uBAAuB,EACvB,eAAe,EACf,YAAY,EACZ,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,YAAY,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { hasNativeDeadLetter, supportsDeliveryMode, supportsDelayedMessages, } from './capabilities.js';
2
+ export { ConnectionManager, defaultConnectionConfig, } from './connection-manager.js';
3
+ export { LocalTransport } from './local/local-transport.js';
4
+ export { MultiTransport } from './multi/multi-transport.js';
5
+ export { RabbitMQTransport } from './rabbitmq/rabbitmq-transport.js';
@@ -0,0 +1,62 @@
1
+ import { type Logger } from '../../hooks/index.js';
2
+ import type { Topology } from '../../topology/types.js';
3
+ import type { Envelope } from '../../types/index.js';
4
+ import type { TransportCapabilities } from '../capabilities.js';
5
+ import type { MessageHandler, MessageReceipt, SendOptions, SubscribeOptions, Subscription, Transport } from '../transport.js';
6
+ /**
7
+ * Local in-memory transport for testing and fallback.
8
+ * Messages are stored in memory and delivered synchronously.
9
+ */
10
+ export declare class LocalTransport implements Transport {
11
+ readonly name = "local";
12
+ readonly capabilities: TransportCapabilities;
13
+ private connected;
14
+ private readonly queues;
15
+ private readonly subscriptions;
16
+ private readonly completedMessages;
17
+ private readonly delayedTimers;
18
+ private messageIdCounter;
19
+ private readonly logger;
20
+ constructor(logger?: Logger);
21
+ connect(): Promise<void>;
22
+ disconnect(): Promise<void>;
23
+ isConnected(): boolean;
24
+ applyTopology(topology: Topology): Promise<void>;
25
+ send(queue: string, envelope: Envelope, options?: SendOptions): Promise<Transport['name']>;
26
+ /**
27
+ * Schedules a message for delayed delivery.
28
+ * Returns immediately (non-blocking) to match real transport behavior.
29
+ */
30
+ private scheduleDelayedMessage;
31
+ private enqueue;
32
+ private deliverToSubscribers;
33
+ subscribe(queue: string, handler: MessageHandler, options?: SubscribeOptions): Promise<Subscription>;
34
+ complete(receipt: MessageReceipt): Promise<void>;
35
+ sendToDeadLetter(receipt: MessageReceipt, dlqName: string, envelope: Envelope, _reason: string): Promise<void>;
36
+ /**
37
+ * Gets the current size of a queue.
38
+ */
39
+ getQueueSize(queue: string): number;
40
+ /**
41
+ * Gets all completed message receipts.
42
+ */
43
+ getCompleted(): readonly MessageReceipt[];
44
+ /**
45
+ * Gets pending (uncompleted) messages from a queue.
46
+ */
47
+ getPendingMessages(queue: string): readonly Envelope[];
48
+ /**
49
+ * Clears all state (for test isolation).
50
+ */
51
+ clear(): void;
52
+ /**
53
+ * Receives one message from the queue without a subscription.
54
+ * Useful for testing.
55
+ */
56
+ receiveOne(queue: string): Promise<{
57
+ envelope: Envelope;
58
+ receipt: MessageReceipt;
59
+ } | null>;
60
+ private getOrCreateQueue;
61
+ }
62
+ //# sourceMappingURL=local-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-transport.d.ts","sourceRoot":"","sources":["../../../src/transport/local/local-transport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAiB,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACV,MAAM,iBAAiB,CAAC;AAiCzB;;;GAGG;AACH,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,YAAY,wBAAqB;IAE1C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2C;IACzE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwB;IAC1D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4C;IAC1E,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,MAAM,CAAC,EAAE,MAAM;IAIrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBjC,WAAW,IAAI,OAAO;IAIhB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBhD,IAAI,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAe7B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;YAkBhB,OAAO;YAgBP,oBAAoB;IA4B5B,SAAS,CACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,YAAY,CAAC;IAsClB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,gBAAgB,CACpB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAQhB;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAMnC;;OAEG;IACH,YAAY,IAAI,SAAS,cAAc,EAAE;IAIzC;;OAEG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE;IAMtD;;OAEG;IACH,KAAK,IAAI,IAAI;IAYb;;;OAGG;IACG,UAAU,CACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,cAAc,CAAA;KAAE,GAAG,IAAI,CAAC;IAmBlE,OAAO,CAAC,gBAAgB;CAQzB"}
@@ -0,0 +1,241 @@
1
+ import { TransportNotConnectedError } from '../../errors/index.js';
2
+ import { consoleLogger } from '../../hooks/index.js';
3
+ /**
4
+ * Capabilities of the LocalTransport.
5
+ */
6
+ const localCapabilities = {
7
+ deliveryModes: ['at-least-once', 'at-most-once'],
8
+ delayedMessages: true, // Implemented with setTimeout
9
+ deadLetterRouting: 'manual',
10
+ attemptTracking: false,
11
+ concurrencyModel: 'none',
12
+ ordering: 'queue',
13
+ priorities: false,
14
+ };
15
+ /**
16
+ * Local in-memory transport for testing and fallback.
17
+ * Messages are stored in memory and delivered synchronously.
18
+ */
19
+ export class LocalTransport {
20
+ name = 'local';
21
+ capabilities = localCapabilities;
22
+ connected = false;
23
+ queues = new Map();
24
+ subscriptions = new Map();
25
+ completedMessages = [];
26
+ delayedTimers = new Set();
27
+ messageIdCounter = 0;
28
+ logger;
29
+ constructor(logger) {
30
+ this.logger = logger ?? consoleLogger;
31
+ }
32
+ async connect() {
33
+ this.connected = true;
34
+ }
35
+ async disconnect() {
36
+ // Cancel all delayed message timers
37
+ for (const timer of this.delayedTimers) {
38
+ clearTimeout(timer);
39
+ }
40
+ this.delayedTimers.clear();
41
+ // Deactivate all subscriptions
42
+ for (const subs of this.subscriptions.values()) {
43
+ for (const sub of subs) {
44
+ sub.active = false;
45
+ }
46
+ }
47
+ this.connected = false;
48
+ }
49
+ isConnected() {
50
+ return this.connected;
51
+ }
52
+ async applyTopology(topology) {
53
+ if (!this.connected) {
54
+ throw new TransportNotConnectedError(this.name, 'applyTopology');
55
+ }
56
+ // Initialize queues for the topology.
57
+ // Note: Retry queues are not pre-created here because LocalTransport handles
58
+ // retries by re-enqueueing messages with a delay to the original queue, matching
59
+ // how the pipeline schedules retries via transport.send() with a delay option.
60
+ for (const queueDef of topology.queues) {
61
+ const queueName = `${topology.namespace}.${queueDef.name}`;
62
+ if (!this.queues.has(queueName)) {
63
+ this.queues.set(queueName, []);
64
+ }
65
+ }
66
+ }
67
+ async send(queue, envelope, options) {
68
+ if (!this.connected) {
69
+ throw new TransportNotConnectedError(this.name, 'send');
70
+ }
71
+ // Handle delayed messages (non-blocking, like real transports)
72
+ if (options?.delay !== undefined && options.delay > 0) {
73
+ this.scheduleDelayedMessage(queue, envelope, options.delay);
74
+ return this.name;
75
+ }
76
+ await this.enqueue(queue, envelope);
77
+ return this.name;
78
+ }
79
+ /**
80
+ * Schedules a message for delayed delivery.
81
+ * Returns immediately (non-blocking) to match real transport behavior.
82
+ */
83
+ scheduleDelayedMessage(queue, envelope, delayMs) {
84
+ const timer = setTimeout(() => {
85
+ this.delayedTimers.delete(timer);
86
+ // Fire and forget - errors are logged in enqueue/deliverToSubscribers
87
+ this.enqueue(queue, envelope).catch((error) => {
88
+ this.logger.error('[Matador] 🔴 Failed to enqueue delayed message', error);
89
+ });
90
+ }, delayMs);
91
+ this.delayedTimers.add(timer);
92
+ }
93
+ async enqueue(queue, envelope) {
94
+ const messages = this.getOrCreateQueue(queue);
95
+ const messageId = `${++this.messageIdCounter}`;
96
+ const queuedMessage = {
97
+ envelope,
98
+ id: messageId,
99
+ completed: false,
100
+ };
101
+ messages.push(queuedMessage);
102
+ // Deliver to any active subscriptions
103
+ await this.deliverToSubscribers(queue, queuedMessage);
104
+ }
105
+ async deliverToSubscribers(queue, message) {
106
+ const subs = this.subscriptions.get(queue);
107
+ if (!subs)
108
+ return;
109
+ for (const sub of subs) {
110
+ if (!sub.active || message.completed)
111
+ continue;
112
+ const receipt = {
113
+ handle: message,
114
+ redelivered: false,
115
+ attemptNumber: message.envelope.docket.attempts,
116
+ deliveryCount: message.envelope.docket.attempts,
117
+ sourceQueue: queue,
118
+ sourceTransport: this.name,
119
+ };
120
+ try {
121
+ await sub.handler(message.envelope, receipt);
122
+ }
123
+ catch (error) {
124
+ // Handler errors should be caught in the pipeline
125
+ this.logger.error('🔴 Handler error in message processing', error);
126
+ }
127
+ }
128
+ }
129
+ async subscribe(queue, handler, options = {}) {
130
+ if (!this.connected) {
131
+ throw new TransportNotConnectedError(this.name, 'subscribe');
132
+ }
133
+ const subscription = {
134
+ handler,
135
+ options,
136
+ active: true,
137
+ };
138
+ const subs = this.subscriptions.get(queue) ?? [];
139
+ subs.push(subscription);
140
+ this.subscriptions.set(queue, subs);
141
+ // Deliver any pending messages
142
+ const messages = this.queues.get(queue) ?? [];
143
+ for (const message of messages) {
144
+ if (message.completed)
145
+ continue;
146
+ await this.deliverToSubscribers(queue, message);
147
+ }
148
+ return {
149
+ unsubscribe: async () => {
150
+ subscription.active = false;
151
+ const remaining = subs.filter((s) => s !== subscription);
152
+ if (remaining.length > 0) {
153
+ this.subscriptions.set(queue, remaining);
154
+ }
155
+ else {
156
+ this.subscriptions.delete(queue);
157
+ }
158
+ },
159
+ get isActive() {
160
+ return subscription.active;
161
+ },
162
+ };
163
+ }
164
+ async complete(receipt) {
165
+ const message = receipt.handle;
166
+ message.completed = true;
167
+ this.completedMessages.push(receipt);
168
+ }
169
+ async sendToDeadLetter(receipt, dlqName, envelope, _reason) {
170
+ const dlqQueueName = `${receipt.sourceQueue}.${dlqName}`;
171
+ await this.enqueue(dlqQueueName, envelope);
172
+ await this.complete(receipt);
173
+ }
174
+ // Test helpers
175
+ /**
176
+ * Gets the current size of a queue.
177
+ */
178
+ getQueueSize(queue) {
179
+ const messages = this.queues.get(queue);
180
+ if (!messages)
181
+ return 0;
182
+ return messages.filter((m) => !m.completed).length;
183
+ }
184
+ /**
185
+ * Gets all completed message receipts.
186
+ */
187
+ getCompleted() {
188
+ return this.completedMessages;
189
+ }
190
+ /**
191
+ * Gets pending (uncompleted) messages from a queue.
192
+ */
193
+ getPendingMessages(queue) {
194
+ const messages = this.queues.get(queue);
195
+ if (!messages)
196
+ return [];
197
+ return messages.filter((m) => !m.completed).map((m) => m.envelope);
198
+ }
199
+ /**
200
+ * Clears all state (for test isolation).
201
+ */
202
+ clear() {
203
+ this.queues.clear();
204
+ this.subscriptions.clear();
205
+ this.completedMessages.length = 0;
206
+ this.messageIdCounter = 0;
207
+ for (const timer of this.delayedTimers) {
208
+ clearTimeout(timer);
209
+ }
210
+ this.delayedTimers.clear();
211
+ }
212
+ /**
213
+ * Receives one message from the queue without a subscription.
214
+ * Useful for testing.
215
+ */
216
+ async receiveOne(queue) {
217
+ const messages = this.queues.get(queue);
218
+ if (!messages)
219
+ return null;
220
+ const pending = messages.find((m) => !m.completed);
221
+ if (!pending)
222
+ return null;
223
+ const receipt = {
224
+ handle: pending,
225
+ redelivered: false,
226
+ attemptNumber: pending.envelope.docket.attempts,
227
+ deliveryCount: pending.envelope.docket.attempts,
228
+ sourceQueue: queue,
229
+ sourceTransport: this.name,
230
+ };
231
+ return { envelope: pending.envelope, receipt };
232
+ }
233
+ getOrCreateQueue(queue) {
234
+ let messages = this.queues.get(queue);
235
+ if (!messages) {
236
+ messages = [];
237
+ this.queues.set(queue, messages);
238
+ }
239
+ return messages;
240
+ }
241
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=local-transport.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-transport.test.d.ts","sourceRoot":"","sources":["../../../src/transport/local/local-transport.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,192 @@
1
+ import { beforeEach, describe, expect, it } from 'bun:test';
2
+ import { createEnvelope } from '../../types/index.js';
3
+ import { LocalTransport } from './local-transport.js';
4
+ describe('LocalTransport', () => {
5
+ let transport;
6
+ beforeEach(() => {
7
+ transport = new LocalTransport();
8
+ });
9
+ describe('connection', () => {
10
+ it('should start disconnected', () => {
11
+ expect(transport.isConnected()).toBe(false);
12
+ });
13
+ it('should connect successfully', async () => {
14
+ await transport.connect();
15
+ expect(transport.isConnected()).toBe(true);
16
+ });
17
+ it('should disconnect successfully', async () => {
18
+ await transport.connect();
19
+ await transport.disconnect();
20
+ expect(transport.isConnected()).toBe(false);
21
+ });
22
+ });
23
+ describe('capabilities', () => {
24
+ it('should report correct capabilities', () => {
25
+ expect(transport.name).toBe('local');
26
+ expect(transport.capabilities.deliveryModes).toContain('at-least-once');
27
+ expect(transport.capabilities.delayedMessages).toBe(true);
28
+ expect(transport.capabilities.deadLetterRouting).toBe('manual');
29
+ });
30
+ });
31
+ describe('send and receive', () => {
32
+ beforeEach(async () => {
33
+ await transport.connect();
34
+ });
35
+ it('should throw when sending while disconnected', async () => {
36
+ await transport.disconnect();
37
+ const envelope = createTestEnvelope();
38
+ await expect(transport.send('test-queue', envelope)).rejects.toThrow('is not connected');
39
+ });
40
+ it('should send and receive a message', async () => {
41
+ const envelope = createTestEnvelope();
42
+ await transport.send('test-queue', envelope);
43
+ const received = await transport.receiveOne('test-queue');
44
+ expect(received).not.toBeNull();
45
+ expect(received?.envelope.id).toBe(envelope.id);
46
+ expect(received?.envelope.data).toEqual({ test: 'data' });
47
+ });
48
+ it('should track queue size correctly', async () => {
49
+ expect(transport.getQueueSize('test-queue')).toBe(0);
50
+ await transport.send('test-queue', createTestEnvelope());
51
+ expect(transport.getQueueSize('test-queue')).toBe(1);
52
+ await transport.send('test-queue', createTestEnvelope());
53
+ expect(transport.getQueueSize('test-queue')).toBe(2);
54
+ });
55
+ it('should complete messages and remove from queue', async () => {
56
+ const envelope = createTestEnvelope();
57
+ await transport.send('test-queue', envelope);
58
+ const received = await transport.receiveOne('test-queue');
59
+ expect(received).not.toBeNull();
60
+ await transport.complete(received.receipt);
61
+ expect(transport.getQueueSize('test-queue')).toBe(0);
62
+ expect(transport.getCompleted()).toHaveLength(1);
63
+ });
64
+ it('should return null when queue is empty', async () => {
65
+ const received = await transport.receiveOne('empty-queue');
66
+ expect(received).toBeNull();
67
+ });
68
+ });
69
+ describe('subscriptions', () => {
70
+ beforeEach(async () => {
71
+ await transport.connect();
72
+ });
73
+ it('should throw when subscribing while disconnected', async () => {
74
+ await transport.disconnect();
75
+ await expect(transport.subscribe('test-queue', async () => { })).rejects.toThrow('is not connected');
76
+ });
77
+ it('should deliver messages to subscribers', async () => {
78
+ const receivedMessages = [];
79
+ await transport.subscribe('test-queue', async (envelope) => {
80
+ receivedMessages.push(envelope);
81
+ });
82
+ const envelope = createTestEnvelope();
83
+ await transport.send('test-queue', envelope);
84
+ expect(receivedMessages).toHaveLength(1);
85
+ expect(receivedMessages[0].id).toBe(envelope.id);
86
+ });
87
+ it('should deliver pending messages when subscribing', async () => {
88
+ const envelope = createTestEnvelope();
89
+ await transport.send('test-queue', envelope);
90
+ const receivedMessages = [];
91
+ await transport.subscribe('test-queue', async (env) => {
92
+ receivedMessages.push(env);
93
+ });
94
+ expect(receivedMessages).toHaveLength(1);
95
+ });
96
+ it('should stop delivering after unsubscribe', async () => {
97
+ const receivedMessages = [];
98
+ const subscription = await transport.subscribe('test-queue', async (envelope) => {
99
+ receivedMessages.push(envelope);
100
+ });
101
+ await transport.send('test-queue', createTestEnvelope());
102
+ expect(receivedMessages).toHaveLength(1);
103
+ await subscription.unsubscribe();
104
+ expect(subscription.isActive).toBe(false);
105
+ });
106
+ });
107
+ describe('dead letter queue', () => {
108
+ beforeEach(async () => {
109
+ await transport.connect();
110
+ });
111
+ it('should send messages to dead letter queue', async () => {
112
+ const envelope = createTestEnvelope();
113
+ await transport.send('test-queue', envelope);
114
+ const received = await transport.receiveOne('test-queue');
115
+ expect(received).not.toBeNull();
116
+ await transport.sendToDeadLetter(received.receipt, 'dlq', envelope, 'test error');
117
+ expect(transport.getQueueSize('test-queue')).toBe(0);
118
+ expect(transport.getQueueSize('test-queue.dlq')).toBe(1);
119
+ });
120
+ });
121
+ describe('topology', () => {
122
+ it('should apply topology and create queues', async () => {
123
+ const topology = {
124
+ namespace: 'test',
125
+ queues: [{ name: 'events' }, { name: 'notifications' }],
126
+ deadLetter: {
127
+ unhandled: { enabled: true },
128
+ undeliverable: { enabled: true },
129
+ },
130
+ retry: {
131
+ enabled: true,
132
+ defaultDelayMs: 1000,
133
+ maxDelayMs: 30000,
134
+ },
135
+ };
136
+ await transport.connect();
137
+ await transport.applyTopology(topology);
138
+ // Queues should be created
139
+ expect(transport.getQueueSize('test.events')).toBe(0);
140
+ expect(transport.getQueueSize('test.notifications')).toBe(0);
141
+ });
142
+ });
143
+ describe('clear', () => {
144
+ it('should reset all state', async () => {
145
+ await transport.connect();
146
+ await transport.send('test-queue', createTestEnvelope());
147
+ const received = await transport.receiveOne('test-queue');
148
+ await transport.complete(received.receipt);
149
+ transport.clear();
150
+ expect(transport.getQueueSize('test-queue')).toBe(0);
151
+ expect(transport.getCompleted()).toHaveLength(0);
152
+ });
153
+ });
154
+ describe('delayed messages', () => {
155
+ beforeEach(async () => {
156
+ await transport.connect();
157
+ });
158
+ it('should return immediately and delay message delivery', async () => {
159
+ const envelope = createTestEnvelope();
160
+ // Send returns immediately (non-blocking)
161
+ await transport.send('test-queue', envelope, {
162
+ delay: 100,
163
+ });
164
+ // Message should not be in queue immediately
165
+ expect(transport.getQueueSize('test-queue')).toBe(0);
166
+ // Wait for the delay to pass
167
+ await new Promise((resolve) => setTimeout(resolve, 150));
168
+ // Message should now be in queue
169
+ expect(transport.getQueueSize('test-queue')).toBe(1);
170
+ });
171
+ it('should cancel delayed messages on disconnect', async () => {
172
+ const envelope = createTestEnvelope();
173
+ await transport.send('test-queue', envelope, {
174
+ delay: 100,
175
+ });
176
+ // Disconnect before delay expires
177
+ await transport.disconnect();
178
+ // Wait past the original delay
179
+ await new Promise((resolve) => setTimeout(resolve, 150));
180
+ // Message should never have been delivered
181
+ expect(transport.getQueueSize('test-queue')).toBe(0);
182
+ });
183
+ });
184
+ });
185
+ function createTestEnvelope() {
186
+ return createEnvelope({
187
+ eventKey: 'test.event',
188
+ targetSubscriber: 'test-subscriber',
189
+ data: { test: 'data' },
190
+ importance: 'should-investigate',
191
+ });
192
+ }
@@ -0,0 +1,94 @@
1
+ import type { TransportFallbackContext } from '../../hooks/index.js';
2
+ import type { Topology } from '../../topology/types.js';
3
+ import type { Envelope } from '../../types/index.js';
4
+ import type { TransportCapabilities } from '../capabilities.js';
5
+ import type { MessageHandler, MessageReceipt, SendOptions, SubscribeOptions, Subscription, Transport } from '../transport.js';
6
+ /**
7
+ * Configuration for MultiTransport.
8
+ */
9
+ export interface MultiTransportConfig {
10
+ /**
11
+ * Ordered list of transports.
12
+ * First transport is primary, rest are used as fallbacks when primary fails
13
+ * (if fallback is enabled), or can be explicitly selected via the getDesiredBackend hook.
14
+ */
15
+ readonly transports: readonly Transport[];
16
+ /**
17
+ * Whether to automatically try fallback transports when the primary/selected fails.
18
+ * When true (default), send() will try each transport in order until one succeeds.
19
+ * When false, send() will only use the selected transport and throw immediately on failure.
20
+ *
21
+ * @default true
22
+ */
23
+ readonly fallbackEnabled?: boolean;
24
+ }
25
+ /**
26
+ * Hooks for MultiTransport.
27
+ */
28
+ export interface MultiTransportHooks {
29
+ /**
30
+ * Hook to dynamically select which backend to use.
31
+ * Return the transport name (e.g., 'local', 'rabbitmq') or undefined to use primary.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * getDesiredBackend: async () => {
36
+ * if (process.env.SANDBOX === 'true') return 'local';
37
+ * const backend = await runtimeConfig.get('events.backend');
38
+ * return backend || 'rabbitmq';
39
+ * }
40
+ * ```
41
+ */
42
+ readonly getDesiredBackend?: () => string | undefined | Promise<string | undefined>;
43
+ /**
44
+ * Called when a fallback transport is used successfully after the selected one fails.
45
+ * Only called when fallbackEnabled is true.
46
+ */
47
+ readonly onEnqueueFallback?: (context: TransportFallbackContext) => void;
48
+ }
49
+ /**
50
+ * A transport wrapper that manages multiple transports.
51
+ *
52
+ * Features:
53
+ * - All transports are connected upfront
54
+ * - send() tries transports in order until one succeeds (fallback behavior)
55
+ * - Specific transport can be selected via getDesiredBackend hook
56
+ * - Subscriptions are created on ALL transports
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const transport = new MultiTransport(
61
+ * { transports: [rabbitMQTransport, localTransport] },
62
+ * { onEnqueueFallback: (ctx) => console.warn(`Fallback to ${ctx.nextTransport}`) },
63
+ * );
64
+ * ```
65
+ */
66
+ export declare class MultiTransport implements Transport {
67
+ readonly name: string;
68
+ readonly capabilities: TransportCapabilities;
69
+ readonly primary: Transport;
70
+ /** All available transports, in order of preference (primary first). */
71
+ readonly transports: readonly Transport[];
72
+ /** Whether fallback to secondary transports is enabled. */
73
+ readonly fallbackEnabled: boolean;
74
+ private readonly hooks;
75
+ private connected;
76
+ constructor(config: MultiTransportConfig, hooks?: MultiTransportHooks);
77
+ connect(): Promise<void>;
78
+ disconnect(): Promise<void>;
79
+ isConnected(): boolean;
80
+ applyTopology(topology: Topology): Promise<void>;
81
+ send(queue: string, envelope: Envelope, options?: SendOptions): Promise<Transport['name']>;
82
+ /**
83
+ * Selects the transport to use based on the getDesiredBackend hook.
84
+ */
85
+ private selectTransport;
86
+ /**
87
+ * Returns transports in order, with the selected transport first.
88
+ */
89
+ private getTransportOrder;
90
+ subscribe(queue: string, handler: MessageHandler, options?: SubscribeOptions): Promise<Subscription>;
91
+ complete(receipt: MessageReceipt): Promise<void>;
92
+ sendToDeadLetter(receipt: MessageReceipt, dlqName: string, envelope: Envelope, reason: string): Promise<void>;
93
+ }
94
+ //# sourceMappingURL=multi-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-transport.d.ts","sourceRoot":"","sources":["../../../src/transport/multi/multi-transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACV,MAAM,iBAAiB,CAAC;AAgBzB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAE1C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MACzB,MAAM,GACN,SAAS,GACT,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEhC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;CAC1E;AAmBD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,cAAe,YAAW,SAAS;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAE5B,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAE1C,2DAA2D;IAC3D,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAElC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,oBAAoB,EAAE,KAAK,GAAE,mBAAwB;IAcnE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,WAAW,IAAI,OAAO;IAKhB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,IAAI,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAyC7B;;OAEG;YACW,eAAe;IAwB7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASnB,SAAS,CACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,YAAY,CAAC;IA0BlB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,gBAAgB,CACpB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;CAOjB"}