s3db.js 11.3.2 → 12.0.1

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.
Files changed (83) hide show
  1. package/README.md +102 -8
  2. package/dist/s3db.cjs.js +36945 -15510
  3. package/dist/s3db.cjs.js.map +1 -1
  4. package/dist/s3db.d.ts +66 -1
  5. package/dist/s3db.es.js +36914 -15534
  6. package/dist/s3db.es.js.map +1 -1
  7. package/mcp/entrypoint.js +58 -0
  8. package/mcp/tools/documentation.js +434 -0
  9. package/mcp/tools/index.js +4 -0
  10. package/package.json +35 -15
  11. package/src/behaviors/user-managed.js +13 -6
  12. package/src/client.class.js +79 -49
  13. package/src/concerns/base62.js +85 -0
  14. package/src/concerns/dictionary-encoding.js +294 -0
  15. package/src/concerns/geo-encoding.js +256 -0
  16. package/src/concerns/high-performance-inserter.js +34 -30
  17. package/src/concerns/ip.js +325 -0
  18. package/src/concerns/metadata-encoding.js +345 -66
  19. package/src/concerns/money.js +193 -0
  20. package/src/concerns/partition-queue.js +7 -4
  21. package/src/concerns/plugin-storage.js +97 -47
  22. package/src/database.class.js +76 -74
  23. package/src/errors.js +0 -4
  24. package/src/plugins/api/auth/api-key-auth.js +88 -0
  25. package/src/plugins/api/auth/basic-auth.js +154 -0
  26. package/src/plugins/api/auth/index.js +112 -0
  27. package/src/plugins/api/auth/jwt-auth.js +169 -0
  28. package/src/plugins/api/index.js +544 -0
  29. package/src/plugins/api/middlewares/index.js +15 -0
  30. package/src/plugins/api/middlewares/validator.js +185 -0
  31. package/src/plugins/api/routes/auth-routes.js +241 -0
  32. package/src/plugins/api/routes/resource-routes.js +304 -0
  33. package/src/plugins/api/server.js +354 -0
  34. package/src/plugins/api/utils/error-handler.js +147 -0
  35. package/src/plugins/api/utils/openapi-generator.js +1240 -0
  36. package/src/plugins/api/utils/response-formatter.js +218 -0
  37. package/src/plugins/backup/streaming-exporter.js +132 -0
  38. package/src/plugins/backup.plugin.js +103 -50
  39. package/src/plugins/cache/s3-cache.class.js +95 -47
  40. package/src/plugins/cache.plugin.js +107 -9
  41. package/src/plugins/concerns/plugin-dependencies.js +313 -0
  42. package/src/plugins/concerns/prometheus-formatter.js +255 -0
  43. package/src/plugins/consumers/rabbitmq-consumer.js +4 -0
  44. package/src/plugins/consumers/sqs-consumer.js +4 -0
  45. package/src/plugins/costs.plugin.js +255 -39
  46. package/src/plugins/eventual-consistency/helpers.js +15 -1
  47. package/src/plugins/geo.plugin.js +873 -0
  48. package/src/plugins/importer/index.js +1020 -0
  49. package/src/plugins/index.js +11 -0
  50. package/src/plugins/metrics.plugin.js +163 -4
  51. package/src/plugins/queue-consumer.plugin.js +6 -27
  52. package/src/plugins/relation.errors.js +139 -0
  53. package/src/plugins/relation.plugin.js +1242 -0
  54. package/src/plugins/replicator.plugin.js +2 -1
  55. package/src/plugins/replicators/bigquery-replicator.class.js +180 -8
  56. package/src/plugins/replicators/dynamodb-replicator.class.js +383 -0
  57. package/src/plugins/replicators/index.js +28 -3
  58. package/src/plugins/replicators/mongodb-replicator.class.js +391 -0
  59. package/src/plugins/replicators/mysql-replicator.class.js +558 -0
  60. package/src/plugins/replicators/planetscale-replicator.class.js +409 -0
  61. package/src/plugins/replicators/postgres-replicator.class.js +182 -7
  62. package/src/plugins/replicators/s3db-replicator.class.js +1 -12
  63. package/src/plugins/replicators/schema-sync.helper.js +601 -0
  64. package/src/plugins/replicators/sqs-replicator.class.js +11 -9
  65. package/src/plugins/replicators/turso-replicator.class.js +416 -0
  66. package/src/plugins/replicators/webhook-replicator.class.js +612 -0
  67. package/src/plugins/state-machine.plugin.js +122 -68
  68. package/src/plugins/tfstate/README.md +745 -0
  69. package/src/plugins/tfstate/base-driver.js +80 -0
  70. package/src/plugins/tfstate/errors.js +112 -0
  71. package/src/plugins/tfstate/filesystem-driver.js +129 -0
  72. package/src/plugins/tfstate/index.js +2660 -0
  73. package/src/plugins/tfstate/s3-driver.js +192 -0
  74. package/src/plugins/ttl.plugin.js +536 -0
  75. package/src/resource.class.js +315 -36
  76. package/src/s3db.d.ts +66 -1
  77. package/src/schema.class.js +366 -32
  78. package/SECURITY.md +0 -76
  79. package/src/partition-drivers/base-partition-driver.js +0 -106
  80. package/src/partition-drivers/index.js +0 -66
  81. package/src/partition-drivers/memory-partition-driver.js +0 -289
  82. package/src/partition-drivers/sqs-partition-driver.js +0 -337
  83. package/src/partition-drivers/sync-partition-driver.js +0 -38
