@stacksjs/ts-cloud 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.
Files changed (117) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +321 -0
  3. package/bin/cli.ts +133 -0
  4. package/bin/commands/analytics.ts +328 -0
  5. package/bin/commands/api.ts +379 -0
  6. package/bin/commands/assets.ts +221 -0
  7. package/bin/commands/audit.ts +501 -0
  8. package/bin/commands/backup.ts +682 -0
  9. package/bin/commands/cache.ts +294 -0
  10. package/bin/commands/cdn.ts +281 -0
  11. package/bin/commands/config.ts +202 -0
  12. package/bin/commands/container.ts +105 -0
  13. package/bin/commands/cost.ts +208 -0
  14. package/bin/commands/database.ts +401 -0
  15. package/bin/commands/deploy.ts +674 -0
  16. package/bin/commands/domain.ts +397 -0
  17. package/bin/commands/email.ts +423 -0
  18. package/bin/commands/environment.ts +285 -0
  19. package/bin/commands/events.ts +424 -0
  20. package/bin/commands/firewall.ts +145 -0
  21. package/bin/commands/function.ts +116 -0
  22. package/bin/commands/generate.ts +280 -0
  23. package/bin/commands/git.ts +139 -0
  24. package/bin/commands/iam.ts +464 -0
  25. package/bin/commands/index.ts +48 -0
  26. package/bin/commands/init.ts +120 -0
  27. package/bin/commands/logs.ts +148 -0
  28. package/bin/commands/network.ts +579 -0
  29. package/bin/commands/notify.ts +489 -0
  30. package/bin/commands/queue.ts +407 -0
  31. package/bin/commands/scheduler.ts +370 -0
  32. package/bin/commands/secrets.ts +54 -0
  33. package/bin/commands/server.ts +629 -0
  34. package/bin/commands/shared.ts +97 -0
  35. package/bin/commands/ssl.ts +138 -0
  36. package/bin/commands/stack.ts +325 -0
  37. package/bin/commands/status.ts +385 -0
  38. package/bin/commands/storage.ts +450 -0
  39. package/bin/commands/team.ts +96 -0
  40. package/bin/commands/tunnel.ts +489 -0
  41. package/bin/commands/utils.ts +202 -0
  42. package/build.ts +15 -0
  43. package/cloud +2 -0
  44. package/package.json +99 -0
  45. package/src/aws/acm.ts +768 -0
  46. package/src/aws/application-autoscaling.ts +845 -0
  47. package/src/aws/bedrock.ts +4074 -0
  48. package/src/aws/client.ts +878 -0
  49. package/src/aws/cloudformation.ts +896 -0
  50. package/src/aws/cloudfront.ts +1531 -0
  51. package/src/aws/cloudwatch-logs.ts +154 -0
  52. package/src/aws/comprehend.ts +839 -0
  53. package/src/aws/connect.ts +1056 -0
  54. package/src/aws/deploy-imap.ts +384 -0
  55. package/src/aws/dynamodb.ts +340 -0
  56. package/src/aws/ec2.ts +1385 -0
  57. package/src/aws/ecr.ts +621 -0
  58. package/src/aws/ecs.ts +615 -0
  59. package/src/aws/elasticache.ts +301 -0
  60. package/src/aws/elbv2.ts +942 -0
  61. package/src/aws/email.ts +928 -0
  62. package/src/aws/eventbridge.ts +248 -0
  63. package/src/aws/iam.ts +1689 -0
  64. package/src/aws/imap-server.ts +2100 -0
  65. package/src/aws/index.ts +213 -0
  66. package/src/aws/kendra.ts +1097 -0
  67. package/src/aws/lambda.ts +786 -0
  68. package/src/aws/opensearch.ts +158 -0
  69. package/src/aws/personalize.ts +977 -0
  70. package/src/aws/polly.ts +559 -0
  71. package/src/aws/rds.ts +888 -0
  72. package/src/aws/rekognition.ts +846 -0
  73. package/src/aws/route53-domains.ts +359 -0
  74. package/src/aws/route53.ts +1046 -0
  75. package/src/aws/s3.ts +2318 -0
  76. package/src/aws/scheduler.ts +571 -0
  77. package/src/aws/secrets-manager.ts +769 -0
  78. package/src/aws/ses.ts +1081 -0
  79. package/src/aws/setup-phone.ts +104 -0
  80. package/src/aws/setup-sms.ts +580 -0
  81. package/src/aws/sms.ts +1735 -0
  82. package/src/aws/smtp-server.ts +531 -0
  83. package/src/aws/sns.ts +758 -0
  84. package/src/aws/sqs.ts +382 -0
  85. package/src/aws/ssm.ts +807 -0
  86. package/src/aws/sts.ts +92 -0
  87. package/src/aws/support.ts +391 -0
  88. package/src/aws/test-imap.ts +86 -0
  89. package/src/aws/textract.ts +780 -0
  90. package/src/aws/transcribe.ts +108 -0
  91. package/src/aws/translate.ts +641 -0
  92. package/src/aws/voice.ts +1379 -0
  93. package/src/config.ts +35 -0
  94. package/src/deploy/index.ts +7 -0
  95. package/src/deploy/static-site-external-dns.ts +906 -0
  96. package/src/deploy/static-site.ts +1125 -0
  97. package/src/dns/godaddy.ts +412 -0
  98. package/src/dns/index.ts +183 -0
  99. package/src/dns/porkbun.ts +362 -0
  100. package/src/dns/route53-adapter.ts +414 -0
  101. package/src/dns/types.ts +114 -0
  102. package/src/dns/validator.ts +369 -0
  103. package/src/generators/index.ts +5 -0
  104. package/src/generators/infrastructure.ts +1660 -0
  105. package/src/index.ts +163 -0
  106. package/src/push/apns.ts +452 -0
  107. package/src/push/fcm.ts +506 -0
  108. package/src/push/index.ts +58 -0
  109. package/src/ssl/acme-client.ts +478 -0
  110. package/src/ssl/index.ts +7 -0
  111. package/src/ssl/letsencrypt.ts +747 -0
  112. package/src/types.ts +2 -0
  113. package/src/utils/cli.ts +398 -0
  114. package/src/validation/index.ts +5 -0
  115. package/src/validation/template.ts +405 -0
  116. package/test/index.test.ts +128 -0
  117. package/tsconfig.json +18 -0
