@geekmidas/events 0.0.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/{BasicConnection-C4_Y0nIj.d.mts → BasicConnection-BTRsXiuH.d.cts} +3 -2
  2. package/dist/BasicConnection-BTRsXiuH.d.cts.map +1 -0
  3. package/dist/BasicConnection-C-Cg2FJT.cjs.map +1 -1
  4. package/dist/BasicConnection-CpwybcC9.mjs.map +1 -1
  5. package/dist/{BasicConnection-CddnULuT.d.cts → BasicConnection-DIxtA7jK.d.mts} +3 -2
  6. package/dist/BasicConnection-DIxtA7jK.d.mts.map +1 -0
  7. package/dist/BasicPublisher-CXAVKxgq.cjs.map +1 -1
  8. package/dist/{BasicPublisher-DCBxaTwC.d.mts → BasicPublisher-CpJFK2oS.d.mts} +5 -3
  9. package/dist/BasicPublisher-CpJFK2oS.d.mts.map +1 -0
  10. package/dist/{BasicPublisher-V5hELHG9.d.cts → BasicPublisher-D1q0a2xp.d.cts} +5 -3
  11. package/dist/BasicPublisher-D1q0a2xp.d.cts.map +1 -0
  12. package/dist/BasicPublisher-DogbeHAH.mjs.map +1 -1
  13. package/dist/{BasicSubscriber-BB3aKeph.d.mts → BasicSubscriber-6w0Af4DD.d.mts} +5 -3
  14. package/dist/BasicSubscriber-6w0Af4DD.d.mts.map +1 -0
  15. package/dist/{BasicSubscriber-CCKfbRMo.mjs → BasicSubscriber-BJSZN22M.mjs} +2 -4
  16. package/dist/BasicSubscriber-BJSZN22M.mjs.map +1 -0
  17. package/dist/{BasicSubscriber-DOwgFw5j.d.cts → BasicSubscriber-DXxQewjc.d.cts} +5 -3
  18. package/dist/BasicSubscriber-DXxQewjc.d.cts.map +1 -0
  19. package/dist/{BasicSubscriber-BGqv3c8x.cjs → BasicSubscriber-mVJRMXhZ.cjs} +2 -4
  20. package/dist/BasicSubscriber-mVJRMXhZ.cjs.map +1 -0
  21. package/dist/{EventConnection-DZhn1Msl.d.cts → EventConnection-BaJRXdg7.d.cts} +2 -2
  22. package/dist/EventConnection-BaJRXdg7.d.cts.map +1 -0
  23. package/dist/EventConnection-ClLMoIUU.mjs.map +1 -1
  24. package/dist/EventConnection-F_N81SXu.cjs.map +1 -1
  25. package/dist/{EventConnection-DeXfLGom.d.mts → EventConnection-SOhtmxib.d.mts} +2 -2
  26. package/dist/EventConnection-SOhtmxib.d.mts.map +1 -0
  27. package/dist/EventConnection.d.cts +2 -2
  28. package/dist/EventConnection.d.mts +2 -2
  29. package/dist/{Publisher-C3m8JFXm.d.mts → Publisher-1CfcYRnm.d.mts} +4 -2
  30. package/dist/Publisher-1CfcYRnm.d.mts.map +1 -0
  31. package/dist/{Publisher-nXNVjL0e.d.cts → Publisher-BfNgvHwQ.d.cts} +4 -2
  32. package/dist/Publisher-BfNgvHwQ.d.cts.map +1 -0
  33. package/dist/Publisher-DS0aOh8r.mjs.map +1 -1
  34. package/dist/Publisher-ceu6OxCj.cjs.map +1 -1
  35. package/dist/Publisher.d.cts +2 -2
  36. package/dist/Publisher.d.mts +2 -2
  37. package/dist/{RabbitMQConnection-ungB0Zl6.cjs → RabbitMQConnection-Blj9Lo05.cjs} +2 -2
  38. package/dist/RabbitMQConnection-Blj9Lo05.cjs.map +1 -0
  39. package/dist/{RabbitMQConnection-7cWp_-_Q.d.cts → RabbitMQConnection-Bm8VCI2R.d.cts} +3 -2
  40. package/dist/RabbitMQConnection-Bm8VCI2R.d.cts.map +1 -0
  41. package/dist/{RabbitMQConnection-C2HC7J7K.d.mts → RabbitMQConnection-Ck-ktCp_.d.mts} +3 -2
  42. package/dist/RabbitMQConnection-Ck-ktCp_.d.mts.map +1 -0
  43. package/dist/{RabbitMQConnection-kU3MvN5P.mjs → RabbitMQConnection-Co7f5Xsx.mjs} +2 -2
  44. package/dist/RabbitMQConnection-Co7f5Xsx.mjs.map +1 -0
  45. package/dist/RabbitMQPublisher--DL6GM6g.cjs.map +1 -1
  46. package/dist/{RabbitMQPublisher-CpcbgrXj.d.cts → RabbitMQPublisher-COnxcWEZ.d.mts} +5 -3
  47. package/dist/RabbitMQPublisher-COnxcWEZ.d.mts.map +1 -0
  48. package/dist/RabbitMQPublisher-o_oVI3wr.mjs.map +1 -1
  49. package/dist/{RabbitMQPublisher-DDZi15Ro.d.mts → RabbitMQPublisher-qQT7-1-p.d.cts} +5 -3
  50. package/dist/RabbitMQPublisher-qQT7-1-p.d.cts.map +1 -0
  51. package/dist/{RabbitMQSubscriber-BplEJEk8.cjs → RabbitMQSubscriber-C8MYAihn.cjs} +2 -3
  52. package/dist/RabbitMQSubscriber-C8MYAihn.cjs.map +1 -0
  53. package/dist/{RabbitMQSubscriber-BJ9PTGny.d.cts → RabbitMQSubscriber-C_sZjDPU.d.mts} +5 -3
  54. package/dist/RabbitMQSubscriber-C_sZjDPU.d.mts.map +1 -0
  55. package/dist/{RabbitMQSubscriber-CIvIw8MG.d.mts → RabbitMQSubscriber-D12sssMb.d.cts} +5 -3
  56. package/dist/RabbitMQSubscriber-D12sssMb.d.cts.map +1 -0
  57. package/dist/{RabbitMQSubscriber-BaXqs5nO.mjs → RabbitMQSubscriber-DlGL0pC2.mjs} +2 -3
  58. package/dist/RabbitMQSubscriber-DlGL0pC2.mjs.map +1 -0
  59. package/dist/{SNSConnection-CAImaMM2.d.mts → SNSConnection-BDfQrVBO.d.cts} +3 -2
  60. package/dist/SNSConnection-BDfQrVBO.d.cts.map +1 -0
  61. package/dist/SNSConnection-D7wCf9Si.mjs.map +1 -1
  62. package/dist/SNSConnection-DVsC_pbB.cjs.map +1 -1
  63. package/dist/{SNSConnection-Cqbr7-Ho.d.cts → SNSConnection-mHb10nQ6.d.mts} +3 -2
  64. package/dist/SNSConnection-mHb10nQ6.d.mts.map +1 -0
  65. package/dist/{SNSPublisher-BZ6N3JI9.cjs → SNSPublisher-BoA8uLnw.cjs} +2 -3
  66. package/dist/SNSPublisher-BoA8uLnw.cjs.map +1 -0
  67. package/dist/{SNSPublisher-Dkhb4LU-.d.mts → SNSPublisher-CM7UAWtf.d.mts} +7 -6
  68. package/dist/SNSPublisher-CM7UAWtf.d.mts.map +1 -0
  69. package/dist/{SNSPublisher-BfWjzNiB.mjs → SNSPublisher-Drr4kHn6.mjs} +2 -3
  70. package/dist/SNSPublisher-Drr4kHn6.mjs.map +1 -0
  71. package/dist/{SNSPublisher-RVZFa7kL.d.cts → SNSPublisher-kpsSlGDn.d.cts} +7 -6
  72. package/dist/SNSPublisher-kpsSlGDn.d.cts.map +1 -0
  73. package/dist/{SNSSubscriber-C9YJWa7m.mjs → SNSSubscriber-CBIvQpqK.mjs} +4 -8
  74. package/dist/SNSSubscriber-CBIvQpqK.mjs.map +1 -0
  75. package/dist/{SNSSubscriber-UE0ia4XM.cjs → SNSSubscriber-CWiAJjpU.cjs} +4 -8
  76. package/dist/SNSSubscriber-CWiAJjpU.cjs.map +1 -0
  77. package/dist/{SNSSubscriber-B31JmkAE.d.mts → SNSSubscriber-DDB3--pm.d.cts} +4 -3
  78. package/dist/SNSSubscriber-DDB3--pm.d.cts.map +1 -0
  79. package/dist/{SNSSubscriber-k2UwKUxu.d.cts → SNSSubscriber-Dwo8391f.d.mts} +4 -3
  80. package/dist/SNSSubscriber-Dwo8391f.d.mts.map +1 -0
  81. package/dist/{SQSConnection-C5WFqZW7.d.mts → SQSConnection-B5Ep9Tma.d.cts} +3 -2
  82. package/dist/SQSConnection-B5Ep9Tma.d.cts.map +1 -0
  83. package/dist/{SQSConnection-geav2Rsn.d.cts → SQSConnection-BI_xOzyJ.d.mts} +3 -2
  84. package/dist/SQSConnection-BI_xOzyJ.d.mts.map +1 -0
  85. package/dist/SQSConnection-BwNjUPr4.cjs.map +1 -1
  86. package/dist/SQSConnection-Eleqqre3.mjs.map +1 -1
  87. package/dist/{SQSPublisher-CdsayOLV.d.mts → SQSPublisher-BN1ds6SN.d.mts} +5 -3
  88. package/dist/SQSPublisher-BN1ds6SN.d.mts.map +1 -0
  89. package/dist/{SQSPublisher-Utb_FTe5.d.cts → SQSPublisher-DFTqwzRW.d.cts} +5 -3
  90. package/dist/SQSPublisher-DFTqwzRW.d.cts.map +1 -0
  91. package/dist/SQSPublisher-DG9o4ME3.mjs.map +1 -1
  92. package/dist/SQSPublisher-Dq5353oZ.cjs.map +1 -1
  93. package/dist/{SQSSubscriber-DZDNgLE5.cjs → SQSSubscriber-B4sRXVl6.cjs} +5 -12
  94. package/dist/SQSSubscriber-B4sRXVl6.cjs.map +1 -0
  95. package/dist/{SQSSubscriber-B6iL1EnX.d.cts → SQSSubscriber-BO2me_gs.d.cts} +4 -3
  96. package/dist/SQSSubscriber-BO2me_gs.d.cts.map +1 -0
  97. package/dist/{SQSSubscriber-CD66P7hH.mjs → SQSSubscriber-CVGhZ8Nr.mjs} +5 -12
  98. package/dist/SQSSubscriber-CVGhZ8Nr.mjs.map +1 -0
  99. package/dist/{SQSSubscriber-DBeE4XAR.d.mts → SQSSubscriber-FyZFfr2-.d.mts} +4 -3
  100. package/dist/SQSSubscriber-FyZFfr2-.d.mts.map +1 -0
  101. package/dist/Subscriber-Bd9hb_jp.mjs.map +1 -1
  102. package/dist/{Subscriber-Cff9EIpv.d.mts → Subscriber-BxT-KzFJ.d.mts} +4 -2
  103. package/dist/Subscriber-BxT-KzFJ.d.mts.map +1 -0
  104. package/dist/{Subscriber-CpAwcUzb.d.cts → Subscriber-DDD_4Nlx.d.cts} +4 -2
  105. package/dist/Subscriber-DDD_4Nlx.d.cts.map +1 -0
  106. package/dist/Subscriber-saVOWuMq.cjs.map +1 -1
  107. package/dist/Subscriber.d.cts +2 -2
  108. package/dist/Subscriber.d.mts +2 -2
  109. package/dist/basic/BasicConnection.d.cts +2 -2
  110. package/dist/basic/BasicConnection.d.mts +2 -2
  111. package/dist/basic/BasicPublisher.d.cts +3 -3
  112. package/dist/basic/BasicPublisher.d.mts +3 -3
  113. package/dist/basic/BasicSubscriber.cjs +1 -1
  114. package/dist/basic/BasicSubscriber.d.cts +3 -3
  115. package/dist/basic/BasicSubscriber.d.mts +3 -3
  116. package/dist/basic/BasicSubscriber.mjs +1 -1
  117. package/dist/basic/index.cjs +1 -1
  118. package/dist/basic/index.d.cts +4 -4
  119. package/dist/basic/index.d.mts +4 -4
  120. package/dist/basic/index.mjs +1 -1
  121. package/dist/index.d.cts +4 -4
  122. package/dist/index.d.mts +4 -4
  123. package/dist/rabbitmq/RabbitMQConnection.cjs +1 -1
  124. package/dist/rabbitmq/RabbitMQConnection.d.cts +2 -2
  125. package/dist/rabbitmq/RabbitMQConnection.d.mts +2 -2
  126. package/dist/rabbitmq/RabbitMQConnection.mjs +1 -1
  127. package/dist/rabbitmq/RabbitMQPublisher.d.cts +3 -3
  128. package/dist/rabbitmq/RabbitMQPublisher.d.mts +3 -3
  129. package/dist/rabbitmq/RabbitMQSubscriber.cjs +1 -1
  130. package/dist/rabbitmq/RabbitMQSubscriber.d.cts +3 -3
  131. package/dist/rabbitmq/RabbitMQSubscriber.d.mts +3 -3
  132. package/dist/rabbitmq/RabbitMQSubscriber.mjs +1 -1
  133. package/dist/rabbitmq/index.cjs +2 -2
  134. package/dist/rabbitmq/index.d.cts +4 -4
  135. package/dist/rabbitmq/index.d.mts +4 -4
  136. package/dist/rabbitmq/index.mjs +2 -2
  137. package/dist/sns/SNSConnection.d.cts +2 -2
  138. package/dist/sns/SNSConnection.d.mts +2 -2
  139. package/dist/sns/SNSPublisher.cjs +1 -1
  140. package/dist/sns/SNSPublisher.d.cts +3 -3
  141. package/dist/sns/SNSPublisher.d.mts +3 -3
  142. package/dist/sns/SNSPublisher.mjs +1 -1
  143. package/dist/sns/SNSSubscriber.cjs +2 -2
  144. package/dist/sns/SNSSubscriber.d.cts +3 -3
  145. package/dist/sns/SNSSubscriber.d.mts +3 -3
  146. package/dist/sns/SNSSubscriber.mjs +2 -2
  147. package/dist/sns/index.cjs +3 -3
  148. package/dist/sns/index.d.cts +4 -4
  149. package/dist/sns/index.d.mts +4 -4
  150. package/dist/sns/index.mjs +3 -3
  151. package/dist/sqs/SQSConnection.d.cts +2 -2
  152. package/dist/sqs/SQSConnection.d.mts +2 -2
  153. package/dist/sqs/SQSPublisher.d.cts +3 -3
  154. package/dist/sqs/SQSPublisher.d.mts +3 -3
  155. package/dist/sqs/SQSSubscriber.cjs +1 -1
  156. package/dist/sqs/SQSSubscriber.d.cts +3 -3
  157. package/dist/sqs/SQSSubscriber.d.mts +3 -3
  158. package/dist/sqs/SQSSubscriber.mjs +1 -1
  159. package/dist/sqs/index.cjs +1 -1
  160. package/dist/sqs/index.d.cts +4 -4
  161. package/dist/sqs/index.d.mts +4 -4
  162. package/dist/sqs/index.mjs +1 -1
  163. package/dist/types-B63qHVOG.mjs.map +1 -1
  164. package/dist/types-CvSMEO5z.cjs.map +1 -1
  165. package/dist/{types-D0g-o6wX.d.mts → types-DSVsPgKd.d.mts} +2 -1
  166. package/dist/types-DSVsPgKd.d.mts.map +1 -0
  167. package/dist/{types-DEGUg5BA.d.cts → types-Dmbp1U-6.d.cts} +2 -1
  168. package/dist/types-Dmbp1U-6.d.cts.map +1 -0
  169. package/dist/types.d.cts +1 -1
  170. package/dist/types.d.mts +1 -1
  171. package/package.json +24 -5
  172. package/src/EventConnection.ts +31 -31
  173. package/src/Publisher.ts +78 -78
  174. package/src/Subscriber.ts +91 -91
  175. package/src/__tests__/EventConnection.spec.ts +42 -0
  176. package/src/__tests__/Publisher.spec.ts +96 -0
  177. package/src/__tests__/Subscriber.spec.ts +91 -23
  178. package/src/basic/BasicConnection.ts +35 -35
  179. package/src/basic/BasicPublisher.ts +8 -8
  180. package/src/basic/BasicSubscriber.ts +13 -16
  181. package/src/basic/__tests__/BasicSubscriber.spec.ts +116 -116
  182. package/src/index.ts +13 -13
  183. package/src/rabbitmq/RabbitMQConnection.ts +139 -139
  184. package/src/rabbitmq/RabbitMQPublisher.ts +48 -48
  185. package/src/rabbitmq/RabbitMQSubscriber.ts +100 -102
  186. package/src/rabbitmq/__tests__/RabbitMQPublisher.spec.ts +364 -364
  187. package/src/rabbitmq/__tests__/RabbitMQSubscriber.spec.ts +204 -204
  188. package/src/rabbitmq/index.ts +3 -3
  189. package/src/sns/SNSConnection.ts +76 -76
  190. package/src/sns/SNSPublisher.ts +54 -56
  191. package/src/sns/SNSSubscriber.ts +187 -191
  192. package/src/sns/__tests__/SNS-SQS-Integration.spec.ts +321 -321
  193. package/src/sns/__tests__/SNSPublisher.spec.ts +449 -0
  194. package/src/sns/__tests__/SNSSubscriber.spec.ts +527 -0
  195. package/src/sns/index.ts +3 -3
  196. package/src/sqs/SQSConnection.ts +75 -75
  197. package/src/sqs/SQSPublisher.ts +93 -93
  198. package/src/sqs/SQSSubscriber.ts +157 -165
  199. package/src/sqs/__tests__/SQSPublisher.spec.ts +178 -178
  200. package/src/sqs/index.ts +3 -3
  201. package/src/types.ts +28 -29
  202. package/tsconfig.json +9 -0
  203. package/tsdown.config.ts +1 -1
  204. package/dist/BasicSubscriber-BGqv3c8x.cjs.map +0 -1
  205. package/dist/BasicSubscriber-CCKfbRMo.mjs.map +0 -1
  206. package/dist/RabbitMQConnection-kU3MvN5P.mjs.map +0 -1
  207. package/dist/RabbitMQConnection-ungB0Zl6.cjs.map +0 -1
  208. package/dist/RabbitMQSubscriber-BaXqs5nO.mjs.map +0 -1
  209. package/dist/RabbitMQSubscriber-BplEJEk8.cjs.map +0 -1
  210. package/dist/SNSPublisher-BZ6N3JI9.cjs.map +0 -1
  211. package/dist/SNSPublisher-BfWjzNiB.mjs.map +0 -1
  212. package/dist/SNSSubscriber-C9YJWa7m.mjs.map +0 -1
  213. package/dist/SNSSubscriber-UE0ia4XM.cjs.map +0 -1
  214. package/dist/SQSSubscriber-CD66P7hH.mjs.map +0 -1
  215. package/dist/SQSSubscriber-DZDNgLE5.cjs.map +0 -1
