@apipass/sqs-server 0.0.39 → 0.0.41

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.
@@ -1,6 +1,8 @@
1
- import * as SQS from 'aws-sdk/clients/sqs';
1
+ import { type SNSClient } from '@aws-sdk/client-sns';
2
+ import { type SQSClient } from '@aws-sdk/client-sqs';
2
3
  export interface SqsOptions {
3
- endpoint: string;
4
- sqs?: SQS;
5
- autoCreateQueue?: boolean;
4
+ region: string;
5
+ accountId: string;
6
+ sqs?: SQSClient;
7
+ sns?: SNSClient;
6
8
  }
@@ -1,13 +1,18 @@
1
- import { CustomTransportStrategy, Server } from "@nestjs/microservices";
2
- import { SqsOptions } from "./sqs-options.interface";
1
+ import { type CustomTransportStrategy, Server } from '@nestjs/microservices';
2
+ import { type SqsOptions } from './sqs-options.interface';
3
3
  export declare class SQSServer extends Server implements CustomTransportStrategy {
4
4
  private readonly options;
5
- private sqs;
5
+ private readonly sqsClient;
6
+ private readonly snsClient;
6
7
  private consumers;
7
8
  private registeredQueues;
8
9
  constructor(options: SqsOptions);
9
- listen(callback: () => any): any;
10
+ listen(callback: () => any): Promise<any>;
10
11
  private bindHandlers;
12
+ private handle;
13
+ private createAwsResources;
14
+ private createSubscriptionIfNotExists;
15
+ private createTopicIfNotExists;
11
16
  private createQueueIfNotExist;
12
17
  close(): any;
13
18
  }
package/lib/sqs-server.js CHANGED
@@ -24,33 +24,53 @@ exports.SQSServer = void 0;
24
24
  const microservices_1 = require("@nestjs/microservices");
25
25
  const sqs_consumer_1 = require("sqs-consumer");
26
26
  const sqs_context_1 = require("./sqs-context");
27
- const aws = require("aws-sdk");
28
- const sqs = new aws.SQS({ region: 'us-east-1' });
27
+ const client_sqs_1 = require("@aws-sdk/client-sqs");
28
+ const client_sns_1 = require("@aws-sdk/client-sns");
29
29
  class SQSServer extends microservices_1.Server {
30
30
  constructor(options) {
31
+ var _a, _b;
31
32
  super();
32
33
  this.options = options;
33
- this.sqs = this.options.sqs || new aws.SQS();
34
+ this.sqsClient = (_a = this.options.sqs) !== null && _a !== void 0 ? _a : new client_sqs_1.SQSClient();
35
+ this.snsClient = (_b = this.options.sns) !== null && _b !== void 0 ? _b : new client_sns_1.SNSClient();
34
36
  this.consumers = [];
35
37
  this.registeredQueues = [];
36
38
  }
37
39
  listen(callback) {
38
- this.bindHandlers();
39
- callback();
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ yield this.bindHandlers();
42
+ callback();
43
+ });
40
44
  }
41
45
  bindHandlers() {
42
- this.messageHandlers.forEach((handler, queueName) => {
43
- this.createQueueIfNotExist(queueName, this.options);
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ this.messageHandlers.forEach((handler, queueName) => {
48
+ this.handle(handler, queueName)
49
+ .then()
50
+ .catch(reason => {
51
+ console.error(`Error to handle SQS Queue: ${queueName}`, reason);
52
+ });
53
+ });
54
+ });
55
+ }
56
+ handle(handler, queueName) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ const region = this.options.region;
59
+ const accountId = this.options.accountId;
60
+ yield this.createAwsResources(queueName, handler);
44
61
  const queueAlreadyRegistered = this.registeredQueues.includes(queueName);
45
- if (queueAlreadyRegistered)
62
+ if (queueAlreadyRegistered) {
46
63
  return;
64
+ }
47
65
  const app = sqs_consumer_1.Consumer.create({
48
- sqs: this.sqs,
49
- queueUrl: `${this.options.endpoint}/${queueName}`,
66
+ sqs: this.sqsClient,
67
+ queueUrl: `https://sqs.${region}.amazonaws.com/${accountId}/${queueName}`,
50
68
  handleMessage: (message) => __awaiter(this, void 0, void 0, function* () {
51
69
  const { Body } = message, messageMetadata = __rest(message, ["Body"]);
52
70
  const sqsCtx = new sqs_context_1.SQSContext({ queueName, messageMetadata });
53
- yield handler(JSON.parse(Body), sqsCtx);
71
+ if (typeof Body === 'string') {
72
+ yield handler(JSON.parse(Body), sqsCtx);
73
+ }
54
74
  })
55
75
  });
