From babec5193e4b965eaf87f0ab1ae0aba389f515a6 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 12 Mar 2024 19:19:05 +0000 Subject: [PATCH 1/9] feat!: transitioning to ESM --- .prettierrc.js | 8 +- README.md | 32 +- package-lock.json | 111 +-- package.json | 17 +- src/bind.ts | 2 +- src/consumer.ts | 145 +-- src/emitter.ts | 10 +- src/errors.ts | 22 +- src/index.ts | 4 +- src/logger.ts | 3 +- src/types.ts | 12 +- src/validation.ts | 38 +- test/config/cucumber.js | 8 - test/config/cucumber.mjs | 6 + .../step_definitions/gracefulShutdown.js | 42 +- .../step_definitions/handleMessage.js | 64 +- .../step_definitions/handleMessageBatch.js | 60 +- .../utils/consumer/gracefulShutdown.js | 10 +- test/features/utils/consumer/handleMessage.js | 10 +- .../utils/consumer/handleMessageBatch.js | 10 +- test/features/utils/delay.js | 4 +- test/features/utils/producer.js | 10 +- test/features/utils/sqs.js | 22 +- test/tests/consumer.test.ts | 868 +++++++++--------- tsconfig.json | 4 +- 25 files changed, 749 insertions(+), 773 deletions(-) delete mode 100644 test/config/cucumber.js create mode 100644 test/config/cucumber.mjs diff --git a/.prettierrc.js b/.prettierrc.js index c469fe6a..6e5f4c1d 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,5 +1,7 @@ -module.exports = { +/** @type {import("prettier").Config} */ + +export const config = { singleQuote: true, - arrowParens: 'always', - trailingComma: 'none' + arrowParens: "always", + trailingComma: "none", }; diff --git a/README.md b/README.md index 8111fa06..bb7fbf72 100644 --- a/README.md +++ b/README.md @@ -33,20 +33,20 @@ Visit [https://bbc.github.io/sqs-consumer/](https://bbc.github.io/sqs-consumer/) ## Usage ```js -import { Consumer } from 'sqs-consumer'; +import { Consumer } from "sqs-consumer"; const app = Consumer.create({ - queueUrl: 'https://sqs.eu-west-1.amazonaws.com/account-id/queue-name', + queueUrl: "https://sqs.eu-west-1.amazonaws.com/account-id/queue-name", handleMessage: async (message) => { // do some work with `message` - } + }, }); -app.on('error', (err) => { +app.on("error", (err) => { console.error(err.message); }); -app.on('processing_error', (err) => { +app.on("processing_error", (err) => { console.error(err.message); }); @@ -75,32 +75,32 @@ export AWS_ACCESS_KEY_ID=... 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. ```js -import { Consumer } from 'sqs-consumer'; -import { SQSClient } from '@aws-sdk/client-sqs'; +import { Consumer } from "sqs-consumer"; +import { SQSClient } from "@aws-sdk/client-sqs"; const app = Consumer.create({ - queueUrl: 'https://sqs.eu-west-1.amazonaws.com/account-id/queue-name', + queueUrl: "https://sqs.eu-west-1.amazonaws.com/account-id/queue-name", handleMessage: async (message) => { // ... }, sqs: new SQSClient({ - region: 'my-region', + region: "my-region", credentials: { - accessKeyId: 'yourAccessKey', - secretAccessKey: 'yourSecret' - } - }) + accessKeyId: "yourAccessKey", + secretAccessKey: "yourSecret", + }, + }), }); -app.on('error', (err) => { +app.on("error", (err) => { console.error(err.message); }); -app.on('processing_error', (err) => { +app.on("processing_error", (err) => { console.error(err.message); }); -app.on('timeout_error', (err) => { +app.on("timeout_error", (err) => { console.error(err.message); }); diff --git a/package-lock.json b/package-lock.json index 5ccb367c..d019c39d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,13 +25,13 @@ "@types/node": "^20.11.25", "@types/sinon": "^17.0.3", "c8": "^9.1.0", - "chai": "^4.3.10", + "chai": "5.1.0", "conventional-changelog-conventionalcommits": "^7.0.2", "eslint": "^8.57.0", "eslint-config-iplayer": "^9.2.0", "eslint-config-prettier": "^9.1.0", "mocha": "^10.3.0", - "p-event": "^4.2.0", + "p-event": "6.0.1", "prettier": "^3.2.5", "semantic-release": "^23.0.2", "sinon": "^17.0.1", @@ -3054,9 +3054,9 @@ "dev": true }, "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, "node_modules/@types/chai": { @@ -3363,9 +3363,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, "engines": { "node": ">=0.4.0" @@ -3648,12 +3648,12 @@ } }, "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "engines": { - "node": "*" + "node": ">=12" } }, "node_modules/assertion-error-formatter": { @@ -3869,21 +3869,19 @@ "dev": true }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.0.tgz", + "integrity": "sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw==", "dev": true, "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "assertion-error": "^2.0.1", + "check-error": "^2.0.0", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=12" } }, "node_modules/chalk": { @@ -3912,15 +3910,12 @@ } }, "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.0.0.tgz", + "integrity": "sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==", "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, "engines": { - "node": "*" + "node": ">= 16" } }, "node_modules/chokidar": { @@ -4268,13 +4263,10 @@ } }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", + "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, "engines": { "node": ">=6" } @@ -6647,9 +6639,9 @@ } }, "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz", + "integrity": "sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==", "dev": true, "dependencies": { "get-func-name": "^2.0.1" @@ -10060,15 +10052,15 @@ } }, "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", + "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", "dev": true, "dependencies": { - "p-timeout": "^3.1.0" + "p-timeout": "^6.1.2" }, "engines": { - "node": ">=8" + "node": ">=16.17" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10089,15 +10081,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/p-is-promise": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", @@ -10162,15 +10145,15 @@ } }, "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz", + "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==", "dev": true, - "dependencies": { - "p-finally": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -10322,12 +10305,12 @@ } }, "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "engines": { - "node": "*" + "node": ">= 14.16" } }, "node_modules/picomatch": { diff --git a/package.json b/package.json index 3aae5ae1..33f33137 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "sqs-consumer", "version": "9.1.0", "description": "Build SQS-based Node applications without the boilerplate", + "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", "engines": { @@ -15,7 +16,7 @@ "test:unit": "mocha --recursive --full-trace --exit", "pretest:integration:init": "npm run build", "test:integration:init": "sh ./test/scripts/initIntTests.sh", - "test:integration": "npm run test:integration:init && cucumber-js --config ./test/config/cucumber.js", + "test:integration": "npm run test:integration:init && cucumber-js --config ./test/config/cucumber.mjs", "test": "npm run test:unit && npm run test:integration", "coverage": "c8 mocha && c8 report --reporter=html && c8 report --reporter=json-summary", "lcov": "c8 mocha && c8 report --reporter=lcov", @@ -140,13 +141,13 @@ "@types/node": "^20.11.25", "@types/sinon": "^17.0.3", "c8": "^9.1.0", - "chai": "^4.3.10", + "chai": "5.1.0", "conventional-changelog-conventionalcommits": "^7.0.2", "eslint": "^8.57.0", "eslint-config-iplayer": "^9.2.0", "eslint-config-prettier": "^9.1.0", "mocha": "^10.3.0", - "p-event": "^4.2.0", + "p-event": "6.0.1", "prettier": "^3.2.5", "semantic-release": "^23.0.2", "sinon": "^17.0.1", @@ -163,8 +164,13 @@ "@aws-sdk/client-sqs": "^3.529.1" }, "mocha": { + "extensions": [ + "ts" + ], "spec": "test/tests/**/**/*.test.ts", - "require": "ts-node/register" + "node-option": [ + "loader=ts-node/esm" + ] }, "c8": { "include": [ @@ -173,9 +179,6 @@ "extension": [ ".ts" ], - "require": [ - "ts-node/register" - ], "sourceMap": true, "instrument": true }, diff --git a/src/bind.ts b/src/bind.ts index c588e894..2fd897ab 100644 --- a/src/bind.ts +++ b/src/bind.ts @@ -4,7 +4,7 @@ * @param value the value of the property */ function isMethod(propertyName: string, value: any): boolean { - return propertyName !== 'constructor' && typeof value === 'function'; + return propertyName !== "constructor" && typeof value === "function"; } /** diff --git a/src/consumer.ts b/src/consumer.ts index c9be663e..772fdd6f 100644 --- a/src/consumer.ts +++ b/src/consumer.ts @@ -14,22 +14,22 @@ import { ReceiveMessageCommand, ReceiveMessageCommandInput, ReceiveMessageCommandOutput, - QueueAttributeName -} from '@aws-sdk/client-sqs'; + QueueAttributeName, +} from "@aws-sdk/client-sqs"; -import { ConsumerOptions, StopOptions, UpdatableOptions } from './types'; -import { TypedEventEmitter } from './emitter'; -import { autoBind } from './bind'; +import { ConsumerOptions, StopOptions, UpdatableOptions } from "./types.js"; +import { TypedEventEmitter } from "./emitter.js"; +import { autoBind } from "./bind.js"; import { SQSError, TimeoutError, toStandardError, toTimeoutError, toSQSError, - isConnectionError -} from './errors'; -import { validateOption, assertOptions, hasMessages } from './validation'; -import { logger } from './logger'; + isConnectionError, +} from "./errors.js"; +import { validateOption, assertOptions, hasMessages } from "./validation.js"; +import { logger } from "./logger.js"; /** * [Usage](https://bbc.github.io/sqs-consumer/index.html#usage) @@ -87,7 +87,7 @@ export class Consumer extends TypedEventEmitter { options.sqs || new SQSClient({ useQueueUrlAsEndpoint: options.useQueueUrlAsEndpoint ?? true, - region: options.region || process.env.AWS_REGION || 'eu-west-1' + region: options.region || process.env.AWS_REGION || "eu-west-1", }); autoBind(this); } @@ -106,9 +106,9 @@ export class Consumer extends TypedEventEmitter { if (this.stopped) { // Create a new abort controller each time the consumer is started this.abortController = new AbortController(); - logger.debug('starting'); + logger.debug("starting"); this.stopped = false; - this.emit('started'); + this.emit("started"); this.poll(); } } @@ -120,7 +120,7 @@ export class Consumer extends TypedEventEmitter { return { // return the current abortController signal or a fresh signal that has not been aborted. // This effectively defaults the signal sent to the AWS SDK to not aborted - abortSignal: this.abortController?.signal || new AbortController().signal + abortSignal: this.abortController?.signal || new AbortController().signal, }; } @@ -129,11 +129,11 @@ export class Consumer extends TypedEventEmitter { */ public stop(options?: StopOptions): void { if (this.stopped) { - logger.debug('already_stopped'); + logger.debug("already_stopped"); return; } - logger.debug('stopping'); + logger.debug("stopping"); this.stopped = true; if (this.pollingTimeoutId) { @@ -142,9 +142,9 @@ export class Consumer extends TypedEventEmitter { } if (options?.abort) { - logger.debug('aborting'); + logger.debug("aborting"); this.abortController.abort(); - this.emit('aborted'); + this.emit("aborted"); } this.stopRequestedAtTimestamp = Date.now(); @@ -157,7 +157,7 @@ export class Consumer extends TypedEventEmitter { */ private waitForPollingToComplete(): void { if (!this.isPolling || !(this.pollingCompleteWaitTimeMs > 0)) { - this.emit('stopped'); + this.emit("stopped"); return; } @@ -165,12 +165,12 @@ export class Consumer extends TypedEventEmitter { Date.now() - this.stopRequestedAtTimestamp > this.pollingCompleteWaitTimeMs; if (exceededTimeout) { - this.emit('waiting_for_polling_to_complete_timeout_exceeded'); - this.emit('stopped'); + this.emit("waiting_for_polling_to_complete_timeout_exceeded"); + this.emit("stopped"); return; } - this.emit('waiting_for_polling_to_complete'); + this.emit("waiting_for_polling_to_complete"); setTimeout(this.waitForPollingToComplete, 1000); } @@ -184,7 +184,7 @@ export class Consumer extends TypedEventEmitter { } { return { isRunning: !this.stopped, - isPolling: this.isPolling + isPolling: this.isPolling, }; } @@ -195,13 +195,13 @@ export class Consumer extends TypedEventEmitter { */ public updateOption( option: UpdatableOptions, - value: ConsumerOptions[UpdatableOptions] + value: ConsumerOptions[UpdatableOptions], ) { validateOption(option, value, this, true); this[option] = value; - this.emit('option_updated', option, value); + this.emit("option_updated", option, value); } /** @@ -211,13 +211,13 @@ export class Consumer extends TypedEventEmitter { */ private emitError(err: Error, message?: Message): void { if (!message) { - this.emit('error', err); + this.emit("error", err); } else if (err.name === SQSError.name) { - this.emit('error', err, message); + this.emit("error", err, message); } else if (err instanceof TimeoutError) { - this.emit('timeout_error', err, message); + this.emit("timeout_error", err, message); } else { - this.emit('processing_error', err, message); + this.emit("processing_error", err, message); } } @@ -226,13 +226,14 @@ export class Consumer extends TypedEventEmitter { */ private poll(): void { if (this.stopped) { - logger.debug('cancelling_poll', { - detail: 'Poll was called while consumer was stopped, cancelling poll...' + logger.debug("cancelling_poll", { + detail: + "Poll was called while consumer was stopped, cancelling poll...", }); return; } - logger.debug('polling'); + logger.debug("polling"); this.isPolling = true; @@ -243,15 +244,15 @@ export class Consumer extends TypedEventEmitter { MessageAttributeNames: this.messageAttributeNames, MaxNumberOfMessages: this.batchSize, WaitTimeSeconds: this.waitTimeSeconds, - VisibilityTimeout: this.visibilityTimeout + VisibilityTimeout: this.visibilityTimeout, }) .then(this.handleSqsResponse) .catch((err) => { this.emitError(err); if (isConnectionError(err)) { - logger.debug('authentication_error', { + logger.debug("authentication_error", { detail: - 'There was an authentication error. Pausing before retrying.' + "There was an authentication error. Pausing before retrying.", }); currentPollingTimeout = this.authenticationErrorTimeout; } @@ -276,7 +277,7 @@ export class Consumer extends TypedEventEmitter { * @param params The required params to receive messages from SQS */ private async receiveMessage( - params: ReceiveMessageCommandInput + params: ReceiveMessageCommandInput, ): Promise { try { if (this.preReceiveMessageCallback) { @@ -284,7 +285,7 @@ export class Consumer extends TypedEventEmitter { } const result = await this.sqs.send( new ReceiveMessageCommand(params), - this.sqsSendOptions + this.sqsSendOptions, ); if (this.postReceiveMessageCallback) { await this.postReceiveMessageCallback(); @@ -302,7 +303,7 @@ export class Consumer extends TypedEventEmitter { * @param response The output from AWS SQS */ private async handleSqsResponse( - response: ReceiveMessageCommandOutput + response: ReceiveMessageCommandOutput, ): Promise { if (hasMessages(response)) { if (this.handleMessageBatch) { @@ -311,9 +312,9 @@ export class Consumer extends TypedEventEmitter { await Promise.all(response.Messages.map(this.processMessage)); } - this.emit('response_processed'); + this.emit("response_processed"); } else if (response) { - this.emit('empty'); + this.emit("empty"); } } @@ -326,7 +327,7 @@ export class Consumer extends TypedEventEmitter { let heartbeatTimeoutId: NodeJS.Timeout | undefined = undefined; try { - this.emit('message_received', message); + this.emit("message_received", message); if (this.heartbeatInterval) { heartbeatTimeoutId = this.startHeartbeat(message); @@ -337,7 +338,7 @@ export class Consumer extends TypedEventEmitter { if (ackedMessage?.MessageId === message.MessageId) { await this.deleteMessage(message); - this.emit('message_processed', message); + this.emit("message_processed", message); } } catch (err) { this.emitError(err, message); @@ -361,7 +362,7 @@ export class Consumer extends TypedEventEmitter { try { messages.forEach((message) => { - this.emit('message_received', message); + this.emit("message_received", message); }); if (this.heartbeatInterval) { @@ -374,11 +375,11 @@ export class Consumer extends TypedEventEmitter { await this.deleteMessageBatch(ackedMessages); ackedMessages.forEach((message) => { - this.emit('message_processed', message); + this.emit("message_processed", message); }); } } catch (err) { - this.emit('error', err, messages); + this.emit("error", err, messages); if (this.terminateVisibilityTimeout) { await this.changeVisibilityTimeoutBatch(messages, 0); @@ -394,13 +395,13 @@ export class Consumer extends TypedEventEmitter { */ private startHeartbeat( message?: Message, - messages?: Message[] + messages?: Message[], ): NodeJS.Timeout { return setInterval(() => { if (this.handleMessageBatch) { return this.changeVisibilityTimeoutBatch( messages, - this.visibilityTimeout + this.visibilityTimeout, ); } else { return this.changeVisibilityTimeout(message, this.visibilityTimeout); @@ -415,23 +416,23 @@ export class Consumer extends TypedEventEmitter { */ private async changeVisibilityTimeout( message: Message, - timeout: number + timeout: number, ): Promise { try { const input: ChangeMessageVisibilityCommandInput = { QueueUrl: this.queueUrl, ReceiptHandle: message.ReceiptHandle, - VisibilityTimeout: timeout + VisibilityTimeout: timeout, }; return await this.sqs.send( new ChangeMessageVisibilityCommand(input), - this.sqsSendOptions + this.sqsSendOptions, ); } catch (err) { this.emit( - 'error', + "error", toSQSError(err, `Error changing visibility timeout: ${err.message}`), - message + message, ); } } @@ -443,26 +444,26 @@ export class Consumer extends TypedEventEmitter { */ private async changeVisibilityTimeoutBatch( messages: Message[], - timeout: number + timeout: number, ): Promise { const params: ChangeMessageVisibilityBatchCommandInput = { QueueUrl: this.queueUrl, Entries: messages.map((message) => ({ Id: message.MessageId, ReceiptHandle: message.ReceiptHandle, - VisibilityTimeout: timeout - })) + VisibilityTimeout: timeout, + })), }; try { return await this.sqs.send( new ChangeMessageVisibilityBatchCommand(params), - this.sqsSendOptions + this.sqsSendOptions, ); } catch (err) { this.emit( - 'error', + "error", toSQSError(err, `Error changing visibility timeout: ${err.message}`), - messages + messages, ); } } @@ -495,12 +496,12 @@ export class Consumer extends TypedEventEmitter { if (err instanceof TimeoutError) { throw toTimeoutError( err, - `Message handler timed out after ${this.handleMessageTimeout}ms: Operation timed out.` + `Message handler timed out after ${this.handleMessageTimeout}ms: Operation timed out.`, ); } else if (err instanceof Error) { throw toStandardError( err, - `Unexpected message handler failure: ${err.message}` + `Unexpected message handler failure: ${err.message}`, ); } throw err; @@ -526,7 +527,7 @@ export class Consumer extends TypedEventEmitter { if (err instanceof Error) { throw toStandardError( err, - `Unexpected message handler failure: ${err.message}` + `Unexpected message handler failure: ${err.message}`, ); } throw err; @@ -539,23 +540,23 @@ export class Consumer extends TypedEventEmitter { */ private async deleteMessage(message: Message): Promise { if (!this.shouldDeleteMessages) { - logger.debug('skipping_delete', { + logger.debug("skipping_delete", { detail: - 'Skipping message delete since shouldDeleteMessages is set to false' + "Skipping message delete since shouldDeleteMessages is set to false", }); return; } - logger.debug('deleting_message', { messageId: message.MessageId }); + logger.debug("deleting_message", { messageId: message.MessageId }); const deleteParams: DeleteMessageCommandInput = { QueueUrl: this.queueUrl, - ReceiptHandle: message.ReceiptHandle + ReceiptHandle: message.ReceiptHandle, }; try { await this.sqs.send( new DeleteMessageCommand(deleteParams), - this.sqsSendOptions + this.sqsSendOptions, ); } catch (err) { throw toSQSError(err, `SQS delete message failed: ${err.message}`); @@ -568,28 +569,28 @@ export class Consumer extends TypedEventEmitter { */ private async deleteMessageBatch(messages: Message[]): Promise { if (!this.shouldDeleteMessages) { - logger.debug('skipping_delete', { + logger.debug("skipping_delete", { detail: - 'Skipping message delete since shouldDeleteMessages is set to false' + "Skipping message delete since shouldDeleteMessages is set to false", }); return; } - logger.debug('deleting_messages', { - messageIds: messages.map((msg) => msg.MessageId) + logger.debug("deleting_messages", { + messageIds: messages.map((msg) => msg.MessageId), }); const deleteParams: DeleteMessageBatchCommandInput = { QueueUrl: this.queueUrl, Entries: messages.map((message) => ({ Id: message.MessageId, - ReceiptHandle: message.ReceiptHandle - })) + ReceiptHandle: message.ReceiptHandle, + })), }; try { await this.sqs.send( new DeleteMessageBatchCommand(deleteParams), - this.sqsSendOptions + this.sqsSendOptions, ); } catch (err) { throw toSQSError(err, `SQS delete message failed: ${err.message}`); diff --git a/src/emitter.ts b/src/emitter.ts index 4a360e70..1563377a 100644 --- a/src/emitter.ts +++ b/src/emitter.ts @@ -1,7 +1,7 @@ -import { EventEmitter } from 'events'; +import { EventEmitter } from "node:events"; -import { logger } from './logger'; -import { Events } from './types'; +import { logger } from "./logger.js"; +import { Events } from "./types.js"; export class TypedEventEmitter extends EventEmitter { /** @@ -11,7 +11,7 @@ export class TypedEventEmitter extends EventEmitter { */ on( event: E, - listener: (...args: Events[E]) => void + listener: (...args: Events[E]) => void, ): this { return super.on(event, listener); } @@ -22,7 +22,7 @@ export class TypedEventEmitter extends EventEmitter { */ once( event: E, - listener: (...args: Events[E]) => void + listener: (...args: Events[E]) => void, ): this { return super.once(event, listener); } diff --git a/src/errors.ts b/src/errors.ts index 4efe530d..71a25809 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,4 +1,4 @@ -import { AWSError } from './types'; +import { AWSError } from "./types.js"; class SQSError extends Error { code: string; @@ -6,7 +6,7 @@ class SQSError extends Error { service: string; time: Date; retryable: boolean; - fault: 'client' | 'server'; + fault: "client" | "server"; constructor(message: string) { super(message); @@ -18,10 +18,10 @@ class TimeoutError extends Error { cause: Error; time: Date; - constructor(message = 'Operation timed out.') { + constructor(message = "Operation timed out.") { super(message); this.message = message; - this.name = 'TimeoutError'; + this.name = "TimeoutError"; } } @@ -29,10 +29,10 @@ class StandardError extends Error { cause: Error; time: Date; - constructor(message = 'An unexpected error occurred:') { + constructor(message = "An unexpected error occurred:") { super(message); this.message = message; - this.name = 'StandardError'; + this.name = "StandardError"; } } @@ -44,10 +44,10 @@ function isConnectionError(err: Error): boolean { if (err instanceof SQSError) { return ( err.statusCode === 403 || - err.code === 'CredentialsError' || - err.code === 'UnknownEndpoint' || - err.code === 'AWS.SimpleQueueService.NonExistentQueue' || - err.code === 'CredentialsProviderError' + err.code === "CredentialsError" || + err.code === "UnknownEndpoint" || + err.code === "AWS.SimpleQueueService.NonExistentQueue" || + err.code === "CredentialsProviderError" ); } return false; @@ -102,5 +102,5 @@ export { isConnectionError, toSQSError, toStandardError, - toTimeoutError + toTimeoutError, }; diff --git a/src/index.ts b/src/index.ts index f1a8ea4b..78dc2b29 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,2 @@ -export { Consumer } from './consumer'; -export * from './types'; +export { Consumer } from "./consumer.js"; +export * from "./types.js"; diff --git a/src/logger.ts b/src/logger.ts index fc3e4c12..08d1a429 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,4 +1,5 @@ -const debug = require('debug')('sqs-consumer'); +import createDebug from 'debug'; +const debug = createDebug('sqs-consumer'); export const logger = { debug diff --git a/src/types.ts b/src/types.ts index d1577f88..2f01b0b1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { SQSClient, Message, QueueAttributeName } from '@aws-sdk/client-sqs'; +import { SQSClient, Message, QueueAttributeName } from "@aws-sdk/client-sqs"; /** * The options for the consumer. @@ -146,10 +146,10 @@ export interface ConsumerOptions { * A subset of the ConsumerOptions that can be updated at runtime. */ export type UpdatableOptions = - | 'visibilityTimeout' - | 'batchSize' - | 'waitTimeSeconds' - | 'pollingWaitTimeMs'; + | "visibilityTimeout" + | "batchSize" + | "waitTimeSeconds" + | "pollingWaitTimeMs"; /** * The options for the stop method. @@ -246,7 +246,7 @@ export type AWSError = { /** * Whether the client or server are at fault. */ - readonly $fault?: 'client' | 'server'; + readonly $fault?: "client" | "server"; /** * The service that encountered the exception. diff --git a/src/validation.ts b/src/validation.ts index 5fe6abb8..6de283d6 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -1,53 +1,53 @@ -import { ReceiveMessageCommandOutput } from '@aws-sdk/client-sqs'; +import { ReceiveMessageCommandOutput } from "@aws-sdk/client-sqs"; -import { ConsumerOptions } from './types'; +import { ConsumerOptions } from "./types.js"; const requiredOptions = [ - 'queueUrl', + "queueUrl", // only one of handleMessage / handleMessagesBatch is required - 'handleMessage|handleMessageBatch' + "handleMessage|handleMessageBatch", ]; function validateOption( option: string, value: any, allOptions: { [key: string]: any }, - strict?: boolean + strict?: boolean, ): void { switch (option) { - case 'batchSize': + case "batchSize": if (value > 10 || value < 1) { - throw new Error('batchSize must be between 1 and 10.'); + throw new Error("batchSize must be between 1 and 10."); } break; - case 'heartbeatInterval': + case "heartbeatInterval": if ( !allOptions.visibilityTimeout || value >= allOptions.visibilityTimeout ) { throw new Error( - 'heartbeatInterval must be less than visibilityTimeout.' + "heartbeatInterval must be less than visibilityTimeout.", ); } break; - case 'visibilityTimeout': + case "visibilityTimeout": if ( allOptions.heartbeatInterval && value <= allOptions.heartbeatInterval ) { throw new Error( - 'heartbeatInterval must be less than visibilityTimeout.' + "heartbeatInterval must be less than visibilityTimeout.", ); } break; - case 'waitTimeSeconds': + case "waitTimeSeconds": if (value < 1 || value > 20) { - throw new Error('waitTimeSeconds must be between 0 and 20.'); + throw new Error("waitTimeSeconds must be between 0 and 20."); } break; - case 'pollingWaitTimeMs': + case "pollingWaitTimeMs": if (value < 0) { - throw new Error('pollingWaitTimeMs must be greater than 0.'); + throw new Error("pollingWaitTimeMs must be greater than 0."); } break; default: @@ -64,19 +64,19 @@ function validateOption( */ function assertOptions(options: ConsumerOptions): void { requiredOptions.forEach((option) => { - const possibilities = option.split('|'); + const possibilities = option.split("|"); if (!possibilities.find((p) => options[p])) { throw new Error( - `Missing SQS consumer option [ ${possibilities.join(' or ')} ].` + `Missing SQS consumer option [ ${possibilities.join(" or ")} ].`, ); } }); if (options.batchSize) { - validateOption('batchSize', options.batchSize, options); + validateOption("batchSize", options.batchSize, options); } if (options.heartbeatInterval) { - validateOption('heartbeatInterval', options.heartbeatInterval, options); + validateOption("heartbeatInterval", options.heartbeatInterval, options); } } diff --git a/test/config/cucumber.js b/test/config/cucumber.js deleted file mode 100644 index 62195b44..00000000 --- a/test/config/cucumber.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - default: { - parallel: 0, - format: ['html:test/reports/cucumber-report.html'], - paths: ['test/features'], - forceExit: true - } -}; diff --git a/test/config/cucumber.mjs b/test/config/cucumber.mjs new file mode 100644 index 00000000..b160c04e --- /dev/null +++ b/test/config/cucumber.mjs @@ -0,0 +1,6 @@ +export default { + parallel: 0, + format: ['html:test/reports/cucumber-report.html'], + paths: ['test/features'], + forceExit: true +}; diff --git a/test/features/step_definitions/gracefulShutdown.js b/test/features/step_definitions/gracefulShutdown.js index 00a660d2..e6d05ab9 100644 --- a/test/features/step_definitions/gracefulShutdown.js +++ b/test/features/step_definitions/gracefulShutdown.js @@ -1,54 +1,54 @@ -const { Given, Then, After } = require('@cucumber/cucumber'); -const assert = require('assert'); -const { PurgeQueueCommand } = require('@aws-sdk/client-sqs'); -const pEvent = require('p-event'); +import { Given, Then, After } from "@cucumber/cucumber"; +import { strictEqual } from "node:assert"; +import { PurgeQueueCommand } from "@aws-sdk/client-sqs"; +import { pEvent } from "p-event"; -const { consumer } = require('../utils/consumer/gracefulShutdown'); -const { producer } = require('../utils/producer'); -const { sqs, QUEUE_URL } = require('../utils/sqs'); +import { consumer } from "../utils/consumer/gracefulShutdown.js"; +import { producer } from "../utils/producer.js"; +import { sqs, QUEUE_URL } from "../utils/sqs.js"; -Given('Several messages are sent to the SQS queue', async () => { +Given("Several messages are sent to the SQS queue", async () => { const params = { - QueueUrl: QUEUE_URL + QueueUrl: QUEUE_URL, }; const command = new PurgeQueueCommand(params); const response = await sqs.send(command); - assert.strictEqual(response['$metadata'].httpStatusCode, 200); + strictEqual(response["$metadata"].httpStatusCode, 200); const size = await producer.queueSize(); - assert.strictEqual(size, 0); + strictEqual(size, 0); - await producer.send(['msg1', 'msg2', 'msg3']); + await producer.send(["msg1", "msg2", "msg3"]); const size2 = await producer.queueSize(); - assert.strictEqual(size2, 3); + strictEqual(size2, 3); }); -Then('the application is stopped while messages are in flight', async () => { +Then("the application is stopped while messages are in flight", async () => { consumer.start(); consumer.stop(); - assert.strictEqual(consumer.status.isRunning, false); + strictEqual(consumer.status.isRunning, false); }); Then( - 'the in-flight messages should be processed before stopped is emitted', + "the in-flight messages should be processed before stopped is emitted", async () => { let numProcessed = 0; - consumer.on('message_processed', () => { + consumer.on("message_processed", () => { numProcessed++; }); - await pEvent(consumer, 'stopped'); + await pEvent(consumer, "stopped"); - assert.strictEqual(numProcessed, 3); + strictEqual(numProcessed, 3); const size = await producer.queueSize(); - assert.strictEqual(size, 0); - } + strictEqual(size, 0); + }, ); After(() => { diff --git a/test/features/step_definitions/handleMessage.js b/test/features/step_definitions/handleMessage.js index b1a2c219..b7b768e3 100644 --- a/test/features/step_definitions/handleMessage.js +++ b/test/features/step_definitions/handleMessage.js @@ -1,87 +1,87 @@ -const { Given, Then, After } = require('@cucumber/cucumber'); -const assert = require('assert'); -const { PurgeQueueCommand } = require('@aws-sdk/client-sqs'); -const pEvent = require('p-event'); +import { Given, Then, After } from "@cucumber/cucumber"; +import { strictEqual } from "node:assert"; +import { PurgeQueueCommand } from "@aws-sdk/client-sqs"; +import { pEvent } from "p-event"; -const { consumer } = require('../utils/consumer/handleMessage'); -const { producer } = require('../utils/producer'); -const { sqs, QUEUE_URL } = require('../utils/sqs'); +import { consumer } from "../utils/consumer/handleMessage.js"; +import { producer } from "../utils/producer.js"; +import { sqs, QUEUE_URL } from "../utils/sqs.js"; -Given('a message is sent to the SQS queue', async () => { +Given("a message is sent to the SQS queue", async () => { const params = { - QueueUrl: QUEUE_URL + QueueUrl: QUEUE_URL, }; const command = new PurgeQueueCommand(params); const response = await sqs.send(command); - assert.strictEqual(response['$metadata'].httpStatusCode, 200); + strictEqual(response["$metadata"].httpStatusCode, 200); - await producer.send(['msg1']); + await producer.send(["msg1"]); const size = await producer.queueSize(); - assert.strictEqual(size, 1); + strictEqual(size, 1); }); -Then('the message should be consumed without error', async () => { +Then("the message should be consumed without error", async () => { consumer.start(); - assert.strictEqual(consumer.status.isRunning, true); + strictEqual(consumer.status.isRunning, true); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); - assert.strictEqual(consumer.status.isRunning, false); + strictEqual(consumer.status.isRunning, false); const size = await producer.queueSize(); - assert.strictEqual(size, 0); + strictEqual(size, 0); }); -Given('messages are sent to the SQS queue', async () => { +Given("messages are sent to the SQS queue", async () => { const params = { - QueueUrl: QUEUE_URL + QueueUrl: QUEUE_URL, }; const command = new PurgeQueueCommand(params); const response = await sqs.send(command); - assert.strictEqual(response['$metadata'].httpStatusCode, 200); + strictEqual(response["$metadata"].httpStatusCode, 200); - await producer.send(['msg2', 'msg3', 'msg4']); + await producer.send(["msg2", "msg3", "msg4"]); const size = await producer.queueSize(); - assert.strictEqual(size, 3); + strictEqual(size, 3); }); Then( - 'the messages should be consumed without error', + "the messages should be consumed without error", { timeout: 2 * 5000 }, async () => { consumer.start(); - assert.strictEqual(consumer.status.isRunning, true); + strictEqual(consumer.status.isRunning, true); - await pEvent(consumer, 'message_received'); + await pEvent(consumer, "message_received"); const size = await producer.queueSize(); - assert.strictEqual(size, 2); + strictEqual(size, 2); - await pEvent(consumer, 'message_received'); + await pEvent(consumer, "message_received"); const size2 = await producer.queueSize(); - assert.strictEqual(size2, 1); + strictEqual(size2, 1); - await pEvent(consumer, 'message_received'); + await pEvent(consumer, "message_received"); const size3 = await producer.queueSize(); - assert.strictEqual(size3, 0); + strictEqual(size3, 0); consumer.stop(); - assert.strictEqual(consumer.status.isRunning, false); - } + strictEqual(consumer.status.isRunning, false); + }, ); After(() => { diff --git a/test/features/step_definitions/handleMessageBatch.js b/test/features/step_definitions/handleMessageBatch.js index 9eee6ebc..c2af06ad 100644 --- a/test/features/step_definitions/handleMessageBatch.js +++ b/test/features/step_definitions/handleMessageBatch.js @@ -1,79 +1,79 @@ -const { Given, Then, After } = require('@cucumber/cucumber'); -const assert = require('assert'); -const { PurgeQueueCommand } = require('@aws-sdk/client-sqs'); -const pEvent = require('p-event'); +import { Given, Then, After } from "@cucumber/cucumber"; +import { strictEqual } from "node:assert"; +import { PurgeQueueCommand } from "@aws-sdk/client-sqs"; +import { pEvent } from "p-event"; -const { consumer } = require('../utils/consumer/handleMessageBatch'); -const { producer } = require('../utils/producer'); -const { sqs, QUEUE_URL } = require('../utils/sqs'); +import { consumer } from "../utils/consumer/handleMessageBatch.js"; +import { producer } from "../utils/producer.js"; +import { sqs, QUEUE_URL } from "../utils/sqs.js"; -Given('a message batch is sent to the SQS queue', async () => { +Given("a message batch is sent to the SQS queue", async () => { const params = { - QueueUrl: QUEUE_URL + QueueUrl: QUEUE_URL, }; const command = new PurgeQueueCommand(params); const response = await sqs.send(command); - assert.strictEqual(response['$metadata'].httpStatusCode, 200); + strictEqual(response["$metadata"].httpStatusCode, 200); - await producer.send(['msg1', 'msg2', 'msg3', 'msg4']); + await producer.send(["msg1", "msg2", "msg3", "msg4"]); const size = await producer.queueSize(); - assert.strictEqual(size, 4); + strictEqual(size, 4); }); -Then('the message batch should be consumed without error', async () => { +Then("the message batch should be consumed without error", async () => { consumer.start(); - assert.strictEqual(consumer.status.isRunning, true); + strictEqual(consumer.status.isRunning, true); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); - assert.strictEqual(consumer.status.isRunning, false); + strictEqual(consumer.status.isRunning, false); const size = await producer.queueSize(); - assert.strictEqual(size, 0); + strictEqual(size, 0); }); -Given('message batches are sent to the SQS queue', async () => { +Given("message batches are sent to the SQS queue", async () => { const params = { - QueueUrl: QUEUE_URL + QueueUrl: QUEUE_URL, }; const command = new PurgeQueueCommand(params); const response = await sqs.send(command); - assert.strictEqual(response['$metadata'].httpStatusCode, 200); + strictEqual(response["$metadata"].httpStatusCode, 200); - await producer.send(['msg1', 'msg2', 'msg3', 'msg4', 'msg5', 'msg6']); + await producer.send(["msg1", "msg2", "msg3", "msg4", "msg5", "msg6"]); const size = await producer.queueSize(); - assert.strictEqual(size, 6); + strictEqual(size, 6); }); Then( - 'the message batches should be consumed without error', + "the message batches should be consumed without error", { timeout: 2 * 5000 }, async () => { consumer.start(); - assert.strictEqual(consumer.status.isRunning, true); + strictEqual(consumer.status.isRunning, true); - await pEvent(consumer, 'message_received'); + await pEvent(consumer, "message_received"); const size = await producer.queueSize(); - assert.strictEqual(size, 1); + strictEqual(size, 1); - await pEvent(consumer, 'message_received'); + await pEvent(consumer, "message_received"); const size2 = await producer.queueSize(); - assert.strictEqual(size2, 0); + strictEqual(size2, 0); consumer.stop(); - assert.strictEqual(consumer.status.isRunning, false); - } + strictEqual(consumer.status.isRunning, false); + }, ); After(() => { diff --git a/test/features/utils/consumer/gracefulShutdown.js b/test/features/utils/consumer/gracefulShutdown.js index 4d6e26a3..41c28340 100644 --- a/test/features/utils/consumer/gracefulShutdown.js +++ b/test/features/utils/consumer/gracefulShutdown.js @@ -1,8 +1,8 @@ -const { Consumer } = require('../../../../dist/consumer'); +import { Consumer } from "../../../../dist/consumer.js"; -const { QUEUE_URL, sqs } = require('../sqs'); +import { QUEUE_URL, sqs } from "../sqs.js"; -const consumer = Consumer.create({ +export const consumer = Consumer.create({ queueUrl: QUEUE_URL, sqs, pollingWaitTimeMs: 1000, @@ -11,7 +11,5 @@ const consumer = Consumer.create({ handleMessage: async (message) => { await new Promise((resolve) => setTimeout(resolve, 1500)); return message; - } + }, }); - -exports.consumer = consumer; diff --git a/test/features/utils/consumer/handleMessage.js b/test/features/utils/consumer/handleMessage.js index 076b0713..16a6052a 100644 --- a/test/features/utils/consumer/handleMessage.js +++ b/test/features/utils/consumer/handleMessage.js @@ -1,14 +1,12 @@ -const { Consumer } = require('../../../../dist/consumer'); +import { Consumer } from "../../../../dist/consumer.js"; -const { QUEUE_URL, sqs } = require('../sqs'); +import { QUEUE_URL, sqs } from "../sqs.js"; -const consumer = Consumer.create({ +export const consumer = Consumer.create({ queueUrl: QUEUE_URL, sqs, pollingWaitTimeMs: 100, handleMessage: async (message) => { return message; - } + }, }); - -exports.consumer = consumer; diff --git a/test/features/utils/consumer/handleMessageBatch.js b/test/features/utils/consumer/handleMessageBatch.js index a28bbe00..51636920 100644 --- a/test/features/utils/consumer/handleMessageBatch.js +++ b/test/features/utils/consumer/handleMessageBatch.js @@ -1,15 +1,13 @@ -const { Consumer } = require('../../../../dist/consumer'); +import { Consumer } from "../../../../dist/consumer.js"; -const { QUEUE_URL, sqs } = require('../sqs'); +import { QUEUE_URL, sqs } from "../sqs.js"; -const consumer = Consumer.create({ +export const consumer = Consumer.create({ queueUrl: QUEUE_URL, sqs, pollingWaitTimeMs: 100, batchSize: 5, handleMessageBatch: async (messages) => { return messages; - } + }, }); - -exports.consumer = consumer; diff --git a/test/features/utils/delay.js b/test/features/utils/delay.js index bce17f21..9cc57777 100644 --- a/test/features/utils/delay.js +++ b/test/features/utils/delay.js @@ -1,5 +1,3 @@ -function delay(ms) { +export function delay(ms) { return new Promise((res) => setTimeout(res, ms)); } - -exports.delay = delay; diff --git a/test/features/utils/producer.js b/test/features/utils/producer.js index fc3ab26d..881b0866 100644 --- a/test/features/utils/producer.js +++ b/test/features/utils/producer.js @@ -1,11 +1,9 @@ -const { Producer } = require('sqs-producer'); +import { Producer } from "sqs-producer"; -const { QUEUE_URL, sqsConfig, sqs } = require('./sqs'); +import { QUEUE_URL, sqsConfig, sqs } from "./sqs.js"; -const producer = Producer.create({ +export const producer = Producer.create({ queueUrl: QUEUE_URL, region: sqsConfig.region, - sqs + sqs, }); - -exports.producer = producer; diff --git a/test/features/utils/sqs.js b/test/features/utils/sqs.js index feee2f4a..4a12a530 100644 --- a/test/features/utils/sqs.js +++ b/test/features/utils/sqs.js @@ -1,18 +1,16 @@ -const { SQSClient } = require('@aws-sdk/client-sqs'); +import { SQSClient } from "@aws-sdk/client-sqs"; -const sqsConfig = { - region: 'eu-west-1', - endpoint: 'http://localhost:4566', +export const sqsConfig = { + region: "eu-west-1", + endpoint: "http://localhost:4566", credentials: { - accessKeyId: 'key', - secretAccessKey: 'secret' - } + accessKeyId: "key", + secretAccessKey: "secret", + }, }; -exports.sqs = new SQSClient(sqsConfig); +export const sqs = new SQSClient(sqsConfig); -exports.QUEUE_URL = +export const QUEUE_URL = process.env.SQS_QUEUE_URL || - 'http://localhost:4566/000000000000/sqs-consumer-data'; - -exports.sqsConfig = sqsConfig; + "http://localhost:4566/000000000000/sqs-consumer-data"; diff --git a/test/tests/consumer.test.ts b/test/tests/consumer.test.ts index 99624f2f..ab5300a6 100644 --- a/test/tests/consumer.test.ts +++ b/test/tests/consumer.test.ts @@ -5,33 +5,33 @@ import { DeleteMessageCommand, ReceiveMessageCommand, SQSClient, - QueueAttributeName -} from '@aws-sdk/client-sqs'; -import { assert } from 'chai'; -import * as sinon from 'sinon'; -import * as pEvent from 'p-event'; + QueueAttributeName, +} from "@aws-sdk/client-sqs"; +import { assert } from "chai"; +import * as sinon from "sinon"; +import { pEvent } from "p-event"; -import { AWSError } from '../../src/types'; -import { Consumer } from '../../src/consumer'; -import { logger } from '../../src/logger'; +import { AWSError } from "../../src/types.js"; +import { Consumer } from "../../src/consumer.js"; +import { logger } from "../../src/logger.js"; const sandbox = sinon.createSandbox(); const AUTHENTICATION_ERROR_TIMEOUT = 20; const POLLING_TIMEOUT = 100; -const QUEUE_URL = 'some-queue-url'; -const REGION = 'some-region'; +const QUEUE_URL = "some-queue-url"; +const REGION = "some-region"; const mockReceiveMessage = sinon.match.instanceOf(ReceiveMessageCommand); const mockDeleteMessage = sinon.match.instanceOf(DeleteMessageCommand); const mockDeleteMessageBatch = sinon.match.instanceOf( - DeleteMessageBatchCommand + DeleteMessageBatchCommand, ); const mockChangeMessageVisibility = sinon.match.instanceOf( - ChangeMessageVisibilityCommand + ChangeMessageVisibilityCommand, ); const mockChangeMessageVisibilityBatch = sinon.match.instanceOf( - ChangeMessageVisibilityBatchCommand + ChangeMessageVisibilityBatchCommand, ); class MockSQSError extends Error implements AWSError { @@ -43,7 +43,7 @@ class MockSQSError extends Error implements AWSError { $retryable: { throttling: boolean; }; - $fault: 'client' | 'server'; + $fault: "client" | "server"; time: Date; constructor(message: string) { @@ -52,7 +52,7 @@ class MockSQSError extends Error implements AWSError { } } -describe('Consumer', () => { +describe("Consumer", () => { let consumer; let clock; let handleMessage; @@ -61,11 +61,11 @@ describe('Consumer', () => { const response = { Messages: [ { - ReceiptHandle: 'receipt-handle', - MessageId: '123', - Body: 'body' - } - ] + ReceiptHandle: "receipt-handle", + MessageId: "123", + Body: "body", + }, + ], }; beforeEach(() => { @@ -86,7 +86,7 @@ describe('Consumer', () => { region: REGION, handleMessage, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); }); @@ -95,80 +95,80 @@ describe('Consumer', () => { sandbox.restore(); }); - describe('options validation', () => { - it('requires a handleMessage or handleMessagesBatch function to be set', () => { + describe("options validation", () => { + it("requires a handleMessage or handleMessagesBatch function to be set", () => { assert.throws(() => { new Consumer({ handleMessage: undefined, region: REGION, - queueUrl: QUEUE_URL + queueUrl: QUEUE_URL, }); }, `Missing SQS consumer option [ handleMessage or handleMessageBatch ].`); }); - it('requires the batchSize option to be no greater than 10', () => { + it("requires the batchSize option to be no greater than 10", () => { assert.throws(() => { new Consumer({ region: REGION, queueUrl: QUEUE_URL, handleMessage, - batchSize: 11 + batchSize: 11, }); - }, 'batchSize must be between 1 and 10.'); + }, "batchSize must be between 1 and 10."); }); - it('requires the batchSize option to be greater than 0', () => { + it("requires the batchSize option to be greater than 0", () => { assert.throws(() => { new Consumer({ region: REGION, queueUrl: QUEUE_URL, handleMessage, - batchSize: -1 + batchSize: -1, }); - }, 'batchSize must be between 1 and 10.'); + }, "batchSize must be between 1 and 10."); }); - it('requires visibilityTimeout to be set with heartbeatInterval', () => { + it("requires visibilityTimeout to be set with heartbeatInterval", () => { assert.throws(() => { new Consumer({ region: REGION, queueUrl: QUEUE_URL, handleMessage, - heartbeatInterval: 30 + heartbeatInterval: 30, }); - }, 'heartbeatInterval must be less than visibilityTimeout.'); + }, "heartbeatInterval must be less than visibilityTimeout."); }); - it('requires heartbeatInterval to be less than visibilityTimeout', () => { + it("requires heartbeatInterval to be less than visibilityTimeout", () => { assert.throws(() => { new Consumer({ region: REGION, queueUrl: QUEUE_URL, handleMessage, heartbeatInterval: 30, - visibilityTimeout: 30 + visibilityTimeout: 30, }); - }, 'heartbeatInterval must be less than visibilityTimeout.'); + }, "heartbeatInterval must be less than visibilityTimeout."); }); }); - describe('.create', () => { - it('creates a new instance of a Consumer object', () => { + describe(".create", () => { + it("creates a new instance of a Consumer object", () => { const instance = Consumer.create({ region: REGION, queueUrl: QUEUE_URL, batchSize: 1, visibilityTimeout: 10, waitTimeSeconds: 10, - handleMessage + handleMessage, }); assert.instanceOf(instance, Consumer); }); }); - describe('.start', () => { - it('uses the correct abort signal', async () => { + describe(".start", () => { + it("uses the correct abort signal", async () => { sqs.send .withArgs(mockReceiveMessage) .resolves(new Promise((res) => setTimeout(res, 100))); @@ -194,10 +194,10 @@ describe('Consumer', () => { assert.isFalse(sqs.send.lastCall.lastArg.abortSignal.aborted); }); - it('fires an event when the consumer is started', async () => { + it("fires an event when the consumer is started", async () => { const handleStart = sandbox.stub().returns(null); - consumer.on('started', handleStart); + consumer.on("started", handleStart); consumer.start(); consumer.stop(); @@ -205,40 +205,40 @@ describe('Consumer', () => { sandbox.assert.calledOnce(handleStart); }); - it('fires an error event when an error occurs receiving a message', async () => { - const receiveErr = new Error('Receive error'); + it("fires an error event when an error occurs receiving a message", async () => { + const receiveErr = new Error("Receive error"); sqs.send.withArgs(mockReceiveMessage).rejects(receiveErr); consumer.start(); - const err: any = await pEvent(consumer, 'error'); + const err: any = await pEvent(consumer, "error"); consumer.stop(); assert.ok(err); - assert.equal(err.message, 'SQS receive message failed: Receive error'); + assert.equal(err.message, "SQS receive message failed: Receive error"); }); - it('retains sqs error information', async () => { - const receiveErr = new MockSQSError('Receive error'); - receiveErr.name = 'short code'; + it("retains sqs error information", async () => { + const receiveErr = new MockSQSError("Receive error"); + receiveErr.name = "short code"; receiveErr.$retryable = { - throttling: false + throttling: false, }; receiveErr.$metadata = { - httpStatusCode: 403 + httpStatusCode: 403, }; receiveErr.time = new Date(); - receiveErr.$service = 'service'; + receiveErr.$service = "service"; sqs.send.withArgs(mockReceiveMessage).rejects(receiveErr); consumer.start(); - const err: any = await pEvent(consumer, 'error'); + const err: any = await pEvent(consumer, "error"); consumer.stop(); assert.ok(err); - assert.equal(err.message, 'SQS receive message failed: Receive error'); + assert.equal(err.message, "SQS receive message failed: Receive error"); assert.equal(err.code, receiveErr.name); assert.equal(err.retryable, receiveErr.$retryable.throttling); assert.equal(err.statusCode, receiveErr.$metadata.httpStatusCode); @@ -247,7 +247,7 @@ describe('Consumer', () => { assert.equal(err.fault, receiveErr.$fault); }); - it('fires a timeout event if handler function takes too long', async () => { + it("fires a timeout event if handler function takes too long", async () => { const handleMessageTimeout = 500; consumer = new Consumer({ queueUrl: QUEUE_URL, @@ -256,46 +256,46 @@ describe('Consumer', () => { new Promise((resolve) => setTimeout(resolve, 1000)), handleMessageTimeout, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); consumer.start(); const [err]: any = await Promise.all([ - pEvent(consumer, 'timeout_error'), - clock.tickAsync(handleMessageTimeout) + pEvent(consumer, "timeout_error"), + clock.tickAsync(handleMessageTimeout), ]); consumer.stop(); assert.ok(err); assert.equal( err.message, - `Message handler timed out after ${handleMessageTimeout}ms: Operation timed out.` + `Message handler timed out after ${handleMessageTimeout}ms: Operation timed out.`, ); }); - it('handles unexpected exceptions thrown by the handler function', async () => { + it("handles unexpected exceptions thrown by the handler function", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage: () => { - throw new Error('unexpected parsing error'); + throw new Error("unexpected parsing error"); }, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); consumer.start(); - const err: any = await pEvent(consumer, 'processing_error'); + const err: any = await pEvent(consumer, "processing_error"); consumer.stop(); assert.ok(err); assert.equal( err.message, - 'Unexpected message handler failure: unexpected parsing error' + "Unexpected message handler failure: unexpected parsing error", ); }); - it('handles non-standard objects thrown by the handler function', async () => { + it("handles non-standard objects thrown by the handler function", async () => { class CustomError { private _message: string; @@ -312,24 +312,24 @@ describe('Consumer', () => { queueUrl: QUEUE_URL, region: REGION, handleMessage: () => { - throw new CustomError('unexpected parsing error'); + throw new CustomError("unexpected parsing error"); }, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); consumer.start(); - const err: any = await pEvent(consumer, 'processing_error'); + const err: any = await pEvent(consumer, "processing_error"); consumer.stop(); assert.ok(err); - assert.equal(err.message, 'unexpected parsing error'); + assert.equal(err.message, "unexpected parsing error"); }); - it('handles non-standard exceptions thrown by the handler function', async () => { + it("handles non-standard exceptions thrown by the handler function", async () => { const customError = new Error(); - Object.defineProperty(customError, 'message', { - get: () => 'unexpected parsing error' + Object.defineProperty(customError, "message", { + get: () => "unexpected parsing error", }); consumer = new Consumer({ @@ -339,36 +339,36 @@ describe('Consumer', () => { throw customError; }, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); consumer.start(); - const err: any = await pEvent(consumer, 'processing_error'); + const err: any = await pEvent(consumer, "processing_error"); consumer.stop(); assert.ok(err); assert.equal( err.message, - 'Unexpected message handler failure: unexpected parsing error' + "Unexpected message handler failure: unexpected parsing error", ); }); - it('fires an error event when an error occurs deleting a message', async () => { - const deleteErr = new Error('Delete error'); + it("fires an error event when an error occurs deleting a message", async () => { + const deleteErr = new Error("Delete error"); handleMessage.resolves(null); sqs.send.withArgs(mockDeleteMessage).rejects(deleteErr); consumer.start(); - const err: any = await pEvent(consumer, 'error'); + const err: any = await pEvent(consumer, "error"); consumer.stop(); assert.ok(err); - assert.equal(err.message, 'SQS delete message failed: Delete error'); + assert.equal(err.message, "SQS delete message failed: Delete error"); }); - it('fires a `processing_error` event when a non-`SQSError` error occurs processing a message', async () => { - const processingErr = new Error('Processing error'); + it("fires a `processing_error` event when a non-`SQSError` error occurs processing a message", async () => { + const processingErr = new Error("Processing error"); handleMessage.rejects(processingErr); @@ -376,21 +376,21 @@ describe('Consumer', () => { const [err, message] = await pEvent< string | symbol, { [key: string]: string }[] - >(consumer, 'processing_error', { - multiArgs: true + >(consumer, "processing_error", { + multiArgs: true, }); consumer.stop(); assert.equal( - err instanceof Error ? err.message : '', - 'Unexpected message handler failure: Processing error' + err instanceof Error ? err.message : "", + "Unexpected message handler failure: Processing error", ); - assert.equal(message.MessageId, '123'); + assert.equal(message.MessageId, "123"); }); - it('fires an `error` event when an `SQSError` occurs processing a message', async () => { - const sqsError = new Error('Processing error'); - sqsError.name = 'SQSError'; + it("fires an `error` event when an `SQSError` occurs processing a message", async () => { + const sqsError = new Error("Processing error"); + sqsError.name = "SQSError"; handleMessage.resolves(); sqs.send.withArgs(mockDeleteMessage).rejects(sqsError); @@ -399,23 +399,23 @@ describe('Consumer', () => { const [err, message] = await pEvent< string | symbol, { [key: string]: string }[] - >(consumer, 'error', { - multiArgs: true + >(consumer, "error", { + multiArgs: true, }); consumer.stop(); - assert.equal(err.message, 'SQS delete message failed: Processing error'); - assert.equal(message.MessageId, '123'); + assert.equal(err.message, "SQS delete message failed: Processing error"); + assert.equal(message.MessageId, "123"); }); - it('waits before repolling when a credentials error occurs', async () => { + it("waits before repolling when a credentials error occurs", async () => { const credentialsErr = { - name: 'CredentialsError', - message: 'Missing credentials in config' + name: "CredentialsError", + message: "Missing credentials in config", }; sqs.send.withArgs(mockReceiveMessage).rejects(credentialsErr); const errorListener = sandbox.stub(); - consumer.on('error', errorListener); + consumer.on("error", errorListener); consumer.start(); await clock.tickAsync(AUTHENTICATION_ERROR_TIMEOUT); @@ -426,16 +426,16 @@ describe('Consumer', () => { sandbox.assert.calledWithMatch(sqs.send.secondCall, mockReceiveMessage); }); - it('waits before repolling when a 403 error occurs', async () => { + it("waits before repolling when a 403 error occurs", async () => { const invalidSignatureErr = { $metadata: { - httpStatusCode: 403 + httpStatusCode: 403, }, - message: 'The security token included in the request is invalid' + message: "The security token included in the request is invalid", }; sqs.send.withArgs(mockReceiveMessage).rejects(invalidSignatureErr); const errorListener = sandbox.stub(); - consumer.on('error', errorListener); + consumer.on("error", errorListener); consumer.start(); await clock.tickAsync(AUTHENTICATION_ERROR_TIMEOUT); @@ -446,15 +446,15 @@ describe('Consumer', () => { sandbox.assert.calledWithMatch(sqs.send.secondCall, mockReceiveMessage); }); - it('waits before repolling when a UnknownEndpoint error occurs', async () => { + it("waits before repolling when a UnknownEndpoint error occurs", async () => { const unknownEndpointErr = { - name: 'UnknownEndpoint', + name: "UnknownEndpoint", message: - 'Inaccessible host: `sqs.eu-west-1.amazonaws.com`. This service may not be available in the `eu-west-1` region.' + "Inaccessible host: `sqs.eu-west-1.amazonaws.com`. This service may not be available in the `eu-west-1` region.", }; sqs.send.withArgs(mockReceiveMessage).rejects(unknownEndpointErr); const errorListener = sandbox.stub(); - consumer.on('error', errorListener); + consumer.on("error", errorListener); consumer.start(); await clock.tickAsync(AUTHENTICATION_ERROR_TIMEOUT); @@ -466,14 +466,14 @@ describe('Consumer', () => { sandbox.assert.calledWithMatch(sqs.send.secondCall, mockReceiveMessage); }); - it('waits before repolling when a NonExistentQueue error occurs', async () => { + it("waits before repolling when a NonExistentQueue error occurs", async () => { const nonExistentQueueErr = { - name: 'AWS.SimpleQueueService.NonExistentQueue', - message: 'The specified queue does not exist for this wsdl version.' + name: "AWS.SimpleQueueService.NonExistentQueue", + message: "The specified queue does not exist for this wsdl version.", }; sqs.send.withArgs(mockReceiveMessage).rejects(nonExistentQueueErr); const errorListener = sandbox.stub(); - consumer.on('error', errorListener); + consumer.on("error", errorListener); consumer.start(); await clock.tickAsync(AUTHENTICATION_ERROR_TIMEOUT); @@ -485,14 +485,14 @@ describe('Consumer', () => { sandbox.assert.calledWithMatch(sqs.send.secondCall, mockReceiveMessage); }); - it('waits before repolling when a CredentialsProviderError error occurs', async () => { + it("waits before repolling when a CredentialsProviderError error occurs", async () => { const credentialsProviderErr = { - name: 'CredentialsProviderError', - message: 'Could not load credentials from any providers.' + name: "CredentialsProviderError", + message: "Could not load credentials from any providers.", }; sqs.send.withArgs(mockReceiveMessage).rejects(credentialsProviderErr); const errorListener = sandbox.stub(); - consumer.on('error', errorListener); + consumer.on("error", errorListener); consumer.start(); await clock.tickAsync(AUTHENTICATION_ERROR_TIMEOUT); @@ -504,14 +504,14 @@ describe('Consumer', () => { sandbox.assert.calledWithMatch(sqs.send.secondCall, mockReceiveMessage); }); - it('waits before repolling when a polling timeout is set', async () => { + it("waits before repolling when a polling timeout is set", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage, sqs, authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, - pollingWaitTimeMs: POLLING_TIMEOUT + pollingWaitTimeMs: POLLING_TIMEOUT, }); consumer.start(); @@ -525,33 +525,33 @@ describe('Consumer', () => { sandbox.assert.calledWithMatch(sqs.send.getCall(3), mockDeleteMessage); }); - it('fires a message_received event when a message is received', async () => { + it("fires a message_received event when a message is received", async () => { consumer.start(); - const message = await pEvent(consumer, 'message_received'); + const message = await pEvent(consumer, "message_received"); consumer.stop(); assert.equal(message, response.Messages[0]); }); - it('fires a message_processed event when a message is successfully deleted', async () => { + it("fires a message_processed event when a message is successfully deleted", async () => { handleMessage.resolves(); consumer.start(); - const message = await pEvent(consumer, 'message_received'); + const message = await pEvent(consumer, "message_received"); consumer.stop(); assert.equal(message, response.Messages[0]); }); - it('calls the handleMessage function when a message is received', async () => { + it("calls the handleMessage function when a message is received", async () => { consumer.start(); - await pEvent(consumer, 'message_processed'); + await pEvent(consumer, "message_processed"); consumer.stop(); sandbox.assert.calledWith(handleMessage, response.Messages[0]); }); - it('calls the preReceiveMessageCallback and postReceiveMessageCallback function before receiving a message', async () => { + it("calls the preReceiveMessageCallback and postReceiveMessageCallback function before receiving a message", async () => { const preReceiveMessageCallbackStub = sandbox.stub().resolves(null); const postReceiveMessageCallbackStub = sandbox.stub().resolves(null); @@ -562,22 +562,22 @@ describe('Consumer', () => { sqs, authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, preReceiveMessageCallback: preReceiveMessageCallbackStub, - postReceiveMessageCallback: postReceiveMessageCallbackStub + postReceiveMessageCallback: postReceiveMessageCallbackStub, }); consumer.start(); - await pEvent(consumer, 'message_processed'); + await pEvent(consumer, "message_processed"); consumer.stop(); sandbox.assert.calledOnce(preReceiveMessageCallbackStub); sandbox.assert.calledOnce(postReceiveMessageCallbackStub); }); - it('deletes the message when the handleMessage function is called', async () => { + it("deletes the message when the handleMessage function is called", async () => { handleMessage.resolves(); consumer.start(); - await pEvent(consumer, 'message_processed'); + await pEvent(consumer, "message_processed"); consumer.stop(); sandbox.assert.calledWith(sqs.send.secondCall, mockDeleteMessage); @@ -585,41 +585,41 @@ describe('Consumer', () => { sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle' - }) + ReceiptHandle: "receipt-handle", + }), ); }); - it('does not delete the message if shouldDeleteMessages is false', async () => { + it("does not delete the message if shouldDeleteMessages is false", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage, sqs, authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, - shouldDeleteMessages: false + shouldDeleteMessages: false, }); handleMessage.resolves(); consumer.start(); - await pEvent(consumer, 'message_processed'); + await pEvent(consumer, "message_processed"); consumer.stop(); sandbox.assert.neverCalledWithMatch(sqs.send, mockDeleteMessage); }); it("doesn't delete the message when a processing error is reported", async () => { - handleMessage.rejects(new Error('Processing error')); + handleMessage.rejects(new Error("Processing error")); consumer.start(); - await pEvent(consumer, 'processing_error'); + await pEvent(consumer, "processing_error"); consumer.stop(); sandbox.assert.neverCalledWithMatch(sqs.send, mockDeleteMessage); }); - it('consumes another message once one is processed', async () => { + it("consumes another message once one is processed", async () => { handleMessage.resolves(); consumer.start(); @@ -658,38 +658,38 @@ describe('Consumer', () => { sqs.send.calledOnceWith(mockReceiveMessage); }); - it('consumes multiple messages when the batchSize is greater than 1', async () => { + it("consumes multiple messages when the batchSize is greater than 1", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ { - ReceiptHandle: 'receipt-handle-1', - MessageId: '1', - Body: 'body-1' + ReceiptHandle: "receipt-handle-1", + MessageId: "1", + Body: "body-1", }, { - ReceiptHandle: 'receipt-handle-2', - MessageId: '2', - Body: 'body-2' + ReceiptHandle: "receipt-handle-2", + MessageId: "2", + Body: "body-2", }, { - ReceiptHandle: 'receipt-handle-3', - MessageId: '3', - Body: 'body-3' - } - ] + ReceiptHandle: "receipt-handle-3", + MessageId: "3", + Body: "body-3", + }, + ], }); consumer = new Consumer({ queueUrl: QUEUE_URL, - messageAttributeNames: ['attribute-1', 'attribute-2'], + messageAttributeNames: ["attribute-1", "attribute-2"], region: REGION, handleMessage, batchSize: 3, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'message_received'); + await pEvent(consumer, "message_received"); consumer.stop(); sandbox.assert.callCount(handleMessage, 3); @@ -699,30 +699,30 @@ describe('Consumer', () => { sinon.match({ QueueUrl: QUEUE_URL, AttributeNames: [], - MessageAttributeNames: ['attribute-1', 'attribute-2'], + MessageAttributeNames: ["attribute-1", "attribute-2"], MaxNumberOfMessages: 3, WaitTimeSeconds: AUTHENTICATION_ERROR_TIMEOUT, - VisibilityTimeout: undefined - }) + VisibilityTimeout: undefined, + }), ); }); it("consumes messages with message attribute 'ApproximateReceiveCount'", async () => { const messageWithAttr = { - ReceiptHandle: 'receipt-handle-1', - MessageId: '1', - Body: 'body-1', + ReceiptHandle: "receipt-handle-1", + MessageId: "1", + Body: "body-1", Attributes: { - ApproximateReceiveCount: 1 - } + ApproximateReceiveCount: 1, + }, }; sqs.send.withArgs(mockReceiveMessage).resolves({ - Messages: [messageWithAttr] + Messages: [messageWithAttr], }); const attributeNames: QueueAttributeName[] = [ - 'ApproximateReceiveCount' as QueueAttributeName + "ApproximateReceiveCount" as QueueAttributeName, ]; consumer = new Consumer({ @@ -730,11 +730,11 @@ describe('Consumer', () => { attributeNames, region: REGION, handleMessage, - sqs + sqs, }); consumer.start(); - const message = await pEvent(consumer, 'message_received'); + const message = await pEvent(consumer, "message_received"); consumer.stop(); sandbox.assert.calledWith(sqs.send, mockReceiveMessage); @@ -742,160 +742,160 @@ describe('Consumer', () => { sqs.send.firstCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - AttributeNames: ['ApproximateReceiveCount'], + AttributeNames: ["ApproximateReceiveCount"], MessageAttributeNames: [], MaxNumberOfMessages: 1, WaitTimeSeconds: AUTHENTICATION_ERROR_TIMEOUT, - VisibilityTimeout: undefined - }) + VisibilityTimeout: undefined, + }), ); assert.equal(message, messageWithAttr); }); - it('fires an emptyQueue event when all messages have been consumed', async () => { + it("fires an emptyQueue event when all messages have been consumed", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({}); consumer.start(); - await pEvent(consumer, 'empty'); + await pEvent(consumer, "empty"); consumer.stop(); }); - it('terminate message visibility timeout on processing error', async () => { - handleMessage.rejects(new Error('Processing error')); + it("terminate message visibility timeout on processing error", async () => { + handleMessage.rejects(new Error("Processing error")); consumer.terminateVisibilityTimeout = true; consumer.start(); - await pEvent(consumer, 'processing_error'); + await pEvent(consumer, "processing_error"); consumer.stop(); sandbox.assert.calledWith( sqs.send.secondCall, - mockChangeMessageVisibility + mockChangeMessageVisibility, ); sandbox.assert.match( sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle', - VisibilityTimeout: 0 - }) + ReceiptHandle: "receipt-handle", + VisibilityTimeout: 0, + }), ); }); - it('does not terminate visibility timeout when `terminateVisibilityTimeout` option is false', async () => { - handleMessage.rejects(new Error('Processing error')); + it("does not terminate visibility timeout when `terminateVisibilityTimeout` option is false", async () => { + handleMessage.rejects(new Error("Processing error")); consumer.terminateVisibilityTimeout = false; consumer.start(); - await pEvent(consumer, 'processing_error'); + await pEvent(consumer, "processing_error"); consumer.stop(); sqs.send.neverCalledWith(mockChangeMessageVisibility); }); - it('fires error event when failed to terminate visibility timeout on processing error', async () => { - handleMessage.rejects(new Error('Processing error')); + it("fires error event when failed to terminate visibility timeout on processing error", async () => { + handleMessage.rejects(new Error("Processing error")); - const sqsError = new Error('Processing error'); - sqsError.name = 'SQSError'; + const sqsError = new Error("Processing error"); + sqsError.name = "SQSError"; sqs.send.withArgs(mockChangeMessageVisibility).rejects(sqsError); consumer.terminateVisibilityTimeout = true; consumer.start(); - await pEvent(consumer, 'error'); + await pEvent(consumer, "error"); consumer.stop(); sandbox.assert.calledWith( sqs.send.secondCall, - mockChangeMessageVisibility + mockChangeMessageVisibility, ); sandbox.assert.match( sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle', - VisibilityTimeout: 0 - }) + ReceiptHandle: "receipt-handle", + VisibilityTimeout: 0, + }), ); }); - it('fires response_processed event for each batch', async () => { + it("fires response_processed event for each batch", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ { - ReceiptHandle: 'receipt-handle-1', - MessageId: '1', - Body: 'body-1' + ReceiptHandle: "receipt-handle-1", + MessageId: "1", + Body: "body-1", }, { - ReceiptHandle: 'receipt-handle-2', - MessageId: '2', - Body: 'body-2' - } - ] + ReceiptHandle: "receipt-handle-2", + MessageId: "2", + Body: "body-2", + }, + ], }); handleMessage.resolves(null); consumer = new Consumer({ queueUrl: QUEUE_URL, - messageAttributeNames: ['attribute-1', 'attribute-2'], + messageAttributeNames: ["attribute-1", "attribute-2"], region: REGION, handleMessage, batchSize: 2, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(handleMessage, 2); }); - it('calls the handleMessagesBatch function when a batch of messages is received', async () => { + it("calls the handleMessagesBatch function when a batch of messages is received", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, - messageAttributeNames: ['attribute-1', 'attribute-2'], + messageAttributeNames: ["attribute-1", "attribute-2"], region: REGION, handleMessageBatch, batchSize: 2, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(handleMessageBatch, 1); }); - it('handles unexpected exceptions thrown by the handler batch function', async () => { + it("handles unexpected exceptions thrown by the handler batch function", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, - messageAttributeNames: ['attribute-1', 'attribute-2'], + messageAttributeNames: ["attribute-1", "attribute-2"], region: REGION, handleMessageBatch: () => { - throw new Error('unexpected parsing error'); + throw new Error("unexpected parsing error"); }, batchSize: 2, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); consumer.start(); - const err: any = await pEvent(consumer, 'error'); + const err: any = await pEvent(consumer, "error"); consumer.stop(); assert.ok(err); assert.equal( err.message, - 'Unexpected message handler failure: unexpected parsing error' + "Unexpected message handler failure: unexpected parsing error", ); }); - it('handles non-standard objects thrown by the handler batch function', async () => { + it("handles non-standard objects thrown by the handler batch function", async () => { class CustomError { private _message: string; @@ -910,82 +910,82 @@ describe('Consumer', () => { consumer = new Consumer({ queueUrl: QUEUE_URL, - messageAttributeNames: ['attribute-1', 'attribute-2'], + messageAttributeNames: ["attribute-1", "attribute-2"], region: REGION, handleMessageBatch: () => { - throw new CustomError('unexpected parsing error'); + throw new CustomError("unexpected parsing error"); }, batchSize: 2, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); consumer.start(); - const err: any = await pEvent(consumer, 'error'); + const err: any = await pEvent(consumer, "error"); consumer.stop(); assert.ok(err); - assert.equal(err.message, 'unexpected parsing error'); + assert.equal(err.message, "unexpected parsing error"); }); - it('handles non-standard exceptions thrown by the handler batch function', async () => { + it("handles non-standard exceptions thrown by the handler batch function", async () => { const customError = new Error(); - Object.defineProperty(customError, 'message', { - get: () => 'unexpected parsing error' + Object.defineProperty(customError, "message", { + get: () => "unexpected parsing error", }); consumer = new Consumer({ queueUrl: QUEUE_URL, - messageAttributeNames: ['attribute-1', 'attribute-2'], + messageAttributeNames: ["attribute-1", "attribute-2"], region: REGION, handleMessageBatch: () => { throw customError; }, batchSize: 2, sqs, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); consumer.start(); - const err: any = await pEvent(consumer, 'error'); + const err: any = await pEvent(consumer, "error"); consumer.stop(); assert.ok(err); assert.equal( err.message, - 'Unexpected message handler failure: unexpected parsing error' + "Unexpected message handler failure: unexpected parsing error", ); }); - it('prefers handleMessagesBatch over handleMessage when both are set', async () => { + it("prefers handleMessagesBatch over handleMessage when both are set", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, - messageAttributeNames: ['attribute-1', 'attribute-2'], + messageAttributeNames: ["attribute-1", "attribute-2"], region: REGION, handleMessageBatch, handleMessage, batchSize: 2, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(handleMessageBatch, 1); sandbox.assert.callCount(handleMessage, 0); }); - it('ack the message if handleMessage returns void', async () => { + it("ack the message if handleMessage returns void", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage: async () => {}, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'message_processed'); + await pEvent(consumer, "message_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 2); @@ -995,25 +995,25 @@ describe('Consumer', () => { sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle' - }) + ReceiptHandle: "receipt-handle", + }), ); }); - it('ack the message if handleMessage returns a message with the same ID', async () => { + it("ack the message if handleMessage returns a message with the same ID", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage: async () => { return { - MessageId: '123' + MessageId: "123", }; }, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'message_processed'); + await pEvent(consumer, "message_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 2); @@ -1023,50 +1023,50 @@ describe('Consumer', () => { sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle' - }) + ReceiptHandle: "receipt-handle", + }), ); }); - it('does not ack the message if handleMessage returns an empty object', async () => { + it("does not ack the message if handleMessage returns an empty object", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage: async () => { return {}; }, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 1); sandbox.assert.neverCalledWithMatch(sqs.send, mockDeleteMessage); }); - it('does not ack the message if handleMessage returns a different ID', async () => { + it("does not ack the message if handleMessage returns a different ID", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage: async () => { return { - MessageId: '143' + MessageId: "143", }; }, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 1); sandbox.assert.neverCalledWithMatch(sqs.send, mockDeleteMessage); }); - it('deletes the message if alwaysAcknowledge is `true` and handleMessage returns an empty object', async () => { + it("deletes the message if alwaysAcknowledge is `true` and handleMessage returns an empty object", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, @@ -1074,11 +1074,11 @@ describe('Consumer', () => { return {}; }, sqs, - alwaysAcknowledge: true + alwaysAcknowledge: true, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 2); @@ -1088,116 +1088,116 @@ describe('Consumer', () => { sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle' - }) + ReceiptHandle: "receipt-handle", + }), ); }); - it('does not call deleteMessageBatch if handleMessagesBatch returns an empty array', async () => { + it("does not call deleteMessageBatch if handleMessagesBatch returns an empty array", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessageBatch: async () => [], batchSize: 2, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 1); sandbox.assert.neverCalledWithMatch(sqs.send, mockDeleteMessageBatch); }); - it('calls deleteMessageBatch if alwaysAcknowledge is `true` and handleMessagesBatch returns an empty array', async () => { + it("calls deleteMessageBatch if alwaysAcknowledge is `true` and handleMessagesBatch returns an empty array", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessageBatch: async () => [], batchSize: 2, sqs, - alwaysAcknowledge: true + alwaysAcknowledge: true, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 2); sandbox.assert.calledWithMatch(sqs.send.firstCall, mockReceiveMessage); sandbox.assert.calledWithMatch( sqs.send.secondCall, - mockDeleteMessageBatch + mockDeleteMessageBatch, ); sandbox.assert.match( sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - Entries: [{ Id: '123', ReceiptHandle: 'receipt-handle' }] - }) + Entries: [{ Id: "123", ReceiptHandle: "receipt-handle" }], + }), ); }); - it('ack all messages if handleMessageBatch returns void', async () => { + it("ack all messages if handleMessageBatch returns void", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessageBatch: async () => {}, batchSize: 2, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 2); sandbox.assert.calledWithMatch(sqs.send.firstCall, mockReceiveMessage); sandbox.assert.calledWithMatch( sqs.send.secondCall, - mockDeleteMessageBatch + mockDeleteMessageBatch, ); sandbox.assert.match( sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - Entries: [{ Id: '123', ReceiptHandle: 'receipt-handle' }] - }) + Entries: [{ Id: "123", ReceiptHandle: "receipt-handle" }], + }), ); }); - it('ack only returned messages if handleMessagesBatch returns an array', async () => { + it("ack only returned messages if handleMessagesBatch returns an array", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessageBatch: async () => [ - { MessageId: '123', ReceiptHandle: 'receipt-handle' } + { MessageId: "123", ReceiptHandle: "receipt-handle" }, ], batchSize: 2, - sqs + sqs, }); consumer.start(); - await pEvent(consumer, 'response_processed'); + await pEvent(consumer, "response_processed"); consumer.stop(); sandbox.assert.callCount(sqs.send, 2); sandbox.assert.calledWithMatch(sqs.send.firstCall, mockReceiveMessage); sandbox.assert.calledWithMatch( sqs.send.secondCall, - mockDeleteMessageBatch + mockDeleteMessageBatch, ); sandbox.assert.match( sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - Entries: [{ Id: '123', ReceiptHandle: 'receipt-handle' }] - }) + Entries: [{ Id: "123", ReceiptHandle: "receipt-handle" }], + }), ); }); - it('uses the correct visibility timeout for long running handler functions', async () => { + it("uses the correct visibility timeout for long running handler functions", async () => { consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, @@ -1205,51 +1205,51 @@ describe('Consumer', () => { new Promise((resolve) => setTimeout(resolve, 75000)), sqs, visibilityTimeout: 40, - heartbeatInterval: 30 + heartbeatInterval: 30, }); - const clearIntervalSpy = sinon.spy(global, 'clearInterval'); + const clearIntervalSpy = sinon.spy(global, "clearInterval"); consumer.start(); await Promise.all([ - pEvent(consumer, 'response_processed'), - clock.tickAsync(75000) + pEvent(consumer, "response_processed"), + clock.tickAsync(75000), ]); consumer.stop(); sandbox.assert.calledWith( sqs.send.secondCall, - mockChangeMessageVisibility + mockChangeMessageVisibility, ); sandbox.assert.match( sqs.send.secondCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle', - VisibilityTimeout: 40 - }) + ReceiptHandle: "receipt-handle", + VisibilityTimeout: 40, + }), ); sandbox.assert.calledWith( sqs.send.thirdCall, - mockChangeMessageVisibility + mockChangeMessageVisibility, ); sandbox.assert.match( sqs.send.thirdCall.args[0].input, sinon.match({ QueueUrl: QUEUE_URL, - ReceiptHandle: 'receipt-handle', - VisibilityTimeout: 40 - }) + ReceiptHandle: "receipt-handle", + VisibilityTimeout: 40, + }), ); sandbox.assert.calledOnce(clearIntervalSpy); }); - it('passes in the correct visibility timeout for long running batch handler functions', async () => { + it("passes in the correct visibility timeout for long running batch handler functions", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ - { MessageId: '1', ReceiptHandle: 'receipt-handle-1', Body: 'body-1' }, - { MessageId: '2', ReceiptHandle: 'receipt-handle-2', Body: 'body-2' }, - { MessageId: '3', ReceiptHandle: 'receipt-handle-3', Body: 'body-3' } - ] + { MessageId: "1", ReceiptHandle: "receipt-handle-1", Body: "body-1" }, + { MessageId: "2", ReceiptHandle: "receipt-handle-2", Body: "body-2" }, + { MessageId: "3", ReceiptHandle: "receipt-handle-3", Body: "body-3" }, + ], }); consumer = new Consumer({ queueUrl: QUEUE_URL, @@ -1259,20 +1259,20 @@ describe('Consumer', () => { batchSize: 3, sqs, visibilityTimeout: 40, - heartbeatInterval: 30 + heartbeatInterval: 30, }); - const clearIntervalSpy = sinon.spy(global, 'clearInterval'); + const clearIntervalSpy = sinon.spy(global, "clearInterval"); consumer.start(); await Promise.all([ - pEvent(consumer, 'response_processed'), - clock.tickAsync(75000) + pEvent(consumer, "response_processed"), + clock.tickAsync(75000), ]); consumer.stop(); sandbox.assert.calledWith( sqs.send.secondCall, - mockChangeMessageVisibilityBatch + mockChangeMessageVisibilityBatch, ); sandbox.assert.match( sqs.send.secondCall.args[0].input, @@ -1280,26 +1280,26 @@ describe('Consumer', () => { QueueUrl: QUEUE_URL, Entries: sinon.match.array.deepEquals([ { - Id: '1', - ReceiptHandle: 'receipt-handle-1', - VisibilityTimeout: 40 + Id: "1", + ReceiptHandle: "receipt-handle-1", + VisibilityTimeout: 40, }, { - Id: '2', - ReceiptHandle: 'receipt-handle-2', - VisibilityTimeout: 40 + Id: "2", + ReceiptHandle: "receipt-handle-2", + VisibilityTimeout: 40, }, { - Id: '3', - ReceiptHandle: 'receipt-handle-3', - VisibilityTimeout: 40 - } - ]) - }) + Id: "3", + ReceiptHandle: "receipt-handle-3", + VisibilityTimeout: 40, + }, + ]), + }), ); sandbox.assert.calledWith( sqs.send.thirdCall, - mockChangeMessageVisibilityBatch + mockChangeMessageVisibilityBatch, ); sandbox.assert.match( sqs.send.thirdCall.args[0].input, @@ -1307,31 +1307,31 @@ describe('Consumer', () => { QueueUrl: QUEUE_URL, Entries: [ { - Id: '1', - ReceiptHandle: 'receipt-handle-1', - VisibilityTimeout: 40 + Id: "1", + ReceiptHandle: "receipt-handle-1", + VisibilityTimeout: 40, }, { - Id: '2', - ReceiptHandle: 'receipt-handle-2', - VisibilityTimeout: 40 + Id: "2", + ReceiptHandle: "receipt-handle-2", + VisibilityTimeout: 40, }, { - Id: '3', - ReceiptHandle: 'receipt-handle-3', - VisibilityTimeout: 40 - } - ] - }) + Id: "3", + ReceiptHandle: "receipt-handle-3", + VisibilityTimeout: 40, + }, + ], + }), ); sandbox.assert.calledOnce(clearIntervalSpy); }); - it('emit error when changing visibility timeout fails', async () => { + it("emit error when changing visibility timeout fails", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ - { MessageId: '1', ReceiptHandle: 'receipt-handle-1', Body: 'body-1' } - ] + { MessageId: "1", ReceiptHandle: "receipt-handle-1", Body: "body-1" }, + ], }); consumer = new Consumer({ queueUrl: QUEUE_URL, @@ -1340,29 +1340,29 @@ describe('Consumer', () => { new Promise((resolve) => setTimeout(resolve, 75000)), sqs, visibilityTimeout: 40, - heartbeatInterval: 30 + heartbeatInterval: 30, }); - const receiveErr = new MockSQSError('failed'); + const receiveErr = new MockSQSError("failed"); sqs.send.withArgs(mockChangeMessageVisibility).rejects(receiveErr); consumer.start(); const [err]: any[] = await Promise.all([ - pEvent(consumer, 'error'), - clock.tickAsync(75000) + pEvent(consumer, "error"), + clock.tickAsync(75000), ]); consumer.stop(); assert.ok(err); - assert.equal(err.message, 'Error changing visibility timeout: failed'); + assert.equal(err.message, "Error changing visibility timeout: failed"); }); - it('emit error when changing visibility timeout fails for batch handler functions', async () => { + it("emit error when changing visibility timeout fails for batch handler functions", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ - { MessageId: '1', ReceiptHandle: 'receipt-handle-1', Body: 'body-1' }, - { MessageId: '2', ReceiptHandle: 'receipt-handle-2', Body: 'body-2' } - ] + { MessageId: "1", ReceiptHandle: "receipt-handle-1", Body: "body-1" }, + { MessageId: "2", ReceiptHandle: "receipt-handle-2", Body: "body-2" }, + ], }); consumer = new Consumer({ queueUrl: QUEUE_URL, @@ -1372,31 +1372,31 @@ describe('Consumer', () => { sqs, batchSize: 2, visibilityTimeout: 40, - heartbeatInterval: 30 + heartbeatInterval: 30, }); - const receiveErr = new MockSQSError('failed'); + const receiveErr = new MockSQSError("failed"); sqs.send.withArgs(mockChangeMessageVisibilityBatch).rejects(receiveErr); consumer.start(); const [err]: any[] = await Promise.all([ - pEvent(consumer, 'error'), - clock.tickAsync(75000) + pEvent(consumer, "error"), + clock.tickAsync(75000), ]); consumer.stop(); assert.ok(err); - assert.equal(err.message, 'Error changing visibility timeout: failed'); + assert.equal(err.message, "Error changing visibility timeout: failed"); }); }); - describe('event listeners', () => { - it('fires the event multiple times', async () => { + describe("event listeners", () => { + it("fires the event multiple times", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({}); const handleEmpty = sandbox.stub().returns(null); - consumer.on('empty', handleEmpty); + consumer.on("empty", handleEmpty); consumer.start(); @@ -1409,12 +1409,12 @@ describe('Consumer', () => { sandbox.assert.calledTwice(handleEmpty); }); - it('fires the events only once', async () => { + it("fires the events only once", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({}); const handleEmpty = sandbox.stub().returns(null); - consumer.once('empty', handleEmpty); + consumer.once("empty", handleEmpty); consumer.start(); @@ -1428,11 +1428,11 @@ describe('Consumer', () => { }); }); - describe('.stop', () => { - it('stops the consumer polling for messages', async () => { + describe(".stop", () => { + it("stops the consumer polling for messages", async () => { const handleStop = sandbox.stub().returns(null); - consumer.on('stopped', handleStop); + consumer.on("stopped", handleStop); consumer.start(); consumer.stop(); @@ -1443,8 +1443,8 @@ describe('Consumer', () => { sandbox.assert.calledOnce(handleMessage); }); - it('clears the polling timeout when stopped', async () => { - sinon.spy(clock, 'clearTimeout'); + it("clears the polling timeout when stopped", async () => { + sinon.spy(clock, "clearTimeout"); consumer.start(); await clock.tickAsync(0); @@ -1455,10 +1455,10 @@ describe('Consumer', () => { sinon.assert.calledTwice(clock.clearTimeout); }); - it('fires a stopped event only once when stopped multiple times', async () => { + it("fires a stopped event only once when stopped multiple times", async () => { const handleStop = sandbox.stub().returns(null); - consumer.on('stopped', handleStop); + consumer.on("stopped", handleStop); consumer.start(); consumer.stop(); @@ -1469,10 +1469,10 @@ describe('Consumer', () => { sandbox.assert.calledOnce(handleStop); }); - it('fires a stopped event a second time if started and stopped twice', async () => { + it("fires a stopped event a second time if started and stopped twice", async () => { const handleStop = sandbox.stub().returns(null); - consumer.on('stopped', handleStop); + consumer.on("stopped", handleStop); consumer.start(); consumer.stop(); @@ -1483,12 +1483,12 @@ describe('Consumer', () => { sandbox.assert.calledTwice(handleStop); }); - it('aborts requests when the abort param is true', async () => { + it("aborts requests when the abort param is true", async () => { const handleStop = sandbox.stub().returns(null); const handleAbort = sandbox.stub().returns(null); - consumer.on('stopped', handleStop); - consumer.on('aborted', handleAbort); + consumer.on("stopped", handleStop); + consumer.on("aborted", handleAbort); consumer.start(); consumer.stop({ abort: true }); @@ -1501,11 +1501,11 @@ describe('Consumer', () => { sandbox.assert.calledOnce(handleStop); }); - it('waits for in-flight messages before emitting stopped (within timeout)', async () => { + it("waits for in-flight messages before emitting stopped (within timeout)", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ - { MessageId: '1', ReceiptHandle: 'receipt-handle-1', Body: 'body-1' } - ] + { MessageId: "1", ReceiptHandle: "receipt-handle-1", Body: "body-1" }, + ], }); const handleStop = sandbox.stub().returns(null); const handleResponseProcessed = sandbox.stub().returns(null); @@ -1525,15 +1525,15 @@ describe('Consumer', () => { handleMessage, sqs, pollingCompleteWaitTimeMs: 5000, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); - consumer.on('stopped', handleStop); - consumer.on('response_processed', handleResponseProcessed); - consumer.on('waiting_for_polling_to_complete', waitingForPollingComplete); + consumer.on("stopped", handleStop); + consumer.on("response_processed", handleResponseProcessed); + consumer.on("waiting_for_polling_to_complete", waitingForPollingComplete); consumer.on( - 'waiting_for_polling_to_complete_timeout_exceeded', - waitingForPollingCompleteTimeoutExceeded + "waiting_for_polling_to_complete_timeout_exceeded", + waitingForPollingCompleteTimeoutExceeded, ); consumer.start(); @@ -1555,11 +1555,11 @@ describe('Consumer', () => { assert.ok(handleResponseProcessed.calledBefore(handleStop)); }); - it('waits for in-flight messages before emitting stopped (timeout reached)', async () => { + it("waits for in-flight messages before emitting stopped (timeout reached)", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ - { MessageId: '1', ReceiptHandle: 'receipt-handle-1', Body: 'body-1' } - ] + { MessageId: "1", ReceiptHandle: "receipt-handle-1", Body: "body-1" }, + ], }); const handleStop = sandbox.stub().returns(null); const handleResponseProcessed = sandbox.stub().returns(null); @@ -1579,15 +1579,15 @@ describe('Consumer', () => { handleMessage, sqs, pollingCompleteWaitTimeMs: 500, - authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT + authenticationErrorTimeout: AUTHENTICATION_ERROR_TIMEOUT, }); - consumer.on('stopped', handleStop); - consumer.on('response_processed', handleResponseProcessed); - consumer.on('waiting_for_polling_to_complete', waitingForPollingComplete); + consumer.on("stopped", handleStop); + consumer.on("response_processed", handleResponseProcessed); + consumer.on("waiting_for_polling_to_complete", waitingForPollingComplete); consumer.on( - 'waiting_for_polling_to_complete_timeout_exceeded', - waitingForPollingCompleteTimeoutExceeded + "waiting_for_polling_to_complete_timeout_exceeded", + waitingForPollingCompleteTimeoutExceeded, ); consumer.start(); @@ -1608,35 +1608,35 @@ describe('Consumer', () => { }); }); - describe('status', async () => { - it('returns the defaults before the consumer is started', () => { + describe("status", async () => { + it("returns the defaults before the consumer is started", () => { assert.isFalse(consumer.status.isRunning); assert.isFalse(consumer.status.isPolling); }); - it('returns true for `isRunning` if the consumer has not been stopped', () => { + it("returns true for `isRunning` if the consumer has not been stopped", () => { consumer.start(); assert.isTrue(consumer.status.isRunning); consumer.stop(); }); - it('returns false for `isRunning` if the consumer has been stopped', () => { + it("returns false for `isRunning` if the consumer has been stopped", () => { consumer.start(); consumer.stop(); assert.isFalse(consumer.status.isRunning); }); - it('returns true for `isPolling` if the consumer is polling for messages', async () => { + it("returns true for `isPolling` if the consumer is polling for messages", async () => { sqs.send.withArgs(mockReceiveMessage).resolves({ Messages: [ - { MessageId: '1', ReceiptHandle: 'receipt-handle-1', Body: 'body-1' } - ] + { MessageId: "1", ReceiptHandle: "receipt-handle-1", Body: "body-1" }, + ], }); consumer = new Consumer({ queueUrl: QUEUE_URL, region: REGION, handleMessage: () => new Promise((resolve) => setTimeout(resolve, 20)), - sqs + sqs, }); consumer.start(); @@ -1649,176 +1649,176 @@ describe('Consumer', () => { }); }); - describe('updateOption', async () => { - it('updates the visibilityTimeout option and emits an event', () => { + describe("updateOption", async () => { + it("updates the visibilityTimeout option and emits an event", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); - consumer.updateOption('visibilityTimeout', 45); + consumer.updateOption("visibilityTimeout", 45); assert.equal(consumer.visibilityTimeout, 45); sandbox.assert.calledWithMatch( optionUpdatedListener, - 'visibilityTimeout', - 45 + "visibilityTimeout", + 45, ); }); - it('does not update the visibilityTimeout if the value is less than the heartbeatInterval', () => { + it("does not update the visibilityTimeout if the value is less than the heartbeatInterval", () => { consumer = new Consumer({ region: REGION, queueUrl: QUEUE_URL, handleMessage, heartbeatInterval: 30, - visibilityTimeout: 60 + visibilityTimeout: 60, }); const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); assert.throws(() => { - consumer.updateOption('visibilityTimeout', 30); - }, 'heartbeatInterval must be less than visibilityTimeout.'); + consumer.updateOption("visibilityTimeout", 30); + }, "heartbeatInterval must be less than visibilityTimeout."); assert.equal(consumer.visibilityTimeout, 60); sandbox.assert.notCalled(optionUpdatedListener); }); - it('updates the batchSize option and emits an event', () => { + it("updates the batchSize option and emits an event", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); - consumer.updateOption('batchSize', 4); + consumer.updateOption("batchSize", 4); assert.equal(consumer.batchSize, 4); - sandbox.assert.calledWithMatch(optionUpdatedListener, 'batchSize', 4); + sandbox.assert.calledWithMatch(optionUpdatedListener, "batchSize", 4); }); - it('does not update the batchSize if the value is more than 10', () => { + it("does not update the batchSize if the value is more than 10", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); assert.throws(() => { - consumer.updateOption('batchSize', 13); - }, 'batchSize must be between 1 and 10.'); + consumer.updateOption("batchSize", 13); + }, "batchSize must be between 1 and 10."); assert.equal(consumer.batchSize, 1); sandbox.assert.notCalled(optionUpdatedListener); }); - it('does not update the batchSize if the value is less than 1', () => { + it("does not update the batchSize if the value is less than 1", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); assert.throws(() => { - consumer.updateOption('batchSize', 0); - }, 'batchSize must be between 1 and 10.'); + consumer.updateOption("batchSize", 0); + }, "batchSize must be between 1 and 10."); assert.equal(consumer.batchSize, 1); sandbox.assert.notCalled(optionUpdatedListener); }); - it('updates the waitTimeSeconds option and emits an event', () => { + it("updates the waitTimeSeconds option and emits an event", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); - consumer.updateOption('waitTimeSeconds', 18); + consumer.updateOption("waitTimeSeconds", 18); assert.equal(consumer.waitTimeSeconds, 18); sandbox.assert.calledWithMatch( optionUpdatedListener, - 'waitTimeSeconds', - 18 + "waitTimeSeconds", + 18, ); }); - it('does not update the batchSize if the value is less than 0', () => { + it("does not update the batchSize if the value is less than 0", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); assert.throws(() => { - consumer.updateOption('waitTimeSeconds', -1); - }, 'waitTimeSeconds must be between 0 and 20.'); + consumer.updateOption("waitTimeSeconds", -1); + }, "waitTimeSeconds must be between 0 and 20."); assert.equal(consumer.waitTimeSeconds, 20); sandbox.assert.notCalled(optionUpdatedListener); }); - it('does not update the batchSize if the value is more than 20', () => { + it("does not update the batchSize if the value is more than 20", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); assert.throws(() => { - consumer.updateOption('waitTimeSeconds', 27); - }, 'waitTimeSeconds must be between 0 and 20.'); + consumer.updateOption("waitTimeSeconds", 27); + }, "waitTimeSeconds must be between 0 and 20."); assert.equal(consumer.waitTimeSeconds, 20); sandbox.assert.notCalled(optionUpdatedListener); }); - it('updates the pollingWaitTimeMs option and emits an event', () => { + it("updates the pollingWaitTimeMs option and emits an event", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); - consumer.updateOption('pollingWaitTimeMs', 1000); + consumer.updateOption("pollingWaitTimeMs", 1000); assert.equal(consumer.pollingWaitTimeMs, 1000); sandbox.assert.calledWithMatch( optionUpdatedListener, - 'pollingWaitTimeMs', - 1000 + "pollingWaitTimeMs", + 1000, ); }); - it('does not update the pollingWaitTimeMs if the value is less than 0', () => { + it("does not update the pollingWaitTimeMs if the value is less than 0", () => { const optionUpdatedListener = sandbox.stub(); - consumer.on('option_updated', optionUpdatedListener); + consumer.on("option_updated", optionUpdatedListener); assert.throws(() => { - consumer.updateOption('pollingWaitTimeMs', -1); - }, 'pollingWaitTimeMs must be greater than 0.'); + consumer.updateOption("pollingWaitTimeMs", -1); + }, "pollingWaitTimeMs must be greater than 0."); assert.equal(consumer.pollingWaitTimeMs, 0); sandbox.assert.notCalled(optionUpdatedListener); }); - it('throws an error for an unknown option', () => { + it("throws an error for an unknown option", () => { consumer = new Consumer({ region: REGION, queueUrl: QUEUE_URL, handleMessage, - visibilityTimeout: 60 + visibilityTimeout: 60, }); assert.throws(() => { - consumer.updateOption('unknown', 'value'); + consumer.updateOption("unknown", "value"); }, `The update unknown cannot be updated`); }); }); - describe('logger', () => { - it('logs a debug event when an event is emitted', async () => { - const loggerDebug = sandbox.stub(logger, 'debug'); + describe("logger", () => { + it("logs a debug event when an event is emitted", async () => { + const loggerDebug = sandbox.stub(logger, "debug"); consumer.start(); consumer.stop(); sandbox.assert.callCount(loggerDebug, 5); - sandbox.assert.calledWithMatch(loggerDebug, 'starting'); - sandbox.assert.calledWithMatch(loggerDebug, 'started'); - sandbox.assert.calledWithMatch(loggerDebug, 'polling'); - sandbox.assert.calledWithMatch(loggerDebug, 'stopping'); - sandbox.assert.calledWithMatch(loggerDebug, 'stopped'); + sandbox.assert.calledWithMatch(loggerDebug, "starting"); + sandbox.assert.calledWithMatch(loggerDebug, "started"); + sandbox.assert.calledWithMatch(loggerDebug, "polling"); + sandbox.assert.calledWithMatch(loggerDebug, "stopping"); + sandbox.assert.calledWithMatch(loggerDebug, "stopped"); }); }); }); diff --git a/tsconfig.json b/tsconfig.json index 18bad39c..b1ebb7e6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "target": "es2017", - "module": "commonjs", + "target": "es2022", + "module": "esnext", "outDir": "dist", "sourceMap": false, "moduleResolution": "node", From c030d53b4e7f84bfa67fe3b23913681737944adc Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 12 Mar 2024 19:28:58 +0000 Subject: [PATCH 2/9] chore: formatting --- src/logger.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index 08d1a429..cc6a1b55 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,6 +1,6 @@ -import createDebug from 'debug'; -const debug = createDebug('sqs-consumer'); +import createDebug from "debug"; +const debug = createDebug("sqs-consumer"); export const logger = { - debug + debug, }; From 378bf3e036672b3b407c549f6d0ce1af548ffd27 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 12 Mar 2024 19:45:37 +0000 Subject: [PATCH 3/9] chore: added exports and different tsconfig --- package.json | 1 + tsconfig.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 33f33137..1521e265 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Build SQS-based Node applications without the boilerplate", "type": "module", "main": "dist/index.js", + "exports": "./dist/index.js", "types": "dist/index.d.ts", "engines": { "node": ">=18.0.0" diff --git a/tsconfig.json b/tsconfig.json index b1ebb7e6..f2767dca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,10 +1,10 @@ { "compilerOptions": { "target": "es2022", - "module": "esnext", + "module": "Node16", + "moduleResolution": "Node16", "outDir": "dist", "sourceMap": false, - "moduleResolution": "node", "allowJs": false, "noUnusedLocals": true, "declaration": true From 59f001d44c3c7f76ea788de662ee7a5894c598c6 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 12 Mar 2024 19:49:08 +0000 Subject: [PATCH 4/9] chore: changing target to ES2021 --- tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index f2767dca..2a00daf2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { - "target": "es2022", + "lib": ["ES2021"], + "target": "ES2021", "module": "Node16", "moduleResolution": "Node16", "outDir": "dist", From 39255d12861df7d91380118323d900a5092b7661 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Wed, 13 Mar 2024 21:50:22 +0000 Subject: [PATCH 5/9] chore: potentially building cjs and esm --- package.json | 16 +++++++++++----- tsconfig.cjs.json | 9 +++++++++ tsconfig.esm.json | 9 +++++++++ tsconfig.json | 5 +++-- 4 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 tsconfig.cjs.json create mode 100644 tsconfig.esm.json diff --git a/package.json b/package.json index 1521e265..994f092f 100644 --- a/package.json +++ b/package.json @@ -3,16 +3,22 @@ "version": "9.1.0", "description": "Build SQS-based Node applications without the boilerplate", "type": "module", - "main": "dist/index.js", - "exports": "./dist/index.js", - "types": "dist/index.d.ts", + "exports": { + "./*": { + "types": "./dist/types/*.d.ts", + "require": "./dist/cjs/*.js", + "import": "./dist/esm/*.js", + "default": "./dist/esm/*.js" + } + }, "engines": { "node": ">=18.0.0" }, "scripts": { - "build": "npm run clean && tsc", - "watch": "tsc --watch", "clean": "rm -fr dist/*", + "compile": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json", + "build": "npm run clean && npm run compile", + "watch": "tsc --watch", "prepublishOnly": "npm run build", "test:unit": "mocha --recursive --full-trace --exit", "pretest:integration:init": "npm run build", diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 00000000..dc967eaf --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist/cjs", + "module": "commonjs", + "moduleResolution": "node", + "noEmit": false + } +} diff --git a/tsconfig.esm.json b/tsconfig.esm.json new file mode 100644 index 00000000..4279f9a3 --- /dev/null +++ b/tsconfig.esm.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist/esm", + "module": "Node16", + "moduleResolution": "Node16", + "noEmit": false + } +} diff --git a/tsconfig.json b/tsconfig.json index 2a00daf2..195ee945 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,11 +4,12 @@ "target": "ES2021", "module": "Node16", "moduleResolution": "Node16", - "outDir": "dist", + "noEmit": true, "sourceMap": false, "allowJs": false, "noUnusedLocals": true, - "declaration": true + "declaration": true, + "declarationDir": "dist/types" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] From 9e7fa043c57508bddbc9590182d797839f96fec7 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Wed, 13 Mar 2024 21:55:44 +0000 Subject: [PATCH 6/9] fix: cucumber imports --- test/features/utils/consumer/gracefulShutdown.js | 2 +- test/features/utils/consumer/handleMessage.js | 2 +- test/features/utils/consumer/handleMessageBatch.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/features/utils/consumer/gracefulShutdown.js b/test/features/utils/consumer/gracefulShutdown.js index 41c28340..2849e7d7 100644 --- a/test/features/utils/consumer/gracefulShutdown.js +++ b/test/features/utils/consumer/gracefulShutdown.js @@ -1,4 +1,4 @@ -import { Consumer } from "../../../../dist/consumer.js"; +import { Consumer } from "../../../../dist/esm/consumer.js"; import { QUEUE_URL, sqs } from "../sqs.js"; diff --git a/test/features/utils/consumer/handleMessage.js b/test/features/utils/consumer/handleMessage.js index 16a6052a..c6fc2915 100644 --- a/test/features/utils/consumer/handleMessage.js +++ b/test/features/utils/consumer/handleMessage.js @@ -1,4 +1,4 @@ -import { Consumer } from "../../../../dist/consumer.js"; +import { Consumer } from "../../../../dist/esm/consumer.js"; import { QUEUE_URL, sqs } from "../sqs.js"; diff --git a/test/features/utils/consumer/handleMessageBatch.js b/test/features/utils/consumer/handleMessageBatch.js index 51636920..4abf0436 100644 --- a/test/features/utils/consumer/handleMessageBatch.js +++ b/test/features/utils/consumer/handleMessageBatch.js @@ -1,4 +1,4 @@ -import { Consumer } from "../../../../dist/consumer.js"; +import { Consumer } from "../../../../dist/esm/consumer.js"; import { QUEUE_URL, sqs } from "../sqs.js"; From d4cd0e31c5e5af197589ecdec1060dc800fa8239 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Wed, 13 Mar 2024 22:27:46 +0000 Subject: [PATCH 7/9] chore: adding a script to build package files --- .npmignore | 3 ++- package.json | 3 ++- scripts/addPackageJsons.js | 31 +++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 scripts/addPackageJsons.js diff --git a/.npmignore b/.npmignore index a6b788ce..240455e2 100644 --- a/.npmignore +++ b/.npmignore @@ -5,4 +5,5 @@ coverage examples test public -.nyc_output \ No newline at end of file +.nyc_output +scripts \ No newline at end of file diff --git a/package.json b/package.json index 994f092f..95ce1087 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "scripts": { "clean": "rm -fr dist/*", "compile": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json", - "build": "npm run clean && npm run compile", + "add-package-jsons": "node ./scripts/addPackageJsons.js", + "build": "npm run clean && npm run compile && npm run add-package-jsons", "watch": "tsc --watch", "prepublishOnly": "npm run build", "test:unit": "mocha --recursive --full-trace --exit", diff --git a/scripts/addPackageJsons.js b/scripts/addPackageJsons.js new file mode 100644 index 00000000..3a0e76a1 --- /dev/null +++ b/scripts/addPackageJsons.js @@ -0,0 +1,31 @@ +import { readdir, existsSync, writeFile } from "fs"; +import { join } from "path"; + +const buildDir = "./dist"; +function buildPackageJson() { + readdir(buildDir, (err, dirs) => { + if (err) { + throw err; + } + dirs.forEach((dir) => { + const packageJsonFile = join(buildDir, dir, "/package.json"); + + if (!existsSync(packageJsonFile)) { + const value = + dir === "esm" ? '{"type": "module"}' : '{"type": "commonjs"}'; + + writeFile( + packageJsonFile, + new Uint8Array(Buffer.from(value)), + (err) => { + if (err) { + throw err; + } + }, + ); + } + }); + }); +} + +buildPackageJson(); From 722df4cb678a3bbcaa3a88d5ab2b3e7009a96e43 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Thu, 14 Mar 2024 17:21:24 +0000 Subject: [PATCH 8/9] fix: exports --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 95ce1087..242d55b2 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,11 @@ "description": "Build SQS-based Node applications without the boilerplate", "type": "module", "exports": { - "./*": { - "types": "./dist/types/*.d.ts", - "require": "./dist/cjs/*.js", - "import": "./dist/esm/*.js", - "default": "./dist/esm/*.js" + ".": { + "types": "./dist/types/index.d.ts", + "require": "./dist/cjs/index.js", + "import": "./dist/esm/index.js", + "default": "./dist/esm/index.js" } }, "engines": { From a411c003d10dfd9805b9d2173ef9e457903f4318 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Thu, 14 Mar 2024 17:28:54 +0000 Subject: [PATCH 9/9] chore(release): v10.0.0-canary.2 --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index d019c39d..0a4186a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sqs-consumer", - "version": "9.1.0", + "version": "10.0.0-canary.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sqs-consumer", - "version": "9.1.0", + "version": "10.0.0-canary.2", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-sqs": "^3.529.1", diff --git a/package.json b/package.json index 242d55b2..443ad5bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sqs-consumer", - "version": "9.1.0", + "version": "10.0.0-canary.2", "description": "Build SQS-based Node applications without the boilerplate", "type": "module", "exports": { @@ -50,7 +50,7 @@ ], "license": "Apache-2.0", "publishConfig": { - "provenance": true + "provenance": false }, "release": { "branches": [