@@ -6,184 +6,184 @@ import { SQSPublisher } from '../SQSPublisher';
6
6
  type TestMessage = PublishableMessage<'user.created' | 'user.updated', any>;
7
7
 
8
8
  const TEST_QUEUE_URL =
9
- 'https://sqs.us-east-1.amazonaws.com/123456789012/test-queue';
9
+ 'https://sqs.us-east-1.amazonaws.com/123456789012/test-queue';
10
10
 
11
11
  describe('SQSPublisher', () => {
12
- describe('constructor', () => {
13
- it('should create instance with queue URL', () => {
14
- const connection = new SQSConnection({
15
- queueUrl: TEST_QUEUE_URL,
16
- });
17
- const publisher = new SQSPublisher<TestMessage>(connection);
18
-
19
- expect(publisher).toBeDefined();
20
- });
21
-
22
- it('should create instance with region', () => {
23
- const connection = new SQSConnection({
24
- queueUrl: TEST_QUEUE_URL,
25
- region: 'us-east-1',
26
- });
27
- const publisher = new SQSPublisher<TestMessage>(connection);
28
-
29
- expect(publisher).toBeDefined();
30
- });
31
-
32
- it('should create instance with credentials', () => {
33
- const connection = new SQSConnection({
34
- queueUrl: TEST_QUEUE_URL,
35
- region: 'us-east-1',
36
- credentials: {
37
- accessKeyId: 'test-key',
38
- secretAccessKey: 'test-secret',
39
- },
40
- });
41
- const publisher = new SQSPublisher<TestMessage>(connection);
42
-
43
- expect(publisher).toBeDefined();
44
- });
45
-
46
- it('should create instance with custom batch size', () => {
47
- const connection = new SQSConnection({
48
- queueUrl: TEST_QUEUE_URL,
49
- });
50
- const publisher = new SQSPublisher<TestMessage>(connection, {
51
- maxBatchSize: 5,
52
- });
53
-
54
- expect(publisher).toBeDefined();
55
- });
56
-
57
- it('should create instance with custom endpoint', () => {
58
- const connection = new SQSConnection({
59
- queueUrl: TEST_QUEUE_URL,
60
- endpoint: 'http://localhost:4566',
61
- });
62
- const publisher = new SQSPublisher<TestMessage>(connection);
63
-
64
- expect(publisher).toBeDefined();
65
- });
66
-
67
- it('should default maxBatchSize to 10', () => {
68
- const connection = new SQSConnection({
69
- queueUrl: TEST_QUEUE_URL,
70
- });
71
- const publisher = new SQSPublisher<TestMessage>(connection);
72
-
73
- // Access private options through any to test default
74
- expect(publisher.options.maxBatchSize).toBe(10);
75
- });
76
- });
77
-
78
- describe('fromConnectionString', () => {
79
- it('should parse basic connection string', async () => {
80
- const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
81
- `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}`,
82
- );
83
-
84
- expect(publisher).toBeDefined();
85
- });
86
-
87
- it('should parse connection string with region', async () => {
88
- const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
89
- `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&region=us-west-2`,
90
- );
91
-
92
- expect(publisher).toBeDefined();
93
- expect(publisher.connection.config.region).toBe('us-west-2');
94
- });
95
-
96
- it('should parse connection string with credentials', async () => {
97
- const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
98
- `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&accessKeyId=test-key&secretAccessKey=test-secret`,
99
- );
100
-
101
- expect(publisher).toBeDefined();
102
- expect(publisher.connection.config.credentials).toEqual({
103
- accessKeyId: 'test-key',
104
- secretAccessKey: 'test-secret',
105
- sessionToken: undefined,
106
- });
107
- });
108
-
109
- it('should parse connection string with session token', async () => {
110
- const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
111
- `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&accessKeyId=test-key&secretAccessKey=test-secret&sessionToken=test-token`,
112
- );
113
-
114
- expect(publisher).toBeDefined();
115
- expect(publisher.connection.config.credentials).toEqual({
116
- accessKeyId: 'test-key',
117
- secretAccessKey: 'test-secret',
118
- sessionToken: 'test-token',
119
- });
120
- });
121
-
122
- it('should parse connection string with maxBatchSize', async () => {
123
- const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
124
- `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&maxBatchSize=5`,
125
- );
126
-
127
- expect(publisher).toBeDefined();
128
- expect(publisher.options.maxBatchSize).toBe(5);
129
- });
130
-
131
- it('should parse connection string with endpoint', async () => {
132
- const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
133
- `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&endpoint=${encodeURIComponent('http://localhost:4566')}`,
134
- );
135
-
136
- expect(publisher).toBeDefined();
137
- expect(publisher.connection.config.endpoint).toBe(
138
- 'http://localhost:4566',
139
- );
140
- });
141
-
142
- it('should parse connection string with all parameters', async () => {
143
- const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
144
- `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&region=us-west-2&endpoint=${encodeURIComponent('http://localhost:4566')}&maxBatchSize=5&accessKeyId=test&secretAccessKey=secret`,
145
- );
146
-
147
- expect(publisher).toBeDefined();
148
- expect(publisher.connection.config.region).toBe('us-west-2');
149
- expect(publisher.connection.config.endpoint).toBe(
150
- 'http://localhost:4566',
151
- );
152
- expect(publisher.options.maxBatchSize).toBe(5);
153
- expect(publisher.connection.config.credentials).toEqual({
154
- accessKeyId: 'test',
155
- secretAccessKey: 'secret',
156
- sessionToken: undefined,
157
- });
158
- });
159
-
160
- it('should throw error if queueUrl is missing', async () => {
161
- await expect(
162
- SQSPublisher.fromConnectionString<TestMessage>(
163
- 'sqs://?region=us-east-1',
164
- ),
165
- ).rejects.toThrow('queueUrl parameter is required');
166
- });
167
- });
168
-
169
- describe('close', () => {
170
- it('should close without error', async () => {
171
- const connection = new SQSConnection({
172
- queueUrl: TEST_QUEUE_URL,
173
- });
174
- const publisher = new SQSPublisher<TestMessage>(connection);
175
-
176
- await expect(publisher.close()).resolves.toBeUndefined();
177
- });
178
-
179
- it('should allow multiple close calls', async () => {
180
- const connection = new SQSConnection({
181
- queueUrl: TEST_QUEUE_URL,
182
- });
183
- const publisher = new SQSPublisher<TestMessage>(connection);
184
-
185
- await publisher.close();
186
- await expect(publisher.close()).resolves.toBeUndefined();
187
- });
188
- });
12
+ describe('constructor', () => {
13
+ it('should create instance with queue URL', () => {
14
+ const connection = new SQSConnection({
15
+ queueUrl: TEST_QUEUE_URL,
16
+ });
17
+ const publisher = new SQSPublisher<TestMessage>(connection);
18
+
19
+ expect(publisher).toBeDefined();
20
+ });
21
+
22
+ it('should create instance with region', () => {
23
+ const connection = new SQSConnection({
24
+ queueUrl: TEST_QUEUE_URL,
25
+ region: 'us-east-1',
26
+ });
27
+ const publisher = new SQSPublisher<TestMessage>(connection);
28
+
29
+ expect(publisher).toBeDefined();
30
+ });
31
+
32
+ it('should create instance with credentials', () => {
33
+ const connection = new SQSConnection({
34
+ queueUrl: TEST_QUEUE_URL,
35
+ region: 'us-east-1',
36
+ credentials: {
37
+ accessKeyId: 'test-key',
38
+ secretAccessKey: 'test-secret',
39
+ },
40
+ });
41
+ const publisher = new SQSPublisher<TestMessage>(connection);
42
+
43
+ expect(publisher).toBeDefined();
44
+ });
45
+
46
+ it('should create instance with custom batch size', () => {
47
+ const connection = new SQSConnection({
48
+ queueUrl: TEST_QUEUE_URL,
49
+ });
50
+ const publisher = new SQSPublisher<TestMessage>(connection, {
51
+ maxBatchSize: 5,
52
+ });
53
+
54
+ expect(publisher).toBeDefined();
55
+ });
56
+
57
+ it('should create instance with custom endpoint', () => {
58
+ const connection = new SQSConnection({
59
+ queueUrl: TEST_QUEUE_URL,
60
+ endpoint: 'http://localhost:4566',
61
+ });
62
+ const publisher = new SQSPublisher<TestMessage>(connection);
63
+
64
+ expect(publisher).toBeDefined();
65
+ });
66
+
67
+ it('should default maxBatchSize to 10', () => {
68
+ const connection = new SQSConnection({
69
+ queueUrl: TEST_QUEUE_URL,
70
+ });
71
+ const publisher = new SQSPublisher<TestMessage>(connection);
72
+
73
+ // Access private options through any to test default
74
+ expect(publisher.options.maxBatchSize).toBe(10);
75
+ });
76
+ });
77
+
78
+ describe('fromConnectionString', () => {
79
+ it('should parse basic connection string', async () => {
80
+ const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
81
+ `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}`,
82
+ );
83
+
84
+ expect(publisher).toBeDefined();
85
+ });
86
+
87
+ it('should parse connection string with region', async () => {
88
+ const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
89
+ `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&region=us-west-2`,
90
+ );
91
+
92
+ expect(publisher).toBeDefined();
93
+ expect(publisher.connection.config.region).toBe('us-west-2');
94
+ });
95
+
96
+ it('should parse connection string with credentials', async () => {
97
+ const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
98
+ `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&accessKeyId=test-key&secretAccessKey=test-secret`,
99
+ );
100
+
101
+ expect(publisher).toBeDefined();
102
+ expect(publisher.connection.config.credentials).toEqual({
103
+ accessKeyId: 'test-key',
104
+ secretAccessKey: 'test-secret',
105
+ sessionToken: undefined,
106
+ });
107
+ });
108
+
109
+ it('should parse connection string with session token', async () => {
110
+ const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
111
+ `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&accessKeyId=test-key&secretAccessKey=test-secret&sessionToken=test-token`,
112
+ );
113
+
114
+ expect(publisher).toBeDefined();
115
+ expect(publisher.connection.config.credentials).toEqual({
116
+ accessKeyId: 'test-key',
117
+ secretAccessKey: 'test-secret',
118
+ sessionToken: 'test-token',
119
+ });
120
+ });
121
+
122
+ it('should parse connection string with maxBatchSize', async () => {
123
+ const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
124
+ `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&maxBatchSize=5`,
125
+ );
126
+
127
+ expect(publisher).toBeDefined();
128
+ expect(publisher.options.maxBatchSize).toBe(5);
129
+ });
130
+
131
+ it('should parse connection string with endpoint', async () => {
132
+ const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
133
+ `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&endpoint=${encodeURIComponent('http://localhost:4566')}`,
134
+ );
135
+
136
+ expect(publisher).toBeDefined();
137
+ expect(publisher.connection.config.endpoint).toBe(
138
+ 'http://localhost:4566',
139
+ );
140
+ });
141
+
142
+ it('should parse connection string with all parameters', async () => {
143
+ const publisher = await SQSPublisher.fromConnectionString<TestMessage>(
144
+ `sqs://?queueUrl=${encodeURIComponent(TEST_QUEUE_URL)}&region=us-west-2&endpoint=${encodeURIComponent('http://localhost:4566')}&maxBatchSize=5&accessKeyId=test&secretAccessKey=secret`,
145
+ );
146
+
147
+ expect(publisher).toBeDefined();
148
+ expect(publisher.connection.config.region).toBe('us-west-2');
149
+ expect(publisher.connection.config.endpoint).toBe(
150
+ 'http://localhost:4566',
151
+ );
152
+ expect(publisher.options.maxBatchSize).toBe(5);
153
+ expect(publisher.connection.config.credentials).toEqual({
154
+ accessKeyId: 'test',
155
+ secretAccessKey: 'secret',
156
+ sessionToken: undefined,
157
+ });
158
+ });
159
+
160
+ it('should throw error if queueUrl is missing', async () => {
161
+ await expect(
162
+ SQSPublisher.fromConnectionString<TestMessage>(
163
+ 'sqs://?region=us-east-1',
164
+ ),
165
+ ).rejects.toThrow('queueUrl parameter is required');
166
+ });
167
+ });
168
+
169
+ describe('close', () => {
170
+ it('should close without error', async () => {
171
+ const connection = new SQSConnection({
172
+ queueUrl: TEST_QUEUE_URL,
173
+ });
174
+ const publisher = new SQSPublisher<TestMessage>(connection);
175
+
176
+ await expect(publisher.close()).resolves.toBeUndefined();
177
+ });
178
+
179
+ it('should allow multiple close calls', async () => {
180
+ const connection = new SQSConnection({
181
+ queueUrl: TEST_QUEUE_URL,
182
+ });
183
+ const publisher = new SQSPublisher<TestMessage>(connection);
184
+
185
+ await publisher.close();
186
+ await expect(publisher.close()).resolves.toBeUndefined();
187
+ });
188
+ });
189
189
  });
