@supalytics/cli 0.4.3 → 0.4.4
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/funnels.ts +48 -62
package/package.json
CHANGED
package/src/commands/funnels.ts
CHANGED
|
@@ -37,10 +37,10 @@ Examples:
|
|
|
37
37
|
supalytics funnels
|
|
38
38
|
|
|
39
39
|
# View a funnel with conversion analysis
|
|
40
|
-
supalytics funnels
|
|
40
|
+
supalytics funnels <id>
|
|
41
41
|
|
|
42
42
|
# View with custom date range
|
|
43
|
-
supalytics funnels
|
|
43
|
+
supalytics funnels <id> -p 90d
|
|
44
44
|
|
|
45
45
|
# Create a funnel
|
|
46
46
|
supalytics funnels create "Signup Flow" --step "page:/pricing" --step "event:signup_clicked" --step "purchase"
|
|
@@ -215,9 +215,13 @@ function renderAnalysis(rows: FunnelAnalysisRow[], funnel: { name: string; descr
|
|
|
215
215
|
export const funnelsCommand = new Command("funnels")
|
|
216
216
|
.description("Manage and analyze conversion funnels")
|
|
217
217
|
.addHelpText("after", funnelsExamples)
|
|
218
|
+
.argument("[id]", "Funnel ID to view details and conversion analysis")
|
|
218
219
|
.option("-s, --site <site>", "Site to query")
|
|
220
|
+
.option("-p, --period <period>", "Time period: 7d, 14d, 30d, 90d, 12mo, all", "30d")
|
|
221
|
+
.option("--start <date>", "Start date (YYYY-MM-DD)")
|
|
222
|
+
.option("--end <date>", "End date (YYYY-MM-DD)")
|
|
219
223
|
.option("--json", "Output as JSON")
|
|
220
|
-
.action(async (options) => {
|
|
224
|
+
.action(async (id, options) => {
|
|
221
225
|
const site = options.site || (await getDefaultSite())
|
|
222
226
|
|
|
223
227
|
if (!site) {
|
|
@@ -229,6 +233,47 @@ export const funnelsCommand = new Command("funnels")
|
|
|
229
233
|
process.exit(1)
|
|
230
234
|
}
|
|
231
235
|
|
|
236
|
+
// If an ID is provided, show funnel details + analysis
|
|
237
|
+
if (id) {
|
|
238
|
+
try {
|
|
239
|
+
const dateRange =
|
|
240
|
+
options.start && options.end
|
|
241
|
+
? ([options.start, options.end] as [string, string])
|
|
242
|
+
: parsePeriod(options.period as string)
|
|
243
|
+
|
|
244
|
+
// Fetch funnel definition and run analysis in parallel
|
|
245
|
+
const [funnelResponse, analysisResponse] = await Promise.all([
|
|
246
|
+
getFunnel(site, id),
|
|
247
|
+
analyzeFunnel(site, id, dateRange),
|
|
248
|
+
])
|
|
249
|
+
|
|
250
|
+
if (options.json) {
|
|
251
|
+
console.log(
|
|
252
|
+
JSON.stringify(
|
|
253
|
+
{
|
|
254
|
+
funnel: funnelResponse.data,
|
|
255
|
+
analysis: analysisResponse.data,
|
|
256
|
+
meta: analysisResponse.meta,
|
|
257
|
+
},
|
|
258
|
+
null,
|
|
259
|
+
2
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const [startDate, endDate] = analysisResponse.meta.date_range
|
|
266
|
+
console.log(chalk.dim(` ${startDate} → ${endDate} (${analysisResponse.meta.query_ms}ms)`))
|
|
267
|
+
|
|
268
|
+
renderAnalysis(analysisResponse.data, funnelResponse.data)
|
|
269
|
+
} catch (error) {
|
|
270
|
+
console.error(chalk.red(`Error: ${(error as Error).message}`))
|
|
271
|
+
process.exit(1)
|
|
272
|
+
}
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// No ID — list all funnels
|
|
232
277
|
try {
|
|
233
278
|
const response = await listFunnels(site)
|
|
234
279
|
|
|
@@ -271,65 +316,6 @@ export const funnelsCommand = new Command("funnels")
|
|
|
271
316
|
}
|
|
272
317
|
})
|
|
273
318
|
|
|
274
|
-
// Subcommand: view
|
|
275
|
-
funnelsCommand
|
|
276
|
-
.command("view <id>")
|
|
277
|
-
.description("View funnel details and conversion analysis")
|
|
278
|
-
.option("-s, --site <site>", "Site to query")
|
|
279
|
-
.option("-p, --period <period>", "Time period: 7d, 14d, 30d, 90d, 12mo, all", "30d")
|
|
280
|
-
.option("--start <date>", "Start date (YYYY-MM-DD)")
|
|
281
|
-
.option("--end <date>", "End date (YYYY-MM-DD)")
|
|
282
|
-
.option("--json", "Output as JSON")
|
|
283
|
-
.action(async (id, _options, cmd) => {
|
|
284
|
-
const options = mergedOpts(cmd)
|
|
285
|
-
const site = await resolveSiteOption(cmd)
|
|
286
|
-
|
|
287
|
-
if (!site) {
|
|
288
|
-
console.error(
|
|
289
|
-
chalk.red(
|
|
290
|
-
"Error: No site specified. Use --site or set a default with `supalytics login --site`"
|
|
291
|
-
)
|
|
292
|
-
)
|
|
293
|
-
process.exit(1)
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
try {
|
|
297
|
-
const dateRange =
|
|
298
|
-
options.start && options.end
|
|
299
|
-
? ([options.start, options.end] as [string, string])
|
|
300
|
-
: parsePeriod(options.period as string)
|
|
301
|
-
|
|
302
|
-
// Fetch funnel definition and run analysis in parallel
|
|
303
|
-
const [funnelResponse, analysisResponse] = await Promise.all([
|
|
304
|
-
getFunnel(site, id),
|
|
305
|
-
analyzeFunnel(site, id, dateRange),
|
|
306
|
-
])
|
|
307
|
-
|
|
308
|
-
if (options.json) {
|
|
309
|
-
console.log(
|
|
310
|
-
JSON.stringify(
|
|
311
|
-
{
|
|
312
|
-
funnel: funnelResponse.data,
|
|
313
|
-
analysis: analysisResponse.data,
|
|
314
|
-
meta: analysisResponse.meta,
|
|
315
|
-
},
|
|
316
|
-
null,
|
|
317
|
-
2
|
|
318
|
-
)
|
|
319
|
-
)
|
|
320
|
-
return
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const [startDate, endDate] = analysisResponse.meta.date_range
|
|
324
|
-
console.log(chalk.dim(` ${startDate} → ${endDate} (${analysisResponse.meta.query_ms}ms)`))
|
|
325
|
-
|
|
326
|
-
renderAnalysis(analysisResponse.data, funnelResponse.data)
|
|
327
|
-
} catch (error) {
|
|
328
|
-
console.error(chalk.red(`Error: ${(error as Error).message}`))
|
|
329
|
-
process.exit(1)
|
|
330
|
-
}
|
|
331
|
-
})
|
|
332
|
-
|
|
333
319
|
// Subcommand: create
|
|
334
320
|
funnelsCommand
|
|
335
321
|
.command("create <name>")
|