@stacksjs/ts-cloud-core 0.1.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.
- package/LICENSE.md +21 -0
- package/README.md +321 -0
- package/package.json +31 -0
- 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
- package/test/ai.test.ts +327 -0
- package/test/api.test.ts +511 -0
- package/test/auth.test.ts +632 -0
- package/test/cache.test.ts +406 -0
- package/test/cdn.test.ts +247 -0
- package/test/compute.test.ts +861 -0
- package/test/database.test.ts +523 -0
- package/test/deployment.test.ts +499 -0
- package/test/dns.test.ts +270 -0
- package/test/email.test.ts +439 -0
- package/test/filesystem.test.ts +382 -0
- package/test/integration.test.ts +350 -0
- package/test/messaging.test.ts +514 -0
- package/test/monitoring.test.ts +634 -0
- package/test/network.test.ts +425 -0
- package/test/permissions.test.ts +488 -0
- package/test/queue.test.ts +484 -0
- package/test/registry.test.ts +306 -0
- package/test/security.test.ts +462 -0
- package/test/storage.test.ts +463 -0
- package/test/template-validator.test.ts +559 -0
- package/test/workflow.test.ts +592 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Region Resource Management
|
|
3
|
+
* Handles references and dependencies between regions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface CrossRegionReference {
|
|
7
|
+
sourceRegion: string
|
|
8
|
+
targetRegion: string
|
|
9
|
+
resourceType: string
|
|
10
|
+
resourceId: string
|
|
11
|
+
value: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CrossRegionExport {
|
|
15
|
+
region: string
|
|
16
|
+
exportName: string
|
|
17
|
+
value: string
|
|
18
|
+
description?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Cross-region reference manager
|
|
23
|
+
*/
|
|
24
|
+
export class CrossRegionReferenceManager {
|
|
25
|
+
private references: CrossRegionReference[] = []
|
|
26
|
+
private exports: Map<string, CrossRegionExport[]> = new Map()
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Register a cross-region export
|
|
30
|
+
*/
|
|
31
|
+
addExport(export_: CrossRegionExport): void {
|
|
32
|
+
const key = `${export_.region}:${export_.exportName}`
|
|
33
|
+
|
|
34
|
+
if (!this.exports.has(export_.region)) {
|
|
35
|
+
this.exports.set(export_.region, [])
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.exports.get(export_.region)!.push(export_)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get export value from another region
|
|
43
|
+
*/
|
|
44
|
+
getExport(region: string, exportName: string): string | undefined {
|
|
45
|
+
const regionExports = this.exports.get(region)
|
|
46
|
+
|
|
47
|
+
if (!regionExports) return undefined
|
|
48
|
+
|
|
49
|
+
const export_ = regionExports.find(e => e.exportName === exportName)
|
|
50
|
+
return export_?.value
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create cross-region reference
|
|
55
|
+
*/
|
|
56
|
+
createReference(
|
|
57
|
+
sourceRegion: string,
|
|
58
|
+
targetRegion: string,
|
|
59
|
+
resourceType: string,
|
|
60
|
+
resourceId: string,
|
|
61
|
+
): string {
|
|
62
|
+
// In real implementation, this would:
|
|
63
|
+
// 1. Store reference in SSM Parameter Store or Systems Manager
|
|
64
|
+
// 2. Enable cross-region access
|
|
65
|
+
// 3. Return parameter name
|
|
66
|
+
|
|
67
|
+
const parameterName = `/cross-region/${sourceRegion}/${resourceType}/${resourceId}`
|
|
68
|
+
|
|
69
|
+
this.references.push({
|
|
70
|
+
sourceRegion,
|
|
71
|
+
targetRegion,
|
|
72
|
+
resourceType,
|
|
73
|
+
resourceId,
|
|
74
|
+
value: parameterName,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
return parameterName
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Resolve cross-region reference
|
|
82
|
+
*/
|
|
83
|
+
async resolveReference(
|
|
84
|
+
targetRegion: string,
|
|
85
|
+
parameterName: string,
|
|
86
|
+
): Promise<string> {
|
|
87
|
+
// In real implementation, this would:
|
|
88
|
+
// 1. Fetch parameter from SSM Parameter Store
|
|
89
|
+
// 2. Handle cross-region access
|
|
90
|
+
// 3. Return actual value
|
|
91
|
+
|
|
92
|
+
const reference = this.references.find(
|
|
93
|
+
ref => ref.targetRegion === targetRegion && ref.value === parameterName,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if (!reference) {
|
|
97
|
+
throw new Error(`Reference not found: ${parameterName}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Placeholder: return the parameter name
|
|
101
|
+
return `arn:aws:resource:${reference.sourceRegion}:123456789012:${reference.resourceType}/${reference.resourceId}`
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get all references for a region
|
|
106
|
+
*/
|
|
107
|
+
getReferencesForRegion(region: string): CrossRegionReference[] {
|
|
108
|
+
return this.references.filter(
|
|
109
|
+
ref => ref.sourceRegion === region || ref.targetRegion === region,
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Clear all references
|
|
115
|
+
*/
|
|
116
|
+
clear(): void {
|
|
117
|
+
this.references = []
|
|
118
|
+
this.exports.clear()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Global resources that exist in one region but are accessible globally
|
|
124
|
+
*/
|
|
125
|
+
export interface GlobalResource {
|
|
126
|
+
type: 'cloudfront' | 'route53' | 'waf' | 'iam' | 's3-website'
|
|
127
|
+
id: string
|
|
128
|
+
region: string
|
|
129
|
+
arn: string
|
|
130
|
+
endpoint?: string
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Global resource manager
|
|
135
|
+
*/
|
|
136
|
+
export class GlobalResourceManager {
|
|
137
|
+
private resources: Map<string, GlobalResource> = new Map()
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Register a global resource
|
|
141
|
+
*/
|
|
142
|
+
register(resource: GlobalResource): void {
|
|
143
|
+
this.resources.set(resource.id, resource)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get global resource
|
|
148
|
+
*/
|
|
149
|
+
get(id: string): GlobalResource | undefined {
|
|
150
|
+
return this.resources.get(id)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Get global resources by type
|
|
155
|
+
*/
|
|
156
|
+
getByType(type: GlobalResource['type']): GlobalResource[] {
|
|
157
|
+
return Array.from(this.resources.values()).filter(r => r.type === type)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get CloudFront distributions
|
|
162
|
+
*/
|
|
163
|
+
getCloudFrontDistributions(): GlobalResource[] {
|
|
164
|
+
return this.getByType('cloudfront')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get Route53 hosted zones
|
|
169
|
+
*/
|
|
170
|
+
getRoute53HostedZones(): GlobalResource[] {
|
|
171
|
+
return this.getByType('route53')
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get WAF web ACLs
|
|
176
|
+
*/
|
|
177
|
+
getWAFWebACLs(): GlobalResource[] {
|
|
178
|
+
return this.getByType('waf')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Remove global resource
|
|
183
|
+
*/
|
|
184
|
+
remove(id: string): void {
|
|
185
|
+
this.resources.delete(id)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Clear all global resources
|
|
190
|
+
*/
|
|
191
|
+
clear(): void {
|
|
192
|
+
this.resources.clear()
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Region pairing for replication and failover
|
|
198
|
+
*/
|
|
199
|
+
export interface RegionPair {
|
|
200
|
+
primary: string
|
|
201
|
+
secondary: string
|
|
202
|
+
replicationConfig?: {
|
|
203
|
+
s3: boolean
|
|
204
|
+
dynamodb: boolean
|
|
205
|
+
rds: boolean
|
|
206
|
+
}
|
|
207
|
+
failoverConfig?: {
|
|
208
|
+
automatic: boolean
|
|
209
|
+
healthCheckInterval: number
|
|
210
|
+
failoverThreshold: number
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Region pair manager
|
|
216
|
+
*/
|
|
217
|
+
export class RegionPairManager {
|
|
218
|
+
private pairs: RegionPair[] = []
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Add region pair
|
|
222
|
+
*/
|
|
223
|
+
addPair(pair: RegionPair): void {
|
|
224
|
+
this.pairs.push(pair)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get paired region
|
|
229
|
+
*/
|
|
230
|
+
getPairedRegion(region: string): string | undefined {
|
|
231
|
+
const pair = this.pairs.find(p => p.primary === region || p.secondary === region)
|
|
232
|
+
|
|
233
|
+
if (!pair) return undefined
|
|
234
|
+
|
|
235
|
+
return pair.primary === region ? pair.secondary : pair.primary
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get all pairs
|
|
240
|
+
*/
|
|
241
|
+
getAllPairs(): RegionPair[] {
|
|
242
|
+
return [...this.pairs]
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get pairs with replication enabled
|
|
247
|
+
*/
|
|
248
|
+
getReplicatedPairs(): RegionPair[] {
|
|
249
|
+
return this.pairs.filter(p => p.replicationConfig)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get pairs with failover enabled
|
|
254
|
+
*/
|
|
255
|
+
getFailoverPairs(): RegionPair[] {
|
|
256
|
+
return this.pairs.filter(p => p.failoverConfig?.automatic)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Check if regions are paired
|
|
261
|
+
*/
|
|
262
|
+
arePaired(region1: string, region2: string): boolean {
|
|
263
|
+
return this.pairs.some(
|
|
264
|
+
p =>
|
|
265
|
+
(p.primary === region1 && p.secondary === region2)
|
|
266
|
+
|| (p.primary === region2 && p.secondary === region1),
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Clear all pairs
|
|
272
|
+
*/
|
|
273
|
+
clear(): void {
|
|
274
|
+
this.pairs = []
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Cross-region stack dependencies
|
|
280
|
+
*/
|
|
281
|
+
export interface StackDependency {
|
|
282
|
+
dependentStack: string
|
|
283
|
+
dependentRegion: string
|
|
284
|
+
dependsOnStack: string
|
|
285
|
+
dependsOnRegion: string
|
|
286
|
+
outputKey: string
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Stack dependency manager
|
|
291
|
+
*/
|
|
292
|
+
export class StackDependencyManager {
|
|
293
|
+
private dependencies: StackDependency[] = []
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Add stack dependency
|
|
297
|
+
*/
|
|
298
|
+
addDependency(dependency: StackDependency): void {
|
|
299
|
+
this.dependencies.push(dependency)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get dependencies for a stack
|
|
304
|
+
*/
|
|
305
|
+
getDependencies(stackName: string, region: string): StackDependency[] {
|
|
306
|
+
return this.dependencies.filter(
|
|
307
|
+
d => d.dependentStack === stackName && d.dependentRegion === region,
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get dependents of a stack
|
|
313
|
+
*/
|
|
314
|
+
getDependents(stackName: string, region: string): StackDependency[] {
|
|
315
|
+
return this.dependencies.filter(
|
|
316
|
+
d => d.dependsOnStack === stackName && d.dependsOnRegion === region,
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Check if stack has dependencies
|
|
322
|
+
*/
|
|
323
|
+
hasDependencies(stackName: string, region: string): boolean {
|
|
324
|
+
return this.getDependencies(stackName, region).length > 0
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Get deployment order
|
|
329
|
+
*/
|
|
330
|
+
getDeploymentOrder(stacks: Array<{ name: string; region: string }>): Array<{ name: string; region: string }> {
|
|
331
|
+
const visited: Set<string> = new Set()
|
|
332
|
+
const order: Array<{ name: string; region: string }> = []
|
|
333
|
+
|
|
334
|
+
const visit = (stack: { name: string; region: string }) => {
|
|
335
|
+
const key = `${stack.name}:${stack.region}`
|
|
336
|
+
|
|
337
|
+
if (visited.has(key)) return
|
|
338
|
+
|
|
339
|
+
visited.add(key)
|
|
340
|
+
|
|
341
|
+
// Visit dependencies first
|
|
342
|
+
const deps = this.getDependencies(stack.name, stack.region)
|
|
343
|
+
for (const dep of deps) {
|
|
344
|
+
visit({
|
|
345
|
+
name: dep.dependsOnStack,
|
|
346
|
+
region: dep.dependsOnRegion,
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
order.push(stack)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
for (const stack of stacks) {
|
|
354
|
+
visit(stack)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return order
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Detect circular dependencies
|
|
362
|
+
*/
|
|
363
|
+
detectCircularDependencies(): boolean {
|
|
364
|
+
const visited: Set<string> = new Set()
|
|
365
|
+
const recursionStack: Set<string> = new Set()
|
|
366
|
+
|
|
367
|
+
const hasCycle = (stack: string, region: string): boolean => {
|
|
368
|
+
const key = `${stack}:${region}`
|
|
369
|
+
|
|
370
|
+
if (recursionStack.has(key)) return true
|
|
371
|
+
if (visited.has(key)) return false
|
|
372
|
+
|
|
373
|
+
visited.add(key)
|
|
374
|
+
recursionStack.add(key)
|
|
375
|
+
|
|
376
|
+
const deps = this.getDependencies(stack, region)
|
|
377
|
+
for (const dep of deps) {
|
|
378
|
+
if (hasCycle(dep.dependsOnStack, dep.dependsOnRegion)) {
|
|
379
|
+
return true
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
recursionStack.delete(key)
|
|
384
|
+
return false
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
for (const dep of this.dependencies) {
|
|
388
|
+
if (hasCycle(dep.dependentStack, dep.dependentRegion)) {
|
|
389
|
+
return true
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return false
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Clear all dependencies
|
|
398
|
+
*/
|
|
399
|
+
clear(): void {
|
|
400
|
+
this.dependencies = []
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Global instances
|
|
406
|
+
*/
|
|
407
|
+
export const crossRegionReferenceManager: CrossRegionReferenceManager = new CrossRegionReferenceManager()
|
|
408
|
+
export const globalResourceManager: GlobalResourceManager = new GlobalResourceManager()
|
|
409
|
+
export const regionPairManager: RegionPairManager = new RegionPairManager()
|
|
410
|
+
export const stackDependencyManager: StackDependencyManager = new StackDependencyManager()
|