package/src/sqs/index.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { SQSConnection } from './SQSConnection';
2
1
  export type { SQSConnectionConfig } from './SQSConnection';
3
- export { SQSPublisher } from './SQSPublisher';
2
+ export { SQSConnection } from './SQSConnection';
4
3
  export type { SQSPublisherOptions } from './SQSPublisher';
5
- export { SQSSubscriber } from './SQSSubscriber';
4
+ export { SQSPublisher } from './SQSPublisher';
6
5
  export type { SQSSubscriberOptions } from './SQSSubscriber';
6
+ export { SQSSubscriber } from './SQSSubscriber';
package/src/types.ts CHANGED
@@ -8,20 +8,20 @@ import type { StandardSchemaV1 } from '@standard-schema/spec';
8
8
  * @template TPayload - The event payload data
9
9
  */
10
10
  export type PublishableMessage<TType extends string, TPayload> = {
11
- type: TType;
12
- payload: TPayload;
11
+ type: TType;
12
+ payload: TPayload;
13
13
  };
14
14
 
15
15
  /**
16
16
  * Event publisher/subscriber types
17
17
  */
18
18
  export enum EventPublisherType {
19
- Basic = 'basic',
20
- EventBridge = 'eventbridge',
21
- SQS = 'sqs',
22
- SNS = 'sns',
23
- Kafka = 'kafka',
24
- RabbitMQ = 'rabbitmq',
19
+ Basic = 'basic',
20
+ EventBridge = 'eventbridge',
21
+ SQS = 'sqs',
22
+ SNS = 'sns',
23
+ Kafka = 'kafka',
24
+ RabbitMQ = 'rabbitmq',
25
25
  }