@@ -1,66 +0,0 @@
1
- import { SyncPartitionDriver } from './sync-partition-driver.js';
2
- import { MemoryPartitionDriver } from './memory-partition-driver.js';
3
- import { SQSPartitionDriver } from './sqs-partition-driver.js';
4
- import { PartitionDriverError } from '../errors.js';
5
-
6
- /**
7
- * Partition driver factory
8
- */
9
- export class PartitionDriverFactory {
10
- static drivers = {
11
- sync: SyncPartitionDriver,
12
- memory: MemoryPartitionDriver,
13
- sqs: SQSPartitionDriver
14
- };
15
-
16
- /**
17
- * Create a partition driver instance
18
- * @param {string|Object} config - Driver name or configuration object
19
- * @returns {BasePartitionDriver} Driver instance
20
- */
21
- static create(config) {
22
- // Handle string shorthand
23
- if (typeof config === 'string') {
24
- config = { driver: config };
25
- }
26
-
27
- // Default to memory driver
28
- const driverName = config.driver || 'memory';
29
-
30
- // Get driver class
31
- const DriverClass = this.drivers[driverName];
32
- if (!DriverClass) {
33
- throw new PartitionDriverError(`Unknown partition driver: ${driverName}`, {
34
- driver: driverName,
35
- operation: 'create',
36
- availableDrivers: Object.keys(this.drivers),
37
- suggestion: `Use one of the available drivers: ${Object.keys(this.drivers).join(', ')}, or register a custom driver`
38
- });
39
- }
40
-
41
- // Create and initialize driver
42
- const driver = new DriverClass(config);
43
-
44
- return driver;
45
- }
46
-
47
- /**
48
- * Register a custom driver
49
- */
50
- static register(name, DriverClass) {
51
- this.drivers[name] = DriverClass;
52
- }
53
-
54
- /**
55
- * Get available driver names
56
- */
57
- static getAvailableDrivers() {
58
- return Object.keys(this.drivers);
59
- }
60
- }
61
-
62
- // Export individual drivers
63
- export { BasePartitionDriver } from './base-partition-driver.js';
64
- export { SyncPartitionDriver } from './sync-partition-driver.js';
65
- export { MemoryPartitionDriver } from './memory-partition-driver.js';
66
- export { SQSPartitionDriver } from './sqs-partition-driver.js';
@@ -1,289 +0,0 @@
1
- import { BasePartitionDriver } from './base-partition-driver.js';
2
- import { PromisePool } from '@supercharge/promise-pool';
3
- import { PartitionDriverError } from '../errors.js';
4
-
5
- /**
6
- * In-memory partition driver with background processing
7
- * Queues operations in memory and processes them asynchronously
8
- * Fast and efficient for single-instance applications
9
- */
10
- export class MemoryPartitionDriver extends BasePartitionDriver {
11
- constructor(options = {}) {
12
- super(options);
13
- this.name = 'memory';
14
-
15
- // Configuration
16
- this.batchSize = options.batchSize || 100;
17
- this.concurrency = options.concurrency || 10;
18
- this.flushInterval = options.flushInterval || 1000;
19
- this.maxQueueSize = options.maxQueueSize || 10000;
20
- this.maxRetries = options.maxRetries || 3;
21
-
22
- // State
23
- this.queue = [];
24
- this.isProcessing = false;
25
- this.flushTimer = null;
26
- this.retryQueue = [];
27
- }
28
-
29
- async initialize() {
30
- // Start background processor
31
- this.startProcessor();
32
- }
33
-
34
- /**
35
- * Add operation to in-memory queue
36
- */
37
- async queue(operation) {
38
- // Check queue size limit
39
- if (this.queue.length >= this.maxQueueSize) {
40
- const error = new PartitionDriverError('Memory queue full - backpressure detected', {
41
- driver: 'memory',
42
- operation: 'queue',
43
- queueSize: this.queue.length,
44
- maxQueueSize: this.maxQueueSize,
45
- suggestion: 'Increase maxQueueSize, enable rejectOnFull, or reduce operation rate'
46
- });
47
- this.emit('queueFull', { operation, queueSize: this.queue.length });
48
-
49
- if (this.options.rejectOnFull) {
50
- throw error;
51
- }
52
-
53
- // Wait for some space
54
- await this.waitForSpace();
55
- }
56
-
57
- // Add to queue with metadata
58
- const queueItem = {
59
- ...operation,
60
- id: `${Date.now()}-${Math.random()}`,
61
- queuedAt: new Date(),
62
- attempts: 0
63
- };
64
-
65
- this.queue.push(queueItem);
66
- this.stats.queued++;
67
-
68
- // Auto-flush when batch size reached
69
- if (this.queue.length >= this.batchSize) {
70
- this.triggerFlush();
71
- }
72
-
73
- return {
74
- success: true,
75
- driver: 'memory',
76
- queuePosition: this.queue.length,
77
- queueId: queueItem.id
78
- };
79
- }
80
-
81
- /**
82
- * Start the background processor
83
- */
84
- startProcessor() {
85
- // Set up periodic flush
86
- if (this.flushInterval > 0) {
87
- this.flushTimer = setInterval(() => {
88
- if (this.queue.length > 0 && !this.isProcessing) {
89
- this.processQueue();
90
- }
91
- }, this.flushInterval);
92
- }
93
- }
94
-
95
- /**
96
- * Trigger immediate flush
97
- */
98
- triggerFlush() {
99
- if (!this.isProcessing) {
100
- setImmediate(() => this.processQueue());
101
- }
102
- }
103
-
104
- /**
105
- * Process queued operations in batches
106
- */
107
- async processQueue() {
108
- if (this.isProcessing || this.queue.length === 0) return;
109
-
110
- this.isProcessing = true;
111
-
112
- try {
113
- // Take a batch from the queue
114
- const batch = this.queue.splice(0, this.batchSize);
115
-
116
- // Process in parallel with concurrency control
117
- const { results, errors } = await PromisePool
118
- .for(batch)
119
- .withConcurrency(this.concurrency)
120
- .process(async (item) => {
121
- try {
122
- await this.processOperation(item);
123
- return { success: true, item };
124
- } catch (error) {
125
- return this.handleError(item, error);
126
- }
127
- });
128
-
129
- // Handle successful results
130
- const successful = results.filter(r => r.success);
131
- this.emit('batchProcessed', {
132
- processed: successful.length,
133
- failed: errors.length,
134
- retried: results.filter(r => r.retried).length
135
- });
136
-
137
- } finally {
138
- this.isProcessing = false;
139
-
140
- // Continue processing if more items
141
- if (this.queue.length > 0) {
142
- setImmediate(() => this.processQueue());
143
- }
144
-
145
- // Process retry queue if needed
146
- if (this.retryQueue.length > 0) {
147
- this.processRetryQueue();
148
- }
149
- }
150
- }
151
-
152
- /**
153
- * Handle processing errors with retry logic
154
- */
155
- handleError(item, error) {
156
- item.attempts++;
157
- item.lastError = error;
158
-
159
- if (item.attempts < this.maxRetries) {
160
- // Add to retry queue with exponential backoff
161
- const delay = Math.min(1000 * Math.pow(2, item.attempts - 1), 30000);
162
-
163
- setTimeout(() => {
164
- this.retryQueue.push(item);
165
- if (!this.isProcessing) {
166
- this.processRetryQueue();
167
- }
168
- }, delay);
169
-
170
- this.emit('retry', { item, error, attempt: item.attempts, delay });
171
- return { success: false, retried: true, item };
172
- } else {
173
- // Max retries exceeded
174
- this.emit('failed', { item, error, attempts: item.attempts });
175
- return { success: false, retried: false, item };
176
- }
177
- }
178
-
179
- /**
180
- * Process retry queue
181
- */
182
- async processRetryQueue() {
183
- if (this.retryQueue.length === 0) return;
184
-
185
- // Move retry items back to main queue
186
- const retryItems = this.retryQueue.splice(0, this.batchSize);
187
- this.queue.unshift(...retryItems);
188
-
189
- // Trigger processing
190
- this.triggerFlush();
191
- }
192
-
193
- /**
194
- * Wait for queue space
195
- */
196
- async waitForSpace() {
197
- const checkInterval = 100;
198
- const maxWait = 30000;
199
- const startTime = Date.now();
200
-
201
- while (this.queue.length >= this.maxQueueSize) {
202
- if (Date.now() - startTime > maxWait) {
203
- throw new PartitionDriverError('Timeout waiting for queue space', {
204
- driver: 'memory',
205
- operation: 'waitForSpace',
206
- queueSize: this.queue.length,
207
- maxQueueSize: this.maxQueueSize,
208
- waitedMs: Date.now() - startTime,
209
- maxWaitMs: maxWait,
210
- suggestion: 'Queue is full and not draining fast enough. Increase maxQueueSize or concurrency'
211
- });
212
- }
213
-
214
- await new Promise(resolve => setTimeout(resolve, checkInterval));
215
- }
216
- }
217
-
218
- /**
219
- * Force flush all pending operations
220
- */
221
- async flush() {
222
- // Process all remaining items
223
- while (this.queue.length > 0 || this.retryQueue.length > 0 || this.isProcessing) {
224
- await this.processQueue();
225
- await new Promise(resolve => setTimeout(resolve, 10));
226
- }
227
- }
228
-
229
- /**
230
- * Get detailed statistics
231
- */
232
- getStats() {
233
- return {
234
- ...super.getStats(),
235
- queueLength: this.queue.length,
236
- retryQueueLength: this.retryQueue.length,
237
- isProcessing: this.isProcessing,
238
- memoryUsage: this.estimateMemoryUsage()
239
- };
240
- }
241
-
242
- /**
243
- * Estimate memory usage of the queue
244
- */
245
- estimateMemoryUsage() {
246
- // Rough estimate: 1KB per queue item
247
- const bytes = (this.queue.length + this.retryQueue.length) * 1024;
248
- return {
249
- bytes,
250
- mb: (bytes / 1024 / 1024).toFixed(2)
251
- };
252
- }
253
-
254
- /**
255
- * Shutdown the driver
256
- */
257
- async shutdown() {
258
- // Stop the flush timer
259
- if (this.flushTimer) {
260
- clearInterval(this.flushTimer);
261
- this.flushTimer = null;
262
- }
263
-
264
- // Flush remaining items
265
- await this.flush();
266
-
267
- // Clear queues
268
- this.queue = [];
269
- this.retryQueue = [];
270
-
271
- await super.shutdown();
272
- }
273
-
274
- getInfo() {
275
- return {
276
- name: this.name,
277
- mode: 'asynchronous',
278
- description: 'In-memory queue with background processing',
279
- config: {
280
- batchSize: this.batchSize,
281
- concurrency: this.concurrency,
282
- flushInterval: this.flushInterval,
283
- maxQueueSize: this.maxQueueSize,
284
- maxRetries: this.maxRetries
285
- },
286
- stats: this.getStats()
287
- };
288
- }
289
- }
@@ -1,337 +0,0 @@
1
- import { BasePartitionDriver } from './base-partition-driver.js';
2
- import { SQSClient, SendMessageCommand, ReceiveMessageCommand, DeleteMessageCommand } from '@aws-sdk/client-sqs';
3
- import { PartitionDriverError } from '../errors.js';
4
-
5
- /**
6
- * SQS-based partition driver for distributed processing
7
- * Sends partition operations to SQS for processing by workers
8
- * Ideal for high-volume, distributed systems
9
- */
10
- export class SQSPartitionDriver extends BasePartitionDriver {
11
- constructor(options = {}) {
12
- super(options);
13
- this.name = 'sqs';
14
-
15
- // SQS Configuration
16
- this.queueUrl = options.queueUrl;
17
- if (!this.queueUrl) {
18
- throw new PartitionDriverError('SQS queue URL is required', {
19
- driver: 'sqs',
20
- operation: 'constructor',
21
- suggestion: 'Provide queueUrl in options: new SQSPartitionDriver({ queueUrl: "https://sqs.region.amazonaws.com/account/queue" })'
22
- });
23
- }
24
-
25
- this.region = options.region || 'us-east-1';
26
- this.credentials = options.credentials;
27
- this.dlqUrl = options.dlqUrl; // Dead Letter Queue
28
- this.messageGroupId = options.messageGroupId || 's3db-partitions';
29
- this.visibilityTimeout = options.visibilityTimeout || 300; // 5 minutes
30
- this.batchSize = options.batchSize || 10; // SQS max batch size
31
-
32
- // Worker configuration
33
- this.isWorker = options.isWorker || false;
34
- this.workerConcurrency = options.workerConcurrency || 5;
35
- this.pollInterval = options.pollInterval || 1000;
36
-
37
- // Initialize SQS client
38
- this.sqsClient = new SQSClient({
39
- region: this.region,
40
- credentials: this.credentials
41
- });
42
-
43
- this.workerRunning = false;
44
- this.messageBuffer = [];
45
- }
46
-
47
- async initialize() {
48
- // Start worker if configured
49
- if (this.isWorker) {
50
- await this.startWorker();
51
- }
52
- }
53
-
54
- /**
55
- * Send partition operation to SQS
56
- */
57
- async queue(operation) {
58
- try {
59
- // Prepare message
60
- const message = {
61
- id: `${Date.now()}-${Math.random()}`,
62
- timestamp: new Date().toISOString(),
63
- operation: {
64
- type: operation.type,
65
- resourceName: operation.resource.name,
66
- data: this.serializeData(operation.data)
67
- }
68
- };
69
-
70
- // Buffer messages for batch sending
71
- this.messageBuffer.push(message);
72
- this.stats.queued++;
73
-
74
- // Send batch when buffer is full
75
- if (this.messageBuffer.length >= this.batchSize) {
76
- await this.flushMessages();
77
- } else {
78
- // Schedule flush if not already scheduled
79
- if (!this.flushTimeout) {
80
- this.flushTimeout = setTimeout(() => this.flushMessages(), 100);
81
- }
82
- }
83
-
84
- return {
85
- success: true,
86
- driver: 'sqs',
87
- messageId: message.id,
88
- queueUrl: this.queueUrl
89
- };
90
-
91
- } catch (error) {
92
- this.emit('error', { operation, error });
93
- throw error;
94
- }
95
- }
96
-
97
- /**
98
- * Flush buffered messages to SQS
99
- */
100
- async flushMessages() {
101
- if (this.messageBuffer.length === 0) return;
102
-
103
- clearTimeout(this.flushTimeout);
104
- this.flushTimeout = null;
105
-
106
- const messages = this.messageBuffer.splice(0, this.batchSize);
107
-
108
- try {
109
- // For FIFO queues, add deduplication ID
110
- const isFifo = this.queueUrl.includes('.fifo');
111
-
112
- for (const message of messages) {
113
- const params = {
114
- QueueUrl: this.queueUrl,
115
- MessageBody: JSON.stringify(message),
116
- MessageAttributes: {
117
- Type: {
118
- DataType: 'String',
119
- StringValue: message.operation.type
120
- },
121
- Resource: {
122
- DataType: 'String',
123
- StringValue: message.operation.resourceName
124
- }
125
- }
126
- };
127
-
128
- if (isFifo) {
129
- params.MessageGroupId = this.messageGroupId;
130
- params.MessageDeduplicationId = message.id;
131
- }
132
-
133
- await this.sqsClient.send(new SendMessageCommand(params));
134
- }
135
-
136
- this.emit('messagesSent', { count: messages.length });
137
-
138
- } catch (error) {
139
- // Return messages to buffer for retry
140
- this.messageBuffer.unshift(...messages);
141
- this.emit('sendError', { error, messages: messages.length });
142
- throw error;
143
- }
144
- }
145
-
146
- /**
147
- * Start SQS worker to process messages
148
- */
149
- async startWorker() {
150
- if (this.workerRunning) return;
151
-
152
- this.workerRunning = true;
153
- this.emit('workerStarted', { concurrency: this.workerConcurrency });
154
-
155
- // Start multiple concurrent workers
156
- for (let i = 0; i < this.workerConcurrency; i++) {
157
- this.pollMessages(i);
158
- }
159
- }
160
-
161
- /**
162
- * Poll SQS for messages
163
- */
164
- async pollMessages(workerId) {
165
- while (this.workerRunning) {
166
- try {
167
- // Receive messages from SQS
168
- const params = {
169
- QueueUrl: this.queueUrl,
170
- MaxNumberOfMessages: 10,
171
- WaitTimeSeconds: 20, // Long polling
172
- VisibilityTimeout: this.visibilityTimeout,
173
- MessageAttributeNames: ['All']
174
- };
175
-
176
- const response = await this.sqsClient.send(new ReceiveMessageCommand(params));
177
-
178
- if (response.Messages && response.Messages.length > 0) {
179
- // Process messages
180
- for (const message of response.Messages) {
181
- await this.processMessage(message, workerId);
182
- }
183
- }
184
-
185
- } catch (error) {
186
- this.emit('pollError', { workerId, error });
187
- // Wait before retrying
188
- await new Promise(resolve => setTimeout(resolve, this.pollInterval));
189
- }
190
- }
191
- }
192
-
193
- /**
194
- * Process a single SQS message
195
- */
196
- async processMessage(message, workerId) {
197
- try {
198
- // Parse message body
199
- const data = JSON.parse(message.Body);
200
- const operation = {
201
- type: data.operation.type,
202
- data: this.deserializeData(data.operation.data)
203
- };
204
-
205
- // Process the partition operation
206
- // Note: We need the actual resource instance to process
207
- // This would typically be handled by a separate worker service
208
- this.emit('processingMessage', { workerId, messageId: message.MessageId });
209
-
210
- // In a real implementation, you'd look up the resource and process:
211
- // await this.processOperation(operation);
212
-
213
- // Delete message from queue after successful processing
214
- await this.sqsClient.send(new DeleteMessageCommand({
215
- QueueUrl: this.queueUrl,
216
- ReceiptHandle: message.ReceiptHandle
217
- }));
218
-
219
- this.stats.processed++;
220
- this.emit('messageProcessed', { workerId, messageId: message.MessageId });
221
-
222
- } catch (error) {
223
- this.stats.failed++;
224
- this.emit('processError', { workerId, error, messageId: message.MessageId });
225
-
226
- // Message will become visible again after VisibilityTimeout
227
- // and eventually move to DLQ if configured
228
- }
229
- }
230
-
231
- /**
232
- * Serialize data for SQS transport
233
- */
234
- serializeData(data) {
235
- // Remove circular references and functions
236
- return JSON.parse(JSON.stringify(data, (key, value) => {
237
- if (typeof value === 'function') return undefined;
238
- if (value instanceof Buffer) return value.toString('base64');
239
- return value;
240
- }));
241
- }
242
-
243
- /**
244
- * Deserialize data from SQS
245
- */
246
- deserializeData(data) {
247
- return data;
248
- }
249
-
250
- /**
251
- * Stop the worker
252
- */
253
- async stopWorker() {
254
- this.workerRunning = false;
255
- this.emit('workerStopped');
256
- }
257
-
258
- /**
259
- * Force flush all pending messages
260
- */
261
- async flush() {
262
- await this.flushMessages();
263
- }
264
-
265
- /**
266
- * Get queue metrics from SQS
267
- */
268
- async getQueueMetrics() {
269
- try {
270
- const { Attributes } = await this.sqsClient.send(new GetQueueAttributesCommand({
271
- QueueUrl: this.queueUrl,
272
- AttributeNames: [
273
- 'ApproximateNumberOfMessages',
274
- 'ApproximateNumberOfMessagesNotVisible',
275
- 'ApproximateNumberOfMessagesDelayed'
276
- ]
277
- }));
278
-
279
- return {
280
- messagesAvailable: parseInt(Attributes.ApproximateNumberOfMessages || 0),
281
- messagesInFlight: parseInt(Attributes.ApproximateNumberOfMessagesNotVisible || 0),
282
- messagesDelayed: parseInt(Attributes.ApproximateNumberOfMessagesDelayed || 0)
283
- };
284
- } catch (error) {
285
- return null;
286
- }
287
- }
288
-
289
- /**
290
- * Get detailed statistics
291
- */
292
- async getStats() {
293
- const baseStats = super.getStats();
294
- const queueMetrics = await this.getQueueMetrics();
295
-
296
- return {
297
- ...baseStats,
298
- bufferLength: this.messageBuffer.length,
299
- isWorker: this.isWorker,
300
- workerRunning: this.workerRunning,
301
- queue: queueMetrics
302
- };
303
- }
304
-
305
- /**
306
- * Shutdown the driver
307
- */
308
- async shutdown() {
309
- // Stop worker if running
310
- await this.stopWorker();
311
-
312
- // Flush remaining messages
313
- await this.flush();
314
-
315
- // Clear buffer
316
- this.messageBuffer = [];
317
-
318
- await super.shutdown();
319
- }
320
-
321
- getInfo() {
322
- return {
323
- name: this.name,
324
- mode: 'distributed',
325
- description: 'SQS-based queue for distributed partition processing',
326
- config: {
327
- queueUrl: this.queueUrl,
328
- region: this.region,
329
- dlqUrl: this.dlqUrl,
330
- isWorker: this.isWorker,
331
- workerConcurrency: this.workerConcurrency,
332
- visibilityTimeout: this.visibilityTimeout
333
- },
334
- stats: this.getStats()
335
- };
336
- }
337
- }