codeweaver 3.1.3 → 4.0.0
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 +56 -73
- package/package.json +23 -1
- package/src/config.ts +17 -15
- package/src/constants.ts +1 -0
- package/src/core/aws/api-gateway.ts +187 -0
- package/src/core/aws/basic-types.ts +147 -0
- package/src/core/aws/dynamodb.ts +187 -0
- package/src/core/aws/index.ts +9 -0
- package/src/core/aws/lambda.ts +199 -0
- package/src/core/aws/message-broker.ts +167 -0
- package/src/core/aws/message.ts +259 -0
- package/src/core/aws/s3.ts +136 -0
- package/src/core/aws/utilities.ts +44 -0
- package/src/core/cache/basic-types.ts +17 -0
- package/src/core/cache/decorator.ts +72 -0
- package/src/core/cache/index.ts +4 -0
- package/src/core/cache/memory-cache.class.ts +119 -0
- package/src/{utilities/cache/redis-cache.ts → core/cache/redis-cache.class.ts} +58 -10
- package/src/core/container/basic-types.ts +10 -0
- package/src/{utilities → core/container}/container.ts +7 -17
- package/src/core/container/index.ts +2 -0
- package/src/{utilities → core/error}/error-handling.ts +1 -65
- package/src/core/error/index.ts +3 -0
- package/src/core/error/response-error.ts +45 -0
- package/src/core/error/send-http-error.ts +15 -0
- package/src/core/file/file-helpers.ts +166 -0
- package/src/core/file/index.ts +1 -0
- package/src/{utilities → core/helpers}/assignment.ts +2 -2
- package/src/core/helpers/comparison.ts +86 -0
- package/src/{utilities → core/helpers}/conversion.ts +2 -2
- package/src/core/helpers/decorators.ts +316 -0
- package/src/core/helpers/format.ts +9 -0
- package/src/core/helpers/index.ts +7 -0
- package/src/core/helpers/range.ts +67 -0
- package/src/core/helpers/types.ts +3 -0
- package/src/core/logger/index.ts +4 -0
- package/src/{utilities/logger/logger.config.ts → core/logger/winston-logger.config.ts} +1 -1
- package/src/{utilities → core}/logger/winston-logger.service.ts +3 -3
- package/src/core/message-broker/bullmq/basic-types.ts +67 -0
- package/src/core/message-broker/bullmq/broker.ts +141 -0
- package/src/core/message-broker/bullmq/index.ts +3 -0
- package/src/core/message-broker/bullmq/queue.ts +58 -0
- package/src/core/message-broker/bullmq/worker.ts +68 -0
- package/src/core/message-broker/kafka/basic-types.ts +45 -0
- package/src/core/message-broker/kafka/consumer.ts +95 -0
- package/src/core/message-broker/kafka/index.ts +3 -0
- package/src/core/message-broker/kafka/producer.ts +113 -0
- package/src/core/message-broker/rabitmq/basic-types.ts +44 -0
- package/src/core/message-broker/rabitmq/channel.ts +95 -0
- package/src/core/message-broker/rabitmq/consumer.ts +94 -0
- package/src/core/message-broker/rabitmq/index.ts +4 -0
- package/src/core/message-broker/rabitmq/producer.ts +100 -0
- package/src/core/message-broker/utilities.ts +50 -0
- package/src/core/middlewares/basic-types.ts +39 -0
- package/src/core/middlewares/decorators.ts +244 -0
- package/src/core/middlewares/index.ts +3 -0
- package/src/core/middlewares/middlewares.ts +246 -0
- package/src/core/parallel/index.ts +3 -0
- package/src/{utilities → core}/parallel/parallel.ts +11 -1
- package/src/core/rate-limit/basic-types.ts +43 -0
- package/src/core/rate-limit/index.ts +4 -0
- package/src/core/rate-limit/memory-store.ts +65 -0
- package/src/core/rate-limit/rate-limit.ts +134 -0
- package/src/core/rate-limit/redis-store.ts +141 -0
- package/src/core/retry/basic-types.ts +21 -0
- package/src/core/retry/decorator.ts +139 -0
- package/src/core/retry/index.ts +2 -0
- package/src/main.ts +6 -8
- package/src/routers/orders/index.router.ts +5 -1
- package/src/routers/orders/order.controller.ts +46 -59
- package/src/routers/products/index.router.ts +2 -1
- package/src/routers/products/product.controller.ts +25 -63
- package/src/routers/users/index.router.ts +1 -1
- package/src/routers/users/user.controller.ts +22 -50
- package/src/utilities/cache/memory-cache.ts +0 -74
- /package/src/{utilities → core}/logger/base-logger.interface.ts +0 -0
- /package/src/{utilities → core}/logger/logger.service.ts +0 -0
- /package/src/{utilities → core}/parallel/chanel.ts +0 -0
- /package/src/{utilities → core}/parallel/worker-pool.ts +0 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
2
|
+
import {
|
|
3
|
+
DynamoDBDocumentClient,
|
|
4
|
+
PutCommand,
|
|
5
|
+
GetCommand,
|
|
6
|
+
UpdateCommand,
|
|
7
|
+
DeleteCommand,
|
|
8
|
+
QueryCommand,
|
|
9
|
+
ScanCommand,
|
|
10
|
+
PutCommandInput,
|
|
11
|
+
GetCommandInput,
|
|
12
|
+
UpdateCommandInput,
|
|
13
|
+
DeleteCommandInput,
|
|
14
|
+
QueryCommandInput,
|
|
15
|
+
ScanCommandInput,
|
|
16
|
+
} from "@aws-sdk/lib-dynamodb";
|
|
17
|
+
|
|
18
|
+
export function createDocClient(
|
|
19
|
+
region?: string,
|
|
20
|
+
...args: any[]
|
|
21
|
+
): DynamoDBDocumentClient {
|
|
22
|
+
const client = new DynamoDBClient({ region, ...args });
|
|
23
|
+
return DynamoDBDocumentClient.from(client);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Basic wrappers (more convenient with document client)
|
|
27
|
+
export async function putItem<T>(
|
|
28
|
+
docClient: DynamoDBDocumentClient,
|
|
29
|
+
tableName: string,
|
|
30
|
+
item: T
|
|
31
|
+
) {
|
|
32
|
+
const command = new PutCommand({
|
|
33
|
+
TableName: tableName,
|
|
34
|
+
Item: item as any,
|
|
35
|
+
} as PutCommandInput);
|
|
36
|
+
return docClient.send(command);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function getItem<T>(
|
|
40
|
+
docClient: DynamoDBDocumentClient,
|
|
41
|
+
tableName: string,
|
|
42
|
+
key: Record<string, any>
|
|
43
|
+
): Promise<T | undefined> {
|
|
44
|
+
const command = new GetCommand({
|
|
45
|
+
TableName: tableName,
|
|
46
|
+
Key: key,
|
|
47
|
+
} as GetCommandInput);
|
|
48
|
+
const resp = await docClient.send(command);
|
|
49
|
+
return (resp.Item as T) ?? undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function updateItem<T>(
|
|
53
|
+
docClient: DynamoDBDocumentClient,
|
|
54
|
+
tableName: string,
|
|
55
|
+
key: Record<string, any>,
|
|
56
|
+
updateExpression: string,
|
|
57
|
+
expressionAttributeValues: Record<string, any>,
|
|
58
|
+
conditionExpression?: string
|
|
59
|
+
): Promise<T | undefined> {
|
|
60
|
+
const command = new UpdateCommand({
|
|
61
|
+
TableName: tableName,
|
|
62
|
+
Key: key,
|
|
63
|
+
UpdateExpression: updateExpression,
|
|
64
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
65
|
+
ConditionExpression: conditionExpression,
|
|
66
|
+
ReturnValues: "ALL_NEW",
|
|
67
|
+
} as UpdateCommandInput);
|
|
68
|
+
const resp = await docClient.send(command);
|
|
69
|
+
return resp.Attributes as unknown as T;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function deleteItem(
|
|
73
|
+
docClient: DynamoDBDocumentClient,
|
|
74
|
+
tableName: string,
|
|
75
|
+
key: Record<string, any>
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
const command = new DeleteCommand({
|
|
78
|
+
TableName: tableName,
|
|
79
|
+
Key: key,
|
|
80
|
+
} as DeleteCommandInput);
|
|
81
|
+
await docClient.send(command);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function queryItems<T>(
|
|
85
|
+
docClient: DynamoDBDocumentClient,
|
|
86
|
+
tableName: string,
|
|
87
|
+
keyConditionExpression: string,
|
|
88
|
+
expressionAttributeValues: Record<string, any>,
|
|
89
|
+
indexName?: string
|
|
90
|
+
): Promise<T[]> {
|
|
91
|
+
const command = new QueryCommand({
|
|
92
|
+
TableName: tableName,
|
|
93
|
+
IndexName: indexName,
|
|
94
|
+
KeyConditionExpression: keyConditionExpression,
|
|
95
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
96
|
+
} as QueryCommandInput);
|
|
97
|
+
const resp = await docClient.send(command);
|
|
98
|
+
return (resp.Items as T[]) ?? [];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function scanItems<T>(
|
|
102
|
+
docClient: DynamoDBDocumentClient,
|
|
103
|
+
tableName: string,
|
|
104
|
+
filterExpression?: string,
|
|
105
|
+
expressionAttributeValues?: Record<string, any>,
|
|
106
|
+
indexName?: string
|
|
107
|
+
): Promise<T[]> {
|
|
108
|
+
const command = new ScanCommand({
|
|
109
|
+
TableName: tableName,
|
|
110
|
+
FilterExpression: filterExpression,
|
|
111
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
112
|
+
IndexName: indexName,
|
|
113
|
+
} as ScanCommandInput);
|
|
114
|
+
const resp = await docClient.send(command);
|
|
115
|
+
return (resp.Items as T[]) ?? [];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export class DynamoRepository<T extends { [key: string]: any }> {
|
|
119
|
+
public docClient!: DynamoDBDocumentClient;
|
|
120
|
+
private tableName: string;
|
|
121
|
+
|
|
122
|
+
public constructor(tableName: string, region?: string, ...args: any[]) {
|
|
123
|
+
this.tableName = tableName;
|
|
124
|
+
if (region != null) {
|
|
125
|
+
this.docClient = createDocClient(region, ...args);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public async put(item: T): Promise<void> {
|
|
130
|
+
// You may want to enforce key presence here
|
|
131
|
+
await putItem(this.docClient, this.tableName, item);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public async get(key: Record<string, any>): Promise<T | undefined> {
|
|
135
|
+
return (await getItem<T>(this.docClient, this.tableName, key)) as
|
|
136
|
+
| T
|
|
137
|
+
| undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public async update(
|
|
141
|
+
key: Record<string, any>,
|
|
142
|
+
updateExpression: string,
|
|
143
|
+
expressionAttributeValues: Record<string, any>,
|
|
144
|
+
conditionExpression?: string
|
|
145
|
+
): Promise<T | undefined> {
|
|
146
|
+
return await updateItem<T>(
|
|
147
|
+
this.docClient,
|
|
148
|
+
this.tableName,
|
|
149
|
+
key,
|
|
150
|
+
updateExpression,
|
|
151
|
+
expressionAttributeValues,
|
|
152
|
+
conditionExpression
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public async delete(key: Record<string, any>): Promise<void> {
|
|
157
|
+
await deleteItem(this.docClient, this.tableName, key);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public async query(
|
|
161
|
+
keyConditionExpression: string,
|
|
162
|
+
expressionAttributeValues: Record<string, any>,
|
|
163
|
+
indexName?: string
|
|
164
|
+
): Promise<T[]> {
|
|
165
|
+
return await queryItems<T>(
|
|
166
|
+
this.docClient,
|
|
167
|
+
this.tableName,
|
|
168
|
+
keyConditionExpression,
|
|
169
|
+
expressionAttributeValues,
|
|
170
|
+
indexName
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public async scan(
|
|
175
|
+
filterExpression?: string,
|
|
176
|
+
expressionAttributeValues?: Record<string, any>,
|
|
177
|
+
indexName?: string
|
|
178
|
+
): Promise<T[]> {
|
|
179
|
+
return await scanItems<T>(
|
|
180
|
+
this.docClient,
|
|
181
|
+
this.tableName,
|
|
182
|
+
filterExpression,
|
|
183
|
+
expressionAttributeValues,
|
|
184
|
+
indexName
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./basic-types";
|
|
2
|
+
export * from "./utilities";
|
|
3
|
+
export * from "./lambda";
|
|
4
|
+
export * from "./s3";
|
|
5
|
+
export * from "./api-gateway";
|
|
6
|
+
export * from "./message";
|
|
7
|
+
export * from "./message-broker";
|
|
8
|
+
export * from "./api-gateway";
|
|
9
|
+
export * from "./dynamodb";
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LambdaClient,
|
|
3
|
+
CreateFunctionCommand,
|
|
4
|
+
GetFunctionCommand,
|
|
5
|
+
UpdateFunctionCodeCommand,
|
|
6
|
+
UpdateFunctionConfigurationCommand,
|
|
7
|
+
InvokeCommand,
|
|
8
|
+
ListFunctionsCommand,
|
|
9
|
+
DeleteFunctionCommand,
|
|
10
|
+
Runtime,
|
|
11
|
+
} from "@aws-sdk/client-lambda";
|
|
12
|
+
import { LambdaCreateParams } from "./basic-types";
|
|
13
|
+
import { retry, RetryOptions } from "./utilities";
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import util from "util";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Client for interacting with AWS Lambda functions.
|
|
19
|
+
*/
|
|
20
|
+
export class Lambda {
|
|
21
|
+
public client: LambdaClient;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Constructor for LambdaClient.
|
|
25
|
+
* @param {string} [region] - The AWS region to use for the client.
|
|
26
|
+
* If not provided, the default region will be used.
|
|
27
|
+
*/
|
|
28
|
+
public constructor(region?: string, ...args: any[]) {
|
|
29
|
+
if (region != null) {
|
|
30
|
+
this.client = new LambdaClient({ region, ...args });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Tries to update or create a Lambda function.
|
|
36
|
+
* If the function already exists, it will be updated.
|
|
37
|
+
* If the function does not exist, it will be created.
|
|
38
|
+
*
|
|
39
|
+
* @throws If the function could not be updated or created
|
|
40
|
+
*/
|
|
41
|
+
public async createOrUpdateFunction(
|
|
42
|
+
params: LambdaCreateParams,
|
|
43
|
+
shouldRetry = false,
|
|
44
|
+
retryOptions?: RetryOptions
|
|
45
|
+
): Promise<void> {
|
|
46
|
+
const {
|
|
47
|
+
functionName,
|
|
48
|
+
roleArn,
|
|
49
|
+
zipFilePath,
|
|
50
|
+
handler,
|
|
51
|
+
runtime = Runtime.nodejs18x,
|
|
52
|
+
timeout = 15,
|
|
53
|
+
memorySize = 128,
|
|
54
|
+
environment,
|
|
55
|
+
} = params;
|
|
56
|
+
|
|
57
|
+
const codeBytes = await this.readZip(zipFilePath);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Tries to update or create a Lambda function.
|
|
61
|
+
* If the function already exists, it will be updated.
|
|
62
|
+
* If the function does not exist, it will be created.
|
|
63
|
+
*
|
|
64
|
+
* @throws If the function could not be updated or created
|
|
65
|
+
*/
|
|
66
|
+
const upsert = async () => {
|
|
67
|
+
try {
|
|
68
|
+
// Try to get function to decide between update vs create
|
|
69
|
+
await this.client.send(
|
|
70
|
+
new GetFunctionCommand({ FunctionName: functionName })
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Update
|
|
74
|
+
await this.client.send(
|
|
75
|
+
new UpdateFunctionCodeCommand({
|
|
76
|
+
FunctionName: functionName,
|
|
77
|
+
ZipFile: codeBytes,
|
|
78
|
+
})
|
|
79
|
+
);
|
|
80
|
+
await this.client.send(
|
|
81
|
+
new UpdateFunctionConfigurationCommand({
|
|
82
|
+
FunctionName: functionName,
|
|
83
|
+
Role: roleArn,
|
|
84
|
+
Handler: handler,
|
|
85
|
+
Runtime: runtime,
|
|
86
|
+
Timeout: timeout,
|
|
87
|
+
MemorySize: memorySize,
|
|
88
|
+
Environment: environment ? { Variables: environment } : undefined,
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
} catch (err: any) {
|
|
92
|
+
const isNotFound =
|
|
93
|
+
err.name === "ResourceNotFoundException" ||
|
|
94
|
+
(err.$response && err.$response.statusCode === 404);
|
|
95
|
+
if (isNotFound) {
|
|
96
|
+
// Create
|
|
97
|
+
await this.client.send(
|
|
98
|
+
new CreateFunctionCommand({
|
|
99
|
+
FunctionName: functionName,
|
|
100
|
+
Runtime: runtime,
|
|
101
|
+
Role: roleArn,
|
|
102
|
+
Handler: handler,
|
|
103
|
+
Code: { ZipFile: codeBytes },
|
|
104
|
+
Timeout: timeout,
|
|
105
|
+
MemorySize: memorySize,
|
|
106
|
+
Environment: environment ? { Variables: environment } : undefined,
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
} else {
|
|
110
|
+
throw err;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
retry(upsert, retryOptions);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Invoke a lambda function.
|
|
120
|
+
*
|
|
121
|
+
* @param functionName Name of the lambda function to invoke.
|
|
122
|
+
* @param payload Payload to pass to the lambda function.
|
|
123
|
+
* @param invocationType Invocation type; "RequestResponse" for synchronous invocation,
|
|
124
|
+
* "Event" for asynchronous invocation.
|
|
125
|
+
* @returns The response from the lambda function, normalized to a Buffer.
|
|
126
|
+
*/
|
|
127
|
+
public async invoke(
|
|
128
|
+
functionName: string,
|
|
129
|
+
payload: any,
|
|
130
|
+
invocationType: "RequestResponse" | "Event" = "RequestResponse"
|
|
131
|
+
): Promise<Buffer> {
|
|
132
|
+
const cmd = new InvokeCommand({
|
|
133
|
+
FunctionName: functionName,
|
|
134
|
+
Payload:
|
|
135
|
+
typeof payload === "string"
|
|
136
|
+
? payload
|
|
137
|
+
: Buffer.from(JSON.stringify(payload)),
|
|
138
|
+
InvocationType: invocationType,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const resp = await this.client.send(cmd);
|
|
142
|
+
// Payload is a streaming or binary blob; normalize to Buffer
|
|
143
|
+
if (resp.Payload instanceof Uint8Array) {
|
|
144
|
+
return Buffer.from(resp.Payload);
|
|
145
|
+
}
|
|
146
|
+
if (resp.Payload) {
|
|
147
|
+
// Attempt to read as Buffer if possible
|
|
148
|
+
try {
|
|
149
|
+
const chunks: Buffer[] = [];
|
|
150
|
+
for await (const chunk of resp.Payload as any) {
|
|
151
|
+
chunks.push(Buffer.from(chunk));
|
|
152
|
+
}
|
|
153
|
+
return Buffer.concat(chunks);
|
|
154
|
+
} catch {
|
|
155
|
+
// If not iterable, fall back to empty
|
|
156
|
+
return Buffer.alloc(0);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return Buffer.alloc(0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Lists all Lambda functions with an optional prefix filter.
|
|
164
|
+
* @param {string} [prefix] - Optional prefix to filter functions by.
|
|
165
|
+
* @returns {Promise<any[]>} - A Promise resolving with an array of Lambda functions.
|
|
166
|
+
*/
|
|
167
|
+
public async listFunctions(prefix?: string): Promise<any[]> {
|
|
168
|
+
const cmd = new ListFunctionsCommand({});
|
|
169
|
+
const resp: any = await this.client.send(cmd);
|
|
170
|
+
let items: any[] = resp.Functions || [];
|
|
171
|
+
if (prefix) {
|
|
172
|
+
items = items.filter((f) => f.FunctionName?.startsWith(prefix));
|
|
173
|
+
}
|
|
174
|
+
return items;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Deletes a Lambda function.
|
|
179
|
+
* @param functionName The name of the Lambda function to delete.
|
|
180
|
+
* @returns A Promise resolving when the function is deleted.
|
|
181
|
+
*/
|
|
182
|
+
async deleteFunction(functionName: string): Promise<void> {
|
|
183
|
+
await this.client.send(
|
|
184
|
+
new DeleteFunctionCommand({ FunctionName: functionName })
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Reads a file from the local file system as a zip archive and returns the contents as a Buffer.
|
|
190
|
+
* @param path The path to the zip archive to read.
|
|
191
|
+
* @returns A Promise resolving to a Buffer containing the file contents.
|
|
192
|
+
* @private
|
|
193
|
+
*/
|
|
194
|
+
private async readZip(path: string): Promise<Buffer> {
|
|
195
|
+
// Read file using fs.promises
|
|
196
|
+
const readFile = util.promisify(fs.promises.readFile);
|
|
197
|
+
return (await readFile(path, undefined)) as Buffer;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SNSClient,
|
|
3
|
+
CreateTopicCommand,
|
|
4
|
+
SubscribeCommand,
|
|
5
|
+
PublishCommand,
|
|
6
|
+
DeleteTopicCommand,
|
|
7
|
+
ListTopicsCommand,
|
|
8
|
+
} from "@aws-sdk/client-sns";
|
|
9
|
+
import {
|
|
10
|
+
SQSClient,
|
|
11
|
+
CreateQueueCommand,
|
|
12
|
+
GetQueueAttributesCommand,
|
|
13
|
+
ReceiveMessageCommand,
|
|
14
|
+
DeleteMessageCommand,
|
|
15
|
+
DeleteQueueCommand,
|
|
16
|
+
} from "@aws-sdk/client-sqs";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* SNS-SQS Message Broker for publishing and consuming messages with AWS SNS and SQS.
|
|
20
|
+
*/
|
|
21
|
+
export class AwsSnsSqsBroker {
|
|
22
|
+
public snsClient!: SNSClient;
|
|
23
|
+
public sqsClient!: SQSClient;
|
|
24
|
+
|
|
25
|
+
public constructor(region?: string, ...args: any[]) {
|
|
26
|
+
if (region != null) {
|
|
27
|
+
this.snsClient = new SNSClient({ region, ...args });
|
|
28
|
+
this.sqsClient = new SQSClient({ region, ...args });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Creates an SNS topic.
|
|
34
|
+
* @param topicName - The name for the SNS topic.
|
|
35
|
+
* @returns The ARN of the created topic.
|
|
36
|
+
*/
|
|
37
|
+
public async createTopic(topicName: string): Promise<string> {
|
|
38
|
+
const command = new CreateTopicCommand({ Name: topicName });
|
|
39
|
+
const response = await this.snsClient.send(command);
|
|
40
|
+
return response.TopicArn!;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Deletes an SNS topic by ARN.
|
|
45
|
+
* @param topicArn - The ARN of the topic to delete.
|
|
46
|
+
*/
|
|
47
|
+
public async deleteTopic(topicArn: string): Promise<void> {
|
|
48
|
+
const command = new DeleteTopicCommand({ TopicArn: topicArn });
|
|
49
|
+
await this.snsClient.send(command);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Creates an SQS queue.
|
|
54
|
+
* @param queueName - The name for the queue.
|
|
55
|
+
* @param attributes - Optional queue attributes such as visibility timeout.
|
|
56
|
+
* @returns The URL of the created queue.
|
|
57
|
+
*/
|
|
58
|
+
public async createQueue(
|
|
59
|
+
queueName: string,
|
|
60
|
+
attributes?: Record<string, string>
|
|
61
|
+
): Promise<string> {
|
|
62
|
+
const command = new CreateQueueCommand({
|
|
63
|
+
QueueName: queueName,
|
|
64
|
+
Attributes: attributes,
|
|
65
|
+
});
|
|
66
|
+
const response = await this.sqsClient.send(command);
|
|
67
|
+
return response.QueueUrl!;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Deletes an SQS queue by URL.
|
|
72
|
+
* @param queueUrl - The URL of the queue to delete.
|
|
73
|
+
*/
|
|
74
|
+
public async deleteQueue(queueUrl: string): Promise<void> {
|
|
75
|
+
const command = new DeleteQueueCommand({ QueueUrl: queueUrl });
|
|
76
|
+
await this.sqsClient.send(command);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Subscribes an SQS queue to an SNS topic.
|
|
81
|
+
* @param topicArn - ARN of the SNS topic.
|
|
82
|
+
* @param queueArn - ARN of the SQS queue.
|
|
83
|
+
* @returns The Subscription ARN.
|
|
84
|
+
*/
|
|
85
|
+
public async subscribeQueueToTopic(
|
|
86
|
+
topicArn: string,
|
|
87
|
+
queueArn: string
|
|
88
|
+
): Promise<string> {
|
|
89
|
+
const command = new SubscribeCommand({
|
|
90
|
+
TopicArn: topicArn,
|
|
91
|
+
Protocol: "sqs",
|
|
92
|
+
Endpoint: queueArn,
|
|
93
|
+
});
|
|
94
|
+
const response = await this.snsClient.send(command);
|
|
95
|
+
return response.SubscriptionArn!;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Gets the ARN of an SQS queue from its URL.
|
|
100
|
+
* @param queueUrl - The URL of the SQS queue.
|
|
101
|
+
* @returns The ARN string of the queue.
|
|
102
|
+
*/
|
|
103
|
+
public async getQueueArn(queueUrl: string): Promise<string> {
|
|
104
|
+
const command = new GetQueueAttributesCommand({
|
|
105
|
+
QueueUrl: queueUrl,
|
|
106
|
+
AttributeNames: ["QueueArn"],
|
|
107
|
+
});
|
|
108
|
+
const response = await this.sqsClient.send(command);
|
|
109
|
+
return response.Attributes?.QueueArn || "";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Publishes a message to an SNS topic.
|
|
114
|
+
* @param topicArn - ARN of the SNS topic.
|
|
115
|
+
* @param message - The message content to send.
|
|
116
|
+
* @param subject - Optional message subject.
|
|
117
|
+
*/
|
|
118
|
+
public async publishMessage(
|
|
119
|
+
topicArn: string,
|
|
120
|
+
message: string,
|
|
121
|
+
subject?: string
|
|
122
|
+
): Promise<void> {
|
|
123
|
+
const command = new PublishCommand({
|
|
124
|
+
TopicArn: topicArn,
|
|
125
|
+
Message: message,
|
|
126
|
+
Subject: subject,
|
|
127
|
+
});
|
|
128
|
+
await this.snsClient.send(command);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Receives messages from an SQS queue.
|
|
133
|
+
* @param queueUrl - The URL of the SQS queue.
|
|
134
|
+
* @param maxMessages - Maximum number of messages to receive (default 1).
|
|
135
|
+
* @param waitTimeSeconds - Long polling wait time in seconds (default 10).
|
|
136
|
+
* @returns Array of messages received.
|
|
137
|
+
*/
|
|
138
|
+
public async receiveMessages(
|
|
139
|
+
queueUrl: string,
|
|
140
|
+
maxMessages: number = 1,
|
|
141
|
+
waitTimeSeconds: number = 10
|
|
142
|
+
) {
|
|
143
|
+
const command = new ReceiveMessageCommand({
|
|
144
|
+
QueueUrl: queueUrl,
|
|
145
|
+
MaxNumberOfMessages: maxMessages,
|
|
146
|
+
WaitTimeSeconds: waitTimeSeconds,
|
|
147
|
+
});
|
|
148
|
+
const response = await this.sqsClient.send(command);
|
|
149
|
+
return response.Messages || [];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Deletes a message from an SQS queue.
|
|
154
|
+
* @param queueUrl - The URL of the SQS queue.
|
|
155
|
+
* @param receiptHandle - The receipt handle of the message to delete.
|
|
156
|
+
*/
|
|
157
|
+
public async deleteMessage(
|
|
158
|
+
queueUrl: string,
|
|
159
|
+
receiptHandle: string
|
|
160
|
+
): Promise<void> {
|
|
161
|
+
const command = new DeleteMessageCommand({
|
|
162
|
+
QueueUrl: queueUrl,
|
|
163
|
+
ReceiptHandle: receiptHandle,
|
|
164
|
+
});
|
|
165
|
+
await this.sqsClient.send(command);
|
|
166
|
+
}
|
|
167
|
+
}
|