@supalytics/cli 0.4.0 → 0.4.2
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/package.json +1 -1
- package/src/commands/sites.ts +231 -227
- package/src/commands/update.ts +68 -52
- package/src/index.ts +45 -79
package/package.json
CHANGED
package/src/commands/sites.ts
CHANGED
|
@@ -1,251 +1,255 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import chalk from "chalk"
|
|
2
|
+
import { Command } from "commander"
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "../config"
|
|
4
|
+
addSiteWithId,
|
|
5
|
+
getAuth,
|
|
6
|
+
getConfig,
|
|
7
|
+
removeSite,
|
|
8
|
+
saveConfig,
|
|
9
|
+
setDefaultSite,
|
|
10
|
+
} from "../config"
|
|
11
11
|
|
|
12
|
-
const WEB_BASE = process.env.SUPALYTICS_WEB_URL || "https://www.supalytics.co"
|
|
12
|
+
const WEB_BASE = process.env.SUPALYTICS_WEB_URL || "https://www.supalytics.co"
|
|
13
13
|
|
|
14
14
|
interface CreateSiteResponse {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
site: {
|
|
16
|
+
id: string
|
|
17
|
+
site_id: string
|
|
18
|
+
domain: string
|
|
19
|
+
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
interface UpdateSiteResponse {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
site: {
|
|
24
|
+
id: string
|
|
25
|
+
site_id: string
|
|
26
|
+
domain: string
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export async function createSiteViaApi(
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
accessToken: string,
|
|
32
|
+
identifier: string
|
|
33
33
|
): Promise<CreateSiteResponse> {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
34
|
+
let response: Response
|
|
35
|
+
try {
|
|
36
|
+
response = await fetch(`${WEB_BASE}/api/cli/sites`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: `Bearer ${accessToken}`,
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({ identifier }),
|
|
43
|
+
})
|
|
44
|
+
} catch {
|
|
45
|
+
throw new Error(`Network error: Could not connect to ${WEB_BASE}`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
let errorMessage = "Failed to create site"
|
|
50
|
+
try {
|
|
51
|
+
const error = await response.json()
|
|
52
|
+
errorMessage = error.error || errorMessage
|
|
53
|
+
} catch {
|
|
54
|
+
// Response wasn't JSON
|
|
55
|
+
}
|
|
56
|
+
throw new Error(errorMessage)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return response.json()
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
export const sitesCommand = new Command("sites")
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
})
|
|
63
|
+
.description("List all configured sites")
|
|
64
|
+
.action(async () => {
|
|
65
|
+
const config = await getConfig()
|
|
66
|
+
const sites = Object.keys(config.sites)
|
|
67
|
+
|
|
68
|
+
if (sites.length === 0) {
|
|
69
|
+
console.log(chalk.dim("No sites configured."))
|
|
70
|
+
console.log(
|
|
71
|
+
chalk.dim("Run `supalytics login` then `supalytics sites add <name>` to add a site.")
|
|
72
|
+
)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log()
|
|
77
|
+
console.log(chalk.bold("Configured Sites"))
|
|
78
|
+
console.log()
|
|
79
|
+
|
|
80
|
+
for (const site of sites) {
|
|
81
|
+
const isDefault = config.defaultSite === site
|
|
82
|
+
const siteId = config.sites[site].siteId
|
|
83
|
+
|
|
84
|
+
if (isDefault) {
|
|
85
|
+
console.log(
|
|
86
|
+
` ${chalk.green("●")} ${site} ${chalk.dim("(default)")}${siteId ? ` ${chalk.dim(siteId)}` : ""}`
|
|
87
|
+
)
|
|
88
|
+
} else {
|
|
89
|
+
console.log(` ${chalk.dim("○")} ${site}${siteId ? ` ${chalk.dim(siteId)}` : ""}`)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
console.log()
|
|
93
|
+
})
|
|
90
94
|
|
|
91
95
|
// sites add <identifier>
|
|
92
96
|
const addCommand = new Command("add")
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
97
|
+
.description("Create a new site")
|
|
98
|
+
.argument("<identifier>", "Domain or project name")
|
|
99
|
+
.action(async (identifier: string) => {
|
|
100
|
+
const auth = await getAuth()
|
|
101
|
+
if (!auth) {
|
|
102
|
+
console.error(chalk.red("Not logged in. Run `supalytics login` first."))
|
|
103
|
+
process.exit(1)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log(chalk.dim("Creating site..."))
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const result = await createSiteViaApi(auth.accessToken, identifier)
|
|
110
|
+
|
|
111
|
+
// Store locally (including website UUID for updates)
|
|
112
|
+
await addSiteWithId(result.site.domain, result.site.site_id, result.site.id)
|
|
113
|
+
|
|
114
|
+
console.log(chalk.green(`✓ Created ${result.site.domain}`))
|
|
115
|
+
console.log(chalk.dim(` Site ID: ${result.site.site_id}`))
|
|
116
|
+
console.log()
|
|
117
|
+
console.log(chalk.dim("Add this to your HTML <head>:"))
|
|
118
|
+
console.log()
|
|
119
|
+
console.log(
|
|
120
|
+
chalk.cyan(
|
|
121
|
+
` <script src="https://cdn.supalytics.co/script.js" data-site="${result.site.site_id}" defer></script>`
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
console.log()
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error(chalk.red(`Error: ${(error as Error).message}`))
|
|
127
|
+
process.exit(1)
|
|
128
|
+
}
|
|
129
|
+
})
|
|
126
130
|
|
|
127
131
|
// sites update <identifier> --domain <domain>
|
|
128
132
|
const updateCommand = new Command("update")
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
sitesCommand.addCommand(addCommand)
|
|
218
|
-
sitesCommand.addCommand(updateCommand)
|
|
133
|
+
.description("Update a site's domain")
|
|
134
|
+
.argument("<identifier>", "Current domain/identifier")
|
|
135
|
+
.option("-d, --domain <domain>", "New domain name")
|
|
136
|
+
.action(async (identifier: string, options: { domain?: string }) => {
|
|
137
|
+
if (!options.domain) {
|
|
138
|
+
console.error(chalk.red("Error: --domain is required"))
|
|
139
|
+
console.error(chalk.dim("Usage: supalytics sites update <identifier> --domain <new-domain>"))
|
|
140
|
+
process.exit(1)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const auth = await getAuth()
|
|
144
|
+
if (!auth) {
|
|
145
|
+
console.error(chalk.red("Not logged in. Run `supalytics login` first."))
|
|
146
|
+
process.exit(1)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Get site from local config
|
|
150
|
+
const config = await getConfig()
|
|
151
|
+
const siteConfig = config.sites[identifier]
|
|
152
|
+
if (!siteConfig) {
|
|
153
|
+
console.error(chalk.red(`Site '${identifier}' not found locally.`))
|
|
154
|
+
const sites = Object.keys(config.sites)
|
|
155
|
+
if (sites.length > 0) {
|
|
156
|
+
console.log(chalk.dim(`Available sites: ${sites.join(", ")}`))
|
|
157
|
+
}
|
|
158
|
+
process.exit(1)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
console.log(chalk.dim("Updating site..."))
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
// Try to use locally stored website ID first
|
|
165
|
+
let websiteId = siteConfig.id
|
|
166
|
+
|
|
167
|
+
// If no local ID, fetch from server
|
|
168
|
+
if (!websiteId) {
|
|
169
|
+
const listResponse = await fetch(`${WEB_BASE}/api/cli/sites`, {
|
|
170
|
+
headers: { Authorization: `Bearer ${auth.accessToken}` },
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
if (!listResponse.ok) {
|
|
174
|
+
throw new Error("Failed to fetch sites")
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const { sites } = await listResponse.json()
|
|
178
|
+
const site = sites.find((s: { domain: string }) => s.domain === identifier)
|
|
179
|
+
|
|
180
|
+
if (!site) {
|
|
181
|
+
throw new Error(`Site '${identifier}' not found on server`)
|
|
182
|
+
}
|
|
183
|
+
websiteId = site.id
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Update via API
|
|
187
|
+
const updateResponse = await fetch(`${WEB_BASE}/api/cli/sites/${websiteId}`, {
|
|
188
|
+
method: "PATCH",
|
|
189
|
+
headers: {
|
|
190
|
+
Authorization: `Bearer ${auth.accessToken}`,
|
|
191
|
+
"Content-Type": "application/json",
|
|
192
|
+
},
|
|
193
|
+
body: JSON.stringify({ domain: options.domain }),
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
if (!updateResponse.ok) {
|
|
197
|
+
const error = await updateResponse.json()
|
|
198
|
+
throw new Error(error.error || "Failed to update site")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const result: UpdateSiteResponse = await updateResponse.json()
|
|
202
|
+
|
|
203
|
+
// Update local config (preserve all fields)
|
|
204
|
+
const { siteId: existingSiteId, id: existingId } = siteConfig
|
|
205
|
+
const siteId = existingSiteId || result.site.site_id
|
|
206
|
+
const id = existingId || websiteId
|
|
207
|
+
delete config.sites[identifier]
|
|
208
|
+
config.sites[options.domain] = { siteId, id }
|
|
209
|
+
if (config.defaultSite === identifier) {
|
|
210
|
+
config.defaultSite = options.domain
|
|
211
|
+
}
|
|
212
|
+
await saveConfig(config)
|
|
213
|
+
|
|
214
|
+
console.log(chalk.green(`✓ Updated ${identifier} → ${options.domain}`))
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(chalk.red(`Error: ${(error as Error).message}`))
|
|
217
|
+
process.exit(1)
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
sitesCommand.addCommand(addCommand)
|
|
222
|
+
sitesCommand.addCommand(updateCommand)
|
|
219
223
|
|
|
220
224
|
export const defaultCommand = new Command("default")
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
225
|
+
.description("Set the default site")
|
|
226
|
+
.argument("<domain>", "Domain to set as default")
|
|
227
|
+
.action(async (domain: string) => {
|
|
228
|
+
const success = await setDefaultSite(domain)
|
|
229
|
+
|
|
230
|
+
if (!success) {
|
|
231
|
+
const config = await getConfig()
|
|
232
|
+
const sites = Object.keys(config.sites)
|
|
233
|
+
console.error(chalk.red(`Error: Site '${domain}' not found.`))
|
|
234
|
+
if (sites.length > 0) {
|
|
235
|
+
console.log(chalk.dim(`Available sites: ${sites.join(", ")}`))
|
|
236
|
+
}
|
|
237
|
+
process.exit(1)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log(chalk.green(`✓ Default site set to ${domain}`))
|
|
241
|
+
})
|
|
238
242
|
|
|
239
243
|
export const removeCommand = new Command("remove")
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
244
|
+
.description("Remove a site from local CLI config (does not delete from server)")
|
|
245
|
+
.argument("<domain>", "Domain to remove")
|
|
246
|
+
.action(async (domain: string) => {
|
|
247
|
+
const success = await removeSite(domain)
|
|
248
|
+
|
|
249
|
+
if (!success) {
|
|
250
|
+
console.error(chalk.red(`Error: Site '${domain}' not found.`))
|
|
251
|
+
process.exit(1)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.log(chalk.green(`✓ Removed ${domain}`))
|
|
255
|
+
})
|
package/src/commands/update.ts
CHANGED
|
@@ -1,54 +1,70 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import chalk from "chalk"
|
|
3
|
-
import {
|
|
1
|
+
import { $ } from "bun"
|
|
2
|
+
import chalk from "chalk"
|
|
3
|
+
import { Command } from "commander"
|
|
4
4
|
|
|
5
5
|
export const updateCommand = new Command("update")
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
6
|
+
.description("Update Supalytics CLI to the latest version")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
// Read current version
|
|
9
|
+
const pkg = await Bun.file(new URL("../../package.json", import.meta.url)).json()
|
|
10
|
+
console.log(chalk.dim(`Current version: ${pkg.version}`))
|
|
11
|
+
console.log(chalk.dim("Checking for updates..."))
|
|
12
|
+
console.log()
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Check latest version from npm
|
|
16
|
+
const response = await fetch("https://registry.npmjs.org/@supalytics/cli/latest")
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
throw new Error("Failed to check npm registry")
|
|
19
|
+
}
|
|
20
|
+
const data = await response.json()
|
|
21
|
+
const latestVersion = data.version
|
|
22
|
+
|
|
23
|
+
if (latestVersion === pkg.version) {
|
|
24
|
+
console.log(chalk.green("✓ Already on the latest version"))
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log(chalk.cyan(`New version available: ${latestVersion}`))
|
|
29
|
+
console.log()
|
|
30
|
+
console.log(chalk.dim("Updating..."))
|
|
31
|
+
|
|
32
|
+
// Try to update using the appropriate package manager
|
|
33
|
+
let updated = false
|
|
34
|
+
|
|
35
|
+
// Try bun first (bun add -g for global packages)
|
|
36
|
+
try {
|
|
37
|
+
await $`bun add -g @supalytics/cli@latest`.quiet()
|
|
38
|
+
updated = true
|
|
39
|
+
} catch {
|
|
40
|
+
// bun not available or failed, try npm
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Fall back to npm if bun didn't work
|
|
44
|
+
if (!updated) {
|
|
45
|
+
try {
|
|
46
|
+
await $`npm install -g @supalytics/cli@latest`.quiet()
|
|
47
|
+
updated = true
|
|
48
|
+
} catch {
|
|
49
|
+
// npm also failed
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!updated) {
|
|
54
|
+
console.log(chalk.yellow("Automatic update failed."))
|
|
55
|
+
console.log()
|
|
56
|
+
console.log("Please update manually:")
|
|
57
|
+
console.log(chalk.cyan(" bun add -g @supalytics/cli@latest"))
|
|
58
|
+
console.log(" or")
|
|
59
|
+
console.log(chalk.cyan(" npm install -g @supalytics/cli@latest"))
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(chalk.green(`✓ Updated to ${latestVersion}`))
|
|
64
|
+
console.log()
|
|
65
|
+
console.log(chalk.dim("Run `supalytics --version` to verify"))
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(chalk.red(`Error: ${(error as Error).message}`))
|
|
68
|
+
process.exit(1)
|
|
69
|
+
}
|
|
70
|
+
})
|
package/src/index.ts
CHANGED
|
@@ -1,105 +1,71 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { program } from "commander"
|
|
3
|
-
import updateNotifier from "update-notifier"
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { realtimeCommand } from "./commands/realtime"
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { updateCommand } from "./commands/update"
|
|
2
|
+
import { program } from "commander"
|
|
3
|
+
import updateNotifier from "update-notifier"
|
|
4
|
+
import { annotationsCommand } from "./commands/annotations"
|
|
5
|
+
import { completionsCommand } from "./commands/completions"
|
|
6
|
+
import { countriesCommand } from "./commands/countries"
|
|
7
|
+
import { eventsCommand } from "./commands/events"
|
|
8
|
+
import { initCommand } from "./commands/init"
|
|
9
|
+
import { journeysCommand } from "./commands/journeys"
|
|
10
|
+
import { loginCommand } from "./commands/login"
|
|
11
|
+
import { logoutCommand } from "./commands/logout"
|
|
12
|
+
import { pagesCommand } from "./commands/pages"
|
|
13
|
+
import { queryCommand } from "./commands/query"
|
|
14
|
+
import { realtimeCommand } from "./commands/realtime"
|
|
15
|
+
import { referrersCommand } from "./commands/referrers"
|
|
16
|
+
import { defaultCommand, removeCommand, sitesCommand } from "./commands/sites"
|
|
17
|
+
import { statsCommand } from "./commands/stats"
|
|
18
|
+
import { trendCommand } from "./commands/trend"
|
|
19
|
+
import { updateCommand } from "./commands/update"
|
|
20
20
|
|
|
21
21
|
const description = `CLI for Supalytics web analytics.
|
|
22
22
|
|
|
23
|
-
Quick Start:
|
|
24
|
-
supalytics init Auto-setup: login → create site → get snippet
|
|
25
|
-
|
|
26
|
-
Authentication:
|
|
27
|
-
supalytics login Open browser to authenticate
|
|
28
|
-
supalytics logout Log out and remove all credentials
|
|
29
|
-
|
|
30
|
-
Site Management:
|
|
31
|
-
supalytics sites List configured sites
|
|
32
|
-
supalytics sites add <name> Create a new site
|
|
33
|
-
supalytics sites update <name> --domain <domain> Update domain
|
|
34
|
-
supalytics default <domain> Set default site
|
|
35
|
-
supalytics remove <domain> Remove a site
|
|
36
|
-
|
|
37
23
|
Date Ranges:
|
|
38
24
|
--period: 7d, 14d, 30d, 90d, 12mo, all (default: 30d)
|
|
39
25
|
--start/--end: Custom range in YYYY-MM-DD format
|
|
40
26
|
|
|
41
27
|
Filters (-f, --filter):
|
|
42
28
|
Format: field:operator:value
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
referrer, utm_source, utm_medium, utm_campaign, utm_content, utm_term,
|
|
47
|
-
event, event_property, exit_link
|
|
48
|
-
|
|
49
|
-
Operators:
|
|
50
|
-
is Exact match (supports comma-separated: "country:is:US,UK")
|
|
51
|
-
is_not Exclude exact match
|
|
52
|
-
contains Substring match
|
|
53
|
-
not_contains Exclude substring
|
|
54
|
-
starts_with Prefix match
|
|
55
|
-
|
|
56
|
-
Examples:
|
|
57
|
-
-f "country:is:US"
|
|
58
|
-
-f "page:contains:/blog"
|
|
59
|
-
-f "device:is:mobile"
|
|
60
|
-
-f "referrer:is:twitter.com"
|
|
61
|
-
-f "event:is:signup"
|
|
62
|
-
-f "event_property:is:plan:premium"
|
|
29
|
+
Fields: page, country, browser, device, referrer, utm_*, event
|
|
30
|
+
Operators: is, is_not, contains, not_contains, starts_with
|
|
31
|
+
Example: -f "country:is:US" -f "page:contains:/blog"
|
|
63
32
|
|
|
64
33
|
Output:
|
|
65
|
-
--json Raw JSON output
|
|
66
|
-
--no-revenue Exclude revenue metrics
|
|
34
|
+
--json Raw JSON output
|
|
35
|
+
--no-revenue Exclude revenue metrics`
|
|
67
36
|
|
|
68
37
|
// Read version from package.json
|
|
69
|
-
const pkg = await Bun.file(new URL("../package.json", import.meta.url)).json()
|
|
38
|
+
const pkg = await Bun.file(new URL("../package.json", import.meta.url)).json()
|
|
70
39
|
|
|
71
40
|
// Check for updates (runs in background, non-blocking)
|
|
72
|
-
updateNotifier({ pkg }).notify()
|
|
41
|
+
updateNotifier({ pkg }).notify()
|
|
73
42
|
|
|
74
|
-
program
|
|
75
|
-
.name("supalytics")
|
|
76
|
-
.description(description)
|
|
77
|
-
.version(pkg.version);
|
|
43
|
+
program.name("supalytics").description(description).version(pkg.version)
|
|
78
44
|
|
|
79
45
|
// Quick start
|
|
80
|
-
program.addCommand(initCommand)
|
|
46
|
+
program.addCommand(initCommand)
|
|
81
47
|
|
|
82
48
|
// Auth & site management commands
|
|
83
|
-
program.addCommand(loginCommand)
|
|
84
|
-
program.addCommand(logoutCommand)
|
|
85
|
-
program.addCommand(sitesCommand)
|
|
86
|
-
program.addCommand(defaultCommand)
|
|
87
|
-
program.addCommand(removeCommand)
|
|
49
|
+
program.addCommand(loginCommand)
|
|
50
|
+
program.addCommand(logoutCommand)
|
|
51
|
+
program.addCommand(sitesCommand)
|
|
52
|
+
program.addCommand(defaultCommand)
|
|
53
|
+
program.addCommand(removeCommand)
|
|
88
54
|
|
|
89
55
|
// Analytics commands
|
|
90
|
-
program.addCommand(statsCommand)
|
|
91
|
-
program.addCommand(pagesCommand)
|
|
92
|
-
program.addCommand(referrersCommand)
|
|
93
|
-
program.addCommand(countriesCommand)
|
|
94
|
-
program.addCommand(trendCommand)
|
|
95
|
-
program.addCommand(queryCommand)
|
|
96
|
-
program.addCommand(eventsCommand)
|
|
97
|
-
program.addCommand(journeysCommand)
|
|
98
|
-
program.addCommand(realtimeCommand)
|
|
99
|
-
program.addCommand(annotationsCommand)
|
|
100
|
-
program.addCommand(completionsCommand)
|
|
56
|
+
program.addCommand(statsCommand)
|
|
57
|
+
program.addCommand(pagesCommand)
|
|
58
|
+
program.addCommand(referrersCommand)
|
|
59
|
+
program.addCommand(countriesCommand)
|
|
60
|
+
program.addCommand(trendCommand)
|
|
61
|
+
program.addCommand(queryCommand)
|
|
62
|
+
program.addCommand(eventsCommand)
|
|
63
|
+
program.addCommand(journeysCommand)
|
|
64
|
+
program.addCommand(realtimeCommand)
|
|
65
|
+
program.addCommand(annotationsCommand)
|
|
66
|
+
program.addCommand(completionsCommand)
|
|
101
67
|
|
|
102
68
|
// Utility commands
|
|
103
|
-
program.addCommand(updateCommand)
|
|
69
|
+
program.addCommand(updateCommand)
|
|
104
70
|
|
|
105
|
-
program.parse()
|
|
71
|
+
program.parse()
|