@stacksjs/ts-cloud 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.
Files changed (77) hide show
  1. package/dist/aws/s3.d.ts +1 -1
  2. package/dist/bin/cli.js +223 -222
  3. package/dist/index.js +132 -132
  4. package/package.json +18 -16
  5. package/src/aws/acm.ts +768 -0
  6. package/src/aws/application-autoscaling.ts +845 -0
  7. package/src/aws/bedrock.ts +4074 -0
  8. package/src/aws/client.ts +891 -0
  9. package/src/aws/cloudformation.ts +896 -0
  10. package/src/aws/cloudfront.ts +1531 -0
  11. package/src/aws/cloudwatch-logs.ts +154 -0
  12. package/src/aws/comprehend.ts +839 -0
  13. package/src/aws/connect.ts +1056 -0
  14. package/src/aws/deploy-imap.ts +384 -0
  15. package/src/aws/dynamodb.ts +340 -0
  16. package/src/aws/ec2.ts +1385 -0
  17. package/src/aws/ecr.ts +621 -0
  18. package/src/aws/ecs.ts +615 -0
  19. package/src/aws/elasticache.ts +301 -0
  20. package/src/aws/elbv2.ts +942 -0
  21. package/src/aws/email.ts +928 -0
  22. package/src/aws/eventbridge.ts +248 -0
  23. package/src/aws/iam.ts +1689 -0
  24. package/src/aws/imap-server.ts +2100 -0
  25. package/src/aws/index.ts +213 -0
  26. package/src/aws/kendra.ts +1097 -0
  27. package/src/aws/lambda.ts +786 -0
  28. package/src/aws/opensearch.ts +158 -0
  29. package/src/aws/personalize.ts +977 -0
  30. package/src/aws/polly.ts +559 -0
  31. package/src/aws/rds.ts +888 -0
  32. package/src/aws/rekognition.ts +846 -0
  33. package/src/aws/route53-domains.ts +359 -0
  34. package/src/aws/route53.ts +1046 -0
  35. package/src/aws/s3.ts +2334 -0
  36. package/src/aws/scheduler.ts +571 -0
  37. package/src/aws/secrets-manager.ts +769 -0
  38. package/src/aws/ses.ts +1081 -0
  39. package/src/aws/setup-phone.ts +104 -0
  40. package/src/aws/setup-sms.ts +580 -0
  41. package/src/aws/sms.ts +1735 -0
  42. package/src/aws/smtp-server.ts +531 -0
  43. package/src/aws/sns.ts +758 -0
  44. package/src/aws/sqs.ts +382 -0
  45. package/src/aws/ssm.ts +807 -0
  46. package/src/aws/sts.ts +92 -0
  47. package/src/aws/support.ts +391 -0
  48. package/src/aws/test-imap.ts +86 -0
  49. package/src/aws/textract.ts +780 -0
  50. package/src/aws/transcribe.ts +108 -0
  51. package/src/aws/translate.ts +641 -0
  52. package/src/aws/voice.ts +1379 -0
  53. package/src/config.ts +35 -0
  54. package/src/deploy/index.ts +7 -0
  55. package/src/deploy/static-site-external-dns.ts +945 -0
  56. package/src/deploy/static-site.ts +1175 -0
  57. package/src/dns/cloudflare.ts +548 -0
  58. package/src/dns/godaddy.ts +412 -0
  59. package/src/dns/index.ts +205 -0
  60. package/src/dns/porkbun.ts +362 -0
  61. package/src/dns/route53-adapter.ts +414 -0
  62. package/src/dns/types.ts +119 -0
  63. package/src/dns/validator.ts +369 -0
  64. package/src/generators/index.ts +5 -0
  65. package/src/generators/infrastructure.ts +1660 -0
  66. package/src/index.ts +163 -0
  67. package/src/push/apns.ts +452 -0
  68. package/src/push/fcm.ts +506 -0
  69. package/src/push/index.ts +58 -0
  70. package/src/security/pre-deploy-scanner.ts +655 -0
  71. package/src/ssl/acme-client.ts +478 -0
  72. package/src/ssl/index.ts +7 -0
  73. package/src/ssl/letsencrypt.ts +747 -0
  74. package/src/types.ts +2 -0
  75. package/src/utils/cli.ts +398 -0
  76. package/src/validation/index.ts +5 -0
  77. package/src/validation/template.ts +405 -0
