@stacksjs/ts-cloud-core 0.1.7 → 0.1.9
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/package.json +7 -6
- package/src/advanced-features.test.ts +465 -0
- package/src/aws/cloudformation.ts +421 -0
- package/src/aws/cloudfront.ts +158 -0
- package/src/aws/credentials.test.ts +132 -0
- package/src/aws/credentials.ts +545 -0
- package/src/aws/index.ts +87 -0
- package/src/aws/s3.test.ts +188 -0
- package/src/aws/s3.ts +1088 -0
- package/src/aws/signature.test.ts +670 -0
- package/src/aws/signature.ts +1155 -0
- package/src/backup/disaster-recovery.test.ts +726 -0
- package/src/backup/disaster-recovery.ts +500 -0
- package/src/backup/index.ts +34 -0
- package/src/backup/manager.test.ts +498 -0
- package/src/backup/manager.ts +432 -0
- package/src/cicd/circleci.ts +430 -0
- package/src/cicd/github-actions.ts +424 -0
- package/src/cicd/gitlab-ci.ts +255 -0
- package/src/cicd/index.ts +8 -0
- package/src/cli/history.ts +396 -0
- package/src/cli/index.ts +10 -0
- package/src/cli/progress.ts +458 -0
- package/src/cli/repl.ts +454 -0
- package/src/cli/suggestions.ts +327 -0
- package/src/cli/table.test.ts +319 -0
- package/src/cli/table.ts +332 -0
- package/src/cloudformation/builder.test.ts +327 -0
- package/src/cloudformation/builder.ts +378 -0
- package/src/cloudformation/builders/api-gateway.ts +449 -0
- package/src/cloudformation/builders/cache.ts +334 -0
- package/src/cloudformation/builders/cdn.ts +278 -0
- package/src/cloudformation/builders/compute.ts +485 -0
- package/src/cloudformation/builders/database.ts +392 -0
- package/src/cloudformation/builders/functions.ts +343 -0
- package/src/cloudformation/builders/messaging.ts +140 -0
- package/src/cloudformation/builders/monitoring.ts +300 -0
- package/src/cloudformation/builders/network.ts +264 -0
- package/src/cloudformation/builders/queue.ts +147 -0
- package/src/cloudformation/builders/security.ts +399 -0
- package/src/cloudformation/builders/storage.ts +285 -0
- package/src/cloudformation/index.ts +30 -0
- package/src/cloudformation/types.ts +173 -0
- package/src/compliance/aws-config.ts +543 -0
- package/src/compliance/cloudtrail.ts +376 -0
- package/src/compliance/compliance.test.ts +423 -0
- package/src/compliance/guardduty.ts +446 -0
- package/src/compliance/index.ts +66 -0
- package/src/compliance/security-hub.ts +456 -0
- package/src/containers/build-optimization.ts +416 -0
- package/src/containers/containers.test.ts +508 -0
- package/src/containers/image-scanning.ts +360 -0
- package/src/containers/index.ts +9 -0
- package/src/containers/registry.ts +293 -0
- package/src/containers/service-mesh.ts +520 -0
- package/src/database/database.test.ts +762 -0
- package/src/database/index.ts +9 -0
- package/src/database/migrations.ts +444 -0
- package/src/database/performance.ts +528 -0
- package/src/database/replicas.ts +534 -0
- package/src/database/users.ts +494 -0
- package/src/dependency-graph.ts +143 -0
- package/src/deployment/ab-testing.ts +582 -0
- package/src/deployment/blue-green.ts +452 -0
- package/src/deployment/canary.ts +500 -0
- package/src/deployment/deployment.test.ts +526 -0
- package/src/deployment/index.ts +61 -0
- package/src/deployment/progressive.ts +62 -0
- package/src/dns/dns.test.ts +641 -0
- package/src/dns/dnssec.ts +315 -0
- package/src/dns/index.ts +8 -0
- package/src/dns/resolver.ts +496 -0
- package/src/dns/routing.ts +593 -0
- package/src/email/advanced/analytics.ts +445 -0
- package/src/email/advanced/index.ts +11 -0
- package/src/email/advanced/rules.ts +465 -0
- package/src/email/advanced/scheduling.ts +352 -0
- package/src/email/advanced/search.ts +412 -0
- package/src/email/advanced/shared-mailboxes.ts +404 -0
- package/src/email/advanced/templates.ts +455 -0
- package/src/email/advanced/threading.ts +281 -0
- package/src/email/analytics.ts +467 -0
- package/src/email/bounce-handling.ts +425 -0
- package/src/email/email.test.ts +431 -0
- package/src/email/handlers/__tests__/inbound.test.ts +38 -0
- package/src/email/handlers/__tests__/outbound.test.ts +37 -0
- package/src/email/handlers/converter.ts +227 -0
- package/src/email/handlers/feedback.ts +228 -0
- package/src/email/handlers/inbound.ts +169 -0
- package/src/email/handlers/outbound.ts +178 -0
- package/src/email/index.ts +15 -0
- package/src/email/reputation.ts +303 -0
- package/src/email/templates.ts +352 -0
- package/src/errors/index.test.ts +434 -0
- package/src/errors/index.ts +416 -0
- package/src/health-checks/index.ts +40 -0
- package/src/index.ts +360 -0
- package/src/intrinsic-functions.ts +118 -0
- package/src/lambda/concurrency.ts +330 -0
- package/src/lambda/destinations.ts +345 -0
- package/src/lambda/dlq.ts +425 -0
- package/src/lambda/index.ts +11 -0
- package/src/lambda/lambda.test.ts +840 -0
- package/src/lambda/layers.ts +263 -0
- package/src/lambda/versions.ts +376 -0
- package/src/lambda/vpc.ts +399 -0
- package/src/local/config.ts +114 -0
- package/src/local/index.ts +6 -0
- package/src/local/mock-aws.ts +351 -0
- package/src/modules/ai.ts +340 -0
- package/src/modules/api.ts +478 -0
- package/src/modules/auth.ts +805 -0
- package/src/modules/cache.ts +417 -0
- package/src/modules/cdn.ts +1062 -0
- package/src/modules/communication.ts +1094 -0
- package/src/modules/compute.ts +3348 -0
- package/src/modules/database.ts +554 -0
- package/src/modules/deployment.ts +1079 -0
- package/src/modules/dns.ts +337 -0
- package/src/modules/email.ts +1538 -0
- package/src/modules/filesystem.ts +515 -0
- package/src/modules/index.ts +32 -0
- package/src/modules/messaging.ts +486 -0
- package/src/modules/monitoring.ts +2086 -0
- package/src/modules/network.ts +664 -0
- package/src/modules/parameter-store.ts +325 -0
- package/src/modules/permissions.ts +1081 -0
- package/src/modules/phone.ts +494 -0
- package/src/modules/queue.ts +1260 -0
- package/src/modules/redirects.ts +464 -0
- package/src/modules/registry.ts +699 -0
- package/src/modules/search.ts +401 -0
- package/src/modules/secrets.ts +416 -0
- package/src/modules/security.ts +731 -0
- package/src/modules/sms.ts +389 -0
- package/src/modules/storage.ts +1120 -0
- package/src/modules/workflow.ts +680 -0
- package/src/multi-account/config.ts +521 -0
- package/src/multi-account/index.ts +7 -0
- package/src/multi-account/manager.ts +427 -0
- package/src/multi-region/cross-region.ts +410 -0
- package/src/multi-region/index.ts +8 -0
- package/src/multi-region/manager.ts +483 -0
- package/src/multi-region/regions.ts +435 -0
- package/src/network-security/index.ts +48 -0
- package/src/observability/index.ts +9 -0
- package/src/observability/logs.ts +522 -0
- package/src/observability/metrics.ts +460 -0
- package/src/observability/observability.test.ts +782 -0
- package/src/observability/synthetics.ts +568 -0
- package/src/observability/xray.ts +358 -0
- package/src/phone/advanced/analytics.ts +349 -0
- package/src/phone/advanced/callbacks.ts +428 -0
- package/src/phone/advanced/index.ts +8 -0
- package/src/phone/advanced/ivr-builder.ts +504 -0
- package/src/phone/advanced/recording.ts +310 -0
- package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
- package/src/phone/handlers/incoming-call.ts +117 -0
- package/src/phone/handlers/missed-call.ts +116 -0
- package/src/phone/handlers/voicemail.ts +179 -0
- package/src/phone/index.ts +9 -0
- package/src/presets/api-backend.ts +134 -0
- package/src/presets/data-pipeline.ts +204 -0
- package/src/presets/extend.test.ts +295 -0
- package/src/presets/extend.ts +297 -0
- package/src/presets/fullstack-app.ts +144 -0
- package/src/presets/index.ts +27 -0
- package/src/presets/jamstack.ts +135 -0
- package/src/presets/microservices.ts +167 -0
- package/src/presets/ml-api.ts +208 -0
- package/src/presets/nodejs-server.ts +104 -0
- package/src/presets/nodejs-serverless.ts +114 -0
- package/src/presets/realtime-app.ts +184 -0
- package/src/presets/static-site.ts +64 -0
- package/src/presets/traditional-web-app.ts +339 -0
- package/src/presets/wordpress.ts +138 -0
- package/src/preview/github.test.ts +249 -0
- package/src/preview/github.ts +297 -0
- package/src/preview/index.ts +37 -0
- package/src/preview/manager.test.ts +440 -0
- package/src/preview/manager.ts +326 -0
- package/src/preview/notifications.test.ts +582 -0
- package/src/preview/notifications.ts +341 -0
- package/src/queue/batch-processing.ts +402 -0
- package/src/queue/dlq-monitoring.ts +402 -0
- package/src/queue/fifo.ts +342 -0
- package/src/queue/index.ts +9 -0
- package/src/queue/management.ts +428 -0
- package/src/queue/queue.test.ts +429 -0
- package/src/resource-mgmt/index.ts +39 -0
- package/src/resource-naming.ts +62 -0
- package/src/s3/index.ts +523 -0
- package/src/schema/cloud-config.schema.json +554 -0
- package/src/schema/index.ts +68 -0
- package/src/security/certificate-manager.ts +492 -0
- package/src/security/index.ts +9 -0
- package/src/security/scanning.ts +545 -0
- package/src/security/secrets-manager.ts +476 -0
- package/src/security/secrets-rotation.ts +456 -0
- package/src/security/security.test.ts +738 -0
- package/src/sms/advanced/ab-testing.ts +389 -0
- package/src/sms/advanced/analytics.ts +336 -0
- package/src/sms/advanced/campaigns.ts +523 -0
- package/src/sms/advanced/chatbot.ts +224 -0
- package/src/sms/advanced/index.ts +10 -0
- package/src/sms/advanced/link-tracking.ts +248 -0
- package/src/sms/advanced/mms.ts +308 -0
- package/src/sms/handlers/__tests__/send.test.ts +40 -0
- package/src/sms/handlers/delivery-status.ts +133 -0
- package/src/sms/handlers/receive.ts +162 -0
- package/src/sms/handlers/send.ts +174 -0
- package/src/sms/index.ts +9 -0
- package/src/stack-diff.ts +389 -0
- package/src/static-site/index.ts +85 -0
- package/src/template-builder.ts +110 -0
- package/src/template-validator.ts +574 -0
- package/src/utils/cache.ts +291 -0
- package/src/utils/diff.ts +269 -0
- package/src/utils/hash.ts +227 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parallel.ts +294 -0
- package/src/validators/credentials.test.ts +274 -0
- package/src/validators/credentials.ts +233 -0
- package/src/validators/quotas.test.ts +434 -0
- package/src/validators/quotas.ts +217 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
FIFOQueueManager,
|
|
4
|
+
fifoQueueManager,
|
|
5
|
+
DLQMonitoringManager,
|
|
6
|
+
dlqMonitoringManager,
|
|
7
|
+
BatchProcessingManager,
|
|
8
|
+
batchProcessingManager,
|
|
9
|
+
QueueManagementManager,
|
|
10
|
+
queueManagementManager,
|
|
11
|
+
} from '.'
|
|
12
|
+
|
|
13
|
+
describe('FIFO Queue Manager', () => {
|
|
14
|
+
let manager: FIFOQueueManager
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
manager = new FIFOQueueManager()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('should create FIFO queue', () => {
|
|
21
|
+
const queue = manager.createFIFOQueue({
|
|
22
|
+
name: 'test-queue',
|
|
23
|
+
contentBasedDeduplication: true,
|
|
24
|
+
deduplicationScope: 'queue',
|
|
25
|
+
fifoThroughputLimit: 'perQueue',
|
|
26
|
+
messageRetentionPeriod: 345600,
|
|
27
|
+
visibilityTimeout: 30,
|
|
28
|
+
receiveMessageWaitTime: 0,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
expect(queue.id).toContain('fifo-queue')
|
|
32
|
+
expect(queue.name).toBe('test-queue.fifo')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should create high-throughput FIFO', () => {
|
|
36
|
+
const queue = manager.createHighThroughputFIFO({
|
|
37
|
+
name: 'high-throughput',
|
|
38
|
+
contentBasedDeduplication: true,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
expect(queue.deduplicationScope).toBe('messageGroup')
|
|
42
|
+
expect(queue.fifoThroughputLimit).toBe('perMessageGroupId')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should send message to FIFO queue', () => {
|
|
46
|
+
const queue = manager.createStandardFIFO({
|
|
47
|
+
name: 'test',
|
|
48
|
+
contentBasedDeduplication: false,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const message = manager.sendMessage({
|
|
52
|
+
queueId: queue.id,
|
|
53
|
+
messageGroupId: 'group1',
|
|
54
|
+
messageBody: 'Test message',
|
|
55
|
+
messageDeduplicationId: 'dedup-1',
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
expect(message).toBeDefined()
|
|
59
|
+
expect(message?.messageGroupId).toBe('group1')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should deduplicate messages', () => {
|
|
63
|
+
const queue = manager.createStandardFIFO({
|
|
64
|
+
name: 'test',
|
|
65
|
+
contentBasedDeduplication: false,
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const msg1 = manager.sendMessage({
|
|
69
|
+
queueId: queue.id,
|
|
70
|
+
messageGroupId: 'group1',
|
|
71
|
+
messageBody: 'Test',
|
|
72
|
+
messageDeduplicationId: 'same-id',
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const msg2 = manager.sendMessage({
|
|
76
|
+
queueId: queue.id,
|
|
77
|
+
messageGroupId: 'group1',
|
|
78
|
+
messageBody: 'Test',
|
|
79
|
+
messageDeduplicationId: 'same-id',
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
expect(msg1).toBeDefined()
|
|
83
|
+
expect(msg2).toBeNull() // Deduplicated
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should track message groups', () => {
|
|
87
|
+
const queue = manager.createStandardFIFO({ name: 'test' })
|
|
88
|
+
|
|
89
|
+
manager.sendMessage({
|
|
90
|
+
queueId: queue.id,
|
|
91
|
+
messageGroupId: 'group1',
|
|
92
|
+
messageBody: 'Message 1',
|
|
93
|
+
messageDeduplicationId: 'msg1',
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
manager.sendMessage({
|
|
97
|
+
queueId: queue.id,
|
|
98
|
+
messageGroupId: 'group2',
|
|
99
|
+
messageBody: 'Message 2',
|
|
100
|
+
messageDeduplicationId: 'msg2',
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const groups = manager.getMessageGroups(queue.id)
|
|
104
|
+
expect(groups).toHaveLength(2)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should use global instance', () => {
|
|
108
|
+
expect(fifoQueueManager).toBeInstanceOf(FIFOQueueManager)
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
describe('DLQ Monitoring Manager', () => {
|
|
113
|
+
let manager: DLQMonitoringManager
|
|
114
|
+
|
|
115
|
+
beforeEach(() => {
|
|
116
|
+
manager = new DLQMonitoringManager()
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('should create DLQ monitor', () => {
|
|
120
|
+
const monitor = manager.createDLQMonitor({
|
|
121
|
+
name: 'test-dlq',
|
|
122
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/test-dlq',
|
|
123
|
+
sourceQueues: ['source-queue'],
|
|
124
|
+
maxReceiveCount: 3,
|
|
125
|
+
alarmThreshold: 10,
|
|
126
|
+
autoReprocess: false,
|
|
127
|
+
reprocessStrategy: 'manual',
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
expect(monitor.id).toContain('dlq-monitor')
|
|
131
|
+
expect(monitor.maxReceiveCount).toBe(3)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('should create automated monitor', () => {
|
|
135
|
+
const monitor = manager.createAutomatedMonitor({
|
|
136
|
+
name: 'automated',
|
|
137
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/dlq',
|
|
138
|
+
sourceQueues: ['main-queue'],
|
|
139
|
+
notificationTopicArn: 'arn:aws:sns:us-east-1:123456789012:alerts',
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
expect(monitor.autoReprocess).toBe(true)
|
|
143
|
+
expect(monitor.reprocessStrategy).toBe('scheduled')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('should collect metrics', () => {
|
|
147
|
+
const metrics = manager.collectMetrics('https://sqs.us-east-1.amazonaws.com/123456789012/test')
|
|
148
|
+
|
|
149
|
+
expect(metrics.id).toContain('metrics')
|
|
150
|
+
expect(metrics.approximateNumberOfMessages).toBeGreaterThanOrEqual(0)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('should create reprocess job', async () => {
|
|
154
|
+
const job = manager.createReprocessJob({
|
|
155
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/dlq',
|
|
156
|
+
messageId: 'msg-123',
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
expect(job.status).toBe('pending')
|
|
160
|
+
|
|
161
|
+
await manager.executeReprocessJob(job.id)
|
|
162
|
+
|
|
163
|
+
expect(['success', 'failed']).toContain(job.status)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('should batch reprocess messages', async () => {
|
|
167
|
+
const jobs = await manager.batchReprocess({
|
|
168
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/dlq',
|
|
169
|
+
maxMessages: 5,
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
expect(jobs).toHaveLength(5)
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('should get DLQ statistics', () => {
|
|
176
|
+
manager.collectMetrics('https://sqs.us-east-1.amazonaws.com/123456789012/test')
|
|
177
|
+
|
|
178
|
+
const stats = manager.getDLQStatistics('https://sqs.us-east-1.amazonaws.com/123456789012/test')
|
|
179
|
+
|
|
180
|
+
expect(stats).toBeDefined()
|
|
181
|
+
expect(stats.totalMessages).toBeGreaterThanOrEqual(0)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('should use global instance', () => {
|
|
185
|
+
expect(dlqMonitoringManager).toBeInstanceOf(DLQMonitoringManager)
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
describe('Batch Processing Manager', () => {
|
|
190
|
+
let manager: BatchProcessingManager
|
|
191
|
+
|
|
192
|
+
beforeEach(() => {
|
|
193
|
+
manager = new BatchProcessingManager()
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should create batch config', () => {
|
|
197
|
+
const config = manager.createBatchConfig({
|
|
198
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/queue',
|
|
199
|
+
batchSize: 10,
|
|
200
|
+
maxWaitTime: 100,
|
|
201
|
+
parallelProcessors: 5,
|
|
202
|
+
retryAttempts: 3,
|
|
203
|
+
visibilityTimeout: 30,
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
expect(config.id).toContain('batch-config')
|
|
207
|
+
expect(config.batchSize).toBe(10)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('should create high-throughput config', () => {
|
|
211
|
+
const config = manager.createHighThroughputConfig({
|
|
212
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/queue',
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
expect(config.batchSize).toBe(10)
|
|
216
|
+
expect(config.parallelProcessors).toBe(10)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('should create low-latency config', () => {
|
|
220
|
+
const config = manager.createLowLatencyConfig({
|
|
221
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/queue',
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
expect(config.batchSize).toBe(1)
|
|
225
|
+
expect(config.maxWaitTime).toBe(0)
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
it('should create batch job', () => {
|
|
229
|
+
const config = manager.createBatchConfig({
|
|
230
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/queue',
|
|
231
|
+
batchSize: 5,
|
|
232
|
+
maxWaitTime: 100,
|
|
233
|
+
parallelProcessors: 2,
|
|
234
|
+
retryAttempts: 2,
|
|
235
|
+
visibilityTimeout: 30,
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
const job = manager.createBatchJob({
|
|
239
|
+
configId: config.id,
|
|
240
|
+
messageCount: 20,
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
expect(job.messages).toHaveLength(20)
|
|
244
|
+
expect(job.status).toBe('pending')
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('should process batch job', async () => {
|
|
248
|
+
const config = manager.createBatchConfig({
|
|
249
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/queue',
|
|
250
|
+
batchSize: 5,
|
|
251
|
+
maxWaitTime: 100,
|
|
252
|
+
parallelProcessors: 2,
|
|
253
|
+
retryAttempts: 2,
|
|
254
|
+
visibilityTimeout: 30,
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
const job = manager.createBatchJob({
|
|
258
|
+
configId: config.id,
|
|
259
|
+
messageCount: 10,
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
await manager.processBatchJob(job.id)
|
|
263
|
+
|
|
264
|
+
expect(['completed', 'failed']).toContain(job.status)
|
|
265
|
+
expect(job.processedCount).toBeGreaterThan(0)
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
it('should get batch statistics', async () => {
|
|
269
|
+
const config = manager.createBatchConfig({
|
|
270
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/queue',
|
|
271
|
+
batchSize: 5,
|
|
272
|
+
maxWaitTime: 100,
|
|
273
|
+
parallelProcessors: 2,
|
|
274
|
+
retryAttempts: 2,
|
|
275
|
+
visibilityTimeout: 30,
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
const job = manager.createBatchJob({
|
|
279
|
+
configId: config.id,
|
|
280
|
+
messageCount: 10,
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
await manager.processBatchJob(job.id)
|
|
284
|
+
|
|
285
|
+
const stats = manager.getBatchStatistics(config.id)
|
|
286
|
+
|
|
287
|
+
expect(stats.totalJobsProcessed).toBe(1)
|
|
288
|
+
expect(stats.totalMessagesProcessed).toBeGreaterThan(0)
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
it('should optimize batch config', async () => {
|
|
292
|
+
const config = manager.createBatchConfig({
|
|
293
|
+
queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789012/queue',
|
|
294
|
+
batchSize: 5,
|
|
295
|
+
maxWaitTime: 100,
|
|
296
|
+
parallelProcessors: 2,
|
|
297
|
+
retryAttempts: 2,
|
|
298
|
+
visibilityTimeout: 30,
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
const job = manager.createBatchJob({
|
|
302
|
+
configId: config.id,
|
|
303
|
+
messageCount: 10,
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
await manager.processBatchJob(job.id)
|
|
307
|
+
|
|
308
|
+
const optimized = manager.optimizeBatchConfig(config.id)
|
|
309
|
+
|
|
310
|
+
expect(optimized).toBeDefined()
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
it('should use global instance', () => {
|
|
314
|
+
expect(batchProcessingManager).toBeInstanceOf(BatchProcessingManager)
|
|
315
|
+
})
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
describe('Queue Management Manager', () => {
|
|
319
|
+
let manager: QueueManagementManager
|
|
320
|
+
|
|
321
|
+
beforeEach(() => {
|
|
322
|
+
manager = new QueueManagementManager()
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it('should create standard queue', () => {
|
|
326
|
+
const queue = manager.createStandardQueue({
|
|
327
|
+
queueName: 'test-queue',
|
|
328
|
+
messageRetentionDays: 4,
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
expect(queue.id).toContain('queue')
|
|
332
|
+
expect(queue.queueName).toBe('test-queue')
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
it('should create long polling queue', () => {
|
|
336
|
+
const queue = manager.createLongPollingQueue({
|
|
337
|
+
queueName: 'long-poll',
|
|
338
|
+
waitTimeSeconds: 20,
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
expect(queue.receiveMessageWaitTime).toBe(20)
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
it('should create retention policy', () => {
|
|
345
|
+
const queue = manager.createStandardQueue({
|
|
346
|
+
queueName: 'test',
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
const policy = manager.createRetentionPolicy({
|
|
350
|
+
queueId: queue.id,
|
|
351
|
+
retentionPeriod: 86400, // 1 day
|
|
352
|
+
autoCleanup: true,
|
|
353
|
+
archiveExpiredMessages: false,
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
expect(policy.id).toContain('retention')
|
|
357
|
+
expect(policy.retentionPeriod).toBe(86400)
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
it('should create archival retention policy', () => {
|
|
361
|
+
const queue = manager.createStandardQueue({
|
|
362
|
+
queueName: 'test',
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
const policy = manager.createArchivalRetentionPolicy({
|
|
366
|
+
queueId: queue.id,
|
|
367
|
+
retentionDays: 30,
|
|
368
|
+
s3Bucket: 'archive-bucket',
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
expect(policy.archiveExpiredMessages).toBe(true)
|
|
372
|
+
expect(policy.archiveS3Bucket).toBe('archive-bucket')
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
it('should create delay queue', () => {
|
|
376
|
+
const queue = manager.createStandardQueue({
|
|
377
|
+
queueName: 'test',
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
const delay = manager.createDelayQueue({
|
|
381
|
+
queueUrl: queue.queueUrl,
|
|
382
|
+
defaultDelay: 60,
|
|
383
|
+
perMessageDelay: false,
|
|
384
|
+
maxDelay: 900,
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
expect(delay.defaultDelay).toBe(60)
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
it('should purge queue', async () => {
|
|
391
|
+
const queue = manager.createStandardQueue({
|
|
392
|
+
queueName: 'test',
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
const purgeOp = await manager.purgeQueue(queue.id)
|
|
396
|
+
|
|
397
|
+
expect(purgeOp.status).toBe('in_progress')
|
|
398
|
+
|
|
399
|
+
await new Promise(resolve => setTimeout(resolve, 150))
|
|
400
|
+
|
|
401
|
+
expect(purgeOp.status).toBe('completed')
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
it('should collect queue metrics', () => {
|
|
405
|
+
const queue = manager.createStandardQueue({
|
|
406
|
+
queueName: 'test',
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
const metrics = manager.collectQueueMetrics(queue.queueUrl)
|
|
410
|
+
|
|
411
|
+
expect(metrics.approximateNumberOfMessages).toBeGreaterThanOrEqual(0)
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
it('should get queue health', () => {
|
|
415
|
+
const queue = manager.createStandardQueue({
|
|
416
|
+
queueName: 'test',
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
manager.collectQueueMetrics(queue.queueUrl)
|
|
420
|
+
|
|
421
|
+
const health = manager.getQueueHealth(queue.queueUrl)
|
|
422
|
+
|
|
423
|
+
expect(['healthy', 'warning', 'critical']).toContain(health.status)
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
it('should use global instance', () => {
|
|
427
|
+
expect(queueManagementManager).toBeInstanceOf(QueueManagementManager)
|
|
428
|
+
})
|
|
429
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Management - Tagging strategies, cost allocation, resource groups
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface TaggingStrategy { id: string; tags: Record<string, string>; resources: string[] }
|
|
6
|
+
export interface CostAllocation { id: string; tagKey: string; allocations: Array<{ tagValue: string; cost: number }> }
|
|
7
|
+
export interface ResourceGroup { id: string; name: string; query: { resourceTypeFilters: string[]; tagFilters: Array<{ key: string; values: string[] }> } }
|
|
8
|
+
|
|
9
|
+
export class ResourceManagementManager {
|
|
10
|
+
private strategies = new Map<string, TaggingStrategy>()
|
|
11
|
+
private allocations = new Map<string, CostAllocation>()
|
|
12
|
+
private groups = new Map<string, ResourceGroup>()
|
|
13
|
+
private counter = 0
|
|
14
|
+
|
|
15
|
+
createTaggingStrategy(tags: Record<string, string>, resources: string[]): TaggingStrategy {
|
|
16
|
+
const id = `tagging-${Date.now()}-${this.counter++}`
|
|
17
|
+
const strategy = { id, tags, resources }
|
|
18
|
+
this.strategies.set(id, strategy)
|
|
19
|
+
return strategy
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
createCostAllocation(tagKey: string, allocations: Array<{ tagValue: string; cost: number }>): CostAllocation {
|
|
23
|
+
const id = `cost-${Date.now()}-${this.counter++}`
|
|
24
|
+
const allocation = { id, tagKey, allocations }
|
|
25
|
+
this.allocations.set(id, allocation)
|
|
26
|
+
return allocation
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
createResourceGroup(name: string, resourceTypeFilters: string[], tagFilters: Array<{ key: string; values: string[] }>): ResourceGroup {
|
|
30
|
+
const id = `group-${Date.now()}-${this.counter++}`
|
|
31
|
+
const group = { id, name, query: { resourceTypeFilters, tagFilters } }
|
|
32
|
+
this.groups.set(id, group)
|
|
33
|
+
return group
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
clear(): void { this.strategies.clear(); this.allocations.clear(); this.groups.clear() }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const resourceManagementManager: ResourceManagementManager = new ResourceManagementManager()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { EnvironmentType } from '@stacksjs/ts-cloud-types'
|
|
2
|
+
|
|
3
|
+
export interface NamingOptions {
|
|
4
|
+
slug: string
|
|
5
|
+
environment: EnvironmentType
|
|
6
|
+
timestamp?: string
|
|
7
|
+
resourceType: string
|
|
8
|
+
suffix?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generate a consistent resource name following the naming convention:
|
|
13
|
+
* {slug}-{environment}-{resourceType}-{timestamp}
|
|
14
|
+
*/
|
|
15
|
+
export function generateResourceName(options: NamingOptions): string {
|
|
16
|
+
const { slug, environment, resourceType, timestamp, suffix } = options
|
|
17
|
+
|
|
18
|
+
const parts = [
|
|
19
|
+
slug,
|
|
20
|
+
environment,
|
|
21
|
+
resourceType,
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
if (timestamp) {
|
|
25
|
+
parts.push(timestamp)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (suffix) {
|
|
29
|
+
parts.push(suffix)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return parts.join('-')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generate a logical ID for CloudFormation resources
|
|
37
|
+
* Converts to PascalCase and removes hyphens
|
|
38
|
+
*/
|
|
39
|
+
export function generateLogicalId(name: string): string {
|
|
40
|
+
return name
|
|
41
|
+
.split('-')
|
|
42
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
43
|
+
.join('')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get current timestamp for resource naming
|
|
48
|
+
*/
|
|
49
|
+
export function getTimestamp(): string {
|
|
50
|
+
return Date.now().toString()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Sanitize a name to be CloudFormation-compatible
|
|
55
|
+
*/
|
|
56
|
+
export function sanitizeName(name: string): string {
|
|
57
|
+
return name
|
|
58
|
+
.toLowerCase()
|
|
59
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
60
|
+
.replace(/^-+|-+$/g, '')
|
|
61
|
+
.replace(/-+/g, '-')
|
|
62
|
+
}
|