@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
package/bin/cli.ts DELETED
@@ -1,133 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { CLI } from '@stacksjs/clapp'
3
- import { version } from '../package.json'
4
- import {
5
- registerInitCommands,
6
- registerConfigCommands,
7
- registerGenerateCommands,
8
- registerServerCommands,
9
- registerFunctionCommands,
10
- registerContainerCommands,
11
- registerDomainCommands,
12
- registerDatabaseCommands,
13
- registerLogsCommands,
14
- registerSecretsCommands,
15
- registerFirewallCommands,
16
- registerSslCommands,
17
- registerCostCommands,
18
- registerGitCommands,
19
- registerEnvironmentCommands,
20
- registerAssetsCommands,
21
- registerTeamCommands,
22
- registerDeployCommands,
23
- registerStackCommands,
24
- registerUtilsCommands,
25
- registerAnalyticsCommands,
26
- // New infrastructure commands
27
- registerCdnCommands,
28
- registerStorageCommands,
29
- registerCacheCommands,
30
- registerQueueCommands,
31
- registerNetworkCommands,
32
- // Scheduling & Events
33
- registerSchedulerCommands,
34
- registerEventsCommands,
35
- // Communication
36
- registerEmailCommands,
37
- registerNotifyCommands,
38
- // Security & Access
39
- registerIamCommands,
40
- registerAuditCommands,
41
- // Operations
42
- registerStatusCommands,
43
- registerBackupCommands,
44
- registerApiCommands,
45
- registerTunnelCommands,
46
- } from './commands'
47
-
48
- const app = new CLI('cloud')
49
-
50
- // ============================================
51
- // Global Options
52
- // ============================================
53
- app
54
- .option('--env <environment>', 'Environment (production, staging, development)')
55
- .option('--region <region>', 'AWS Region')
56
- .option('--profile <profile>', 'AWS CLI Profile')
57
- .option('--verbose', 'Enable verbose logging')
58
- .option('--dry-run', 'Show what would be done without making changes')
59
-
60
- // ============================================
61
- // Register All Commands
62
- // ============================================
63
-
64
- // Core commands
65
- registerInitCommands(app)
66
- registerConfigCommands(app)
67
- registerGenerateCommands(app)
68
- registerDeployCommands(app)
69
- registerStackCommands(app)
70
-
71
- // Infrastructure Management
72
- registerServerCommands(app)
73
- registerFunctionCommands(app)
74
- registerContainerCommands(app)
75
- registerCdnCommands(app)
76
- registerStorageCommands(app)
77
- registerCacheCommands(app)
78
- registerQueueCommands(app)
79
- registerNetworkCommands(app)
80
-
81
- // Domain & DNS
82
- registerDomainCommands(app)
83
- registerSslCommands(app)
84
-
85
- // Database & Data
86
- registerDatabaseCommands(app)
87
-
88
- // Monitoring & Logs
89
- registerLogsCommands(app)
90
- registerStatusCommands(app)
91
-
92
- // Scheduling & Events
93
- registerSchedulerCommands(app)
94
- registerEventsCommands(app)
95
-
96
- // Communication
97
- registerEmailCommands(app)
98
- registerNotifyCommands(app)
99
-
100
- // Security & Access
101
- registerSecretsCommands(app)
102
- registerFirewallCommands(app)
103
- registerIamCommands(app)
104
- registerAuditCommands(app)
105
-
106
- // Operations & Backup
107
- registerBackupCommands(app)
108
- registerApiCommands(app)
109
-
110
- // Cost & Resources
111
- registerCostCommands(app)
112
-
113
- // Git & Environment
114
- registerGitCommands(app)
115
- registerEnvironmentCommands(app)
116
-
117
- // Assets & Team
118
- registerAssetsCommands(app)
119
- registerTeamCommands(app)
120
-
121
- // Analytics & Tunnel
122
- registerAnalyticsCommands(app)
123
- registerTunnelCommands(app)
124
-
125
- // Utilities
126
- registerUtilsCommands(app, version)
127
-
128
- // ============================================
129
- // Help & Version
130
- // ============================================
131
- app.version(version)
132
- app.help()
133
- app.parse()
@@ -1,328 +0,0 @@
1
- import type { CLI } from '@stacksjs/clapp'
2
- import * as cli from '../../src/utils/cli'
3
- import { DynamoDBClient } from '../../src/aws/dynamodb'
4
-
5
- export function registerAnalyticsCommands(app: CLI): void {
6
- app
7
- .command('analytics:sites:list', 'List all analytics sites')
8
- .option('--table <name>', 'DynamoDB table name', { default: 'ts-analytics' })
9
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
10
- .action(async (options: { table: string; region: string }) => {
11
- cli.header('Analytics Sites')
12
-
13
- try {
14
- const dynamodb = new DynamoDBClient(options.region)
15
-
16
- const spinner = new cli.Spinner('Fetching sites...')
17
- spinner.start()
18
-
19
- const result = await dynamodb.scan({
20
- TableName: options.table,
21
- FilterExpression: 'begins_with(pk, :pk)',
22
- ExpressionAttributeValues: {
23
- ':pk': { S: 'SITE#' },
24
- },
25
- })
26
-
27
- spinner.succeed(`Found ${result.Items?.length || 0} site(s)`)
28
-
29
- if (!result.Items || result.Items.length === 0) {
30
- cli.info('No analytics sites found')
31
- cli.info('Use `cloud analytics:sites:create` to create a new site')
32
- return
33
- }
34
-
35
- const sites = result.Items.map(item => DynamoDBClient.unmarshal(item))
36
-
37
- cli.table(
38
- ['ID', 'Name', 'Domains', 'Active', 'Created'],
39
- sites.map(site => [
40
- site.siteId || 'N/A',
41
- site.name || 'Unnamed',
42
- (site.domains || []).join(', ') || '-',
43
- site.isActive ? 'Yes' : 'No',
44
- site.createdAt ? new Date(site.createdAt).toLocaleDateString() : 'N/A',
45
- ]),
46
- )
47
- }
48
- catch (error: any) {
49
- cli.error(`Failed to list sites: ${error.message}`)
50
- process.exit(1)
51
- }
52
- })
53
-
54
- app
55
- .command('analytics:sites:create', 'Create a new analytics site')
56
- .option('--table <name>', 'DynamoDB table name', { default: 'ts-analytics' })
57
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
58
- .option('--name <name>', 'Site name')
59
- .option('--domain <domain>', 'Site domain(s) (can be specified multiple times)')
60
- .action(async (options: { table: string; region: string; name?: string; domain?: string | string[] }) => {
61
- cli.header('Create Analytics Site')
62
-
63
- try {
64
- const dynamodb = new DynamoDBClient(options.region)
65
-
66
- // Get site name
67
- const name = options.name || await cli.prompt('Site name', 'My Site')
68
-
69
- // Get domains
70
- let domains: string[] = []
71
- if (options.domain) {
72
- domains = Array.isArray(options.domain) ? options.domain : [options.domain]
73
- }
74
- else {
75
- const domainInput = await cli.prompt('Site domains (comma-separated)', 'example.com')
76
- domains = domainInput.split(',').map(d => d.trim()).filter(Boolean)
77
- }
78
-
79
- cli.info(`\nCreating site: ${name}`)
80
- cli.info(`Domains: ${domains.join(', ')}`)
81
-
82
- const confirm = await cli.confirm('\nCreate this site?', true)
83
- if (!confirm) {
84
- cli.info('Operation cancelled')
85
- return
86
- }
87
-
88
- const spinner = new cli.Spinner('Creating site...')
89
- spinner.start()
90
-
91
- // Generate site ID
92
- const siteId = `site_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
93
-
94
- const now = new Date().toISOString()
95
-
96
- await dynamodb.putItem({
97
- TableName: options.table,
98
- Item: {
99
- pk: { S: `SITE#${siteId}` },
100
- sk: { S: `SITE#${siteId}` },
101
- siteId: { S: siteId },
102
- name: { S: name },
103
- domains: { L: domains.map(d => ({ S: d })) },
104
- isActive: { BOOL: true },
105
- createdAt: { S: now },
106
- updatedAt: { S: now },
107
- },
108
- })
109
-
110
- spinner.succeed('Site created successfully')
111
-
112
- cli.success(`\nSite ID: ${siteId}`)
113
- cli.info('\nAdd the tracking script to your website:')
114
- cli.info(` <script src="https://analytics.stacksjs.com/track.js" data-site-id="${siteId}"></script>`)
115
- }
116
- catch (error: any) {
117
- cli.error(`Failed to create site: ${error.message}`)
118
- process.exit(1)
119
- }
120
- })
121
-
122
- app
123
- .command('analytics:sites:update <siteId>', 'Update an analytics site')
124
- .option('--table <name>', 'DynamoDB table name', { default: 'ts-analytics' })
125
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
126
- .option('--name <name>', 'New site name')
127
- .option('--domain <domain>', 'Set domains (replaces existing)')
128
- .option('--active <boolean>', 'Set site active/inactive status')
129
- .action(async (siteId: string, options: { table: string; region: string; name?: string; domain?: string | string[]; active?: string }) => {
130
- cli.header('Update Analytics Site')
131
-
132
- try {
133
- const dynamodb = new DynamoDBClient(options.region)
134
-
135
- // First, verify the site exists
136
- const result = await dynamodb.getItem({
137
- TableName: options.table,
138
- Key: {
139
- pk: { S: `SITE#${siteId}` },
140
- sk: { S: `SITE#${siteId}` },
141
- },
142
- })
143
-
144
- if (!result.Item) {
145
- cli.error(`Site not found: ${siteId}`)
146
- process.exit(1)
147
- }
148
-
149
- const site = DynamoDBClient.unmarshal(result.Item)
150
- cli.info(`Updating site: ${site.name || 'Unnamed'} (${siteId})`)
151
- cli.info('')
152
-
153
- // Build update expression
154
- const updates: string[] = []
155
- const expressionNames: Record<string, string> = {}
156
- const expressionValues: Record<string, any> = {}
157
-
158
- if (options.name) {
159
- updates.push('#n = :name')
160
- expressionNames['#n'] = 'name'
161
- expressionValues[':name'] = { S: options.name }
162
- cli.info(` Name: ${site.name} -> ${options.name}`)
163
- }
164
-
165
- if (options.domain !== undefined) {
166
- const domains = Array.isArray(options.domain) ? options.domain : [options.domain]
167
- updates.push('domains = :domains')
168
- expressionValues[':domains'] = { L: domains.map(d => ({ S: d })) }
169
- cli.info(` Domains: ${JSON.stringify(site.domains || [])} -> ${JSON.stringify(domains)}`)
170
- }
171
-
172
- if (options.active !== undefined) {
173
- const isActive = options.active === 'true' || options.active === '1'
174
- updates.push('isActive = :active')
175
- expressionValues[':active'] = { BOOL: isActive }
176
- cli.info(` Active: ${site.isActive} -> ${isActive}`)
177
- }
178
-
179
- if (updates.length === 0) {
180
- cli.warn('No updates specified. Use --name, --domain, or --active options.')
181
- return
182
- }
183
-
184
- // Always update updatedAt
185
- updates.push('updatedAt = :updatedAt')
186
- expressionValues[':updatedAt'] = { S: new Date().toISOString() }
187
-
188
- await dynamodb.updateItem({
189
- TableName: options.table,
190
- Key: {
191
- pk: { S: `SITE#${siteId}` },
192
- sk: { S: `SITE#${siteId}` },
193
- },
194
- UpdateExpression: `SET ${updates.join(', ')}`,
195
- ExpressionAttributeNames: Object.keys(expressionNames).length > 0 ? expressionNames : undefined,
196
- ExpressionAttributeValues: expressionValues,
197
- })
198
-
199
- cli.info('')
200
- cli.success('Site updated successfully')
201
- }
202
- catch (error: any) {
203
- cli.error(`Failed to update site: ${error.message}`)
204
- process.exit(1)
205
- }
206
- })
207
-
208
- app
209
- .command('analytics:query <siteId>', 'Query analytics data for a site')
210
- .option('--table <name>', 'DynamoDB table name', { default: 'ts-analytics' })
211
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
212
- .option('--limit <n>', 'Max items to return', { default: '10' })
213
- .option('--type <type>', 'Filter by type (pageview, event, etc.)')
214
- .action(async (siteId: string, options: { table: string; region: string; limit: string; type?: string }) => {
215
- cli.header(`Analytics Data: ${siteId}`)
216
-
217
- try {
218
- const dynamodb = new DynamoDBClient(options.region)
219
-
220
- const spinner = new cli.Spinner('Querying data...')
221
- spinner.start()
222
-
223
- const result = await dynamodb.query({
224
- TableName: options.table,
225
- KeyConditionExpression: 'pk = :pk',
226
- ExpressionAttributeValues: {
227
- ':pk': { S: `SITE#${siteId}` },
228
- },
229
- ScanIndexForward: false,
230
- Limit: parseInt(options.limit, 10),
231
- })
232
-
233
- spinner.succeed(`Found ${result.Items?.length || 0} items`)
234
-
235
- if (!result.Items || result.Items.length === 0) {
236
- cli.info('No data found for this site')
237
- return
238
- }
239
-
240
- const items = result.Items.map(item => DynamoDBClient.unmarshal(item))
241
-
242
- for (const item of items) {
243
- cli.info('')
244
- cli.info(`SK: ${item.sk}`)
245
- if (item.path) cli.info(` Path: ${item.path}`)
246
- if (item.timestamp) cli.info(` Time: ${item.timestamp}`)
247
- if (item.visitorId) cli.info(` Visitor: ${item.visitorId}`)
248
- if (item.browser) cli.info(` Browser: ${item.browser}`)
249
- if (item.country) cli.info(` Country: ${item.country}`)
250
- }
251
- }
252
- catch (error: any) {
253
- cli.error(`Failed to query data: ${error.message}`)
254
- process.exit(1)
255
- }
256
- })
257
-
258
- app
259
- .command('analytics:realtime <siteId>', 'Check realtime visitors for a site')
260
- .option('--table <name>', 'DynamoDB table name', { default: 'ts-analytics' })
261
- .option('--region <region>', 'AWS region', { default: 'us-east-1' })
262
- .option('--minutes <n>', 'Minutes to look back', { default: '5' })
263
- .action(async (siteId: string, options: { table: string; region: string; minutes: string }) => {
264
- cli.header(`Realtime: ${siteId}`)
265
-
266
- try {
267
- const dynamodb = new DynamoDBClient(options.region)
268
-
269
- const spinner = new cli.Spinner('Checking realtime...')
270
- spinner.start()
271
-
272
- const minutesAgo = parseInt(options.minutes, 10)
273
- const cutoff = new Date(Date.now() - minutesAgo * 60 * 1000)
274
-
275
- const result = await dynamodb.query({
276
- TableName: options.table,
277
- KeyConditionExpression: 'pk = :pk AND sk BETWEEN :start AND :end',
278
- ExpressionAttributeValues: {
279
- ':pk': { S: `SITE#${siteId}` },
280
- ':start': { S: `PAGEVIEW#${cutoff.toISOString()}` },
281
- ':end': { S: 'PAGEVIEW#Z' },
282
- },
283
- ScanIndexForward: false,
284
- })
285
-
286
- spinner.succeed(`Found ${result.Items?.length || 0} pageviews in last ${minutesAgo} minutes`)
287
-
288
- if (!result.Items || result.Items.length === 0) {
289
- cli.warn('No recent pageviews found')
290
- cli.info('')
291
- cli.info('Possible issues:')
292
- cli.info(' 1. Tracking script not installed correctly')
293
- cli.info(' 2. Site ID mismatch')
294
- cli.info(' 3. CORS or network issues')
295
- return
296
- }
297
-
298
- const items = result.Items.map(item => DynamoDBClient.unmarshal(item))
299
- const uniqueVisitors = new Set(items.map(i => i.visitorId)).size
300
-
301
- cli.info('')
302
- cli.success(`${uniqueVisitors} unique visitor(s) online`)
303
- cli.info('')
304
-
305
- // Group by path
306
- const byPath: Record<string, number> = {}
307
- for (const item of items) {
308
- const path = item.path || '/'
309
- byPath[path] = (byPath[path] || 0) + 1
310
- }
311
-
312
- cli.info('Active pages:')
313
- for (const [path, count] of Object.entries(byPath).sort((a, b) => b[1] - a[1]).slice(0, 5)) {
314
- cli.info(` ${path}: ${count} view(s)`)
315
- }
316
-
317
- cli.info('')
318
- cli.info('Recent pageviews:')
319
- for (const item of items.slice(0, 5)) {
320
- cli.info(` ${item.timestamp} - ${item.path} (${item.browser || 'Unknown'})`)
321
- }
322
- }
323
- catch (error: any) {
324
- cli.error(`Failed to check realtime: ${error.message}`)
325
- process.exit(1)
326
- }
327
- })
328
- }