@@ -0,0 +1,370 @@
1
+ import type { CLI } from '@stacksjs/clapp'
2
+ import * as cli from '../../src/utils/cli'
3
+ import { SchedulerClient, type Schedule, type ScheduleGroup } from '../../src/aws/scheduler'
4
+ import { loadValidatedConfig } from './shared'
5
+
6
+ export function registerSchedulerCommands(app: CLI): void {
7
+ app
8
+ .command('scheduler:list', 'List all EventBridge schedules')
9
+ .option('--region <region>', 'AWS region')
10
+ .option('--group <name>', 'Schedule group name', { default: 'default' })
11
+ .action(async (options: { region?: string; group: string }) => {
12
+ cli.header('EventBridge Schedules')
13
+
14
+ try {
15
+ const config = await loadValidatedConfig()
16
+ const region = options.region || config.project.region || 'us-east-1'
17
+ const scheduler = new SchedulerClient(region)
18
+
19
+ const spinner = new cli.Spinner('Fetching schedules...')
20
+ spinner.start()
21
+
22
+ const result = await scheduler.listSchedules({ GroupName: options.group })
23
+ const schedules = result.Schedules || []
24
+
25
+ spinner.succeed(`Found ${schedules.length} schedule(s)`)
26
+
27
+ if (schedules.length === 0) {
28
+ cli.info('No schedules found')
29
+ cli.info('Use `cloud scheduler:create` to create a new schedule')
30
+ return
31
+ }
32
+
33
+ cli.table(
34
+ ['Name', 'State', 'Schedule Expression', 'Group'],
35
+ schedules.map((s: Schedule) => [
36
+ s.Name || 'N/A',
37
+ s.State || 'N/A',
38
+ s.ScheduleExpression || 'N/A',
39
+ s.GroupName || 'default',
40
+ ]),
41
+ )
42
+ }
43
+ catch (error: any) {
44
+ cli.error(`Failed to list schedules: ${error.message}`)
45
+ process.exit(1)
46
+ }
47
+ })
48
+
49
+ app
50
+ .command('scheduler:create <name>', 'Create a new EventBridge schedule')
51
+ .option('--region <region>', 'AWS region', { default: 'us-east-1' })
52
+ .option('--schedule <expression>', 'Schedule expression (rate or cron)')
53
+ .option('--target-arn <arn>', 'Target ARN (Lambda, SQS, SNS, etc.)')
54
+ .option('--role-arn <arn>', 'IAM role ARN for scheduler')
55
+ .option('--input <json>', 'JSON input to pass to target')
56
+ .option('--group <name>', 'Schedule group name', { default: 'default' })
57
+ .option('--timezone <tz>', 'Timezone for cron expressions', { default: 'UTC' })
58
+ .option('--description <text>', 'Schedule description')
59
+ .option('--start <datetime>', 'Start date/time (ISO 8601)')
60
+ .option('--end <datetime>', 'End date/time (ISO 8601)')
61
+ .action(async (name: string, options: {
62
+ region: string
63
+ schedule?: string
64
+ targetArn?: string
65
+ roleArn?: string
66
+ input?: string
67
+ group: string
68
+ timezone: string
69
+ description?: string
70
+ start?: string
71
+ end?: string
72
+ }) => {
73
+ cli.header('Create EventBridge Schedule')
74
+
75
+ try {
76
+ if (!options.schedule) {
77
+ cli.error('--schedule is required')
78
+ cli.info('Examples:')
79
+ cli.info(' Rate: rate(5 minutes), rate(1 hour), rate(1 day)')
80
+ cli.info(' Cron: cron(0 12 * * ? *) - every day at 12:00 UTC')
81
+ return
82
+ }
83
+
84
+ if (!options.targetArn) {
85
+ cli.error('--target-arn is required')
86
+ return
87
+ }
88
+
89
+ if (!options.roleArn) {
90
+ cli.error('--role-arn is required')
91
+ cli.info('The role must have permissions to invoke the target.')
92
+ return
93
+ }
94
+
95
+ const scheduler = new SchedulerClient(options.region)
96
+
97
+ cli.info(`Name: ${name}`)
98
+ cli.info(`Schedule: ${options.schedule}`)
99
+ cli.info(`Target: ${options.targetArn}`)
100
+ cli.info(`Group: ${options.group}`)
101
+ cli.info(`Timezone: ${options.timezone}`)
102
+
103
+ const confirmed = await cli.confirm('\nCreate this schedule?', true)
104
+ if (!confirmed) {
105
+ cli.info('Operation cancelled')
106
+ return
107
+ }
108
+
109
+ const spinner = new cli.Spinner('Creating schedule...')
110
+ spinner.start()
111
+
112
+ await scheduler.createSchedule({
113
+ Name: name,
114
+ GroupName: options.group,
115
+ ScheduleExpression: options.schedule,
116
+ ScheduleExpressionTimezone: options.timezone,
117
+ Description: options.description,
118
+ State: 'ENABLED',
119
+ FlexibleTimeWindow: {
120
+ Mode: 'OFF',
121
+ },
122
+ Target: {
123
+ Arn: options.targetArn,
124
+ RoleArn: options.roleArn,
125
+ Input: options.input,
126
+ },
127
+ StartDate: options.start ? new Date(options.start) : undefined,
128
+ EndDate: options.end ? new Date(options.end) : undefined,
129
+ })
130
+
131
+ spinner.succeed('Schedule created')
132
+
133
+ cli.success(`\nSchedule: ${name}`)
134
+ cli.info(`Expression: ${options.schedule}`)
135
+ }
136
+ catch (error: any) {
137
+ cli.error(`Failed to create schedule: ${error.message}`)
138
+ process.exit(1)
139
+ }
140
+ })
141
+
142
+ app
143
+ .command('scheduler:delete <name>', 'Delete an EventBridge schedule')
144
+ .option('--region <region>', 'AWS region', { default: 'us-east-1' })
145
+ .option('--group <name>', 'Schedule group name', { default: 'default' })
146
+ .action(async (name: string, options: { region: string; group: string }) => {
147
+ cli.header('Delete EventBridge Schedule')
148
+
149
+ try {
150
+ const scheduler = new SchedulerClient(options.region)
151
+
152
+ cli.warn(`This will delete schedule: ${name}`)
153
+
154
+ const confirmed = await cli.confirm('\nDelete this schedule?', false)
155
+ if (!confirmed) {
156
+ cli.info('Operation cancelled')
157
+ return
158
+ }
159
+
160
+ const spinner = new cli.Spinner('Deleting schedule...')
161
+ spinner.start()
162
+
163
+ await scheduler.deleteSchedule({
164
+ Name: name,
165
+ GroupName: options.group,
166
+ })
167
+
168
+ spinner.succeed('Schedule deleted')
169
+ }
170
+ catch (error: any) {
171
+ cli.error(`Failed to delete schedule: ${error.message}`)
172
+ process.exit(1)
173
+ }
174
+ })
175
+
176
+ app
177
+ .command('scheduler:enable <name>', 'Enable an EventBridge schedule')
178
+ .option('--region <region>', 'AWS region', { default: 'us-east-1' })
179
+ .option('--group <name>', 'Schedule group name', { default: 'default' })
180
+ .action(async (name: string, options: { region: string; group: string }) => {
181
+ cli.header('Enable EventBridge Schedule')
182
+
183
+ try {
184
+ const scheduler = new SchedulerClient(options.region)
185
+
186
+ const spinner = new cli.Spinner('Getting schedule...')
187
+ spinner.start()
188
+
189
+ // Get current schedule
190
+ const current = await scheduler.getSchedule({
191
+ Name: name,
192
+ GroupName: options.group,
193
+ })
194
+
195
+ if (!current) {
196
+ spinner.fail('Schedule not found')
197
+ return
198
+ }
199
+
200
+ spinner.text = 'Enabling schedule...'
201
+
202
+ await scheduler.updateSchedule({
203
+ Name: name,
204
+ GroupName: options.group,
205
+ ScheduleExpression: current.ScheduleExpression,
206
+ ScheduleExpressionTimezone: current.ScheduleExpressionTimezone,
207
+ FlexibleTimeWindow: current.FlexibleTimeWindow,
208
+ Target: current.Target,
209
+ State: 'ENABLED',
210
+ })
211
+
212
+ spinner.succeed('Schedule enabled')
213
+ }
214
+ catch (error: any) {
215
+ cli.error(`Failed to enable schedule: ${error.message}`)
216
+ process.exit(1)
217
+ }
218
+ })
219
+
220
+ app
221
+ .command('scheduler:disable <name>', 'Disable an EventBridge schedule')
222
+ .option('--region <region>', 'AWS region', { default: 'us-east-1' })
223
+ .option('--group <name>', 'Schedule group name', { default: 'default' })
224
+ .action(async (name: string, options: { region: string; group: string }) => {
225
+ cli.header('Disable EventBridge Schedule')
226
+
227
+ try {
228
+ const scheduler = new SchedulerClient(options.region)
229
+
230
+ const spinner = new cli.Spinner('Getting schedule...')
231
+ spinner.start()
232
+
233
+ // Get current schedule
234
+ const current = await scheduler.getSchedule({
235
+ Name: name,
236
+ GroupName: options.group,
237
+ })
238
+
239
+ if (!current) {
240
+ spinner.fail('Schedule not found')
241
+ return
242
+ }
243
+
244
+ spinner.text = 'Disabling schedule...'
245
+
246
+ await scheduler.updateSchedule({
247
+ Name: name,
248
+ GroupName: options.group,
249
+ ScheduleExpression: current.ScheduleExpression,
250
+ ScheduleExpressionTimezone: current.ScheduleExpressionTimezone,
251
+ FlexibleTimeWindow: current.FlexibleTimeWindow,
252
+ Target: current.Target,
253
+ State: 'DISABLED',
254
+ })
255
+
256
+ spinner.succeed('Schedule disabled')
257
+ }
258
+ catch (error: any) {
259
+ cli.error(`Failed to disable schedule: ${error.message}`)
260
+ process.exit(1)
261
+ }
262
+ })
263
+
264
+ app
265
+ .command('scheduler:describe <name>', 'Show EventBridge schedule details')
266
+ .option('--region <region>', 'AWS region', { default: 'us-east-1' })
267
+ .option('--group <name>', 'Schedule group name', { default: 'default' })
268
+ .action(async (name: string, options: { region: string; group: string }) => {
269
+ cli.header(`Schedule: ${name}`)
270
+
271
+ try {
272
+ const scheduler = new SchedulerClient(options.region)
273
+
274
+ const spinner = new cli.Spinner('Fetching schedule...')
275
+ spinner.start()
276
+
277
+ const schedule = await scheduler.getSchedule({
278
+ Name: name,
279
+ GroupName: options.group,
280
+ })
281
+
282
+ if (!schedule) {
283
+ spinner.fail('Schedule not found')
284
+ return
285
+ }
286
+
287
+ spinner.succeed('Schedule loaded')
288
+
289
+ cli.info('\nSchedule Information:')
290
+ cli.info(` Name: ${schedule.Name}`)
291
+ cli.info(` ARN: ${schedule.Arn}`)
292
+ cli.info(` Group: ${schedule.GroupName}`)
293
+ cli.info(` State: ${schedule.State}`)
294
+ cli.info(` Expression: ${schedule.ScheduleExpression}`)
295
+ cli.info(` Timezone: ${schedule.ScheduleExpressionTimezone}`)
296
+
297
+ if (schedule.Description) {
298
+ cli.info(` Description: ${schedule.Description}`)
299
+ }
300
+
301
+ if (schedule.Target) {
302
+ cli.info('\nTarget:')
303
+ cli.info(` ARN: ${schedule.Target.Arn}`)
304
+ cli.info(` Role ARN: ${schedule.Target.RoleArn}`)
305
+ if (schedule.Target.Input) {
306
+ cli.info(` Input: ${schedule.Target.Input}`)
307
+ }
308
+ }
309
+
310
+ cli.info('\nFlexible Time Window:')
311
+ cli.info(` Mode: ${schedule.FlexibleTimeWindow?.Mode}`)
312
+ if (schedule.FlexibleTimeWindow?.MaximumWindowInMinutes) {
313
+ cli.info(` Max Window: ${schedule.FlexibleTimeWindow.MaximumWindowInMinutes} minutes`)
314
+ }
315
+
316
+ if (schedule.StartDate) {
317
+ cli.info(`\nStart Date: ${schedule.StartDate}`)
318
+ }
319
+ if (schedule.EndDate) {
320
+ cli.info(`End Date: ${schedule.EndDate}`)
321
+ }
322
+
323
+ cli.info(`\nCreated: ${schedule.CreationDate || 'N/A'}`)
324
+ cli.info(`Last Modified: ${schedule.LastModificationDate || 'N/A'}`)
325
+ }
326
+ catch (error: any) {
327
+ cli.error(`Failed to get schedule: ${error.message}`)
328
+ process.exit(1)
329
+ }
330
+ })
331
+
332
+ app
333
+ .command('scheduler:groups', 'List schedule groups')
334
+ .option('--region <region>', 'AWS region')
335
+ .action(async (options: { region?: string }) => {
336
+ cli.header('Schedule Groups')
337
+
338
+ try {
339
+ const config = await loadValidatedConfig()
340
+ const region = options.region || config.project.region || 'us-east-1'
341
+ const scheduler = new SchedulerClient(region)
342
+
343
+ const spinner = new cli.Spinner('Fetching groups...')
344
+ spinner.start()
345
+
346
+ const result = await scheduler.listScheduleGroups()
347
+ const groups = result.ScheduleGroups || []
348
+
349
+ spinner.succeed(`Found ${groups.length} group(s)`)
350
+
351
+ if (groups.length === 0) {
352
+ cli.info('No schedule groups found')
353
+ return
354
+ }
355
+
356
+ cli.table(
357
+ ['Name', 'State', 'Created'],
358
+ groups.map((g: ScheduleGroup) => [
359
+ g.Name || 'N/A',
360
+ g.State || 'N/A',
361
+ g.CreationDate ? new Date(g.CreationDate).toLocaleString() : 'N/A',
362
+ ]),
363
+ )
364
+ }
365
+ catch (error: any) {
366
+ cli.error(`Failed to list groups: ${error.message}`)
367
+ process.exit(1)
368
+ }
369
+ })
370
+ }
@@ -0,0 +1,54 @@
1
+ import type { CLI } from '@stacksjs/clapp'
2
+ import * as cli from '../../src/utils/cli'
3
+
4
+ export function registerSecretsCommands(app: CLI): void {
5
+ app
6
+ .command('secrets:list', 'List all secrets')
7
+ .action(async () => {
8
+ cli.header('Secrets')
9
+
10
+ const secrets = [
11
+ ['database-password', 'Last rotated 30 days ago'],
12
+ ['api-key', 'Last rotated 15 days ago'],
13
+ ]
14
+
15
+ cli.table(
16
+ ['Name', 'Status'],
17
+ secrets,
18
+ )
19
+ })
20
+
21
+ app
22
+ .command('secrets:set <key> <value>', 'Set a secret')
23
+ .action(async (key: string, value: string) => {
24
+ cli.header('Setting Secret')
25
+
26
+ const spinner = new cli.Spinner(`Storing secret ${key}...`)
27
+ spinner.start()
28
+
29
+ // TODO: Store in AWS Secrets Manager
30
+ await new Promise(resolve => setTimeout(resolve, 1000))
31
+
32
+ spinner.succeed(`Secret ${key} stored successfully`)
33
+ cli.warn('Secret value is encrypted and stored in AWS Secrets Manager')
34
+ })
35
+
36
+ app
37
+ .command('secrets:get <key>', 'Get secret value')
38
+ .action(async (key: string) => {
39
+ cli.header('Getting Secret')
40
+
41
+ const spinner = new cli.Spinner(`Retrieving secret ${key}...`)
42
+ spinner.start()
43
+
44
+ // TODO: Fetch from AWS Secrets Manager
45
+ await new Promise(resolve => setTimeout(resolve, 1000))
46
+
47
+ spinner.stop()
48
+
49
+ cli.success(`\nSecret: ${key}`)
50
+ cli.info('Value: ************')
51
+ cli.warn('\nSecret values are hidden for security')
52
+ cli.info('To view the actual value, use AWS Console or AWS CLI with --query')
53
+ })
54
+ }