pp-command-bus 1.5.0 → 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 (205) hide show
  1. package/README.md +400 -1219
  2. package/dist/command-bus/command-bus.spec.js +138 -359
  3. package/dist/command-bus/command-bus.spec.js.map +1 -1
  4. package/dist/command-bus/command.d.ts +3 -4
  5. package/dist/command-bus/command.js +3 -32
  6. package/dist/command-bus/command.js.map +1 -1
  7. package/dist/command-bus/config/command-bus-config.d.ts +80 -21
  8. package/dist/command-bus/config/command-bus-config.js +104 -58
  9. package/dist/command-bus/config/command-bus-config.js.map +1 -1
  10. package/dist/command-bus/config/command-bus-config.spec.js +174 -100
  11. package/dist/command-bus/config/command-bus-config.spec.js.map +1 -1
  12. package/dist/command-bus/index.d.ts +41 -50
  13. package/dist/command-bus/index.js +143 -127
  14. package/dist/command-bus/index.js.map +1 -1
  15. package/dist/command-bus/interceptors/index.d.ts +5 -0
  16. package/dist/command-bus/interceptors/index.js +22 -0
  17. package/dist/command-bus/interceptors/index.js.map +1 -0
  18. package/dist/command-bus/interceptors/interceptor.interface.d.ts +35 -0
  19. package/dist/command-bus/interceptors/interceptor.interface.js +3 -0
  20. package/dist/command-bus/interceptors/interceptor.interface.js.map +1 -0
  21. package/dist/command-bus/interceptors/performance-interceptor.d.ts +24 -0
  22. package/dist/command-bus/interceptors/performance-interceptor.js +86 -0
  23. package/dist/command-bus/interceptors/performance-interceptor.js.map +1 -0
  24. package/dist/command-bus/interceptors/performance-interceptor.spec.js +124 -0
  25. package/dist/command-bus/interceptors/performance-interceptor.spec.js.map +1 -0
  26. package/dist/command-bus/logging/command-logger.d.ts +2 -0
  27. package/dist/command-bus/logging/command-logger.js +7 -0
  28. package/dist/command-bus/logging/command-logger.js.map +1 -1
  29. package/dist/command-bus/logging/command-logger.spec.js +36 -0
  30. package/dist/command-bus/logging/command-logger.spec.js.map +1 -1
  31. package/dist/command-bus/serialization/index.d.ts +6 -0
  32. package/dist/command-bus/serialization/index.js +9 -0
  33. package/dist/command-bus/serialization/index.js.map +1 -0
  34. package/dist/command-bus/serialization/msgpack-serializer.d.ts +26 -0
  35. package/dist/command-bus/serialization/msgpack-serializer.js +70 -0
  36. package/dist/command-bus/serialization/msgpack-serializer.js.map +1 -0
  37. package/dist/command-bus/serialization/msgpack-serializer.spec.js +223 -0
  38. package/dist/command-bus/serialization/msgpack-serializer.spec.js.map +1 -0
  39. package/dist/command-bus/serialization/serializer.interface.d.ts +21 -0
  40. package/dist/command-bus/serialization/serializer.interface.js +3 -0
  41. package/dist/command-bus/serialization/serializer.interface.js.map +1 -0
  42. package/dist/command-bus/transport/consumer-loop.d.ts +45 -0
  43. package/dist/command-bus/transport/consumer-loop.js +90 -0
  44. package/dist/command-bus/transport/consumer-loop.js.map +1 -0
  45. package/dist/command-bus/transport/consumer-loop.spec.js +216 -0
  46. package/dist/command-bus/transport/consumer-loop.spec.js.map +1 -0
  47. package/dist/command-bus/transport/index.d.ts +21 -0
  48. package/dist/command-bus/transport/index.js +23 -0
  49. package/dist/command-bus/transport/index.js.map +1 -0
  50. package/dist/command-bus/transport/message-processor.d.ts +70 -0
  51. package/dist/command-bus/transport/message-processor.js +158 -0
  52. package/dist/command-bus/transport/message-processor.js.map +1 -0
  53. package/dist/command-bus/transport/message-processor.spec.js +185 -0
  54. package/dist/command-bus/transport/message-processor.spec.js.map +1 -0
  55. package/dist/command-bus/transport/pending-recovery.d.ts +54 -0
  56. package/dist/command-bus/transport/pending-recovery.js +139 -0
  57. package/dist/command-bus/transport/pending-recovery.js.map +1 -0
  58. package/dist/command-bus/transport/pending-recovery.spec.js +176 -0
  59. package/dist/command-bus/transport/pending-recovery.spec.js.map +1 -0
  60. package/dist/command-bus/transport/redis-codec.d.ts +24 -0
  61. package/dist/command-bus/transport/redis-codec.js +33 -0
  62. package/dist/command-bus/transport/redis-codec.js.map +1 -0
  63. package/dist/command-bus/transport/redis-codec.spec.js +53 -0
  64. package/dist/command-bus/transport/redis-codec.spec.js.map +1 -0
  65. package/dist/command-bus/transport/redis-streams-transport.d.ts +94 -0
  66. package/dist/command-bus/transport/redis-streams-transport.js +143 -0
  67. package/dist/command-bus/transport/redis-streams-transport.js.map +1 -0
  68. package/dist/command-bus/transport/redis-streams-transport.spec.js +420 -0
  69. package/dist/command-bus/transport/redis-streams-transport.spec.js.map +1 -0
  70. package/dist/command-bus/transport/rpc-handler.d.ts +39 -0
  71. package/dist/command-bus/transport/rpc-handler.js +87 -0
  72. package/dist/command-bus/transport/rpc-handler.js.map +1 -0
  73. package/dist/command-bus/transport/rpc-handler.spec.js +157 -0
  74. package/dist/command-bus/transport/rpc-handler.spec.js.map +1 -0
  75. package/dist/command-bus/transport/stream-consumer.d.ts +91 -0
  76. package/dist/command-bus/transport/stream-consumer.js +182 -0
  77. package/dist/command-bus/transport/stream-consumer.js.map +1 -0
  78. package/dist/command-bus/transport/stream-consumer.spec.js +284 -0
  79. package/dist/command-bus/transport/stream-consumer.spec.js.map +1 -0
  80. package/dist/command-bus/transport/stream-producer.d.ts +23 -0
  81. package/dist/command-bus/transport/stream-producer.js +70 -0
  82. package/dist/command-bus/transport/stream-producer.js.map +1 -0
  83. package/dist/command-bus/transport/stream-producer.spec.js +125 -0
  84. package/dist/command-bus/transport/stream-producer.spec.js.map +1 -0
  85. package/dist/command-bus/transport/transport.interface.d.ts +87 -0
  86. package/dist/command-bus/transport/transport.interface.js +3 -0
  87. package/dist/command-bus/transport/transport.interface.js.map +1 -0
  88. package/dist/command-bus/types/index.d.ts +0 -84
  89. package/dist/examples/rpc.demo.js +1 -1
  90. package/dist/examples/rpc.demo.js.map +1 -1
  91. package/dist/index.d.ts +8 -5
  92. package/dist/index.js +6 -4
  93. package/dist/index.js.map +1 -1
  94. package/dist/pp-command-bus-2.0.1.tgz +0 -0
  95. package/dist/shared/redis/connection-pool.d.ts +54 -0
  96. package/dist/shared/redis/connection-pool.js +123 -0
  97. package/dist/shared/redis/connection-pool.js.map +1 -0
  98. package/dist/shared/redis/connection-pool.spec.d.ts +1 -0
  99. package/dist/shared/redis/connection-pool.spec.js +114 -0
  100. package/dist/shared/redis/connection-pool.spec.js.map +1 -0
  101. package/dist/shared/redis/index.d.ts +5 -3
  102. package/dist/shared/redis/index.js +6 -4
  103. package/dist/shared/redis/index.js.map +1 -1
  104. package/dist/shared/redis/rpc-connection-pool.d.ts +61 -0
  105. package/dist/shared/redis/rpc-connection-pool.js +154 -0
  106. package/dist/shared/redis/rpc-connection-pool.js.map +1 -0
  107. package/dist/shared/redis/rpc-connection-pool.spec.d.ts +1 -0
  108. package/dist/shared/redis/rpc-connection-pool.spec.js +173 -0
  109. package/dist/shared/redis/rpc-connection-pool.spec.js.map +1 -0
  110. package/dist/shared/types.d.ts +0 -4
  111. package/dist/shared/utils/error-utils.d.ts +8 -0
  112. package/dist/shared/utils/error-utils.js +14 -0
  113. package/dist/shared/utils/error-utils.js.map +1 -0
  114. package/package.json +12 -12
  115. package/dist/command-bus/config/auto-config-optimizer.d.ts +0 -35
  116. package/dist/command-bus/config/auto-config-optimizer.js +0 -52
  117. package/dist/command-bus/config/auto-config-optimizer.js.map +0 -1
  118. package/dist/command-bus/config/auto-config-optimizer.spec.js +0 -42
  119. package/dist/command-bus/config/auto-config-optimizer.spec.js.map +0 -1
  120. package/dist/command-bus/job/index.d.ts +0 -6
  121. package/dist/command-bus/job/index.js +0 -15
  122. package/dist/command-bus/job/index.js.map +0 -1
  123. package/dist/command-bus/job/job-options-builder.d.ts +0 -21
  124. package/dist/command-bus/job/job-options-builder.js +0 -58
  125. package/dist/command-bus/job/job-options-builder.js.map +0 -1
  126. package/dist/command-bus/job/job-options-builder.spec.js +0 -156
  127. package/dist/command-bus/job/job-options-builder.spec.js.map +0 -1
  128. package/dist/command-bus/job/job-processor.d.ts +0 -39
  129. package/dist/command-bus/job/job-processor.js +0 -203
  130. package/dist/command-bus/job/job-processor.js.map +0 -1
  131. package/dist/command-bus/job/job-processor.spec.js +0 -436
  132. package/dist/command-bus/job/job-processor.spec.js.map +0 -1
  133. package/dist/command-bus/queue/index.d.ts +0 -5
  134. package/dist/command-bus/queue/index.js +0 -13
  135. package/dist/command-bus/queue/index.js.map +0 -1
  136. package/dist/command-bus/queue/queue-manager.d.ts +0 -56
  137. package/dist/command-bus/queue/queue-manager.js +0 -163
  138. package/dist/command-bus/queue/queue-manager.js.map +0 -1
  139. package/dist/command-bus/queue/queue-manager.spec.js +0 -371
  140. package/dist/command-bus/queue/queue-manager.spec.js.map +0 -1
  141. package/dist/command-bus/rpc/index.d.ts +0 -11
  142. package/dist/command-bus/rpc/index.js +0 -19
  143. package/dist/command-bus/rpc/index.js.map +0 -1
  144. package/dist/command-bus/rpc/payload-compression.service.d.ts +0 -50
  145. package/dist/command-bus/rpc/payload-compression.service.js +0 -215
  146. package/dist/command-bus/rpc/payload-compression.service.js.map +0 -1
  147. package/dist/command-bus/rpc/payload-compression.service.spec.js +0 -376
  148. package/dist/command-bus/rpc/payload-compression.service.spec.js.map +0 -1
  149. package/dist/command-bus/rpc/rpc-coordinator.d.ts +0 -96
  150. package/dist/command-bus/rpc/rpc-coordinator.js +0 -500
  151. package/dist/command-bus/rpc/rpc-coordinator.js.map +0 -1
  152. package/dist/command-bus/rpc/rpc-coordinator.spec.js +0 -621
  153. package/dist/command-bus/rpc/rpc-coordinator.spec.js.map +0 -1
  154. package/dist/command-bus/rpc/rpc-job-cancellation.service.d.ts +0 -82
  155. package/dist/command-bus/rpc/rpc-job-cancellation.service.js +0 -180
  156. package/dist/command-bus/rpc/rpc-job-cancellation.service.js.map +0 -1
  157. package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js +0 -286
  158. package/dist/command-bus/rpc/rpc-job-cancellation.service.spec.js.map +0 -1
  159. package/dist/command-bus/worker/index.d.ts +0 -10
  160. package/dist/command-bus/worker/index.js +0 -19
  161. package/dist/command-bus/worker/index.js.map +0 -1
  162. package/dist/command-bus/worker/worker-benchmark.d.ts +0 -71
  163. package/dist/command-bus/worker/worker-benchmark.js +0 -202
  164. package/dist/command-bus/worker/worker-benchmark.js.map +0 -1
  165. package/dist/command-bus/worker/worker-benchmark.spec.js +0 -310
  166. package/dist/command-bus/worker/worker-benchmark.spec.js.map +0 -1
  167. package/dist/command-bus/worker/worker-metrics-collector.d.ts +0 -98
  168. package/dist/command-bus/worker/worker-metrics-collector.js +0 -242
  169. package/dist/command-bus/worker/worker-metrics-collector.js.map +0 -1
  170. package/dist/command-bus/worker/worker-orchestrator.d.ts +0 -70
  171. package/dist/command-bus/worker/worker-orchestrator.js +0 -339
  172. package/dist/command-bus/worker/worker-orchestrator.js.map +0 -1
  173. package/dist/command-bus/worker/worker-orchestrator.spec.js +0 -712
  174. package/dist/command-bus/worker/worker-orchestrator.spec.js.map +0 -1
  175. package/dist/examples/auto-config.demo.d.ts +0 -9
  176. package/dist/examples/auto-config.demo.js +0 -106
  177. package/dist/examples/auto-config.demo.js.map +0 -1
  178. package/dist/examples/rpc-compression.demo.d.ts +0 -5
  179. package/dist/examples/rpc-compression.demo.js +0 -358
  180. package/dist/examples/rpc-compression.demo.js.map +0 -1
  181. package/dist/examples/rpc-resilience.demo.d.ts +0 -15
  182. package/dist/examples/rpc-resilience.demo.js +0 -233
  183. package/dist/examples/rpc-resilience.demo.js.map +0 -1
  184. package/dist/pp-command-bus-1.5.0.tgz +0 -0
  185. package/dist/shared/config/base-config.d.ts +0 -54
  186. package/dist/shared/config/base-config.js +0 -114
  187. package/dist/shared/config/base-config.js.map +0 -1
  188. package/dist/shared/config/base-config.spec.js +0 -204
  189. package/dist/shared/config/base-config.spec.js.map +0 -1
  190. package/dist/shared/config/index.d.ts +0 -1
  191. package/dist/shared/config/index.js +0 -9
  192. package/dist/shared/config/index.js.map +0 -1
  193. package/dist/shared/redis/redis-connection-factory.d.ts +0 -66
  194. package/dist/shared/redis/redis-connection-factory.js +0 -113
  195. package/dist/shared/redis/redis-connection-factory.js.map +0 -1
  196. /package/dist/command-bus/{config/auto-config-optimizer.spec.d.ts → interceptors/performance-interceptor.spec.d.ts} +0 -0
  197. /package/dist/command-bus/{job/job-options-builder.spec.d.ts → serialization/msgpack-serializer.spec.d.ts} +0 -0
  198. /package/dist/command-bus/{job/job-processor.spec.d.ts → transport/consumer-loop.spec.d.ts} +0 -0
  199. /package/dist/command-bus/{queue/queue-manager.spec.d.ts → transport/message-processor.spec.d.ts} +0 -0
  200. /package/dist/command-bus/{rpc/payload-compression.service.spec.d.ts → transport/pending-recovery.spec.d.ts} +0 -0
  201. /package/dist/command-bus/{rpc/rpc-coordinator.spec.d.ts → transport/redis-codec.spec.d.ts} +0 -0
  202. /package/dist/command-bus/{rpc/rpc-job-cancellation.service.spec.d.ts → transport/redis-streams-transport.spec.d.ts} +0 -0
  203. /package/dist/command-bus/{worker/worker-benchmark.spec.d.ts → transport/rpc-handler.spec.d.ts} +0 -0
  204. /package/dist/command-bus/{worker/worker-orchestrator.spec.d.ts → transport/stream-consumer.spec.d.ts} +0 -0
  205. /package/dist/{shared/config/base-config.spec.d.ts → command-bus/transport/stream-producer.spec.d.ts} +0 -0
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const pending_recovery_1 = require("./pending-recovery");
13
+ /**
14
+ * Mock helpers
15
+ */
16
+ function createMockLogger() {
17
+ return {
18
+ log: jest.fn(),
19
+ error: jest.fn(),
20
+ warn: jest.fn(),
21
+ debug: jest.fn(),
22
+ };
23
+ }
24
+ function createMockConnection() {
25
+ return {
26
+ xpending: jest.fn().mockResolvedValue([]),
27
+ xclaim: jest.fn().mockResolvedValue([]),
28
+ xack: jest.fn().mockResolvedValue(1),
29
+ xadd: jest.fn().mockResolvedValue('1700000000000-0'),
30
+ };
31
+ }
32
+ function createMockPool() {
33
+ const conn = createMockConnection();
34
+ return {
35
+ pool: { next: jest.fn().mockReturnValue(conn) },
36
+ conn,
37
+ };
38
+ }
39
+ function createMockConsumer() {
40
+ return {
41
+ processMessage: jest.fn().mockResolvedValue(undefined),
42
+ processing: new Map(),
43
+ };
44
+ }
45
+ describe('PendingRecovery', () => {
46
+ let recovery;
47
+ let logger;
48
+ let mockConn;
49
+ let mockPool;
50
+ let mockConsumer;
51
+ beforeEach(() => {
52
+ jest.clearAllMocks();
53
+ jest.useFakeTimers();
54
+ logger = createMockLogger();
55
+ const poolMock = createMockPool();
56
+ mockPool = poolMock.pool;
57
+ mockConn = poolMock.conn;
58
+ mockConsumer = createMockConsumer();
59
+ recovery = new pending_recovery_1.PendingRecovery({
60
+ pool: mockPool,
61
+ logger,
62
+ consumerId: 'test-consumer',
63
+ maxAttempts: 3,
64
+ claimTimeout: 30000,
65
+ });
66
+ });
67
+ afterEach(() => {
68
+ recovery.stop();
69
+ jest.useRealTimers();
70
+ });
71
+ describe('start/stop', () => {
72
+ it('powinien uruchomić periodyczny recovery', () => {
73
+ const handler = jest.fn();
74
+ recovery.start('cmd:Test', 'workers', handler, mockConsumer);
75
+ expect(recovery['recoveryIntervals'].length).toBe(1);
76
+ });
77
+ it('powinien zatrzymać recovery intervals', () => {
78
+ const handler = jest.fn();
79
+ recovery.start('cmd:Test', 'workers', handler, mockConsumer);
80
+ recovery.start('cmd:Other', 'workers', handler, mockConsumer);
81
+ expect(recovery['recoveryIntervals'].length).toBe(2);
82
+ recovery.stop();
83
+ expect(recovery['recoveryIntervals'].length).toBe(0);
84
+ });
85
+ it('powinien wywołać recoverPending co claimTimeout', () => {
86
+ const handler = jest.fn();
87
+ recovery.start('cmd:Test', 'workers', handler, mockConsumer);
88
+ // Advance timer o 3 interwały
89
+ jest.advanceTimersByTime(90000); // 3 * 30000
90
+ // XPENDING powinien być wywołany 3 razy
91
+ expect(mockConn.xpending).toHaveBeenCalledTimes(3);
92
+ });
93
+ });
94
+ describe('recoverPending()', () => {
95
+ /**
96
+ * Dostęp do prywatnej metody recoverPending przez casting
97
+ */
98
+ const callRecoverPending = () => __awaiter(void 0, void 0, void 0, function* () {
99
+ const any = recovery;
100
+ yield any['recoverPending']('cmd:Test', 'workers', jest.fn(), mockConsumer);
101
+ });
102
+ it('powinien nie robić nic gdy brak pending wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
103
+ mockConn.xpending.mockResolvedValue([]);
104
+ yield callRecoverPending();
105
+ expect(mockConn.xclaim).not.toHaveBeenCalled();
106
+ expect(mockConn.xack).not.toHaveBeenCalled();
107
+ }));
108
+ it('powinien przejąć stalled wiadomość przez XCLAIM', () => __awaiter(void 0, void 0, void 0, function* () {
109
+ const testPayload = Buffer.from('recovered-data').toString('base64');
110
+ mockConn.xpending.mockResolvedValue([
111
+ ['msg-1', 'consumer-old', 60000, 1], // idleTime > claimTimeout, deliveryCount < maxAttempts
112
+ ]);
113
+ mockConn.xclaim.mockResolvedValue([['msg-1', ['data', testPayload]]]);
114
+ yield callRecoverPending();
115
+ expect(mockConn.xclaim).toHaveBeenCalledWith('cmd:Test', 'workers', 'test-consumer', 30000, 'msg-1');
116
+ expect(mockConsumer.processMessage).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-1', ['data', testPayload], expect.any(Function));
117
+ }));
118
+ it('powinien przenieść do DLQ po maxAttempts (D3)', () => __awaiter(void 0, void 0, void 0, function* () {
119
+ const testPayload = Buffer.from('dead-data').toString('base64');
120
+ mockConn.xpending.mockResolvedValue([
121
+ ['msg-dead', 'consumer-old', 60000, 3], // deliveryCount >= maxAttempts
122
+ ]);
123
+ // XCLAIM zwraca dane wiadomości do przeniesienia do DLQ
124
+ mockConn.xclaim.mockResolvedValue([['msg-dead', ['data', testPayload]]]);
125
+ yield callRecoverPending();
126
+ // XCLAIM powinien być wywołany (żeby pobrać dane do DLQ)
127
+ expect(mockConn.xclaim).toHaveBeenCalled();
128
+ // XADD do dlq: strumienia
129
+ expect(mockConn.xadd).toHaveBeenCalledWith('dlq:cmd:Test', '*', 'data', testPayload, 'original_stream', 'cmd:Test', 'delivery_count', '3');
130
+ // XACK po przeniesieniu do DLQ
131
+ expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-dead');
132
+ expect(logger.error).toHaveBeenCalledWith('Wiadomość przeniesiona do Dead Letter Queue', expect.objectContaining({
133
+ messageId: 'msg-dead',
134
+ dlqStream: 'dlq:cmd:Test',
135
+ deliveryCount: 3,
136
+ }));
137
+ }));
138
+ it('nie powinien przejmować wiadomości z idleTime < claimTimeout', () => __awaiter(void 0, void 0, void 0, function* () {
139
+ mockConn.xpending.mockResolvedValue([
140
+ ['msg-young', 'consumer-other', 5000, 1], // idleTime (5s) < claimTimeout (30s)
141
+ ]);
142
+ yield callRecoverPending();
143
+ expect(mockConn.xclaim).not.toHaveBeenCalled();
144
+ expect(mockConn.xack).not.toHaveBeenCalled();
145
+ }));
146
+ it('powinien zalogować błąd przy wyjątku', () => __awaiter(void 0, void 0, void 0, function* () {
147
+ mockConn.xpending.mockRejectedValue(new Error('Redis connection error'));
148
+ yield callRecoverPending();
149
+ expect(logger.error).toHaveBeenCalledWith('Błąd recovery pending wiadomości', expect.objectContaining({ error: 'Redis connection error' }));
150
+ }));
151
+ it('powinien obsłużyć pusty wynik XCLAIM', () => __awaiter(void 0, void 0, void 0, function* () {
152
+ mockConn.xpending.mockResolvedValue([['msg-1', 'consumer-old', 60000, 1]]);
153
+ mockConn.xclaim.mockResolvedValue([]);
154
+ yield callRecoverPending();
155
+ // processMessage NIE powinien być wywołany (brak danych w XCLAIM)
156
+ expect(mockConsumer.processMessage).not.toHaveBeenCalled();
157
+ }));
158
+ it('powinien obsłużyć wiele pending wiadomości', () => __awaiter(void 0, void 0, void 0, function* () {
159
+ const testPayload = Buffer.from('data').toString('base64');
160
+ mockConn.xpending.mockResolvedValue([
161
+ ['msg-1', 'consumer-old', 60000, 1],
162
+ ['msg-2', 'consumer-old', 60000, 2],
163
+ ['msg-dead', 'consumer-old', 60000, 5], // Dead letter
164
+ ]);
165
+ mockConn.xclaim.mockResolvedValue([['msg-claimed', ['data', testPayload]]]);
166
+ yield callRecoverPending();
167
+ // XCLAIM: msg-1, msg-2 (recovery) + msg-dead (DLQ pobieranie danych) = 3
168
+ expect(mockConn.xclaim).toHaveBeenCalledTimes(3);
169
+ // XADD do DLQ
170
+ expect(mockConn.xadd).toHaveBeenCalledWith('dlq:cmd:Test', '*', expect.anything(), expect.anything(), 'original_stream', 'cmd:Test', 'delivery_count', '5');
171
+ // XACK dla dead letter
172
+ expect(mockConn.xack).toHaveBeenCalledWith('cmd:Test', 'workers', 'msg-dead');
173
+ }));
174
+ });
175
+ });
176
+ //# sourceMappingURL=pending-recovery.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-recovery.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/pending-recovery.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Kodek Redis — enkapsulacja kodowania/dekodowania binarnych danych
3
+ *
4
+ * ioredis dekoduje string responses jako UTF-8, co korumpuje surowe bajty msgpack.
5
+ * Base64 zapewnia bezpieczne przechowywanie binarnych danych w Redis Streams.
6
+ *
7
+ * Warianty *Buffer() (np. xreadgroupBuffer) nie są praktyczne — zwracają Buffer
8
+ * dla WSZYSTKICH pól (nazwy strumieni, messageId, klucze), co komplikuje parsowanie
9
+ * zagnieżdżonej struktury XREADGROUP.
10
+ */
11
+ export declare class RedisCodec {
12
+ /**
13
+ * Koduje dane binarne do bezpiecznego formatu dla Redis
14
+ * @param data - Surowe dane binarne
15
+ * @returns Zakodowany string (base64)
16
+ */
17
+ static encode(data: Buffer): string;
18
+ /**
19
+ * Dekoduje dane z Redis do formatu binarnego
20
+ * @param encoded - Zakodowany string (base64)
21
+ * @returns Surowe dane binarne
22
+ */
23
+ static decode(encoded: string): Buffer;
24
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisCodec = void 0;
4
+ /**
5
+ * Kodek Redis — enkapsulacja kodowania/dekodowania binarnych danych
6
+ *
7
+ * ioredis dekoduje string responses jako UTF-8, co korumpuje surowe bajty msgpack.
8
+ * Base64 zapewnia bezpieczne przechowywanie binarnych danych w Redis Streams.
9
+ *
10
+ * Warianty *Buffer() (np. xreadgroupBuffer) nie są praktyczne — zwracają Buffer
11
+ * dla WSZYSTKICH pól (nazwy strumieni, messageId, klucze), co komplikuje parsowanie
12
+ * zagnieżdżonej struktury XREADGROUP.
13
+ */
14
+ class RedisCodec {
15
+ /**
16
+ * Koduje dane binarne do bezpiecznego formatu dla Redis
17
+ * @param data - Surowe dane binarne
18
+ * @returns Zakodowany string (base64)
19
+ */
20
+ static encode(data) {
21
+ return data.toString('base64');
22
+ }
23
+ /**
24
+ * Dekoduje dane z Redis do formatu binarnego
25
+ * @param encoded - Zakodowany string (base64)
26
+ * @returns Surowe dane binarne
27
+ */
28
+ static decode(encoded) {
29
+ return Buffer.from(encoded, 'base64');
30
+ }
31
+ }
32
+ exports.RedisCodec = RedisCodec;
33
+ //# sourceMappingURL=redis-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-codec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/redis-codec.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;GASG;AACH,MAAa,UAAU;IACrB;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,OAAe;QAC3B,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;CACF;AAlBD,gCAkBC"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const redis_codec_1 = require("./redis-codec");
4
+ describe('RedisCodec', () => {
5
+ describe('encode/decode roundtrip', () => {
6
+ it('powinien zakodować i zdekodować dane binarne bez utraty', () => {
7
+ const original = Buffer.from('Jan Kowalski, ul. Długa 15, Warszawa');
8
+ const encoded = redis_codec_1.RedisCodec.encode(original);
9
+ const decoded = redis_codec_1.RedisCodec.decode(encoded);
10
+ expect(decoded).toEqual(original);
11
+ });
12
+ it('powinien obsłużyć pusty Buffer', () => {
13
+ const original = Buffer.alloc(0);
14
+ const encoded = redis_codec_1.RedisCodec.encode(original);
15
+ const decoded = redis_codec_1.RedisCodec.decode(encoded);
16
+ expect(decoded).toEqual(original);
17
+ expect(decoded.length).toBe(0);
18
+ });
19
+ it('powinien obsłużyć dane binarne z null bytes', () => {
20
+ const original = Buffer.from([0x00, 0x01, 0xff, 0x00, 0xab]);
21
+ const encoded = redis_codec_1.RedisCodec.encode(original);
22
+ const decoded = redis_codec_1.RedisCodec.decode(encoded);
23
+ expect(decoded).toEqual(original);
24
+ });
25
+ it('powinien obsłużyć duże dane (1MB)', () => {
26
+ const original = Buffer.alloc(1024 * 1024, 0xab);
27
+ const encoded = redis_codec_1.RedisCodec.encode(original);
28
+ const decoded = redis_codec_1.RedisCodec.decode(encoded);
29
+ expect(decoded).toEqual(original);
30
+ });
31
+ });
32
+ describe('encode()', () => {
33
+ it('powinien zwrócić string base64', () => {
34
+ const data = Buffer.from('test');
35
+ const encoded = redis_codec_1.RedisCodec.encode(data);
36
+ expect(typeof encoded).toBe('string');
37
+ // Walidacja formatu base64
38
+ expect(encoded).toMatch(/^[A-Za-z0-9+/]*={0,2}$/);
39
+ });
40
+ });
41
+ describe('decode()', () => {
42
+ it('powinien zdekodować prawidłowy base64 string', () => {
43
+ const base64 = Buffer.from('Anna Nowak').toString('base64');
44
+ const decoded = redis_codec_1.RedisCodec.decode(base64);
45
+ expect(decoded.toString()).toBe('Anna Nowak');
46
+ });
47
+ it('powinien zwrócić pusty Buffer dla pustego stringa', () => {
48
+ const decoded = redis_codec_1.RedisCodec.decode('');
49
+ expect(decoded.length).toBe(0);
50
+ });
51
+ });
52
+ });
53
+ //# sourceMappingURL=redis-codec.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-codec.spec.js","sourceRoot":"","sources":["../../../src/command-bus/transport/redis-codec.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { ILogger } from '../../shared/types';
2
+ import type { ISerializer } from '../serialization/serializer.interface';
3
+ import type { ITransport, ConsumerHandler } from './transport.interface';
4
+ import type RedisConnectionPool from '../../shared/redis/connection-pool';
5
+ import type RpcConnectionPool from '../../shared/redis/rpc-connection-pool';
6
+ import type { ICommandInterceptor } from '../interceptors';
7
+ /**
8
+ * Opcje konfiguracji RedisStreamsTransport
9
+ */
10
+ export interface RedisStreamsTransportOptions {
11
+ /** Pula połączeń Redis (round-robin, non-blocking ops) */
12
+ pool: RedisConnectionPool;
13
+ /** Pula połączeń RPC (bounded, lazy, blocking BRPOP) */
14
+ rpcPool: RpcConnectionPool;
15
+ /** Serializer do konwersji RPC metadata */
16
+ serializer: ISerializer;
17
+ /** Logger */
18
+ logger: ILogger;
19
+ /** Maksymalna liczba wiadomości w strumieniu (XTRIM ~) */
20
+ maxRetained: number;
21
+ /** Maksymalna liczba prób przetworzenia wiadomości */
22
+ maxAttempts: number;
23
+ /** Czas po którym stalled wiadomość jest przejmowana (ms) */
24
+ claimTimeout: number;
25
+ /** Liczba wiadomości pobieranych w jednym XREADGROUP */
26
+ batchSize: number;
27
+ /** Maksymalna liczba wiadomości przetwarzanych równolegle per konsument */
28
+ concurrency: number;
29
+ /** Interceptor przechwytujący wykonanie handlera */
30
+ interceptor?: ICommandInterceptor;
31
+ }
32
+ /**
33
+ * Fasada transportu Redis Streams dla CommandBus
34
+ *
35
+ * Kompozycja 4 komponentów z jasno rozdzielonymi odpowiedzialnościami:
36
+ * - StreamProducer: enqueue / enqueueBatch (XADD)
37
+ * - StreamConsumer: consume / consumerLoop / processMessage
38
+ * - RpcHandler: rpcCall / rpcRespond (LPUSH/BRPOP)
39
+ * - PendingRecovery: XPENDING / XCLAIM / dead letter
40
+ *
41
+ * Zachowuje publiczne API ITransport — zero zmian dla CommandBus
42
+ */
43
+ export default class RedisStreamsTransport implements ITransport {
44
+ private readonly pool;
45
+ private readonly rpcPool;
46
+ private readonly logger;
47
+ /** Komponenty fasady */
48
+ private readonly producer;
49
+ private readonly consumer;
50
+ private readonly rpc;
51
+ private readonly recovery;
52
+ /** Identyfikator procesu (dla consumer name) */
53
+ private readonly consumerId;
54
+ constructor(options: RedisStreamsTransportOptions);
55
+ /**
56
+ * Dodaje komendę do strumienia (fire-and-forget)
57
+ * Deleguje do StreamProducer
58
+ */
59
+ enqueue(streamName: string, data: Buffer): Promise<string>;
60
+ /**
61
+ * Dodaje wiele komend w jednym pipeline
62
+ * Deleguje do StreamProducer
63
+ */
64
+ enqueueBatch(entries: Array<{
65
+ streamName: string;
66
+ data: Buffer;
67
+ }>): Promise<string[]>;
68
+ /**
69
+ * Rejestruje konsumenta dla strumienia z consumer group
70
+ * Deleguje do StreamConsumer + uruchamia PendingRecovery
71
+ */
72
+ consume(streamName: string, groupName: string, handler: ConsumerHandler): Promise<void>;
73
+ /**
74
+ * RPC: wysyła request do strumienia i czeka na odpowiedź via BRPOP
75
+ * Deleguje do RpcHandler
76
+ */
77
+ rpcCall(commandName: string, data: Buffer, timeout: number): Promise<Buffer>;
78
+ /**
79
+ * RPC: odpowiada na request przez LPUSH + EXPIRE
80
+ * Deleguje do RpcHandler
81
+ */
82
+ rpcRespond(responseKey: string, data: Buffer, ttl: number): Promise<void>;
83
+ /**
84
+ * Zamyka transport gracefully
85
+ *
86
+ * Kolejność:
87
+ * 1. Zatrzymaj consumer.running (przerywa consumer loops)
88
+ * 2. Zatrzymaj recovery intervals
89
+ * 3. Zamknij dedykowane połączenia konsumentów (przerywa XREADGROUP BLOCK)
90
+ * 4. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
91
+ * 5. Zamknij pule połączeń
92
+ */
93
+ close(): Promise<void>;
94
+ }
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const crypto_1 = require("crypto");
13
+ const stream_producer_1 = require("./stream-producer");
14
+ const stream_consumer_1 = require("./stream-consumer");
15
+ const rpc_handler_1 = require("./rpc-handler");
16
+ const pending_recovery_1 = require("./pending-recovery");
17
+ /**
18
+ * Fasada transportu Redis Streams dla CommandBus
19
+ *
20
+ * Kompozycja 4 komponentów z jasno rozdzielonymi odpowiedzialnościami:
21
+ * - StreamProducer: enqueue / enqueueBatch (XADD)
22
+ * - StreamConsumer: consume / consumerLoop / processMessage
23
+ * - RpcHandler: rpcCall / rpcRespond (LPUSH/BRPOP)
24
+ * - PendingRecovery: XPENDING / XCLAIM / dead letter
25
+ *
26
+ * Zachowuje publiczne API ITransport — zero zmian dla CommandBus
27
+ */
28
+ class RedisStreamsTransport {
29
+ constructor(options) {
30
+ this.pool = options.pool;
31
+ this.rpcPool = options.rpcPool;
32
+ this.logger = options.logger;
33
+ this.consumerId = `consumer-${process.pid}-${(0, crypto_1.randomUUID)().slice(0, 8)}`;
34
+ // Inicjalizacja komponentów
35
+ this.producer = new stream_producer_1.StreamProducer(options.pool);
36
+ this.rpc = new rpc_handler_1.RpcHandler(options.pool, options.rpcPool, options.serializer);
37
+ this.consumer = new stream_consumer_1.StreamConsumer({
38
+ pool: options.pool,
39
+ serializer: options.serializer,
40
+ logger: options.logger,
41
+ consumerId: this.consumerId,
42
+ batchSize: options.batchSize,
43
+ concurrency: options.concurrency,
44
+ maxRetained: options.maxRetained,
45
+ rpcRespond: this.rpc.rpcRespond.bind(this.rpc),
46
+ interceptor: options.interceptor,
47
+ });
48
+ this.recovery = new pending_recovery_1.PendingRecovery({
49
+ pool: options.pool,
50
+ logger: options.logger,
51
+ consumerId: this.consumerId,
52
+ maxAttempts: options.maxAttempts,
53
+ claimTimeout: options.claimTimeout,
54
+ });
55
+ // Log inicjalizacji transportu
56
+ this.logger.log('Transport Redis Streams zainicjalizowany', {
57
+ consumerId: this.consumerId,
58
+ poolSize: options.pool.size,
59
+ maxRetained: options.maxRetained,
60
+ concurrency: options.concurrency,
61
+ timestamp: new Date().toISOString(),
62
+ });
63
+ }
64
+ /**
65
+ * Dodaje komendę do strumienia (fire-and-forget)
66
+ * Deleguje do StreamProducer
67
+ */
68
+ enqueue(streamName, data) {
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ return this.producer.enqueue(streamName, data);
71
+ });
72
+ }
73
+ /**
74
+ * Dodaje wiele komend w jednym pipeline
75
+ * Deleguje do StreamProducer
76
+ */
77
+ enqueueBatch(entries) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ return this.producer.enqueueBatch(entries);
80
+ });
81
+ }
82
+ /**
83
+ * Rejestruje konsumenta dla strumienia z consumer group
84
+ * Deleguje do StreamConsumer + uruchamia PendingRecovery
85
+ */
86
+ consume(streamName, groupName, handler) {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ yield this.consumer.consume(streamName, groupName, handler);
89
+ // Uruchom recovery loop dla pending wiadomości
90
+ this.recovery.start(streamName, groupName, handler, this.consumer);
91
+ });
92
+ }
93
+ /**
94
+ * RPC: wysyła request do strumienia i czeka na odpowiedź via BRPOP
95
+ * Deleguje do RpcHandler
96
+ */
97
+ rpcCall(commandName, data, timeout) {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ return this.rpc.rpcCall(commandName, data, timeout);
100
+ });
101
+ }
102
+ /**
103
+ * RPC: odpowiada na request przez LPUSH + EXPIRE
104
+ * Deleguje do RpcHandler
105
+ */
106
+ rpcRespond(responseKey, data, ttl) {
107
+ return __awaiter(this, void 0, void 0, function* () {
108
+ return this.rpc.rpcRespond(responseKey, data, ttl);
109
+ });
110
+ }
111
+ /**
112
+ * Zamyka transport gracefully
113
+ *
114
+ * Kolejność:
115
+ * 1. Zatrzymaj consumer.running (przerywa consumer loops)
116
+ * 2. Zatrzymaj recovery intervals
117
+ * 3. Zamknij dedykowane połączenia konsumentów (przerywa XREADGROUP BLOCK)
118
+ * 4. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
119
+ * 5. Zamknij pule połączeń
120
+ */
121
+ close() {
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ if (!this.consumer.running)
124
+ return;
125
+ this.consumer.running = false;
126
+ this.logger.debug('Zamykanie RedisStreamsTransport', {
127
+ consumers: this.consumer.consumerCount,
128
+ timestamp: new Date().toISOString(),
129
+ });
130
+ // 1. Zatrzymaj recovery intervals
131
+ this.recovery.stop();
132
+ // 2. Zamknij dedykowane połączenia konsumentów — przerywa XREADGROUP BLOCK
133
+ this.consumer.closeConnections();
134
+ // 3. Czekaj na zakończenie consumer loops (active tasks kończą processMessage)
135
+ yield this.consumer.awaitLoops();
136
+ // 4. Zamknij pule połączeń — dopiero po zakończeniu wszystkich active tasks
137
+ yield this.pool.close();
138
+ yield this.rpcPool.close();
139
+ });
140
+ }
141
+ }
142
+ exports.default = RedisStreamsTransport;
143
+ //# sourceMappingURL=redis-streams-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-streams-transport.js","sourceRoot":"","sources":["../../../src/command-bus/transport/redis-streams-transport.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,mCAAoC;AAOpC,uDAAmD;AACnD,uDAAmD;AACnD,+CAA2C;AAC3C,yDAAqD;AA4BrD;;;;;;;;;;GAUG;AACH,MAAqB,qBAAqB;IAcxC,YAAY,OAAqC;QAC/C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,YAAY,OAAO,CAAC,GAAG,IAAI,IAAA,mBAAU,GAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAExE,4BAA4B;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,gCAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEjD,IAAI,CAAC,GAAG,GAAG,IAAI,wBAAU,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAE7E,IAAI,CAAC,QAAQ,GAAG,IAAI,gCAAc,CAAC;YACjC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YAC9C,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,GAAG,IAAI,kCAAe,CAAC;YAClC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC,CAAC,CAAC;QAEH,+BAA+B;QAC/B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,0CAA0C,EAAE;YAC1D,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;YAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACU,OAAO,CAAC,UAAkB,EAAE,IAAY;;YACnD,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACjD,CAAC;KAAA;IAED;;;OAGG;IACU,YAAY,CACvB,OAAoD;;YAEpD,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC7C,CAAC;KAAA;IAED;;;OAGG;IACU,OAAO,CAClB,UAAkB,EAClB,SAAiB,EACjB,OAAwB;;YAExB,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YAE5D,+CAA+C;YAC/C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrE,CAAC;KAAA;IAED;;;OAGG;IACU,OAAO,CAAC,WAAmB,EAAE,IAAY,EAAE,OAAe;;YACrE,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACtD,CAAC;KAAA;IAED;;;OAGG;IACU,UAAU,CAAC,WAAmB,EAAE,IAAY,EAAE,GAAW;;YACpE,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACrD,CAAC;KAAA;IAED;;;;;;;;;OASG;IACU,KAAK;;YAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO;gBAAE,OAAO;YACnC,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;YAE9B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE;gBACnD,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa;gBACtC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAC;YAEH,kCAAkC;YAClC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAErB,2EAA2E;YAC3E,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAEjC,+EAA+E;YAC/E,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YAEjC,4EAA4E;YAC5E,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC7B,CAAC;KAAA;CACF;AAxID,wCAwIC"}