@stacksjs/ts-cloud 0.1.3 → 0.1.5

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 (187) hide show
  1. package/README.md +98 -13
  2. package/dist/aws/acm.d.ts +129 -0
  3. package/dist/aws/application-autoscaling.d.ts +282 -0
  4. package/dist/aws/bedrock.d.ts +2292 -0
  5. package/dist/aws/client.d.ts +79 -0
  6. package/dist/aws/cloudformation.d.ts +105 -0
  7. package/dist/aws/cloudfront.d.ts +265 -0
  8. package/dist/aws/cloudwatch-logs.d.ts +48 -0
  9. package/dist/aws/comprehend.d.ts +505 -0
  10. package/dist/aws/connect.d.ts +377 -0
  11. package/dist/aws/deploy-imap.d.ts +14 -0
  12. package/dist/aws/dynamodb.d.ts +176 -0
  13. package/dist/aws/ec2.d.ts +272 -0
  14. package/dist/aws/ecr.d.ts +149 -0
  15. package/dist/aws/ecs.d.ts +162 -0
  16. package/dist/aws/elasticache.d.ts +71 -0
  17. package/dist/aws/elbv2.d.ts +248 -0
  18. package/dist/aws/email.d.ts +175 -0
  19. package/dist/aws/eventbridge.d.ts +142 -0
  20. package/dist/aws/iam.d.ts +638 -0
  21. package/dist/aws/imap-server.d.ts +119 -0
  22. package/{src/aws/index.ts → dist/aws/index.d.ts} +62 -83
  23. package/{src/aws/kendra.ts → dist/aws/kendra.d.ts} +71 -386
  24. package/dist/aws/lambda.d.ts +232 -0
  25. package/dist/aws/opensearch.d.ts +87 -0
  26. package/dist/aws/personalize.d.ts +516 -0
  27. package/dist/aws/polly.d.ts +214 -0
  28. package/dist/aws/rds.d.ts +240 -0
  29. package/dist/aws/rekognition.d.ts +543 -0
  30. package/dist/aws/route53-domains.d.ts +113 -0
  31. package/dist/aws/route53.d.ts +215 -0
  32. package/dist/aws/s3.d.ts +212 -0
  33. package/dist/aws/scheduler.d.ts +140 -0
  34. package/dist/aws/secrets-manager.d.ts +170 -0
  35. package/dist/aws/ses.d.ts +288 -0
  36. package/dist/aws/setup-phone.d.ts +0 -0
  37. package/dist/aws/setup-sms.d.ts +115 -0
  38. package/dist/aws/sms.d.ts +304 -0
  39. package/dist/aws/smtp-server.d.ts +61 -0
  40. package/dist/aws/sns.d.ts +117 -0
  41. package/dist/aws/sqs.d.ts +65 -0
  42. package/dist/aws/ssm.d.ts +179 -0
  43. package/dist/aws/sts.d.ts +15 -0
  44. package/dist/aws/support.d.ts +104 -0
  45. package/dist/aws/test-imap.d.ts +0 -0
  46. package/dist/aws/textract.d.ts +403 -0
  47. package/dist/aws/transcribe.d.ts +60 -0
  48. package/dist/aws/translate.d.ts +358 -0
  49. package/dist/aws/voice.d.ts +219 -0
  50. package/dist/bin/cli.js +1724 -0
  51. package/dist/config.d.ts +7 -0
  52. package/dist/deploy/index.d.ts +2 -0
  53. package/dist/deploy/static-site-external-dns.d.ts +51 -0
  54. package/dist/deploy/static-site.d.ts +71 -0
  55. package/dist/dns/cloudflare.d.ts +52 -0
  56. package/dist/dns/godaddy.d.ts +38 -0
  57. package/dist/dns/index.d.ts +45 -0
  58. package/dist/dns/porkbun.d.ts +18 -0
  59. package/dist/dns/route53-adapter.d.ts +38 -0
  60. package/{src/dns/types.ts → dist/dns/types.d.ts} +26 -63
  61. package/dist/dns/validator.d.ts +78 -0
  62. package/dist/generators/index.d.ts +1 -0
  63. package/dist/generators/infrastructure.d.ts +30 -0
  64. package/{src/index.ts → dist/index.d.ts} +70 -93
  65. package/dist/index.js +7881 -0
  66. package/dist/push/apns.d.ts +60 -0
  67. package/dist/push/fcm.d.ts +117 -0
  68. package/dist/push/index.d.ts +14 -0
  69. package/dist/security/pre-deploy-scanner.d.ts +69 -0
  70. package/dist/ssl/acme-client.d.ts +67 -0
  71. package/dist/ssl/index.d.ts +2 -0
  72. package/dist/ssl/letsencrypt.d.ts +48 -0
  73. package/dist/types.d.ts +1 -0
  74. package/dist/utils/cli.d.ts +123 -0
  75. package/dist/validation/index.d.ts +1 -0
  76. package/dist/validation/template.d.ts +23 -0
  77. package/package.json +8 -8
  78. package/bin/cli.ts +0 -133
  79. package/bin/commands/analytics.ts +0 -328
  80. package/bin/commands/api.ts +0 -379
  81. package/bin/commands/assets.ts +0 -221
  82. package/bin/commands/audit.ts +0 -501
  83. package/bin/commands/backup.ts +0 -682
  84. package/bin/commands/cache.ts +0 -294
  85. package/bin/commands/cdn.ts +0 -281
  86. package/bin/commands/config.ts +0 -202
  87. package/bin/commands/container.ts +0 -105
  88. package/bin/commands/cost.ts +0 -208
  89. package/bin/commands/database.ts +0 -401
  90. package/bin/commands/deploy.ts +0 -674
  91. package/bin/commands/domain.ts +0 -397
  92. package/bin/commands/email.ts +0 -423
  93. package/bin/commands/environment.ts +0 -285
  94. package/bin/commands/events.ts +0 -424
  95. package/bin/commands/firewall.ts +0 -145
  96. package/bin/commands/function.ts +0 -116
  97. package/bin/commands/generate.ts +0 -280
  98. package/bin/commands/git.ts +0 -139
  99. package/bin/commands/iam.ts +0 -464
  100. package/bin/commands/index.ts +0 -48
  101. package/bin/commands/init.ts +0 -120
  102. package/bin/commands/logs.ts +0 -148
  103. package/bin/commands/network.ts +0 -579
  104. package/bin/commands/notify.ts +0 -489
  105. package/bin/commands/queue.ts +0 -407
  106. package/bin/commands/scheduler.ts +0 -370
  107. package/bin/commands/secrets.ts +0 -54
  108. package/bin/commands/server.ts +0 -629
  109. package/bin/commands/shared.ts +0 -97
  110. package/bin/commands/ssl.ts +0 -138
  111. package/bin/commands/stack.ts +0 -325
  112. package/bin/commands/status.ts +0 -385
  113. package/bin/commands/storage.ts +0 -450
  114. package/bin/commands/team.ts +0 -96
  115. package/bin/commands/tunnel.ts +0 -489
  116. package/bin/commands/utils.ts +0 -202
  117. package/build.ts +0 -15
  118. package/cloud +0 -2
  119. package/src/aws/acm.ts +0 -768
  120. package/src/aws/application-autoscaling.ts +0 -845
  121. package/src/aws/bedrock.ts +0 -4074
  122. package/src/aws/client.ts +0 -878
  123. package/src/aws/cloudformation.ts +0 -896
  124. package/src/aws/cloudfront.ts +0 -1531
  125. package/src/aws/cloudwatch-logs.ts +0 -154
  126. package/src/aws/comprehend.ts +0 -839
  127. package/src/aws/connect.ts +0 -1056
  128. package/src/aws/deploy-imap.ts +0 -384
  129. package/src/aws/dynamodb.ts +0 -340
  130. package/src/aws/ec2.ts +0 -1385
  131. package/src/aws/ecr.ts +0 -621
  132. package/src/aws/ecs.ts +0 -615
  133. package/src/aws/elasticache.ts +0 -301
  134. package/src/aws/elbv2.ts +0 -942
  135. package/src/aws/email.ts +0 -928
  136. package/src/aws/eventbridge.ts +0 -248
  137. package/src/aws/iam.ts +0 -1689
  138. package/src/aws/imap-server.ts +0 -2100
  139. package/src/aws/lambda.ts +0 -786
  140. package/src/aws/opensearch.ts +0 -158
  141. package/src/aws/personalize.ts +0 -977
  142. package/src/aws/polly.ts +0 -559
  143. package/src/aws/rds.ts +0 -888
  144. package/src/aws/rekognition.ts +0 -846
  145. package/src/aws/route53-domains.ts +0 -359
  146. package/src/aws/route53.ts +0 -1046
  147. package/src/aws/s3.ts +0 -2318
  148. package/src/aws/scheduler.ts +0 -571
  149. package/src/aws/secrets-manager.ts +0 -769
  150. package/src/aws/ses.ts +0 -1081
  151. package/src/aws/setup-phone.ts +0 -104
  152. package/src/aws/setup-sms.ts +0 -580
  153. package/src/aws/sms.ts +0 -1735
  154. package/src/aws/smtp-server.ts +0 -531
  155. package/src/aws/sns.ts +0 -758
  156. package/src/aws/sqs.ts +0 -382
  157. package/src/aws/ssm.ts +0 -807
  158. package/src/aws/sts.ts +0 -92
  159. package/src/aws/support.ts +0 -391
  160. package/src/aws/test-imap.ts +0 -86
  161. package/src/aws/textract.ts +0 -780
  162. package/src/aws/transcribe.ts +0 -108
  163. package/src/aws/translate.ts +0 -641
  164. package/src/aws/voice.ts +0 -1379
  165. package/src/config.ts +0 -35
  166. package/src/deploy/index.ts +0 -7
  167. package/src/deploy/static-site-external-dns.ts +0 -906
  168. package/src/deploy/static-site.ts +0 -1125
  169. package/src/dns/godaddy.ts +0 -412
  170. package/src/dns/index.ts +0 -183
  171. package/src/dns/porkbun.ts +0 -362
  172. package/src/dns/route53-adapter.ts +0 -414
  173. package/src/dns/validator.ts +0 -369
  174. package/src/generators/index.ts +0 -5
  175. package/src/generators/infrastructure.ts +0 -1660
  176. package/src/push/apns.ts +0 -452
  177. package/src/push/fcm.ts +0 -506
  178. package/src/push/index.ts +0 -58
  179. package/src/ssl/acme-client.ts +0 -478
  180. package/src/ssl/index.ts +0 -7
  181. package/src/ssl/letsencrypt.ts +0 -747
  182. package/src/types.ts +0 -2
  183. package/src/utils/cli.ts +0 -398
  184. package/src/validation/index.ts +0 -5
  185. package/src/validation/template.ts +0 -405
  186. package/test/index.test.ts +0 -128
  187. package/tsconfig.json +0 -18
