@zintrust/queue-sqs 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # @zintrust/queue-sqs
2
+
3
+ AWS SQS queue driver registration for Zintrust.
4
+
5
+ - Docs: https://zintrust.com/queue
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm i @zintrust/queue-sqs
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```ts
16
+ import '@zintrust/queue-sqs/register';
17
+ ```
18
+
19
+ Then set `QUEUE_DRIVER=sqs` and configure:
20
+
21
+ - `AWS_REGION`
22
+ - `SQS_QUEUE_URL` (or pass queue URL explicitly in your app config)
@@ -0,0 +1,22 @@
1
+ export type QueueMessage<T = unknown> = {
2
+ id: string;
3
+ payload: T;
4
+ attempts: number;
5
+ };
6
+ export type SqsQueueConfig = {
7
+ driver: 'sqs';
8
+ region?: string;
9
+ queueUrl?: string;
10
+ waitTimeSeconds?: number;
11
+ visibilityTimeout?: number;
12
+ };
13
+ export declare const SqsQueue: Readonly<{
14
+ create(config?: SqsQueueConfig): {
15
+ enqueue<T = unknown>(queue: string, payload: T): Promise<string>;
16
+ dequeue<T = unknown>(queue: string): Promise<QueueMessage<T> | undefined>;
17
+ ack(queue: string, id: string): Promise<void>;
18
+ length(queue: string): Promise<number>;
19
+ drain(queue: string): Promise<void>;
20
+ };
21
+ }>;
22
+ export default SqsQueue;
package/dist/index.js ADDED
@@ -0,0 +1,98 @@
1
+ import { ErrorFactory, generateUuid } from '@zintrust/core';
2
+ async function importSqs() {
3
+ // Avoid a string-literal import so TypeScript doesn't require the module at build time.
4
+ const specifier = '@aws-sdk/client-sqs';
5
+ return (await import(specifier));
6
+ }
7
+ function resolveRegion(config) {
8
+ const region = (config?.region ?? process.env['AWS_REGION'] ?? '').toString().trim();
9
+ if (region === '')
10
+ throw ErrorFactory.createConfigError('SQS: missing AWS_REGION');
11
+ return region;
12
+ }
13
+ function resolveQueueUrl(config) {
14
+ const queueUrl = (config?.queueUrl ?? process.env['SQS_QUEUE_URL'] ?? '').toString().trim();
15
+ if (queueUrl === '')
16
+ throw ErrorFactory.createConfigError('SQS: missing SQS_QUEUE_URL');
17
+ return queueUrl;
18
+ }
19
+ async function ensure(state, config) {
20
+ if (state.client !== undefined && state.mod !== undefined)
21
+ return { client: state.client, mod: state.mod };
22
+ state.mod = await importSqs();
23
+ state.client = new state.mod.SQSClient({ region: resolveRegion(config) });
24
+ return { client: state.client, mod: state.mod };
25
+ }
26
+ function resolveUrl(_queue, config) {
27
+ return resolveQueueUrl(config);
28
+ }
29
+ function createSqsQueueDriver(config) {
30
+ const waitTimeSeconds = config?.waitTimeSeconds ?? 0;
31
+ const visibilityTimeout = config?.visibilityTimeout;
32
+ const state = { receipts: new Map() };
33
+ return {
34
+ async enqueue(queue, payload) {
35
+ const id = generateUuid();
36
+ const { client, mod } = await ensure(state, config);
37
+ const body = JSON.stringify({ id, payload, attempts: 0 });
38
+ await client.send(new mod.SendMessageCommand({
39
+ QueueUrl: resolveUrl(queue, config),
40
+ MessageBody: body,
41
+ }));
42
+ return id;
43
+ },
44
+ async dequeue(queue) {
45
+ const { client, mod } = await ensure(state, config);
46
+ const resp = (await client.send(new mod.ReceiveMessageCommand({
47
+ QueueUrl: resolveUrl(queue, config),
48
+ MaxNumberOfMessages: 1,
49
+ WaitTimeSeconds: waitTimeSeconds,
50
+ VisibilityTimeout: visibilityTimeout,
51
+ })));
52
+ const msg = resp.Messages?.[0];
53
+ if (msg?.Body === undefined)
54
+ return undefined;
55
+ try {
56
+ const parsed = JSON.parse(msg.Body);
57
+ if (msg.ReceiptHandle && typeof parsed?.id === 'string' && parsed.id.trim() !== '') {
58
+ state.receipts.set(parsed.id, msg.ReceiptHandle);
59
+ }
60
+ return parsed;
61
+ }
62
+ catch (err) {
63
+ throw ErrorFactory.createTryCatchError('Failed to parse queue message', err);
64
+ }
65
+ },
66
+ async ack(queue, id) {
67
+ const receipt = state.receipts.get(id);
68
+ if (receipt === undefined)
69
+ return;
70
+ state.receipts.delete(id);
71
+ const { client, mod } = await ensure(state, config);
72
+ await client.send(new mod.DeleteMessageCommand({
73
+ QueueUrl: resolveUrl(queue, config),
74
+ ReceiptHandle: receipt,
75
+ }));
76
+ },
77
+ async length(queue) {
78
+ const { client, mod } = await ensure(state, config);
79
+ const resp = (await client.send(new mod.GetQueueAttributesCommand({
80
+ QueueUrl: resolveUrl(queue, config),
81
+ AttributeNames: ['ApproximateNumberOfMessages'],
82
+ })));
83
+ const raw = resp.Attributes?.['ApproximateNumberOfMessages'] ?? '0';
84
+ const n = Number(raw);
85
+ return Number.isFinite(n) ? n : 0;
86
+ },
87
+ async drain(queue) {
88
+ const { client, mod } = await ensure(state, config);
89
+ await client.send(new mod.PurgeQueueCommand({ QueueUrl: resolveUrl(queue, config) }));
90
+ },
91
+ };
92
+ }
93
+ export const SqsQueue = Object.freeze({
94
+ create(config) {
95
+ return createSqsQueueDriver(config);
96
+ },
97
+ });
98
+ export default SqsQueue;
@@ -0,0 +1,5 @@
1
+ type QueueApi = {
2
+ register: (name: string, driver: unknown) => void;
3
+ };
4
+ export declare function registerSqsQueueDriver(queue: QueueApi): Promise<void>;
5
+ export {};
@@ -0,0 +1,21 @@
1
+ export async function registerSqsQueueDriver(queue) {
2
+ const { SqsQueue } = (await import('./index.js'));
3
+ queue.register('sqs', SqsQueue.create());
4
+ }
5
+ const importCore = async () => {
6
+ try {
7
+ return await import('@zintrust/core');
8
+ }
9
+ catch {
10
+ try {
11
+ return await import('@zintrust/core');
12
+ }
13
+ catch {
14
+ return {};
15
+ }
16
+ }
17
+ };
18
+ const core = (await importCore());
19
+ if (core.Queue !== undefined) {
20
+ await registerSqsQueueDriver(core.Queue);
21
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@zintrust/queue-sqs",
3
+ "version": "0.1.12",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./register": {
17
+ "types": "./dist/register.d.ts",
18
+ "default": "./dist/register.js"
19
+ }
20
+ },
21
+ "engines": {
22
+ "node": ">=20.0.0"
23
+ },
24
+ "peerDependencies": {
25
+ "@zintrust/core": "^0.1.12"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "tsc -p tsconfig.json",
32
+ "prepublishOnly": "npm run build"
33
+ }
34
+ }