fauxqs 0.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 (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/dist/app.d.ts +16 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +132 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/common/arnHelper.d.ts +11 -0
  8. package/dist/common/arnHelper.d.ts.map +1 -0
  9. package/dist/common/arnHelper.js +21 -0
  10. package/dist/common/arnHelper.js.map +1 -0
  11. package/dist/common/errors.d.ts +18 -0
  12. package/dist/common/errors.d.ts.map +1 -0
  13. package/dist/common/errors.js +35 -0
  14. package/dist/common/errors.js.map +1 -0
  15. package/dist/common/md5.d.ts +8 -0
  16. package/dist/common/md5.d.ts.map +1 -0
  17. package/dist/common/md5.js +40 -0
  18. package/dist/common/md5.js.map +1 -0
  19. package/dist/common/types.d.ts +3 -0
  20. package/dist/common/types.d.ts.map +1 -0
  21. package/dist/common/types.js +3 -0
  22. package/dist/common/types.js.map +1 -0
  23. package/dist/common/xml.d.ts +4 -0
  24. package/dist/common/xml.d.ts.map +1 -0
  25. package/dist/common/xml.js +35 -0
  26. package/dist/common/xml.js.map +1 -0
  27. package/dist/server.d.ts +2 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +3 -0
  30. package/dist/server.js.map +1 -0
  31. package/dist/sns/actions/confirmSubscription.d.ts +3 -0
  32. package/dist/sns/actions/confirmSubscription.d.ts.map +1 -0
  33. package/dist/sns/actions/confirmSubscription.js +23 -0
  34. package/dist/sns/actions/confirmSubscription.js.map +1 -0
  35. package/dist/sns/actions/createTopic.d.ts +3 -0
  36. package/dist/sns/actions/createTopic.d.ts.map +1 -0
  37. package/dist/sns/actions/createTopic.js +59 -0
  38. package/dist/sns/actions/createTopic.js.map +1 -0
  39. package/dist/sns/actions/deleteTopic.d.ts +3 -0
  40. package/dist/sns/actions/deleteTopic.d.ts.map +1 -0
  41. package/dist/sns/actions/deleteTopic.js +11 -0
  42. package/dist/sns/actions/deleteTopic.js.map +1 -0
  43. package/dist/sns/actions/getSubscriptionAttributes.d.ts +3 -0
  44. package/dist/sns/actions/getSubscriptionAttributes.d.ts.map +1 -0
  45. package/dist/sns/actions/getSubscriptionAttributes.js +28 -0
  46. package/dist/sns/actions/getSubscriptionAttributes.js.map +1 -0
  47. package/dist/sns/actions/getTopicAttributes.d.ts +3 -0
  48. package/dist/sns/actions/getTopicAttributes.d.ts.map +1 -0
  49. package/dist/sns/actions/getTopicAttributes.js +25 -0
  50. package/dist/sns/actions/getTopicAttributes.js.map +1 -0
  51. package/dist/sns/actions/listSubscriptions.d.ts +4 -0
  52. package/dist/sns/actions/listSubscriptions.d.ts.map +1 -0
  53. package/dist/sns/actions/listSubscriptions.js +25 -0
  54. package/dist/sns/actions/listSubscriptions.js.map +1 -0
  55. package/dist/sns/actions/listTopics.d.ts +3 -0
  56. package/dist/sns/actions/listTopics.d.ts.map +1 -0
  57. package/dist/sns/actions/listTopics.js +9 -0
  58. package/dist/sns/actions/listTopics.js.map +1 -0
  59. package/dist/sns/actions/publish.d.ts +5 -0
  60. package/dist/sns/actions/publish.d.ts.map +1 -0
  61. package/dist/sns/actions/publish.js +182 -0
  62. package/dist/sns/actions/publish.js.map +1 -0
  63. package/dist/sns/actions/setSubscriptionAttributes.d.ts +3 -0
  64. package/dist/sns/actions/setSubscriptionAttributes.d.ts.map +1 -0
  65. package/dist/sns/actions/setSubscriptionAttributes.js +19 -0
  66. package/dist/sns/actions/setSubscriptionAttributes.js.map +1 -0
  67. package/dist/sns/actions/setTopicAttributes.d.ts +3 -0
  68. package/dist/sns/actions/setTopicAttributes.d.ts.map +1 -0
  69. package/dist/sns/actions/setTopicAttributes.js +19 -0
  70. package/dist/sns/actions/setTopicAttributes.js.map +1 -0
  71. package/dist/sns/actions/subscribe.d.ts +3 -0
  72. package/dist/sns/actions/subscribe.d.ts.map +1 -0
  73. package/dist/sns/actions/subscribe.js +47 -0
  74. package/dist/sns/actions/subscribe.js.map +1 -0
  75. package/dist/sns/actions/tagResource.d.ts +5 -0
  76. package/dist/sns/actions/tagResource.d.ts.map +1 -0
  77. package/dist/sns/actions/tagResource.js +55 -0
  78. package/dist/sns/actions/tagResource.js.map +1 -0
  79. package/dist/sns/actions/unsubscribe.d.ts +3 -0
  80. package/dist/sns/actions/unsubscribe.d.ts.map +1 -0
  81. package/dist/sns/actions/unsubscribe.js +11 -0
  82. package/dist/sns/actions/unsubscribe.js.map +1 -0
  83. package/dist/sns/filter.d.ts +23 -0
  84. package/dist/sns/filter.d.ts.map +1 -0
  85. package/dist/sns/filter.js +192 -0
  86. package/dist/sns/filter.js.map +1 -0
  87. package/dist/sns/snsRouter.d.ts +13 -0
  88. package/dist/sns/snsRouter.d.ts.map +1 -0
  89. package/dist/sns/snsRouter.js +43 -0
  90. package/dist/sns/snsRouter.js.map +1 -0
  91. package/dist/sns/snsStore.d.ts +15 -0
  92. package/dist/sns/snsStore.d.ts.map +1 -0
  93. package/dist/sns/snsStore.js +82 -0
  94. package/dist/sns/snsStore.js.map +1 -0
  95. package/dist/sns/snsTypes.d.ts +21 -0
  96. package/dist/sns/snsTypes.d.ts.map +1 -0
  97. package/dist/sns/snsTypes.js +2 -0
  98. package/dist/sns/snsTypes.js.map +1 -0
  99. package/dist/sqs/actions/changeMessageVisibility.d.ts +3 -0
  100. package/dist/sqs/actions/changeMessageVisibility.d.ts.map +1 -0
  101. package/dist/sqs/actions/changeMessageVisibility.js +25 -0
  102. package/dist/sqs/actions/changeMessageVisibility.js.map +1 -0
  103. package/dist/sqs/actions/changeMessageVisibilityBatch.d.ts +3 -0
  104. package/dist/sqs/actions/changeMessageVisibilityBatch.d.ts.map +1 -0
  105. package/dist/sqs/actions/changeMessageVisibilityBatch.js +36 -0
  106. package/dist/sqs/actions/changeMessageVisibilityBatch.js.map +1 -0
  107. package/dist/sqs/actions/createQueue.d.ts +4 -0
  108. package/dist/sqs/actions/createQueue.d.ts.map +1 -0
  109. package/dist/sqs/actions/createQueue.js +31 -0
  110. package/dist/sqs/actions/createQueue.js.map +1 -0
  111. package/dist/sqs/actions/deleteMessage.d.ts +3 -0
  112. package/dist/sqs/actions/deleteMessage.d.ts.map +1 -0
  113. package/dist/sqs/actions/deleteMessage.js +19 -0
  114. package/dist/sqs/actions/deleteMessage.js.map +1 -0
  115. package/dist/sqs/actions/deleteMessageBatch.d.ts +3 -0
  116. package/dist/sqs/actions/deleteMessageBatch.d.ts.map +1 -0
  117. package/dist/sqs/actions/deleteMessageBatch.js +32 -0
  118. package/dist/sqs/actions/deleteMessageBatch.js.map +1 -0
  119. package/dist/sqs/actions/deleteQueue.d.ts +3 -0
  120. package/dist/sqs/actions/deleteQueue.d.ts.map +1 -0
  121. package/dist/sqs/actions/deleteQueue.js +13 -0
  122. package/dist/sqs/actions/deleteQueue.js.map +1 -0
  123. package/dist/sqs/actions/getQueueAttributes.d.ts +3 -0
  124. package/dist/sqs/actions/getQueueAttributes.d.ts.map +1 -0
  125. package/dist/sqs/actions/getQueueAttributes.js +15 -0
  126. package/dist/sqs/actions/getQueueAttributes.js.map +1 -0
  127. package/dist/sqs/actions/getQueueUrl.d.ts +3 -0
  128. package/dist/sqs/actions/getQueueUrl.d.ts.map +1 -0
  129. package/dist/sqs/actions/getQueueUrl.js +13 -0
  130. package/dist/sqs/actions/getQueueUrl.js.map +1 -0
  131. package/dist/sqs/actions/listQueueTags.d.ts +3 -0
  132. package/dist/sqs/actions/listQueueTags.d.ts.map +1 -0
  133. package/dist/sqs/actions/listQueueTags.js +13 -0
  134. package/dist/sqs/actions/listQueueTags.js.map +1 -0
  135. package/dist/sqs/actions/listQueues.d.ts +3 -0
  136. package/dist/sqs/actions/listQueues.d.ts.map +1 -0
  137. package/dist/sqs/actions/listQueues.js +9 -0
  138. package/dist/sqs/actions/listQueues.js.map +1 -0
  139. package/dist/sqs/actions/purgeQueue.d.ts +3 -0
  140. package/dist/sqs/actions/purgeQueue.d.ts.map +1 -0
  141. package/dist/sqs/actions/purgeQueue.js +14 -0
  142. package/dist/sqs/actions/purgeQueue.js.map +1 -0
  143. package/dist/sqs/actions/receiveMessage.d.ts +3 -0
  144. package/dist/sqs/actions/receiveMessage.d.ts.map +1 -0
  145. package/dist/sqs/actions/receiveMessage.js +64 -0
  146. package/dist/sqs/actions/receiveMessage.js.map +1 -0
  147. package/dist/sqs/actions/sendMessage.d.ts +3 -0
  148. package/dist/sqs/actions/sendMessage.d.ts.map +1 -0
  149. package/dist/sqs/actions/sendMessage.js +31 -0
  150. package/dist/sqs/actions/sendMessage.js.map +1 -0
  151. package/dist/sqs/actions/sendMessageBatch.d.ts +3 -0
  152. package/dist/sqs/actions/sendMessageBatch.d.ts.map +1 -0
  153. package/dist/sqs/actions/sendMessageBatch.js +44 -0
  154. package/dist/sqs/actions/sendMessageBatch.js.map +1 -0
  155. package/dist/sqs/actions/setQueueAttributes.d.ts +3 -0
  156. package/dist/sqs/actions/setQueueAttributes.d.ts.map +1 -0
  157. package/dist/sqs/actions/setQueueAttributes.js +21 -0
  158. package/dist/sqs/actions/setQueueAttributes.js.map +1 -0
  159. package/dist/sqs/actions/tagQueue.d.ts +3 -0
  160. package/dist/sqs/actions/tagQueue.d.ts.map +1 -0
  161. package/dist/sqs/actions/tagQueue.js +17 -0
  162. package/dist/sqs/actions/tagQueue.js.map +1 -0
  163. package/dist/sqs/actions/untagQueue.d.ts +3 -0
  164. package/dist/sqs/actions/untagQueue.d.ts.map +1 -0
  165. package/dist/sqs/actions/untagQueue.js +17 -0
  166. package/dist/sqs/actions/untagQueue.js.map +1 -0
  167. package/dist/sqs/sqsRouter.d.ts +11 -0
  168. package/dist/sqs/sqsRouter.d.ts.map +1 -0
  169. package/dist/sqs/sqsRouter.js +45 -0
  170. package/dist/sqs/sqsRouter.js.map +1 -0
  171. package/dist/sqs/sqsStore.d.ts +43 -0
  172. package/dist/sqs/sqsStore.d.ts.map +1 -0
  173. package/dist/sqs/sqsStore.js +256 -0
  174. package/dist/sqs/sqsStore.js.map +1 -0
  175. package/dist/sqs/sqsTypes.d.ts +37 -0
  176. package/dist/sqs/sqsTypes.d.ts.map +1 -0
  177. package/dist/sqs/sqsTypes.js +32 -0
  178. package/dist/sqs/sqsTypes.js.map +1 -0
  179. package/package.json +64 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Igor Savin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # fauxqs
2
+
3
+ Local SNS/SQS emulator for development and testing. Point your `@aws-sdk/client-sqs` and `@aws-sdk/client-sns` clients at fauxqs instead of real AWS or LocalStack.
4
+
5
+ All state is in-memory. No persistence, no external dependencies.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install fauxqs
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Running the server
16
+
17
+ ```bash
18
+ npx fauxqs
19
+ ```
20
+
21
+ The server starts on port 3000 and handles both SQS and SNS on a single endpoint.
22
+
23
+ A health check is available at `GET /health`.
24
+
25
+ ### Configuring AWS SDK clients
26
+
27
+ Point your SDK clients at the local server:
28
+
29
+ ```typescript
30
+ import { SQSClient } from "@aws-sdk/client-sqs";
31
+ import { SNSClient } from "@aws-sdk/client-sns";
32
+
33
+ const sqsClient = new SQSClient({
34
+ endpoint: "http://localhost:3000",
35
+ region: "us-east-1",
36
+ credentials: { accessKeyId: "test", secretAccessKey: "test" },
37
+ });
38
+
39
+ const snsClient = new SNSClient({
40
+ endpoint: "http://localhost:3000",
41
+ region: "us-east-1",
42
+ credentials: { accessKeyId: "test", secretAccessKey: "test" },
43
+ });
44
+ ```
45
+
46
+ Any credentials are accepted and never validated.
47
+
48
+ ### Programmatic usage
49
+
50
+ You can also embed fauxqs directly in your test suite:
51
+
52
+ ```typescript
53
+ import { startFauxqs } from "fauxqs";
54
+
55
+ const server = await startFauxqs({ logger: false });
56
+
57
+ console.log(server.address); // "http://127.0.0.1:12345"
58
+ console.log(server.port); // 12345
59
+
60
+ // point your SDK clients at server.address
61
+
62
+ // clean up when done
63
+ await server.stop();
64
+ ```
65
+
66
+ ## Supported API Actions
67
+
68
+ ### SQS
69
+
70
+ | Action | Supported |
71
+ |--------|-----------|
72
+ | CreateQueue | Yes |
73
+ | DeleteQueue | Yes |
74
+ | GetQueueUrl | Yes |
75
+ | ListQueues | Yes |
76
+ | GetQueueAttributes | Yes |
77
+ | SetQueueAttributes | Yes |
78
+ | PurgeQueue | Yes |
79
+ | SendMessage | Yes |
80
+ | SendMessageBatch | Yes |
81
+ | ReceiveMessage | Yes |
82
+ | DeleteMessage | Yes |
83
+ | DeleteMessageBatch | Yes |
84
+ | ChangeMessageVisibility | Yes |
85
+ | ChangeMessageVisibilityBatch | Yes |
86
+ | TagQueue | Yes |
87
+ | UntagQueue | Yes |
88
+ | ListQueueTags | Yes |
89
+
90
+ ### SNS
91
+
92
+ | Action | Supported |
93
+ |--------|-----------|
94
+ | CreateTopic | Yes |
95
+ | DeleteTopic | Yes |
96
+ | ListTopics | Yes |
97
+ | GetTopicAttributes | Yes |
98
+ | SetTopicAttributes | Yes |
99
+ | Subscribe | Yes |
100
+ | Unsubscribe | Yes |
101
+ | ConfirmSubscription | Yes |
102
+ | ListSubscriptions | Yes |
103
+ | ListSubscriptionsByTopic | Yes |
104
+ | GetSubscriptionAttributes | Yes |
105
+ | SetSubscriptionAttributes | Yes |
106
+ | Publish | Yes |
107
+ | PublishBatch | Yes |
108
+ | TagResource | Yes |
109
+ | UntagResource | Yes |
110
+ | ListTagsForResource | Yes |
111
+
112
+ ## SQS Features
113
+
114
+ - **Message attributes** with MD5 checksums matching the AWS algorithm
115
+ - **Visibility timeout** — messages become invisible after receive and reappear after timeout
116
+ - **Delay queues** — per-queue default delay and per-message delay overrides
117
+ - **Long polling** — `WaitTimeSeconds` on ReceiveMessage blocks until messages arrive or timeout
118
+ - **Dead letter queues** — messages exceeding `maxReceiveCount` are moved to the configured DLQ
119
+ - **Batch operations** — SendMessageBatch, DeleteMessageBatch, ChangeMessageVisibilityBatch
120
+ - **Queue tags**
121
+
122
+ ## SNS Features
123
+
124
+ - **SNS-to-SQS fan-out** — publish to a topic and messages are delivered to all confirmed SQS subscriptions
125
+ - **Filter policies** — both `MessageAttributes` and `MessageBody` scope, supporting exact match, prefix, suffix, anything-but, numeric ranges, and exists
126
+ - **Raw message delivery** — configurable per subscription
127
+ - **Topic and subscription tags**
128
+ - **Batch publish**
129
+
130
+ ## Conventions
131
+
132
+ - Account ID: `000000000000`
133
+ - Region: `us-east-1`
134
+ - Queue URL format: `http://{host}:{port}/000000000000/{queueName}`
135
+ - Queue ARN format: `arn:aws:sqs:us-east-1:000000000000:{queueName}`
136
+ - Topic ARN format: `arn:aws:sns:us-east-1:000000000000:{topicName}`
137
+
138
+ ## Limitations
139
+
140
+ fauxqs is designed for development and testing. It does not support:
141
+
142
+ - FIFO queues and topics
143
+ - Non-SQS SNS delivery protocols (HTTP/S, Lambda, email, SMS)
144
+ - Persistence across restarts
145
+ - Authentication or authorization
146
+ - Message size limits
147
+ - Cross-region or cross-account operations
148
+
149
+ ## License
150
+
151
+ MIT
package/dist/app.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import Fastify from "fastify";
2
+ export declare function buildApp(options?: {
3
+ logger?: boolean;
4
+ }): Fastify.FastifyInstance<import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>, import("node:http").IncomingMessage, import("node:http").ServerResponse<import("node:http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault> & PromiseLike<Fastify.FastifyInstance<import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>, import("node:http").IncomingMessage, import("node:http").ServerResponse<import("node:http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>> & {
5
+ __linterBrands: "SafePromiseLike";
6
+ };
7
+ export interface FauxqsServer {
8
+ readonly port: number;
9
+ readonly address: string;
10
+ stop(): Promise<void>;
11
+ }
12
+ export declare function startFauxqs(options?: {
13
+ port?: number;
14
+ logger?: boolean;
15
+ }): Promise<FauxqsServer>;
16
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAoC9B,wBAAgB,QAAQ,CAAC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE;;EAgGtD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAsB,WAAW,CAC/B,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5C,OAAO,CAAC,YAAY,CAAC,CAgBvB"}
package/dist/app.js ADDED
@@ -0,0 +1,132 @@
1
+ import Fastify from "fastify";
2
+ import { SqsStore } from "./sqs/sqsStore.js";
3
+ import { SqsRouter } from "./sqs/sqsRouter.js";
4
+ import { SnsStore } from "./sns/snsStore.js";
5
+ import { SnsRouter } from "./sns/snsRouter.js";
6
+ import { createQueue } from "./sqs/actions/createQueue.js";
7
+ import { deleteQueue } from "./sqs/actions/deleteQueue.js";
8
+ import { getQueueUrl } from "./sqs/actions/getQueueUrl.js";
9
+ import { listQueues } from "./sqs/actions/listQueues.js";
10
+ import { getQueueAttributes } from "./sqs/actions/getQueueAttributes.js";
11
+ import { setQueueAttributes } from "./sqs/actions/setQueueAttributes.js";
12
+ import { purgeQueue } from "./sqs/actions/purgeQueue.js";
13
+ import { sendMessage } from "./sqs/actions/sendMessage.js";
14
+ import { receiveMessage } from "./sqs/actions/receiveMessage.js";
15
+ import { deleteMessage } from "./sqs/actions/deleteMessage.js";
16
+ import { sendMessageBatch } from "./sqs/actions/sendMessageBatch.js";
17
+ import { deleteMessageBatch } from "./sqs/actions/deleteMessageBatch.js";
18
+ import { changeMessageVisibility } from "./sqs/actions/changeMessageVisibility.js";
19
+ import { changeMessageVisibilityBatch } from "./sqs/actions/changeMessageVisibilityBatch.js";
20
+ import { tagQueue } from "./sqs/actions/tagQueue.js";
21
+ import { untagQueue } from "./sqs/actions/untagQueue.js";
22
+ import { listQueueTags } from "./sqs/actions/listQueueTags.js";
23
+ import { createTopic } from "./sns/actions/createTopic.js";
24
+ import { deleteTopic } from "./sns/actions/deleteTopic.js";
25
+ import { listTopics } from "./sns/actions/listTopics.js";
26
+ import { getTopicAttributes } from "./sns/actions/getTopicAttributes.js";
27
+ import { setTopicAttributes } from "./sns/actions/setTopicAttributes.js";
28
+ import { subscribe } from "./sns/actions/subscribe.js";
29
+ import { unsubscribe } from "./sns/actions/unsubscribe.js";
30
+ import { confirmSubscription } from "./sns/actions/confirmSubscription.js";
31
+ import { listSubscriptions, listSubscriptionsByTopic } from "./sns/actions/listSubscriptions.js";
32
+ import { getSubscriptionAttributes } from "./sns/actions/getSubscriptionAttributes.js";
33
+ import { setSubscriptionAttributes } from "./sns/actions/setSubscriptionAttributes.js";
34
+ import { publish, publishBatch } from "./sns/actions/publish.js";
35
+ import { tagResource, untagResource, listTagsForResource } from "./sns/actions/tagResource.js";
36
+ export function buildApp(options) {
37
+ const app = Fastify({
38
+ logger: options?.logger ?? true,
39
+ });
40
+ const sqsStore = new SqsStore();
41
+ const snsStore = new SnsStore();
42
+ const sqsRouter = new SqsRouter(sqsStore);
43
+ sqsRouter.register("CreateQueue", createQueue);
44
+ sqsRouter.register("DeleteQueue", deleteQueue);
45
+ sqsRouter.register("GetQueueUrl", getQueueUrl);
46
+ sqsRouter.register("ListQueues", listQueues);
47
+ sqsRouter.register("GetQueueAttributes", getQueueAttributes);
48
+ sqsRouter.register("SetQueueAttributes", setQueueAttributes);
49
+ sqsRouter.register("PurgeQueue", purgeQueue);
50
+ sqsRouter.register("SendMessage", sendMessage);
51
+ sqsRouter.register("ReceiveMessage", receiveMessage);
52
+ sqsRouter.register("DeleteMessage", deleteMessage);
53
+ sqsRouter.register("SendMessageBatch", sendMessageBatch);
54
+ sqsRouter.register("DeleteMessageBatch", deleteMessageBatch);
55
+ sqsRouter.register("ChangeMessageVisibility", changeMessageVisibility);
56
+ sqsRouter.register("ChangeMessageVisibilityBatch", changeMessageVisibilityBatch);
57
+ sqsRouter.register("TagQueue", tagQueue);
58
+ sqsRouter.register("UntagQueue", untagQueue);
59
+ sqsRouter.register("ListQueueTags", listQueueTags);
60
+ const snsRouter = new SnsRouter(snsStore, sqsStore);
61
+ snsRouter.register("CreateTopic", createTopic);
62
+ snsRouter.register("DeleteTopic", deleteTopic);
63
+ snsRouter.register("ListTopics", listTopics);
64
+ snsRouter.register("GetTopicAttributes", getTopicAttributes);
65
+ snsRouter.register("SetTopicAttributes", setTopicAttributes);
66
+ snsRouter.register("Subscribe", subscribe);
67
+ snsRouter.register("Unsubscribe", unsubscribe);
68
+ snsRouter.register("ConfirmSubscription", confirmSubscription);
69
+ snsRouter.register("ListSubscriptions", listSubscriptions);
70
+ snsRouter.register("ListSubscriptionsByTopic", listSubscriptionsByTopic);
71
+ snsRouter.register("GetSubscriptionAttributes", getSubscriptionAttributes);
72
+ snsRouter.register("SetSubscriptionAttributes", setSubscriptionAttributes);
73
+ snsRouter.register("Publish", publish);
74
+ snsRouter.register("PublishBatch", publishBatch);
75
+ snsRouter.register("TagResource", tagResource);
76
+ snsRouter.register("UntagResource", untagResource);
77
+ snsRouter.register("ListTagsForResource", listTagsForResource);
78
+ // Parse AWS JSON protocol (SQS)
79
+ app.addContentTypeParser("application/x-amz-json-1.0", { parseAs: "string" }, (_req, body, done) => {
80
+ try {
81
+ done(null, JSON.parse(body));
82
+ }
83
+ catch (err) {
84
+ done(err);
85
+ }
86
+ });
87
+ // Parse Query protocol (SNS)
88
+ app.addContentTypeParser("application/x-www-form-urlencoded", { parseAs: "string" }, (_req, body, done) => {
89
+ try {
90
+ const result = {};
91
+ for (const [key, value] of new URLSearchParams(body)) {
92
+ result[key] = value;
93
+ }
94
+ done(null, result);
95
+ }
96
+ catch (err) {
97
+ done(err);
98
+ }
99
+ });
100
+ app.get("/health", async () => {
101
+ return { status: "ok" };
102
+ });
103
+ app.post("/", async (request, reply) => {
104
+ const contentType = request.headers["content-type"] ?? "";
105
+ if (contentType.includes("application/x-amz-json-1.0")) {
106
+ return sqsRouter.handle(request, reply);
107
+ }
108
+ if (contentType.includes("application/x-www-form-urlencoded")) {
109
+ return snsRouter.handle(request, reply);
110
+ }
111
+ reply.status(400);
112
+ return { error: "Unsupported content type" };
113
+ });
114
+ return app;
115
+ }
116
+ export async function startFauxqs(options) {
117
+ const app = buildApp({ logger: options?.logger ?? true });
118
+ const listenAddress = await app.listen({ port: options?.port ?? 0, host: "127.0.0.1" });
119
+ const url = new URL(listenAddress);
120
+ return {
121
+ get port() {
122
+ return parseInt(url.port);
123
+ },
124
+ get address() {
125
+ return listenAddress;
126
+ },
127
+ stop() {
128
+ return app.close();
129
+ },
130
+ };
131
+ }
132
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare function sqsQueueArn(queueName: string): string;
2
+ export declare function snsTopicArn(topicName: string): string;
3
+ export declare function snsSubscriptionArn(topicName: string, id: string): string;
4
+ export declare function parseArn(arn: string): {
5
+ partition: string;
6
+ service: string;
7
+ region: string;
8
+ accountId: string;
9
+ resource: string;
10
+ };
11
+ //# sourceMappingURL=arnHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arnHelper.d.ts","sourceRoot":"","sources":["../../src/common/arnHelper.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM;;;;;;EASnC"}
@@ -0,0 +1,21 @@
1
+ import { DEFAULT_ACCOUNT_ID, DEFAULT_REGION } from "./types.js";
2
+ export function sqsQueueArn(queueName) {
3
+ return `arn:aws:sqs:${DEFAULT_REGION}:${DEFAULT_ACCOUNT_ID}:${queueName}`;
4
+ }
5
+ export function snsTopicArn(topicName) {
6
+ return `arn:aws:sns:${DEFAULT_REGION}:${DEFAULT_ACCOUNT_ID}:${topicName}`;
7
+ }
8
+ export function snsSubscriptionArn(topicName, id) {
9
+ return `arn:aws:sns:${DEFAULT_REGION}:${DEFAULT_ACCOUNT_ID}:${topicName}:${id}`;
10
+ }
11
+ export function parseArn(arn) {
12
+ const parts = arn.split(":");
13
+ return {
14
+ partition: parts[1],
15
+ service: parts[2],
16
+ region: parts[3],
17
+ accountId: parts[4],
18
+ resource: parts.slice(5).join(":"),
19
+ };
20
+ }
21
+ //# sourceMappingURL=arnHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arnHelper.js","sourceRoot":"","sources":["../../src/common/arnHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEhE,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO,eAAe,cAAc,IAAI,kBAAkB,IAAI,SAAS,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO,eAAe,cAAc,IAAI,kBAAkB,IAAI,SAAS,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,EAAU;IAC9D,OAAO,eAAe,cAAc,IAAI,kBAAkB,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;QACnB,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QACjB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAChB,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;QACnB,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;KACnC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ export declare class SqsError extends Error {
2
+ readonly code: string;
3
+ readonly statusCode: number;
4
+ readonly senderFault: boolean;
5
+ constructor(code: string, message: string, statusCode?: number, senderFault?: boolean);
6
+ toJSON(): {
7
+ __type: string;
8
+ message: string;
9
+ };
10
+ get queryErrorHeader(): string;
11
+ }
12
+ export declare class SnsError extends Error {
13
+ readonly code: string;
14
+ readonly statusCode: number;
15
+ readonly senderFault: boolean;
16
+ constructor(code: string, message: string, statusCode?: number, senderFault?: boolean);
17
+ }
18
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/common/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aAEZ,UAAU,EAAE,MAAM;aAClB,WAAW,EAAE,OAAO;gBAHpB,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,UAAU,GAAE,MAAY,EACxB,WAAW,GAAE,OAAc;IAM7C,MAAM;;;;IAON,IAAI,gBAAgB,IAAI,MAAM,CAG7B;CACF;AAED,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aAEZ,UAAU,EAAE,MAAM;aAClB,WAAW,EAAE,OAAO;gBAHpB,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,UAAU,GAAE,MAAY,EACxB,WAAW,GAAE,OAAc;CAK9C"}
@@ -0,0 +1,35 @@
1
+ export class SqsError extends Error {
2
+ code;
3
+ statusCode;
4
+ senderFault;
5
+ constructor(code, message, statusCode = 400, senderFault = true) {
6
+ super(message);
7
+ this.code = code;
8
+ this.statusCode = statusCode;
9
+ this.senderFault = senderFault;
10
+ this.name = "SqsError";
11
+ }
12
+ toJSON() {
13
+ return {
14
+ __type: `com.amazonaws.sqs#${this.code}`,
15
+ message: this.message,
16
+ };
17
+ }
18
+ get queryErrorHeader() {
19
+ const fault = this.senderFault ? "Sender" : "Receiver";
20
+ return `AWS.SimpleQueueService.${this.code};${fault}`;
21
+ }
22
+ }
23
+ export class SnsError extends Error {
24
+ code;
25
+ statusCode;
26
+ senderFault;
27
+ constructor(code, message, statusCode = 400, senderFault = true) {
28
+ super(message);
29
+ this.code = code;
30
+ this.statusCode = statusCode;
31
+ this.senderFault = senderFault;
32
+ this.name = "SnsError";
33
+ }
34
+ }
35
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/common/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IAEA;IACA;IAJlB,YACkB,IAAY,EAC5B,OAAe,EACC,aAAqB,GAAG,EACxB,cAAuB,IAAI;QAE3C,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAQ;QAEZ,eAAU,GAAV,UAAU,CAAc;QACxB,gBAAW,GAAX,WAAW,CAAgB;QAG3C,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;IAED,MAAM;QACJ,OAAO;YACL,MAAM,EAAE,qBAAqB,IAAI,CAAC,IAAI,EAAE;YACxC,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,gBAAgB;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;QACvD,OAAO,0BAA0B,IAAI,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC;IACxD,CAAC;CACF;AAED,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IAEA;IACA;IAJlB,YACkB,IAAY,EAC5B,OAAe,EACC,aAAqB,GAAG,EACxB,cAAuB,IAAI;QAE3C,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAQ;QAEZ,eAAU,GAAV,UAAU,CAAc;QACxB,gBAAW,GAAX,WAAW,CAAgB;QAG3C,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ export declare function md5(input: string): string;
2
+ export interface MessageAttributeForMd5 {
3
+ DataType: string;
4
+ StringValue?: string;
5
+ BinaryValue?: string;
6
+ }
7
+ export declare function md5OfMessageAttributes(attributes: Record<string, MessageAttributeForMd5>): string;
8
+ //# sourceMappingURL=md5.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"md5.d.ts","sourceRoot":"","sources":["../../src/common/md5.ts"],"names":[],"mappings":"AAEA,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,GACjD,MAAM,CAsCR"}
@@ -0,0 +1,40 @@
1
+ import { createHash } from "node:crypto";
2
+ export function md5(input) {
3
+ return createHash("md5").update(input, "utf-8").digest("hex");
4
+ }
5
+ export function md5OfMessageAttributes(attributes) {
6
+ const names = Object.keys(attributes).sort();
7
+ if (names.length === 0)
8
+ return "";
9
+ const buffers = [];
10
+ for (const name of names) {
11
+ const attr = attributes[name];
12
+ const nameBytes = Buffer.from(name, "utf-8");
13
+ const dataTypeBytes = Buffer.from(attr.DataType, "utf-8");
14
+ // Name: 4-byte length (big-endian) + UTF-8 bytes
15
+ const nameLenBuf = Buffer.alloc(4);
16
+ nameLenBuf.writeUInt32BE(nameBytes.length);
17
+ buffers.push(nameLenBuf, nameBytes);
18
+ // Data type: 4-byte length (big-endian) + UTF-8 bytes
19
+ const dtLenBuf = Buffer.alloc(4);
20
+ dtLenBuf.writeUInt32BE(dataTypeBytes.length);
21
+ buffers.push(dtLenBuf, dataTypeBytes);
22
+ // Transport type + value
23
+ if (attr.DataType.startsWith("String") || attr.DataType.startsWith("Number")) {
24
+ buffers.push(Buffer.from([1]));
25
+ const valueBytes = Buffer.from(attr.StringValue ?? "", "utf-8");
26
+ const valLenBuf = Buffer.alloc(4);
27
+ valLenBuf.writeUInt32BE(valueBytes.length);
28
+ buffers.push(valLenBuf, valueBytes);
29
+ }
30
+ else if (attr.DataType.startsWith("Binary")) {
31
+ buffers.push(Buffer.from([2]));
32
+ const valueBytes = Buffer.from(attr.BinaryValue ?? "", "base64");
33
+ const valLenBuf = Buffer.alloc(4);
34
+ valLenBuf.writeUInt32BE(valueBytes.length);
35
+ buffers.push(valLenBuf, valueBytes);
36
+ }
37
+ }
38
+ return createHash("md5").update(Buffer.concat(buffers)).digest("hex");
39
+ }
40
+ //# sourceMappingURL=md5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"md5.js","sourceRoot":"","sources":["../../src/common/md5.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,GAAG,CAAC,KAAa;IAC/B,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAQD,MAAM,UAAU,sBAAsB,CACpC,UAAkD;IAElD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE1D,iDAAiD;QACjD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAEpC,sDAAsD;QACtD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjC,QAAQ,CAAC,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAEtC,yBAAyB;QACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7E,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;YAChE,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClC,SAAS,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACtC,CAAC;aAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;YACjE,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClC,SAAS,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const DEFAULT_ACCOUNT_ID = "000000000000";
2
+ export declare const DEFAULT_REGION = "us-east-1";
3
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,cAAc,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ export const DEFAULT_ACCOUNT_ID = "000000000000";
2
+ export const DEFAULT_REGION = "us-east-1";
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,cAAc,CAAC;AACjD,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function snsSuccessResponse(action: string, resultBody: string): string;
2
+ export declare function snsErrorResponse(code: string, message: string, type?: "Sender" | "Receiver"): string;
3
+ export declare function escapeXml(str: string): string;
4
+ //# sourceMappingURL=xml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../../src/common/xml.ts"],"names":[],"mappings":"AAIA,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAW7E;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,QAAQ,GAAG,UAAqB,GACrC,MAAM,CAWR;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO7C"}
@@ -0,0 +1,35 @@
1
+ import { randomUUID } from "node:crypto";
2
+ const SNS_XMLNS = "http://sns.amazonaws.com/doc/2010-03-31/";
3
+ export function snsSuccessResponse(action, resultBody) {
4
+ return [
5
+ `<${action}Response xmlns="${SNS_XMLNS}">`,
6
+ ` <${action}Result>`,
7
+ ` ${resultBody}`,
8
+ ` </${action}Result>`,
9
+ ` <ResponseMetadata>`,
10
+ ` <RequestId>${randomUUID()}</RequestId>`,
11
+ ` </ResponseMetadata>`,
12
+ `</${action}Response>`,
13
+ ].join("\n");
14
+ }
15
+ export function snsErrorResponse(code, message, type = "Sender") {
16
+ return [
17
+ `<ErrorResponse xmlns="${SNS_XMLNS}">`,
18
+ ` <Error>`,
19
+ ` <Type>${type}</Type>`,
20
+ ` <Code>${code}</Code>`,
21
+ ` <Message>${escapeXml(message)}</Message>`,
22
+ ` </Error>`,
23
+ ` <RequestId>${randomUUID()}</RequestId>`,
24
+ `</ErrorResponse>`,
25
+ ].join("\n");
26
+ }
27
+ export function escapeXml(str) {
28
+ return str
29
+ .replace(/&/g, "&amp;")
30
+ .replace(/</g, "&lt;")
31
+ .replace(/>/g, "&gt;")
32
+ .replace(/"/g, "&quot;")
33
+ .replace(/'/g, "&apos;");
34
+ }
35
+ //# sourceMappingURL=xml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xml.js","sourceRoot":"","sources":["../../src/common/xml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,SAAS,GAAG,0CAA0C,CAAC;AAE7D,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,UAAkB;IACnE,OAAO;QACL,IAAI,MAAM,mBAAmB,SAAS,IAAI;QAC1C,MAAM,MAAM,SAAS;QACrB,OAAO,UAAU,EAAE;QACnB,OAAO,MAAM,SAAS;QACtB,sBAAsB;QACtB,kBAAkB,UAAU,EAAE,cAAc;QAC5C,uBAAuB;QACvB,KAAK,MAAM,WAAW;KACvB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,OAA8B,QAAQ;IAEtC,OAAO;QACL,yBAAyB,SAAS,IAAI;QACtC,WAAW;QACX,aAAa,IAAI,SAAS;QAC1B,aAAa,IAAI,SAAS;QAC1B,gBAAgB,SAAS,CAAC,OAAO,CAAC,YAAY;QAC9C,YAAY;QACZ,gBAAgB,UAAU,EAAE,cAAc;QAC1C,kBAAkB;KACnB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
package/dist/server.js ADDED
@@ -0,0 +1,3 @@
1
+ import { startFauxqs } from "./app.js";
2
+ startFauxqs({ port: 3000, logger: true });
3
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,WAAW,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SnsStore } from "../snsStore.js";
2
+ export declare function confirmSubscription(params: Record<string, string>, snsStore: SnsStore): string;
3
+ //# sourceMappingURL=confirmSubscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmSubscription.d.ts","sourceRoot":"","sources":["../../../src/sns/actions/confirmSubscription.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,QAAQ,EAAE,QAAQ,GACjB,MAAM,CA6BR"}
@@ -0,0 +1,23 @@
1
+ import { SnsError } from "../../common/errors.js";
2
+ import { snsSuccessResponse, escapeXml } from "../../common/xml.js";
3
+ export function confirmSubscription(params, snsStore) {
4
+ const topicArn = params.TopicArn;
5
+ if (!topicArn) {
6
+ throw new SnsError("InvalidParameter", "TopicArn is required");
7
+ }
8
+ // In our emulator, SQS subscriptions are auto-confirmed.
9
+ // This is a no-op that returns the subscription ARN.
10
+ const topic = snsStore.getTopic(topicArn);
11
+ if (!topic) {
12
+ throw new SnsError("NotFound", "Topic does not exist", 404);
13
+ }
14
+ // Find the subscription for this topic (simplified: return first)
15
+ const subs = snsStore.listSubscriptionsByTopic(topicArn);
16
+ const sub = subs[0];
17
+ if (sub) {
18
+ sub.confirmed = true;
19
+ return snsSuccessResponse("ConfirmSubscription", `<SubscriptionArn>${escapeXml(sub.arn)}</SubscriptionArn>`);
20
+ }
21
+ return snsSuccessResponse("ConfirmSubscription", `<SubscriptionArn>PendingConfirmation</SubscriptionArn>`);
22
+ }
23
+ //# sourceMappingURL=confirmSubscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmSubscription.js","sourceRoot":"","sources":["../../../src/sns/actions/confirmSubscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGpE,MAAM,UAAU,mBAAmB,CACjC,MAA8B,EAC9B,QAAkB;IAElB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;IACjE,CAAC;IAED,yDAAyD;IACzD,qDAAqD;IACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,kEAAkE;IAClE,MAAM,IAAI,GAAG,QAAQ,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEpB,IAAI,GAAG,EAAE,CAAC;QACR,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;QACrB,OAAO,kBAAkB,CACvB,qBAAqB,EACrB,oBAAoB,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAC3D,CAAC;IACJ,CAAC;IAED,OAAO,kBAAkB,CACvB,qBAAqB,EACrB,wDAAwD,CACzD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SnsStore } from "../snsStore.js";
2
+ export declare function createTopic(params: Record<string, string>, snsStore: SnsStore): string;
3
+ //# sourceMappingURL=createTopic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTopic.d.ts","sourceRoot":"","sources":["../../../src/sns/actions/createTopic.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAkER"}