@@ -1,450 +0,0 @@
1
- import type { CLI } from '@stacksjs/clapp'
2
- import { readdirSync, statSync } from 'node:fs'
3
- import { join, relative } from 'node:path'
4
- import * as cli from '../../src/utils/cli'
5
- import { S3Client } from '../../src/aws/s3'
6
- import { loadValidatedConfig } from './shared'
7
-
8
- export function registerStorageCommands(app: CLI): void {
9
- app
10
- .command('storage:list', 'List all S3 buckets')
11
- .option('--region <region>', 'AWS region')
12
- .action(async (options: { region?: string }) => {
13
- cli.header('S3 Buckets')
14
-
15
- try {
16
- const config = await loadValidatedConfig()
17
- const region = options.region || config.project.region || 'us-east-1'
18
- const s3 = new S3Client(region)
19
-
20
- const spinner = new cli.Spinner('Fetching buckets...')
21
- spinner.start()
22
-
23
- const result = await s3.listBuckets()
24
- const buckets = result.Buckets || []
25
-
26
- spinner.succeed(`Found ${buckets.length} bucket(s)`)
27
-
28
- if (buckets.length === 0) {
29
- cli.info('No S3 buckets found')
30
- cli.info('Use `cloud storage:create` to create a new bucket')
31
- return
32
- }
33
-
34
- cli.table(
35
- ['Name', 'Created'],
36
- buckets.map(bucket => [
37
- bucket.Name || 'N/A',
38
- bucket.CreationDate ? new Date(bucket.CreationDate).toLocaleDateString() : 'N/A',
39
- ]),
40
- )
41
- }
42
- catch (error: any) {
43
- cli.error(`Failed to list buckets: ${error.message}`)
44
- process.exit(1)
45
- }
46
- })
47
-
48
- app
49
- .command('storage:create <name>', 'Create a new S3 bucket')
50
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
51
- .option('--public', 'Enable public access')
52
- .option('--versioning', 'Enable versioning')
53
- .action(async (name: string, options: { region: string; public?: boolean; versioning?: boolean }) => {
54
- cli.header('Create S3 Bucket')
55
-
56
- try {
57
- const s3 = new S3Client(options.region)
58
-
59
- cli.info(`Bucket name: ${name}`)
60
- cli.info(`Region: ${options.region}`)
61
- cli.info(`Public access: ${options.public ? 'Yes' : 'No'}`)
62
- cli.info(`Versioning: ${options.versioning ? 'Yes' : 'No'}`)
63
-
64
- const confirmed = await cli.confirm('\nCreate this bucket?', true)
65
- if (!confirmed) {
66
- cli.info('Operation cancelled')
67
- return
68
- }
69
-
70
- const spinner = new cli.Spinner('Creating bucket...')
71
- spinner.start()
72
-
73
- await s3.createBucket(name)
74
-
75
- // Block public access by default
76
- if (!options.public) {
77
- spinner.text = 'Configuring public access block...'
78
- await s3.putPublicAccessBlock(name, {
79
- BlockPublicAcls: true,
80
- IgnorePublicAcls: true,
81
- BlockPublicPolicy: true,
82
- RestrictPublicBuckets: true,
83
- })
84
- }
85
-
86
- // Enable versioning if requested
87
- if (options.versioning) {
88
- spinner.text = 'Enabling versioning...'
89
- await s3.putBucketVersioning(name, 'Enabled')
90
- }
91
-
92
- spinner.succeed('Bucket created')
93
-
94
- cli.success(`\nBucket: ${name}`)
95
- cli.info(`Region: ${options.region}`)
96
- cli.info(`URL: s3://${name}`)
97
- }
98
- catch (error: any) {
99
- cli.error(`Failed to create bucket: ${error.message}`)
100
- process.exit(1)
101
- }
102
- })
103
-
104
- app
105
- .command('storage:delete <name>', 'Delete an S3 bucket')
106
- .option('--force', 'Delete all objects first')
107
- .action(async (name: string, options: { force?: boolean }) => {
108
- cli.header('Delete S3 Bucket')
109
-
110
- try {
111
- const s3 = new S3Client('us-east-1')
112
-
113
- cli.warn(`This will permanently delete bucket: ${name}`)
114
- if (options.force) {
115
- cli.warn('All objects in the bucket will be deleted!')
116
- }
117
-
118
- const confirmed = await cli.confirm('\nDelete this bucket?', false)
119
- if (!confirmed) {
120
- cli.info('Operation cancelled')
121
- return
122
- }
123
-
124
- const spinner = new cli.Spinner('Deleting bucket...')
125
- spinner.start()
126
-
127
- if (options.force) {
128
- spinner.text = 'Emptying bucket...'
129
- await s3.emptyBucket(name)
130
- }
131
-
132
- await s3.deleteBucket(name)
133
-
134
- spinner.succeed('Bucket deleted')
135
- }
136
- catch (error: any) {
137
- cli.error(`Failed to delete bucket: ${error.message}`)
138
- process.exit(1)
139
- }
140
- })
141
-
142
- app
143
- .command('storage:sync <source> <bucket>', 'Sync local directory to S3 bucket')
144
- .option('--prefix <prefix>', 'S3 key prefix')
145
- .option('--delete', 'Delete files in S3 that are not in source')
146
- .option('--dry-run', 'Show what would be synced without making changes')
147
- .action(async (source: string, bucket: string, options: { prefix?: string; delete?: boolean; dryRun?: boolean }) => {
148
- cli.header('Sync to S3')
149
-
150
- try {
151
- const s3 = new S3Client('us-east-1')
152
-
153
- cli.info(`Source: ${source}`)
154
- cli.info(`Destination: s3://${bucket}/${options.prefix || ''}`)
155
-
156
- if (options.dryRun) {
157
- cli.info('Dry run mode - no changes will be made')
158
- }
159
-
160
- const spinner = new cli.Spinner('Scanning files...')
161
- spinner.start()
162
-
163
- // Get all local files
164
- const localFiles: { path: string; key: string; size: number }[] = []
165
-
166
- function scanDirectory(dir: string, baseDir: string) {
167
- const entries = readdirSync(dir, { withFileTypes: true })
168
- for (const entry of entries) {
169
- const fullPath = join(dir, entry.name)
170
- if (entry.isDirectory()) {
171
- scanDirectory(fullPath, baseDir)
172
- }
173
- else {
174
- const relativePath = relative(baseDir, fullPath)
175
- const key = options.prefix ? `${options.prefix}/${relativePath}` : relativePath
176
- const stats = statSync(fullPath)
177
- localFiles.push({ path: fullPath, key, size: stats.size })
178
- }
179
- }
180
- }
181
-
182
- scanDirectory(source, source)
183
-
184
- spinner.succeed(`Found ${localFiles.length} local file(s)`)
185
-
186
- if (localFiles.length === 0) {
187
- cli.info('No files to sync')
188
- return
189
- }
190
-
191
- // Show preview
192
- cli.info('\nFiles to sync:')
193
- for (const file of localFiles.slice(0, 10)) {
194
- cli.info(` ${file.key} (${(file.size / 1024).toFixed(2)} KB)`)
195
- }
196
- if (localFiles.length > 10) {
197
- cli.info(` ... and ${localFiles.length - 10} more`)
198
- }
199
-
200
- if (options.dryRun) {
201
- cli.info('\nDry run complete - no changes made')
202
- return
203
- }
204
-
205
- const confirmed = await cli.confirm('\nSync these files?', true)
206
- if (!confirmed) {
207
- cli.info('Operation cancelled')
208
- return
209
- }
210
-
211
- const uploadSpinner = new cli.Spinner('Uploading files...')
212
- uploadSpinner.start()
213
-
214
- let uploaded = 0
215
- for (const file of localFiles) {
216
- uploadSpinner.text = `Uploading ${file.key}... (${uploaded + 1}/${localFiles.length})`
217
-
218
- const fileContent = Bun.file(file.path)
219
- const buffer = await fileContent.arrayBuffer()
220
-
221
- await s3.putObject({
222
- bucket: bucket,
223
- key: file.key,
224
- body: Buffer.from(buffer),
225
- contentType: getContentType(file.key),
226
- })
227
-
228
- uploaded++
229
- }
230
-
231
- uploadSpinner.succeed(`Uploaded ${uploaded} file(s)`)
232
-
233
- // Delete remote files not in source if requested
234
- if (options.delete) {
235
- const deleteSpinner = new cli.Spinner('Checking for files to delete...')
236
- deleteSpinner.start()
237
-
238
- const remoteResult = await s3.listObjects({
239
- bucket,
240
- prefix: options.prefix,
241
- })
242
-
243
- const localKeys = new Set(localFiles.map(f => f.key))
244
- const toDelete = remoteResult.objects
245
- .filter((obj: any) => obj.Key && !localKeys.has(obj.Key))
246
- .map((obj: any) => obj.Key!)
247
-
248
- if (toDelete.length > 0) {
249
- deleteSpinner.text = `Deleting ${toDelete.length} remote file(s)...`
250
-
251
- for (const key of toDelete) {
252
- await s3.deleteObject(bucket, key)
253
- }
254
-
255
- deleteSpinner.succeed(`Deleted ${toDelete.length} remote file(s)`)
256
- }
257
- else {
258
- deleteSpinner.succeed('No files to delete')
259
- }
260
- }
261
-
262
- cli.success('\nSync complete!')
263
- }
264
- catch (error: any) {
265
- cli.error(`Failed to sync: ${error.message}`)
266
- process.exit(1)
267
- }
268
- })
269
-
270
- app
271
- .command('storage:policy <bucket>', 'Show or set bucket policy')
272
- .option('--set <file>', 'Set policy from JSON file')
273
- .option('--public-read', 'Set a public read policy')
274
- .option('--delete', 'Delete the bucket policy')
275
- .action(async (bucket: string, options: { set?: string; publicRead?: boolean; delete?: boolean }) => {
276
- cli.header('S3 Bucket Policy')
277
-
278
- try {
279
- const s3 = new S3Client('us-east-1')
280
-
281
- if (options.delete) {
282
- cli.warn(`This will delete the policy for bucket: ${bucket}`)
283
-
284
- const confirmed = await cli.confirm('\nDelete bucket policy?', false)
285
- if (!confirmed) {
286
- cli.info('Operation cancelled')
287
- return
288
- }
289
-
290
- const spinner = new cli.Spinner('Deleting policy...')
291
- spinner.start()
292
-
293
- await s3.deleteBucketPolicy(bucket)
294
-
295
- spinner.succeed('Policy deleted')
296
- return
297
- }
298
-
299
- if (options.publicRead) {
300
- cli.warn(`This will make bucket ${bucket} publicly readable!`)
301
-
302
- const confirmed = await cli.confirm('\nSet public read policy?', false)
303
- if (!confirmed) {
304
- cli.info('Operation cancelled')
305
- return
306
- }
307
-
308
- const spinner = new cli.Spinner('Setting policy...')
309
- spinner.start()
310
-
311
- const policy = {
312
- Version: '2012-10-17',
313
- Statement: [
314
- {
315
- Sid: 'PublicReadGetObject',
316
- Effect: 'Allow',
317
- Principal: '*',
318
- Action: 's3:GetObject',
319
- Resource: `arn:aws:s3:::${bucket}/*`,
320
- },
321
- ],
322
- }
323
-
324
- await s3.putBucketPolicy(bucket, policy)
325
-
326
- spinner.succeed('Public read policy set')
327
- return
328
- }
329
-
330
- if (options.set) {
331
- const spinner = new cli.Spinner('Setting policy...')
332
- spinner.start()
333
-
334
- const policyFile = Bun.file(options.set)
335
- const policy = await policyFile.text()
336
-
337
- await s3.putBucketPolicy(bucket, policy)
338
-
339
- spinner.succeed('Policy set')
340
- return
341
- }
342
-
343
- // Show current policy
344
- const spinner = new cli.Spinner('Fetching policy...')
345
- spinner.start()
346
-
347
- try {
348
- const result = await s3.getBucketPolicy(bucket)
349
- spinner.succeed('Policy loaded')
350
-
351
- cli.info('\nBucket Policy:')
352
- console.log(JSON.stringify(result || {}, null, 2))
353
- }
354
- catch (err: any) {
355
- if (err.message?.includes('NoSuchBucketPolicy')) {
356
- spinner.succeed('No policy set')
357
- cli.info('This bucket has no policy configured.')
358
- }
359
- else {
360
- throw err
361
- }
362
- }
363
- }
364
- catch (error: any) {
365
- cli.error(`Failed to manage policy: ${error.message}`)
366
- process.exit(1)
367
- }
368
- })
369
-
370
- app
371
- .command('storage:ls <bucket>', 'List objects in a bucket')
372
- .option('--prefix <prefix>', 'Filter by prefix')
373
- .option('--limit <number>', 'Limit number of results', { default: '100' })
374
- .action(async (bucket: string, options: { prefix?: string; limit?: string }) => {
375
- cli.header(`Objects in ${bucket}`)
376
-
377
- try {
378
- const s3 = new S3Client('us-east-1')
379
-
380
- const spinner = new cli.Spinner('Listing objects...')
381
- spinner.start()
382
-
383
- const result = await s3.listObjects({
384
- bucket,
385
- prefix: options.prefix,
386
- maxKeys: Number.parseInt(options.limit || '100'),
387
- })
388
-
389
- const objects = result.objects
390
-
391
- spinner.succeed(`Found ${objects.length} object(s)${result.nextContinuationToken ? ' (truncated)' : ''}`)
392
-
393
- if (objects.length === 0) {
394
- cli.info('No objects found')
395
- return
396
- }
397
-
398
- cli.table(
399
- ['Key', 'Size', 'Last Modified'],
400
- objects.map(obj => [
401
- obj.Key || 'N/A',
402
- formatBytes(obj.Size || 0),
403
- obj.LastModified ? new Date(obj.LastModified).toLocaleString() : 'N/A',
404
- ]),
405
- )
406
-
407
- if (result.nextContinuationToken) {
408
- cli.info(`\nMore objects available. Use --limit to see more.`)
409
- }
410
- }
411
- catch (error: any) {
412
- cli.error(`Failed to list objects: ${error.message}`)
413
- process.exit(1)
414
- }
415
- })
416
- }
417
-
418
- function getContentType(filename: string): string {
419
- const ext = filename.split('.').pop()?.toLowerCase()
420
- const types: Record<string, string> = {
421
- html: 'text/html',
422
- css: 'text/css',
423
- js: 'application/javascript',
424
- json: 'application/json',
425
- png: 'image/png',
426
- jpg: 'image/jpeg',
427
- jpeg: 'image/jpeg',
428
- gif: 'image/gif',
429
- svg: 'image/svg+xml',
430
- ico: 'image/x-icon',
431
- woff: 'font/woff',
432
- woff2: 'font/woff2',
433
- ttf: 'font/ttf',
434
- eot: 'application/vnd.ms-fontobject',
435
- pdf: 'application/pdf',
436
- zip: 'application/zip',
437
- xml: 'application/xml',
438
- txt: 'text/plain',
439
- md: 'text/markdown',
440
- }
441
- return types[ext || ''] || 'application/octet-stream'
442
- }
443
-
444
- function formatBytes(bytes: number): string {
445
- if (bytes === 0) return '0 B'
446
- const k = 1024
447
- const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
448
- const i = Math.floor(Math.log(bytes) / Math.log(k))
449
- return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`
450
- }
@@ -1,96 +0,0 @@
1
- import type { CLI } from '@stacksjs/clapp'
2
- import * as cli from '../../src/utils/cli'
3
-
4
- export function registerTeamCommands(app: CLI): void {
5
- app
6
- .command('team:add <email> <role>', 'Add team member')
7
- .action(async (email: string, role: string) => {
8
- cli.header('Adding Team Member')
9
-
10
- cli.info(`Email: ${email}`)
11
- cli.info(`Role: ${role}`)
12
-
13
- const validRoles = ['admin', 'developer', 'viewer']
14
- if (!validRoles.includes(role.toLowerCase())) {
15
- cli.error(`Invalid role. Must be one of: ${validRoles.join(', ')}`)
16
- return
17
- }
18
-
19
- const confirm = await cli.confirm('\nAdd this team member?', true)
20
- if (!confirm) {
21
- cli.info('Operation cancelled')
22
- return
23
- }
24
-
25
- const spinner = new cli.Spinner('Creating IAM user and sending invitation...')
26
- spinner.start()
27
-
28
- // TODO: Create IAM user with appropriate policies based on role
29
- // TODO: Send invitation email with credentials
30
- await new Promise(resolve => setTimeout(resolve, 2000))
31
-
32
- spinner.succeed('Team member added successfully')
33
-
34
- cli.success('\nTeam member added!')
35
- cli.info('An invitation email has been sent with access credentials')
36
-
37
- cli.info('\nAccess Details:')
38
- cli.info(` - Email: ${email}`)
39
- cli.info(` - Role: ${role}`)
40
- cli.info(` - Status: Pending`)
41
- })
42
-
43
- app
44
- .command('team:list', 'List team members')
45
- .action(async () => {
46
- cli.header('Team Members')
47
-
48
- const spinner = new cli.Spinner('Fetching team members...')
49
- spinner.start()
50
-
51
- // TODO: Fetch IAM users with appropriate tags
52
- await new Promise(resolve => setTimeout(resolve, 1500))
53
-
54
- spinner.stop()
55
-
56
- cli.table(
57
- ['Email', 'Role', 'Status', 'Added', 'Last Login'],
58
- [
59
- ['admin@example.com', 'Admin', 'Active', '2024-01-01', '2 hours ago'],
60
- ['dev@example.com', 'Developer', 'Active', '2024-01-15', '1 day ago'],
61
- ['viewer@example.com', 'Viewer', 'Active', '2024-02-01', '3 days ago'],
62
- ['new@example.com', 'Developer', 'Pending', '2024-11-10', 'Never'],
63
- ],
64
- )
65
-
66
- cli.info('\nTip: Use `cloud team:add` to add new team members')
67
- cli.info('Tip: Use `cloud team:remove` to remove team members')
68
- })
69
-
70
- app
71
- .command('team:remove <email>', 'Remove team member')
72
- .action(async (email: string) => {
73
- cli.header('Removing Team Member')
74
-
75
- cli.info(`Email: ${email}`)
76
-
77
- cli.warn('\nThis will revoke all access for this team member')
78
-
79
- const confirm = await cli.confirm('Remove this team member?', false)
80
- if (!confirm) {
81
- cli.info('Operation cancelled')
82
- return
83
- }
84
-
85
- const spinner = new cli.Spinner('Removing IAM user and access...')
86
- spinner.start()
87
-
88
- // TODO: Delete IAM user and associated resources
89
- await new Promise(resolve => setTimeout(resolve, 2000))
90
-
91
- spinner.succeed('Team member removed successfully')
92
-
93
- cli.success('\nTeam member removed!')
94
- cli.info('All access credentials have been revoked')
95
- })
96
- }