package/src/aws/rds.ts ADDED
@@ -0,0 +1,888 @@
1
+ /**
2
+ * AWS RDS Operations
3
+ * Direct API calls without AWS CLI dependency
4
+ */
5
+
6
+ import { AWSClient, buildQueryParams } from './client'
7
+
8
+ export interface DBInstance {
9
+ DBInstanceIdentifier?: string
10
+ DBInstanceClass?: string
11
+ Engine?: string
12
+ EngineVersion?: string
13
+ DBInstanceStatus?: string
14
+ MasterUsername?: string
15
+ DBName?: string
16
+ Endpoint?: {
17
+ Address?: string
18
+ Port?: number
19
+ HostedZoneId?: string
20
+ }
21
+ AllocatedStorage?: number
22
+ InstanceCreateTime?: string
23
+ PreferredBackupWindow?: string
24
+ BackupRetentionPeriod?: number
25
+ DBSecurityGroups?: Array<{
26
+ DBSecurityGroupName?: string
27
+ Status?: string
28
+ }>
29
+ VpcSecurityGroups?: Array<{
30
+ VpcSecurityGroupId?: string
31
+ Status?: string
32
+ }>
33
+ DBParameterGroups?: Array<{
34
+ DBParameterGroupName?: string
35
+ ParameterApplyStatus?: string
36
+ }>
37
+ AvailabilityZone?: string
38
+ DBSubnetGroup?: {
39
+ DBSubnetGroupName?: string
40
+ DBSubnetGroupDescription?: string
41
+ VpcId?: string
42
+ SubnetGroupStatus?: string
43
+ Subnets?: Array<{
44
+ SubnetIdentifier?: string
45
+ SubnetAvailabilityZone?: { Name?: string }
46
+ SubnetStatus?: string
47
+ }>
48
+ }
49
+ PreferredMaintenanceWindow?: string
50
+ PendingModifiedValues?: Record<string, any>
51
+ MultiAZ?: boolean
52
+ AutoMinorVersionUpgrade?: boolean
53
+ ReadReplicaSourceDBInstanceIdentifier?: string
54
+ ReadReplicaDBInstanceIdentifiers?: string[]
55
+ LicenseModel?: string
56
+ OptionGroupMemberships?: Array<{
57
+ OptionGroupName?: string
58
+ Status?: string
59
+ }>
60
+ PubliclyAccessible?: boolean
61
+ StorageType?: string
62
+ StorageEncrypted?: boolean
63
+ KmsKeyId?: string
64
+ DbiResourceId?: string
65
+ CACertificateIdentifier?: string
66
+ DeletionProtection?: boolean
67
+ TagList?: Array<{ Key?: string; Value?: string }>
68
+ }
69
+
70
+ export interface DBCluster {
71
+ DBClusterIdentifier?: string
72
+ DBClusterArn?: string
73
+ Status?: string
74
+ Engine?: string
75
+ EngineVersion?: string
76
+ Endpoint?: string
77
+ ReaderEndpoint?: string
78
+ Port?: number
79
+ MasterUsername?: string
80
+ DatabaseName?: string
81
+ PreferredBackupWindow?: string
82
+ PreferredMaintenanceWindow?: string
83
+ MultiAZ?: boolean
84
+ EngineMode?: string
85
+ DBClusterMembers?: Array<{
86
+ DBInstanceIdentifier?: string
87
+ IsClusterWriter?: boolean
88
+ DBClusterParameterGroupStatus?: string
89
+ }>
90
+ VpcSecurityGroups?: Array<{
91
+ VpcSecurityGroupId?: string
92
+ Status?: string
93
+ }>
94
+ HostedZoneId?: string
95
+ StorageEncrypted?: boolean
96
+ KmsKeyId?: string
97
+ DeletionProtection?: boolean
98
+ TagList?: Array<{ Key?: string; Value?: string }>
99
+ }
100
+
101
+ export interface DBSnapshot {
102
+ DBSnapshotIdentifier?: string
103
+ DBInstanceIdentifier?: string
104
+ SnapshotCreateTime?: string
105
+ Engine?: string
106
+ AllocatedStorage?: number
107
+ Status?: string
108
+ Port?: number
109
+ AvailabilityZone?: string
110
+ VpcId?: string
111
+ InstanceCreateTime?: string
112
+ MasterUsername?: string
113
+ EngineVersion?: string
114
+ LicenseModel?: string
115
+ SnapshotType?: string
116
+ OptionGroupName?: string
117
+ PercentProgress?: number
118
+ SourceRegion?: string
119
+ StorageType?: string
120
+ Encrypted?: boolean
121
+ KmsKeyId?: string
122
+ DBSnapshotArn?: string
123
+ }
124
+
125
+ export interface DBSubnetGroup {
126
+ DBSubnetGroupName?: string
127
+ DBSubnetGroupDescription?: string
128
+ VpcId?: string
129
+ SubnetGroupStatus?: string
130
+ Subnets?: Array<{
131
+ SubnetIdentifier?: string
132
+ SubnetAvailabilityZone?: { Name?: string }
133
+ SubnetStatus?: string
134
+ }>
135
+ DBSubnetGroupArn?: string
136
+ }
137
+
138
+ /**
139
+ * RDS service management using direct API calls
140
+ */
141
+ export class RDSClient {
142
+ private client: AWSClient
143
+ private region: string
144
+
145
+ constructor(region: string = 'us-east-1') {
146
+ this.region = region
147
+ this.client = new AWSClient()
148
+ }
149
+
150
+ /**
151
+ * Describe all RDS DB instances
152
+ */
153
+ async describeDBInstances(options?: {
154
+ DBInstanceIdentifier?: string
155
+ Filters?: Array<{ Name: string; Values: string[] }>
156
+ MaxRecords?: number
157
+ Marker?: string
158
+ }): Promise<{ DBInstances?: DBInstance[]; Marker?: string }> {
159
+ const params: Record<string, any> = {
160
+ Action: 'DescribeDBInstances',
161
+ Version: '2014-10-31',
162
+ }
163
+
164
+ if (options?.DBInstanceIdentifier) {
165
+ params.DBInstanceIdentifier = options.DBInstanceIdentifier
166
+ }
167
+
168
+ if (options?.MaxRecords) {
169
+ params.MaxRecords = options.MaxRecords
170
+ }
171
+
172
+ if (options?.Marker) {
173
+ params.Marker = options.Marker
174
+ }
175
+
176
+ if (options?.Filters) {
177
+ options.Filters.forEach((filter, i) => {
178
+ params[`Filters.Filter.${i + 1}.Name`] = filter.Name
179
+ filter.Values.forEach((value, j) => {
180
+ params[`Filters.Filter.${i + 1}.Values.Value.${j + 1}`] = value
181
+ })
182
+ })
183
+ }
184
+
185
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
186
+
187
+ const result = await this.client.request({
188
+ service: 'rds',
189
+ region: this.region,
190
+ method: 'POST',
191
+ path: '/',
192
+ headers: {
193
+ 'Content-Type': 'application/x-www-form-urlencoded',
194
+ },
195
+ body: queryString,
196
+ })
197
+
198
+ // Parse the response - RDS returns XML wrapped in DescribeDBInstancesResult
199
+ const response = result.DescribeDBInstancesResult || result
200
+
201
+ // Handle array vs single instance
202
+ let instances = response.DBInstances?.DBInstance || []
203
+ if (!Array.isArray(instances)) {
204
+ instances = instances ? [instances] : []
205
+ }
206
+
207
+ return {
208
+ DBInstances: instances,
209
+ Marker: response.Marker,
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Describe a specific DB instance
215
+ */
216
+ async describeDBInstance(dbInstanceIdentifier: string): Promise<DBInstance | undefined> {
217
+ const result = await this.describeDBInstances({ DBInstanceIdentifier: dbInstanceIdentifier })
218
+ return result.DBInstances?.[0]
219
+ }
220
+
221
+ /**
222
+ * Describe all RDS DB clusters (Aurora)
223
+ */
224
+ async describeDBClusters(options?: {
225
+ DBClusterIdentifier?: string
226
+ Filters?: Array<{ Name: string; Values: string[] }>
227
+ MaxRecords?: number
228
+ Marker?: string
229
+ }): Promise<{ DBClusters?: DBCluster[]; Marker?: string }> {
230
+ const params: Record<string, any> = {
231
+ Action: 'DescribeDBClusters',
232
+ Version: '2014-10-31',
233
+ }
234
+
235
+ if (options?.DBClusterIdentifier) {
236
+ params.DBClusterIdentifier = options.DBClusterIdentifier
237
+ }
238
+
239
+ if (options?.MaxRecords) {
240
+ params.MaxRecords = options.MaxRecords
241
+ }
242
+
243
+ if (options?.Marker) {
244
+ params.Marker = options.Marker
245
+ }
246
+
247
+ if (options?.Filters) {
248
+ options.Filters.forEach((filter, i) => {
249
+ params[`Filters.Filter.${i + 1}.Name`] = filter.Name
250
+ filter.Values.forEach((value, j) => {
251
+ params[`Filters.Filter.${i + 1}.Values.Value.${j + 1}`] = value
252
+ })
253
+ })
254
+ }
255
+
256
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
257
+
258
+ const result = await this.client.request({
259
+ service: 'rds',
260
+ region: this.region,
261
+ method: 'POST',
262
+ path: '/',
263
+ headers: {
264
+ 'Content-Type': 'application/x-www-form-urlencoded',
265
+ },
266
+ body: queryString,
267
+ })
268
+
269
+ const response = result.DescribeDBClustersResult || result
270
+
271
+ let clusters = response.DBClusters?.DBCluster || []
272
+ if (!Array.isArray(clusters)) {
273
+ clusters = clusters ? [clusters] : []
274
+ }
275
+
276
+ return {
277
+ DBClusters: clusters,
278
+ Marker: response.Marker,
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Describe DB snapshots
284
+ */
285
+ async describeDBSnapshots(options?: {
286
+ DBInstanceIdentifier?: string
287
+ DBSnapshotIdentifier?: string
288
+ SnapshotType?: 'automated' | 'manual' | 'shared' | 'public' | 'awsbackup'
289
+ MaxRecords?: number
290
+ Marker?: string
291
+ }): Promise<{ DBSnapshots?: DBSnapshot[]; Marker?: string }> {
292
+ const params: Record<string, any> = {
293
+ Action: 'DescribeDBSnapshots',
294
+ Version: '2014-10-31',
295
+ }
296
+
297
+ if (options?.DBInstanceIdentifier) {
298
+ params.DBInstanceIdentifier = options.DBInstanceIdentifier
299
+ }
300
+
301
+ if (options?.DBSnapshotIdentifier) {
302
+ params.DBSnapshotIdentifier = options.DBSnapshotIdentifier
303
+ }
304
+
305
+ if (options?.SnapshotType) {
306
+ params.SnapshotType = options.SnapshotType
307
+ }
308
+
309
+ if (options?.MaxRecords) {
310
+ params.MaxRecords = options.MaxRecords
311
+ }
312
+
313
+ if (options?.Marker) {
314
+ params.Marker = options.Marker
315
+ }
316
+
317
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
318
+
319
+ const result = await this.client.request({
320
+ service: 'rds',
321
+ region: this.region,
322
+ method: 'POST',
323
+ path: '/',
324
+ headers: {
325
+ 'Content-Type': 'application/x-www-form-urlencoded',
326
+ },
327
+ body: queryString,
328
+ })
329
+
330
+ const response = result.DescribeDBSnapshotsResult || result
331
+
332
+ let snapshots = response.DBSnapshots?.DBSnapshot || []
333
+ if (!Array.isArray(snapshots)) {
334
+ snapshots = snapshots ? [snapshots] : []
335
+ }
336
+
337
+ return {
338
+ DBSnapshots: snapshots,
339
+ Marker: response.Marker,
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Describe DB subnet groups
345
+ */
346
+ async describeDBSubnetGroups(options?: {
347
+ DBSubnetGroupName?: string
348
+ MaxRecords?: number
349
+ Marker?: string
350
+ }): Promise<{ DBSubnetGroups?: DBSubnetGroup[]; Marker?: string }> {
351
+ const params: Record<string, any> = {
352
+ Action: 'DescribeDBSubnetGroups',
353
+ Version: '2014-10-31',
354
+ }
355
+
356
+ if (options?.DBSubnetGroupName) {
357
+ params.DBSubnetGroupName = options.DBSubnetGroupName
358
+ }
359
+
360
+ if (options?.MaxRecords) {
361
+ params.MaxRecords = options.MaxRecords
362
+ }
363
+
364
+ if (options?.Marker) {
365
+ params.Marker = options.Marker
366
+ }
367
+
368
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
369
+
370
+ const result = await this.client.request({
371
+ service: 'rds',
372
+ region: this.region,
373
+ method: 'POST',
374
+ path: '/',
375
+ headers: {
376
+ 'Content-Type': 'application/x-www-form-urlencoded',
377
+ },
378
+ body: queryString,
379
+ })
380
+
381
+ const response = result.DescribeDBSubnetGroupsResult || result
382
+
383
+ let groups = response.DBSubnetGroups?.DBSubnetGroup || []
384
+ if (!Array.isArray(groups)) {
385
+ groups = groups ? [groups] : []
386
+ }
387
+
388
+ return {
389
+ DBSubnetGroups: groups,
390
+ Marker: response.Marker,
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Create a new DB instance
396
+ */
397
+ async createDBInstance(options: {
398
+ DBInstanceIdentifier: string
399
+ DBInstanceClass: string
400
+ Engine: string
401
+ MasterUsername?: string
402
+ MasterUserPassword?: string
403
+ DBName?: string
404
+ AllocatedStorage?: number
405
+ VpcSecurityGroupIds?: string[]
406
+ DBSubnetGroupName?: string
407
+ AvailabilityZone?: string
408
+ PreferredMaintenanceWindow?: string
409
+ PreferredBackupWindow?: string
410
+ BackupRetentionPeriod?: number
411
+ MultiAZ?: boolean
412
+ EngineVersion?: string
413
+ AutoMinorVersionUpgrade?: boolean
414
+ LicenseModel?: string
415
+ PubliclyAccessible?: boolean
416
+ StorageType?: 'gp2' | 'gp3' | 'io1' | 'standard'
417
+ StorageEncrypted?: boolean
418
+ KmsKeyId?: string
419
+ DeletionProtection?: boolean
420
+ Tags?: Array<{ Key: string; Value: string }>
421
+ }): Promise<{ DBInstance?: DBInstance }> {
422
+ const params: Record<string, any> = {
423
+ Action: 'CreateDBInstance',
424
+ Version: '2014-10-31',
425
+ DBInstanceIdentifier: options.DBInstanceIdentifier,
426
+ DBInstanceClass: options.DBInstanceClass,
427
+ Engine: options.Engine,
428
+ }
429
+
430
+ if (options.MasterUsername) params.MasterUsername = options.MasterUsername
431
+ if (options.MasterUserPassword) params.MasterUserPassword = options.MasterUserPassword
432
+ if (options.DBName) params.DBName = options.DBName
433
+ if (options.AllocatedStorage) params.AllocatedStorage = options.AllocatedStorage
434
+ if (options.DBSubnetGroupName) params.DBSubnetGroupName = options.DBSubnetGroupName
435
+ if (options.AvailabilityZone) params.AvailabilityZone = options.AvailabilityZone
436
+ if (options.PreferredMaintenanceWindow) params.PreferredMaintenanceWindow = options.PreferredMaintenanceWindow
437
+ if (options.PreferredBackupWindow) params.PreferredBackupWindow = options.PreferredBackupWindow
438
+ if (options.BackupRetentionPeriod !== undefined) params.BackupRetentionPeriod = options.BackupRetentionPeriod
439
+ if (options.MultiAZ !== undefined) params.MultiAZ = options.MultiAZ
440
+ if (options.EngineVersion) params.EngineVersion = options.EngineVersion
441
+ if (options.AutoMinorVersionUpgrade !== undefined) params.AutoMinorVersionUpgrade = options.AutoMinorVersionUpgrade
442
+ if (options.LicenseModel) params.LicenseModel = options.LicenseModel
443
+ if (options.PubliclyAccessible !== undefined) params.PubliclyAccessible = options.PubliclyAccessible
444
+ if (options.StorageType) params.StorageType = options.StorageType
445
+ if (options.StorageEncrypted !== undefined) params.StorageEncrypted = options.StorageEncrypted
446
+ if (options.KmsKeyId) params.KmsKeyId = options.KmsKeyId
447
+ if (options.DeletionProtection !== undefined) params.DeletionProtection = options.DeletionProtection
448
+
449
+ if (options.VpcSecurityGroupIds) {
450
+ options.VpcSecurityGroupIds.forEach((id, i) => {
451
+ params[`VpcSecurityGroupIds.VpcSecurityGroupId.${i + 1}`] = id
452
+ })
453
+ }
454
+
455
+ if (options.Tags) {
456
+ options.Tags.forEach((tag, i) => {
457
+ params[`Tags.Tag.${i + 1}.Key`] = tag.Key
458
+ params[`Tags.Tag.${i + 1}.Value`] = tag.Value
459
+ })
460
+ }
461
+
462
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
463
+
464
+ const result = await this.client.request({
465
+ service: 'rds',
466
+ region: this.region,
467
+ method: 'POST',
468
+ path: '/',
469
+ headers: {
470
+ 'Content-Type': 'application/x-www-form-urlencoded',
471
+ },
472
+ body: queryString,
473
+ })
474
+
475
+ const response = result.CreateDBInstanceResult || result
476
+ return {
477
+ DBInstance: response.DBInstance,
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Delete a DB instance
483
+ */
484
+ async deleteDBInstance(options: {
485
+ DBInstanceIdentifier: string
486
+ SkipFinalSnapshot?: boolean
487
+ FinalDBSnapshotIdentifier?: string
488
+ DeleteAutomatedBackups?: boolean
489
+ }): Promise<{ DBInstance?: DBInstance }> {
490
+ const params: Record<string, any> = {
491
+ Action: 'DeleteDBInstance',
492
+ Version: '2014-10-31',
493
+ DBInstanceIdentifier: options.DBInstanceIdentifier,
494
+ }
495
+
496
+ if (options.SkipFinalSnapshot !== undefined) {
497
+ params.SkipFinalSnapshot = options.SkipFinalSnapshot
498
+ }
499
+
500
+ if (options.FinalDBSnapshotIdentifier) {
501
+ params.FinalDBSnapshotIdentifier = options.FinalDBSnapshotIdentifier
502
+ }
503
+
504
+ if (options.DeleteAutomatedBackups !== undefined) {
505
+ params.DeleteAutomatedBackups = options.DeleteAutomatedBackups
506
+ }
507
+
508
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
509
+
510
+ const result = await this.client.request({
511
+ service: 'rds',
512
+ region: this.region,
513
+ method: 'POST',
514
+ path: '/',
515
+ headers: {
516
+ 'Content-Type': 'application/x-www-form-urlencoded',
517
+ },
518
+ body: queryString,
519
+ })
520
+
521
+ const response = result.DeleteDBInstanceResult || result
522
+ return {
523
+ DBInstance: response.DBInstance,
524
+ }
525
+ }
526
+
527
+ /**
528
+ * Modify a DB instance
529
+ */
530
+ async modifyDBInstance(options: {
531
+ DBInstanceIdentifier: string
532
+ DBInstanceClass?: string
533
+ AllocatedStorage?: number
534
+ MasterUserPassword?: string
535
+ BackupRetentionPeriod?: number
536
+ PreferredBackupWindow?: string
537
+ PreferredMaintenanceWindow?: string
538
+ MultiAZ?: boolean
539
+ EngineVersion?: string
540
+ AutoMinorVersionUpgrade?: boolean
541
+ PubliclyAccessible?: boolean
542
+ VpcSecurityGroupIds?: string[]
543
+ ApplyImmediately?: boolean
544
+ StorageType?: 'gp2' | 'gp3' | 'io1' | 'standard'
545
+ DeletionProtection?: boolean
546
+ }): Promise<{ DBInstance?: DBInstance }> {
547
+ const params: Record<string, any> = {
548
+ Action: 'ModifyDBInstance',
549
+ Version: '2014-10-31',
550
+ DBInstanceIdentifier: options.DBInstanceIdentifier,
551
+ }
552
+
553
+ if (options.DBInstanceClass) params.DBInstanceClass = options.DBInstanceClass
554
+ if (options.AllocatedStorage) params.AllocatedStorage = options.AllocatedStorage
555
+ if (options.MasterUserPassword) params.MasterUserPassword = options.MasterUserPassword
556
+ if (options.BackupRetentionPeriod !== undefined) params.BackupRetentionPeriod = options.BackupRetentionPeriod
557
+ if (options.PreferredBackupWindow) params.PreferredBackupWindow = options.PreferredBackupWindow
558
+ if (options.PreferredMaintenanceWindow) params.PreferredMaintenanceWindow = options.PreferredMaintenanceWindow
559
+ if (options.MultiAZ !== undefined) params.MultiAZ = options.MultiAZ
560
+ if (options.EngineVersion) params.EngineVersion = options.EngineVersion
561
+ if (options.AutoMinorVersionUpgrade !== undefined) params.AutoMinorVersionUpgrade = options.AutoMinorVersionUpgrade
562
+ if (options.PubliclyAccessible !== undefined) params.PubliclyAccessible = options.PubliclyAccessible
563
+ if (options.ApplyImmediately !== undefined) params.ApplyImmediately = options.ApplyImmediately
564
+ if (options.StorageType) params.StorageType = options.StorageType
565
+ if (options.DeletionProtection !== undefined) params.DeletionProtection = options.DeletionProtection
566
+
567
+ if (options.VpcSecurityGroupIds) {
568
+ options.VpcSecurityGroupIds.forEach((id, i) => {
569
+ params[`VpcSecurityGroupIds.VpcSecurityGroupId.${i + 1}`] = id
570
+ })
571
+ }
572
+
573
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
574
+
575
+ const result = await this.client.request({
576
+ service: 'rds',
577
+ region: this.region,
578
+ method: 'POST',
579
+ path: '/',
580
+ headers: {
581
+ 'Content-Type': 'application/x-www-form-urlencoded',
582
+ },
583
+ body: queryString,
584
+ })
585
+
586
+ const response = result.ModifyDBInstanceResult || result
587
+ return {
588
+ DBInstance: response.DBInstance,
589
+ }
590
+ }
591
+
592
+ /**
593
+ * Start a DB instance
594
+ */
595
+ async startDBInstance(dbInstanceIdentifier: string): Promise<{ DBInstance?: DBInstance }> {
596
+ const params: Record<string, any> = {
597
+ Action: 'StartDBInstance',
598
+ Version: '2014-10-31',
599
+ DBInstanceIdentifier: dbInstanceIdentifier,
600
+ }
601
+
602
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
603
+
604
+ const result = await this.client.request({
605
+ service: 'rds',
606
+ region: this.region,
607
+ method: 'POST',
608
+ path: '/',
609
+ headers: {
610
+ 'Content-Type': 'application/x-www-form-urlencoded',
611
+ },
612
+ body: queryString,
613
+ })
614
+
615
+ const response = result.StartDBInstanceResult || result
616
+ return {
617
+ DBInstance: response.DBInstance,
618
+ }
619
+ }
620
+
621
+ /**
622
+ * Stop a DB instance
623
+ */
624
+ async stopDBInstance(options: {
625
+ DBInstanceIdentifier: string
626
+ DBSnapshotIdentifier?: string
627
+ }): Promise<{ DBInstance?: DBInstance }> {
628
+ const params: Record<string, any> = {
629
+ Action: 'StopDBInstance',
630
+ Version: '2014-10-31',
631
+ DBInstanceIdentifier: options.DBInstanceIdentifier,
632
+ }
633
+
634
+ if (options.DBSnapshotIdentifier) {
635
+ params.DBSnapshotIdentifier = options.DBSnapshotIdentifier
636
+ }
637
+
638
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
639
+
640
+ const result = await this.client.request({
641
+ service: 'rds',
642
+ region: this.region,
643
+ method: 'POST',
644
+ path: '/',
645
+ headers: {
646
+ 'Content-Type': 'application/x-www-form-urlencoded',
647
+ },
648
+ body: queryString,
649
+ })
650
+
651
+ const response = result.StopDBInstanceResult || result
652
+ return {
653
+ DBInstance: response.DBInstance,
654
+ }
655
+ }
656
+
657
+ /**
658
+ * Reboot a DB instance
659
+ */
660
+ async rebootDBInstance(options: {
661
+ DBInstanceIdentifier: string
662
+ ForceFailover?: boolean
663
+ }): Promise<{ DBInstance?: DBInstance }> {
664
+ const params: Record<string, any> = {
665
+ Action: 'RebootDBInstance',
666
+ Version: '2014-10-31',
667
+ DBInstanceIdentifier: options.DBInstanceIdentifier,
668
+ }
669
+
670
+ if (options.ForceFailover !== undefined) {
671
+ params.ForceFailover = options.ForceFailover
672
+ }
673
+
674
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
675
+
676
+ const result = await this.client.request({
677
+ service: 'rds',
678
+ region: this.region,
679
+ method: 'POST',
680
+ path: '/',
681
+ headers: {
682
+ 'Content-Type': 'application/x-www-form-urlencoded',
683
+ },
684
+ body: queryString,
685
+ })
686
+
687
+ const response = result.RebootDBInstanceResult || result
688
+ return {
689
+ DBInstance: response.DBInstance,
690
+ }
691
+ }
692
+
693
+ /**
694
+ * Create a DB snapshot
695
+ */
696
+ async createDBSnapshot(options: {
697
+ DBInstanceIdentifier: string
698
+ DBSnapshotIdentifier: string
699
+ Tags?: Array<{ Key: string; Value: string }>
700
+ }): Promise<{ DBSnapshot?: DBSnapshot }> {
701
+ const params: Record<string, any> = {
702
+ Action: 'CreateDBSnapshot',
703
+ Version: '2014-10-31',
704
+ DBInstanceIdentifier: options.DBInstanceIdentifier,
705
+ DBSnapshotIdentifier: options.DBSnapshotIdentifier,
706
+ }
707
+
708
+ if (options.Tags) {
709
+ options.Tags.forEach((tag, i) => {
710
+ params[`Tags.Tag.${i + 1}.Key`] = tag.Key
711
+ params[`Tags.Tag.${i + 1}.Value`] = tag.Value
712
+ })
713
+ }
714
+
715
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
716
+
717
+ const result = await this.client.request({
718
+ service: 'rds',
719
+ region: this.region,
720
+ method: 'POST',
721
+ path: '/',
722
+ headers: {
723
+ 'Content-Type': 'application/x-www-form-urlencoded',
724
+ },
725
+ body: queryString,
726
+ })
727
+
728
+ const response = result.CreateDBSnapshotResult || result
729
+ return {
730
+ DBSnapshot: response.DBSnapshot,
731
+ }
732
+ }
733
+
734
+ /**
735
+ * Delete a DB snapshot
736
+ */
737
+ async deleteDBSnapshot(dbSnapshotIdentifier: string): Promise<{ DBSnapshot?: DBSnapshot }> {
738
+ const params: Record<string, any> = {
739
+ Action: 'DeleteDBSnapshot',
740
+ Version: '2014-10-31',
741
+ DBSnapshotIdentifier: dbSnapshotIdentifier,
742
+ }
743
+
744
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
745
+
746
+ const result = await this.client.request({
747
+ service: 'rds',
748
+ region: this.region,
749
+ method: 'POST',
750
+ path: '/',
751
+ headers: {
752
+ 'Content-Type': 'application/x-www-form-urlencoded',
753
+ },
754
+ body: queryString,
755
+ })
756
+
757
+ const response = result.DeleteDBSnapshotResult || result
758
+ return {
759
+ DBSnapshot: response.DBSnapshot,
760
+ }
761
+ }
762
+
763
+ /**
764
+ * Restore DB instance from snapshot
765
+ */
766
+ async restoreDBInstanceFromDBSnapshot(options: {
767
+ DBInstanceIdentifier: string
768
+ DBSnapshotIdentifier: string
769
+ DBInstanceClass?: string
770
+ Port?: number
771
+ AvailabilityZone?: string
772
+ DBSubnetGroupName?: string
773
+ MultiAZ?: boolean
774
+ PubliclyAccessible?: boolean
775
+ AutoMinorVersionUpgrade?: boolean
776
+ StorageType?: 'gp2' | 'gp3' | 'io1' | 'standard'
777
+ VpcSecurityGroupIds?: string[]
778
+ DeletionProtection?: boolean
779
+ Tags?: Array<{ Key: string; Value: string }>
780
+ }): Promise<{ DBInstance?: DBInstance }> {
781
+ const params: Record<string, any> = {
782
+ Action: 'RestoreDBInstanceFromDBSnapshot',
783
+ Version: '2014-10-31',
784
+ DBInstanceIdentifier: options.DBInstanceIdentifier,
785
+ DBSnapshotIdentifier: options.DBSnapshotIdentifier,
786
+ }
787
+
788
+ if (options.DBInstanceClass) params.DBInstanceClass = options.DBInstanceClass
789
+ if (options.Port) params.Port = options.Port
790
+ if (options.AvailabilityZone) params.AvailabilityZone = options.AvailabilityZone
791
+ if (options.DBSubnetGroupName) params.DBSubnetGroupName = options.DBSubnetGroupName
792
+ if (options.MultiAZ !== undefined) params.MultiAZ = options.MultiAZ
793
+ if (options.PubliclyAccessible !== undefined) params.PubliclyAccessible = options.PubliclyAccessible
794
+ if (options.AutoMinorVersionUpgrade !== undefined) params.AutoMinorVersionUpgrade = options.AutoMinorVersionUpgrade
795
+ if (options.StorageType) params.StorageType = options.StorageType
796
+ if (options.DeletionProtection !== undefined) params.DeletionProtection = options.DeletionProtection
797
+
798
+ if (options.VpcSecurityGroupIds) {
799
+ options.VpcSecurityGroupIds.forEach((id, i) => {
800
+ params[`VpcSecurityGroupIds.VpcSecurityGroupId.${i + 1}`] = id
801
+ })
802
+ }
803
+
804
+ if (options.Tags) {
805
+ options.Tags.forEach((tag, i) => {
806
+ params[`Tags.Tag.${i + 1}.Key`] = tag.Key
807
+ params[`Tags.Tag.${i + 1}.Value`] = tag.Value
808
+ })
809
+ }
810
+
811
+ const queryString = new URLSearchParams(buildQueryParams(params)).toString()
812
+
813
+ const result = await this.client.request({
814
+ service: 'rds',
815
+ region: this.region,
816
+ method: 'POST',
817
+ path: '/',
818
+ headers: {
819
+ 'Content-Type': 'application/x-www-form-urlencoded',
820
+ },
821
+ body: queryString,
822
+ })
823
+
824
+ const response = result.RestoreDBInstanceFromDBSnapshotResult || result
825
+ return {
826
+ DBInstance: response.DBInstance,
827
+ }
828
+ }
829
+
830
+ /**
831
+ * Wait for DB instance to become available
832
+ */
833
+ async waitForDBInstanceAvailable(
834
+ dbInstanceIdentifier: string,
835
+ maxAttempts = 60,
836
+ delayMs = 30000
837
+ ): Promise<DBInstance | undefined> {
838
+ for (let i = 0; i < maxAttempts; i++) {
839
+ const instance = await this.describeDBInstance(dbInstanceIdentifier)
840
+
841
+ if (instance?.DBInstanceStatus === 'available') {
842
+ return instance
843
+ }
844
+
845
+ // Check for terminal states
846
+ if (['deleted', 'failed', 'incompatible-restore', 'incompatible-parameters'].includes(instance?.DBInstanceStatus || '')) {
847
+ throw new Error(`DB instance ${dbInstanceIdentifier} is in terminal state: ${instance?.DBInstanceStatus}`)
848
+ }
849
+
850
+ await new Promise(resolve => setTimeout(resolve, delayMs))
851
+ }
852
+
853
+ throw new Error(`Timeout waiting for DB instance ${dbInstanceIdentifier} to become available`)
854
+ }
855
+
856
+ /**
857
+ * Wait for DB instance to be deleted
858
+ */
859
+ async waitForDBInstanceDeleted(
860
+ dbInstanceIdentifier: string,
861
+ maxAttempts = 60,
862
+ delayMs = 30000
863
+ ): Promise<void> {
864
+ for (let i = 0; i < maxAttempts; i++) {
865
+ try {
866
+ const instance = await this.describeDBInstance(dbInstanceIdentifier)
867
+
868
+ // Still exists, check state
869
+ if (instance?.DBInstanceStatus === 'deleting') {
870
+ await new Promise(resolve => setTimeout(resolve, delayMs))
871
+ continue
872
+ }
873
+
874
+ // If it exists but not deleting, there might be an issue
875
+ throw new Error(`DB instance ${dbInstanceIdentifier} is in state: ${instance?.DBInstanceStatus}`)
876
+ }
877
+ catch (error: any) {
878
+ // DBInstanceNotFound means it's deleted
879
+ if (error.code === 'DBInstanceNotFound' || error.code === 'DBInstanceNotFoundFault') {
880
+ return
881
+ }
882
+ throw error
883
+ }
884
+ }
885
+
886
+ throw new Error(`Timeout waiting for DB instance ${dbInstanceIdentifier} to be deleted`)
887
+ }
888
+ }