26
26
 
27
27
  /**
@@ -29,10 +29,10 @@ export enum EventPublisherType {
29
29
  * Connections manage the underlying transport (RabbitMQ channel, SQS client, etc.)
30
30
  */
31
31
  export interface EventConnection {
32
- readonly type: EventPublisherType;
33
- connect(): Promise<void>;
34
- close(): Promise<void>;
35
- isConnected(): boolean;
32
+ readonly type: EventPublisherType;
33
+ connect(): Promise<void>;
34
+ close(): Promise<void>;
35
+ isConnected(): boolean;
36
36
  }
37
37
 
38
38
  /**
@@ -42,7 +42,7 @@ export interface EventConnection {
42
42
  * @template TMessage - The union type of all publishable messages
43
43
  */
44
44
  export type EventPublisher<TMessage extends PublishableMessage<string, any>> = {
45
- publish: (message: TMessage[]) => Promise<void>;
45
+ publish: (message: TMessage[]) => Promise<void>;
46
46
  };
47
47
 
48
48
  /**
@@ -51,26 +51,25 @@ export type EventPublisher<TMessage extends PublishableMessage<string, any>> = {
51
51
  * @template TMessage - The union type of all publishable messages
52
52
  */
53
53
  export type EventSubscriber<TMessage extends PublishableMessage<string, any>> =
54
- {
55
- subscribe: (
56
- messages: TMessage['type'][],
57
- listener: (payload: TMessage) => Promise<void>,
58
- ) => Promise<void>;
59
- };
54
+ {
55
+ subscribe: (
56
+ messages: TMessage['type'][],
57
+ listener: (payload: TMessage) => Promise<void>,
58
+ ) => Promise<void>;
59
+ };
60
60
  /**
61
61
  * Utility type to extract the message from EventPublisher
62
62
  */
63
- export type ExtractPublisherMessage<T> = T extends EventPublisher<infer M>
64
- ? M
65
- : never;
63
+ export type ExtractPublisherMessage<T> =
64
+ T extends EventPublisher<infer M> ? M : never;
66
65
 
67
66
  export type MappedEvent<
68
- T extends EventPublisher<any> | undefined,
69
- OutSchema extends StandardSchemaV1 | undefined = undefined,
67
+ T extends EventPublisher<any> | undefined,
68
+ OutSchema extends StandardSchemaV1 | undefined = undefined,
70
69
  > = {
71
- type: ExtractPublisherMessage<T>['type'];
72
- payload: (
73
- ctx: InferStandardSchema<OutSchema>,
74
- ) => ExtractPublisherMessage<T>['payload'];
75
- when?: (ctx: InferStandardSchema<OutSchema>) => boolean;
70
+ type: ExtractPublisherMessage<T>['type'];
71
+ payload: (
72
+ ctx: InferStandardSchema<OutSchema>,
73
+ ) => ExtractPublisherMessage<T>['payload'];
74
+ when?: (ctx: InferStandardSchema<OutSchema>) => boolean;
76
75
  };
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "composite": true
7
+ },
8
+ "include": ["src/**/*"]
9
+ }
package/tsdown.config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defineConfig } from 'tsdown';
2
2
 
3
3
  export default defineConfig({
4
- external: ['amqplib', '@aws-sdk/client-sqs', '@aws-sdk/client-sns'],
4
+ external: ['amqplib', '@aws-sdk/client-sqs', '@aws-sdk/client-sns'],
5
5
  });
