@geekmidas/events 10.0.0-alpha.71 → 10.0.0-alpha.72
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.
- package/README.md +46 -1
- package/dist/basic/index.cjs +19 -0
- package/dist/basic/index.cjs.map +1 -1
- package/dist/basic/index.d.cts +8 -1
- package/dist/basic/index.d.cts.map +1 -1
- package/dist/basic/index.d.mts +8 -1
- package/dist/basic/index.d.mts.map +1 -1
- package/dist/basic/index.mjs +19 -1
- package/dist/basic/index.mjs.map +1 -1
- package/dist/index.cjs +33 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -33
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +15 -33
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +30 -138
- package/dist/index.mjs.map +1 -1
- package/dist/pgboss/index.cjs +38 -21
- package/dist/pgboss/index.cjs.map +1 -1
- package/dist/pgboss/index.d.cts +9 -1
- package/dist/pgboss/index.d.cts.map +1 -1
- package/dist/pgboss/index.d.mts +9 -1
- package/dist/pgboss/index.d.mts.map +1 -1
- package/dist/pgboss/index.mjs +38 -21
- package/dist/pgboss/index.mjs.map +1 -1
- package/dist/rabbitmq/index.cjs +28 -12
- package/dist/rabbitmq/index.cjs.map +1 -1
- package/dist/rabbitmq/index.d.cts +9 -1
- package/dist/rabbitmq/index.d.cts.map +1 -1
- package/dist/rabbitmq/index.d.mts +9 -1
- package/dist/rabbitmq/index.d.mts.map +1 -1
- package/dist/rabbitmq/index.mjs +29 -12
- package/dist/rabbitmq/index.mjs.map +1 -1
- package/dist/{types-gGaoT8qc.d.cts → registry-DIx25Q5s.d.cts} +108 -2
- package/dist/registry-DIx25Q5s.d.cts.map +1 -0
- package/dist/{types-gGaoT8qc.d.mts → registry-DIx25Q5s.d.mts} +108 -2
- package/dist/registry-DIx25Q5s.d.mts.map +1 -0
- package/dist/registry-DLnflkMm.mjs +99 -0
- package/dist/registry-DLnflkMm.mjs.map +1 -0
- package/dist/registry-DNk5GnGq.cjs +122 -0
- package/dist/registry-DNk5GnGq.cjs.map +1 -0
- package/dist/sns/index.cjs +261 -244
- package/dist/sns/index.cjs.map +1 -1
- package/dist/sns/index.d.cts +9 -1
- package/dist/sns/index.d.cts.map +1 -1
- package/dist/sns/index.d.mts +9 -1
- package/dist/sns/index.d.mts.map +1 -1
- package/dist/sns/index.mjs +261 -244
- package/dist/sns/index.mjs.map +1 -1
- package/dist/sqs/index.cjs +21 -0
- package/dist/sqs/index.cjs.map +1 -1
- package/dist/sqs/index.d.cts +9 -1
- package/dist/sqs/index.d.cts.map +1 -1
- package/dist/sqs/index.d.mts +9 -1
- package/dist/sqs/index.d.mts.map +1 -1
- package/dist/sqs/index.mjs +21 -1
- package/dist/sqs/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/PgBossConnection-CywKoAZU.cjs +0 -2
- package/dist/PgBossConnection-DjoqT84r.mjs +0 -2
- package/dist/RabbitMQConnection-C9eccBL8.cjs +0 -2
- package/dist/RabbitMQConnection-CAp7VqyT.mjs +0 -2
- package/dist/SNSConnection-BWDC1wAF.cjs +0 -2
- package/dist/SNSConnection-ezQvVrDv.mjs +0 -2
- package/dist/types-gGaoT8qc.d.cts.map +0 -1
- package/dist/types-gGaoT8qc.d.mts.map +0 -1
package/dist/sns/index.mjs
CHANGED
|
@@ -1,9 +1,268 @@
|
|
|
1
|
+
import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
|
|
1
2
|
import "../types-Bk5JM6MP.mjs";
|
|
2
3
|
import { n as SQSConnection, t as SQSSubscriber } from "../SQSSubscriber-BXLE_1L3.mjs";
|
|
3
4
|
import { parse, t as snsUrl_exports } from "./snsUrl.mjs";
|
|
4
5
|
import { CreateQueueCommand, DeleteQueueCommand, GetQueueAttributesCommand, SQSClient, SetQueueAttributesCommand } from "@aws-sdk/client-sqs";
|
|
5
|
-
import { createVerify } from "node:crypto";
|
|
6
6
|
import { GetSubscriptionAttributesCommand, ListSubscriptionsByTopicCommand, PublishCommand, SNSClient, SetSubscriptionAttributesCommand, SubscribeCommand, UnsubscribeCommand } from "@aws-sdk/client-sns";
|
|
7
|
+
import { createVerify } from "node:crypto";
|
|
8
|
+
//#region src/sns/SNSConnection.ts
|
|
9
|
+
var SNSConnection_exports = /* @__PURE__ */ __exportAll({ SNSConnection: () => SNSConnection });
|
|
10
|
+
var SNSConnection = class SNSConnection {
|
|
11
|
+
type = "sns";
|
|
12
|
+
client;
|
|
13
|
+
connected = false;
|
|
14
|
+
config;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
const clientConfig = {
|
|
18
|
+
region: config.region,
|
|
19
|
+
endpoint: config.endpoint,
|
|
20
|
+
credentials: config.credentials
|
|
21
|
+
};
|
|
22
|
+
this.client = new SNSClient(clientConfig);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create an SNSConnection from a connection string
|
|
26
|
+
* Format: sns://?topicArn=arn:aws:sns:region:account:topic®ion=us-east-1&endpoint=http://localhost:4566
|
|
27
|
+
*/
|
|
28
|
+
static async fromConnectionString(connectionString) {
|
|
29
|
+
const { topicArn, region, endpoint } = parse(connectionString);
|
|
30
|
+
const params = new URL(connectionString).searchParams;
|
|
31
|
+
const config = {
|
|
32
|
+
topicArn,
|
|
33
|
+
region,
|
|
34
|
+
endpoint
|
|
35
|
+
};
|
|
36
|
+
const accessKeyId = params.get("accessKeyId");
|
|
37
|
+
const secretAccessKey = params.get("secretAccessKey");
|
|
38
|
+
if (accessKeyId && secretAccessKey) config.credentials = {
|
|
39
|
+
accessKeyId,
|
|
40
|
+
secretAccessKey,
|
|
41
|
+
sessionToken: params.get("sessionToken") || void 0
|
|
42
|
+
};
|
|
43
|
+
const connection = new SNSConnection(config);
|
|
44
|
+
await connection.connect();
|
|
45
|
+
return connection;
|
|
46
|
+
}
|
|
47
|
+
async connect() {
|
|
48
|
+
this.connected = true;
|
|
49
|
+
}
|
|
50
|
+
async close() {
|
|
51
|
+
this.client.destroy();
|
|
52
|
+
this.connected = false;
|
|
53
|
+
}
|
|
54
|
+
isConnected() {
|
|
55
|
+
return this.connected;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the underlying SNS client
|
|
59
|
+
*/
|
|
60
|
+
get snsClient() {
|
|
61
|
+
return this.client;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the topic ARN for this connection
|
|
65
|
+
*/
|
|
66
|
+
get topicArn() {
|
|
67
|
+
return this.config.topicArn;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/sns/SNSPublisher.ts
|
|
72
|
+
var SNSPublisher = class SNSPublisher {
|
|
73
|
+
connection;
|
|
74
|
+
constructor(connection, _options = {}) {
|
|
75
|
+
this.connection = connection;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Create an SNSPublisher from a connection string
|
|
79
|
+
* Format: sns://?topicArn=arn:aws:sns:region:account:topic®ion=us-east-1&endpoint=http://localhost:4566
|
|
80
|
+
*/
|
|
81
|
+
static async fromConnectionString(connectionString) {
|
|
82
|
+
const { SNSConnection } = await Promise.resolve().then(() => SNSConnection_exports);
|
|
83
|
+
const connection = await SNSConnection.fromConnectionString(connectionString);
|
|
84
|
+
return new SNSPublisher(connection);
|
|
85
|
+
}
|
|
86
|
+
async publish(messages) {
|
|
87
|
+
if (messages.length === 0) return;
|
|
88
|
+
if (!this.connection.isConnected()) await this.connection.connect();
|
|
89
|
+
await Promise.all(messages.map((message) => this.publishMessage(message)));
|
|
90
|
+
}
|
|
91
|
+
async publishMessage(message) {
|
|
92
|
+
const command = new PublishCommand({
|
|
93
|
+
TopicArn: this.connection.topicArn,
|
|
94
|
+
Message: JSON.stringify({
|
|
95
|
+
type: message.type,
|
|
96
|
+
payload: message.payload
|
|
97
|
+
}),
|
|
98
|
+
MessageAttributes: { type: {
|
|
99
|
+
DataType: "String",
|
|
100
|
+
StringValue: message.type
|
|
101
|
+
} }
|
|
102
|
+
});
|
|
103
|
+
await this.connection.snsClient.send(command);
|
|
104
|
+
}
|
|
105
|
+
async close() {}
|
|
106
|
+
};
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/sns/SNSSubscriber.ts
|
|
109
|
+
/**
|
|
110
|
+
* SNS Subscriber - receives push-based messages from SNS via SQS queue
|
|
111
|
+
*
|
|
112
|
+
* Architecture:
|
|
113
|
+
* SNS Topic → (push) → SQS Queue → Subscriber
|
|
114
|
+
*
|
|
115
|
+
* This subscriber automatically:
|
|
116
|
+
* 1. Creates an SQS queue (or uses existing one)
|
|
117
|
+
* 2. Subscribes the queue to the SNS topic
|
|
118
|
+
* 3. Receives messages pushed from SNS to the queue
|
|
119
|
+
* 4. Filters messages by topic ARN and message type
|
|
120
|
+
* 5. Processes and acknowledges messages
|
|
121
|
+
*
|
|
122
|
+
* Note: While SQS long-polling is used internally to receive messages,
|
|
123
|
+
* this is an implementation detail of the SNS push delivery mechanism.
|
|
124
|
+
* Messages are pushed from SNS to SQS, and we receive those pushed messages.
|
|
125
|
+
*/
|
|
126
|
+
var SNSSubscriber = class SNSSubscriber {
|
|
127
|
+
connection;
|
|
128
|
+
sqsClient;
|
|
129
|
+
queueUrl;
|
|
130
|
+
queueArn;
|
|
131
|
+
subscriptionArn;
|
|
132
|
+
sqsSubscriber;
|
|
133
|
+
options;
|
|
134
|
+
constructor(connection, options = {}) {
|
|
135
|
+
this.connection = connection;
|
|
136
|
+
this.options = {
|
|
137
|
+
queueName: options.queueName || `sns-sub-${Date.now()}-${Math.random().toString(36).substring(7)}`,
|
|
138
|
+
createQueue: options.createQueue ?? true,
|
|
139
|
+
deleteQueueOnClose: options.deleteQueueOnClose ?? !options.queueName,
|
|
140
|
+
waitTimeSeconds: options.waitTimeSeconds ?? 20,
|
|
141
|
+
maxMessages: options.maxMessages ?? 10
|
|
142
|
+
};
|
|
143
|
+
this.sqsClient = new SQSClient({
|
|
144
|
+
region: this.connection.config.region,
|
|
145
|
+
endpoint: this.connection.config.endpoint,
|
|
146
|
+
credentials: this.connection.config.credentials
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Create an SNSSubscriber from a connection string
|
|
151
|
+
* Format: sns://?topicArn=...&queueName=myqueue®ion=us-east-1
|
|
152
|
+
*/
|
|
153
|
+
static async fromConnectionString(connectionString) {
|
|
154
|
+
const params = new URL(connectionString).searchParams;
|
|
155
|
+
const { SNSConnection } = await Promise.resolve().then(() => SNSConnection_exports);
|
|
156
|
+
const connection = await SNSConnection.fromConnectionString(connectionString);
|
|
157
|
+
const options = {
|
|
158
|
+
queueName: params.get("queueName") || void 0,
|
|
159
|
+
createQueue: params.get("createQueue") !== "false",
|
|
160
|
+
deleteQueueOnClose: params.get("deleteQueueOnClose") === "true",
|
|
161
|
+
waitTimeSeconds: params.get("waitTimeSeconds") ? Number.parseInt(params.get("waitTimeSeconds"), 10) : void 0
|
|
162
|
+
};
|
|
163
|
+
return new SNSSubscriber(connection, options);
|
|
164
|
+
}
|
|
165
|
+
async subscribe(messages, listener) {
|
|
166
|
+
await this.setupQueue();
|
|
167
|
+
await this.subscribeToTopic();
|
|
168
|
+
const sqsConnection = new SQSConnection({
|
|
169
|
+
queueUrl: this.queueUrl,
|
|
170
|
+
region: this.connection.config.region,
|
|
171
|
+
endpoint: this.connection.config.endpoint,
|
|
172
|
+
credentials: this.connection.config.credentials
|
|
173
|
+
});
|
|
174
|
+
await sqsConnection.connect();
|
|
175
|
+
this.sqsSubscriber = new SQSSubscriber(sqsConnection, {
|
|
176
|
+
waitTimeSeconds: this.options.waitTimeSeconds,
|
|
177
|
+
maxMessages: this.options.maxMessages,
|
|
178
|
+
expectedTopicArn: this.connection.topicArn
|
|
179
|
+
});
|
|
180
|
+
await this.sqsSubscriber.subscribe(messages, listener);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Stop receiving messages and clean up resources
|
|
184
|
+
*/
|
|
185
|
+
async stop() {
|
|
186
|
+
if (this.sqsSubscriber) this.sqsSubscriber.stop();
|
|
187
|
+
if (this.subscriptionArn) try {
|
|
188
|
+
const command = new UnsubscribeCommand({ SubscriptionArn: this.subscriptionArn });
|
|
189
|
+
await this.connection.snsClient.send(command);
|
|
190
|
+
} catch (_error) {}
|
|
191
|
+
if (this.queueUrl && this.options.deleteQueueOnClose) try {
|
|
192
|
+
const command = new DeleteQueueCommand({ QueueUrl: this.queueUrl });
|
|
193
|
+
await this.sqsClient.send(command);
|
|
194
|
+
} catch (_error) {}
|
|
195
|
+
this.sqsClient.destroy();
|
|
196
|
+
}
|
|
197
|
+
async setupQueue() {
|
|
198
|
+
if (this.options.createQueue) {
|
|
199
|
+
const createCommand = new CreateQueueCommand({ QueueName: this.options.queueName });
|
|
200
|
+
const response = await this.sqsClient.send(createCommand);
|
|
201
|
+
this.queueUrl = response.QueueUrl;
|
|
202
|
+
} else throw new SnsQueueMissing(this.options.queueName);
|
|
203
|
+
const attrsCommand = new GetQueueAttributesCommand({
|
|
204
|
+
QueueUrl: this.queueUrl,
|
|
205
|
+
AttributeNames: ["QueueArn"]
|
|
206
|
+
});
|
|
207
|
+
const attrsResponse = await this.sqsClient.send(attrsCommand);
|
|
208
|
+
this.queueArn = attrsResponse.Attributes?.QueueArn;
|
|
209
|
+
await this.setQueuePolicy();
|
|
210
|
+
}
|
|
211
|
+
async setQueuePolicy() {
|
|
212
|
+
const policy = {
|
|
213
|
+
Version: "2012-10-17",
|
|
214
|
+
Statement: [{
|
|
215
|
+
Effect: "Allow",
|
|
216
|
+
Principal: "*",
|
|
217
|
+
Action: "SQS:SendMessage",
|
|
218
|
+
Resource: this.queueArn,
|
|
219
|
+
Condition: { ArnEquals: { "aws:SourceArn": this.connection.topicArn } }
|
|
220
|
+
}]
|
|
221
|
+
};
|
|
222
|
+
const command = new SetQueueAttributesCommand({
|
|
223
|
+
QueueUrl: this.queueUrl,
|
|
224
|
+
Attributes: { Policy: JSON.stringify(policy) }
|
|
225
|
+
});
|
|
226
|
+
await this.sqsClient.send(command);
|
|
227
|
+
}
|
|
228
|
+
async subscribeToTopic() {
|
|
229
|
+
const command = new SubscribeCommand({
|
|
230
|
+
TopicArn: this.connection.topicArn,
|
|
231
|
+
Protocol: "sqs",
|
|
232
|
+
Endpoint: this.queueArn
|
|
233
|
+
});
|
|
234
|
+
const response = await this.connection.snsClient.send(command);
|
|
235
|
+
this.subscriptionArn = response.SubscriptionArn;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* A subscriber asked to use a queue it may not create. The SQS queue behind an
|
|
240
|
+
* SNS subscription has to exist first, or `createQueue` has to allow it.
|
|
241
|
+
*/
|
|
242
|
+
var SnsQueueMissing = class extends Error {
|
|
243
|
+
queueName;
|
|
244
|
+
constructor(queueName) {
|
|
245
|
+
super(`The SNS subscriber's queue${queueName ? ` "${queueName}"` : ""} is not created here: pass createQueue: true, or create the queue first.`);
|
|
246
|
+
this.queueName = queueName;
|
|
247
|
+
this.name = "SnsQueueMissing";
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/sns/driver.ts
|
|
252
|
+
/**
|
|
253
|
+
* `sns://` — an SNS topic, consumed through an SQS queue subscribed to it.
|
|
254
|
+
* Register it with `registerEventsDriver(snsEventsDriver)`; an AWS entry
|
|
255
|
+
* registers `sqsEventsDriver` beside it.
|
|
256
|
+
*/
|
|
257
|
+
const snsEventsDriver = {
|
|
258
|
+
scheme: "sns",
|
|
259
|
+
connect: (url) => SNSConnection.fromConnectionString(url),
|
|
260
|
+
publisher: (url) => SNSPublisher.fromConnectionString(url),
|
|
261
|
+
publisherFor: (connection) => new SNSPublisher(connection),
|
|
262
|
+
subscriber: (url) => SNSSubscriber.fromConnectionString(url),
|
|
263
|
+
subscriberFor: (connection) => new SNSSubscriber(connection)
|
|
264
|
+
};
|
|
265
|
+
//#endregion
|
|
7
266
|
//#region src/sns/push.ts
|
|
8
267
|
/** The fields signed, in the order SNS signs them, per message type. */
|
|
9
268
|
const SIGNED_FIELDS = {
|
|
@@ -255,248 +514,6 @@ var SnsEndpointNotHttp = class extends Error {
|
|
|
255
514
|
}
|
|
256
515
|
};
|
|
257
516
|
//#endregion
|
|
258
|
-
|
|
259
|
-
var SNSConnection = class SNSConnection {
|
|
260
|
-
type = "sns";
|
|
261
|
-
client;
|
|
262
|
-
connected = false;
|
|
263
|
-
config;
|
|
264
|
-
constructor(config) {
|
|
265
|
-
this.config = config;
|
|
266
|
-
const clientConfig = {
|
|
267
|
-
region: config.region,
|
|
268
|
-
endpoint: config.endpoint,
|
|
269
|
-
credentials: config.credentials
|
|
270
|
-
};
|
|
271
|
-
this.client = new SNSClient(clientConfig);
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Create an SNSConnection from a connection string
|
|
275
|
-
* Format: sns://?topicArn=arn:aws:sns:region:account:topic®ion=us-east-1&endpoint=http://localhost:4566
|
|
276
|
-
*/
|
|
277
|
-
static async fromConnectionString(connectionString) {
|
|
278
|
-
const { topicArn, region, endpoint } = parse(connectionString);
|
|
279
|
-
const params = new URL(connectionString).searchParams;
|
|
280
|
-
const config = {
|
|
281
|
-
topicArn,
|
|
282
|
-
region,
|
|
283
|
-
endpoint
|
|
284
|
-
};
|
|
285
|
-
const accessKeyId = params.get("accessKeyId");
|
|
286
|
-
const secretAccessKey = params.get("secretAccessKey");
|
|
287
|
-
if (accessKeyId && secretAccessKey) config.credentials = {
|
|
288
|
-
accessKeyId,
|
|
289
|
-
secretAccessKey,
|
|
290
|
-
sessionToken: params.get("sessionToken") || void 0
|
|
291
|
-
};
|
|
292
|
-
const connection = new SNSConnection(config);
|
|
293
|
-
await connection.connect();
|
|
294
|
-
return connection;
|
|
295
|
-
}
|
|
296
|
-
async connect() {
|
|
297
|
-
this.connected = true;
|
|
298
|
-
}
|
|
299
|
-
async close() {
|
|
300
|
-
this.client.destroy();
|
|
301
|
-
this.connected = false;
|
|
302
|
-
}
|
|
303
|
-
isConnected() {
|
|
304
|
-
return this.connected;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Get the underlying SNS client
|
|
308
|
-
*/
|
|
309
|
-
get snsClient() {
|
|
310
|
-
return this.client;
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Get the topic ARN for this connection
|
|
314
|
-
*/
|
|
315
|
-
get topicArn() {
|
|
316
|
-
return this.config.topicArn;
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
//#endregion
|
|
320
|
-
//#region src/sns/SNSPublisher.ts
|
|
321
|
-
var SNSPublisher = class SNSPublisher {
|
|
322
|
-
connection;
|
|
323
|
-
constructor(connection, _options = {}) {
|
|
324
|
-
this.connection = connection;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Create an SNSPublisher from a connection string
|
|
328
|
-
* Format: sns://?topicArn=arn:aws:sns:region:account:topic®ion=us-east-1&endpoint=http://localhost:4566
|
|
329
|
-
*/
|
|
330
|
-
static async fromConnectionString(connectionString) {
|
|
331
|
-
const { SNSConnection } = await import("../SNSConnection-ezQvVrDv.mjs");
|
|
332
|
-
const connection = await SNSConnection.fromConnectionString(connectionString);
|
|
333
|
-
return new SNSPublisher(connection);
|
|
334
|
-
}
|
|
335
|
-
async publish(messages) {
|
|
336
|
-
if (messages.length === 0) return;
|
|
337
|
-
if (!this.connection.isConnected()) await this.connection.connect();
|
|
338
|
-
await Promise.all(messages.map((message) => this.publishMessage(message)));
|
|
339
|
-
}
|
|
340
|
-
async publishMessage(message) {
|
|
341
|
-
const command = new PublishCommand({
|
|
342
|
-
TopicArn: this.connection.topicArn,
|
|
343
|
-
Message: JSON.stringify({
|
|
344
|
-
type: message.type,
|
|
345
|
-
payload: message.payload
|
|
346
|
-
}),
|
|
347
|
-
MessageAttributes: { type: {
|
|
348
|
-
DataType: "String",
|
|
349
|
-
StringValue: message.type
|
|
350
|
-
} }
|
|
351
|
-
});
|
|
352
|
-
await this.connection.snsClient.send(command);
|
|
353
|
-
}
|
|
354
|
-
async close() {}
|
|
355
|
-
};
|
|
356
|
-
//#endregion
|
|
357
|
-
//#region src/sns/SNSSubscriber.ts
|
|
358
|
-
/**
|
|
359
|
-
* SNS Subscriber - receives push-based messages from SNS via SQS queue
|
|
360
|
-
*
|
|
361
|
-
* Architecture:
|
|
362
|
-
* SNS Topic → (push) → SQS Queue → Subscriber
|
|
363
|
-
*
|
|
364
|
-
* This subscriber automatically:
|
|
365
|
-
* 1. Creates an SQS queue (or uses existing one)
|
|
366
|
-
* 2. Subscribes the queue to the SNS topic
|
|
367
|
-
* 3. Receives messages pushed from SNS to the queue
|
|
368
|
-
* 4. Filters messages by topic ARN and message type
|
|
369
|
-
* 5. Processes and acknowledges messages
|
|
370
|
-
*
|
|
371
|
-
* Note: While SQS long-polling is used internally to receive messages,
|
|
372
|
-
* this is an implementation detail of the SNS push delivery mechanism.
|
|
373
|
-
* Messages are pushed from SNS to SQS, and we receive those pushed messages.
|
|
374
|
-
*/
|
|
375
|
-
var SNSSubscriber = class SNSSubscriber {
|
|
376
|
-
connection;
|
|
377
|
-
sqsClient;
|
|
378
|
-
queueUrl;
|
|
379
|
-
queueArn;
|
|
380
|
-
subscriptionArn;
|
|
381
|
-
sqsSubscriber;
|
|
382
|
-
options;
|
|
383
|
-
constructor(connection, options = {}) {
|
|
384
|
-
this.connection = connection;
|
|
385
|
-
this.options = {
|
|
386
|
-
queueName: options.queueName || `sns-sub-${Date.now()}-${Math.random().toString(36).substring(7)}`,
|
|
387
|
-
createQueue: options.createQueue ?? true,
|
|
388
|
-
deleteQueueOnClose: options.deleteQueueOnClose ?? !options.queueName,
|
|
389
|
-
waitTimeSeconds: options.waitTimeSeconds ?? 20,
|
|
390
|
-
maxMessages: options.maxMessages ?? 10
|
|
391
|
-
};
|
|
392
|
-
this.sqsClient = new SQSClient({
|
|
393
|
-
region: this.connection.config.region,
|
|
394
|
-
endpoint: this.connection.config.endpoint,
|
|
395
|
-
credentials: this.connection.config.credentials
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Create an SNSSubscriber from a connection string
|
|
400
|
-
* Format: sns://?topicArn=...&queueName=myqueue®ion=us-east-1
|
|
401
|
-
*/
|
|
402
|
-
static async fromConnectionString(connectionString) {
|
|
403
|
-
const params = new URL(connectionString).searchParams;
|
|
404
|
-
const { SNSConnection } = await import("../SNSConnection-ezQvVrDv.mjs");
|
|
405
|
-
const connection = await SNSConnection.fromConnectionString(connectionString);
|
|
406
|
-
const options = {
|
|
407
|
-
queueName: params.get("queueName") || void 0,
|
|
408
|
-
createQueue: params.get("createQueue") !== "false",
|
|
409
|
-
deleteQueueOnClose: params.get("deleteQueueOnClose") === "true",
|
|
410
|
-
waitTimeSeconds: params.get("waitTimeSeconds") ? Number.parseInt(params.get("waitTimeSeconds"), 10) : void 0
|
|
411
|
-
};
|
|
412
|
-
return new SNSSubscriber(connection, options);
|
|
413
|
-
}
|
|
414
|
-
async subscribe(messages, listener) {
|
|
415
|
-
await this.setupQueue();
|
|
416
|
-
await this.subscribeToTopic();
|
|
417
|
-
const sqsConnection = new SQSConnection({
|
|
418
|
-
queueUrl: this.queueUrl,
|
|
419
|
-
region: this.connection.config.region,
|
|
420
|
-
endpoint: this.connection.config.endpoint,
|
|
421
|
-
credentials: this.connection.config.credentials
|
|
422
|
-
});
|
|
423
|
-
await sqsConnection.connect();
|
|
424
|
-
this.sqsSubscriber = new SQSSubscriber(sqsConnection, {
|
|
425
|
-
waitTimeSeconds: this.options.waitTimeSeconds,
|
|
426
|
-
maxMessages: this.options.maxMessages,
|
|
427
|
-
expectedTopicArn: this.connection.topicArn
|
|
428
|
-
});
|
|
429
|
-
await this.sqsSubscriber.subscribe(messages, listener);
|
|
430
|
-
}
|
|
431
|
-
/**
|
|
432
|
-
* Stop receiving messages and clean up resources
|
|
433
|
-
*/
|
|
434
|
-
async stop() {
|
|
435
|
-
if (this.sqsSubscriber) this.sqsSubscriber.stop();
|
|
436
|
-
if (this.subscriptionArn) try {
|
|
437
|
-
const command = new UnsubscribeCommand({ SubscriptionArn: this.subscriptionArn });
|
|
438
|
-
await this.connection.snsClient.send(command);
|
|
439
|
-
} catch (_error) {}
|
|
440
|
-
if (this.queueUrl && this.options.deleteQueueOnClose) try {
|
|
441
|
-
const command = new DeleteQueueCommand({ QueueUrl: this.queueUrl });
|
|
442
|
-
await this.sqsClient.send(command);
|
|
443
|
-
} catch (_error) {}
|
|
444
|
-
this.sqsClient.destroy();
|
|
445
|
-
}
|
|
446
|
-
async setupQueue() {
|
|
447
|
-
if (this.options.createQueue) {
|
|
448
|
-
const createCommand = new CreateQueueCommand({ QueueName: this.options.queueName });
|
|
449
|
-
const response = await this.sqsClient.send(createCommand);
|
|
450
|
-
this.queueUrl = response.QueueUrl;
|
|
451
|
-
} else throw new SnsQueueMissing(this.options.queueName);
|
|
452
|
-
const attrsCommand = new GetQueueAttributesCommand({
|
|
453
|
-
QueueUrl: this.queueUrl,
|
|
454
|
-
AttributeNames: ["QueueArn"]
|
|
455
|
-
});
|
|
456
|
-
const attrsResponse = await this.sqsClient.send(attrsCommand);
|
|
457
|
-
this.queueArn = attrsResponse.Attributes?.QueueArn;
|
|
458
|
-
await this.setQueuePolicy();
|
|
459
|
-
}
|
|
460
|
-
async setQueuePolicy() {
|
|
461
|
-
const policy = {
|
|
462
|
-
Version: "2012-10-17",
|
|
463
|
-
Statement: [{
|
|
464
|
-
Effect: "Allow",
|
|
465
|
-
Principal: "*",
|
|
466
|
-
Action: "SQS:SendMessage",
|
|
467
|
-
Resource: this.queueArn,
|
|
468
|
-
Condition: { ArnEquals: { "aws:SourceArn": this.connection.topicArn } }
|
|
469
|
-
}]
|
|
470
|
-
};
|
|
471
|
-
const command = new SetQueueAttributesCommand({
|
|
472
|
-
QueueUrl: this.queueUrl,
|
|
473
|
-
Attributes: { Policy: JSON.stringify(policy) }
|
|
474
|
-
});
|
|
475
|
-
await this.sqsClient.send(command);
|
|
476
|
-
}
|
|
477
|
-
async subscribeToTopic() {
|
|
478
|
-
const command = new SubscribeCommand({
|
|
479
|
-
TopicArn: this.connection.topicArn,
|
|
480
|
-
Protocol: "sqs",
|
|
481
|
-
Endpoint: this.queueArn
|
|
482
|
-
});
|
|
483
|
-
const response = await this.connection.snsClient.send(command);
|
|
484
|
-
this.subscriptionArn = response.SubscriptionArn;
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
/**
|
|
488
|
-
* A subscriber asked to use a queue it may not create. The SQS queue behind an
|
|
489
|
-
* SNS subscription has to exist first, or `createQueue` has to allow it.
|
|
490
|
-
*/
|
|
491
|
-
var SnsQueueMissing = class extends Error {
|
|
492
|
-
queueName;
|
|
493
|
-
constructor(queueName) {
|
|
494
|
-
super(`The SNS subscriber's queue${queueName ? ` "${queueName}"` : ""} is not created here: pass createQueue: true, or create the queue first.`);
|
|
495
|
-
this.queueName = queueName;
|
|
496
|
-
this.name = "SnsQueueMissing";
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
//#endregion
|
|
500
|
-
export { SNSConnection, SNSPublisher, SNSSubscriber, SnsCertificateUnavailable, SnsCertificateUntrusted, SnsConfirmationFailed, SnsEndpointNotHttp, SnsMessageTypeUnknown, SnsNotAConfirmation, SnsQueueMissing, SnsSignatureInvalid, SnsSignatureVersionUnknown, confirmSnsSubscription, snsStringToSign, snsUrl_exports as snsUrl, subscribeHttpEndpoint, toSnsEvent, verifySnsMessage };
|
|
517
|
+
export { SNSConnection, SNSPublisher, SNSSubscriber, SnsCertificateUnavailable, SnsCertificateUntrusted, SnsConfirmationFailed, SnsEndpointNotHttp, SnsMessageTypeUnknown, SnsNotAConfirmation, SnsQueueMissing, SnsSignatureInvalid, SnsSignatureVersionUnknown, confirmSnsSubscription, snsEventsDriver, snsStringToSign, snsUrl_exports as snsUrl, subscribeHttpEndpoint, toSnsEvent, verifySnsMessage };
|
|
501
518
|
|
|
502
519
|
//# sourceMappingURL=index.mjs.map
|