@stacksjs/ts-cloud-core 0.1.2 → 0.1.6

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 (250) hide show
  1. package/README.md +98 -13
  2. package/package.json +12 -3
  3. package/src/advanced-features.test.ts +0 -465
  4. package/src/aws/cloudformation.ts +0 -421
  5. package/src/aws/cloudfront.ts +0 -158
  6. package/src/aws/credentials.test.ts +0 -132
  7. package/src/aws/credentials.ts +0 -545
  8. package/src/aws/index.ts +0 -87
  9. package/src/aws/s3.test.ts +0 -188
  10. package/src/aws/s3.ts +0 -1088
  11. package/src/aws/signature.test.ts +0 -670
  12. package/src/aws/signature.ts +0 -1155
  13. package/src/backup/disaster-recovery.test.ts +0 -726
  14. package/src/backup/disaster-recovery.ts +0 -500
  15. package/src/backup/index.ts +0 -34
  16. package/src/backup/manager.test.ts +0 -498
  17. package/src/backup/manager.ts +0 -432
  18. package/src/cicd/circleci.ts +0 -430
  19. package/src/cicd/github-actions.ts +0 -424
  20. package/src/cicd/gitlab-ci.ts +0 -255
  21. package/src/cicd/index.ts +0 -8
  22. package/src/cli/history.ts +0 -396
  23. package/src/cli/index.ts +0 -10
  24. package/src/cli/progress.ts +0 -458
  25. package/src/cli/repl.ts +0 -454
  26. package/src/cli/suggestions.ts +0 -327
  27. package/src/cli/table.test.ts +0 -319
  28. package/src/cli/table.ts +0 -332
  29. package/src/cloudformation/builder.test.ts +0 -327
  30. package/src/cloudformation/builder.ts +0 -378
  31. package/src/cloudformation/builders/api-gateway.ts +0 -449
  32. package/src/cloudformation/builders/cache.ts +0 -334
  33. package/src/cloudformation/builders/cdn.ts +0 -278
  34. package/src/cloudformation/builders/compute.ts +0 -485
  35. package/src/cloudformation/builders/database.ts +0 -392
  36. package/src/cloudformation/builders/functions.ts +0 -343
  37. package/src/cloudformation/builders/messaging.ts +0 -140
  38. package/src/cloudformation/builders/monitoring.ts +0 -300
  39. package/src/cloudformation/builders/network.ts +0 -264
  40. package/src/cloudformation/builders/queue.ts +0 -147
  41. package/src/cloudformation/builders/security.ts +0 -399
  42. package/src/cloudformation/builders/storage.ts +0 -285
  43. package/src/cloudformation/index.ts +0 -30
  44. package/src/cloudformation/types.ts +0 -173
  45. package/src/compliance/aws-config.ts +0 -543
  46. package/src/compliance/cloudtrail.ts +0 -376
  47. package/src/compliance/compliance.test.ts +0 -423
  48. package/src/compliance/guardduty.ts +0 -446
  49. package/src/compliance/index.ts +0 -66
  50. package/src/compliance/security-hub.ts +0 -456
  51. package/src/containers/build-optimization.ts +0 -416
  52. package/src/containers/containers.test.ts +0 -508
  53. package/src/containers/image-scanning.ts +0 -360
  54. package/src/containers/index.ts +0 -9
  55. package/src/containers/registry.ts +0 -293
  56. package/src/containers/service-mesh.ts +0 -520
  57. package/src/database/database.test.ts +0 -762
  58. package/src/database/index.ts +0 -9
  59. package/src/database/migrations.ts +0 -444
  60. package/src/database/performance.ts +0 -528
  61. package/src/database/replicas.ts +0 -534
  62. package/src/database/users.ts +0 -494
  63. package/src/dependency-graph.ts +0 -143
  64. package/src/deployment/ab-testing.ts +0 -582
  65. package/src/deployment/blue-green.ts +0 -452
  66. package/src/deployment/canary.ts +0 -500
  67. package/src/deployment/deployment.test.ts +0 -526
  68. package/src/deployment/index.ts +0 -61
  69. package/src/deployment/progressive.ts +0 -62
  70. package/src/dns/dns.test.ts +0 -641
  71. package/src/dns/dnssec.ts +0 -315
  72. package/src/dns/index.ts +0 -8
  73. package/src/dns/resolver.ts +0 -496
  74. package/src/dns/routing.ts +0 -593
  75. package/src/email/advanced/analytics.ts +0 -445
  76. package/src/email/advanced/index.ts +0 -11
  77. package/src/email/advanced/rules.ts +0 -465
  78. package/src/email/advanced/scheduling.ts +0 -352
  79. package/src/email/advanced/search.ts +0 -412
  80. package/src/email/advanced/shared-mailboxes.ts +0 -404
  81. package/src/email/advanced/templates.ts +0 -455
  82. package/src/email/advanced/threading.ts +0 -281
  83. package/src/email/analytics.ts +0 -467
  84. package/src/email/bounce-handling.ts +0 -425
  85. package/src/email/email.test.ts +0 -431
  86. package/src/email/handlers/__tests__/inbound.test.ts +0 -38
  87. package/src/email/handlers/__tests__/outbound.test.ts +0 -37
  88. package/src/email/handlers/converter.ts +0 -227
  89. package/src/email/handlers/feedback.ts +0 -228
  90. package/src/email/handlers/inbound.ts +0 -169
  91. package/src/email/handlers/outbound.ts +0 -178
  92. package/src/email/index.ts +0 -15
  93. package/src/email/reputation.ts +0 -303
  94. package/src/email/templates.ts +0 -352
  95. package/src/errors/index.test.ts +0 -434
  96. package/src/errors/index.ts +0 -416
  97. package/src/health-checks/index.ts +0 -40
  98. package/src/index.ts +0 -360
  99. package/src/intrinsic-functions.ts +0 -118
  100. package/src/lambda/concurrency.ts +0 -330
  101. package/src/lambda/destinations.ts +0 -345
  102. package/src/lambda/dlq.ts +0 -425
  103. package/src/lambda/index.ts +0 -11
  104. package/src/lambda/lambda.test.ts +0 -840
  105. package/src/lambda/layers.ts +0 -263
  106. package/src/lambda/versions.ts +0 -376
  107. package/src/lambda/vpc.ts +0 -399
  108. package/src/local/config.ts +0 -114
  109. package/src/local/index.ts +0 -6
  110. package/src/local/mock-aws.ts +0 -351
  111. package/src/modules/ai.ts +0 -340
  112. package/src/modules/api.ts +0 -478
  113. package/src/modules/auth.ts +0 -805
  114. package/src/modules/cache.ts +0 -417
  115. package/src/modules/cdn.ts +0 -1062
  116. package/src/modules/communication.ts +0 -1094
  117. package/src/modules/compute.ts +0 -3348
  118. package/src/modules/database.ts +0 -554
  119. package/src/modules/deployment.ts +0 -1079
  120. package/src/modules/dns.ts +0 -337
  121. package/src/modules/email.ts +0 -1538
  122. package/src/modules/filesystem.ts +0 -515
  123. package/src/modules/index.ts +0 -32
  124. package/src/modules/messaging.ts +0 -486
  125. package/src/modules/monitoring.ts +0 -2086
  126. package/src/modules/network.ts +0 -664
  127. package/src/modules/parameter-store.ts +0 -325
  128. package/src/modules/permissions.ts +0 -1081
  129. package/src/modules/phone.ts +0 -494
  130. package/src/modules/queue.ts +0 -1260
  131. package/src/modules/redirects.ts +0 -464
  132. package/src/modules/registry.ts +0 -699
  133. package/src/modules/search.ts +0 -401
  134. package/src/modules/secrets.ts +0 -416
  135. package/src/modules/security.ts +0 -731
  136. package/src/modules/sms.ts +0 -389
  137. package/src/modules/storage.ts +0 -1120
  138. package/src/modules/workflow.ts +0 -680
  139. package/src/multi-account/config.ts +0 -521
  140. package/src/multi-account/index.ts +0 -7
  141. package/src/multi-account/manager.ts +0 -427
  142. package/src/multi-region/cross-region.ts +0 -410
  143. package/src/multi-region/index.ts +0 -8
  144. package/src/multi-region/manager.ts +0 -483
  145. package/src/multi-region/regions.ts +0 -435
  146. package/src/network-security/index.ts +0 -48
  147. package/src/observability/index.ts +0 -9
  148. package/src/observability/logs.ts +0 -522
  149. package/src/observability/metrics.ts +0 -460
  150. package/src/observability/observability.test.ts +0 -782
  151. package/src/observability/synthetics.ts +0 -568
  152. package/src/observability/xray.ts +0 -358
  153. package/src/phone/advanced/analytics.ts +0 -349
  154. package/src/phone/advanced/callbacks.ts +0 -428
  155. package/src/phone/advanced/index.ts +0 -8
  156. package/src/phone/advanced/ivr-builder.ts +0 -504
  157. package/src/phone/advanced/recording.ts +0 -310
  158. package/src/phone/handlers/__tests__/incoming-call.test.ts +0 -40
  159. package/src/phone/handlers/incoming-call.ts +0 -117
  160. package/src/phone/handlers/missed-call.ts +0 -116
  161. package/src/phone/handlers/voicemail.ts +0 -179
  162. package/src/phone/index.ts +0 -9
  163. package/src/presets/api-backend.ts +0 -134
  164. package/src/presets/data-pipeline.ts +0 -204
  165. package/src/presets/extend.test.ts +0 -295
  166. package/src/presets/extend.ts +0 -297
  167. package/src/presets/fullstack-app.ts +0 -144
  168. package/src/presets/index.ts +0 -27
  169. package/src/presets/jamstack.ts +0 -135
  170. package/src/presets/microservices.ts +0 -167
  171. package/src/presets/ml-api.ts +0 -208
  172. package/src/presets/nodejs-server.ts +0 -104
  173. package/src/presets/nodejs-serverless.ts +0 -114
  174. package/src/presets/realtime-app.ts +0 -184
  175. package/src/presets/static-site.ts +0 -64
  176. package/src/presets/traditional-web-app.ts +0 -339
  177. package/src/presets/wordpress.ts +0 -138
  178. package/src/preview/github.test.ts +0 -249
  179. package/src/preview/github.ts +0 -297
  180. package/src/preview/index.ts +0 -37
  181. package/src/preview/manager.test.ts +0 -440
  182. package/src/preview/manager.ts +0 -326
  183. package/src/preview/notifications.test.ts +0 -582
  184. package/src/preview/notifications.ts +0 -341
  185. package/src/queue/batch-processing.ts +0 -402
  186. package/src/queue/dlq-monitoring.ts +0 -402
  187. package/src/queue/fifo.ts +0 -342
  188. package/src/queue/index.ts +0 -9
  189. package/src/queue/management.ts +0 -428
  190. package/src/queue/queue.test.ts +0 -429
  191. package/src/resource-mgmt/index.ts +0 -39
  192. package/src/resource-naming.ts +0 -62
  193. package/src/s3/index.ts +0 -523
  194. package/src/schema/cloud-config.schema.json +0 -554
  195. package/src/schema/index.ts +0 -68
  196. package/src/security/certificate-manager.ts +0 -492
  197. package/src/security/index.ts +0 -9
  198. package/src/security/scanning.ts +0 -545
  199. package/src/security/secrets-manager.ts +0 -476
  200. package/src/security/secrets-rotation.ts +0 -456
  201. package/src/security/security.test.ts +0 -738
  202. package/src/sms/advanced/ab-testing.ts +0 -389
  203. package/src/sms/advanced/analytics.ts +0 -336
  204. package/src/sms/advanced/campaigns.ts +0 -523
  205. package/src/sms/advanced/chatbot.ts +0 -224
  206. package/src/sms/advanced/index.ts +0 -10
  207. package/src/sms/advanced/link-tracking.ts +0 -248
  208. package/src/sms/advanced/mms.ts +0 -308
  209. package/src/sms/handlers/__tests__/send.test.ts +0 -40
  210. package/src/sms/handlers/delivery-status.ts +0 -133
  211. package/src/sms/handlers/receive.ts +0 -162
  212. package/src/sms/handlers/send.ts +0 -174
  213. package/src/sms/index.ts +0 -9
  214. package/src/stack-diff.ts +0 -389
  215. package/src/static-site/index.ts +0 -85
  216. package/src/template-builder.ts +0 -110
  217. package/src/template-validator.ts +0 -574
  218. package/src/utils/cache.ts +0 -291
  219. package/src/utils/diff.ts +0 -269
  220. package/src/utils/hash.ts +0 -227
  221. package/src/utils/index.ts +0 -8
  222. package/src/utils/parallel.ts +0 -294
  223. package/src/validators/credentials.test.ts +0 -274
  224. package/src/validators/credentials.ts +0 -233
  225. package/src/validators/quotas.test.ts +0 -434
  226. package/src/validators/quotas.ts +0 -217
  227. package/test/ai.test.ts +0 -327
  228. package/test/api.test.ts +0 -511
  229. package/test/auth.test.ts +0 -632
  230. package/test/cache.test.ts +0 -406
  231. package/test/cdn.test.ts +0 -247
  232. package/test/compute.test.ts +0 -861
  233. package/test/database.test.ts +0 -523
  234. package/test/deployment.test.ts +0 -499
  235. package/test/dns.test.ts +0 -270
  236. package/test/email.test.ts +0 -439
  237. package/test/filesystem.test.ts +0 -382
  238. package/test/integration.test.ts +0 -350
  239. package/test/messaging.test.ts +0 -514
  240. package/test/monitoring.test.ts +0 -634
  241. package/test/network.test.ts +0 -425
  242. package/test/permissions.test.ts +0 -488
  243. package/test/queue.test.ts +0 -484
  244. package/test/registry.test.ts +0 -306
  245. package/test/security.test.ts +0 -462
  246. package/test/storage.test.ts +0 -463
  247. package/test/template-validator.test.ts +0 -559
  248. package/test/workflow.test.ts +0 -592
  249. package/tsconfig.json +0 -16
  250. package/tsconfig.tsbuildinfo +0 -1
