sqs-producer 6.0.2-canary.2 → 7.0.0-canary.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.
- package/CHANGELOG.md +1 -5
- package/README.md +31 -31
- package/dist/{errors.js → cjs/errors.js} +1 -1
- package/dist/{format.d.ts → cjs/format.d.ts} +2 -2
- package/dist/{format.js → cjs/format.js} +17 -17
- package/dist/cjs/index.d.ts +2 -0
- package/dist/{index.js → cjs/index.js} +3 -3
- package/dist/cjs/package.json +1 -0
- package/dist/{producer.d.ts → cjs/producer.d.ts} +2 -2
- package/dist/{producer.js → cjs/producer.js} +14 -12
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/{types.d.ts → cjs/types.d.ts} +1 -1
- package/dist/{validation.js → cjs/validation.js} +4 -4
- package/dist/esm/errors.d.ts +11 -0
- package/dist/esm/errors.js +12 -0
- package/dist/esm/format.d.ts +8 -0
- package/dist/esm/format.js +79 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/producer.d.ts +40 -0
- package/dist/esm/producer.js +97 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/esm/types.d.ts +65 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/validation.d.ts +15 -0
- package/dist/esm/validation.js +27 -0
- package/package.json +49 -54
- package/src/errors.ts +1 -1
- package/src/format.ts +14 -13
- package/src/index.ts +2 -2
- package/src/producer.ts +19 -18
- package/src/types.ts +1 -1
- package/src/validation.ts +4 -4
- package/tsconfig.cjs.json +10 -0
- package/tsconfig.esm.json +10 -0
- package/tsconfig.json +6 -5
- package/.github/CODEOWNERS +0 -2
- package/.github/CODE_OF_CONDUCT.md +0 -74
- package/.github/CONTRIBUTING.md +0 -51
- package/.github/ISSUE_TEMPLATE/bug-report.yml +0 -115
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/SECURITY.md +0 -9
- package/.github/pull_request_template.md +0 -29
- package/.github/renovate.json +0 -33
- package/.github/workflows/cla.yml +0 -29
- package/.github/workflows/codeql.yml +0 -76
- package/.github/workflows/coverage.yml +0 -39
- package/.github/workflows/dependency-review.yml +0 -14
- package/.github/workflows/docs.yml +0 -59
- package/.github/workflows/lock-threads.yml +0 -29
- package/.github/workflows/publish.yml +0 -30
- package/.github/workflows/stale.yml +0 -24
- package/.github/workflows/test.yml +0 -38
- package/.prettierignore +0 -5
- package/.prettierrc.js +0 -5
- package/dist/index.d.ts +0 -2
- /package/dist/{errors.d.ts → cjs/errors.d.ts} +0 -0
- /package/dist/{types.js → cjs/types.js} +0 -0
- /package/dist/{validation.d.ts → cjs/validation.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
## [
|
|
2
|
-
|
|
3
|
-
### Chores
|
|
4
|
-
|
|
5
|
-
* **config:** migrate config .github/renovate.json ([#115](https://github.com/bbc/sqs-producer/issues/115)) ([e461bf0](https://github.com/bbc/sqs-producer/commit/e461bf00eabfe8c1603d7ee97e009356238ac36d))
|
|
1
|
+
## [7.0.0-canary.1](https://github.com/bbc/sqs-producer/compare/v6.1.0-canary.1...v7.0.0-canary.1) (2025-01-08)
|
package/README.md
CHANGED
|
@@ -26,17 +26,17 @@ Visit [https://bbc.github.io/sqs-producer/](https://bbc.github.io/sqs-producer/)
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
28
28
|
```js
|
|
29
|
-
import { Producer } from
|
|
30
|
-
import { SQSClient } from
|
|
29
|
+
import { Producer } from "sqs-producer";
|
|
30
|
+
import { SQSClient } from "@aws-sdk/client-sqs";
|
|
31
31
|
|
|
32
32
|
// create simple producer
|
|
33
33
|
const producer = Producer.create({
|
|
34
|
-
queueUrl:
|
|
35
|
-
region:
|
|
34
|
+
queueUrl: "https://sqs.eu-west-1.amazonaws.com/account-id/queue-name",
|
|
35
|
+
region: "eu-west-1",
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
// send messages to the queue
|
|
39
|
-
await producer.send([
|
|
39
|
+
await producer.send(["msg1", "msg2"]);
|
|
40
40
|
|
|
41
41
|
// get the current size of the queue
|
|
42
42
|
const size = await producer.queueSize();
|
|
@@ -45,9 +45,9 @@ console.log(`There are ${size} messages on the queue.`);
|
|
|
45
45
|
// send a message to the queue with a specific ID (by default the body is used as the ID)
|
|
46
46
|
await producer.send([
|
|
47
47
|
{
|
|
48
|
-
id:
|
|
49
|
-
body:
|
|
50
|
-
}
|
|
48
|
+
id: "id1",
|
|
49
|
+
body: "Hello world",
|
|
50
|
+
},
|
|
51
51
|
]);
|
|
52
52
|
|
|
53
53
|
// send a message to the queue with
|
|
@@ -55,18 +55,18 @@ await producer.send([
|
|
|
55
55
|
// - messageAttributes
|
|
56
56
|
await producer.send([
|
|
57
57
|
{
|
|
58
|
-
id:
|
|
59
|
-
body:
|
|
58
|
+
id: "id1",
|
|
59
|
+
body: "Hello world with two string attributes: attr1 and attr2",
|
|
60
60
|
messageAttributes: {
|
|
61
|
-
attr1: { DataType:
|
|
62
|
-
attr2: { DataType:
|
|
63
|
-
}
|
|
61
|
+
attr1: { DataType: "String", StringValue: "stringValue" },
|
|
62
|
+
attr2: { DataType: "Binary", BinaryValue: new Buffer("binaryValue") },
|
|
63
|
+
},
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
|
-
id:
|
|
67
|
-
body:
|
|
68
|
-
delaySeconds: 5
|
|
69
|
-
}
|
|
66
|
+
id: "id2",
|
|
67
|
+
body: "Hello world delayed by 5 seconds",
|
|
68
|
+
delaySeconds: 5,
|
|
69
|
+
},
|
|
70
70
|
]);
|
|
71
71
|
|
|
72
72
|
// send a message to a FIFO queue
|
|
@@ -79,10 +79,10 @@ await producer.send([
|
|
|
79
79
|
//
|
|
80
80
|
// https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queue-recommendations.html
|
|
81
81
|
await producer.send({
|
|
82
|
-
id:
|
|
83
|
-
body:
|
|
84
|
-
groupId:
|
|
85
|
-
deduplicationId:
|
|
82
|
+
id: "testId",
|
|
83
|
+
body: "Hello world from our FIFO queue!",
|
|
84
|
+
groupId: "group1234",
|
|
85
|
+
deduplicationId: "abcdef123456", // typically a hash of the message body
|
|
86
86
|
});
|
|
87
87
|
```
|
|
88
88
|
|
|
@@ -98,24 +98,24 @@ export AWS_ACCESS_KEY_ID=...
|
|
|
98
98
|
If you need to specify your credentials manually, you can use a pre-configured instance of the [SQS Client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/classes/sqsclient.html) client.
|
|
99
99
|
|
|
100
100
|
```js
|
|
101
|
-
import { Producer } from
|
|
102
|
-
import { SQSClient } from
|
|
101
|
+
import { Producer } from "sqs-producer";
|
|
102
|
+
import { SQSClient } from "@aws-sdk/client-sqs";
|
|
103
103
|
|
|
104
104
|
// create simple producer
|
|
105
105
|
const producer = Producer.create({
|
|
106
|
-
queueUrl:
|
|
107
|
-
region:
|
|
106
|
+
queueUrl: "https://sqs.eu-west-1.amazonaws.com/account-id/queue-name",
|
|
107
|
+
region: "eu-west-1",
|
|
108
108
|
sqs: new SQSClient({
|
|
109
|
-
region:
|
|
109
|
+
region: "my-region",
|
|
110
110
|
credentials: {
|
|
111
|
-
accessKeyId:
|
|
112
|
-
secretAccessKey:
|
|
113
|
-
}
|
|
114
|
-
})
|
|
111
|
+
accessKeyId: "yourAccessKey",
|
|
112
|
+
secretAccessKey: "yourSecret",
|
|
113
|
+
},
|
|
114
|
+
}),
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
// send messages to the queue
|
|
118
|
-
await producer.send([
|
|
118
|
+
await producer.send(["msg1", "msg2"]);
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
## Development
|
|
@@ -9,7 +9,7 @@ class FailedMessagesError extends Error {
|
|
|
9
9
|
* @param failedMessages Ids of messages that failed to send.
|
|
10
10
|
*/
|
|
11
11
|
constructor(failedMessages) {
|
|
12
|
-
super(`Failed to send messages: ${failedMessages.join(
|
|
12
|
+
super(`Failed to send messages: ${failedMessages.join(", ")}`);
|
|
13
13
|
this.failedMessages = failedMessages;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SendMessageBatchRequestEntry } from
|
|
2
|
-
import { Message } from
|
|
1
|
+
import type { SendMessageBatchRequestEntry } from "@aws-sdk/client-sqs";
|
|
2
|
+
import type { Message } from "./types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Converts a message to a SendMessageBatchRequestEntry using the appropriate method
|
|
5
5
|
* depending on if the message is a string or an object
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toEntry = toEntry;
|
|
4
|
-
const
|
|
4
|
+
const validation_js_1 = require("./validation.js");
|
|
5
5
|
/**
|
|
6
6
|
* Converts a message object to a SendMessageBatchRequestEntry
|
|
7
7
|
* @param message - The message to convert
|
|
@@ -19,38 +19,38 @@ function entryFromObject(message) {
|
|
|
19
19
|
throw new Error(`FIFO Queue messages must have 'groupId' prop`);
|
|
20
20
|
}
|
|
21
21
|
if (message.id) {
|
|
22
|
-
if (!(0,
|
|
23
|
-
throw new Error(
|
|
22
|
+
if (!(0, validation_js_1.isString)(message.id)) {
|
|
23
|
+
throw new Error("Message.id value must be a string");
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
const entry = {
|
|
27
27
|
Id: message.id,
|
|
28
|
-
MessageBody: message.body
|
|
28
|
+
MessageBody: message.body,
|
|
29
29
|
};
|
|
30
30
|
if (message.delaySeconds) {
|
|
31
|
-
if (typeof message.delaySeconds !==
|
|
31
|
+
if (typeof message.delaySeconds !== "number" ||
|
|
32
32
|
message.delaySeconds < 0 ||
|
|
33
33
|
message.delaySeconds > 900) {
|
|
34
|
-
throw new Error(
|
|
34
|
+
throw new Error("Message.delaySeconds value must be a number contained within [0 - 900]");
|
|
35
35
|
}
|
|
36
36
|
entry.DelaySeconds = message.delaySeconds;
|
|
37
37
|
}
|
|
38
38
|
if (message.messageAttributes) {
|
|
39
|
-
if (!(0,
|
|
40
|
-
throw new Error(
|
|
39
|
+
if (!(0, validation_js_1.isObject)(message.messageAttributes)) {
|
|
40
|
+
throw new Error("Message.messageAttributes must be an object");
|
|
41
41
|
}
|
|
42
|
-
Object.values(message.messageAttributes).every(
|
|
42
|
+
Object.values(message.messageAttributes).every(validation_js_1.isMessageAttributeValid);
|
|
43
43
|
entry.MessageAttributes = message.messageAttributes;
|
|
44
44
|
}
|
|
45
45
|
if (message.groupId) {
|
|
46
|
-
if (!(0,
|
|
47
|
-
throw new Error(
|
|
46
|
+
if (!(0, validation_js_1.isString)(message.groupId)) {
|
|
47
|
+
throw new Error("Message.groupId value must be a string");
|
|
48
48
|
}
|
|
49
49
|
entry.MessageGroupId = message.groupId;
|
|
50
50
|
}
|
|
51
51
|
if (message.deduplicationId) {
|
|
52
|
-
if (!(0,
|
|
53
|
-
throw new Error(
|
|
52
|
+
if (!(0, validation_js_1.isString)(message.deduplicationId)) {
|
|
53
|
+
throw new Error("Message.deduplicationId value must be a string");
|
|
54
54
|
}
|
|
55
55
|
entry.MessageDeduplicationId = message.deduplicationId;
|
|
56
56
|
}
|
|
@@ -63,7 +63,7 @@ function entryFromObject(message) {
|
|
|
63
63
|
function entryFromString(message) {
|
|
64
64
|
return {
|
|
65
65
|
Id: message,
|
|
66
|
-
MessageBody: message
|
|
66
|
+
MessageBody: message,
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
@@ -72,11 +72,11 @@ function entryFromString(message) {
|
|
|
72
72
|
* @param message The message to convert
|
|
73
73
|
*/
|
|
74
74
|
function toEntry(message) {
|
|
75
|
-
if ((0,
|
|
75
|
+
if ((0, validation_js_1.isString)(message)) {
|
|
76
76
|
return entryFromString(message);
|
|
77
77
|
}
|
|
78
|
-
if ((0,
|
|
78
|
+
if ((0, validation_js_1.isObject)(message)) {
|
|
79
79
|
return entryFromObject(message);
|
|
80
80
|
}
|
|
81
|
-
throw new Error(
|
|
81
|
+
throw new Error("A message can either be an object or a string");
|
|
82
82
|
}
|
|
@@ -15,6 +15,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.Producer = void 0;
|
|
18
|
-
var
|
|
19
|
-
Object.defineProperty(exports, "Producer", { enumerable: true, get: function () { return
|
|
20
|
-
__exportStar(require("./types"), exports);
|
|
18
|
+
var producer_js_1 = require("./producer.js");
|
|
19
|
+
Object.defineProperty(exports, "Producer", { enumerable: true, get: function () { return producer_js_1.Producer; } });
|
|
20
|
+
__exportStar(require("./types.js"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "commonjs"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SQSClient, SendMessageBatchResultEntry } from
|
|
2
|
-
import { Message, ProducerOptions } from
|
|
1
|
+
import { SQSClient, type SendMessageBatchResultEntry } from "@aws-sdk/client-sqs";
|
|
2
|
+
import type { Message, ProducerOptions } from "./types.js";
|
|
3
3
|
/**
|
|
4
4
|
* [Usage](https://bbc.github.io/sqs-producer/index.html#usage)
|
|
5
5
|
*/
|
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Producer = void 0;
|
|
4
4
|
const client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const requiredOptions = [
|
|
5
|
+
const format_js_1 = require("./format.js");
|
|
6
|
+
const errors_js_1 = require("./errors.js");
|
|
7
|
+
const requiredOptions = ["queueUrl"];
|
|
8
8
|
/**
|
|
9
9
|
* [Usage](https://bbc.github.io/sqs-producer/index.html#usage)
|
|
10
10
|
*/
|
|
11
11
|
class Producer {
|
|
12
12
|
constructor(options) {
|
|
13
|
-
var _a;
|
|
14
13
|
this.validate(options);
|
|
15
14
|
this.queueUrl = options.queueUrl;
|
|
16
15
|
this.batchSize = options.batchSize || 10;
|
|
17
16
|
this.sqs =
|
|
18
17
|
options.sqs ||
|
|
19
|
-
new client_sqs_1.SQSClient(
|
|
18
|
+
new client_sqs_1.SQSClient({
|
|
19
|
+
...options,
|
|
20
|
+
useQueueUrlAsEndpoint: options.useQueueUrlAsEndpoint ?? true,
|
|
21
|
+
region: options.region || process.env.AWS_REGION || "eu-west-1",
|
|
22
|
+
});
|
|
20
23
|
}
|
|
21
24
|
/**
|
|
22
25
|
* Returns the number of messages in the queue.
|
|
@@ -25,7 +28,7 @@ class Producer {
|
|
|
25
28
|
async queueSize() {
|
|
26
29
|
const command = new client_sqs_1.GetQueueAttributesCommand({
|
|
27
30
|
QueueUrl: this.queueUrl,
|
|
28
|
-
AttributeNames: [
|
|
31
|
+
AttributeNames: ["ApproximateNumberOfMessages"],
|
|
29
32
|
});
|
|
30
33
|
const result = await this.sqs.send(command);
|
|
31
34
|
return Number(result &&
|
|
@@ -56,7 +59,7 @@ class Producer {
|
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
if (options.batchSize > 10 || options.batchSize < 1) {
|
|
59
|
-
throw new Error(
|
|
62
|
+
throw new Error("SQS batchSize option must be between 1 and 10.");
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
/**
|
|
@@ -69,24 +72,23 @@ class Producer {
|
|
|
69
72
|
* @throws FailedMessagesError
|
|
70
73
|
*/
|
|
71
74
|
async sendBatch(failedMessages, successfulMessages, messages, startIndex) {
|
|
72
|
-
var _a;
|
|
73
75
|
const endIndex = startIndex + this.batchSize;
|
|
74
76
|
const batch = messages.slice(startIndex, endIndex);
|
|
75
77
|
const params = {
|
|
76
78
|
QueueUrl: this.queueUrl,
|
|
77
|
-
Entries: batch.map(
|
|
79
|
+
Entries: batch.map(format_js_1.toEntry),
|
|
78
80
|
};
|
|
79
81
|
const command = new client_sqs_1.SendMessageBatchCommand(params);
|
|
80
82
|
const result = await this.sqs.send(command);
|
|
81
|
-
const failedMessagesBatch = failedMessages.concat(
|
|
82
|
-
const successfulMessagesBatch = successfulMessages.concat(
|
|
83
|
+
const failedMessagesBatch = failedMessages.concat(result?.Failed?.map((entry) => entry.Id) || []);
|
|
84
|
+
const successfulMessagesBatch = successfulMessages.concat(result?.Successful || []);
|
|
83
85
|
if (endIndex < messages.length) {
|
|
84
86
|
return this.sendBatch(failedMessagesBatch, successfulMessagesBatch, messages, endIndex);
|
|
85
87
|
}
|
|
86
88
|
if (failedMessagesBatch.length === 0) {
|
|
87
89
|
return successfulMessagesBatch;
|
|
88
90
|
}
|
|
89
|
-
throw new
|
|
91
|
+
throw new errors_js_1.FailedMessagesError(failedMessagesBatch);
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
exports.Producer = Producer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../../src/errors.ts","../../src/format.ts","../../src/index.ts","../../src/producer.ts","../../src/types.ts","../../src/validation.ts"],"version":"5.7.2"}
|
|
@@ -8,14 +8,14 @@ exports.isMessageAttributeValid = isMessageAttributeValid;
|
|
|
8
8
|
* @param value - The value to check
|
|
9
9
|
*/
|
|
10
10
|
function isString(value) {
|
|
11
|
-
return typeof value ===
|
|
11
|
+
return typeof value === "string" || value instanceof String;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Checks if the value is an object
|
|
15
15
|
* @param value - The value to check
|
|
16
16
|
*/
|
|
17
17
|
function isObject(value) {
|
|
18
|
-
return value && typeof value ===
|
|
18
|
+
return value && typeof value === "object" && value instanceof Object;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Checks if a MessageAttribute is valid
|
|
@@ -23,10 +23,10 @@ function isObject(value) {
|
|
|
23
23
|
*/
|
|
24
24
|
function isMessageAttributeValid(messageAttribute) {
|
|
25
25
|
if (!messageAttribute.DataType) {
|
|
26
|
-
throw new Error(
|
|
26
|
+
throw new Error("A MessageAttribute must have a DataType key");
|
|
27
27
|
}
|
|
28
28
|
if (!isString(messageAttribute.DataType)) {
|
|
29
|
-
throw new Error(
|
|
29
|
+
throw new Error("The DataType key of a MessageAttribute must be a String");
|
|
30
30
|
}
|
|
31
31
|
return true;
|
|
32
32
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when a message fails to send.
|
|
3
|
+
*/
|
|
4
|
+
export declare class FailedMessagesError extends Error {
|
|
5
|
+
/** Ids of messages that failed to send. */
|
|
6
|
+
failedMessages: string[];
|
|
7
|
+
/**
|
|
8
|
+
* @param failedMessages Ids of messages that failed to send.
|
|
9
|
+
*/
|
|
10
|
+
constructor(failedMessages: string[]);
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when a message fails to send.
|
|
3
|
+
*/
|
|
4
|
+
export class FailedMessagesError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* @param failedMessages Ids of messages that failed to send.
|
|
7
|
+
*/
|
|
8
|
+
constructor(failedMessages) {
|
|
9
|
+
super(`Failed to send messages: ${failedMessages.join(", ")}`);
|
|
10
|
+
this.failedMessages = failedMessages;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SendMessageBatchRequestEntry } from "@aws-sdk/client-sqs";
|
|
2
|
+
import type { Message } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Converts a message to a SendMessageBatchRequestEntry using the appropriate method
|
|
5
|
+
* depending on if the message is a string or an object
|
|
6
|
+
* @param message The message to convert
|
|
7
|
+
*/
|
|
8
|
+
export declare function toEntry(message: string | Message): SendMessageBatchRequestEntry;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { isObject, isString, isMessageAttributeValid } from "./validation.js";
|
|
2
|
+
/**
|
|
3
|
+
* Converts a message object to a SendMessageBatchRequestEntry
|
|
4
|
+
* @param message - The message to convert
|
|
5
|
+
* @returns The SendMessageBatchRequestEntry
|
|
6
|
+
* @throws Will throw an error if the message is invalid
|
|
7
|
+
*/
|
|
8
|
+
function entryFromObject(message) {
|
|
9
|
+
if (!message.body) {
|
|
10
|
+
throw new Error(`Object messages must have 'body' prop`);
|
|
11
|
+
}
|
|
12
|
+
if (!message.groupId && !message.deduplicationId && !message.id) {
|
|
13
|
+
throw new Error(`Object messages must have 'id' prop`);
|
|
14
|
+
}
|
|
15
|
+
if (message.deduplicationId && !message.groupId) {
|
|
16
|
+
throw new Error(`FIFO Queue messages must have 'groupId' prop`);
|
|
17
|
+
}
|
|
18
|
+
if (message.id) {
|
|
19
|
+
if (!isString(message.id)) {
|
|
20
|
+
throw new Error("Message.id value must be a string");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const entry = {
|
|
24
|
+
Id: message.id,
|
|
25
|
+
MessageBody: message.body,
|
|
26
|
+
};
|
|
27
|
+
if (message.delaySeconds) {
|
|
28
|
+
if (typeof message.delaySeconds !== "number" ||
|
|
29
|
+
message.delaySeconds < 0 ||
|
|
30
|
+
message.delaySeconds > 900) {
|
|
31
|
+
throw new Error("Message.delaySeconds value must be a number contained within [0 - 900]");
|
|
32
|
+
}
|
|
33
|
+
entry.DelaySeconds = message.delaySeconds;
|
|
34
|
+
}
|
|
35
|
+
if (message.messageAttributes) {
|
|
36
|
+
if (!isObject(message.messageAttributes)) {
|
|
37
|
+
throw new Error("Message.messageAttributes must be an object");
|
|
38
|
+
}
|
|
39
|
+
Object.values(message.messageAttributes).every(isMessageAttributeValid);
|
|
40
|
+
entry.MessageAttributes = message.messageAttributes;
|
|
41
|
+
}
|
|
42
|
+
if (message.groupId) {
|
|
43
|
+
if (!isString(message.groupId)) {
|
|
44
|
+
throw new Error("Message.groupId value must be a string");
|
|
45
|
+
}
|
|
46
|
+
entry.MessageGroupId = message.groupId;
|
|
47
|
+
}
|
|
48
|
+
if (message.deduplicationId) {
|
|
49
|
+
if (!isString(message.deduplicationId)) {
|
|
50
|
+
throw new Error("Message.deduplicationId value must be a string");
|
|
51
|
+
}
|
|
52
|
+
entry.MessageDeduplicationId = message.deduplicationId;
|
|
53
|
+
}
|
|
54
|
+
return entry;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Converts a message string to a SendMessageBatchRequestEntry
|
|
58
|
+
* @param message The message to convert
|
|
59
|
+
*/
|
|
60
|
+
function entryFromString(message) {
|
|
61
|
+
return {
|
|
62
|
+
Id: message,
|
|
63
|
+
MessageBody: message,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Converts a message to a SendMessageBatchRequestEntry using the appropriate method
|
|
68
|
+
* depending on if the message is a string or an object
|
|
69
|
+
* @param message The message to convert
|
|
70
|
+
*/
|
|
71
|
+
export function toEntry(message) {
|
|
72
|
+
if (isString(message)) {
|
|
73
|
+
return entryFromString(message);
|
|
74
|
+
}
|
|
75
|
+
if (isObject(message)) {
|
|
76
|
+
return entryFromObject(message);
|
|
77
|
+
}
|
|
78
|
+
throw new Error("A message can either be an object or a string");
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "module"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SQSClient, type SendMessageBatchResultEntry } from "@aws-sdk/client-sqs";
|
|
2
|
+
import type { Message, ProducerOptions } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* [Usage](https://bbc.github.io/sqs-producer/index.html#usage)
|
|
5
|
+
*/
|
|
6
|
+
export declare class Producer {
|
|
7
|
+
static create: (options: ProducerOptions) => Producer;
|
|
8
|
+
queueUrl: string;
|
|
9
|
+
batchSize: number;
|
|
10
|
+
sqs: SQSClient;
|
|
11
|
+
region?: string;
|
|
12
|
+
constructor(options: ProducerOptions);
|
|
13
|
+
/**
|
|
14
|
+
* Returns the number of messages in the queue.
|
|
15
|
+
* @returns A promise that resolves to the number of messages in the queue.
|
|
16
|
+
*/
|
|
17
|
+
queueSize(): Promise<number>;
|
|
18
|
+
/**
|
|
19
|
+
* Send a message to the queue.
|
|
20
|
+
* @param messages - A single message or an array of messages.
|
|
21
|
+
* @returns A promise that resolves to the result of the send operation.
|
|
22
|
+
*/
|
|
23
|
+
send(messages: string | Message | (string | Message)[]): Promise<SendMessageBatchResultEntry[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Validate the producer options.
|
|
26
|
+
* @param options - The producer options to validate.
|
|
27
|
+
* @throws Error if any required options are missing or invalid.
|
|
28
|
+
*/
|
|
29
|
+
private validate;
|
|
30
|
+
/**
|
|
31
|
+
* Send a batch of messages to the queue.
|
|
32
|
+
* @param failedMessages - An array of failed message IDs.
|
|
33
|
+
* @param successfulMessages - An array of successful message results.
|
|
34
|
+
* @param messages - An array of messages to send.
|
|
35
|
+
* @param startIndex - The index of the first message in the batch.
|
|
36
|
+
* @returns A promise that resolves to the result of the send operation.
|
|
37
|
+
* @throws FailedMessagesError
|
|
38
|
+
*/
|
|
39
|
+
private sendBatch;
|
|
40
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { SQSClient, SendMessageBatchCommand, GetQueueAttributesCommand, } from "@aws-sdk/client-sqs";
|
|
2
|
+
import { toEntry } from "./format.js";
|
|
3
|
+
import { FailedMessagesError } from "./errors.js";
|
|
4
|
+
const requiredOptions = ["queueUrl"];
|
|
5
|
+
/**
|
|
6
|
+
* [Usage](https://bbc.github.io/sqs-producer/index.html#usage)
|
|
7
|
+
*/
|
|
8
|
+
export class Producer {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.validate(options);
|
|
11
|
+
this.queueUrl = options.queueUrl;
|
|
12
|
+
this.batchSize = options.batchSize || 10;
|
|
13
|
+
this.sqs =
|
|
14
|
+
options.sqs ||
|
|
15
|
+
new SQSClient({
|
|
16
|
+
...options,
|
|
17
|
+
useQueueUrlAsEndpoint: options.useQueueUrlAsEndpoint ?? true,
|
|
18
|
+
region: options.region || process.env.AWS_REGION || "eu-west-1",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Returns the number of messages in the queue.
|
|
23
|
+
* @returns A promise that resolves to the number of messages in the queue.
|
|
24
|
+
*/
|
|
25
|
+
async queueSize() {
|
|
26
|
+
const command = new GetQueueAttributesCommand({
|
|
27
|
+
QueueUrl: this.queueUrl,
|
|
28
|
+
AttributeNames: ["ApproximateNumberOfMessages"],
|
|
29
|
+
});
|
|
30
|
+
const result = await this.sqs.send(command);
|
|
31
|
+
return Number(result &&
|
|
32
|
+
result.Attributes &&
|
|
33
|
+
result.Attributes.ApproximateNumberOfMessages);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Send a message to the queue.
|
|
37
|
+
* @param messages - A single message or an array of messages.
|
|
38
|
+
* @returns A promise that resolves to the result of the send operation.
|
|
39
|
+
*/
|
|
40
|
+
async send(messages) {
|
|
41
|
+
const failedMessages = [];
|
|
42
|
+
const successfulMessages = [];
|
|
43
|
+
const startIndex = 0;
|
|
44
|
+
const messagesArr = !Array.isArray(messages) ? [messages] : messages;
|
|
45
|
+
return this.sendBatch(failedMessages, successfulMessages, messagesArr, startIndex);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Validate the producer options.
|
|
49
|
+
* @param options - The producer options to validate.
|
|
50
|
+
* @throws Error if any required options are missing or invalid.
|
|
51
|
+
*/
|
|
52
|
+
validate(options) {
|
|
53
|
+
for (const option of requiredOptions) {
|
|
54
|
+
if (!options[option]) {
|
|
55
|
+
throw new Error(`Missing SQS producer option [${option}].`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (options.batchSize > 10 || options.batchSize < 1) {
|
|
59
|
+
throw new Error("SQS batchSize option must be between 1 and 10.");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Send a batch of messages to the queue.
|
|
64
|
+
* @param failedMessages - An array of failed message IDs.
|
|
65
|
+
* @param successfulMessages - An array of successful message results.
|
|
66
|
+
* @param messages - An array of messages to send.
|
|
67
|
+
* @param startIndex - The index of the first message in the batch.
|
|
68
|
+
* @returns A promise that resolves to the result of the send operation.
|
|
69
|
+
* @throws FailedMessagesError
|
|
70
|
+
*/
|
|
71
|
+
async sendBatch(failedMessages, successfulMessages, messages, startIndex) {
|
|
72
|
+
const endIndex = startIndex + this.batchSize;
|
|
73
|
+
const batch = messages.slice(startIndex, endIndex);
|
|
74
|
+
const params = {
|
|
75
|
+
QueueUrl: this.queueUrl,
|
|
76
|
+
Entries: batch.map(toEntry),
|
|
77
|
+
};
|
|
78
|
+
const command = new SendMessageBatchCommand(params);
|
|
79
|
+
const result = await this.sqs.send(command);
|
|
80
|
+
const failedMessagesBatch = failedMessages.concat(result?.Failed?.map((entry) => entry.Id) || []);
|
|
81
|
+
const successfulMessagesBatch = successfulMessages.concat(result?.Successful || []);
|
|
82
|
+
if (endIndex < messages.length) {
|
|
83
|
+
return this.sendBatch(failedMessagesBatch, successfulMessagesBatch, messages, endIndex);
|
|
84
|
+
}
|
|
85
|
+
if (failedMessagesBatch.length === 0) {
|
|
86
|
+
return successfulMessagesBatch;
|
|
87
|
+
}
|
|
88
|
+
throw new FailedMessagesError(failedMessagesBatch);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Creates a new producer.
|
|
93
|
+
* @param options - The producer options.
|
|
94
|
+
*/
|
|
95
|
+
Producer.create = (options) => {
|
|
96
|
+
return new Producer(options);
|
|
97
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../../src/errors.ts","../../src/format.ts","../../src/index.ts","../../src/producer.ts","../../src/types.ts","../../src/validation.ts"],"version":"5.7.2"}
|