@bigcommerce/catalyst 1.4.0 → 1.4.1
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 +223 -52
- 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.4.
|
|
28
|
+
version: "1.4.1",
|
|
29
29
|
type: "module",
|
|
30
30
|
repository: {
|
|
31
31
|
type: "git",
|
|
@@ -215,7 +215,7 @@ import { Command as Command15 } from "commander";
|
|
|
215
215
|
import { colorize as colorize13 } from "consola/utils";
|
|
216
216
|
|
|
217
217
|
// src/cli/commands/auth.ts
|
|
218
|
-
import { Command } from "commander";
|
|
218
|
+
import { Command, Option as Option2 } from "commander";
|
|
219
219
|
import { z as z5 } from "zod";
|
|
220
220
|
|
|
221
221
|
// src/cli/lib/auth-errors.ts
|
|
@@ -685,6 +685,19 @@ async function fetchStoreProfile2(storeHash, accessToken, apiHost) {
|
|
|
685
685
|
}
|
|
686
686
|
return result.data.data;
|
|
687
687
|
}
|
|
688
|
+
async function checkCredentials(storeHash, accessToken, apiHost) {
|
|
689
|
+
try {
|
|
690
|
+
const { store_name: storeName } = await fetchStoreProfile2(storeHash, accessToken, apiHost);
|
|
691
|
+
return { valid: true, storeName };
|
|
692
|
+
} catch (error) {
|
|
693
|
+
if (error instanceof UnauthorizedError) return { valid: false, reason: "unauthorized" };
|
|
694
|
+
return {
|
|
695
|
+
valid: false,
|
|
696
|
+
reason: "unverifiable",
|
|
697
|
+
message: error instanceof Error ? error.message : String(error)
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
}
|
|
688
701
|
var whoami = new Command("whoami").configureHelp({ showGlobalOptions: true }).description("Verify stored credentials and display store/project info.").addHelpText(
|
|
689
702
|
"after",
|
|
690
703
|
`
|
|
@@ -739,7 +752,7 @@ Example:
|
|
|
739
752
|
}
|
|
740
753
|
});
|
|
741
754
|
var login2 = new Command("login").configureHelp({ showGlobalOptions: true }).description(
|
|
742
|
-
"Authenticate via browser using the OAuth device code flow. Falls back to an interactive store hash + access token prompt if the browser flow is unavailable. If already logged in, displays
|
|
755
|
+
"Authenticate via browser using the OAuth device code flow. Falls back to an interactive store hash + access token prompt if the browser flow is unavailable. Passing --store-hash and --access-token verifies and stores those credentials instead. If already logged in with credentials that still work, displays them and suggests `catalyst auth logout`; if the stored token has expired or been revoked, re-authenticates in place."
|
|
743
756
|
).addHelpText(
|
|
744
757
|
"after",
|
|
745
758
|
`
|
|
@@ -748,19 +761,67 @@ Examples:
|
|
|
748
761
|
$ catalyst auth login
|
|
749
762
|
|
|
750
763
|
# Login with existing credentials (skips interactive flow)
|
|
751
|
-
$ catalyst auth login --store-hash <STORE_HASH> --access-token <ACCESS_TOKEN
|
|
752
|
-
|
|
764
|
+
$ catalyst auth login --store-hash <STORE_HASH> --access-token <ACCESS_TOKEN>
|
|
765
|
+
|
|
766
|
+
# Re-authenticate without checking the stored credentials first
|
|
767
|
+
$ catalyst auth login --force`
|
|
768
|
+
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(loginUrlOption()).addOption(
|
|
769
|
+
new Option2(
|
|
770
|
+
"--force",
|
|
771
|
+
"Skip the check on any credentials already stored and re-authenticate regardless."
|
|
772
|
+
)
|
|
773
|
+
).action(async (options, command) => {
|
|
753
774
|
try {
|
|
754
775
|
const config2 = getProjectConfig();
|
|
755
776
|
const apiHost = resolveApiHost(options, config2);
|
|
756
777
|
const storeHash = options.storeHash ?? config2.get("storeHash");
|
|
757
778
|
const accessToken = options.accessToken ?? config2.get("accessToken");
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
779
|
+
const suppliedOnCli = command.getOptionValueSource("storeHash") === "cli" && command.getOptionValueSource("accessToken") === "cli";
|
|
780
|
+
if (suppliedOnCli && storeHash && accessToken) {
|
|
781
|
+
if (!options.force) {
|
|
782
|
+
const status = await checkCredentials(storeHash, accessToken, apiHost);
|
|
783
|
+
if (!status.valid && status.reason === "unauthorized") {
|
|
784
|
+
consola.error(`The credentials provided for store ${storeHash} were rejected.`);
|
|
785
|
+
consola.info(
|
|
786
|
+
"Check the store hash and access token, or run `catalyst auth login` without them to authenticate in the browser."
|
|
787
|
+
);
|
|
788
|
+
process.exit(1);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
if (!status.valid) {
|
|
792
|
+
consola.warn(`Couldn't verify the credentials provided: ${status.message}`);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
config2.set("storeHash", storeHash);
|
|
796
|
+
config2.set("accessToken", accessToken);
|
|
797
|
+
consola.success(`Logged in to store ${storeHash}.`);
|
|
761
798
|
process.exit(0);
|
|
762
799
|
return;
|
|
763
800
|
}
|
|
801
|
+
if (storeHash && accessToken && !options.force) {
|
|
802
|
+
const status = await checkCredentials(storeHash, accessToken, apiHost);
|
|
803
|
+
if (status.valid) {
|
|
804
|
+
consola.info(`Already logged in to ${status.storeName} (${storeHash}).`);
|
|
805
|
+
consola.info(
|
|
806
|
+
"Run `catalyst auth logout` first to re-authenticate, or `catalyst auth login --force` to skip this check."
|
|
807
|
+
);
|
|
808
|
+
process.exit(0);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (status.reason === "unverifiable") {
|
|
812
|
+
consola.warn(
|
|
813
|
+
`Found credentials for store ${storeHash} but couldn't verify them: ${status.message}`
|
|
814
|
+
);
|
|
815
|
+
consola.info(
|
|
816
|
+
"Keeping them. Re-run once the API is reachable, or `catalyst auth login --force` to re-authenticate regardless."
|
|
817
|
+
);
|
|
818
|
+
process.exit(0);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
consola.warn(
|
|
822
|
+
`Stored credentials for store ${storeHash} are no longer valid \u2014 re-authenticating.`
|
|
823
|
+
);
|
|
824
|
+
}
|
|
764
825
|
const credentials = await login(options.loginUrl, apiHost);
|
|
765
826
|
config2.set("storeHash", credentials.storeHash);
|
|
766
827
|
config2.set("accessToken", credentials.accessToken);
|
|
@@ -807,7 +868,7 @@ Example:
|
|
|
807
868
|
var auth = new Command("auth").configureHelp({ showGlobalOptions: true }).description("Manage authentication for the BigCommerce CLI.").addCommand(whoami).addCommand(login2).addCommand(logout);
|
|
808
869
|
|
|
809
870
|
// src/cli/commands/build.ts
|
|
810
|
-
import { Command as Command2, InvalidArgumentError, Option as
|
|
871
|
+
import { Command as Command2, InvalidArgumentError, Option as Option3 } from "commander";
|
|
811
872
|
import { execa as execa2 } from "execa";
|
|
812
873
|
import { copyFile, cp, rm, writeFile } from "fs/promises";
|
|
813
874
|
import { join as join6 } from "path";
|
|
@@ -918,7 +979,7 @@ var cleanupCloudflareIncompatibilities = async (projectDir) => {
|
|
|
918
979
|
return;
|
|
919
980
|
}
|
|
920
981
|
const shouldRemove = await confirm2({
|
|
921
|
-
message: 'Catalyst found instrumentation.ts, which is incompatible with the Cloudflare Workers bundle when it uses @vercel/otel (causes "Failed to prepare server" at cold start)
|
|
982
|
+
message: 'Catalyst found instrumentation.ts, which is incompatible with the Cloudflare Workers bundle when it uses @vercel/otel (causes "Failed to prepare server" at cold start).\nRemove it and drop @vercel/otel from package.json? (required for native hosting)',
|
|
922
983
|
default: true
|
|
923
984
|
});
|
|
924
985
|
if (!shouldRemove) {
|
|
@@ -1523,12 +1584,12 @@ Examples:
|
|
|
1523
1584
|
# Build with a specific Wrangler version
|
|
1524
1585
|
$ catalyst build --wrangler-version 4.24.3`
|
|
1525
1586
|
).addOption(
|
|
1526
|
-
new
|
|
1587
|
+
new Option3(
|
|
1527
1588
|
"--project-uuid <uuid>",
|
|
1528
1589
|
"Project UUID to be included in the deployment configuration."
|
|
1529
1590
|
).env("CATALYST_PROJECT_UUID")
|
|
1530
1591
|
).addOption(
|
|
1531
|
-
new
|
|
1592
|
+
new Option3(
|
|
1532
1593
|
"--wrangler-version <version>",
|
|
1533
1594
|
`Wrangler version or dist-tag to build with. Defaults to ${WRANGLER_VERSION}.`
|
|
1534
1595
|
).argParser(parseWranglerVersion)
|
|
@@ -1557,7 +1618,7 @@ Examples:
|
|
|
1557
1618
|
|
|
1558
1619
|
// src/cli/commands/channels.ts
|
|
1559
1620
|
import { confirm as confirm3, select as select4 } from "@inquirer/prompts";
|
|
1560
|
-
import { Command as Command3, InvalidArgumentError as InvalidArgumentError2, Option as
|
|
1621
|
+
import { Command as Command3, InvalidArgumentError as InvalidArgumentError2, Option as Option4 } from "commander";
|
|
1561
1622
|
import { colorize as colorize5 } from "consola/utils";
|
|
1562
1623
|
|
|
1563
1624
|
// src/cli/lib/channel-checkout-url-flow.ts
|
|
@@ -1900,7 +1961,7 @@ async function resolveChannel(options) {
|
|
|
1900
1961
|
);
|
|
1901
1962
|
}
|
|
1902
1963
|
const id = await select2({
|
|
1903
|
-
message: "Select the channel to update.",
|
|
1964
|
+
message: options.message ?? "Select the channel to update.",
|
|
1904
1965
|
choices: catalystChannels.map((c) => ({
|
|
1905
1966
|
name: c.name,
|
|
1906
1967
|
value: c.id,
|
|
@@ -2317,22 +2378,22 @@ Examples:
|
|
|
2317
2378
|
# Fall back to the shared checkout domain
|
|
2318
2379
|
$ catalyst channels update --channel-id 123 --remove-checkout-url`
|
|
2319
2380
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(projectUuidOption()).addOption(
|
|
2320
|
-
new
|
|
2381
|
+
new Option4(
|
|
2321
2382
|
"--channel-id <id>",
|
|
2322
2383
|
"Skip the channel prompt and target this channel directly."
|
|
2323
2384
|
).argParser((value) => Number(value))
|
|
2324
2385
|
).addOption(
|
|
2325
|
-
new
|
|
2386
|
+
new Option4(
|
|
2326
2387
|
"--hostname <hostname>",
|
|
2327
2388
|
"Skip the hostname prompt and use this hostname directly. Must be one of the project's deployment_hostnames."
|
|
2328
2389
|
)
|
|
2329
2390
|
).addOption(
|
|
2330
|
-
new
|
|
2391
|
+
new Option4(
|
|
2331
2392
|
"--checkout-url <url>",
|
|
2332
2393
|
"Set the channel's checkout URL. Must share a main domain with the storefront URL."
|
|
2333
2394
|
).argParser(parseCheckoutUrl)
|
|
2334
2395
|
).addOption(
|
|
2335
|
-
new
|
|
2396
|
+
new Option4(
|
|
2336
2397
|
"--remove-checkout-url",
|
|
2337
2398
|
"Remove the channel's custom checkout URL so checkout falls back to the shared checkout domain."
|
|
2338
2399
|
).conflicts("checkoutUrl")
|
|
@@ -2406,14 +2467,14 @@ Examples:
|
|
|
2406
2467
|
# Append extra environment variables to .env.local
|
|
2407
2468
|
$ catalyst channels link --channel-id 123 --env MY_FLAG=1`
|
|
2408
2469
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(loginUrlOption()).addOption(
|
|
2409
|
-
new
|
|
2470
|
+
new Option4("--channel-id <id>", "Link this channel directly, skipping the picker.").argParser(
|
|
2410
2471
|
parseChannelId
|
|
2411
2472
|
)
|
|
2412
2473
|
).option(
|
|
2413
2474
|
"--env <vars...>",
|
|
2414
2475
|
"Arbitrary environment variables to set in .env.local. Format: KEY=VALUE (repeatable)."
|
|
2415
2476
|
).addOption(
|
|
2416
|
-
new
|
|
2477
|
+
new Option4("--cli-api-origin <origin>", "Catalyst CLI API origin").default("https://cxm-prd.bigcommerceapp.com").hideHelp()
|
|
2417
2478
|
).action(async (options) => {
|
|
2418
2479
|
const config2 = getProjectConfig();
|
|
2419
2480
|
const apiHost = resolveApiHost(options, config2);
|
|
@@ -2484,11 +2545,11 @@ Examples:
|
|
|
2484
2545
|
).option(
|
|
2485
2546
|
"--additional-locales <locales...>",
|
|
2486
2547
|
"Additional storefront locales, max 4 (e.g. --additional-locales es fr). Skips the additional-languages prompt."
|
|
2487
|
-
).addOption(new
|
|
2548
|
+
).addOption(new Option4("--sample-data", "Install sample data on the new channel.")).addOption(new Option4("--no-sample-data", "Create the channel without sample data.")).option(
|
|
2488
2549
|
"--link",
|
|
2489
2550
|
"Link the new channel to this project \u2014 write its credentials to .env.local without prompting."
|
|
2490
2551
|
).addOption(
|
|
2491
|
-
new
|
|
2552
|
+
new Option4("--cli-api-origin <origin>", "Catalyst CLI API origin").default("https://cxm-prd.bigcommerceapp.com").hideHelp()
|
|
2492
2553
|
).action(async (options) => {
|
|
2493
2554
|
if (options.additionalLocales && options.additionalLocales.length > 4) {
|
|
2494
2555
|
consola.error("You can only set up to 4 additional locales.");
|
|
@@ -2570,7 +2631,10 @@ async function resolveChannelTarget(options) {
|
|
|
2570
2631
|
storeHash,
|
|
2571
2632
|
accessToken,
|
|
2572
2633
|
apiHost,
|
|
2573
|
-
channelId: options.channelId
|
|
2634
|
+
channelId: options.channelId,
|
|
2635
|
+
// Read-only: these commands report on a channel, so the picker must not
|
|
2636
|
+
// say "to update" — the shared default is written for `channels update`.
|
|
2637
|
+
message: "Select a channel."
|
|
2574
2638
|
});
|
|
2575
2639
|
return {
|
|
2576
2640
|
config: config2,
|
|
@@ -2592,7 +2656,7 @@ Examples:
|
|
|
2592
2656
|
# Target a channel directly
|
|
2593
2657
|
$ catalyst channels info --channel-id 123`
|
|
2594
2658
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(
|
|
2595
|
-
new
|
|
2659
|
+
new Option4(
|
|
2596
2660
|
"--channel-id <id>",
|
|
2597
2661
|
"Skip the channel prompt and target this channel directly."
|
|
2598
2662
|
).argParser(parseChannelId)
|
|
@@ -2638,7 +2702,7 @@ Examples:
|
|
|
2638
2702
|
var channels = new Command3("channels").alias("channel").configureHelp({ showGlobalOptions: true }).description("Manage BigCommerce channels.").addCommand(info, { isDefault: true }).addCommand(create).addCommand(link).addCommand(update);
|
|
2639
2703
|
|
|
2640
2704
|
// src/cli/commands/create.ts
|
|
2641
|
-
import { Command as Command4, InvalidArgumentError as InvalidArgumentError3, Option as
|
|
2705
|
+
import { Command as Command4, InvalidArgumentError as InvalidArgumentError3, Option as Option5 } from "@commander-js/extra-typings";
|
|
2642
2706
|
import { input as input5, select as select5 } from "@inquirer/prompts";
|
|
2643
2707
|
import { execSync as execSync2 } from "child_process";
|
|
2644
2708
|
import { colorize as colorize6 } from "consola/utils";
|
|
@@ -2915,7 +2979,7 @@ Examples:
|
|
|
2915
2979
|
"Arbitrary environment variables to set in .env.local. Format: KEY=VALUE (repeatable).",
|
|
2916
2980
|
parseEnvFlag
|
|
2917
2981
|
).addOption(
|
|
2918
|
-
new
|
|
2982
|
+
new Option5(
|
|
2919
2983
|
"--hosting <mode>",
|
|
2920
2984
|
'Hosting mode: "self-hosted" (default) or "commerce" to set up Commerce Hosting at create time. When omitted, scaffolding is hosting-agnostic; run `catalyst deploy` later to opt in.'
|
|
2921
2985
|
).choices(["self-hosted", "commerce"])
|
|
@@ -2923,11 +2987,11 @@ Examples:
|
|
|
2923
2987
|
"--use-existing",
|
|
2924
2988
|
"Only used with --hosting commerce and --project-name. When the named project already exists on the store, reuse it instead of prompting. Has no effect without --hosting commerce."
|
|
2925
2989
|
).addOption(
|
|
2926
|
-
new
|
|
2990
|
+
new Option5("--bigcommerce-hostname <hostname>", "BigCommerce hostname").default("bigcommerce.com").hideHelp()
|
|
2927
2991
|
).addOption(
|
|
2928
|
-
new
|
|
2992
|
+
new Option5("--login-url <url>", "BigCommerce login URL.").env("BIGCOMMERCE_LOGIN_URL").default(DEFAULT_LOGIN_URL).hideHelp()
|
|
2929
2993
|
).addOption(
|
|
2930
|
-
new
|
|
2994
|
+
new Option5("--cli-api-origin <origin>", "Catalyst CLI API origin").default("https://cxm-prd.bigcommerceapp.com").hideHelp()
|
|
2931
2995
|
).action(async (options) => {
|
|
2932
2996
|
const { ghRef, repository } = options;
|
|
2933
2997
|
if (options.useExisting && options.hosting !== "commerce") {
|
|
@@ -3083,7 +3147,7 @@ ${steps.map((step) => ` ${colorize6("yellow", step)}`).join("\n")}`
|
|
|
3083
3147
|
});
|
|
3084
3148
|
|
|
3085
3149
|
// src/cli/commands/debug.ts
|
|
3086
|
-
import { Command as Command5, Option as
|
|
3150
|
+
import { Command as Command5, Option as Option6 } from "commander";
|
|
3087
3151
|
|
|
3088
3152
|
// src/cli/lib/collect-diagnostics.ts
|
|
3089
3153
|
import { parse } from "dotenv";
|
|
@@ -3334,7 +3398,7 @@ Examples:
|
|
|
3334
3398
|
|
|
3335
3399
|
# Print machine-readable JSON (useful for copy/paste or piping)
|
|
3336
3400
|
$ catalyst debug --json`
|
|
3337
|
-
).addOption(new
|
|
3401
|
+
).addOption(new Option6("--json", "Output the report as JSON.")).action((options) => {
|
|
3338
3402
|
const diagnostics = collectDiagnostics();
|
|
3339
3403
|
if (options.json) {
|
|
3340
3404
|
consola.log(JSON.stringify(diagnostics, null, 2));
|
|
@@ -3346,7 +3410,7 @@ Examples:
|
|
|
3346
3410
|
// src/cli/commands/deploy.ts
|
|
3347
3411
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
3348
3412
|
import AdmZip from "adm-zip";
|
|
3349
|
-
import { Command as Command6, Option as
|
|
3413
|
+
import { Command as Command6, Option as Option7 } from "commander";
|
|
3350
3414
|
import { colorize as colorize7 } from "consola/utils";
|
|
3351
3415
|
import { access as access2, readdir, readFile } from "fs/promises";
|
|
3352
3416
|
import { join as join13 } from "path";
|
|
@@ -3616,7 +3680,7 @@ Example:
|
|
|
3616
3680
|
"--update-checkout-url",
|
|
3617
3681
|
"After a successful deploy, prompt to update a channel's checkout URL."
|
|
3618
3682
|
).addOption(
|
|
3619
|
-
new
|
|
3683
|
+
new Option7(
|
|
3620
3684
|
"--secret <value>",
|
|
3621
3685
|
"Secret to set for this deployment (repeatable). Overrides a stored value for the same key. Format: --secret KEY=VALUE"
|
|
3622
3686
|
).argParser((value, previous = []) => {
|
|
@@ -3626,7 +3690,7 @@ Example:
|
|
|
3626
3690
|
"--prebuilt",
|
|
3627
3691
|
"Skip the build step. Requires .bigcommerce/dist/ to already contain build output."
|
|
3628
3692
|
).addOption(
|
|
3629
|
-
new
|
|
3693
|
+
new Option7(
|
|
3630
3694
|
"--wrangler-version <version>",
|
|
3631
3695
|
`Wrangler version or dist-tag to build with. Ignored with --prebuilt. Defaults to ${WRANGLER_VERSION}.`
|
|
3632
3696
|
).argParser(parseWranglerVersion)
|
|
@@ -3785,7 +3849,7 @@ Example:
|
|
|
3785
3849
|
|
|
3786
3850
|
// src/cli/commands/domains.ts
|
|
3787
3851
|
import { confirm as confirm5, select as select6 } from "@inquirer/prompts";
|
|
3788
|
-
import { Command as Command7, Option as
|
|
3852
|
+
import { Command as Command7, Option as Option8 } from "commander";
|
|
3789
3853
|
import { colorize as colorize9 } from "consola/utils";
|
|
3790
3854
|
|
|
3791
3855
|
// src/cli/lib/domains.ts
|
|
@@ -4357,7 +4421,7 @@ Examples:
|
|
|
4357
4421
|
# Show pending domains only
|
|
4358
4422
|
$ catalyst domains list --status pending`
|
|
4359
4423
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(projectUuidOption()).option("--domain <domain>", "Only show a specific domain.").addOption(
|
|
4360
|
-
new
|
|
4424
|
+
new Option8("--status <status>", "Filter by verification status.").choices(
|
|
4361
4425
|
DOMAIN_STATUS_FILTERS
|
|
4362
4426
|
)
|
|
4363
4427
|
).action(async (options) => {
|
|
@@ -4662,7 +4726,7 @@ var env = new Command8("env").configureHelp({ showGlobalOptions: true }).descrip
|
|
|
4662
4726
|
).addCommand(add2).addCommand(remove2).addCommand(list2);
|
|
4663
4727
|
|
|
4664
4728
|
// src/cli/commands/logs.ts
|
|
4665
|
-
import { Command as Command9, InvalidArgumentError as InvalidArgumentError4, Option as
|
|
4729
|
+
import { Command as Command9, InvalidArgumentError as InvalidArgumentError4, Option as Option9 } from "commander";
|
|
4666
4730
|
import { colorize as colorize10 } from "consola/utils";
|
|
4667
4731
|
import { z as z16 } from "zod";
|
|
4668
4732
|
var DEFAULT_CONNECTION_TTL_MS = 1 * 60 * 1e3;
|
|
@@ -4879,7 +4943,7 @@ Examples:
|
|
|
4879
4943
|
# Tail logs as raw JSON (useful for piping to other tools)
|
|
4880
4944
|
$ catalyst logs tail --format json`
|
|
4881
4945
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(projectUuidOption()).addOption(
|
|
4882
|
-
new
|
|
4946
|
+
new Option9("--format <format>", "Output format for log events.").choices(["json", "pretty", "default", "short", "request"]).default("default")
|
|
4883
4947
|
).action(async (options) => {
|
|
4884
4948
|
try {
|
|
4885
4949
|
const config2 = getProjectConfig();
|
|
@@ -4980,7 +5044,7 @@ Examples:
|
|
|
4980
5044
|
# Raw JSON (NDJSON) for piping to other tools
|
|
4981
5045
|
$ catalyst logs query --since 2d --format json`
|
|
4982
5046
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(projectUuidOption()).addOption(
|
|
4983
|
-
new
|
|
5047
|
+
new Option9(
|
|
4984
5048
|
"--since <duration>",
|
|
4985
5049
|
"Relative window ending at --end (default: now), e.g. 30m, 6h, 2d (units: s, m, h, d)."
|
|
4986
5050
|
).conflicts("start")
|
|
@@ -4988,28 +5052,28 @@ Examples:
|
|
|
4988
5052
|
"--end <time>",
|
|
4989
5053
|
"Window end: ISO-8601 timestamp or Unix epoch (seconds). Defaults to now. The window must not exceed 7 days."
|
|
4990
5054
|
).option("--method <method>", "Filter by request HTTP method (case-insensitive).").addOption(
|
|
4991
|
-
new
|
|
5055
|
+
new Option9("--status-code <code>", "Filter by response status code (100-599).").argParser(
|
|
4992
5056
|
parseIntInRange("--status-code", 100, 599)
|
|
4993
5057
|
)
|
|
4994
5058
|
).option("--url-like <substring>", "Filter by URL substring (case-sensitive).").addOption(
|
|
4995
|
-
new
|
|
5059
|
+
new Option9("--level-min <level>", "Minimum log level.").choices(Array.from(LOG_LEVELS))
|
|
4996
5060
|
).addOption(
|
|
4997
|
-
new
|
|
5061
|
+
new Option9(
|
|
4998
5062
|
"--limit <count>",
|
|
4999
5063
|
"Maximum entries per page (1-500). Defaults to the API default (100)."
|
|
5000
5064
|
).argParser(parseIntInRange("--limit", 1, 500))
|
|
5001
5065
|
).addOption(
|
|
5002
|
-
new
|
|
5066
|
+
new Option9(
|
|
5003
5067
|
"--after <cursor>",
|
|
5004
5068
|
"Return the page after (older than) this cursor, from a previous page's end_cursor."
|
|
5005
5069
|
).conflicts("before")
|
|
5006
5070
|
).addOption(
|
|
5007
|
-
new
|
|
5071
|
+
new Option9(
|
|
5008
5072
|
"--before <cursor>",
|
|
5009
5073
|
"Return the page before (newer than) this cursor, from a previous page's start_cursor."
|
|
5010
5074
|
)
|
|
5011
5075
|
).addOption(
|
|
5012
|
-
new
|
|
5076
|
+
new Option9("--format <format>", "Output format for log entries.").choices(["json", "pretty", "default", "short", "request"]).default("default")
|
|
5013
5077
|
).action(async (options) => {
|
|
5014
5078
|
try {
|
|
5015
5079
|
const config2 = getProjectConfig();
|
|
@@ -5352,7 +5416,7 @@ Example:
|
|
|
5352
5416
|
});
|
|
5353
5417
|
|
|
5354
5418
|
// src/cli/commands/telemetry.ts
|
|
5355
|
-
import { Argument, Command as Command12, Option as
|
|
5419
|
+
import { Argument, Command as Command12, Option as Option10 } from "commander";
|
|
5356
5420
|
import { colorize as colorize12 } from "consola/utils";
|
|
5357
5421
|
var telemetryService = getTelemetry();
|
|
5358
5422
|
var isEnabled = telemetryService.isEnabled();
|
|
@@ -5370,7 +5434,7 @@ Examples:
|
|
|
5370
5434
|
|
|
5371
5435
|
# Disable telemetry collection
|
|
5372
5436
|
$ catalyst telemetry --disable`
|
|
5373
|
-
).addArgument(new Argument("[arg]").choices(["disable", "enable", "status"])).addOption(new
|
|
5437
|
+
).addArgument(new Argument("[arg]").choices(["disable", "enable", "status"])).addOption(new Option10("--enable", `Enables CLI telemetry collection.`).conflicts("disable")).option("--disable", `Disables CLI telemetry collection.`).action((arg, options) => {
|
|
5374
5438
|
if (options.enable || arg === "enable") {
|
|
5375
5439
|
telemetryService.setEnabled(true);
|
|
5376
5440
|
isEnabled = true;
|
|
@@ -5397,7 +5461,7 @@ Examples:
|
|
|
5397
5461
|
});
|
|
5398
5462
|
|
|
5399
5463
|
// src/cli/commands/upgrade.ts
|
|
5400
|
-
import { Command as Command13, Option as
|
|
5464
|
+
import { Command as Command13, Option as Option11 } from "@commander-js/extra-typings";
|
|
5401
5465
|
import { confirm as confirm7 } from "@inquirer/prompts";
|
|
5402
5466
|
import { execa as execa4 } from "execa";
|
|
5403
5467
|
import {
|
|
@@ -5559,6 +5623,72 @@ async function findStaleCli(pkgRaw) {
|
|
|
5559
5623
|
const current = minVersion2(range)?.version;
|
|
5560
5624
|
return current !== void 0 && semverLt2(current, latest) ? { current, latest } : null;
|
|
5561
5625
|
}
|
|
5626
|
+
var CLI_MANAGED_SCRIPTS = ["build", "start", "deploy"];
|
|
5627
|
+
var ScriptsPackageJson = z17.looseObject({
|
|
5628
|
+
scripts: z17.record(z17.string(), z17.string()).optional()
|
|
5629
|
+
});
|
|
5630
|
+
var readScripts = (raw) => {
|
|
5631
|
+
try {
|
|
5632
|
+
return ScriptsPackageJson.parse(JSON.parse(raw)).scripts ?? {};
|
|
5633
|
+
} catch {
|
|
5634
|
+
return {};
|
|
5635
|
+
}
|
|
5636
|
+
};
|
|
5637
|
+
var SCRIPTS_BLOCK = /"scripts"\s*:\s*\{(?:[^{}"]|"(?:[^"\\]|\\.)*")*\}/;
|
|
5638
|
+
var rewriteScriptCommand = (raw, name, command) => {
|
|
5639
|
+
const block = SCRIPTS_BLOCK.exec(raw);
|
|
5640
|
+
if (!block) return raw;
|
|
5641
|
+
const splice = (replacement) => raw.slice(0, block.index) + replacement + raw.slice(block.index + block[0].length);
|
|
5642
|
+
const updated = block[0].replace(
|
|
5643
|
+
new RegExp(`("${escapeRegExp(name)}"\\s*:\\s*)"(?:[^"\\\\]|\\\\.)*"`),
|
|
5644
|
+
(_match, key) => `${key}${JSON.stringify(command)}`
|
|
5645
|
+
);
|
|
5646
|
+
if (updated !== block[0]) return splice(updated);
|
|
5647
|
+
const closeIdx = block[0].length - 1;
|
|
5648
|
+
const head = block[0].slice(0, closeIdx).replace(/\s+$/, "");
|
|
5649
|
+
const closeIndent = /\n([ \t]*)$/.exec(block[0].slice(0, closeIdx))?.[1] ?? "";
|
|
5650
|
+
const entryIndent = /\n([ \t]*)"/.exec(block[0])?.[1] ?? `${closeIndent} `;
|
|
5651
|
+
const separator = head.endsWith("{") ? "" : ",";
|
|
5652
|
+
return splice(
|
|
5653
|
+
`${head}${separator}
|
|
5654
|
+
${entryIndent}${JSON.stringify(name)}: ${JSON.stringify(command)}
|
|
5655
|
+
${closeIndent}}`
|
|
5656
|
+
);
|
|
5657
|
+
};
|
|
5658
|
+
async function normalizeManagedScripts(ourPkgRaw, baseDir, theirsDir) {
|
|
5659
|
+
const basePath = join15(baseDir, "package.json");
|
|
5660
|
+
const theirsPath = join15(theirsDir, "package.json");
|
|
5661
|
+
const [originalBase, originalTheirs] = await Promise.all([
|
|
5662
|
+
readFile2(basePath, "utf-8").catch(() => null),
|
|
5663
|
+
readFile2(theirsPath, "utf-8").catch(() => null)
|
|
5664
|
+
]);
|
|
5665
|
+
if (originalBase === null || originalTheirs === null) return { pinned: [], upstreamChanged: [] };
|
|
5666
|
+
const ourScripts = readScripts(ourPkgRaw);
|
|
5667
|
+
const baseScripts = readScripts(originalBase);
|
|
5668
|
+
const theirsScripts = readScripts(originalTheirs);
|
|
5669
|
+
const decisions = CLI_MANAGED_SCRIPTS.flatMap((name) => {
|
|
5670
|
+
const ours = ourScripts[name];
|
|
5671
|
+
return ours !== void 0 && ours !== baseScripts[name] ? [{ name, ours }] : [];
|
|
5672
|
+
});
|
|
5673
|
+
const upstreamChanged = decisions.flatMap(({ name }) => {
|
|
5674
|
+
const base = baseScripts[name] ?? null;
|
|
5675
|
+
const theirs = theirsScripts[name] ?? null;
|
|
5676
|
+
return base !== theirs ? [{ name, base, theirs }] : [];
|
|
5677
|
+
});
|
|
5678
|
+
const baseRaw = decisions.reduce(
|
|
5679
|
+
(acc, { name, ours }) => rewriteScriptCommand(acc, name, ours),
|
|
5680
|
+
originalBase
|
|
5681
|
+
);
|
|
5682
|
+
const theirsRaw = decisions.reduce(
|
|
5683
|
+
(acc, { name, ours }) => rewriteScriptCommand(acc, name, ours),
|
|
5684
|
+
originalTheirs
|
|
5685
|
+
);
|
|
5686
|
+
await Promise.all([
|
|
5687
|
+
baseRaw === originalBase ? null : writeFile2(basePath, baseRaw),
|
|
5688
|
+
theirsRaw === originalTheirs ? null : writeFile2(theirsPath, theirsRaw)
|
|
5689
|
+
]);
|
|
5690
|
+
return { pinned: decisions.map(({ name }) => name), upstreamChanged };
|
|
5691
|
+
}
|
|
5562
5692
|
async function mergeFile(oursPath, basePath, theirsPath) {
|
|
5563
5693
|
const merged = await execa4(
|
|
5564
5694
|
"git",
|
|
@@ -5930,6 +6060,20 @@ ${rows}
|
|
|
5930
6060
|
They resolve to your local packages/ copies, which \`catalyst upgrade\` does not update \u2014 so they never receive upgrades.`
|
|
5931
6061
|
);
|
|
5932
6062
|
}
|
|
6063
|
+
function printManagedScriptFindings(findings) {
|
|
6064
|
+
if (findings.length === 0) return;
|
|
6065
|
+
const pad = Math.max(...findings.map((finding) => finding.name.length));
|
|
6066
|
+
const show = (command) => command ?? "(absent)";
|
|
6067
|
+
const rows = findings.map(
|
|
6068
|
+
(finding) => ` ${finding.name.padEnd(pad)} ${show(finding.base)} \u2192 ${show(finding.theirs)}`
|
|
6069
|
+
).join("\n");
|
|
6070
|
+
consola.warn(
|
|
6071
|
+
`Core's own version of ${findings.length} npm script${findings.length === 1 ? "" : "s"} the CLI manages for you changed:
|
|
6072
|
+
${rows}
|
|
6073
|
+
|
|
6074
|
+
Your project keeps its \`catalyst\`-backed command, which is almost always what you want \u2014 \`catalyst build\`/\`start\`/\`deploy\` wrap the equivalent \`next\` command. Apply the change by hand only if you have opted out of the CLI scripts.`
|
|
6075
|
+
);
|
|
6076
|
+
}
|
|
5933
6077
|
function printSummary({
|
|
5934
6078
|
result,
|
|
5935
6079
|
relDir,
|
|
@@ -5973,23 +6117,42 @@ Resolve them, then: git add ${relDir} && git commit${install}`
|
|
|
5973
6117
|
);
|
|
5974
6118
|
}
|
|
5975
6119
|
}
|
|
6120
|
+
async function reconcileNativeHosting(catalystRoot, result) {
|
|
6121
|
+
const state = getProjectState(catalystRoot);
|
|
6122
|
+
if (!state.isLinked && !state.isTransformed) return;
|
|
6123
|
+
const instrumentationRel = "instrumentation.ts";
|
|
6124
|
+
const instrumentationPath = join15(catalystRoot, instrumentationRel);
|
|
6125
|
+
const hadInstrumentation = await pathExists(instrumentationPath);
|
|
6126
|
+
try {
|
|
6127
|
+
await cleanupCloudflareIncompatibilities(catalystRoot);
|
|
6128
|
+
} catch (err) {
|
|
6129
|
+
consola.warn(
|
|
6130
|
+
`Couldn't fully reconcile native-hosting files (${err instanceof Error ? err.message : String(err)}). Remove @vercel/otel from package.json by hand if the merge brought it back.`
|
|
6131
|
+
);
|
|
6132
|
+
}
|
|
6133
|
+
if (hadInstrumentation && !await pathExists(instrumentationPath)) {
|
|
6134
|
+
result.conflicted = result.conflicted.filter((rel) => rel !== instrumentationRel);
|
|
6135
|
+
result.applied = result.applied.filter((rel) => rel !== instrumentationRel);
|
|
6136
|
+
result.added = result.added.filter((rel) => rel !== instrumentationRel);
|
|
6137
|
+
}
|
|
6138
|
+
}
|
|
5976
6139
|
var upgrade = new Command13("upgrade").configureHelp({ showGlobalOptions: true }).aliases([
|
|
5977
6140
|
"up",
|
|
5978
6141
|
// These are hidden aliases
|
|
5979
6142
|
"upgrayedd",
|
|
5980
6143
|
"ugrad"
|
|
5981
6144
|
]).description("Upgrade your Catalyst project to a newer version by applying a 3-way merge.").argument("[version]", "Target version to upgrade to (default: latest)").addOption(
|
|
5982
|
-
new
|
|
6145
|
+
new Option11(
|
|
5983
6146
|
"--ref <ref>",
|
|
5984
6147
|
"Full git tag to upgrade to, e.g. an integration family like @bigcommerce/catalyst-makeswift@1.7.0. Overrides [version]."
|
|
5985
6148
|
)
|
|
5986
|
-
).addOption(new
|
|
5987
|
-
new
|
|
6149
|
+
).addOption(new Option11("--from <ref>", "Base ref to upgrade from (when catalyst.ref is missing)")).option("--dry-run", "Generate and display the diff without applying it").option("--yes", "Skip confirmation prompts (e.g. inferred base ref)").addOption(
|
|
6150
|
+
new Option11(
|
|
5988
6151
|
"--strategy <strategy>",
|
|
5989
6152
|
"Merge engine: tree (git merge-tree, full fidelity), per-file (git merge-file, no-history fallback), or auto (tree when git >= 2.38, else per-file)"
|
|
5990
6153
|
).choices(["auto", "tree", "per-file"]).default("auto").hideHelp()
|
|
5991
6154
|
).addOption(
|
|
5992
|
-
new
|
|
6155
|
+
new Option11("--repository <owner/repo>", "GitHub repository to pull versions from").default(
|
|
5993
6156
|
DEFAULT_REPOSITORY
|
|
5994
6157
|
)
|
|
5995
6158
|
).addHelpText(
|
|
@@ -6104,6 +6267,11 @@ to raise the GitHub API rate limit.`
|
|
|
6104
6267
|
baseVersions,
|
|
6105
6268
|
targetVersions
|
|
6106
6269
|
);
|
|
6270
|
+
const { upstreamChanged: managedScripts } = await normalizeManagedScripts(
|
|
6271
|
+
project.rawContent,
|
|
6272
|
+
baseDir,
|
|
6273
|
+
theirsDir
|
|
6274
|
+
);
|
|
6107
6275
|
if (options.dryRun) {
|
|
6108
6276
|
const diffSpinner = yoctoSpinner4().start("Generating diff...");
|
|
6109
6277
|
const diff = await execa4(
|
|
@@ -6124,6 +6292,7 @@ to raise the GitHub API rate limit.`
|
|
|
6124
6292
|
consola.log("\nDiff preview (--dry-run, not applied):\n");
|
|
6125
6293
|
consola.log(diff.stdout);
|
|
6126
6294
|
printWorkspaceFindings(workspaceDeps);
|
|
6295
|
+
printManagedScriptFindings(managedScripts);
|
|
6127
6296
|
return;
|
|
6128
6297
|
}
|
|
6129
6298
|
const strategy = await resolveStrategy(options.strategy);
|
|
@@ -6171,6 +6340,7 @@ to raise the GitHub API rate limit.`
|
|
|
6171
6340
|
);
|
|
6172
6341
|
}
|
|
6173
6342
|
}
|
|
6343
|
+
printManagedScriptFindings(managedScripts);
|
|
6174
6344
|
printWorkspaceFindings(workspaceDeps);
|
|
6175
6345
|
let migratedDeps = 0;
|
|
6176
6346
|
if (workspaceDeps.length) {
|
|
@@ -6190,6 +6360,7 @@ to raise the GitHub API rate limit.`
|
|
|
6190
6360
|
);
|
|
6191
6361
|
}
|
|
6192
6362
|
}
|
|
6363
|
+
await reconcileNativeHosting(catalystRoot, result);
|
|
6193
6364
|
try {
|
|
6194
6365
|
await applyIndexState(gitRoot, relDir, baseDir, theirsDir, result, stampedText !== null);
|
|
6195
6366
|
} catch (err) {
|