@stacksjs/ts-cloud 0.1.3 → 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 (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,489 +0,0 @@
1
- import type { CLI } from '@stacksjs/clapp'
2
- import * as cli from '../../src/utils/cli'
3
-
4
- export function registerTunnelCommands(app: CLI): void {
5
- app
6
- .command('tunnel', 'Start a local tunnel to expose your local server')
7
- .option('--port <number>', 'Local port to expose', { default: '3000' })
8
- .option('--subdomain <name>', 'Custom subdomain (if available)')
9
- .option('--host <hostname>', 'Local hostname', { default: 'localhost' })
10
- .option('--server <url>', 'Tunnel server URL', { default: 'localtunnel.dev' })
11
- .option('--verbose', 'Enable verbose logging')
12
- .action(async (options: { port: string; subdomain?: string; host: string; server: string; verbose?: boolean }) => {
13
- cli.header('Local Tunnel')
14
-
15
- const port = Number.parseInt(options.port)
16
-
17
- cli.info(`Local server: ${options.host}:${port}`)
18
- cli.info(`Tunnel server: ${options.server}`)
19
-
20
- if (options.subdomain) {
21
- cli.info(`Requested subdomain: ${options.subdomain}`)
22
- }
23
-
24
- const spinner = new cli.Spinner('Connecting to tunnel server...')
25
- spinner.start()
26
-
27
- try {
28
- // Try to dynamically import localtunnels
29
- let TunnelClient: any
30
-
31
- try {
32
- // @ts-expect-error -- localtunnels is an optional dependency
33
- const localtunnels = await import('localtunnels')
34
- TunnelClient = localtunnels.TunnelClient
35
- }
36
- catch {
37
- spinner.fail('localtunnels package not found')
38
- cli.info('\nTo use tunnels, install the localtunnels package:')
39
- cli.info(' bun add localtunnels')
40
- cli.info('\nOr use the standalone CLI:')
41
- cli.info(' bunx localtunnels --port 3000')
42
- return
43
- }
44
-
45
- const serverHost = options.server.replace(/^(wss?|https?):\/\//, '')
46
- const secure = options.server.startsWith('wss://') || options.server.startsWith('https://') || serverHost === 'localtunnel.dev'
47
-
48
- const client = new TunnelClient({
49
- localPort: port,
50
- localHost: options.host,
51
- subdomain: options.subdomain,
52
- host: serverHost,
53
- port: secure ? 443 : 80,
54
- secure,
55
- verbose: options.verbose,
56
- })
57
-
58
- client.on('connected', (info: { url: string; subdomain: string }) => {
59
- spinner.succeed('Connected!')
60
- cli.success(`\nYour tunnel URL: ${info.url}`)
61
- cli.info(`Subdomain: ${info.subdomain}`)
62
- cli.info(`\nForwarding: ${info.url} -> http://${options.host}:${port}`)
63
- cli.info('\nPress Ctrl+C to stop the tunnel')
64
- })
65
-
66
- client.on('request', (req: { method: string; url: string }) => {
67
- if (options.verbose) {
68
- cli.info(`→ ${req.method} ${req.url}`)
69
- }
70
- })
71
-
72
- client.on('response', (res: { status: number; size: number; duration?: number }) => {
73
- if (options.verbose) {
74
- cli.info(`← ${res.status} (${res.size} bytes${res.duration ? `, ${res.duration}ms` : ''})`)
75
- }
76
- })
77
-
78
- client.on('reconnecting', (info: { attempt: number; maxAttempts: number }) => {
79
- cli.info(`Reconnecting... (attempt ${info.attempt}/${info.maxAttempts})`)
80
- })
81
-
82
- client.on('error', (error: Error) => {
83
- cli.error(`Tunnel error: ${error.message}`)
84
- })
85
-
86
- client.on('close', () => {
87
- cli.info('\nTunnel closed')
88
- })
89
-
90
- // Handle process signals for graceful shutdown
91
- const cleanup = () => {
92
- cli.info('\nShutting down tunnel...')
93
- client.disconnect()
94
- process.exit(0)
95
- }
96
-
97
- process.on('SIGINT', cleanup)
98
- process.on('SIGTERM', cleanup)
99
-
100
- await client.connect()
101
-
102
- // Keep the process running
103
- await new Promise(() => {})
104
- }
105
- catch (error: any) {
106
- spinner.fail('Failed to connect')
107
- cli.error(`Error: ${error.message}`)
108
- process.exit(1)
109
- }
110
- })
111
-
112
- app
113
- .command('tunnel:status', 'Check tunnel server status')
114
- .option('--server <url>', 'Tunnel server URL', { default: 'https://localtunnel.dev' })
115
- .action(async (options: { server: string }) => {
116
- cli.header('Tunnel Server Status')
117
-
118
- const spinner = new cli.Spinner('Checking server status...')
119
- spinner.start()
120
-
121
- try {
122
- const serverUrl = options.server.startsWith('http')
123
- ? options.server
124
- : `https://${options.server}`
125
-
126
- const response = await fetch(`${serverUrl}/status`, {
127
- method: 'GET',
128
- headers: { Accept: 'application/json' },
129
- })
130
-
131
- if (response.ok) {
132
- const status = await response.json() as Record<string, any>
133
- spinner.succeed('Server is online')
134
-
135
- cli.info(`\nServer: ${options.server}`)
136
- cli.info(`Status: ${status.status || 'operational'}`)
137
-
138
- if (status.version) {
139
- cli.info(`Version: ${status.version}`)
140
- }
141
-
142
- if (status.connections !== undefined) {
143
- cli.info(`Active connections: ${status.connections}`)
144
- }
145
-
146
- if (status.uptime) {
147
- cli.info(`Uptime: ${status.uptime}`)
148
- }
149
-
150
- if (status.activeSubdomains?.length) {
151
- cli.info(`Active subdomains: ${status.activeSubdomains.join(', ')}`)
152
- }
153
- }
154
- else {
155
- spinner.fail(`Server returned status ${response.status}`)
156
- }
157
- }
158
- catch (error: any) {
159
- spinner.fail('Failed to check server status')
160
- cli.error(`Error: ${error.message}`)
161
- cli.info('\nThe tunnel server may be offline or unreachable.')
162
- }
163
- })
164
-
165
- app
166
- .command('tunnel:info', 'Show tunnel configuration and setup info')
167
- .action(async () => {
168
- cli.header('Local Tunnel Information')
169
-
170
- cli.info('ts-cloud uses localtunnels for secure tunnel connections.')
171
- cli.info('')
172
- cli.info('Default server: localtunnel.dev')
173
- cli.info('')
174
- cli.info('Usage:')
175
- cli.info(' cloud tunnel --port 3000 # Expose port 3000')
176
- cli.info(' cloud tunnel --port 8080 --subdomain myapp')
177
- cli.info('')
178
- cli.info('Features:')
179
- cli.info(' - Secure WebSocket-based tunnels')
180
- cli.info(' - Custom subdomains (when available)')
181
- cli.info(' - Automatic reconnection')
182
- cli.info(' - Request logging')
183
- cli.info(' - Binary data support')
184
- cli.info('')
185
- cli.info('Self-hosted tunnel server:')
186
- cli.info(' You can run your own tunnel server using localtunnels.')
187
- cli.info(' See: https://github.com/stacksjs/localtunnels')
188
- cli.info('')
189
- cli.info('Environment variables:')
190
- cli.info(' TUNNEL_SERVER - Custom tunnel server URL')
191
- cli.info(' TUNNEL_SUBDOMAIN - Default subdomain to request')
192
- })
193
-
194
- app
195
- .command('tunnel:deploy', 'Deploy tunnel infrastructure to AWS')
196
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
197
- .option('--prefix <prefix>', 'Resource name prefix', { default: 'localtunnel' })
198
- .option('--verbose', 'Enable verbose logging')
199
- .action(async (options: { region: string; prefix: string; verbose?: boolean }) => {
200
- cli.header('Deploy Tunnel Infrastructure')
201
-
202
- cli.info(`Region: ${options.region}`)
203
- cli.info(`Prefix: ${options.prefix}`)
204
- cli.info('')
205
-
206
- cli.info('This will deploy:')
207
- cli.info(' - DynamoDB tables for connection tracking')
208
- cli.info(' - Lambda functions for handling requests')
209
- cli.info(' - Lambda Function URLs for public access')
210
- cli.info('')
211
-
212
- const confirmed = await cli.confirm('Deploy tunnel infrastructure?', false)
213
- if (!confirmed) {
214
- cli.info('Operation cancelled')
215
- return
216
- }
217
-
218
- const spinner = new cli.Spinner('Deploying infrastructure...')
219
- spinner.start()
220
-
221
- try {
222
- // Try to import the deploy function from localtunnels
223
- let deployTunnelInfrastructure: any
224
-
225
- try {
226
- // @ts-expect-error -- localtunnels is an optional dependency
227
- const cloudModule = await import('localtunnels/cloud')
228
- deployTunnelInfrastructure = cloudModule.deployTunnelInfrastructure
229
- }
230
- catch {
231
- spinner.fail('localtunnels package not found')
232
- cli.info('\nTo deploy tunnel infrastructure, install localtunnels:')
233
- cli.info(' bun add localtunnels')
234
- cli.info('\nOr deploy using the localtunnels CLI directly:')
235
- cli.info(' bunx localtunnels deploy --region us-east-1')
236
- return
237
- }
238
-
239
- const result = await deployTunnelInfrastructure({
240
- region: options.region,
241
- prefix: options.prefix,
242
- verbose: options.verbose,
243
- })
244
-
245
- spinner.succeed('Deployment complete!')
246
-
247
- cli.info('')
248
- cli.info('Resources created:')
249
- cli.info(` DynamoDB Tables:`)
250
- cli.info(` - ${result.connectionsTable}`)
251
- cli.info(` - ${result.responsesTable}`)
252
- cli.info('')
253
- cli.info(` Lambda Functions:`)
254
- cli.info(` - ${result.functions.http}`)
255
- cli.info(` - ${result.functions.message}`)
256
- cli.info('')
257
-
258
- if (result.httpUrl || result.wsUrl) {
259
- cli.info('Endpoints:')
260
- if (result.httpUrl) {
261
- cli.info(` HTTP URL: ${result.httpUrl}`)
262
- }
263
- if (result.wsUrl) {
264
- cli.info(` WebSocket URL: ${result.wsUrl}`)
265
- }
266
- }
267
- }
268
- catch (error: any) {
269
- spinner.fail('Deployment failed')
270
- cli.error(`Error: ${error.message}`)
271
- if (options.verbose) {
272
- console.error(error.stack)
273
- }
274
- process.exit(1)
275
- }
276
- })
277
-
278
- app
279
- .command('tunnel:destroy', 'Destroy tunnel infrastructure from AWS')
280
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
281
- .option('--prefix <prefix>', 'Resource name prefix', { default: 'localtunnel' })
282
- .option('--verbose', 'Enable verbose logging')
283
- .action(async (options: { region: string; prefix: string; verbose?: boolean }) => {
284
- cli.header('Destroy Tunnel Infrastructure')
285
-
286
- cli.info(`Region: ${options.region}`)
287
- cli.info(`Prefix: ${options.prefix}`)
288
- cli.info('')
289
-
290
- cli.warn('This will permanently delete:')
291
- cli.warn(' - All DynamoDB tables and data')
292
- cli.warn(' - All Lambda functions')
293
- cli.warn(' - All IAM roles and policies')
294
- cli.info('')
295
-
296
- const confirmed = await cli.confirm('Are you sure you want to destroy this infrastructure?', false)
297
- if (!confirmed) {
298
- cli.info('Operation cancelled')
299
- return
300
- }
301
-
302
- const spinner = new cli.Spinner('Destroying infrastructure...')
303
- spinner.start()
304
-
305
- try {
306
- let destroyTunnelInfrastructure: any
307
-
308
- try {
309
- // @ts-expect-error -- localtunnels is an optional dependency
310
- const cloudModule = await import('localtunnels/cloud')
311
- destroyTunnelInfrastructure = cloudModule.destroyTunnelInfrastructure
312
- }
313
- catch {
314
- spinner.fail('localtunnels package not found')
315
- cli.info('\nTo destroy tunnel infrastructure, install localtunnels:')
316
- cli.info(' bun add localtunnels')
317
- cli.info('\nOr destroy using the localtunnels CLI directly:')
318
- cli.info(' bunx localtunnels destroy --region us-east-1')
319
- return
320
- }
321
-
322
- await destroyTunnelInfrastructure({
323
- region: options.region,
324
- prefix: options.prefix,
325
- verbose: options.verbose,
326
- })
327
-
328
- spinner.succeed('Infrastructure destroyed!')
329
- }
330
- catch (error: any) {
331
- spinner.fail('Destruction failed')
332
- cli.error(`Error: ${error.message}`)
333
- if (options.verbose) {
334
- console.error(error.stack)
335
- }
336
- process.exit(1)
337
- }
338
- })
339
-
340
- app
341
- .command('tunnel:logs', 'View tunnel server logs')
342
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
343
- .option('--prefix <prefix>', 'Resource name prefix', { default: 'localtunnel' })
344
- .option('--tail', 'Tail the logs')
345
- .action(async (options: { region: string; prefix: string; tail?: boolean }) => {
346
- cli.header('Tunnel Server Logs')
347
-
348
- cli.info('Tunnel server log groups:')
349
- cli.info(` - /aws/lambda/${options.prefix}-connect`)
350
- cli.info(` - /aws/lambda/${options.prefix}-disconnect`)
351
- cli.info(` - /aws/lambda/${options.prefix}-message`)
352
- cli.info(` - /aws/lambda/${options.prefix}-http`)
353
- cli.info('')
354
-
355
- cli.info('To view logs:')
356
- cli.info(` aws logs tail /aws/lambda/${options.prefix}-http --region ${options.region}${options.tail ? ' --follow' : ''}`)
357
- cli.info('')
358
-
359
- cli.info('Or use CloudWatch Insights:')
360
- cli.info(` 1. Go to CloudWatch > Logs Insights`)
361
- cli.info(` 2. Select the tunnel log groups`)
362
- cli.info(` 3. Run queries like:`)
363
- cli.info(` fields @timestamp, @message | filter @message like /error/i`)
364
- })
365
-
366
- app
367
- .command('tunnel:test <url>', 'Test a tunnel connection')
368
- .action(async (url: string) => {
369
- cli.header('Test Tunnel Connection')
370
-
371
- const spinner = new cli.Spinner(`Testing ${url}...`)
372
- spinner.start()
373
-
374
- try {
375
- const startTime = Date.now()
376
- const response = await fetch(url, {
377
- method: 'GET',
378
- headers: {
379
- 'User-Agent': 'ts-cloud-tunnel-test',
380
- },
381
- })
382
-
383
- const elapsed = Date.now() - startTime
384
-
385
- spinner.succeed(`Connected in ${elapsed}ms`)
386
-
387
- cli.info(`\nStatus: ${response.status} ${response.statusText}`)
388
- cli.info('\nResponse headers:')
389
- response.headers.forEach((value, key) => {
390
- cli.info(` ${key}: ${value}`)
391
- })
392
-
393
- const body = await response.text()
394
- if (body.length > 0) {
395
- cli.info('\nResponse body (first 500 chars):')
396
- console.log(body.substring(0, 500))
397
- if (body.length > 500) {
398
- cli.info(`... (${body.length - 500} more characters)`)
399
- }
400
- }
401
- }
402
- catch (error: any) {
403
- spinner.fail('Connection failed')
404
- cli.error(`Error: ${error.message}`)
405
- }
406
- })
407
-
408
- app
409
- .command('tunnel:server', 'Start a self-hosted tunnel server')
410
- .option('--port <number>', 'Port to listen on', { default: '3000' })
411
- .option('--host <hostname>', 'Host to bind to', { default: '0.0.0.0' })
412
- .option('--domain <domain>', 'Domain for tunnel URLs', { default: 'localhost' })
413
- .option('--verbose', 'Enable verbose logging')
414
- .action(async (options: { port: string; host: string; domain: string; verbose?: boolean }) => {
415
- cli.header('Local Tunnel Server')
416
-
417
- const port = Number.parseInt(options.port)
418
-
419
- cli.info(`Listening on: ${options.host}:${port}`)
420
- cli.info(`Domain: ${options.domain}`)
421
- cli.info('')
422
-
423
- const spinner = new cli.Spinner('Starting tunnel server...')
424
- spinner.start()
425
-
426
- try {
427
- let TunnelServer: any
428
-
429
- try {
430
- // @ts-expect-error -- localtunnels is an optional dependency
431
- const localtunnels = await import('localtunnels')
432
- TunnelServer = localtunnels.TunnelServer
433
- }
434
- catch {
435
- spinner.fail('localtunnels package not found')
436
- cli.info('\nTo run a tunnel server, install localtunnels:')
437
- cli.info(' bun add localtunnels')
438
- cli.info('\nOr use the standalone CLI:')
439
- cli.info(' bunx localtunnels server --port 3000')
440
- return
441
- }
442
-
443
- const server = new TunnelServer({
444
- port,
445
- host: options.host,
446
- verbose: options.verbose,
447
- })
448
-
449
- server.on('connection', (info: { subdomain: string; totalConnections: number }) => {
450
- cli.info(`+ Client connected: ${info.subdomain} (total: ${info.totalConnections})`)
451
- })
452
-
453
- server.on('disconnection', (info: { subdomain: string }) => {
454
- cli.info(`- Client disconnected: ${info.subdomain}`)
455
- })
456
-
457
- // Handle process signals for graceful shutdown
458
- const cleanup = () => {
459
- cli.info('\nShutting down server...')
460
- server.stop()
461
- process.exit(0)
462
- }
463
-
464
- process.on('SIGINT', cleanup)
465
- process.on('SIGTERM', cleanup)
466
-
467
- await server.start()
468
-
469
- spinner.succeed('Server running!')
470
-
471
- cli.info('')
472
- cli.info(`WebSocket URL: ws://${options.host === '0.0.0.0' ? 'localhost' : options.host}:${port}`)
473
- cli.info(`HTTP URL: http://${options.host === '0.0.0.0' ? 'localhost' : options.host}:${port}`)
474
- cli.info('')
475
- cli.info('Clients can connect with:')
476
- cli.info(` cloud tunnel --port 3000 --server ${options.host === '0.0.0.0' ? 'localhost' : options.host}:${port}`)
477
- cli.info('')
478
- cli.info('Press Ctrl+C to stop the server')
479
-
480
- // Keep the process running
481
- await new Promise(() => {})
482
- }
483
- catch (error: any) {
484
- spinner.fail('Failed to start server')
485
- cli.error(`Error: ${error.message}`)
486
- process.exit(1)
487
- }
488
- })
489
- }
@@ -1,202 +0,0 @@
1
- import type { CLI } from '@stacksjs/clapp'
2
- import { existsSync } from 'node:fs'
3
- import * as cli from '../../src/utils/cli'
4
- import { CloudFormationClient } from '../../src/aws/cloudformation'
5
- import { ACMClient } from '../../src/aws/acm'
6
-
7
- export function registerUtilsCommands(app: CLI, version: string): void {
8
- app
9
- .command('upgrade', 'Upgrade CLI to latest version')
10
- .action(async () => {
11
- cli.header('Upgrading ts-cloud CLI')
12
-
13
- const spinner = new cli.Spinner('Checking for updates...')
14
- spinner.start()
15
-
16
- // TODO: Check npm/GitHub for latest version
17
- await new Promise(resolve => setTimeout(resolve, 2000))
18
-
19
- spinner.stop()
20
-
21
- cli.info('\nCurrent version: 0.1.0')
22
- cli.info('Latest version: 0.2.0')
23
-
24
- const confirm = await cli.confirm('\nUpgrade to latest version?', true)
25
- if (!confirm) {
26
- cli.info('Operation cancelled')
27
- return
28
- }
29
-
30
- const upgradeSpinner = new cli.Spinner('Upgrading...')
31
- upgradeSpinner.start()
32
-
33
- // TODO: Run npm/bun upgrade command
34
- await new Promise(resolve => setTimeout(resolve, 3000))
35
-
36
- upgradeSpinner.succeed('Upgrade completed successfully')
37
-
38
- cli.success('\nts-cloud CLI upgraded to v0.2.0!')
39
-
40
- cli.info('\nWhat\'s new in v0.2.0:')
41
- cli.info(' - New cost optimization commands')
42
- cli.info(' - Improved team collaboration features')
43
- cli.info(' - Better error messages')
44
- cli.info(' - Performance improvements')
45
-
46
- cli.info('\nTip: Run `cloud --help` to see all available commands')
47
- })
48
-
49
- app
50
- .command('doctor', 'Check system requirements and AWS credentials')
51
- .action(async () => {
52
- cli.header('System Diagnostics')
53
-
54
- // Check Bun
55
- cli.step('Checking Bun...')
56
- cli.success(`Bun ${process.versions.bun}`)
57
-
58
- // Check AWS CLI
59
- cli.step('Checking AWS CLI...')
60
- const hasAwsCli = await cli.checkAwsCli()
61
- if (hasAwsCli) {
62
- cli.success('AWS CLI is installed')
63
- }
64
- else {
65
- cli.error('AWS CLI is not installed')
66
- cli.info('Install: https://aws.amazon.com/cli/')
67
- }
68
-
69
- // Check AWS credentials
70
- cli.step('Checking AWS credentials...')
71
- const hasCredentials = await cli.checkAwsCredentials()
72
- if (hasCredentials) {
73
- cli.success('AWS credentials are configured')
74
- const accountId = await cli.getAwsAccountId()
75
- if (accountId) {
76
- cli.info(`Account ID: ${accountId}`)
77
- }
78
- }
79
- else {
80
- cli.error('AWS credentials are not configured')
81
- cli.info('Run: aws configure')
82
- }
83
-
84
- // Check CloudFront access (list)
85
- cli.step('Checking CloudFront list access...')
86
- let cloudfrontListOk = false
87
- try {
88
- const { CloudFrontClient } = await import('../../src/aws/cloudfront')
89
- const cloudfront = new CloudFrontClient()
90
- await cloudfront.listDistributions()
91
- cli.success('CloudFront list access is enabled')
92
- cloudfrontListOk = true
93
- }
94
- catch (error: any) {
95
- cli.warn(`CloudFront list check failed: ${error.message}`)
96
- }
97
-
98
- // Check CloudFront create access (via CloudFormation - the common issue point)
99
- if (cloudfrontListOk) {
100
- cli.step('Checking CloudFront create access...')
101
- try {
102
- // Try to validate a CloudFormation template with CloudFront resource
103
- const cfn = new CloudFormationClient('us-east-1')
104
- const testTemplate = JSON.stringify({
105
- AWSTemplateFormatVersion: '2010-09-09',
106
- Description: 'Test CloudFront access',
107
- Resources: {
108
- TestOAC: {
109
- Type: 'AWS::CloudFront::OriginAccessControl',
110
- Properties: {
111
- OriginAccessControlConfig: {
112
- Name: 'test-oac-validation',
113
- OriginAccessControlOriginType: 's3',
114
- SigningBehavior: 'always',
115
- SigningProtocol: 'sigv4',
116
- },
117
- },
118
- },
119
- },
120
- })
121
- await cfn.validateTemplate(testTemplate)
122
- cli.success('CloudFront create access appears enabled')
123
- }
124
- catch (error: any) {
125
- if (error.message?.includes('403') || error.message?.includes('AccessDenied') || error.message?.includes('must be verified')) {
126
- cli.error('CloudFront create access denied - account verification required')
127
- cli.info('')
128
- cli.info('Your AWS account needs to be verified for CloudFront.')
129
- cli.info('This is required before you can create CloudFront distributions.')
130
- cli.info('')
131
- cli.info('To verify your account:')
132
- cli.info(' 1. Go to: https://console.aws.amazon.com/support/home#/')
133
- cli.info(' 2. Create a support case')
134
- cli.info(' 3. Select: Service limit increase > CloudFront')
135
- cli.info(' 4. Request: "Please verify my account for CloudFront access"')
136
- cli.info('')
137
- cli.info('Verification usually takes 1-2 business days.')
138
- }
139
- else {
140
- // Template validation might fail for other reasons, that's ok
141
- cli.success('CloudFront create access appears enabled (validation passed)')
142
- }
143
- }
144
- }
145
-
146
- // Check S3 access
147
- cli.step('Checking S3 access...')
148
- try {
149
- const { S3Client } = await import('../../src/aws/s3')
150
- const s3 = new S3Client('us-east-1')
151
- await s3.listBuckets()
152
- cli.success('S3 access is enabled')
153
- }
154
- catch (error: any) {
155
- cli.warn(`S3 check failed: ${error.message}`)
156
- }
157
-
158
- // Check ACM access
159
- cli.step('Checking ACM (SSL certificates) access...')
160
- try {
161
- const acm = new ACMClient('us-east-1')
162
- await acm.listCertificates()
163
- cli.success('ACM access is enabled')
164
- }
165
- catch (error: any) {
166
- cli.warn(`ACM check failed: ${error.message}`)
167
- }
168
-
169
- // Check for cloud.config.ts
170
- cli.step('Checking configuration...')
171
- if (existsSync('cloud.config.ts')) {
172
- cli.success('cloud.config.ts found')
173
- }
174
- else {
175
- cli.warn('cloud.config.ts not found')
176
- cli.info('Run: cloud init')
177
- }
178
- })
179
-
180
- app
181
- .command('regions', 'List available AWS regions')
182
- .action(async () => {
183
- cli.header('AWS Regions')
184
-
185
- const spinner = new cli.Spinner('Fetching regions...')
186
- spinner.start()
187
-
188
- const regions = await cli.getAwsRegions()
189
- spinner.stop()
190
-
191
- regions.forEach((region) => {
192
- console.log(` ${region}`)
193
- })
194
- })
195
-
196
- app
197
- .command('version', 'Show the version of the CLI')
198
- .alias('v')
199
- .action(() => {
200
- console.log(`ts-cloud v${version}`)
201
- })
202
- }