@@ -1 +0,0 @@
1
- {"version":3,"file":"BasicSubscriber-BGqv3c8x.cjs","names":["connection: BasicConnection","messages: TMessage['type'][]","listener: (payload: TMessage) => Promise<void>","message: TMessage"],"sources":["../src/basic/BasicSubscriber.ts"],"sourcesContent":["import type { EventSubscriber, PublishableMessage } from '../types';\nimport type { BasicConnection } from './BasicConnection';\n\nexport class BasicSubscriber<TMessage extends PublishableMessage<string, any>>\n implements EventSubscriber<TMessage>\n{\n constructor(private connection: BasicConnection) {}\n\n async subscribe(\n messages: TMessage['type'][],\n listener: (payload: TMessage) => Promise<void>,\n ): Promise<void> {\n const emitter = this.connection.eventEmitter;\n\n for (const messageType of messages) {\n emitter.on(messageType, (message: TMessage) => {\n listener(message).catch((error) => {\n // Log error but don't throw to prevent unhandled promise rejections\n console.error(`Error processing message ${messageType}:`, error);\n });\n });\n }\n }\n}\n"],"mappings":";;AAGA,IAAa,kBAAb,MAEA;CACE,YAAoBA,YAA6B;EAA7B;CAA+B;CAEnD,MAAM,UACJC,UACAC,UACe;EACf,MAAM,UAAU,KAAK,WAAW;AAEhC,OAAK,MAAM,eAAe,SACxB,SAAQ,GAAG,aAAa,CAACC,YAAsB;AAC7C,YAAS,QAAQ,CAAC,MAAM,CAAC,UAAU;AAEjC,YAAQ,OAAO,2BAA2B,YAAY,IAAI,MAAM;GACjE,EAAC;EACH,EAAC;CAEL;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"BasicSubscriber-CCKfbRMo.mjs","names":["connection: BasicConnection","messages: TMessage['type'][]","listener: (payload: TMessage) => Promise<void>","message: TMessage"],"sources":["../src/basic/BasicSubscriber.ts"],"sourcesContent":["import type { EventSubscriber, PublishableMessage } from '../types';\nimport type { BasicConnection } from './BasicConnection';\n\nexport class BasicSubscriber<TMessage extends PublishableMessage<string, any>>\n implements EventSubscriber<TMessage>\n{\n constructor(private connection: BasicConnection) {}\n\n async subscribe(\n messages: TMessage['type'][],\n listener: (payload: TMessage) => Promise<void>,\n ): Promise<void> {\n const emitter = this.connection.eventEmitter;\n\n for (const messageType of messages) {\n emitter.on(messageType, (message: TMessage) => {\n listener(message).catch((error) => {\n // Log error but don't throw to prevent unhandled promise rejections\n console.error(`Error processing message ${messageType}:`, error);\n });\n });\n }\n }\n}\n"],"mappings":";AAGA,IAAa,kBAAb,MAEA;CACE,YAAoBA,YAA6B;EAA7B;CAA+B;CAEnD,MAAM,UACJC,UACAC,UACe;EACf,MAAM,UAAU,KAAK,WAAW;AAEhC,OAAK,MAAM,eAAe,SACxB,SAAQ,GAAG,aAAa,CAACC,YAAsB;AAC7C,YAAS,QAAQ,CAAC,MAAM,CAAC,UAAU;AAEjC,YAAQ,OAAO,2BAA2B,YAAY,IAAI,MAAM;GACjE,EAAC;EACH,EAAC;CAEL;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"RabbitMQConnection-kU3MvN5P.mjs","names":["config: RabbitMQConnectionConfig","connectionString: string","_err: Error"],"sources":["../src/rabbitmq/RabbitMQConnection.ts"],"sourcesContent":["import amqplib from 'amqplib';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface RabbitMQConnectionConfig {\n url: string;\n exchange?: string;\n exchangeType?: 'topic' | 'direct' | 'fanout' | 'headers';\n exchangeOptions?: amqplib.Options.AssertExchange;\n timeout?: number; // Connection timeout in milliseconds (default: 5000)\n}\n\nexport class RabbitMQConnection implements EventConnection {\n readonly type = EventPublisherType.RabbitMQ;\n private connection?: amqplib.ChannelModel;\n private channel?: amqplib.Channel;\n private connecting?: Promise<void>;\n private config: Required<\n Pick<RabbitMQConnectionConfig, 'exchange' | 'exchangeType' | 'timeout'>\n > &\n RabbitMQConnectionConfig;\n\n constructor(config: RabbitMQConnectionConfig) {\n this.config = {\n ...config,\n exchange: config.exchange || 'geekmidas.events',\n exchangeType: config.exchangeType || 'topic',\n timeout: config.timeout ?? 5000,\n exchangeOptions: {\n durable: true,\n ...config.exchangeOptions,\n },\n };\n }\n\n /**\n * Create a RabbitMQConnection from a connection string\n * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n */\n static async fromConnectionString(\n connectionString: string,\n ): Promise<RabbitMQConnection> {\n const url = new URL(connectionString);\n const params = url.searchParams;\n\n // Extract connection URL without query params\n const baseUrl = `amqp://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n const timeoutParam = params.get('timeout');\n const config: RabbitMQConnectionConfig = {\n url: baseUrl,\n exchange: params.get('exchange') || 'geekmidas.events',\n exchangeType: (params.get('type') as any) || 'topic',\n timeout: timeoutParam ? Number.parseInt(timeoutParam, 10) : undefined,\n };\n\n const connection = new RabbitMQConnection(config);\n await connection.connect();\n return connection;\n }\n\n async connect(): Promise<void> {\n if (this.channel) return;\n\n // Prevent multiple simultaneous connection attempts\n if (this.connecting) {\n await this.connecting;\n return;\n }\n\n this.connecting = (async () => {\n try {\n const connection = await amqplib.connect(this.config.url, {\n timeout: this.config.timeout,\n });\n const channel = await connection.createChannel();\n\n // Assert the exchange exists\n await channel.assertExchange(\n this.config.exchange!,\n this.config.exchangeType!,\n this.config.exchangeOptions,\n );\n\n // Handle connection errors\n connection.on('error', (_err: Error) => {\n this.cleanup();\n });\n\n connection.on('close', () => {\n this.cleanup();\n });\n\n // Only set after successful setup\n this.connection = connection;\n this.channel = channel;\n } catch (error) {\n this.cleanup();\n throw error;\n }\n })();\n\n await this.connecting;\n this.connecting = undefined;\n }\n\n async close(): Promise<void> {\n try {\n await this.channel?.close();\n await this.connection?.close();\n } catch (error) {\n // Ignore errors during close\n } finally {\n this.cleanup();\n }\n }\n\n isConnected(): boolean {\n return !!this.channel;\n }\n\n private cleanup(): void {\n this.channel = undefined;\n this.connection = undefined;\n this.connecting = undefined;\n }\n\n /**\n * Get the underlying channel for publishing/subscribing\n */\n get amqpChannel(): amqplib.Channel | undefined {\n return this.channel;\n }\n\n /**\n * Get the exchange name for this connection\n */\n get exchangeName(): string {\n return this.config.exchange;\n }\n\n /**\n * Get the exchange type for this connection\n */\n get exchangeType(): string {\n return this.config.exchangeType;\n }\n}\n"],"mappings":";;;;AAYA,IAAa,qBAAb,MAAa,mBAA8C;CACzD,AAAS,OAAO,mBAAmB;CACnC,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAKR,YAAYA,QAAkC;AAC5C,OAAK,SAAS;GACZ,GAAG;GACH,UAAU,OAAO,YAAY;GAC7B,cAAc,OAAO,gBAAgB;GACrC,SAAS,OAAO,WAAW;GAC3B,iBAAiB;IACf,SAAS;IACT,GAAG,OAAO;GACX;EACF;CACF;;;;;CAMD,aAAa,qBACXC,kBAC6B;EAC7B,MAAM,MAAM,IAAI,IAAI;EACpB,MAAM,SAAS,IAAI;EAGnB,MAAM,WAAW,SAAS,IAAI,YAAY,EAAE,IAAI,SAAS,GAAG,IAAI,SAAS,KAAK,GAAG,EAAE,IAAI,KAAK,EAAE,IAAI,SAAS;EAE3G,MAAM,eAAe,OAAO,IAAI,UAAU;EAC1C,MAAMD,SAAmC;GACvC,KAAK;GACL,UAAU,OAAO,IAAI,WAAW,IAAI;GACpC,cAAe,OAAO,IAAI,OAAO,IAAY;GAC7C,SAAS,eAAe,OAAO,SAAS,cAAc,GAAG;EAC1D;EAED,MAAM,aAAa,IAAI,mBAAmB;AAC1C,QAAM,WAAW,SAAS;AAC1B,SAAO;CACR;CAED,MAAM,UAAyB;AAC7B,MAAI,KAAK,QAAS;AAGlB,MAAI,KAAK,YAAY;AACnB,SAAM,KAAK;AACX;EACD;AAED,OAAK,aAAa,CAAC,YAAY;AAC7B,OAAI;IACF,MAAM,aAAa,MAAM,QAAQ,QAAQ,KAAK,OAAO,KAAK,EACxD,SAAS,KAAK,OAAO,QACtB,EAAC;IACF,MAAM,UAAU,MAAM,WAAW,eAAe;AAGhD,UAAM,QAAQ,eACZ,KAAK,OAAO,UACZ,KAAK,OAAO,cACZ,KAAK,OAAO,gBACb;AAGD,eAAW,GAAG,SAAS,CAACE,SAAgB;AACtC,UAAK,SAAS;IACf,EAAC;AAEF,eAAW,GAAG,SAAS,MAAM;AAC3B,UAAK,SAAS;IACf,EAAC;AAGF,SAAK,aAAa;AAClB,SAAK,UAAU;GAChB,SAAQ,OAAO;AACd,SAAK,SAAS;AACd,UAAM;GACP;EACF,IAAG;AAEJ,QAAM,KAAK;AACX,OAAK;CACN;CAED,MAAM,QAAuB;AAC3B,MAAI;AACF,SAAM,KAAK,SAAS,OAAO;AAC3B,SAAM,KAAK,YAAY,OAAO;EAC/B,SAAQ,OAAO,CAEf,UAAS;AACR,QAAK,SAAS;EACf;CACF;CAED,cAAuB;AACrB,WAAS,KAAK;CACf;CAED,AAAQ,UAAgB;AACtB,OAAK;AACL,OAAK;AACL,OAAK;CACN;;;;CAKD,IAAI,cAA2C;AAC7C,SAAO,KAAK;CACb;;;;CAKD,IAAI,eAAuB;AACzB,SAAO,KAAK,OAAO;CACpB;;;;CAKD,IAAI,eAAuB;AACzB,SAAO,KAAK,OAAO;CACpB;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"RabbitMQConnection-ungB0Zl6.cjs","names":["EventPublisherType","config: RabbitMQConnectionConfig","connectionString: string","_err: Error"],"sources":["../src/rabbitmq/RabbitMQConnection.ts"],"sourcesContent":["import amqplib from 'amqplib';\nimport type { EventConnection } from '../types';\nimport { EventPublisherType } from '../types';\n\nexport interface RabbitMQConnectionConfig {\n url: string;\n exchange?: string;\n exchangeType?: 'topic' | 'direct' | 'fanout' | 'headers';\n exchangeOptions?: amqplib.Options.AssertExchange;\n timeout?: number; // Connection timeout in milliseconds (default: 5000)\n}\n\nexport class RabbitMQConnection implements EventConnection {\n readonly type = EventPublisherType.RabbitMQ;\n private connection?: amqplib.ChannelModel;\n private channel?: amqplib.Channel;\n private connecting?: Promise<void>;\n private config: Required<\n Pick<RabbitMQConnectionConfig, 'exchange' | 'exchangeType' | 'timeout'>\n > &\n RabbitMQConnectionConfig;\n\n constructor(config: RabbitMQConnectionConfig) {\n this.config = {\n ...config,\n exchange: config.exchange || 'geekmidas.events',\n exchangeType: config.exchangeType || 'topic',\n timeout: config.timeout ?? 5000,\n exchangeOptions: {\n durable: true,\n ...config.exchangeOptions,\n },\n };\n }\n\n /**\n * Create a RabbitMQConnection from a connection string\n * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&timeout=5000\n */\n static async fromConnectionString(\n connectionString: string,\n ): Promise<RabbitMQConnection> {\n const url = new URL(connectionString);\n const params = url.searchParams;\n\n // Extract connection URL without query params\n const baseUrl = `amqp://${url.username ? `${url.username}:${url.password}@` : ''}${url.host}${url.pathname}`;\n\n const timeoutParam = params.get('timeout');\n const config: RabbitMQConnectionConfig = {\n url: baseUrl,\n exchange: params.get('exchange') || 'geekmidas.events',\n exchangeType: (params.get('type') as any) || 'topic',\n timeout: timeoutParam ? Number.parseInt(timeoutParam, 10) : undefined,\n };\n\n const connection = new RabbitMQConnection(config);\n await connection.connect();\n return connection;\n }\n\n async connect(): Promise<void> {\n if (this.channel) return;\n\n // Prevent multiple simultaneous connection attempts\n if (this.connecting) {\n await this.connecting;\n return;\n }\n\n this.connecting = (async () => {\n try {\n const connection = await amqplib.connect(this.config.url, {\n timeout: this.config.timeout,\n });\n const channel = await connection.createChannel();\n\n // Assert the exchange exists\n await channel.assertExchange(\n this.config.exchange!,\n this.config.exchangeType!,\n this.config.exchangeOptions,\n );\n\n // Handle connection errors\n connection.on('error', (_err: Error) => {\n this.cleanup();\n });\n\n connection.on('close', () => {\n this.cleanup();\n });\n\n // Only set after successful setup\n this.connection = connection;\n this.channel = channel;\n } catch (error) {\n this.cleanup();\n throw error;\n }\n })();\n\n await this.connecting;\n this.connecting = undefined;\n }\n\n async close(): Promise<void> {\n try {\n await this.channel?.close();\n await this.connection?.close();\n } catch (error) {\n // Ignore errors during close\n } finally {\n this.cleanup();\n }\n }\n\n isConnected(): boolean {\n return !!this.channel;\n }\n\n private cleanup(): void {\n this.channel = undefined;\n this.connection = undefined;\n this.connecting = undefined;\n }\n\n /**\n * Get the underlying channel for publishing/subscribing\n */\n get amqpChannel(): amqplib.Channel | undefined {\n return this.channel;\n }\n\n /**\n * Get the exchange name for this connection\n */\n get exchangeName(): string {\n return this.config.exchange;\n }\n\n /**\n * Get the exchange type for this connection\n */\n get exchangeType(): string {\n return this.config.exchangeType;\n }\n}\n"],"mappings":";;;;;AAYA,IAAa,qBAAb,MAAa,mBAA8C;CACzD,AAAS,OAAOA,iCAAmB;CACnC,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAKR,YAAYC,QAAkC;AAC5C,OAAK,SAAS;GACZ,GAAG;GACH,UAAU,OAAO,YAAY;GAC7B,cAAc,OAAO,gBAAgB;GACrC,SAAS,OAAO,WAAW;GAC3B,iBAAiB;IACf,SAAS;IACT,GAAG,OAAO;GACX;EACF;CACF;;;;;CAMD,aAAa,qBACXC,kBAC6B;EAC7B,MAAM,MAAM,IAAI,IAAI;EACpB,MAAM,SAAS,IAAI;EAGnB,MAAM,WAAW,SAAS,IAAI,YAAY,EAAE,IAAI,SAAS,GAAG,IAAI,SAAS,KAAK,GAAG,EAAE,IAAI,KAAK,EAAE,IAAI,SAAS;EAE3G,MAAM,eAAe,OAAO,IAAI,UAAU;EAC1C,MAAMD,SAAmC;GACvC,KAAK;GACL,UAAU,OAAO,IAAI,WAAW,IAAI;GACpC,cAAe,OAAO,IAAI,OAAO,IAAY;GAC7C,SAAS,eAAe,OAAO,SAAS,cAAc,GAAG;EAC1D;EAED,MAAM,aAAa,IAAI,mBAAmB;AAC1C,QAAM,WAAW,SAAS;AAC1B,SAAO;CACR;CAED,MAAM,UAAyB;AAC7B,MAAI,KAAK,QAAS;AAGlB,MAAI,KAAK,YAAY;AACnB,SAAM,KAAK;AACX;EACD;AAED,OAAK,aAAa,CAAC,YAAY;AAC7B,OAAI;IACF,MAAM,aAAa,MAAM,gBAAQ,QAAQ,KAAK,OAAO,KAAK,EACxD,SAAS,KAAK,OAAO,QACtB,EAAC;IACF,MAAM,UAAU,MAAM,WAAW,eAAe;AAGhD,UAAM,QAAQ,eACZ,KAAK,OAAO,UACZ,KAAK,OAAO,cACZ,KAAK,OAAO,gBACb;AAGD,eAAW,GAAG,SAAS,CAACE,SAAgB;AACtC,UAAK,SAAS;IACf,EAAC;AAEF,eAAW,GAAG,SAAS,MAAM;AAC3B,UAAK,SAAS;IACf,EAAC;AAGF,SAAK,aAAa;AAClB,SAAK,UAAU;GAChB,SAAQ,OAAO;AACd,SAAK,SAAS;AACd,UAAM;GACP;EACF,IAAG;AAEJ,QAAM,KAAK;AACX,OAAK;CACN;CAED,MAAM,QAAuB;AAC3B,MAAI;AACF,SAAM,KAAK,SAAS,OAAO;AAC3B,SAAM,KAAK,YAAY,OAAO;EAC/B,SAAQ,OAAO,CAEf,UAAS;AACR,QAAK,SAAS;EACf;CACF;CAED,cAAuB;AACrB,WAAS,KAAK;CACf;CAED,AAAQ,UAAgB;AACtB,OAAK;AACL,OAAK;AACL,OAAK;CACN;;;;CAKD,IAAI,cAA2C;AAC7C,SAAO,KAAK;CACb;;;;CAKD,IAAI,eAAuB;AACzB,SAAO,KAAK,OAAO;CACpB;;;;CAKD,IAAI,eAAuB;AACzB,SAAO,KAAK,OAAO;CACpB;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"RabbitMQSubscriber-BaXqs5nO.mjs","names":["connection: RabbitMQConnection","options: RabbitMQSubscriberOptions","connectionString: string","messages: TMessage['type'][]","listener: (payload: TMessage) => Promise<void>","queueOptions: amqplib.Options.AssertQueue","fullMessage: TMessage"],"sources":["../src/rabbitmq/RabbitMQSubscriber.ts"],"sourcesContent":["import type amqplib from 'amqplib';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQSubscriberOptions {\n queueName?: string; // If not provided, a unique queue will be generated\n queueOptions?: amqplib.Options.AssertQueue;\n consumeOptions?: amqplib.Options.Consume;\n prefetch?: number; // Number of messages to prefetch (default: 1)\n}\n\nexport class RabbitMQSubscriber<\n TMessage extends PublishableMessage<string, any>,\n> implements EventSubscriber<TMessage>\n{\n constructor(\n private connection: RabbitMQConnection,\n private options: RabbitMQSubscriberOptions = {},\n ) {}\n\n /**\n * Create a RabbitMQSubscriber from a connection string\n * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&queueName=myqueue&prefetch=10\n */\n static async fromConnectionString<\n TMessage extends PublishableMessage<string, any>,\n >(connectionString: string): Promise<RabbitMQSubscriber<TMessage>> {\n const url = new URL(connectionString);\n const params = url.searchParams;\n\n const { RabbitMQConnection } = await import('./RabbitMQConnection');\n const connection =\n await RabbitMQConnection.fromConnectionString(connectionString);\n\n const options: RabbitMQSubscriberOptions = {\n queueName: params.get('queueName') || undefined,\n prefetch: params.get('prefetch')\n ? Number.parseInt(params.get('prefetch')!, 10)\n : undefined,\n };\n\n return new RabbitMQSubscriber<TMessage>(connection, options);\n }\n\n async subscribe(\n messages: TMessage['type'][],\n listener: (payload: TMessage) => Promise<void>,\n ): Promise<void> {\n if (!this.connection.isConnected()) {\n await this.connection.connect();\n }\n\n const channel = this.connection.amqpChannel;\n if (!channel) {\n throw new Error('Channel not initialized');\n }\n\n const exchange = this.connection.exchangeName;\n\n // Set prefetch if specified\n if (this.options.prefetch) {\n await channel.prefetch(this.options.prefetch);\n }\n\n // Assert queue\n const queueName = this.options.queueName || '';\n const queueOptions: amqplib.Options.AssertQueue = {\n durable: true,\n ...this.options.queueOptions,\n };\n\n const { queue } = await channel.assertQueue(queueName, queueOptions);\n\n // Bind queue to exchange for each message type\n for (const messageType of messages) {\n await channel.bindQueue(queue, exchange, messageType);\n }\n\n // Consume messages\n await channel.consume(\n queue,\n async (msg) => {\n if (!msg) return;\n\n try {\n // Parse message payload\n const content = msg.content.toString();\n const payload = JSON.parse(content);\n\n // Get message type from properties\n const messageType = msg.properties.type;\n\n // Reconstruct full message\n const fullMessage: TMessage = {\n type: messageType,\n payload,\n } as TMessage;\n\n // Call listener\n await listener(fullMessage);\n\n // Ack message\n channel.ack(msg);\n } catch (error) {\n // Log error and nack message (requeue)\n console.error('Error processing message:', error);\n channel.nack(msg, false, true);\n }\n },\n this.options.consumeOptions,\n );\n }\n}\n"],"mappings":";AAWA,IAAa,qBAAb,MAAa,mBAGb;CACE,YACUA,YACAC,UAAqC,CAAE,GAC/C;EAFQ;EACA;CACN;;;;;CAMJ,aAAa,qBAEXC,kBAAiE;EACjE,MAAM,MAAM,IAAI,IAAI;EACpB,MAAM,SAAS,IAAI;EAEnB,MAAM,EAAE,oBAAoB,GAAG,MAAM,OAAO;EAC5C,MAAM,aACJ,MAAM,mBAAmB,qBAAqB,iBAAiB;EAEjE,MAAMD,UAAqC;GACzC,WAAW,OAAO,IAAI,YAAY;GAClC,UAAU,OAAO,IAAI,WAAW,GAC5B,OAAO,SAAS,OAAO,IAAI,WAAW,EAAG,GAAG;EAEjD;AAED,SAAO,IAAI,mBAA6B,YAAY;CACrD;CAED,MAAM,UACJE,UACAC,UACe;AACf,OAAK,KAAK,WAAW,aAAa,CAChC,OAAM,KAAK,WAAW,SAAS;EAGjC,MAAM,UAAU,KAAK,WAAW;AAChC,OAAK,QACH,OAAM,IAAI,MAAM;EAGlB,MAAM,WAAW,KAAK,WAAW;AAGjC,MAAI,KAAK,QAAQ,SACf,OAAM,QAAQ,SAAS,KAAK,QAAQ,SAAS;EAI/C,MAAM,YAAY,KAAK,QAAQ,aAAa;EAC5C,MAAMC,eAA4C;GAChD,SAAS;GACT,GAAG,KAAK,QAAQ;EACjB;EAED,MAAM,EAAE,OAAO,GAAG,MAAM,QAAQ,YAAY,WAAW,aAAa;AAGpE,OAAK,MAAM,eAAe,SACxB,OAAM,QAAQ,UAAU,OAAO,UAAU,YAAY;AAIvD,QAAM,QAAQ,QACZ,OACA,OAAO,QAAQ;AACb,QAAK,IAAK;AAEV,OAAI;IAEF,MAAM,UAAU,IAAI,QAAQ,UAAU;IACtC,MAAM,UAAU,KAAK,MAAM,QAAQ;IAGnC,MAAM,cAAc,IAAI,WAAW;IAGnC,MAAMC,cAAwB;KAC5B,MAAM;KACN;IACD;AAGD,UAAM,SAAS,YAAY;AAG3B,YAAQ,IAAI,IAAI;GACjB,SAAQ,OAAO;AAEd,YAAQ,MAAM,6BAA6B,MAAM;AACjD,YAAQ,KAAK,KAAK,OAAO,KAAK;GAC/B;EACF,GACD,KAAK,QAAQ,eACd;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"RabbitMQSubscriber-BplEJEk8.cjs","names":["connection: RabbitMQConnection","options: RabbitMQSubscriberOptions","connectionString: string","messages: TMessage['type'][]","listener: (payload: TMessage) => Promise<void>","queueOptions: amqplib.Options.AssertQueue","fullMessage: TMessage"],"sources":["../src/rabbitmq/RabbitMQSubscriber.ts"],"sourcesContent":["import type amqplib from 'amqplib';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport type { RabbitMQConnection } from './RabbitMQConnection';\n\nexport interface RabbitMQSubscriberOptions {\n queueName?: string; // If not provided, a unique queue will be generated\n queueOptions?: amqplib.Options.AssertQueue;\n consumeOptions?: amqplib.Options.Consume;\n prefetch?: number; // Number of messages to prefetch (default: 1)\n}\n\nexport class RabbitMQSubscriber<\n TMessage extends PublishableMessage<string, any>,\n> implements EventSubscriber<TMessage>\n{\n constructor(\n private connection: RabbitMQConnection,\n private options: RabbitMQSubscriberOptions = {},\n ) {}\n\n /**\n * Create a RabbitMQSubscriber from a connection string\n * Format: rabbitmq://user:pass@host:port/vhost?exchange=name&type=topic&queueName=myqueue&prefetch=10\n */\n static async fromConnectionString<\n TMessage extends PublishableMessage<string, any>,\n >(connectionString: string): Promise<RabbitMQSubscriber<TMessage>> {\n const url = new URL(connectionString);\n const params = url.searchParams;\n\n const { RabbitMQConnection } = await import('./RabbitMQConnection');\n const connection =\n await RabbitMQConnection.fromConnectionString(connectionString);\n\n const options: RabbitMQSubscriberOptions = {\n queueName: params.get('queueName') || undefined,\n prefetch: params.get('prefetch')\n ? Number.parseInt(params.get('prefetch')!, 10)\n : undefined,\n };\n\n return new RabbitMQSubscriber<TMessage>(connection, options);\n }\n\n async subscribe(\n messages: TMessage['type'][],\n listener: (payload: TMessage) => Promise<void>,\n ): Promise<void> {\n if (!this.connection.isConnected()) {\n await this.connection.connect();\n }\n\n const channel = this.connection.amqpChannel;\n if (!channel) {\n throw new Error('Channel not initialized');\n }\n\n const exchange = this.connection.exchangeName;\n\n // Set prefetch if specified\n if (this.options.prefetch) {\n await channel.prefetch(this.options.prefetch);\n }\n\n // Assert queue\n const queueName = this.options.queueName || '';\n const queueOptions: amqplib.Options.AssertQueue = {\n durable: true,\n ...this.options.queueOptions,\n };\n\n const { queue } = await channel.assertQueue(queueName, queueOptions);\n\n // Bind queue to exchange for each message type\n for (const messageType of messages) {\n await channel.bindQueue(queue, exchange, messageType);\n }\n\n // Consume messages\n await channel.consume(\n queue,\n async (msg) => {\n if (!msg) return;\n\n try {\n // Parse message payload\n const content = msg.content.toString();\n const payload = JSON.parse(content);\n\n // Get message type from properties\n const messageType = msg.properties.type;\n\n // Reconstruct full message\n const fullMessage: TMessage = {\n type: messageType,\n payload,\n } as TMessage;\n\n // Call listener\n await listener(fullMessage);\n\n // Ack message\n channel.ack(msg);\n } catch (error) {\n // Log error and nack message (requeue)\n console.error('Error processing message:', error);\n channel.nack(msg, false, true);\n }\n },\n this.options.consumeOptions,\n );\n }\n}\n"],"mappings":";;AAWA,IAAa,qBAAb,MAAa,mBAGb;CACE,YACUA,YACAC,UAAqC,CAAE,GAC/C;EAFQ;EACA;CACN;;;;;CAMJ,aAAa,qBAEXC,kBAAiE;EACjE,MAAM,MAAM,IAAI,IAAI;EACpB,MAAM,SAAS,IAAI;EAEnB,MAAM,EAAE,oBAAoB,GAAG,2CAAM;EACrC,MAAM,aACJ,MAAM,mBAAmB,qBAAqB,iBAAiB;EAEjE,MAAMD,UAAqC;GACzC,WAAW,OAAO,IAAI,YAAY;GAClC,UAAU,OAAO,IAAI,WAAW,GAC5B,OAAO,SAAS,OAAO,IAAI,WAAW,EAAG,GAAG;EAEjD;AAED,SAAO,IAAI,mBAA6B,YAAY;CACrD;CAED,MAAM,UACJE,UACAC,UACe;AACf,OAAK,KAAK,WAAW,aAAa,CAChC,OAAM,KAAK,WAAW,SAAS;EAGjC,MAAM,UAAU,KAAK,WAAW;AAChC,OAAK,QACH,OAAM,IAAI,MAAM;EAGlB,MAAM,WAAW,KAAK,WAAW;AAGjC,MAAI,KAAK,QAAQ,SACf,OAAM,QAAQ,SAAS,KAAK,QAAQ,SAAS;EAI/C,MAAM,YAAY,KAAK,QAAQ,aAAa;EAC5C,MAAMC,eAA4C;GAChD,SAAS;GACT,GAAG,KAAK,QAAQ;EACjB;EAED,MAAM,EAAE,OAAO,GAAG,MAAM,QAAQ,YAAY,WAAW,aAAa;AAGpE,OAAK,MAAM,eAAe,SACxB,OAAM,QAAQ,UAAU,OAAO,UAAU,YAAY;AAIvD,QAAM,QAAQ,QACZ,OACA,OAAO,QAAQ;AACb,QAAK,IAAK;AAEV,OAAI;IAEF,MAAM,UAAU,IAAI,QAAQ,UAAU;IACtC,MAAM,UAAU,KAAK,MAAM,QAAQ;IAGnC,MAAM,cAAc,IAAI,WAAW;IAGnC,MAAMC,cAAwB;KAC5B,MAAM;KACN;IACD;AAGD,UAAM,SAAS,YAAY;AAG3B,YAAQ,IAAI,IAAI;GACjB,SAAQ,OAAO;AAEd,YAAQ,MAAM,6BAA6B,MAAM;AACjD,YAAQ,KAAK,KAAK,OAAO,KAAK;GAC/B;EACF,GACD,KAAK,QAAQ,eACd;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"SNSPublisher-BZ6N3JI9.cjs","names":["connection: SNSConnection","options: SNSPublisherOptions","connectionString: string","messages: TMessage[]","message: TMessage","PublishCommand"],"sources":["../src/sns/SNSPublisher.ts"],"sourcesContent":["import { PublishCommand } from '@aws-sdk/client-sns';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport type { SNSConnection } from './SNSConnection';\n\nexport interface SNSPublisherOptions {\n // Optional publisher-specific options\n}\n\nexport class SNSPublisher<TMessage extends PublishableMessage<string, any>>\n implements EventPublisher<TMessage>\n{\n constructor(\n private connection: SNSConnection,\n private options: SNSPublisherOptions = {},\n ) {}\n\n /**\n * Create an SNSPublisher from a connection string\n * Format: sns://?topicArn=arn:aws:sns:region:account:topic&region=us-east-1&endpoint=http://localhost:4566\n */\n static async fromConnectionString<\n TMessage extends PublishableMessage<string, any>,\n >(connectionString: string): Promise<SNSPublisher<TMessage>> {\n const { SNSConnection } = await import('./SNSConnection');\n const connection =\n await SNSConnection.fromConnectionString(connectionString);\n\n return new SNSPublisher<TMessage>(connection);\n }\n\n async publish(messages: TMessage[]): Promise<void> {\n if (messages.length === 0) return;\n\n if (!this.connection.isConnected()) {\n await this.connection.connect();\n }\n\n // Publish all messages\n await Promise.all(messages.map((message) => this.publishMessage(message)));\n }\n\n private async publishMessage(message: TMessage): Promise<void> {\n const command = new PublishCommand({\n TopicArn: this.connection.topicArn,\n Message: JSON.stringify({\n type: message.type,\n payload: message.payload,\n }),\n MessageAttributes: {\n type: {\n DataType: 'String',\n StringValue: message.type,\n },\n },\n });\n\n await this.connection.snsClient.send(command);\n }\n\n async close(): Promise<void> {\n // Publisher doesn't own the connection\n // Connection should be closed by whoever created it\n }\n}\n"],"mappings":";;;;AAQA,IAAa,eAAb,MAAa,aAEb;CACE,YACUA,YACAC,UAA+B,CAAE,GACzC;EAFQ;EACA;CACN;;;;;CAMJ,aAAa,qBAEXC,kBAA2D;EAC3D,MAAM,EAAE,eAAe,GAAG,2CAAM;EAChC,MAAM,aACJ,MAAM,cAAc,qBAAqB,iBAAiB;AAE5D,SAAO,IAAI,aAAuB;CACnC;CAED,MAAM,QAAQC,UAAqC;AACjD,MAAI,SAAS,WAAW,EAAG;AAE3B,OAAK,KAAK,WAAW,aAAa,CAChC,OAAM,KAAK,WAAW,SAAS;AAIjC,QAAM,QAAQ,IAAI,SAAS,IAAI,CAAC,YAAY,KAAK,eAAe,QAAQ,CAAC,CAAC;CAC3E;CAED,MAAc,eAAeC,SAAkC;EAC7D,MAAM,UAAU,IAAIC,oCAAe;GACjC,UAAU,KAAK,WAAW;GAC1B,SAAS,KAAK,UAAU;IACtB,MAAM,QAAQ;IACd,SAAS,QAAQ;GAClB,EAAC;GACF,mBAAmB,EACjB,MAAM;IACJ,UAAU;IACV,aAAa,QAAQ;GACtB,EACF;EACF;AAED,QAAM,KAAK,WAAW,UAAU,KAAK,QAAQ;CAC9C;CAED,MAAM,QAAuB,CAG5B;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"SNSPublisher-BfWjzNiB.mjs","names":["connection: SNSConnection","options: SNSPublisherOptions","connectionString: string","messages: TMessage[]","message: TMessage"],"sources":["../src/sns/SNSPublisher.ts"],"sourcesContent":["import { PublishCommand } from '@aws-sdk/client-sns';\nimport type { EventPublisher, PublishableMessage } from '../types';\nimport type { SNSConnection } from './SNSConnection';\n\nexport interface SNSPublisherOptions {\n // Optional publisher-specific options\n}\n\nexport class SNSPublisher<TMessage extends PublishableMessage<string, any>>\n implements EventPublisher<TMessage>\n{\n constructor(\n private connection: SNSConnection,\n private options: SNSPublisherOptions = {},\n ) {}\n\n /**\n * Create an SNSPublisher from a connection string\n * Format: sns://?topicArn=arn:aws:sns:region:account:topic&region=us-east-1&endpoint=http://localhost:4566\n */\n static async fromConnectionString<\n TMessage extends PublishableMessage<string, any>,\n >(connectionString: string): Promise<SNSPublisher<TMessage>> {\n const { SNSConnection } = await import('./SNSConnection');\n const connection =\n await SNSConnection.fromConnectionString(connectionString);\n\n return new SNSPublisher<TMessage>(connection);\n }\n\n async publish(messages: TMessage[]): Promise<void> {\n if (messages.length === 0) return;\n\n if (!this.connection.isConnected()) {\n await this.connection.connect();\n }\n\n // Publish all messages\n await Promise.all(messages.map((message) => this.publishMessage(message)));\n }\n\n private async publishMessage(message: TMessage): Promise<void> {\n const command = new PublishCommand({\n TopicArn: this.connection.topicArn,\n Message: JSON.stringify({\n type: message.type,\n payload: message.payload,\n }),\n MessageAttributes: {\n type: {\n DataType: 'String',\n StringValue: message.type,\n },\n },\n });\n\n await this.connection.snsClient.send(command);\n }\n\n async close(): Promise<void> {\n // Publisher doesn't own the connection\n // Connection should be closed by whoever created it\n }\n}\n"],"mappings":";;;AAQA,IAAa,eAAb,MAAa,aAEb;CACE,YACUA,YACAC,UAA+B,CAAE,GACzC;EAFQ;EACA;CACN;;;;;CAMJ,aAAa,qBAEXC,kBAA2D;EAC3D,MAAM,EAAE,eAAe,GAAG,MAAM,OAAO;EACvC,MAAM,aACJ,MAAM,cAAc,qBAAqB,iBAAiB;AAE5D,SAAO,IAAI,aAAuB;CACnC;CAED,MAAM,QAAQC,UAAqC;AACjD,MAAI,SAAS,WAAW,EAAG;AAE3B,OAAK,KAAK,WAAW,aAAa,CAChC,OAAM,KAAK,WAAW,SAAS;AAIjC,QAAM,QAAQ,IAAI,SAAS,IAAI,CAAC,YAAY,KAAK,eAAe,QAAQ,CAAC,CAAC;CAC3E;CAED,MAAc,eAAeC,SAAkC;EAC7D,MAAM,UAAU,IAAI,eAAe;GACjC,UAAU,KAAK,WAAW;GAC1B,SAAS,KAAK,UAAU;IACtB,MAAM,QAAQ;IACd,SAAS,QAAQ;GAClB,EAAC;GACF,mBAAmB,EACjB,MAAM;IACJ,UAAU;IACV,aAAa,QAAQ;GACtB,EACF;EACF;AAED,QAAM,KAAK,WAAW,UAAU,KAAK,QAAQ;CAC9C;CAED,MAAM,QAAuB,CAG5B;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"SNSSubscriber-C9YJWa7m.mjs","names":["connection: SNSConnection","options: SNSSubscriberOptions","connectionString: string","messages: TMessage['type'][]","listener: (payload: TMessage) => Promise<void>"],"sources":["../src/sns/SNSSubscriber.ts"],"sourcesContent":["import { SubscribeCommand, UnsubscribeCommand } from '@aws-sdk/client-sns';\nimport {\n CreateQueueCommand,\n DeleteQueueCommand,\n GetQueueAttributesCommand,\n SQSClient,\n SetQueueAttributesCommand,\n} from '@aws-sdk/client-sqs';\nimport { SQSConnection } from '../sqs/SQSConnection';\nimport { SQSSubscriber } from '../sqs/SQSSubscriber';\nimport type { EventSubscriber, PublishableMessage } from '../types';\nimport type { SNSConnection } from './SNSConnection';\n\nexport interface SNSSubscriberOptions {\n queueName?: string; // Optional queue name (defaults to auto-generated)\n createQueue?: boolean; // Auto-create SQS queue (default: true)\n deleteQueueOnClose?: boolean; // Delete queue when subscriber closes (default: false for named queues, true for auto-generated)\n waitTimeSeconds?: number; // SQS long polling (default: 20)\n maxMessages?: number; // Max messages per poll (default: 10)\n}\n\n/**\n * SNS Subscriber - receives push-based messages from SNS via SQS queue\n *\n * Architecture:\n * SNS Topic → (push) → SQS Queue → Subscriber\n *\n * This subscriber automatically:\n * 1. Creates an SQS queue (or uses existing one)\n * 2. Subscribes the queue to the SNS topic\n * 3. Receives messages pushed from SNS to the queue\n * 4. Filters messages by topic ARN and message type\n * 5. Processes and acknowledges messages\n *\n * Note: While SQS long-polling is used internally to receive messages,\n * this is an implementation detail of the SNS push delivery mechanism.\n * Messages are pushed from SNS to SQS, and we receive those pushed messages.\n */\nexport class SNSSubscriber<TMessage extends PublishableMessage<string, any>>\n implements EventSubscriber<TMessage>\n{\n private sqsClient: SQSClient;\n private queueUrl?: string;\n private queueArn?: string;\n private subscriptionArn?: string;\n private sqsSubscriber?: SQSSubscriber<TMessage>;\n private options: Required<SNSSubscriberOptions>;\n\n constructor(\n private connection: SNSConnection,\n options: SNSSubscriberOptions = {},\n ) {\n this.options = {\n queueName:\n options.queueName ||\n `sns-sub-${Date.now()}-${Math.random().toString(36).substring(7)}`,\n createQueue: options.createQueue ?? true,\n deleteQueueOnClose: options.deleteQueueOnClose ?? !options.queueName, // Delete auto-generated queues\n waitTimeSeconds: options.waitTimeSeconds ?? 20,\n maxMessages: options.maxMessages ?? 10,\n };\n\n // Create SQS client with same config as SNS\n this.sqsClient = new SQSClient({\n region: (this.connection as any).config.region,\n endpoint: (this.connection as any).config.endpoint,\n credentials: (this.connection as any).config.credentials,\n });\n }\n\n /**\n * Create an SNSSubscriber from a connection string\n * Format: sns://?topicArn=...&queueName=myqueue&region=us-east-1\n */\n static async fromConnectionString<\n TMessage extends PublishableMessage<string, any>,\n >(connectionString: string): Promise<SNSSubscriber<TMessage>> {\n const url = new URL(connectionString);\n const params = url.searchParams;\n\n const { SNSConnection } = await import('./SNSConnection');\n const connection =\n await SNSConnection.fromConnectionString(connectionString);\n\n const options: SNSSubscriberOptions = {\n queueName: params.get('queueName') || undefined,\n createQueue: params.get('createQueue') !== 'false',\n deleteQueueOnClose: params.get('deleteQueueOnClose') === 'true',\n waitTimeSeconds: params.get('waitTimeSeconds')\n ? Number.parseInt(params.get('waitTimeSeconds')!, 10)\n : undefined,\n };\n\n return new SNSSubscriber<TMessage>(connection, options);\n }\n\n async subscribe(\n messages: TMessage['type'][],\n listener: (payload: TMessage) => Promise<void>,\n ): Promise<void> {\n // Setup SQS queue and SNS subscription\n await this.setupQueue();\n await this.subscribeToTopic();\n\n // Create SQS connection for the subscriber\n const sqsConnection = new SQSConnection({\n queueUrl: this.queueUrl!,\n region: (this.connection as any).config.region,\n endpoint: (this.connection as any).config.endpoint,\n credentials: (this.connection as any).config.credentials,\n });\n await sqsConnection.connect();\n\n // Use SQSSubscriber to receive messages, with topic filtering\n this.sqsSubscriber = new SQSSubscriber<TMessage>(sqsConnection, {\n waitTimeSeconds: this.options.waitTimeSeconds,\n maxMessages: this.options.maxMessages,\n expectedTopicArn: this.connection.topicArn,\n });\n\n await this.sqsSubscriber.subscribe(messages, listener);\n }\n\n /**\n * Stop receiving messages and clean up resources\n */\n async stop(): Promise<void> {\n // Stop SQS subscriber\n if (this.sqsSubscriber) {\n this.sqsSubscriber.stop();\n }\n\n // Unsubscribe from topic\n if (this.subscriptionArn) {\n try {\n const command = new UnsubscribeCommand({\n SubscriptionArn: this.subscriptionArn,\n });\n await this.connection.snsClient.send(command);\n } catch (error) {\n console.error('Error unsubscribing:', error);\n }\n }\n\n // Delete queue if configured\n if (this.queueUrl && this.options.deleteQueueOnClose) {\n try {\n const command = new DeleteQueueCommand({\n QueueUrl: this.queueUrl,\n });\n await this.sqsClient.send(command);\n } catch (error) {\n console.error('Error deleting queue:', error);\n }\n }\n\n this.sqsClient.destroy();\n }\n\n private async setupQueue(): Promise<void> {\n if (this.options.createQueue) {\n // Create queue\n const createCommand = new CreateQueueCommand({\n QueueName: this.options.queueName,\n });\n const response = await this.sqsClient.send(createCommand);\n this.queueUrl = response.QueueUrl!;\n } else {\n throw new Error('Queue must exist or createQueue option must be true');\n }\n\n // Get queue ARN\n const attrsCommand = new GetQueueAttributesCommand({\n QueueUrl: this.queueUrl,\n AttributeNames: ['QueueArn'],\n });\n const attrsResponse = await this.sqsClient.send(attrsCommand);\n this.queueArn = attrsResponse.Attributes?.QueueArn!;\n\n // Set queue policy to allow SNS\n await this.setQueuePolicy();\n }\n\n private async setQueuePolicy(): Promise<void> {\n const policy = {\n Version: '2012-10-17',\n Statement: [\n {\n Effect: 'Allow',\n Principal: '*',\n Action: 'SQS:SendMessage',\n Resource: this.queueArn,\n Condition: {\n ArnEquals: {\n 'aws:SourceArn': this.connection.topicArn,\n },\n },\n },\n ],\n };\n\n const command = new SetQueueAttributesCommand({\n QueueUrl: this.queueUrl,\n Attributes: {\n Policy: JSON.stringify(policy),\n },\n });\n\n await this.sqsClient.send(command);\n }\n\n private async subscribeToTopic(): Promise<void> {\n const command = new SubscribeCommand({\n TopicArn: this.connection.topicArn,\n Protocol: 'sqs',\n Endpoint: this.queueArn,\n });\n\n const response = await this.connection.snsClient.send(command);\n this.subscriptionArn = response.SubscriptionArn!;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsCA,IAAa,gBAAb,MAAa,cAEb;CACE,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YACUA,YACRC,UAAgC,CAAE,GAClC;EAFQ;AAGR,OAAK,UAAU;GACb,WACE,QAAQ,cACP,UAAU,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,UAAU,EAAE,CAAC;GACnE,aAAa,QAAQ,eAAe;GACpC,oBAAoB,QAAQ,uBAAuB,QAAQ;GAC3D,iBAAiB,QAAQ,mBAAmB;GAC5C,aAAa,QAAQ,eAAe;EACrC;AAGD,OAAK,YAAY,IAAI,UAAU;GAC7B,QAAS,KAAK,WAAmB,OAAO;GACxC,UAAW,KAAK,WAAmB,OAAO;GAC1C,aAAc,KAAK,WAAmB,OAAO;EAC9C;CACF;;;;;CAMD,aAAa,qBAEXC,kBAA4D;EAC5D,MAAM,MAAM,IAAI,IAAI;EACpB,MAAM,SAAS,IAAI;EAEnB,MAAM,EAAE,eAAe,GAAG,MAAM,OAAO;EACvC,MAAM,aACJ,MAAM,cAAc,qBAAqB,iBAAiB;EAE5D,MAAMD,UAAgC;GACpC,WAAW,OAAO,IAAI,YAAY;GAClC,aAAa,OAAO,IAAI,cAAc,KAAK;GAC3C,oBAAoB,OAAO,IAAI,qBAAqB,KAAK;GACzD,iBAAiB,OAAO,IAAI,kBAAkB,GAC1C,OAAO,SAAS,OAAO,IAAI,kBAAkB,EAAG,GAAG;EAExD;AAED,SAAO,IAAI,cAAwB,YAAY;CAChD;CAED,MAAM,UACJE,UACAC,UACe;AAEf,QAAM,KAAK,YAAY;AACvB,QAAM,KAAK,kBAAkB;EAG7B,MAAM,gBAAgB,IAAI,cAAc;GACtC,UAAU,KAAK;GACf,QAAS,KAAK,WAAmB,OAAO;GACxC,UAAW,KAAK,WAAmB,OAAO;GAC1C,aAAc,KAAK,WAAmB,OAAO;EAC9C;AACD,QAAM,cAAc,SAAS;AAG7B,OAAK,gBAAgB,IAAI,cAAwB,eAAe;GAC9D,iBAAiB,KAAK,QAAQ;GAC9B,aAAa,KAAK,QAAQ;GAC1B,kBAAkB,KAAK,WAAW;EACnC;AAED,QAAM,KAAK,cAAc,UAAU,UAAU,SAAS;CACvD;;;;CAKD,MAAM,OAAsB;AAE1B,MAAI,KAAK,cACP,MAAK,cAAc,MAAM;AAI3B,MAAI,KAAK,gBACP,KAAI;GACF,MAAM,UAAU,IAAI,mBAAmB,EACrC,iBAAiB,KAAK,gBACvB;AACD,SAAM,KAAK,WAAW,UAAU,KAAK,QAAQ;EAC9C,SAAQ,OAAO;AACd,WAAQ,MAAM,wBAAwB,MAAM;EAC7C;AAIH,MAAI,KAAK,YAAY,KAAK,QAAQ,mBAChC,KAAI;GACF,MAAM,UAAU,IAAI,mBAAmB,EACrC,UAAU,KAAK,SAChB;AACD,SAAM,KAAK,UAAU,KAAK,QAAQ;EACnC,SAAQ,OAAO;AACd,WAAQ,MAAM,yBAAyB,MAAM;EAC9C;AAGH,OAAK,UAAU,SAAS;CACzB;CAED,MAAc,aAA4B;AACxC,MAAI,KAAK,QAAQ,aAAa;GAE5B,MAAM,gBAAgB,IAAI,mBAAmB,EAC3C,WAAW,KAAK,QAAQ,UACzB;GACD,MAAM,WAAW,MAAM,KAAK,UAAU,KAAK,cAAc;AACzD,QAAK,WAAW,SAAS;EAC1B,MACC,OAAM,IAAI,MAAM;EAIlB,MAAM,eAAe,IAAI,0BAA0B;GACjD,UAAU,KAAK;GACf,gBAAgB,CAAC,UAAW;EAC7B;EACD,MAAM,gBAAgB,MAAM,KAAK,UAAU,KAAK,aAAa;AAC7D,OAAK,WAAW,cAAc,YAAY;AAG1C,QAAM,KAAK,gBAAgB;CAC5B;CAED,MAAc,iBAAgC;EAC5C,MAAM,SAAS;GACb,SAAS;GACT,WAAW,CACT;IACE,QAAQ;IACR,WAAW;IACX,QAAQ;IACR,UAAU,KAAK;IACf,WAAW,EACT,WAAW,EACT,iBAAiB,KAAK,WAAW,SAClC,EACF;GACF,CACF;EACF;EAED,MAAM,UAAU,IAAI,0BAA0B;GAC5C,UAAU,KAAK;GACf,YAAY,EACV,QAAQ,KAAK,UAAU,OAAO,CAC/B;EACF;AAED,QAAM,KAAK,UAAU,KAAK,QAAQ;CACnC;CAED,MAAc,mBAAkC;EAC9C,MAAM,UAAU,IAAI,iBAAiB;GACnC,UAAU,KAAK,WAAW;GAC1B,UAAU;GACV,UAAU,KAAK;EAChB;EAED,MAAM,WAAW,MAAM,KAAK,WAAW,UAAU,KAAK,QAAQ;AAC9D,OAAK,kBAAkB,SAAS;CACjC;AACF"}