s3db.js 6.2.0 → 7.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/PLUGINS.md +2724 -0
- package/README.md +372 -469
- package/UNLICENSE +24 -0
- package/dist/s3db.cjs.js +30057 -18387
- package/dist/s3db.cjs.min.js +1 -1
- package/dist/s3db.d.ts +373 -72
- package/dist/s3db.es.js +30043 -18384
- package/dist/s3db.es.min.js +1 -1
- package/dist/s3db.iife.js +29730 -18061
- package/dist/s3db.iife.min.js +1 -1
- package/package.json +44 -69
- package/src/behaviors/body-only.js +110 -0
- package/src/behaviors/body-overflow.js +153 -0
- package/src/behaviors/enforce-limits.js +195 -0
- package/src/behaviors/index.js +39 -0
- package/src/behaviors/truncate-data.js +204 -0
- package/src/behaviors/user-managed.js +147 -0
- package/src/client.class.js +515 -0
- package/src/concerns/base62.js +61 -0
- package/src/concerns/calculator.js +204 -0
- package/src/concerns/crypto.js +142 -0
- package/src/concerns/id.js +8 -0
- package/src/concerns/index.js +5 -0
- package/src/concerns/try-fn.js +151 -0
- package/src/connection-string.class.js +75 -0
- package/src/database.class.js +599 -0
- package/src/errors.js +261 -0
- package/src/index.js +17 -0
- package/src/plugins/audit.plugin.js +442 -0
- package/src/plugins/cache/cache.class.js +53 -0
- package/src/plugins/cache/index.js +6 -0
- package/src/plugins/cache/memory-cache.class.js +164 -0
- package/src/plugins/cache/s3-cache.class.js +189 -0
- package/src/plugins/cache.plugin.js +275 -0
- package/src/plugins/consumers/index.js +24 -0
- package/src/plugins/consumers/rabbitmq-consumer.js +56 -0
- package/src/plugins/consumers/sqs-consumer.js +102 -0
- package/src/plugins/costs.plugin.js +81 -0
- package/src/plugins/fulltext.plugin.js +473 -0
- package/src/plugins/index.js +12 -0
- package/src/plugins/metrics.plugin.js +603 -0
- package/src/plugins/plugin.class.js +210 -0
- package/src/plugins/plugin.obj.js +13 -0
- package/src/plugins/queue-consumer.plugin.js +134 -0
- package/src/plugins/replicator.plugin.js +769 -0
- package/src/plugins/replicators/base-replicator.class.js +85 -0
- package/src/plugins/replicators/bigquery-replicator.class.js +328 -0
- package/src/plugins/replicators/index.js +44 -0
- package/src/plugins/replicators/postgres-replicator.class.js +427 -0
- package/src/plugins/replicators/s3db-replicator.class.js +352 -0
- package/src/plugins/replicators/sqs-replicator.class.js +427 -0
- package/src/resource.class.js +2626 -0
- package/src/s3db.d.ts +1263 -0
- package/src/schema.class.js +706 -0
- package/src/stream/index.js +16 -0
- package/src/stream/resource-ids-page-reader.class.js +10 -0
- package/src/stream/resource-ids-reader.class.js +63 -0
- package/src/stream/resource-reader.class.js +81 -0
- package/src/stream/resource-writer.class.js +92 -0
- package/src/validator.class.js +97 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQS Replicator Configuration Documentation
|
|
3
|
+
*
|
|
4
|
+
* This replicator sends replicator events to Amazon SQS queues. It supports both
|
|
5
|
+
* resource-specific queues and a single queue for all events, with a flexible message
|
|
6
|
+
* structure that includes operation details and data.
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ REQUIRED DEPENDENCY: You must install the AWS SQS SDK to use this replicator:
|
|
9
|
+
*
|
|
10
|
+
* ```bash
|
|
11
|
+
* npm install @aws-sdk/client-sqs
|
|
12
|
+
* # or
|
|
13
|
+
* yarn add @aws-sdk/client-sqs
|
|
14
|
+
* # or
|
|
15
|
+
* pnpm add @aws-sdk/client-sqs
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @typedef {Object} SQSReplicatorConfig
|
|
19
|
+
* @property {string} region - AWS region where the SQS queues are located
|
|
20
|
+
* @property {string} [accessKeyId] - AWS access key ID (if not using IAM roles)
|
|
21
|
+
* @property {string} [secretAccessKey] - AWS secret access key (if not using IAM roles)
|
|
22
|
+
* @property {string} [sessionToken] - AWS session token for temporary credentials
|
|
23
|
+
* @property {string} [defaultQueueUrl] - Default SQS queue URL for all events when resource-specific queues are not configured
|
|
24
|
+
* @property {Object.<string, string>} [resourceQueues] - Maps s3db resource names to specific SQS queue URLs
|
|
25
|
+
* - Key: s3db resource name (e.g., 'users', 'orders')
|
|
26
|
+
* - Value: SQS queue URL (e.g., 'https://sqs.us-east-1.amazonaws.com/123456789012/users-queue')
|
|
27
|
+
* - If not provided, defaultQueueUrl is used for all resources
|
|
28
|
+
* @property {number} [maxRetries=3] - Maximum number of retry attempts for failed message sends
|
|
29
|
+
* @property {number} [retryDelay=1000] - Delay in milliseconds between retry attempts
|
|
30
|
+
* @property {boolean} [logMessages=false] - Whether to log message details to console for debugging
|
|
31
|
+
* @property {number} [messageDelaySeconds=0] - Delay in seconds before messages become visible in queue
|
|
32
|
+
* @property {Object} [messageAttributes] - Additional attributes to include with every SQS message
|
|
33
|
+
* - Key: attribute name (e.g., 'environment', 'version')
|
|
34
|
+
* - Value: attribute value (e.g., 'production', '1.0.0')
|
|
35
|
+
* @property {string} [messageGroupId] - Message group ID for FIFO queues (required for FIFO queues)
|
|
36
|
+
* @property {boolean} [useFIFO=false] - Whether the target queues are FIFO queues
|
|
37
|
+
* @property {number} [batchSize=10] - Number of messages to send in a single batch (for batch operations)
|
|
38
|
+
* @property {boolean} [compressMessages=false] - Whether to compress message bodies using gzip
|
|
39
|
+
* @property {string} [messageFormat='json'] - Format for message body: 'json' or 'stringified'
|
|
40
|
+
* @property {Object} [sqsClientOptions] - Additional options to pass to the SQS client constructor
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // Configuration with resource-specific queues
|
|
44
|
+
* {
|
|
45
|
+
* region: 'us-east-1',
|
|
46
|
+
* accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
|
|
47
|
+
* secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
|
48
|
+
* resourceQueues: {
|
|
49
|
+
* 'users': 'https://sqs.us-east-1.amazonaws.com/123456789012/users-events',
|
|
50
|
+
* 'orders': 'https://sqs.us-east-1.amazonaws.com/123456789012/orders-events',
|
|
51
|
+
* 'products': 'https://sqs.us-east-1.amazonaws.com/123456789012/products-events'
|
|
52
|
+
* },
|
|
53
|
+
* logMessages: true,
|
|
54
|
+
* messageAttributes: {
|
|
55
|
+
* 'environment': 'production',
|
|
56
|
+
* 'source': 's3db-replicator'
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* // Configuration with single default queue
|
|
62
|
+
* {
|
|
63
|
+
* region: 'us-west-2',
|
|
64
|
+
* defaultQueueUrl: 'https://sqs.us-west-2.amazonaws.com/123456789012/all-events',
|
|
65
|
+
* maxRetries: 5,
|
|
66
|
+
* retryDelay: 2000,
|
|
67
|
+
* compressMessages: true
|
|
68
|
+
* }
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // FIFO queue configuration
|
|
72
|
+
* {
|
|
73
|
+
* region: 'eu-west-1',
|
|
74
|
+
* defaultQueueUrl: 'https://sqs.eu-west-1.amazonaws.com/123456789012/events.fifo',
|
|
75
|
+
* useFIFO: true,
|
|
76
|
+
* messageGroupId: 's3db-events',
|
|
77
|
+
* messageDelaySeconds: 5
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* // Minimal configuration using IAM roles
|
|
82
|
+
* {
|
|
83
|
+
* region: 'us-east-1',
|
|
84
|
+
* defaultQueueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue'
|
|
85
|
+
* }
|
|
86
|
+
*
|
|
87
|
+
* @notes
|
|
88
|
+
* - Requires AWS credentials with SQS SendMessage permissions
|
|
89
|
+
* - Resource-specific queues take precedence over defaultQueueUrl
|
|
90
|
+
* - Message structure includes: resource, action, data, before (for updates), timestamp, source
|
|
91
|
+
* - FIFO queues require messageGroupId and ensure strict ordering
|
|
92
|
+
* - Message compression reduces bandwidth but increases CPU usage
|
|
93
|
+
* - Batch operations improve performance but may fail if any message in batch fails
|
|
94
|
+
* - Retry mechanism uses exponential backoff for failed sends
|
|
95
|
+
* - Message attributes are useful for filtering and routing in SQS
|
|
96
|
+
* - Message delay is useful for implementing eventual consistency patterns
|
|
97
|
+
* - SQS client options allow for custom endpoint, credentials, etc.
|
|
98
|
+
*/
|
|
99
|
+
import BaseReplicator from './base-replicator.class.js';
|
|
100
|
+
import tryFn from "../../concerns/try-fn.js";
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* SQS Replicator - Sends data to AWS SQS queues with support for resource-specific queues
|
|
104
|
+
*
|
|
105
|
+
* Configuration options:
|
|
106
|
+
* - queueUrl: Single queue URL for all resources
|
|
107
|
+
* - queues: Object mapping resource names to specific queue URLs
|
|
108
|
+
* - defaultQueueUrl: Fallback queue URL when resource-specific queue is not found
|
|
109
|
+
* - messageGroupId: For FIFO queues
|
|
110
|
+
* - deduplicationId: For FIFO queues
|
|
111
|
+
*
|
|
112
|
+
* Example configurations:
|
|
113
|
+
*
|
|
114
|
+
* // Single queue for all resources
|
|
115
|
+
* {
|
|
116
|
+
* queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue'
|
|
117
|
+
* }
|
|
118
|
+
*
|
|
119
|
+
* // Resource-specific queues
|
|
120
|
+
* {
|
|
121
|
+
* queues: {
|
|
122
|
+
* users: 'https://sqs.us-east-1.amazonaws.com/123456789012/users-queue',
|
|
123
|
+
* orders: 'https://sqs.us-east-1.amazonaws.com/123456789012/orders-queue'
|
|
124
|
+
* },
|
|
125
|
+
* defaultQueueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/default-queue'
|
|
126
|
+
* }
|
|
127
|
+
*/
|
|
128
|
+
class SqsReplicator extends BaseReplicator {
|
|
129
|
+
constructor(config = {}, resources = [], client = null) {
|
|
130
|
+
super(config);
|
|
131
|
+
this.resources = resources;
|
|
132
|
+
this.client = client;
|
|
133
|
+
this.queueUrl = config.queueUrl;
|
|
134
|
+
this.queues = config.queues || {};
|
|
135
|
+
this.defaultQueue = config.defaultQueue || config.defaultQueueUrl || config.queueUrlDefault;
|
|
136
|
+
this.region = config.region || 'us-east-1';
|
|
137
|
+
this.sqsClient = client || null;
|
|
138
|
+
this.messageGroupId = config.messageGroupId;
|
|
139
|
+
this.deduplicationId = config.deduplicationId;
|
|
140
|
+
|
|
141
|
+
// Build queues from resources configuration
|
|
142
|
+
if (resources && typeof resources === 'object') {
|
|
143
|
+
for (const [resourceName, resourceConfig] of Object.entries(resources)) {
|
|
144
|
+
if (resourceConfig.queueUrl) {
|
|
145
|
+
this.queues[resourceName] = resourceConfig.queueUrl;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
validateConfig() {
|
|
152
|
+
const errors = [];
|
|
153
|
+
if (!this.queueUrl && Object.keys(this.queues).length === 0 && !this.defaultQueue && !this.resourceQueueMap) {
|
|
154
|
+
errors.push('Either queueUrl, queues object, defaultQueue, or resourceQueueMap must be provided');
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
isValid: errors.length === 0,
|
|
158
|
+
errors
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
getQueueUrlsForResource(resource) {
|
|
163
|
+
// Prefer resourceQueueMap if present
|
|
164
|
+
if (this.resourceQueueMap && this.resourceQueueMap[resource]) {
|
|
165
|
+
return this.resourceQueueMap[resource];
|
|
166
|
+
}
|
|
167
|
+
if (this.queues[resource]) {
|
|
168
|
+
return [this.queues[resource]];
|
|
169
|
+
}
|
|
170
|
+
if (this.queueUrl) {
|
|
171
|
+
return [this.queueUrl];
|
|
172
|
+
}
|
|
173
|
+
if (this.defaultQueue) {
|
|
174
|
+
return [this.defaultQueue];
|
|
175
|
+
}
|
|
176
|
+
throw new Error(`No queue URL found for resource '${resource}'`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
_applyTransformer(resource, data) {
|
|
180
|
+
const entry = this.resources[resource];
|
|
181
|
+
let result = data;
|
|
182
|
+
|
|
183
|
+
if (!entry) return data;
|
|
184
|
+
|
|
185
|
+
// Check for transform function in resource config
|
|
186
|
+
if (typeof entry.transform === 'function') {
|
|
187
|
+
result = entry.transform(data);
|
|
188
|
+
} else if (typeof entry.transformer === 'function') {
|
|
189
|
+
result = entry.transformer(data);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return result || data;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Create standardized message structure
|
|
197
|
+
*/
|
|
198
|
+
createMessage(resource, operation, data, id, beforeData = null) {
|
|
199
|
+
const baseMessage = {
|
|
200
|
+
resource: resource, // padronizado para 'resource'
|
|
201
|
+
action: operation,
|
|
202
|
+
timestamp: new Date().toISOString(),
|
|
203
|
+
source: 's3db-replicator'
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
switch (operation) {
|
|
207
|
+
case 'insert':
|
|
208
|
+
return {
|
|
209
|
+
...baseMessage,
|
|
210
|
+
data: data
|
|
211
|
+
};
|
|
212
|
+
case 'update':
|
|
213
|
+
return {
|
|
214
|
+
...baseMessage,
|
|
215
|
+
before: beforeData,
|
|
216
|
+
data: data
|
|
217
|
+
};
|
|
218
|
+
case 'delete':
|
|
219
|
+
return {
|
|
220
|
+
...baseMessage,
|
|
221
|
+
data: data
|
|
222
|
+
};
|
|
223
|
+
default:
|
|
224
|
+
return {
|
|
225
|
+
...baseMessage,
|
|
226
|
+
data: data
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async initialize(database, client) {
|
|
232
|
+
await super.initialize(database);
|
|
233
|
+
if (!this.sqsClient) {
|
|
234
|
+
const [ok, err, sdk] = await tryFn(() => import('@aws-sdk/client-sqs'));
|
|
235
|
+
if (!ok) {
|
|
236
|
+
this.emit('initialization_error', {
|
|
237
|
+
replicator: this.name,
|
|
238
|
+
error: err.message
|
|
239
|
+
});
|
|
240
|
+
throw err;
|
|
241
|
+
}
|
|
242
|
+
const { SQSClient } = sdk;
|
|
243
|
+
this.sqsClient = client || new SQSClient({
|
|
244
|
+
region: this.region,
|
|
245
|
+
credentials: this.config.credentials
|
|
246
|
+
});
|
|
247
|
+
this.emit('initialized', {
|
|
248
|
+
replicator: this.name,
|
|
249
|
+
queueUrl: this.queueUrl,
|
|
250
|
+
queues: this.queues,
|
|
251
|
+
defaultQueue: this.defaultQueue
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async replicate(resource, operation, data, id, beforeData = null) {
|
|
257
|
+
if (!this.enabled || !this.shouldReplicateResource(resource)) {
|
|
258
|
+
return { skipped: true, reason: 'resource_not_included' };
|
|
259
|
+
}
|
|
260
|
+
const [ok, err, result] = await tryFn(async () => {
|
|
261
|
+
const { SendMessageCommand } = await import('@aws-sdk/client-sqs');
|
|
262
|
+
const queueUrls = this.getQueueUrlsForResource(resource);
|
|
263
|
+
// Apply transformation before creating message
|
|
264
|
+
const transformedData = this._applyTransformer(resource, data);
|
|
265
|
+
const message = this.createMessage(resource, operation, transformedData, id, beforeData);
|
|
266
|
+
const results = [];
|
|
267
|
+
for (const queueUrl of queueUrls) {
|
|
268
|
+
const command = new SendMessageCommand({
|
|
269
|
+
QueueUrl: queueUrl,
|
|
270
|
+
MessageBody: JSON.stringify(message),
|
|
271
|
+
MessageGroupId: this.messageGroupId,
|
|
272
|
+
MessageDeduplicationId: this.deduplicationId ? `${resource}:${operation}:${id}` : undefined
|
|
273
|
+
});
|
|
274
|
+
const result = await this.sqsClient.send(command);
|
|
275
|
+
results.push({ queueUrl, messageId: result.MessageId });
|
|
276
|
+
this.emit('replicated', {
|
|
277
|
+
replicator: this.name,
|
|
278
|
+
resource,
|
|
279
|
+
operation,
|
|
280
|
+
id,
|
|
281
|
+
queueUrl,
|
|
282
|
+
messageId: result.MessageId,
|
|
283
|
+
success: true
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
return { success: true, results };
|
|
287
|
+
});
|
|
288
|
+
if (ok) return result;
|
|
289
|
+
this.emit('replicator_error', {
|
|
290
|
+
replicator: this.name,
|
|
291
|
+
resource,
|
|
292
|
+
operation,
|
|
293
|
+
id,
|
|
294
|
+
error: err.message
|
|
295
|
+
});
|
|
296
|
+
return { success: false, error: err.message };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async replicateBatch(resource, records) {
|
|
300
|
+
if (!this.enabled || !this.shouldReplicateResource(resource)) {
|
|
301
|
+
return { skipped: true, reason: 'resource_not_included' };
|
|
302
|
+
}
|
|
303
|
+
const [ok, err, result] = await tryFn(async () => {
|
|
304
|
+
const { SendMessageBatchCommand } = await import('@aws-sdk/client-sqs');
|
|
305
|
+
const queueUrls = this.getQueueUrlsForResource(resource);
|
|
306
|
+
// SQS batch limit is 10 messages
|
|
307
|
+
const batchSize = 10;
|
|
308
|
+
const batches = [];
|
|
309
|
+
for (let i = 0; i < records.length; i += batchSize) {
|
|
310
|
+
batches.push(records.slice(i, i + batchSize));
|
|
311
|
+
}
|
|
312
|
+
const results = [];
|
|
313
|
+
const errors = [];
|
|
314
|
+
for (const batch of batches) {
|
|
315
|
+
const [okBatch, errBatch] = await tryFn(async () => {
|
|
316
|
+
const entries = batch.map((record, index) => ({
|
|
317
|
+
Id: `${record.id}-${index}`,
|
|
318
|
+
MessageBody: JSON.stringify(this.createMessage(
|
|
319
|
+
resource,
|
|
320
|
+
record.operation,
|
|
321
|
+
record.data,
|
|
322
|
+
record.id,
|
|
323
|
+
record.beforeData
|
|
324
|
+
)),
|
|
325
|
+
MessageGroupId: this.messageGroupId,
|
|
326
|
+
MessageDeduplicationId: this.deduplicationId ?
|
|
327
|
+
`${resource}:${record.operation}:${record.id}` : undefined
|
|
328
|
+
}));
|
|
329
|
+
const command = new SendMessageBatchCommand({
|
|
330
|
+
QueueUrl: queueUrls[0], // Assuming all queueUrls in a batch are the same for batching
|
|
331
|
+
Entries: entries
|
|
332
|
+
});
|
|
333
|
+
const result = await this.sqsClient.send(command);
|
|
334
|
+
results.push(result);
|
|
335
|
+
});
|
|
336
|
+
if (!okBatch) {
|
|
337
|
+
errors.push({ batch: batch.length, error: errBatch.message });
|
|
338
|
+
// If this is a critical error (like connection failure), fail the entire operation
|
|
339
|
+
if (errBatch.message && (errBatch.message.includes('Batch error') || errBatch.message.includes('Connection') || errBatch.message.includes('Network'))) {
|
|
340
|
+
throw errBatch;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
this.emit('batch_replicated', {
|
|
345
|
+
replicator: this.name,
|
|
346
|
+
resource,
|
|
347
|
+
queueUrl: queueUrls[0], // Assuming all queueUrls in a batch are the same for batching
|
|
348
|
+
total: records.length,
|
|
349
|
+
successful: results.length,
|
|
350
|
+
errors: errors.length
|
|
351
|
+
});
|
|
352
|
+
return {
|
|
353
|
+
success: errors.length === 0,
|
|
354
|
+
results,
|
|
355
|
+
errors,
|
|
356
|
+
total: records.length,
|
|
357
|
+
queueUrl: queueUrls[0] // Assuming all queueUrls in a batch are the same for batching
|
|
358
|
+
};
|
|
359
|
+
});
|
|
360
|
+
if (ok) return result;
|
|
361
|
+
const errorMessage = err?.message || err || 'Unknown error';
|
|
362
|
+
this.emit('batch_replicator_error', {
|
|
363
|
+
replicator: this.name,
|
|
364
|
+
resource,
|
|
365
|
+
error: errorMessage
|
|
366
|
+
});
|
|
367
|
+
return { success: false, error: errorMessage };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async testConnection() {
|
|
371
|
+
const [ok, err] = await tryFn(async () => {
|
|
372
|
+
if (!this.sqsClient) {
|
|
373
|
+
await this.initialize(this.database);
|
|
374
|
+
}
|
|
375
|
+
// Try to get queue attributes to test connection
|
|
376
|
+
const { GetQueueAttributesCommand } = await import('@aws-sdk/client-sqs');
|
|
377
|
+
const command = new GetQueueAttributesCommand({
|
|
378
|
+
QueueUrl: this.queueUrl,
|
|
379
|
+
AttributeNames: ['QueueArn']
|
|
380
|
+
});
|
|
381
|
+
await this.sqsClient.send(command);
|
|
382
|
+
return true;
|
|
383
|
+
});
|
|
384
|
+
if (ok) return true;
|
|
385
|
+
this.emit('connection_error', {
|
|
386
|
+
replicator: this.name,
|
|
387
|
+
error: err.message
|
|
388
|
+
});
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async getStatus() {
|
|
393
|
+
const baseStatus = await super.getStatus();
|
|
394
|
+
return {
|
|
395
|
+
...baseStatus,
|
|
396
|
+
connected: !!this.sqsClient,
|
|
397
|
+
queueUrl: this.queueUrl,
|
|
398
|
+
region: this.region,
|
|
399
|
+
resources: this.resources,
|
|
400
|
+
totalreplicators: this.listenerCount('replicated'),
|
|
401
|
+
totalErrors: this.listenerCount('replicator_error')
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async cleanup() {
|
|
406
|
+
if (this.sqsClient) {
|
|
407
|
+
this.sqsClient.destroy();
|
|
408
|
+
}
|
|
409
|
+
await super.cleanup();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
shouldReplicateResource(resource) {
|
|
413
|
+
// Return true if:
|
|
414
|
+
// 1. Resource has a specific queue mapping, OR
|
|
415
|
+
// 2. Resource has a queue in the queues object, OR
|
|
416
|
+
// 3. A default queue is configured (accepts all resources), OR
|
|
417
|
+
// 4. Resource is in the resources list (if provided)
|
|
418
|
+
const result = (this.resourceQueueMap && Object.keys(this.resourceQueueMap).includes(resource))
|
|
419
|
+
|| (this.queues && Object.keys(this.queues).includes(resource))
|
|
420
|
+
|| !!(this.defaultQueue || this.queueUrl) // Default queue accepts all resources
|
|
421
|
+
|| (this.resources && Object.keys(this.resources).includes(resource))
|
|
422
|
+
|| false;
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export default SqsReplicator;
|