@@ -1,291 +0,0 @@
1
- /**
2
- * Caching utilities for performance optimization
3
- * Caches CloudFormation templates, credentials, and other data
4
- */
5
-
6
- import { createHash } from 'node:crypto'
7
- import fs from 'node:fs'
8
- import path from 'node:path'
9
-
10
- export interface CacheOptions {
11
- ttl?: number // Time to live in milliseconds
12
- maxSize?: number // Maximum cache size
13
- }
14
-
15
- export interface CacheEntry<T> {
16
- value: T
17
- timestamp: number
18
- hash?: string
19
- }
20
-
21
- /**
22
- * Simple in-memory cache with TTL support
23
- */
24
- export class Cache<T = any> {
25
- private cache: Map<string, CacheEntry<T>>
26
- private ttl: number
27
- private maxSize: number
28
-
29
- constructor(options: CacheOptions = {}) {
30
- this.cache = new Map()
31
- this.ttl = options.ttl || 5 * 60 * 1000 // Default: 5 minutes
32
- this.maxSize = options.maxSize || 100 // Default: 100 entries
33
- }
34
-
35
- /**
36
- * Get value from cache
37
- */
38
- get(key: string): T | undefined {
39
- const entry = this.cache.get(key)
40
-
41
- if (!entry) {
42
- return undefined
43
- }
44
-
45
- // Check if entry has expired
46
- if (Date.now() - entry.timestamp > this.ttl) {
47
- this.cache.delete(key)
48
- return undefined
49
- }
50
-
51
- return entry.value
52
- }
53
-
54
- /**
55
- * Set value in cache
56
- */
57
- set(key: string, value: T, hash?: string): void {
58
- // If cache is full, remove oldest entry
59
- if (this.cache.size >= this.maxSize) {
60
- const firstKey = this.cache.keys().next().value
61
- if (firstKey !== undefined) {
62
- this.cache.delete(firstKey)
63
- }
64
- }
65
-
66
- this.cache.set(key, {
67
- value,
68
- timestamp: Date.now(),
69
- hash,
70
- })
71
- }
72
-
73
- /**
74
- * Check if cache has key and it's not expired
75
- */
76
- has(key: string): boolean {
77
- return this.get(key) !== undefined
78
- }
79
-
80
- /**
81
- * Clear cache
82
- */
83
- clear(): void {
84
- this.cache.clear()
85
- }
86
-
87
- /**
88
- * Remove expired entries
89
- */
90
- prune(): void {
91
- const now = Date.now()
92
- for (const [key, entry] of this.cache.entries()) {
93
- if (now - entry.timestamp > this.ttl) {
94
- this.cache.delete(key)
95
- }
96
- }
97
- }
98
-
99
- /**
100
- * Get cache stats
101
- */
102
- stats(): { size: number, ttl: number, maxSize: number } {
103
- return {
104
- size: this.cache.size,
105
- ttl: this.ttl,
106
- maxSize: this.maxSize,
107
- }
108
- }
109
- }
110
-
111
- /**
112
- * File-based cache for persistent caching
113
- */
114
- export class FileCache<T = any> {
115
- private cacheDir: string
116
- private ttl: number
117
-
118
- constructor(cacheDir: string, options: CacheOptions = {}) {
119
- this.cacheDir = cacheDir
120
- this.ttl = options.ttl || 24 * 60 * 60 * 1000 // Default: 24 hours
121
-
122
- // Create cache directory if it doesn't exist
123
- if (!fs.existsSync(cacheDir)) {
124
- fs.mkdirSync(cacheDir, { recursive: true })
125
- }
126
- }
127
-
128
- /**
129
- * Get cache file path for key
130
- */
131
- private getCachePath(key: string): string {
132
- const hash = createHash('sha256').update(key).digest('hex')
133
- return path.join(this.cacheDir, `${hash}.json`)
134
- }
135
-
136
- /**
137
- * Get value from cache
138
- */
139
- get(key: string): T | undefined {
140
- const cachePath = this.getCachePath(key)
141
-
142
- if (!fs.existsSync(cachePath)) {
143
- return undefined
144
- }
145
-
146
- try {
147
- const data = fs.readFileSync(cachePath, 'utf-8')
148
- const entry: CacheEntry<T> = JSON.parse(data)
149
-
150
- // Check if entry has expired
151
- if (Date.now() - entry.timestamp > this.ttl) {
152
- fs.unlinkSync(cachePath)
153
- return undefined
154
- }
155
-
156
- return entry.value
157
- }
158
- catch {
159
- // If cache file is corrupted, delete it
160
- fs.unlinkSync(cachePath)
161
- return undefined
162
- }
163
- }
164
-
165
- /**
166
- * Set value in cache
167
- */
168
- set(key: string, value: T, hash?: string): void {
169
- const cachePath = this.getCachePath(key)
170
-
171
- const entry: CacheEntry<T> = {
172
- value,
173
- timestamp: Date.now(),
174
- hash,
175
- }
176
-
177
- fs.writeFileSync(cachePath, JSON.stringify(entry), 'utf-8')
178
- }
179
-
180
- /**
181
- * Check if cache has key and it's not expired
182
- */
183
- has(key: string): boolean {
184
- return this.get(key) !== undefined
185
- }
186
-
187
- /**
188
- * Clear all cache files
189
- */
190
- clear(): void {
191
- const files = fs.readdirSync(this.cacheDir)
192
- for (const file of files) {
193
- fs.unlinkSync(path.join(this.cacheDir, file))
194
- }
195
- }
196
-
197
- /**
198
- * Remove expired entries
199
- */
200
- prune(): void {
201
- const files = fs.readdirSync(this.cacheDir)
202
- const now = Date.now()
203
-
204
- for (const file of files) {
205
- const filePath = path.join(this.cacheDir, file)
206
-
207
- try {
208
- const data = fs.readFileSync(filePath, 'utf-8')
209
- const entry: CacheEntry<any> = JSON.parse(data)
210
-
211
- if (now - entry.timestamp > this.ttl) {
212
- fs.unlinkSync(filePath)
213
- }
214
- }
215
- catch {
216
- // If file is corrupted, delete it
217
- fs.unlinkSync(filePath)
218
- }
219
- }
220
- }
221
- }
222
-
223
- /**
224
- * Template cache for CloudFormation templates
225
- */
226
- export class TemplateCache {
227
- private cache: FileCache<string>
228
-
229
- constructor(cacheDir: string = '.ts-cloud/cache/templates') {
230
- this.cache = new FileCache<string>(cacheDir, {
231
- ttl: 24 * 60 * 60 * 1000, // 24 hours
232
- })
233
- }
234
-
235
- /**
236
- * Get template from cache
237
- */
238
- getTemplate(stackName: string): string | undefined {
239
- return this.cache.get(`template:${stackName}`)
240
- }
241
-
242
- /**
243
- * Save template to cache
244
- */
245
- setTemplate(stackName: string, template: string): void {
246
- const hash = this.hashTemplate(template)
247
- this.cache.set(`template:${stackName}`, template, hash)
248
- }
249
-
250
- /**
251
- * Check if template has changed
252
- */
253
- hasChanged(stackName: string, newTemplate: string): boolean {
254
- const cached = this.cache.get(`template:${stackName}`)
255
-
256
- if (!cached) {
257
- return true
258
- }
259
-
260
- const cachedHash = this.hashTemplate(cached)
261
- const newHash = this.hashTemplate(newTemplate)
262
-
263
- return cachedHash !== newHash
264
- }
265
-
266
- /**
267
- * Hash template for comparison
268
- */
269
- private hashTemplate(template: string): string {
270
- return createHash('sha256').update(template).digest('hex')
271
- }
272
-
273
- /**
274
- * Clear all templates
275
- */
276
- clear(): void {
277
- this.cache.clear()
278
- }
279
-
280
- /**
281
- * Prune expired templates
282
- */
283
- prune(): void {
284
- this.cache.prune()
285
- }
286
- }
287
-
288
- /**
289
- * Global template cache instance
290
- */
291
- export const templateCache: TemplateCache = new TemplateCache()
package/src/utils/diff.ts DELETED
@@ -1,269 +0,0 @@
1
- /**
2
- * Template diff utilities for incremental deployments
3
- * Detect changes between CloudFormation templates to optimize deployments
4
- */
5
-
6
- import type { CloudFormationTemplate } from '../cloudformation/types'
7
-
8
- export interface TemplateDiff {
9
- added: string[] // Resource logical IDs
10
- modified: string[] // Resource logical IDs
11
- deleted: string[] // Resource logical IDs
12
- unchanged: string[] // Resource logical IDs
13
- parametersChanged: boolean
14
- outputsChanged: boolean
15
- hasChanges: boolean
16
- }
17
-
18
- /**
19
- * Compare two CloudFormation templates
20
- */
21
- export function diffTemplates(
22
- oldTemplate: CloudFormationTemplate,
23
- newTemplate: CloudFormationTemplate,
24
- ): TemplateDiff {
25
- const added: string[] = []
26
- const modified: string[] = []
27
- const deleted: string[] = []
28
- const unchanged: string[] = []
29
-
30
- const oldResources = oldTemplate.Resources || {}
31
- const newResources = newTemplate.Resources || {}
32
-
33
- const oldResourceIds = new Set(Object.keys(oldResources))
34
- const newResourceIds = new Set(Object.keys(newResources))
35
-
36
- // Find added resources
37
- for (const id of newResourceIds) {
38
- if (!oldResourceIds.has(id)) {
39
- added.push(id)
40
- }
41
- }
42
-
43
- // Find deleted resources
44
- for (const id of oldResourceIds) {
45
- if (!newResourceIds.has(id)) {
46
- deleted.push(id)
47
- }
48
- }
49
-
50
- // Find modified resources
51
- for (const id of newResourceIds) {
52
- if (oldResourceIds.has(id)) {
53
- const oldResource = oldResources[id]
54
- const newResource = newResources[id]
55
-
56
- if (JSON.stringify(oldResource) !== JSON.stringify(newResource)) {
57
- modified.push(id)
58
- }
59
- else {
60
- unchanged.push(id)
61
- }
62
- }
63
- }
64
-
65
- // Check if parameters changed
66
- const parametersChanged = JSON.stringify(oldTemplate.Parameters || {})
67
- !== JSON.stringify(newTemplate.Parameters || {})
68
-
69
- // Check if outputs changed
70
- const outputsChanged = JSON.stringify(oldTemplate.Outputs || {})
71
- !== JSON.stringify(newTemplate.Outputs || {})
72
-
73
- return {
74
- added,
75
- modified,
76
- deleted,
77
- unchanged,
78
- parametersChanged,
79
- outputsChanged,
80
- hasChanges: added.length > 0 || modified.length > 0 || deleted.length > 0 || parametersChanged || outputsChanged,
81
- }
82
- }
83
-
84
- /**
85
- * Get diff summary string
86
- */
87
- export function getDiffSummary(diff: TemplateDiff): string {
88
- const lines: string[] = []
89
-
90
- if (!diff.hasChanges) {
91
- return 'No changes detected'
92
- }
93
-
94
- if (diff.added.length > 0) {
95
- lines.push(`Added resources (${diff.added.length}):`)
96
- for (const id of diff.added) {
97
- lines.push(` + ${id}`)
98
- }
99
- }
100
-
101
- if (diff.modified.length > 0) {
102
- lines.push(`Modified resources (${diff.modified.length}):`)
103
- for (const id of diff.modified) {
104
- lines.push(` ~ ${id}`)
105
- }
106
- }
107
-
108
- if (diff.deleted.length > 0) {
109
- lines.push(`Deleted resources (${diff.deleted.length}):`)
110
- for (const id of diff.deleted) {
111
- lines.push(` - ${id}`)
112
- }
113
- }
114
-
115
- if (diff.parametersChanged) {
116
- lines.push('Parameters changed')
117
- }
118
-
119
- if (diff.outputsChanged) {
120
- lines.push('Outputs changed')
121
- }
122
-
123
- return lines.join('\n')
124
- }
125
-
126
- /**
127
- * Check if diff requires replacement (destructive changes)
128
- */
129
- export function requiresReplacement(
130
- diff: TemplateDiff,
131
- oldTemplate: CloudFormationTemplate,
132
- newTemplate: CloudFormationTemplate,
133
- ): boolean {
134
- // If any resources are deleted, it requires replacement
135
- if (diff.deleted.length > 0) {
136
- return true
137
- }
138
-
139
- // Check modified resources for replacement-requiring changes
140
- for (const id of diff.modified) {
141
- const oldResource = oldTemplate.Resources[id]
142
- const newResource = newTemplate.Resources[id]
143
-
144
- // If resource type changed, it requires replacement
145
- if (oldResource.Type !== newResource.Type) {
146
- return true
147
- }
148
-
149
- // Check if properties that require replacement changed
150
- // This is a simplified check - in reality, each resource type has specific properties
151
- const replacementProperties = getReplacementProperties(newResource.Type)
152
-
153
- for (const prop of replacementProperties) {
154
- const oldValue = oldResource.Properties?.[prop]
155
- const newValue = newResource.Properties?.[prop]
156
-
157
- if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
158
- return true
159
- }
160
- }
161
- }
162
-
163
- return false
164
- }
165
-
166
- /**
167
- * Get properties that require replacement when changed
168
- * This is a simplified version - production code should use CloudFormation property docs
169
- */
170
- function getReplacementProperties(resourceType: string): string[] {
171
- const replacementProps: Record<string, string[]> = {
172
- 'AWS::S3::Bucket': ['BucketName'],
173
- 'AWS::EC2::Instance': ['ImageId', 'InstanceType', 'KeyName'],
174
- 'AWS::RDS::DBInstance': ['DBInstanceIdentifier', 'Engine'],
175
- 'AWS::DynamoDB::Table': ['TableName', 'KeySchema'],
176
- 'AWS::Lambda::Function': ['FunctionName'],
177
- 'AWS::ECS::Service': ['ServiceName'],
178
- 'AWS::ElasticLoadBalancingV2::LoadBalancer': ['Name', 'Type'],
179
- }
180
-
181
- return replacementProps[resourceType] || []
182
- }
183
-
184
- /**
185
- * Categorize changes by risk level
186
- */
187
- export function categorizeChanges(diff: TemplateDiff): {
188
- safe: string[]
189
- caution: string[]
190
- dangerous: string[]
191
- } {
192
- const safe: string[] = []
193
- const caution: string[] = []
194
- const dangerous: string[] = []
195
-
196
- // Additions are generally safe
197
- safe.push(...diff.added)
198
-
199
- // Modifications need to be categorized
200
- // This is simplified - real implementation would analyze specific property changes
201
- for (const id of diff.modified) {
202
- // For now, mark all modifications as caution
203
- caution.push(id)
204
- }
205
-
206
- // Deletions are dangerous
207
- dangerous.push(...diff.deleted)
208
-
209
- return { safe, caution, dangerous }
210
- }
211
-
212
- /**
213
- * Get deployment strategy based on diff
214
- */
215
- export function getDeploymentStrategy(diff: TemplateDiff): {
216
- strategy: 'create' | 'update' | 'replace' | 'skip'
217
- reason: string
218
- } {
219
- if (!diff.hasChanges) {
220
- return {
221
- strategy: 'skip',
222
- reason: 'No changes detected',
223
- }
224
- }
225
-
226
- if (diff.deleted.length > 0) {
227
- return {
228
- strategy: 'replace',
229
- reason: 'Resources will be deleted',
230
- }
231
- }
232
-
233
- if (diff.added.length > 0 && diff.modified.length === 0) {
234
- return {
235
- strategy: 'update',
236
- reason: 'Only new resources added',
237
- }
238
- }
239
-
240
- return {
241
- strategy: 'update',
242
- reason: 'Resources will be updated',
243
- }
244
- }
245
-
246
- /**
247
- * Calculate diff statistics
248
- */
249
- export function getDiffStats(diff: TemplateDiff): {
250
- total: number
251
- added: number
252
- modified: number
253
- deleted: number
254
- unchanged: number
255
- changePercentage: number
256
- } {
257
- const total = diff.added.length + diff.modified.length + diff.deleted.length + diff.unchanged.length
258
- const changes = diff.added.length + diff.modified.length + diff.deleted.length
259
- const changePercentage = total > 0 ? (changes / total) * 100 : 0
260
-
261
- return {
262
- total,
263
- added: diff.added.length,
264
- modified: diff.modified.length,
265
- deleted: diff.deleted.length,
266
- unchanged: diff.unchanged.length,
267
- changePercentage,
268
- }
269
- }