@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.
- package/README.md +98 -13
- package/dist/aws/acm.d.ts +129 -0
- package/dist/aws/application-autoscaling.d.ts +282 -0
- package/dist/aws/bedrock.d.ts +2292 -0
- package/dist/aws/client.d.ts +79 -0
- package/dist/aws/cloudformation.d.ts +105 -0
- package/dist/aws/cloudfront.d.ts +265 -0
- package/dist/aws/cloudwatch-logs.d.ts +48 -0
- package/dist/aws/comprehend.d.ts +505 -0
- package/dist/aws/connect.d.ts +377 -0
- package/dist/aws/deploy-imap.d.ts +14 -0
- package/dist/aws/dynamodb.d.ts +176 -0
- package/dist/aws/ec2.d.ts +272 -0
- package/dist/aws/ecr.d.ts +149 -0
- package/dist/aws/ecs.d.ts +162 -0
- package/dist/aws/elasticache.d.ts +71 -0
- package/dist/aws/elbv2.d.ts +248 -0
- package/dist/aws/email.d.ts +175 -0
- package/dist/aws/eventbridge.d.ts +142 -0
- package/dist/aws/iam.d.ts +638 -0
- package/dist/aws/imap-server.d.ts +119 -0
- package/{src/aws/index.ts → dist/aws/index.d.ts} +62 -83
- package/{src/aws/kendra.ts → dist/aws/kendra.d.ts} +71 -386
- package/dist/aws/lambda.d.ts +232 -0
- package/dist/aws/opensearch.d.ts +87 -0
- package/dist/aws/personalize.d.ts +516 -0
- package/dist/aws/polly.d.ts +214 -0
- package/dist/aws/rds.d.ts +240 -0
- package/dist/aws/rekognition.d.ts +543 -0
- package/dist/aws/route53-domains.d.ts +113 -0
- package/dist/aws/route53.d.ts +215 -0
- package/dist/aws/s3.d.ts +212 -0
- package/dist/aws/scheduler.d.ts +140 -0
- package/dist/aws/secrets-manager.d.ts +170 -0
- package/dist/aws/ses.d.ts +288 -0
- package/dist/aws/setup-phone.d.ts +0 -0
- package/dist/aws/setup-sms.d.ts +115 -0
- package/dist/aws/sms.d.ts +304 -0
- package/dist/aws/smtp-server.d.ts +61 -0
- package/dist/aws/sns.d.ts +117 -0
- package/dist/aws/sqs.d.ts +65 -0
- package/dist/aws/ssm.d.ts +179 -0
- package/dist/aws/sts.d.ts +15 -0
- package/dist/aws/support.d.ts +104 -0
- package/dist/aws/test-imap.d.ts +0 -0
- package/dist/aws/textract.d.ts +403 -0
- package/dist/aws/transcribe.d.ts +60 -0
- package/dist/aws/translate.d.ts +358 -0
- package/dist/aws/voice.d.ts +219 -0
- package/dist/bin/cli.js +1724 -0
- package/dist/config.d.ts +7 -0
- package/dist/deploy/index.d.ts +2 -0
- package/dist/deploy/static-site-external-dns.d.ts +51 -0
- package/dist/deploy/static-site.d.ts +71 -0
- package/dist/dns/cloudflare.d.ts +52 -0
- package/dist/dns/godaddy.d.ts +38 -0
- package/dist/dns/index.d.ts +45 -0
- package/dist/dns/porkbun.d.ts +18 -0
- package/dist/dns/route53-adapter.d.ts +38 -0
- package/{src/dns/types.ts → dist/dns/types.d.ts} +26 -63
- package/dist/dns/validator.d.ts +78 -0
- package/dist/generators/index.d.ts +1 -0
- package/dist/generators/infrastructure.d.ts +30 -0
- package/{src/index.ts → dist/index.d.ts} +70 -93
- package/dist/index.js +7881 -0
- package/dist/push/apns.d.ts +60 -0
- package/dist/push/fcm.d.ts +117 -0
- package/dist/push/index.d.ts +14 -0
- package/dist/security/pre-deploy-scanner.d.ts +69 -0
- package/dist/ssl/acme-client.d.ts +67 -0
- package/dist/ssl/index.d.ts +2 -0
- package/dist/ssl/letsencrypt.d.ts +48 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils/cli.d.ts +123 -0
- package/dist/validation/index.d.ts +1 -0
- package/dist/validation/template.d.ts +23 -0
- package/package.json +8 -8
- package/bin/cli.ts +0 -133
- package/bin/commands/analytics.ts +0 -328
- package/bin/commands/api.ts +0 -379
- package/bin/commands/assets.ts +0 -221
- package/bin/commands/audit.ts +0 -501
- package/bin/commands/backup.ts +0 -682
- package/bin/commands/cache.ts +0 -294
- package/bin/commands/cdn.ts +0 -281
- package/bin/commands/config.ts +0 -202
- package/bin/commands/container.ts +0 -105
- package/bin/commands/cost.ts +0 -208
- package/bin/commands/database.ts +0 -401
- package/bin/commands/deploy.ts +0 -674
- package/bin/commands/domain.ts +0 -397
- package/bin/commands/email.ts +0 -423
- package/bin/commands/environment.ts +0 -285
- package/bin/commands/events.ts +0 -424
- package/bin/commands/firewall.ts +0 -145
- package/bin/commands/function.ts +0 -116
- package/bin/commands/generate.ts +0 -280
- package/bin/commands/git.ts +0 -139
- package/bin/commands/iam.ts +0 -464
- package/bin/commands/index.ts +0 -48
- package/bin/commands/init.ts +0 -120
- package/bin/commands/logs.ts +0 -148
- package/bin/commands/network.ts +0 -579
- package/bin/commands/notify.ts +0 -489
- package/bin/commands/queue.ts +0 -407
- package/bin/commands/scheduler.ts +0 -370
- package/bin/commands/secrets.ts +0 -54
- package/bin/commands/server.ts +0 -629
- package/bin/commands/shared.ts +0 -97
- package/bin/commands/ssl.ts +0 -138
- package/bin/commands/stack.ts +0 -325
- package/bin/commands/status.ts +0 -385
- package/bin/commands/storage.ts +0 -450
- package/bin/commands/team.ts +0 -96
- package/bin/commands/tunnel.ts +0 -489
- package/bin/commands/utils.ts +0 -202
- package/build.ts +0 -15
- package/cloud +0 -2
- package/src/aws/acm.ts +0 -768
- package/src/aws/application-autoscaling.ts +0 -845
- package/src/aws/bedrock.ts +0 -4074
- package/src/aws/client.ts +0 -878
- package/src/aws/cloudformation.ts +0 -896
- package/src/aws/cloudfront.ts +0 -1531
- package/src/aws/cloudwatch-logs.ts +0 -154
- package/src/aws/comprehend.ts +0 -839
- package/src/aws/connect.ts +0 -1056
- package/src/aws/deploy-imap.ts +0 -384
- package/src/aws/dynamodb.ts +0 -340
- package/src/aws/ec2.ts +0 -1385
- package/src/aws/ecr.ts +0 -621
- package/src/aws/ecs.ts +0 -615
- package/src/aws/elasticache.ts +0 -301
- package/src/aws/elbv2.ts +0 -942
- package/src/aws/email.ts +0 -928
- package/src/aws/eventbridge.ts +0 -248
- package/src/aws/iam.ts +0 -1689
- package/src/aws/imap-server.ts +0 -2100
- package/src/aws/lambda.ts +0 -786
- package/src/aws/opensearch.ts +0 -158
- package/src/aws/personalize.ts +0 -977
- package/src/aws/polly.ts +0 -559
- package/src/aws/rds.ts +0 -888
- package/src/aws/rekognition.ts +0 -846
- package/src/aws/route53-domains.ts +0 -359
- package/src/aws/route53.ts +0 -1046
- package/src/aws/s3.ts +0 -2318
- package/src/aws/scheduler.ts +0 -571
- package/src/aws/secrets-manager.ts +0 -769
- package/src/aws/ses.ts +0 -1081
- package/src/aws/setup-phone.ts +0 -104
- package/src/aws/setup-sms.ts +0 -580
- package/src/aws/sms.ts +0 -1735
- package/src/aws/smtp-server.ts +0 -531
- package/src/aws/sns.ts +0 -758
- package/src/aws/sqs.ts +0 -382
- package/src/aws/ssm.ts +0 -807
- package/src/aws/sts.ts +0 -92
- package/src/aws/support.ts +0 -391
- package/src/aws/test-imap.ts +0 -86
- package/src/aws/textract.ts +0 -780
- package/src/aws/transcribe.ts +0 -108
- package/src/aws/translate.ts +0 -641
- package/src/aws/voice.ts +0 -1379
- package/src/config.ts +0 -35
- package/src/deploy/index.ts +0 -7
- package/src/deploy/static-site-external-dns.ts +0 -906
- package/src/deploy/static-site.ts +0 -1125
- package/src/dns/godaddy.ts +0 -412
- package/src/dns/index.ts +0 -183
- package/src/dns/porkbun.ts +0 -362
- package/src/dns/route53-adapter.ts +0 -414
- package/src/dns/validator.ts +0 -369
- package/src/generators/index.ts +0 -5
- package/src/generators/infrastructure.ts +0 -1660
- package/src/push/apns.ts +0 -452
- package/src/push/fcm.ts +0 -506
- package/src/push/index.ts +0 -58
- package/src/ssl/acme-client.ts +0 -478
- package/src/ssl/index.ts +0 -7
- package/src/ssl/letsencrypt.ts +0 -747
- package/src/types.ts +0 -2
- package/src/utils/cli.ts +0 -398
- package/src/validation/index.ts +0 -5
- package/src/validation/template.ts +0 -405
- package/test/index.test.ts +0 -128
- 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
|
-
}
|