56
76
  app.on('error', (err) => {
@@ -64,28 +84,62 @@ class SQSServer extends microservices_1.Server {
64
84
  this.registeredQueues.push(queueName);
65
85
  });
66
86
  }
67
- createQueueIfNotExist(queueName, options) {
68
- console.log(`AutoCreateQueue: ${options.autoCreateQueue}`);
69
- if (!options.autoCreateQueue) {
70
- return;
71
- }
72
- var params = {
73
- QueueName: queueName,
74
- };
75
- sqs.getQueueUrl(params, function (err, data) {
76
- if (err) {
77
- if (err.code === 'AWS.SimpleQueueService.NonExistentQueue') {
78
- sqs.createQueue(params, function (err, data) {
79
- if (err)
80
- console.log(`Fail on create queue. Error: ${err}`);
81
- else
82
- console.log(`Success on create queue ${queueName}`);
83
- });
87
+ createAwsResources(queueName, handler) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ var _a, _b;
90
+ yield this.createQueueIfNotExist(queueName);
91
+ if ((_a = handler.extras) === null || _a === void 0 ? void 0 : _a.topic) {
92
+ const topicArn = yield this.createTopicIfNotExists((_b = handler.extras) === null || _b === void 0 ? void 0 : _b.topic);
93
+ if (topicArn) {
94
+ yield this.createSubscriptionIfNotExists(topicArn, queueName, handler.extras.filter);
84
95
  }
85
96
  }
86
- else {
87
- console.log(`Queue ${queueName} exist.`);
97
+ });
98
+ }
99
+ createSubscriptionIfNotExists(topicArn, queueName, filter) {
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ const input = {
102
+ TopicArn: topicArn,
103
+ Protocol: 'sqs',
104
+ Endpoint: `arn:aws:sqs:${this.options.region}:${this.options.accountId}:${queueName}`,
105
+ Attributes: {
106
+ RawMessageDelivery: 'true'
107
+ }
108
+ };
109
+ if (filter) {
110
+ input.Attributes.FilterPolicyScope = 'MessageAttributes';
111
+ input.Attributes.FilterPolicy = JSON.stringify(filter);
88
112
  }
113
+ yield this.snsClient.send(new client_sns_1.SubscribeCommand(input));
114
+ });
115
+ }
116
+ createTopicIfNotExists(topicName) {
117
+ return __awaiter(this, void 0, void 0, function* () {
118
+ const input = {
119
+ Name: topicName
120
+ };
121
+ const result = yield this.snsClient.send(new client_sns_1.CreateTopicCommand(input));
122
+ return result.TopicArn;
123
+ });
124
+ }
125
+ createQueueIfNotExist(queueName) {
126
+ return __awaiter(this, void 0, void 0, function* () {
127
+ const params = {
128
+ QueueName: queueName,
129
+ Attributes: {
130
+ Policy: JSON.stringify({
131
+ Statement: [{
132
+ Effect: 'Allow',
133
+ Principal: {
134
+ Service: 'sns.amazonaws.com'
135
+ },
136
+ Action: 'SQS:SendMessage',
137
+ Resource: `arn:aws:sqs:${this.options.region}:${this.options.accountId}:${queueName}`
138
+ }]
139
+ })
140
+ }
141
+ };
142
+ yield this.sqsClient.send(new client_sqs_1.CreateQueueCommand(params));
89
143
  });
90
144
  }
91
145
  close() {
@@ -1 +1 @@
1
- {"version":3,"file":"sqs-server.js","sourceRoot":"","sources":["../src/sqs-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqs-server.js","sourceRoot":"","sources":["../src/sqs-server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apipass/sqs-server",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "> TODO: description",
5
5
  "author": "Alexandre Zanelatto <alexandre@apipass.com.br>",
6
6
  "license": "ISC",
@@ -11,7 +11,8 @@
11
11
  "test": "__tests__"
12
12
  },
13
13
  "dependencies": {
14
- "sqs-consumer": "5.7.0"
14
+ "@aws-sdk/client-sns": "3.666.0",
15
+ "sqs-consumer": "11.1.0"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@nestjs/microservices": "9.2.1"
@@ -26,5 +27,5 @@
26
27
  "tsc": "tsc",
27
28
  "test": "node ./__tests__/@apipass/sqs-server.test.js"
28
29
  },
29
- "gitHead": "922e078a7dc86af67296cde18dccae08491f796c"
30
+ "gitHead": "89f71a0e9ea46ce8a8eabdccde105f5011b0c37b"
30
31
  }