From 16f19e2a76dd0fe66ff9a54eb4a450334113553e Mon Sep 17 00:00:00 2001 From: dorianfouvez Date: Thu, 31 Jul 2025 14:19:15 +0200 Subject: [PATCH] feat(create-handler): add static method to avoid double import of client --- README.md | 130 ++++++++++++++++++++++---------------- src/SQSHandler.ts | 35 ++++++++-- test/src/createHandler.ts | 10 +++ 3 files changed, 116 insertions(+), 59 deletions(-) create mode 100644 test/src/createHandler.ts diff --git a/README.md b/README.md index 6dc2ab2..53089df 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ [![Coverage Status](https://coveralls.io/repos/github/Sagacify/sqs-handler/badge.svg?branch=master)](https://coveralls.io/github/Sagacify/sqs-handler?branch=master) [![npm version](https://img.shields.io/npm/v/@sagacify/sqs-handler.svg)](https://www.npmjs.com/package/@sagacify/sqs-handler) +[![Issues](https://img.shields.io/github/issues/Sagacify/s3-handler)](https://www.npmjs.com/package/@sagacify/s3-handler) +[![License](https://img.shields.io/github/license/Sagacify/s3-handler)](https://www.npmjs.com/package/@sagacify/s3-handler) +[![Stars](https://img.shields.io/github/stars/Sagacify/s3-handler)](https://www.npmjs.com/package/@sagacify/s3-handler) ## Description @@ -19,6 +22,7 @@ $ npm install @sagacify/sqs-handler ## Usage ### Import in your project + ```js import { SQSClient } from '@aws-sdk/client-sqs'; import { SQSHandler } from '@sagacify/sqs-handler'; @@ -27,7 +31,8 @@ const sqsClient = new SQSClient({ region: 'eu-west-1'}); const sqsHandler = new SQSHandler<{ data: string }>( sqsClient, - 'https://sqs.eu-west-1.amazonaws.com/23452042942/some-sqs-queue', { + 'https://sqs.eu-west-1.amazonaws.com/23452042942/some-sqs-queue', + { VisibilityTimeout: 120, WaitTimeSeconds: 0 } @@ -93,21 +98,40 @@ await sqsHandler.destroyBatch([ ]); ``` +There is a second way to create your handler. +The static method `createHandler` will allow you to remove the instantiation of the Client on your code. This will use `@aws-sdk/client-sqs` under the hood. + +```js +import { SQSHandler } from '@sagacify/sqs-handler'; + +const sqsHandler = + SQSHandler.createHandler < + { data: string } > + ({ region: 'eu-west-1' }, + 'https://sqs.eu-west-1.amazonaws.com/23452042942/some-sqs-queue', + { + VisibilityTimeout: 120, + WaitTimeSeconds: 0 + }); +``` + ### Readable Stream Usage ```js import { SQSClient } from '@aws-sdk/client-sqs'; import { SQSHandler } from '@sagacify/sqs-handler'; -const sqsClient = new SQSClient({ region: 'eu-west-1'}); +const sqsClient = new SQSClient({ region: 'eu-west-1' }); -const sqsHandler = new SQSHandler<{ data: string }>( - sqsClient, - 'https://sqs.eu-west-1.amazonaws.com/23452042942/some-sqs-queue', { +const sqsHandler = + new SQSHandler() < + { data: string } > + (sqsClient, + 'https://sqs.eu-west-1.amazonaws.com/23452042942/some-sqs-queue', + { VisibilityTimeout: 120, WaitTimeSeconds: 0 - } -); + }); const readable = sqsHandler.readableStream(); @@ -157,48 +181,48 @@ writable.write({ Equivalent of [ReceiveMessageCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sqs/command/ReceiveMessageCommand) with automatique parsing. -*Options differences:* +_Options differences:_ - - QueueUrl: useless, SQSHandler.queueUrl will be used instead - - VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead - - WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead +- QueueUrl: useless, SQSHandler.queueUrl will be used instead +- VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead +- WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead - *Response differrences:* +_Response differrences:_ - - Messages: Content of Messages is directly returned as an Array. - - Messages[].Body: automatically JSON parsed - - Messages[].MessageAttributes: automatically parsed as simple object with the right type +- Messages: Content of Messages is directly returned as an Array. +- Messages[].Body: automatically JSON parsed +- Messages[].MessageAttributes: automatically parsed as simple object with the right type - **receiveOne(options)** +**receiveOne(options)** Equivalent of [ReceiveMessageCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sqs/command/ReceiveMessageCommand) for one message with automatique parsing. -*Options differences:* +_Options differences:_ - - QueueUrl: useless, SQSHandler.queueUrl will be used instead - - VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead - - WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead - - MaxNumberOfMessages: forced at 1 +- QueueUrl: useless, SQSHandler.queueUrl will be used instead +- VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead +- WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead +- MaxNumberOfMessages: forced at 1 - *Response differrences:* +_Response differrences:_ - - Messages: Content of Messages[0] directly returned as an Object or null if no messages. - - Messages[0].Body: automatically JSON parsed - - Messages[0].MessageAttributes: automatically parsed as simple object with the right type +- Messages: Content of Messages[0] directly returned as an Object or null if no messages. +- Messages[0].Body: automatically JSON parsed +- Messages[0].MessageAttributes: automatically parsed as simple object with the right type **send(messageBody, options)** Equivalent of [SendMessageCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sqs/command/SendMessageCommand) with automatique composition. -*Options differences:* +_Options differences:_ - - QueueUrl: useless, SQSHandler.queueUrl will be used instead - - VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead - - WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead - - MessageAttributes: simple object that will be automatically composed in { DataType, StringValue|BinaryValue } - - MessageBody: taken from messageBody and automatically JSON stringified +- QueueUrl: useless, SQSHandler.queueUrl will be used instead +- VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead +- WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead +- MessageAttributes: simple object that will be automatically composed in { DataType, StringValue|BinaryValue } +- MessageBody: taken from messageBody and automatically JSON stringified - *Response differrences:* +_Response differrences:_ (None) @@ -206,15 +230,15 @@ Equivalent of [SendMessageCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/ Equivalent of [SendMessageBatchCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sqs/command/SendMessageBatchCommand) with automatique composition. -*Options differences:* +_Options differences:_ - - entries[].QueueUrl: useless, SQSHandler.queueUrl will be used instead - - entries[].VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead - - entries[].WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead - - entries[].MessageAttributes: simple object that will be automatically composed in { DataType, StringValue|BinaryValue } - - entries[].MessageBody: taken from messageBody and automatically JSON stringified +- entries[].QueueUrl: useless, SQSHandler.queueUrl will be used instead +- entries[].VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead +- entries[].WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead +- entries[].MessageAttributes: simple object that will be automatically composed in { DataType, StringValue|BinaryValue } +- entries[].MessageBody: taken from messageBody and automatically JSON stringified - *Response differrences:* +_Response differrences:_ (None) @@ -222,13 +246,13 @@ Equivalent of [SendMessageBatchCommand](https://docs.aws.amazon.com/AWSJavaScrip Equivalent of [DeleteMessageCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sqs/command/DeleteMessageCommand) with automatique composition. -*Options differences:* +_Options differences:_ - - QueueUrl: useless, SQSHandler.queueUrl will be used instead - - VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead - - WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead +- QueueUrl: useless, SQSHandler.queueUrl will be used instead +- VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead +- WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead - *Response differrences:* +_Response differrences:_ (None) @@ -236,13 +260,13 @@ Equivalent of [DeleteMessageCommand](https://docs.aws.amazon.com/AWSJavaScriptSD Equivalent of [DeleteMessageBatchCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sqs/command/DeleteMessageBatchCommand) with automatique composition. -*Options differences:* +_Options differences:_ - - entries[].QueueUrl: useless, SQSHandler.queueUrl will be used instead - - entries[].VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead - - entries[].WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead +- entries[].QueueUrl: useless, SQSHandler.queueUrl will be used instead +- entries[].VisibilityTimeout: SQSHandler.visibilityTimeout will be used instead +- entries[].WaitTimeSeconds: SQSHandler.waitTimeSeconds will be used instead - *Response differrences:* +_Response differrences:_ (None) @@ -258,9 +282,9 @@ For queue related operations use directly the SQS instance. returns a readable stream from the SQS queue. Each message received from the queue will trigger the `data` event. -*Options:* +_Options:_ -- autoDestroy: automatically destroy received message from the queue once pushed to the stream buffer, if set to false you will have to destroy the message yourself otherwise it will be available to be consumed after the *visibilityTimeout* (default: false) +- autoDestroy: automatically destroy received message from the queue once pushed to the stream buffer, if set to false you will have to destroy the message yourself otherwise it will be available to be consumed after the _visibilityTimeout_ (default: false) - autoClose: automatically close the stream when no more message are received from the queue (default: false) see **receive** for other options details. @@ -270,7 +294,7 @@ see **receive** for other options details. returns a writable stream to the SQS queue. Each message written to this stream will be pushed to the queue with the specified options. -*Options:* +_Options:_ - batchSize: set the number of messages to be sent per batch (default: 1) @@ -310,7 +334,7 @@ This will create a coverage folder with all the report in `coverage/index.html` $ npm test:all ``` -*Note: that's the one you want to use most of the time* +_Note: that's the one you want to use most of the time_ ## Reporting bugs and contributing diff --git a/src/SQSHandler.ts b/src/SQSHandler.ts index c6ad10f..a807601 100644 --- a/src/SQSHandler.ts +++ b/src/SQSHandler.ts @@ -1,20 +1,21 @@ import { Readable, Writable } from 'stream'; import { - SQSClient, + DeleteMessageCommand, + DeleteMessageBatchCommand, ReceiveMessageCommand, SendMessageCommand, SendMessageBatchCommand, - DeleteMessageCommand, - DeleteMessageBatchCommand + SQSClient } from '@aws-sdk/client-sqs'; import type { + DeleteMessageBatchRequestEntry, Message, MessageAttributeValue, ReceiveMessageCommandInput, - SendMessageCommandInput, SendMessageBatchRequestEntry, - DeleteMessageBatchRequestEntry + SendMessageCommandInput, + SQSClientConfig } from '@aws-sdk/client-sqs'; export type SQSOptions = { VisibilityTimeout?: number; WaitTimeSeconds?: number }; @@ -49,6 +50,13 @@ export type SqsWritableOptions = SendOptions & { batchSize?: number; }; +type SQSHandlerOptions = + | { + VisibilityTimeout?: number; + WaitTimeSeconds?: number; + } + | undefined; + export class SQSHandler { private readonly client: SQSClient; private readonly queueUrl: string; @@ -58,7 +66,7 @@ export class SQSHandler { constructor( sqsClient: SQSClient, queueUrl: string, - { VisibilityTimeout = 60, WaitTimeSeconds = 0 } = {} + { VisibilityTimeout = 60, WaitTimeSeconds = 0 }: SQSHandlerOptions = {} ) { this.client = sqsClient; this.queueUrl = queueUrl; @@ -66,6 +74,21 @@ export class SQSHandler { this.waitTimeSeconds = WaitTimeSeconds; } + /** + * **Note:** *Credentials can be loaded from the* `~/.aws/config` *file in development* + * @param sqsOptions - Optional configuration for the SQS client + * @param queueUrl - The URL of the SQS queue + * @param handlerOptions - Optional configuration for the SQS handler + * @returns an instance of `SQSHandler` + */ + static createHandler( + sqsOptions: SQSClientConfig = {}, + queueUrl: string, + handlerOptions?: SQSHandlerOptions + ): SQSHandler { + return new this(new SQSClient(sqsOptions), queueUrl, handlerOptions); + } + static composeMessageAttributes( attributes: ParsedMessageAttributes ): Record { diff --git a/test/src/createHandler.ts b/test/src/createHandler.ts new file mode 100644 index 0000000..4e7bc00 --- /dev/null +++ b/test/src/createHandler.ts @@ -0,0 +1,10 @@ +import { expect } from 'chai'; +import { SQSHandler } from '../../src/SQSHandler'; + +describe('SQSHandler.createHandler (static)', () => { + it('should succeed when all parameters are provided', async () => { + const create = () => SQSHandler.createHandler>({}, 'https://fake-queue'); + + expect(create).not.throw(); + }); +});