@bigcommerce/catalyst 1.1.0 → 1.2.0
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/dist/cli.js +131 -35
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import { randomBytes, randomUUID } from "crypto";
|
|
|
25
25
|
// package.json
|
|
26
26
|
var package_default = {
|
|
27
27
|
name: "@bigcommerce/catalyst",
|
|
28
|
-
version: "1.
|
|
28
|
+
version: "1.2.0",
|
|
29
29
|
type: "module",
|
|
30
30
|
repository: {
|
|
31
31
|
type: "git",
|
|
@@ -119,6 +119,8 @@ function getUserConfig() {
|
|
|
119
119
|
// src/cli/lib/telemetry.ts
|
|
120
120
|
var TELEMETRY_KEY_ENABLED = "telemetry.enabled";
|
|
121
121
|
var TELEMETRY_KEY_ID = `telemetry.anonymousId`;
|
|
122
|
+
var TELEMETRY_FLUSH_INTERVAL_MS = 200;
|
|
123
|
+
var TELEMETRY_HTTP_REQUEST_TIMEOUT_MS = 200;
|
|
122
124
|
var Telemetry = class {
|
|
123
125
|
constructor() {
|
|
124
126
|
this.commandName = "unknown";
|
|
@@ -133,7 +135,10 @@ var Telemetry = class {
|
|
|
133
135
|
this.correlationId = randomUUID();
|
|
134
136
|
this.startTime = Date.now();
|
|
135
137
|
this.analytics = new Analytics({
|
|
136
|
-
writeKey: "OCkxLj3KTc1N3ebEbnFBqbhxfE3tVb3Z"
|
|
138
|
+
writeKey: "OCkxLj3KTc1N3ebEbnFBqbhxfE3tVb3Z",
|
|
139
|
+
flushInterval: TELEMETRY_FLUSH_INTERVAL_MS,
|
|
140
|
+
httpRequestTimeout: TELEMETRY_HTTP_REQUEST_TIMEOUT_MS,
|
|
141
|
+
maxRetries: 0
|
|
137
142
|
});
|
|
138
143
|
}
|
|
139
144
|
durationMs() {
|
|
@@ -262,6 +267,10 @@ async function httpError(response, action) {
|
|
|
262
267
|
var DEVICE_OAUTH_CLIENT_ID = "b8063bu6hhml4e0lqh22yut63atsbyv";
|
|
263
268
|
var DEVICE_OAUTH_SCOPES = [
|
|
264
269
|
"store_v2_information",
|
|
270
|
+
"store_v2_products",
|
|
271
|
+
"store_v2_content",
|
|
272
|
+
"store_sites",
|
|
273
|
+
"store_storefront_api",
|
|
265
274
|
"store_infrastructure_deployments_manage",
|
|
266
275
|
"store_infrastructure_logs_read_only",
|
|
267
276
|
"store_infrastructure_projects_manage",
|
|
@@ -2708,7 +2717,7 @@ function collectDiagnostics({
|
|
|
2708
2717
|
env: env2 = process.env
|
|
2709
2718
|
} = {}) {
|
|
2710
2719
|
const state = getProjectState(cwd);
|
|
2711
|
-
const
|
|
2720
|
+
const telemetry2 = getTelemetry();
|
|
2712
2721
|
const projectJson = readProjectJson(cwd);
|
|
2713
2722
|
const storefront = readStorefrontInfo(cwd);
|
|
2714
2723
|
const cliEnv = [{ source: "process.env", values: env2 }];
|
|
@@ -2760,8 +2769,8 @@ function collectDiagnostics({
|
|
|
2760
2769
|
buildEnvVars: resolveEnvVars(buildEnv, BUILD_ENV_VARS)
|
|
2761
2770
|
},
|
|
2762
2771
|
telemetry: {
|
|
2763
|
-
enabled:
|
|
2764
|
-
correlationId:
|
|
2772
|
+
enabled: telemetry2.isEnabled(),
|
|
2773
|
+
correlationId: telemetry2.correlationId
|
|
2765
2774
|
},
|
|
2766
2775
|
files: {
|
|
2767
2776
|
".env.local": existsSync5(join11(cwd, ".env.local")),
|
|
@@ -3143,8 +3152,8 @@ Example:
|
|
|
3143
3152
|
const config2 = getProjectConfig();
|
|
3144
3153
|
const apiHost = resolveApiHost(options, config2);
|
|
3145
3154
|
const { storeHash, accessToken } = resolveCredentials(options, config2);
|
|
3146
|
-
const
|
|
3147
|
-
await
|
|
3155
|
+
const telemetry2 = getTelemetry();
|
|
3156
|
+
await telemetry2.identify(storeHash);
|
|
3148
3157
|
const linkedProjectUuid = options.projectUuid ?? config2.get("projectUuid");
|
|
3149
3158
|
let projectUuid;
|
|
3150
3159
|
const promptForProject = async () => {
|
|
@@ -3297,7 +3306,22 @@ var logEntrySchema = z14.object({
|
|
|
3297
3306
|
}).nullable().optional()
|
|
3298
3307
|
});
|
|
3299
3308
|
var queryLogsSchema = z14.object({
|
|
3300
|
-
data: z14.array(logEntrySchema)
|
|
3309
|
+
data: z14.array(logEntrySchema),
|
|
3310
|
+
meta: z14.object({
|
|
3311
|
+
cursor_pagination: z14.object({
|
|
3312
|
+
// The REST proxy exposes page availability via links, while the
|
|
3313
|
+
// gRPC response uses has_next_page/has_prev_page. Accept both while
|
|
3314
|
+
// the API contract is transitioning.
|
|
3315
|
+
has_next_page: z14.boolean().optional(),
|
|
3316
|
+
has_prev_page: z14.boolean().optional(),
|
|
3317
|
+
start_cursor: z14.string().nullable().optional(),
|
|
3318
|
+
end_cursor: z14.string().nullable().optional(),
|
|
3319
|
+
links: z14.object({
|
|
3320
|
+
next: z14.string().optional(),
|
|
3321
|
+
previous: z14.string().optional()
|
|
3322
|
+
}).optional()
|
|
3323
|
+
}).optional()
|
|
3324
|
+
}).optional()
|
|
3301
3325
|
});
|
|
3302
3326
|
var v3ErrorSchema = z14.object({
|
|
3303
3327
|
title: z14.string().optional(),
|
|
@@ -3412,6 +3436,8 @@ async function queryLogs(projectUuid, storeHash, accessToken, apiHost, params) {
|
|
|
3412
3436
|
if (params.urlLike) search.set("url:like", params.urlLike);
|
|
3413
3437
|
if (params.levelMin) search.set("level:min", params.levelMin);
|
|
3414
3438
|
if (params.limit != null) search.set("limit", String(params.limit));
|
|
3439
|
+
if (params.after) search.set("after", params.after);
|
|
3440
|
+
if (params.before) search.set("before", params.before);
|
|
3415
3441
|
const response = await fetch(
|
|
3416
3442
|
`https://${apiHost}/stores/${storeHash}/v3/infrastructure/logs/${projectUuid}?${search.toString()}`,
|
|
3417
3443
|
{
|
|
@@ -3430,7 +3456,9 @@ async function queryLogs(projectUuid, storeHash, accessToken, apiHost, params) {
|
|
|
3430
3456
|
);
|
|
3431
3457
|
}
|
|
3432
3458
|
if (response.status === 404) {
|
|
3433
|
-
throw new UserActionableError(
|
|
3459
|
+
throw new UserActionableError(
|
|
3460
|
+
"Project not found. Check the project UUID, and that --store-hash and --access-token belong to the store that owns the project."
|
|
3461
|
+
);
|
|
3434
3462
|
}
|
|
3435
3463
|
if (response.status === 400 || response.status === 422) {
|
|
3436
3464
|
const body = await response.json().catch(() => null);
|
|
@@ -4079,7 +4107,6 @@ var env = new Command8("env").configureHelp({ showGlobalOptions: true }).descrip
|
|
|
4079
4107
|
import { Command as Command9, InvalidArgumentError as InvalidArgumentError4, Option as Option8 } from "commander";
|
|
4080
4108
|
import { colorize as colorize10 } from "consola/utils";
|
|
4081
4109
|
import { z as z16 } from "zod";
|
|
4082
|
-
var telemetry = new Telemetry();
|
|
4083
4110
|
var DEFAULT_CONNECTION_TTL_MS = 1 * 60 * 1e3;
|
|
4084
4111
|
var MAX_RETRIES = 5;
|
|
4085
4112
|
var isFatalStatusCode = (status) => status >= 400 && status < 500;
|
|
@@ -4278,7 +4305,7 @@ Examples:
|
|
|
4278
4305
|
const config2 = getProjectConfig();
|
|
4279
4306
|
const apiHost = resolveApiHost(options, config2);
|
|
4280
4307
|
const { storeHash, accessToken } = resolveCredentials(options, config2);
|
|
4281
|
-
await
|
|
4308
|
+
await getTelemetry().identify(storeHash);
|
|
4282
4309
|
const projectUuid = resolveProjectUuid(options);
|
|
4283
4310
|
await tailLogs(projectUuid, storeHash, accessToken, apiHost, options.format);
|
|
4284
4311
|
} catch (error) {
|
|
@@ -4293,17 +4320,68 @@ var parseIntInRange = (flag, min, max) => (value) => {
|
|
|
4293
4320
|
}
|
|
4294
4321
|
return parsed;
|
|
4295
4322
|
};
|
|
4323
|
+
function invocationPrefix() {
|
|
4324
|
+
const packageManager = process.env.npm_config_user_agent?.split("/")[0];
|
|
4325
|
+
switch (packageManager) {
|
|
4326
|
+
case "pnpm":
|
|
4327
|
+
case "yarn":
|
|
4328
|
+
return `${packageManager} catalyst`;
|
|
4329
|
+
case "bun":
|
|
4330
|
+
return "bunx catalyst";
|
|
4331
|
+
case "npm":
|
|
4332
|
+
return "npx catalyst";
|
|
4333
|
+
default:
|
|
4334
|
+
return "catalyst";
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
function printPaginationHints(pagination, start2, end, options) {
|
|
4338
|
+
const hasNextPage = Boolean(pagination?.links?.next) || pagination?.has_next_page === true;
|
|
4339
|
+
const hasPrevPage = Boolean(pagination?.links?.previous) || pagination?.has_prev_page === true;
|
|
4340
|
+
const endCursor = pagination?.end_cursor;
|
|
4341
|
+
const startCursor = pagination?.start_cursor;
|
|
4342
|
+
if (!(hasNextPage && endCursor) && !(hasPrevPage && startCursor)) return;
|
|
4343
|
+
const quoteArg = (value) => /\s/.test(value) ? `'${value}'` : value;
|
|
4344
|
+
const baseFlags = [
|
|
4345
|
+
`--start ${quoteArg(start2)}`,
|
|
4346
|
+
`--end ${quoteArg(end)}`,
|
|
4347
|
+
...options.method ? [`--method ${quoteArg(options.method)}`] : [],
|
|
4348
|
+
...options.statusCode != null ? [`--status-code ${options.statusCode}`] : [],
|
|
4349
|
+
...options.urlLike ? [`--url-like ${quoteArg(options.urlLike)}`] : [],
|
|
4350
|
+
...options.levelMin ? [`--level-min ${options.levelMin}`] : [],
|
|
4351
|
+
...options.limit != null ? [`--limit ${options.limit}`] : [],
|
|
4352
|
+
...options.format !== "default" ? [`--format ${options.format}`] : []
|
|
4353
|
+
];
|
|
4354
|
+
const command = `${invocationPrefix()} logs query ${baseFlags.join(" ")}`;
|
|
4355
|
+
if (hasNextPage && endCursor) {
|
|
4356
|
+
consola.info(`More results available. Next page:
|
|
4357
|
+
${command} --after ${quoteArg(endCursor)}`);
|
|
4358
|
+
}
|
|
4359
|
+
if (hasPrevPage && startCursor) {
|
|
4360
|
+
consola.info(
|
|
4361
|
+
`Newer results available. Previous page:
|
|
4362
|
+
${command} --before ${quoteArg(startCursor)}`
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4296
4366
|
var query = new Command9("query").configureHelp({ showGlobalOptions: true }).description("Query historical logs from your deployed application.").addHelpText(
|
|
4297
4367
|
"after",
|
|
4298
4368
|
`
|
|
4299
4369
|
Specify a time window with \`--since\` (relative to now) or \`--start\`/\`--end\`
|
|
4300
4370
|
(ISO-8601 timestamps or Unix epoch seconds, UTC). The window may not exceed
|
|
4301
|
-
7 days. Entries print oldest-first; timestamps are UTC.
|
|
4371
|
+
7 days. Entries print oldest-first; timestamps are UTC. Page toward older
|
|
4372
|
+
entries by passing a previous page's end cursor to \`--after\` (the CLI prints
|
|
4373
|
+
a ready-to-run command when more entries are available), or toward newer
|
|
4374
|
+
entries with \`--before\`. Cursors are only valid with the same window and
|
|
4375
|
+
filters they came from. With \`--format json\`, the pagination cursors are
|
|
4376
|
+
emitted as a final \`{"meta": ...}\` line after the entries.
|
|
4302
4377
|
|
|
4303
4378
|
Examples:
|
|
4304
4379
|
# Last hour of logs
|
|
4305
4380
|
$ catalyst logs query --since 1h
|
|
4306
4381
|
|
|
4382
|
+
# Newest 20 errors in the window (follow the printed --after hint for more)
|
|
4383
|
+
$ catalyst logs query --since 24h --level-min error --limit 20
|
|
4384
|
+
|
|
4307
4385
|
# Everything from today (UTC)
|
|
4308
4386
|
$ catalyst logs query --start 2026-06-11T00:00:00Z
|
|
4309
4387
|
|
|
@@ -4330,7 +4408,20 @@ Examples:
|
|
|
4330
4408
|
).option("--url-like <substring>", "Filter by URL substring (case-sensitive).").addOption(
|
|
4331
4409
|
new Option8("--level-min <level>", "Minimum log level.").choices(Array.from(LOG_LEVELS))
|
|
4332
4410
|
).addOption(
|
|
4333
|
-
new Option8(
|
|
4411
|
+
new Option8(
|
|
4412
|
+
"--limit <count>",
|
|
4413
|
+
"Maximum entries per page (1-500). Defaults to the API default (100)."
|
|
4414
|
+
).argParser(parseIntInRange("--limit", 1, 500))
|
|
4415
|
+
).addOption(
|
|
4416
|
+
new Option8(
|
|
4417
|
+
"--after <cursor>",
|
|
4418
|
+
"Return the page after (older than) this cursor, from a previous page's end_cursor."
|
|
4419
|
+
).conflicts("before")
|
|
4420
|
+
).addOption(
|
|
4421
|
+
new Option8(
|
|
4422
|
+
"--before <cursor>",
|
|
4423
|
+
"Return the page before (newer than) this cursor, from a previous page's start_cursor."
|
|
4424
|
+
)
|
|
4334
4425
|
).addOption(
|
|
4335
4426
|
new Option8("--format <format>", "Output format for log entries.").choices(["json", "pretty", "default", "short", "request"]).default("default")
|
|
4336
4427
|
).action(async (options) => {
|
|
@@ -4338,7 +4429,7 @@ Examples:
|
|
|
4338
4429
|
const config2 = getProjectConfig();
|
|
4339
4430
|
const apiHost = resolveApiHost(options, config2);
|
|
4340
4431
|
const { storeHash, accessToken } = resolveCredentials(options, config2);
|
|
4341
|
-
await
|
|
4432
|
+
await getTelemetry().identify(storeHash);
|
|
4342
4433
|
const projectUuid = resolveProjectUuid(options);
|
|
4343
4434
|
const { start: start2, end } = resolveTimeWindow(options);
|
|
4344
4435
|
const result = await queryLogs(projectUuid, storeHash, accessToken, apiHost, {
|
|
@@ -4348,13 +4439,22 @@ Examples:
|
|
|
4348
4439
|
statusCode: options.statusCode,
|
|
4349
4440
|
urlLike: options.urlLike,
|
|
4350
4441
|
levelMin: options.levelMin,
|
|
4351
|
-
limit: options.limit
|
|
4442
|
+
limit: options.limit,
|
|
4443
|
+
after: options.after,
|
|
4444
|
+
before: options.before
|
|
4352
4445
|
});
|
|
4353
4446
|
const entries = result.data;
|
|
4354
4447
|
const ordered = [...entries].reverse();
|
|
4355
4448
|
if (options.format === "json") {
|
|
4356
4449
|
ordered.forEach((entry) => process.stdout.write(`${JSON.stringify(entry)}
|
|
4357
4450
|
`));
|
|
4451
|
+
const cursorPagination = result.meta?.cursor_pagination;
|
|
4452
|
+
if (cursorPagination) {
|
|
4453
|
+
process.stdout.write(
|
|
4454
|
+
`${JSON.stringify({ meta: { cursor_pagination: cursorPagination } })}
|
|
4455
|
+
`
|
|
4456
|
+
);
|
|
4457
|
+
}
|
|
4358
4458
|
return;
|
|
4359
4459
|
}
|
|
4360
4460
|
if (options.format === "pretty") {
|
|
@@ -4370,11 +4470,7 @@ Examples:
|
|
|
4370
4470
|
consola.info(
|
|
4371
4471
|
`${entries.length} ${entries.length === 1 ? "entry" : "entries"} shown (oldest first, times in UTC).`
|
|
4372
4472
|
);
|
|
4373
|
-
|
|
4374
|
-
consola.info(
|
|
4375
|
-
`Limit of ${options.limit} reached; older entries may exist. Narrow the time window or raise --limit (max 500) to see more.`
|
|
4376
|
-
);
|
|
4377
|
-
}
|
|
4473
|
+
printPaginationHints(result.meta?.cursor_pagination, start2, end, options);
|
|
4378
4474
|
} catch (error) {
|
|
4379
4475
|
consola.error(error instanceof Error ? error.message : error);
|
|
4380
4476
|
process.exit(1);
|
|
@@ -4669,7 +4765,7 @@ import { Argument, Command as Command12, Option as Option9 } from "commander";
|
|
|
4669
4765
|
import { colorize as colorize12 } from "consola/utils";
|
|
4670
4766
|
var telemetryService = getTelemetry();
|
|
4671
4767
|
var isEnabled = telemetryService.isEnabled();
|
|
4672
|
-
var
|
|
4768
|
+
var telemetry = new Command12("telemetry").configureHelp({ showGlobalOptions: true }).description(
|
|
4673
4769
|
"View or change CLI telemetry collection status. Enabling telemetry helps BigCommerce support diagnose and troubleshoot errors you encounter when using the CLI."
|
|
4674
4770
|
).addHelpText(
|
|
4675
4771
|
"after",
|
|
@@ -5398,17 +5494,17 @@ function getCommandPath(cmd) {
|
|
|
5398
5494
|
return parts.join(" ");
|
|
5399
5495
|
}
|
|
5400
5496
|
var telemetryPreHook = async (thisCommand, actionCommand) => {
|
|
5401
|
-
const
|
|
5497
|
+
const telemetry2 = getTelemetry();
|
|
5402
5498
|
const commandName = getCommandPath(actionCommand);
|
|
5403
|
-
|
|
5404
|
-
return await
|
|
5499
|
+
telemetry2.commandName = commandName;
|
|
5500
|
+
return await telemetry2.track(commandName, {
|
|
5405
5501
|
...parseArguments(thisCommand.args)
|
|
5406
5502
|
});
|
|
5407
5503
|
};
|
|
5408
5504
|
var telemetryPostHook = async () => {
|
|
5409
|
-
const
|
|
5410
|
-
await
|
|
5411
|
-
await
|
|
5505
|
+
const telemetry2 = getTelemetry();
|
|
5506
|
+
await telemetry2.track("command_completed", { durationMs: telemetry2.durationMs() });
|
|
5507
|
+
await telemetry2.analytics.closeAndFlush();
|
|
5412
5508
|
};
|
|
5413
5509
|
|
|
5414
5510
|
// src/cli/program.ts
|
|
@@ -5420,21 +5516,21 @@ consola.log(colorize13("cyanBright", `\u25E2 ${package_default.name} v${package_
|
|
|
5420
5516
|
`));
|
|
5421
5517
|
program.name(package_default.name).version(package_default.version).summary("CLI tool for Catalyst development").description(
|
|
5422
5518
|
"CLI tool for Catalyst development.\n\nConfiguration priority: flags > process.env > .bigcommerce/project.json. `build` and `deploy` additionally load env files (--env-path, or an auto-loaded .env.local/.env) for the build.\n\nCATALYST_STORE_HASH falls back to BIGCOMMERCE_STORE_HASH if unset.\n\nRun `catalyst <command> --help` for details on a specific command."
|
|
5423
|
-
).configureHelp({ showGlobalOptions: true }).addCommand(version).addCommand(create2).addCommand(start).addCommand(build).addCommand(deploy).addCommand(domains).addCommand(logs).addCommand(project).addCommand(env).addCommand(channel).addCommand(auth).addCommand(upgrade).addCommand(
|
|
5519
|
+
).configureHelp({ showGlobalOptions: true }).addCommand(version).addCommand(create2).addCommand(start).addCommand(build).addCommand(deploy).addCommand(domains).addCommand(logs).addCommand(project).addCommand(env).addCommand(channel).addCommand(auth).addCommand(upgrade).addCommand(telemetry).addCommand(debug).hook("preAction", telemetryPreHook).hook("postAction", telemetryPostHook);
|
|
5424
5520
|
|
|
5425
5521
|
// src/cli/index.ts
|
|
5426
5522
|
var handleFatalError = async (error) => {
|
|
5427
|
-
const
|
|
5523
|
+
const telemetry2 = getTelemetry();
|
|
5428
5524
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5429
5525
|
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
5430
5526
|
try {
|
|
5431
|
-
await
|
|
5432
|
-
commandName:
|
|
5527
|
+
await telemetry2.track("error", {
|
|
5528
|
+
commandName: telemetry2.commandName,
|
|
5433
5529
|
errorMessage,
|
|
5434
5530
|
errorStack,
|
|
5435
|
-
durationMs:
|
|
5531
|
+
durationMs: telemetry2.durationMs()
|
|
5436
5532
|
});
|
|
5437
|
-
await
|
|
5533
|
+
await telemetry2.analytics.closeAndFlush();
|
|
5438
5534
|
} catch {
|
|
5439
5535
|
}
|
|
5440
5536
|
if (error instanceof UserActionableError) {
|
|
@@ -5442,9 +5538,9 @@ var handleFatalError = async (error) => {
|
|
|
5442
5538
|
process.exit(1);
|
|
5443
5539
|
}
|
|
5444
5540
|
consola.error(errorMessage);
|
|
5445
|
-
if (
|
|
5541
|
+
if (telemetry2.isEnabled()) {
|
|
5446
5542
|
consola.info(
|
|
5447
|
-
`Correlation ID: ${
|
|
5543
|
+
`Correlation ID: ${telemetry2.correlationId}
|
|
5448
5544
|
Share this Correlation ID with BigCommerce support.`
|
|
5449
5545
|
);
|
|
5450
5546
|
} else {
|