@bigcommerce/catalyst 1.1.1 → 1.3.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/README.md +1 -1
- package/dist/cli.js +638 -226
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/open-next.config.ts +59 -5
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.3.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() {
|
|
@@ -589,9 +594,9 @@ async function deleteProject(projectUuid, storeHash, accessToken, apiHost) {
|
|
|
589
594
|
// src/cli/lib/project-config.ts
|
|
590
595
|
import Conf2 from "conf";
|
|
591
596
|
import { join } from "path";
|
|
592
|
-
function getProjectConfig() {
|
|
597
|
+
function getProjectConfig(cwd = process.cwd()) {
|
|
593
598
|
return new Conf2({
|
|
594
|
-
cwd: join(
|
|
599
|
+
cwd: join(cwd, ".bigcommerce"),
|
|
595
600
|
projectSuffix: "",
|
|
596
601
|
configName: "project",
|
|
597
602
|
schema: {
|
|
@@ -642,7 +647,7 @@ var resolveProjectUuid = (options) => {
|
|
|
642
647
|
const projectUuid = options.projectUuid ?? config2.get("projectUuid");
|
|
643
648
|
if (!projectUuid) {
|
|
644
649
|
throw new Error(
|
|
645
|
-
"Project UUID is required. Please run either `catalyst
|
|
650
|
+
"Project UUID is required. Please run either `catalyst projects link` or `catalyst projects create` or this command again with --project-uuid <uuid>."
|
|
646
651
|
);
|
|
647
652
|
}
|
|
648
653
|
return projectUuid;
|
|
@@ -698,8 +703,8 @@ Example:
|
|
|
698
703
|
const store = await fetchStoreProfile2(storeHash, accessToken, apiHost);
|
|
699
704
|
const projectUuid = config2.get("projectUuid");
|
|
700
705
|
if (projectUuid) {
|
|
701
|
-
const
|
|
702
|
-
const linkedProject =
|
|
706
|
+
const projects2 = await fetchProjects(storeHash, accessToken, apiHost);
|
|
707
|
+
const linkedProject = projects2.find((p) => p.uuid === projectUuid);
|
|
703
708
|
if (linkedProject) {
|
|
704
709
|
consola.info(
|
|
705
710
|
`Logged in to ${store.store_name} (${storeHash}), connected to project ${linkedProject.name} (${projectUuid})`
|
|
@@ -1018,6 +1023,10 @@ async function buildCatalystProject(projectUuid, wranglerVersion = WRANGLER_VERS
|
|
|
1018
1023
|
cwd: coreDir
|
|
1019
1024
|
}
|
|
1020
1025
|
);
|
|
1026
|
+
await copyFile(
|
|
1027
|
+
join4(getModuleCliPath(), "templates", "public_headers"),
|
|
1028
|
+
join4(openNextOutDir, "assets", "_headers")
|
|
1029
|
+
);
|
|
1021
1030
|
await execa2(
|
|
1022
1031
|
"pnpm",
|
|
1023
1032
|
[
|
|
@@ -1082,13 +1091,13 @@ Examples:
|
|
|
1082
1091
|
const projectUuid = options.projectUuid ?? config2.get("projectUuid");
|
|
1083
1092
|
if (!projectUuid) {
|
|
1084
1093
|
throw new Error(
|
|
1085
|
-
"Project UUID is required. Please run `catalyst
|
|
1094
|
+
"Project UUID is required. Please run `catalyst projects create` or `catalyst projects link` or this command again with --project-uuid <uuid>."
|
|
1086
1095
|
);
|
|
1087
1096
|
}
|
|
1088
1097
|
await buildCatalystProject(projectUuid, options.wranglerVersion);
|
|
1089
1098
|
});
|
|
1090
1099
|
|
|
1091
|
-
// src/cli/commands/
|
|
1100
|
+
// src/cli/commands/channels.ts
|
|
1092
1101
|
import { select as select4 } from "@inquirer/prompts";
|
|
1093
1102
|
import { Command as Command3, InvalidArgumentError as InvalidArgumentError2, Option as Option3 } from "commander";
|
|
1094
1103
|
import { colorize as colorize5 } from "consola/utils";
|
|
@@ -1118,8 +1127,8 @@ var channelsResponseSchema = z7.object({
|
|
|
1118
1127
|
data: z7.array(channelSchema)
|
|
1119
1128
|
});
|
|
1120
1129
|
var CHANNEL_PLATFORM_ORDER = ["catalyst", "next", "bigcommerce"];
|
|
1121
|
-
function sortChannelsByPlatform(
|
|
1122
|
-
return [...
|
|
1130
|
+
function sortChannelsByPlatform(channels2) {
|
|
1131
|
+
return [...channels2].sort((a, b) => {
|
|
1123
1132
|
const aIndex = CHANNEL_PLATFORM_ORDER.indexOf(a.platform);
|
|
1124
1133
|
const bIndex = CHANNEL_PLATFORM_ORDER.indexOf(b.platform);
|
|
1125
1134
|
if (aIndex === -1 && bIndex === -1) return 0;
|
|
@@ -1284,6 +1293,16 @@ var OPENNEXT_CLOUDFLARE_VERSION = "1.17.3";
|
|
|
1284
1293
|
var corePackageJsonSchema = z8.looseObject({
|
|
1285
1294
|
dependencies: z8.record(z8.string(), z8.string()).optional()
|
|
1286
1295
|
});
|
|
1296
|
+
var projectJsonSchema2 = z8.looseObject({});
|
|
1297
|
+
var readProjectJson = (path) => {
|
|
1298
|
+
if (!existsSync3(path)) return {};
|
|
1299
|
+
try {
|
|
1300
|
+
const parsed = projectJsonSchema2.safeParse(JSON.parse(readFileSync2(path, "utf-8")));
|
|
1301
|
+
return parsed.success ? parsed.data : {};
|
|
1302
|
+
} catch {
|
|
1303
|
+
return {};
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1287
1306
|
var writeJson = (path, value) => {
|
|
1288
1307
|
mkdirSync(dirname2(path), { recursive: true });
|
|
1289
1308
|
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
@@ -1343,13 +1362,15 @@ var setupCommerceHosting = async ({
|
|
|
1343
1362
|
"@opennextjs/cloudflare": OPENNEXT_CLOUDFLARE_VERSION
|
|
1344
1363
|
};
|
|
1345
1364
|
writeJson(corePackageJsonPath, sortPackageJsonFields(pkg));
|
|
1365
|
+
const projectJsonPath = join5(projectDir, ".bigcommerce", "project.json");
|
|
1346
1366
|
const projectJson = {
|
|
1367
|
+
...readProjectJson(projectJsonPath),
|
|
1347
1368
|
projectUuid,
|
|
1348
1369
|
framework: "catalyst"
|
|
1349
1370
|
};
|
|
1350
1371
|
if (storeHash) projectJson.storeHash = storeHash;
|
|
1351
1372
|
if (accessToken) projectJson.accessToken = accessToken;
|
|
1352
|
-
writeJson(
|
|
1373
|
+
writeJson(projectJsonPath, projectJson);
|
|
1353
1374
|
convertProxyToMiddleware(projectDir);
|
|
1354
1375
|
};
|
|
1355
1376
|
var NoLinkedProjectError = class extends Error {
|
|
@@ -1405,7 +1426,7 @@ async function selectOrCreateInfrastructureProject(api, linkedProjectUuid) {
|
|
|
1405
1426
|
}
|
|
1406
1427
|
async function promptForCommerceHostingProject(api, defaultName, autoUseDefaultName, useExistingOnCollision) {
|
|
1407
1428
|
const existingProjects = await fetchProjects(api.storeHash, api.accessToken, api.apiHost);
|
|
1408
|
-
const takenNames = existingProjects.map((
|
|
1429
|
+
const takenNames = existingProjects.map((project) => project.name);
|
|
1409
1430
|
if (autoUseDefaultName) {
|
|
1410
1431
|
return autoCreateCommerceHostingProject(
|
|
1411
1432
|
api,
|
|
@@ -1415,7 +1436,7 @@ async function promptForCommerceHostingProject(api, defaultName, autoUseDefaultN
|
|
|
1415
1436
|
);
|
|
1416
1437
|
}
|
|
1417
1438
|
const conflict = existingProjects.find(
|
|
1418
|
-
(
|
|
1439
|
+
(project) => project.name.toLowerCase() === defaultName.toLowerCase()
|
|
1419
1440
|
);
|
|
1420
1441
|
if (!conflict) {
|
|
1421
1442
|
return autoCreateCommerceHostingProject(
|
|
@@ -1447,10 +1468,10 @@ async function promptForCommerceHostingProject(api, defaultName, autoUseDefaultN
|
|
|
1447
1468
|
const selected = await select({
|
|
1448
1469
|
message: "Which Commerce Hosting project would you like to use?",
|
|
1449
1470
|
choices: [
|
|
1450
|
-
...existingProjects.map((
|
|
1451
|
-
name:
|
|
1452
|
-
value:
|
|
1453
|
-
description:
|
|
1471
|
+
...existingProjects.map((project) => ({
|
|
1472
|
+
name: project.name,
|
|
1473
|
+
value: project,
|
|
1474
|
+
description: project.uuid
|
|
1454
1475
|
})),
|
|
1455
1476
|
new Separator(),
|
|
1456
1477
|
{ name: "Create a new project", value: "create-new" }
|
|
@@ -1514,7 +1535,7 @@ async function resolveCollisionChoice(existingName, useExistingOnCollision) {
|
|
|
1514
1535
|
}
|
|
1515
1536
|
async function autoCreateCommerceHostingProject(api, name, existingProjects, useExistingOnCollision) {
|
|
1516
1537
|
const existing = existingProjects.find(
|
|
1517
|
-
(
|
|
1538
|
+
(project) => project.name.toLowerCase() === name.toLowerCase()
|
|
1518
1539
|
);
|
|
1519
1540
|
if (existing) {
|
|
1520
1541
|
const shouldUseExisting = await resolveCollisionChoice(existing.name, useExistingOnCollision);
|
|
@@ -1551,8 +1572,8 @@ async function resolveProject(options) {
|
|
|
1551
1572
|
apiHost: options.apiHost
|
|
1552
1573
|
};
|
|
1553
1574
|
if (options.projectUuid) {
|
|
1554
|
-
const
|
|
1555
|
-
const matched =
|
|
1575
|
+
const projects2 = await fetchProjects(api.storeHash, api.accessToken, api.apiHost);
|
|
1576
|
+
const matched = projects2.find((p) => p.uuid === options.projectUuid);
|
|
1556
1577
|
if (matched) return matched;
|
|
1557
1578
|
consola.warn(
|
|
1558
1579
|
`Project ${options.projectUuid} not found on this store. Pick another to continue.`
|
|
@@ -1565,13 +1586,13 @@ async function resolveChannel(options) {
|
|
|
1565
1586
|
return { id: options.channelId };
|
|
1566
1587
|
}
|
|
1567
1588
|
consola.start("Fetching channels...");
|
|
1568
|
-
const
|
|
1589
|
+
const channels2 = await fetchAvailableChannels(
|
|
1569
1590
|
options.storeHash,
|
|
1570
1591
|
options.accessToken,
|
|
1571
1592
|
options.apiHost
|
|
1572
1593
|
);
|
|
1573
1594
|
consola.success("Channels fetched.");
|
|
1574
|
-
const catalystChannels =
|
|
1595
|
+
const catalystChannels = channels2.filter((c) => c.platform === "catalyst");
|
|
1575
1596
|
if (catalystChannels.length === 0) {
|
|
1576
1597
|
throw new Error(
|
|
1577
1598
|
"No Catalyst channels found on this store. Create one with `catalyst create` and try again."
|
|
@@ -1588,19 +1609,19 @@ async function resolveChannel(options) {
|
|
|
1588
1609
|
const matched = catalystChannels.find((c) => c.id === id);
|
|
1589
1610
|
return { id, name: matched?.name };
|
|
1590
1611
|
}
|
|
1591
|
-
async function resolveHostname(
|
|
1612
|
+
async function resolveHostname(project, options) {
|
|
1592
1613
|
if (options.hostname) {
|
|
1593
1614
|
return options.hostname;
|
|
1594
1615
|
}
|
|
1595
|
-
if (
|
|
1616
|
+
if (project.deployment_hostnames.length === 0) {
|
|
1596
1617
|
throw new Error(
|
|
1597
|
-
`Project "${
|
|
1618
|
+
`Project "${project.name}" has no deployment hostnames yet. Run \`catalyst deploy\` first to create one.`
|
|
1598
1619
|
);
|
|
1599
1620
|
}
|
|
1600
1621
|
const ordered = options.preferHostname ? [
|
|
1601
|
-
...
|
|
1602
|
-
...
|
|
1603
|
-
] :
|
|
1622
|
+
...project.deployment_hostnames.filter((h) => h === options.preferHostname),
|
|
1623
|
+
...project.deployment_hostnames.filter((h) => h !== options.preferHostname)
|
|
1624
|
+
] : project.deployment_hostnames;
|
|
1604
1625
|
const selected = await select2({
|
|
1605
1626
|
message: "Select the hostname to point the channel at.",
|
|
1606
1627
|
choices: ordered.map((h) => ({ name: h, value: h }))
|
|
@@ -1608,18 +1629,18 @@ async function resolveHostname(project2, options) {
|
|
|
1608
1629
|
return selected;
|
|
1609
1630
|
}
|
|
1610
1631
|
async function runChannelSiteUrlFlow(options) {
|
|
1611
|
-
const
|
|
1612
|
-
const
|
|
1613
|
-
const hostname = await resolveHostname(
|
|
1632
|
+
const project = await resolveProject(options);
|
|
1633
|
+
const channel = await resolveChannel(options);
|
|
1634
|
+
const hostname = await resolveHostname(project, options);
|
|
1614
1635
|
const siteUrl = hostname.startsWith("https://") ? hostname : `https://${hostname}`;
|
|
1615
1636
|
await updateChannelSiteUrl(
|
|
1616
|
-
|
|
1637
|
+
channel.id,
|
|
1617
1638
|
siteUrl,
|
|
1618
1639
|
options.storeHash,
|
|
1619
1640
|
options.accessToken,
|
|
1620
1641
|
options.apiHost
|
|
1621
1642
|
);
|
|
1622
|
-
const channelLabel =
|
|
1643
|
+
const channelLabel = channel.name ? `"${channel.name}" (${channel.id})` : String(channel.id);
|
|
1623
1644
|
consola.success(`Updated channel ${channelLabel} site URL to ${siteUrl}.`);
|
|
1624
1645
|
}
|
|
1625
1646
|
|
|
@@ -1744,7 +1765,8 @@ async function runCreateChannelFlow(options) {
|
|
|
1744
1765
|
{ name: "No", value: false }
|
|
1745
1766
|
]
|
|
1746
1767
|
});
|
|
1747
|
-
|
|
1768
|
+
consola.start("Creating channel...");
|
|
1769
|
+
const channel = await createChannel(
|
|
1748
1770
|
name,
|
|
1749
1771
|
storefrontLocale,
|
|
1750
1772
|
additionalLocales,
|
|
@@ -1753,6 +1775,8 @@ async function runCreateChannelFlow(options) {
|
|
|
1753
1775
|
accessToken,
|
|
1754
1776
|
cliApiOrigin
|
|
1755
1777
|
);
|
|
1778
|
+
consola.success("Channel created.");
|
|
1779
|
+
return channel;
|
|
1756
1780
|
}
|
|
1757
1781
|
|
|
1758
1782
|
// src/cli/lib/env-config.ts
|
|
@@ -1869,7 +1893,7 @@ var writeEnv = (projectDir, envVars) => {
|
|
|
1869
1893
|
`);
|
|
1870
1894
|
};
|
|
1871
1895
|
|
|
1872
|
-
// src/cli/commands/
|
|
1896
|
+
// src/cli/commands/channels.ts
|
|
1873
1897
|
var parseChannelId = (value) => {
|
|
1874
1898
|
const parsed = Number.parseInt(value, 10);
|
|
1875
1899
|
if (Number.isNaN(parsed)) {
|
|
@@ -1902,10 +1926,10 @@ var update = new Command3("update").configureHelp({ showGlobalOptions: true }).d
|
|
|
1902
1926
|
`
|
|
1903
1927
|
Examples:
|
|
1904
1928
|
# Pick a channel and hostname interactively
|
|
1905
|
-
$ catalyst
|
|
1929
|
+
$ catalyst channels update
|
|
1906
1930
|
|
|
1907
1931
|
# Skip both prompts
|
|
1908
|
-
$ catalyst
|
|
1932
|
+
$ catalyst channels update --channel-id 123 --hostname my-storefront.example.com`
|
|
1909
1933
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(projectUuidOption()).addOption(
|
|
1910
1934
|
new Option3(
|
|
1911
1935
|
"--channel-id <id>",
|
|
@@ -1933,7 +1957,7 @@ Examples:
|
|
|
1933
1957
|
} catch (error) {
|
|
1934
1958
|
if (error instanceof NoLinkedProjectError) {
|
|
1935
1959
|
consola.info(
|
|
1936
|
-
"When you're ready to create a project, run `catalyst
|
|
1960
|
+
"When you're ready to create a project, run `catalyst projects create` or re-run `catalyst channels update`."
|
|
1937
1961
|
);
|
|
1938
1962
|
process.exit(0);
|
|
1939
1963
|
return;
|
|
@@ -1949,13 +1973,13 @@ var link = new Command3("link").configureHelp({ showGlobalOptions: true }).descr
|
|
|
1949
1973
|
`
|
|
1950
1974
|
Examples:
|
|
1951
1975
|
# Pick a channel interactively (logs you in if needed)
|
|
1952
|
-
$ catalyst
|
|
1976
|
+
$ catalyst channels link
|
|
1953
1977
|
|
|
1954
1978
|
# Non-interactive
|
|
1955
|
-
$ catalyst
|
|
1979
|
+
$ catalyst channels link --store-hash <hash> --access-token <token> --channel-id 123
|
|
1956
1980
|
|
|
1957
1981
|
# Append extra environment variables to .env.local
|
|
1958
|
-
$ catalyst
|
|
1982
|
+
$ catalyst channels link --channel-id 123 --env MY_FLAG=1`
|
|
1959
1983
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(loginUrlOption()).addOption(
|
|
1960
1984
|
new Option3("--channel-id <id>", "Link this channel directly, skipping the picker.").argParser(
|
|
1961
1985
|
parseChannelId
|
|
@@ -1971,7 +1995,7 @@ Examples:
|
|
|
1971
1995
|
const credentials = await resolveCredentialsWithLogin(options, config2, apiHost);
|
|
1972
1996
|
if (!credentials) {
|
|
1973
1997
|
consola.info(
|
|
1974
|
-
"Login aborted. Re-run `catalyst
|
|
1998
|
+
"Login aborted. Re-run `catalyst channels link` when you have your credentials ready."
|
|
1975
1999
|
);
|
|
1976
2000
|
process.exit(0);
|
|
1977
2001
|
return;
|
|
@@ -1981,8 +2005,8 @@ Examples:
|
|
|
1981
2005
|
let channelId = options.channelId;
|
|
1982
2006
|
let channelName;
|
|
1983
2007
|
if (channelId === void 0) {
|
|
1984
|
-
const
|
|
1985
|
-
if (
|
|
2008
|
+
const availableChannels = await fetchAvailableChannels(storeHash, accessToken, apiHost);
|
|
2009
|
+
if (availableChannels.length === 0) {
|
|
1986
2010
|
consola.info(
|
|
1987
2011
|
"No storefront channels found on this store. Create one with `catalyst create` and try again."
|
|
1988
2012
|
);
|
|
@@ -1991,13 +2015,13 @@ Examples:
|
|
|
1991
2015
|
}
|
|
1992
2016
|
channelId = await select4({
|
|
1993
2017
|
message: "Which channel would you like to link?",
|
|
1994
|
-
choices: sortChannelsByPlatform(
|
|
2018
|
+
choices: sortChannelsByPlatform(availableChannels).map((c) => ({
|
|
1995
2019
|
name: c.name,
|
|
1996
2020
|
value: c.id,
|
|
1997
2021
|
description: channelPlatformLabel(c.platform)
|
|
1998
2022
|
}))
|
|
1999
2023
|
});
|
|
2000
|
-
channelName =
|
|
2024
|
+
channelName = availableChannels.find((c) => c.id === channelId)?.name;
|
|
2001
2025
|
}
|
|
2002
2026
|
const initData = await getChannelInit(channelId, storeHash, accessToken, options.cliApiOrigin);
|
|
2003
2027
|
const envVars = { ...initData.envVars };
|
|
@@ -2022,13 +2046,13 @@ var create = new Command3("create").configureHelp({ showGlobalOptions: true }).d
|
|
|
2022
2046
|
`
|
|
2023
2047
|
Examples:
|
|
2024
2048
|
# Create a channel interactively (logs you in if needed)
|
|
2025
|
-
$ catalyst
|
|
2049
|
+
$ catalyst channels create
|
|
2026
2050
|
|
|
2027
2051
|
# Non-interactive, and link it to this project afterwards
|
|
2028
|
-
$ catalyst
|
|
2052
|
+
$ catalyst channels create --name "My Store" --locale en --no-sample-data --link
|
|
2029
2053
|
|
|
2030
2054
|
# Add additional storefront languages (max 4)
|
|
2031
|
-
$ catalyst
|
|
2055
|
+
$ catalyst channels create --name "My Store" --additional-locales es fr`
|
|
2032
2056
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(loginUrlOption()).option("--name <name>", "Name for the new channel. Skips the name prompt.").option(
|
|
2033
2057
|
"--locale <locale>",
|
|
2034
2058
|
'Default storefront locale (e.g. "en"). Skips the default-language prompt.'
|
|
@@ -2051,7 +2075,7 @@ Examples:
|
|
|
2051
2075
|
const credentials = await resolveCredentialsWithLogin(options, config2, apiHost);
|
|
2052
2076
|
if (!credentials) {
|
|
2053
2077
|
consola.info(
|
|
2054
|
-
"Login aborted. Re-run `catalyst
|
|
2078
|
+
"Login aborted. Re-run `catalyst channels create` when you have your credentials ready."
|
|
2055
2079
|
);
|
|
2056
2080
|
process.exit(0);
|
|
2057
2081
|
return;
|
|
@@ -2096,7 +2120,7 @@ Examples:
|
|
|
2096
2120
|
}
|
|
2097
2121
|
process.exit(0);
|
|
2098
2122
|
});
|
|
2099
|
-
var
|
|
2123
|
+
var channels = new Command3("channels").alias("channel").configureHelp({ showGlobalOptions: true }).description("Manage BigCommerce channels.").addCommand(create).addCommand(link).addCommand(update);
|
|
2100
2124
|
|
|
2101
2125
|
// src/cli/commands/create.ts
|
|
2102
2126
|
import { Command as Command4, InvalidArgumentError as InvalidArgumentError3, Option as Option4 } from "@commander-js/extra-typings";
|
|
@@ -2105,10 +2129,27 @@ import { execSync as execSync2 } from "child_process";
|
|
|
2105
2129
|
import { colorize as colorize6 } from "consola/utils";
|
|
2106
2130
|
import { pathExistsSync } from "fs-extra/esm";
|
|
2107
2131
|
import kebabCase from "lodash.kebabcase";
|
|
2108
|
-
import { join as
|
|
2132
|
+
import { join as join11 } from "path";
|
|
2109
2133
|
|
|
2110
2134
|
// src/cli/lib/detect-package-manager.ts
|
|
2135
|
+
import { access } from "fs/promises";
|
|
2136
|
+
import { join as join7 } from "path";
|
|
2111
2137
|
import { detectPackageManager as detectFromDir } from "nypm";
|
|
2138
|
+
var PROJECT_LOCKFILES = [
|
|
2139
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
2140
|
+
["yarn.lock", "yarn"],
|
|
2141
|
+
["bun.lock", "bun"],
|
|
2142
|
+
["bun.lockb", "bun"],
|
|
2143
|
+
["package-lock.json", "npm"]
|
|
2144
|
+
];
|
|
2145
|
+
var detectLockfileManager = async (dir) => {
|
|
2146
|
+
const found = await Promise.all(
|
|
2147
|
+
PROJECT_LOCKFILES.map(
|
|
2148
|
+
async ([file, manager]) => access(join7(dir, file)).then(() => manager).catch(() => null)
|
|
2149
|
+
)
|
|
2150
|
+
);
|
|
2151
|
+
return found.find((manager) => manager !== null) ?? null;
|
|
2152
|
+
};
|
|
2112
2153
|
var detectPackageManager = () => {
|
|
2113
2154
|
const userAgent = process.env.npm_config_user_agent ?? "";
|
|
2114
2155
|
const name = userAgent.split(" ")[0]?.split("/")[0];
|
|
@@ -2184,7 +2225,7 @@ var extractCatalyst = async ({
|
|
|
2184
2225
|
// src/cli/lib/init-git-repo.ts
|
|
2185
2226
|
import { execSync } from "child_process";
|
|
2186
2227
|
import { rmSync } from "fs";
|
|
2187
|
-
import { join as
|
|
2228
|
+
import { join as join8 } from "path";
|
|
2188
2229
|
var run = (command, cwd) => execSync(command, { cwd, stdio: "ignore" });
|
|
2189
2230
|
var initGitRepo = (projectDir) => {
|
|
2190
2231
|
try {
|
|
@@ -2193,7 +2234,7 @@ var initGitRepo = (projectDir) => {
|
|
|
2193
2234
|
run('git commit -m "Initial commit from Catalyst"', projectDir);
|
|
2194
2235
|
consola.success("Initialized a git repository.");
|
|
2195
2236
|
} catch {
|
|
2196
|
-
rmSync(
|
|
2237
|
+
rmSync(join8(projectDir, ".git"), { recursive: true, force: true });
|
|
2197
2238
|
consola.warn("Could not initialize a git repository. Skipping.");
|
|
2198
2239
|
}
|
|
2199
2240
|
};
|
|
@@ -2237,7 +2278,7 @@ var installDependencies = async (projectDir, packageManager = "pnpm") => {
|
|
|
2237
2278
|
|
|
2238
2279
|
// src/cli/lib/rewrite-core-package.ts
|
|
2239
2280
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
2240
|
-
import { join as
|
|
2281
|
+
import { join as join9 } from "path";
|
|
2241
2282
|
import { z as z10 } from "zod";
|
|
2242
2283
|
var NATIVE_BUILD_ALLOWLIST = [
|
|
2243
2284
|
"@parcel/watcher",
|
|
@@ -2279,7 +2320,7 @@ var resolvePublishedVersion = async (pkgName) => {
|
|
|
2279
2320
|
return `^${version2}`;
|
|
2280
2321
|
};
|
|
2281
2322
|
var rewriteCorePackage = async (projectDir, ref) => {
|
|
2282
|
-
const packageJsonPath =
|
|
2323
|
+
const packageJsonPath = join9(projectDir, "package.json");
|
|
2283
2324
|
const pkg = corePackageJsonSchema2.parse(JSON.parse(readFileSync4(packageJsonPath, "utf-8")));
|
|
2284
2325
|
const workspaceDeps = DEP_FIELDS.flatMap((field) => {
|
|
2285
2326
|
const deps = pkg[field];
|
|
@@ -2304,12 +2345,12 @@ var rewriteCorePackage = async (projectDir, ref) => {
|
|
|
2304
2345
|
pkg.catalyst = { ...pkg.catalyst, version: pkg.version, ref };
|
|
2305
2346
|
writeFileSync2(packageJsonPath, `${JSON.stringify(sortPackageJsonFields(pkg), null, 2)}
|
|
2306
2347
|
`);
|
|
2307
|
-
writeFileSync2(
|
|
2348
|
+
writeFileSync2(join9(projectDir, ".npmrc"), "legacy-peer-deps=true\n");
|
|
2308
2349
|
};
|
|
2309
2350
|
|
|
2310
2351
|
// src/cli/lib/setup-core-project.ts
|
|
2311
2352
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2312
|
-
import { dirname as dirname3, join as
|
|
2353
|
+
import { dirname as dirname3, join as join10 } from "path";
|
|
2313
2354
|
import { z as z11 } from "zod";
|
|
2314
2355
|
var corePackageJsonSchema3 = z11.looseObject({
|
|
2315
2356
|
scripts: z11.record(z11.string(), z11.string()).optional(),
|
|
@@ -2321,7 +2362,7 @@ var writeJson2 = (path, value) => {
|
|
|
2321
2362
|
`);
|
|
2322
2363
|
};
|
|
2323
2364
|
var setupCoreProject = (projectDir) => {
|
|
2324
|
-
const corePackageJsonPath =
|
|
2365
|
+
const corePackageJsonPath = join10(projectDir, "package.json");
|
|
2325
2366
|
const pkg = corePackageJsonSchema3.parse(JSON.parse(readFileSync5(corePackageJsonPath, "utf-8")));
|
|
2326
2367
|
pkg.scripts = {
|
|
2327
2368
|
...pkg.scripts,
|
|
@@ -2361,10 +2402,10 @@ function parseEnvFlag(value, previous = {}) {
|
|
|
2361
2402
|
return { ...previous, [key]: val };
|
|
2362
2403
|
}
|
|
2363
2404
|
async function handleChannelSelection(storeHash, accessToken, apiHost) {
|
|
2364
|
-
const
|
|
2405
|
+
const channels2 = await fetchAvailableChannels(storeHash, accessToken, apiHost);
|
|
2365
2406
|
const existingChannel = await select5({
|
|
2366
2407
|
message: "Which channel would you like to use?",
|
|
2367
|
-
choices: sortChannelsByPlatform(
|
|
2408
|
+
choices: sortChannelsByPlatform(channels2).map((ch) => ({
|
|
2368
2409
|
name: ch.name,
|
|
2369
2410
|
value: ch,
|
|
2370
2411
|
description: `Channel Platform: ${channelPlatformLabel(ch.platform)}`
|
|
@@ -2380,7 +2421,7 @@ async function setupProject(options) {
|
|
|
2380
2421
|
}
|
|
2381
2422
|
if (projectName) {
|
|
2382
2423
|
projectName = kebabCase(projectName);
|
|
2383
|
-
projectDir =
|
|
2424
|
+
projectDir = join11(options.projectDir, projectName);
|
|
2384
2425
|
if (pathExistsSync(projectDir)) {
|
|
2385
2426
|
consola.error(`${projectDir} already exists`);
|
|
2386
2427
|
process.exit(1);
|
|
@@ -2390,7 +2431,7 @@ async function setupProject(options) {
|
|
|
2390
2431
|
const validateProjectName = (i) => {
|
|
2391
2432
|
const formatted = kebabCase(i);
|
|
2392
2433
|
if (!formatted) return "Project name is required";
|
|
2393
|
-
const targetDir =
|
|
2434
|
+
const targetDir = join11(options.projectDir, formatted);
|
|
2394
2435
|
if (pathExistsSync(targetDir)) return `Destination '${targetDir}' already exists`;
|
|
2395
2436
|
projectName = formatted;
|
|
2396
2437
|
projectDir = targetDir;
|
|
@@ -2573,6 +2614,11 @@ Examples:
|
|
|
2573
2614
|
accessToken
|
|
2574
2615
|
});
|
|
2575
2616
|
}
|
|
2617
|
+
if (storeHash && accessToken) {
|
|
2618
|
+
const projectConfig = getProjectConfig(projectDir);
|
|
2619
|
+
projectConfig.set("storeHash", storeHash);
|
|
2620
|
+
projectConfig.set("accessToken", accessToken);
|
|
2621
|
+
}
|
|
2576
2622
|
writeEnv(projectDir, envVars);
|
|
2577
2623
|
await installDependencies(projectDir, packageManager);
|
|
2578
2624
|
initGitRepo(projectDir);
|
|
@@ -2605,7 +2651,7 @@ import { Command as Command5, Option as Option5 } from "commander";
|
|
|
2605
2651
|
import { parse } from "dotenv";
|
|
2606
2652
|
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
|
|
2607
2653
|
import { release } from "os";
|
|
2608
|
-
import { dirname as dirname4, join as
|
|
2654
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
2609
2655
|
import { z as z12 } from "zod";
|
|
2610
2656
|
var CLI_ENV_VARS = [
|
|
2611
2657
|
"CATALYST_STORE_HASH",
|
|
@@ -2622,7 +2668,7 @@ var BUILD_ENV_VARS = [
|
|
|
2622
2668
|
"AUTH_SECRET"
|
|
2623
2669
|
];
|
|
2624
2670
|
var ENV_FILES = [".env.local", ".env"];
|
|
2625
|
-
var
|
|
2671
|
+
var PROJECT_LOCKFILES2 = [
|
|
2626
2672
|
["pnpm-lock.yaml", "pnpm"],
|
|
2627
2673
|
["yarn.lock", "yarn"],
|
|
2628
2674
|
["bun.lock", "bun"],
|
|
@@ -2633,7 +2679,7 @@ var hasValue = (value) => value !== void 0 && value.trim() !== "";
|
|
|
2633
2679
|
var buildEnvLayers = (cwd, env2) => {
|
|
2634
2680
|
const layers = [{ source: "process.env", values: env2 }];
|
|
2635
2681
|
ENV_FILES.forEach((file) => {
|
|
2636
|
-
const path =
|
|
2682
|
+
const path = join12(cwd, file);
|
|
2637
2683
|
if (!existsSync5(path)) {
|
|
2638
2684
|
return;
|
|
2639
2685
|
}
|
|
@@ -2656,7 +2702,7 @@ var resolveValue = (envSource, configValue) => {
|
|
|
2656
2702
|
return { present: false, source: "unset" };
|
|
2657
2703
|
};
|
|
2658
2704
|
var asString = (value) => typeof value === "string" ? value : void 0;
|
|
2659
|
-
var lockfileManager = (dir) =>
|
|
2705
|
+
var lockfileManager = (dir) => PROJECT_LOCKFILES2.find(([file]) => existsSync5(join12(dir, file)))?.[1];
|
|
2660
2706
|
var detectProjectPackageManager2 = (cwd) => {
|
|
2661
2707
|
let dir = cwd;
|
|
2662
2708
|
for (; ; ) {
|
|
@@ -2671,7 +2717,7 @@ var detectProjectPackageManager2 = (cwd) => {
|
|
|
2671
2717
|
dir = parent;
|
|
2672
2718
|
}
|
|
2673
2719
|
};
|
|
2674
|
-
var
|
|
2720
|
+
var projectJsonSchema3 = z12.looseObject({});
|
|
2675
2721
|
var safeReadJson2 = (path) => {
|
|
2676
2722
|
try {
|
|
2677
2723
|
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
@@ -2679,9 +2725,9 @@ var safeReadJson2 = (path) => {
|
|
|
2679
2725
|
return null;
|
|
2680
2726
|
}
|
|
2681
2727
|
};
|
|
2682
|
-
var
|
|
2683
|
-
const result =
|
|
2684
|
-
safeReadJson2(
|
|
2728
|
+
var readProjectJson2 = (cwd) => {
|
|
2729
|
+
const result = projectJsonSchema3.safeParse(
|
|
2730
|
+
safeReadJson2(join12(cwd, ".bigcommerce", "project.json"))
|
|
2685
2731
|
);
|
|
2686
2732
|
return result.success ? result.data : null;
|
|
2687
2733
|
};
|
|
@@ -2691,7 +2737,7 @@ var storefrontPackageSchema = z12.looseObject({
|
|
|
2691
2737
|
catalyst: z12.looseObject({ version: z12.string().optional() }).optional()
|
|
2692
2738
|
});
|
|
2693
2739
|
var readStorefrontInfo = (cwd) => {
|
|
2694
|
-
const result = storefrontPackageSchema.safeParse(safeReadJson2(
|
|
2740
|
+
const result = storefrontPackageSchema.safeParse(safeReadJson2(join12(cwd, "package.json")));
|
|
2695
2741
|
if (!result.success) {
|
|
2696
2742
|
return { name: null, version: null };
|
|
2697
2743
|
}
|
|
@@ -2712,8 +2758,8 @@ function collectDiagnostics({
|
|
|
2712
2758
|
env: env2 = process.env
|
|
2713
2759
|
} = {}) {
|
|
2714
2760
|
const state = getProjectState(cwd);
|
|
2715
|
-
const
|
|
2716
|
-
const projectJson =
|
|
2761
|
+
const telemetry2 = getTelemetry();
|
|
2762
|
+
const projectJson = readProjectJson2(cwd);
|
|
2717
2763
|
const storefront = readStorefrontInfo(cwd);
|
|
2718
2764
|
const cliEnv = [{ source: "process.env", values: env2 }];
|
|
2719
2765
|
const buildEnv = buildEnvLayers(cwd, env2);
|
|
@@ -2764,16 +2810,16 @@ function collectDiagnostics({
|
|
|
2764
2810
|
buildEnvVars: resolveEnvVars(buildEnv, BUILD_ENV_VARS)
|
|
2765
2811
|
},
|
|
2766
2812
|
telemetry: {
|
|
2767
|
-
enabled:
|
|
2768
|
-
correlationId:
|
|
2813
|
+
enabled: telemetry2.isEnabled(),
|
|
2814
|
+
correlationId: telemetry2.correlationId
|
|
2769
2815
|
},
|
|
2770
2816
|
files: {
|
|
2771
|
-
".env.local": existsSync5(
|
|
2772
|
-
".env": existsSync5(
|
|
2773
|
-
".bigcommerce/project.json": existsSync5(
|
|
2774
|
-
".bigcommerce/wrangler.jsonc": existsSync5(
|
|
2775
|
-
".open-next/": existsSync5(
|
|
2776
|
-
"package.json": existsSync5(
|
|
2817
|
+
".env.local": existsSync5(join12(cwd, ".env.local")),
|
|
2818
|
+
".env": existsSync5(join12(cwd, ".env")),
|
|
2819
|
+
".bigcommerce/project.json": existsSync5(join12(cwd, ".bigcommerce", "project.json")),
|
|
2820
|
+
".bigcommerce/wrangler.jsonc": existsSync5(join12(cwd, ".bigcommerce", "wrangler.jsonc")),
|
|
2821
|
+
".open-next/": existsSync5(join12(cwd, ".open-next")),
|
|
2822
|
+
"package.json": existsSync5(join12(cwd, "package.json"))
|
|
2777
2823
|
}
|
|
2778
2824
|
};
|
|
2779
2825
|
}
|
|
@@ -2864,8 +2910,8 @@ import { confirm as confirm3 } from "@inquirer/prompts";
|
|
|
2864
2910
|
import AdmZip from "adm-zip";
|
|
2865
2911
|
import { Command as Command6, Option as Option6 } from "commander";
|
|
2866
2912
|
import { colorize as colorize7 } from "consola/utils";
|
|
2867
|
-
import { access, readdir, readFile } from "fs/promises";
|
|
2868
|
-
import { join as
|
|
2913
|
+
import { access as access2, readdir, readFile } from "fs/promises";
|
|
2914
|
+
import { join as join13 } from "path";
|
|
2869
2915
|
import yoctoSpinner3 from "yocto-spinner";
|
|
2870
2916
|
import { z as z13 } from "zod";
|
|
2871
2917
|
|
|
@@ -2937,10 +2983,10 @@ var DeploymentStatusSchema = z13.object({
|
|
|
2937
2983
|
});
|
|
2938
2984
|
var generateBundleZip = async () => {
|
|
2939
2985
|
consola.info("Generating bundle...");
|
|
2940
|
-
const bigcommerceDir =
|
|
2941
|
-
const distDir =
|
|
2986
|
+
const bigcommerceDir = join13(process.cwd(), ".bigcommerce");
|
|
2987
|
+
const distDir = join13(process.cwd(), ".bigcommerce", "dist");
|
|
2942
2988
|
try {
|
|
2943
|
-
await
|
|
2989
|
+
await access2(distDir);
|
|
2944
2990
|
} catch {
|
|
2945
2991
|
throw new Error(`Dist directory not found: ${distDir}`);
|
|
2946
2992
|
}
|
|
@@ -2948,7 +2994,7 @@ var generateBundleZip = async () => {
|
|
|
2948
2994
|
if (buildDirContents.length === 0) {
|
|
2949
2995
|
throw new Error(`Dist directory is empty: ${distDir}`);
|
|
2950
2996
|
}
|
|
2951
|
-
const outputZip =
|
|
2997
|
+
const outputZip = join13(bigcommerceDir, "bundle.zip");
|
|
2952
2998
|
const zip = new AdmZip();
|
|
2953
2999
|
zip.addLocalFolder(distDir, "output");
|
|
2954
3000
|
zip.writeZip(outputZip);
|
|
@@ -2980,7 +3026,7 @@ var generateUploadSignature = async (storeHash, accessToken, apiHost) => {
|
|
|
2980
3026
|
};
|
|
2981
3027
|
var uploadBundleZip = async (uploadUrl) => {
|
|
2982
3028
|
consola.info("Uploading bundle...");
|
|
2983
|
-
const zipPath =
|
|
3029
|
+
const zipPath = join13(process.cwd(), ".bigcommerce", "bundle.zip");
|
|
2984
3030
|
const fileBuffer = await readFile(zipPath);
|
|
2985
3031
|
const response = await fetch(uploadUrl, {
|
|
2986
3032
|
method: "PUT",
|
|
@@ -3115,7 +3161,7 @@ var fetchProject = async (projectUuid, storeHash, accessToken, apiHost) => {
|
|
|
3115
3161
|
}
|
|
3116
3162
|
const res = await response.json();
|
|
3117
3163
|
const { data } = ProjectSchema.parse(res);
|
|
3118
|
-
return data.find((
|
|
3164
|
+
return data.find((project) => project.uuid === projectUuid);
|
|
3119
3165
|
};
|
|
3120
3166
|
var deploy = new Command6("deploy").configureHelp({ showGlobalOptions: true }).description("Deploy your application to Cloudflare.").addHelpText(
|
|
3121
3167
|
"after",
|
|
@@ -3147,8 +3193,8 @@ Example:
|
|
|
3147
3193
|
const config2 = getProjectConfig();
|
|
3148
3194
|
const apiHost = resolveApiHost(options, config2);
|
|
3149
3195
|
const { storeHash, accessToken } = resolveCredentials(options, config2);
|
|
3150
|
-
const
|
|
3151
|
-
await
|
|
3196
|
+
const telemetry2 = getTelemetry();
|
|
3197
|
+
await telemetry2.identify(storeHash);
|
|
3152
3198
|
const linkedProjectUuid = options.projectUuid ?? config2.get("projectUuid");
|
|
3153
3199
|
let projectUuid;
|
|
3154
3200
|
const promptForProject = async () => {
|
|
@@ -3161,7 +3207,7 @@ Example:
|
|
|
3161
3207
|
} catch (error) {
|
|
3162
3208
|
if (error instanceof NoLinkedProjectError) {
|
|
3163
3209
|
consola.info(
|
|
3164
|
-
"When you're ready to create a project, run `catalyst
|
|
3210
|
+
"When you're ready to create a project, run `catalyst projects create` or re-run `catalyst deploy`."
|
|
3165
3211
|
);
|
|
3166
3212
|
process.exit(0);
|
|
3167
3213
|
}
|
|
@@ -3206,9 +3252,9 @@ Example:
|
|
|
3206
3252
|
await cleanupCloudflareIncompatibilities(process.cwd());
|
|
3207
3253
|
}
|
|
3208
3254
|
if (options.prebuilt) {
|
|
3209
|
-
const distDir =
|
|
3255
|
+
const distDir = join13(process.cwd(), ".bigcommerce", "dist");
|
|
3210
3256
|
try {
|
|
3211
|
-
await
|
|
3257
|
+
await access2(distDir);
|
|
3212
3258
|
} catch {
|
|
3213
3259
|
throw new Error(
|
|
3214
3260
|
"No build output found at .bigcommerce/dist/. Run `catalyst build` first or remove `--prebuilt` to build automatically."
|
|
@@ -3290,6 +3336,7 @@ var LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
|
3290
3336
|
var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3291
3337
|
var logEntrySchema = z14.object({
|
|
3292
3338
|
timestamp: z14.string().nullable().optional(),
|
|
3339
|
+
entry_type: z14.string().optional(),
|
|
3293
3340
|
level: z14.string().optional(),
|
|
3294
3341
|
messages: z14.array(z14.unknown()).optional(),
|
|
3295
3342
|
is_exception: z14.boolean().optional(),
|
|
@@ -3301,7 +3348,22 @@ var logEntrySchema = z14.object({
|
|
|
3301
3348
|
}).nullable().optional()
|
|
3302
3349
|
});
|
|
3303
3350
|
var queryLogsSchema = z14.object({
|
|
3304
|
-
data: z14.array(logEntrySchema)
|
|
3351
|
+
data: z14.array(logEntrySchema),
|
|
3352
|
+
meta: z14.object({
|
|
3353
|
+
cursor_pagination: z14.object({
|
|
3354
|
+
// The REST proxy exposes page availability via links, while the
|
|
3355
|
+
// gRPC response uses has_next_page/has_prev_page. Accept both while
|
|
3356
|
+
// the API contract is transitioning.
|
|
3357
|
+
has_next_page: z14.boolean().optional(),
|
|
3358
|
+
has_prev_page: z14.boolean().optional(),
|
|
3359
|
+
start_cursor: z14.string().nullable().optional(),
|
|
3360
|
+
end_cursor: z14.string().nullable().optional(),
|
|
3361
|
+
links: z14.object({
|
|
3362
|
+
next: z14.string().optional(),
|
|
3363
|
+
previous: z14.string().optional()
|
|
3364
|
+
}).optional()
|
|
3365
|
+
}).optional()
|
|
3366
|
+
}).optional()
|
|
3305
3367
|
});
|
|
3306
3368
|
var v3ErrorSchema = z14.object({
|
|
3307
3369
|
title: z14.string().optional(),
|
|
@@ -3391,8 +3453,16 @@ function isRedundantExceptionName(name, message) {
|
|
|
3391
3453
|
return parts.length > 0 && parts.every((part) => message.includes(part));
|
|
3392
3454
|
}
|
|
3393
3455
|
var stringifyMessage = (message) => typeof message === "string" ? message : JSON.stringify(message);
|
|
3456
|
+
var joinMessages = (messages) => (messages ?? []).map(stringifyMessage).join(" ").replace(/\s+/g, " ").trim();
|
|
3457
|
+
function isRequestLogEntry(entry) {
|
|
3458
|
+
if (entry.entry_type != null) return entry.entry_type === "request";
|
|
3459
|
+
const method = entry.request?.method;
|
|
3460
|
+
const url = entry.request?.url;
|
|
3461
|
+
if (!method || !url) return false;
|
|
3462
|
+
return joinMessages(entry.messages) === `${method} ${url}`;
|
|
3463
|
+
}
|
|
3394
3464
|
function formatLogEntry(entry, format = "default") {
|
|
3395
|
-
const message = (entry.messages
|
|
3465
|
+
const message = joinMessages(entry.messages);
|
|
3396
3466
|
if (format === "short") return message;
|
|
3397
3467
|
const level = entry.level ?? "unknown";
|
|
3398
3468
|
const coloredLevel = colorize8(LEVEL_COLORS[level.toLowerCase()] ?? "white", level.toUpperCase());
|
|
@@ -3405,17 +3475,23 @@ function formatLogEntry(entry, format = "default") {
|
|
|
3405
3475
|
const status = entry.request.status_code ? ` (${entry.request.status_code})` : "";
|
|
3406
3476
|
if (parts.length > 0) requestStr = ` ${parts.join(" ")}${status}`;
|
|
3407
3477
|
}
|
|
3408
|
-
|
|
3478
|
+
if (format === "request" && isRequestLogEntry(entry)) {
|
|
3479
|
+
return `[${entry.timestamp ?? UNKNOWN_TIME}]${requestStr}`;
|
|
3480
|
+
}
|
|
3481
|
+
return `[${entry.timestamp ?? UNKNOWN_TIME}]${requestStr} [${coloredLevel}]${exceptionStr} ${message}`;
|
|
3409
3482
|
}
|
|
3410
3483
|
async function queryLogs(projectUuid, storeHash, accessToken, apiHost, params) {
|
|
3411
3484
|
const search = new URLSearchParams();
|
|
3412
3485
|
search.set("start", params.start);
|
|
3413
3486
|
search.set("end", params.end);
|
|
3487
|
+
if (params.entryType) search.set("entry_type", params.entryType);
|
|
3414
3488
|
if (params.method) search.set("method", params.method);
|
|
3415
3489
|
if (params.statusCode != null) search.set("status_code", String(params.statusCode));
|
|
3416
3490
|
if (params.urlLike) search.set("url:like", params.urlLike);
|
|
3417
3491
|
if (params.levelMin) search.set("level:min", params.levelMin);
|
|
3418
3492
|
if (params.limit != null) search.set("limit", String(params.limit));
|
|
3493
|
+
if (params.after) search.set("after", params.after);
|
|
3494
|
+
if (params.before) search.set("before", params.before);
|
|
3419
3495
|
const response = await fetch(
|
|
3420
3496
|
`https://${apiHost}/stores/${storeHash}/v3/infrastructure/logs/${projectUuid}?${search.toString()}`,
|
|
3421
3497
|
{
|
|
@@ -3434,7 +3510,9 @@ async function queryLogs(projectUuid, storeHash, accessToken, apiHost, params) {
|
|
|
3434
3510
|
);
|
|
3435
3511
|
}
|
|
3436
3512
|
if (response.status === 404) {
|
|
3437
|
-
throw new UserActionableError(
|
|
3513
|
+
throw new UserActionableError(
|
|
3514
|
+
"Project not found. Check the project UUID, and that --store-hash and --access-token belong to the store that owns the project."
|
|
3515
|
+
);
|
|
3438
3516
|
}
|
|
3439
3517
|
if (response.status === 400 || response.status === 422) {
|
|
3440
3518
|
const body = await response.json().catch(() => null);
|
|
@@ -3449,11 +3527,18 @@ async function queryLogs(projectUuid, storeHash, accessToken, apiHost, params) {
|
|
|
3449
3527
|
|
|
3450
3528
|
// src/cli/lib/domains.ts
|
|
3451
3529
|
var domainStatusSchema = z15.enum(["pending", "verified", "failed", "unknown"]);
|
|
3530
|
+
var pointingRecordsSchema = z15.object({
|
|
3531
|
+
a_record_value: z15.string().nullish(),
|
|
3532
|
+
cname_record_value: z15.string().nullish()
|
|
3533
|
+
});
|
|
3452
3534
|
var domainSchema = z15.object({
|
|
3453
3535
|
domain: z15.string(),
|
|
3454
3536
|
project_uuid: z15.string(),
|
|
3455
3537
|
verification_status: domainStatusSchema
|
|
3456
3538
|
});
|
|
3539
|
+
var createdDomainSchema = domainSchema.extend({
|
|
3540
|
+
pointing_records: pointingRecordsSchema.nullish()
|
|
3541
|
+
});
|
|
3457
3542
|
var ownershipVerificationSchema = z15.object({
|
|
3458
3543
|
type: z15.string(),
|
|
3459
3544
|
name: z15.string(),
|
|
@@ -3494,6 +3579,9 @@ function parseBoundProjectUuid(body) {
|
|
|
3494
3579
|
var domainResponseSchema = z15.object({
|
|
3495
3580
|
data: domainSchema
|
|
3496
3581
|
});
|
|
3582
|
+
var createdDomainResponseSchema = z15.object({
|
|
3583
|
+
data: createdDomainSchema
|
|
3584
|
+
});
|
|
3497
3585
|
var domainListResponseSchema = z15.object({
|
|
3498
3586
|
data: z15.array(domainSchema)
|
|
3499
3587
|
});
|
|
@@ -3562,7 +3650,7 @@ async function createDomain(domain, projectUuid, storeHash, accessToken, apiHost
|
|
|
3562
3650
|
});
|
|
3563
3651
|
await assertDomainResponse(response, "Failed to add domain");
|
|
3564
3652
|
const result = await response.json();
|
|
3565
|
-
return
|
|
3653
|
+
return createdDomainResponseSchema.parse(result).data;
|
|
3566
3654
|
}
|
|
3567
3655
|
async function getDomain(domain, projectUuid, storeHash, accessToken, apiHost) {
|
|
3568
3656
|
const response = await fetch(domainUrl(storeHash, projectUuid, domain, apiHost), {
|
|
@@ -3633,6 +3721,7 @@ async function transferDomain(domain, projectUuid, newProjectUuid, storeHash, ac
|
|
|
3633
3721
|
var WAIT_INTERVAL_MS = 5e3;
|
|
3634
3722
|
var WAIT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3635
3723
|
var DOMAIN_STATUS_FILTERS = ["pending", "verified", "failed"];
|
|
3724
|
+
var RECORD_TYPE_WIDTH = "CNAME".length;
|
|
3636
3725
|
var STATUS_COLORS = {
|
|
3637
3726
|
pending: "yellow",
|
|
3638
3727
|
verified: "green",
|
|
@@ -3666,20 +3755,20 @@ async function resolveDestinationProject(domain, context, toProjectUuid) {
|
|
|
3666
3755
|
return toProjectUuid;
|
|
3667
3756
|
}
|
|
3668
3757
|
consola.start("Fetching projects...");
|
|
3669
|
-
const
|
|
3758
|
+
const projects2 = await fetchProjects(context.storeHash, context.accessToken, context.apiHost);
|
|
3670
3759
|
consola.success("Projects fetched.");
|
|
3671
|
-
const destinations =
|
|
3760
|
+
const destinations = projects2.filter((project) => project.uuid !== context.projectUuid);
|
|
3672
3761
|
if (destinations.length === 0) {
|
|
3673
3762
|
throw new UserActionableError(
|
|
3674
|
-
"No other projects to transfer to. Create another project with `catalyst
|
|
3763
|
+
"No other projects to transfer to. Create another project with `catalyst projects create` first."
|
|
3675
3764
|
);
|
|
3676
3765
|
}
|
|
3677
3766
|
return select6({
|
|
3678
3767
|
message: `Select the project to transfer ${domain} to (Press <enter> to select).`,
|
|
3679
|
-
choices: destinations.map((
|
|
3680
|
-
name:
|
|
3681
|
-
value:
|
|
3682
|
-
description:
|
|
3768
|
+
choices: destinations.map((project) => ({
|
|
3769
|
+
name: project.name,
|
|
3770
|
+
value: project.uuid,
|
|
3771
|
+
description: project.uuid
|
|
3683
3772
|
}))
|
|
3684
3773
|
});
|
|
3685
3774
|
}
|
|
@@ -3689,6 +3778,19 @@ function formatDomainStatus(status) {
|
|
|
3689
3778
|
function formatDomain(domain) {
|
|
3690
3779
|
return `${domain.domain} ${formatDomainStatus(domain.verification_status)}`;
|
|
3691
3780
|
}
|
|
3781
|
+
function formatPointingRecords(records) {
|
|
3782
|
+
const rows = [];
|
|
3783
|
+
if (records?.a_record_value) {
|
|
3784
|
+
rows.push(`${"A".padEnd(RECORD_TYPE_WIDTH)} ${records.a_record_value}`);
|
|
3785
|
+
}
|
|
3786
|
+
if (records?.cname_record_value) {
|
|
3787
|
+
rows.push(`${"CNAME".padEnd(RECORD_TYPE_WIDTH)} ${records.cname_record_value}`);
|
|
3788
|
+
}
|
|
3789
|
+
if (rows.length === 0) {
|
|
3790
|
+
return null;
|
|
3791
|
+
}
|
|
3792
|
+
return rows.map((row) => ` ${row}`).join("\n");
|
|
3793
|
+
}
|
|
3692
3794
|
function formatOwnershipVerification(record) {
|
|
3693
3795
|
const lines = [
|
|
3694
3796
|
"Add this DNS record to verify ownership:",
|
|
@@ -3720,6 +3822,10 @@ async function waitForDomainVerification({
|
|
|
3720
3822
|
var add = new Command7("add").configureHelp({ showGlobalOptions: true }).description("Add a custom domain to the current Native Hosting project.").argument("<domain>", "Custom domain to add.").addHelpText(
|
|
3721
3823
|
"after",
|
|
3722
3824
|
`
|
|
3825
|
+
The DNS records that point the domain at this project are printed once the domain
|
|
3826
|
+
is added. They are returned only by this command, so save them: publish the CNAME
|
|
3827
|
+
for a subdomain, or the A record for an apex domain.
|
|
3828
|
+
|
|
3723
3829
|
Examples:
|
|
3724
3830
|
$ catalyst domains add www.example.com
|
|
3725
3831
|
|
|
@@ -3729,9 +3835,9 @@ Examples:
|
|
|
3729
3835
|
const context = resolveDomainCommandContext(options);
|
|
3730
3836
|
await getTelemetry().identify(context.storeHash);
|
|
3731
3837
|
consola.start(`Adding domain ${domain}...`);
|
|
3732
|
-
let
|
|
3838
|
+
let created;
|
|
3733
3839
|
try {
|
|
3734
|
-
|
|
3840
|
+
created = await createDomain(
|
|
3735
3841
|
domain,
|
|
3736
3842
|
context.projectUuid,
|
|
3737
3843
|
context.storeHash,
|
|
@@ -3758,12 +3864,26 @@ Examples:
|
|
|
3758
3864
|
}
|
|
3759
3865
|
throw error;
|
|
3760
3866
|
}
|
|
3761
|
-
consola.success(`Domain ${
|
|
3867
|
+
consola.success(`Domain ${created.domain} added.`);
|
|
3868
|
+
const records = formatPointingRecords(created.pointing_records);
|
|
3869
|
+
let result = created;
|
|
3762
3870
|
if (options.wait && result.verification_status === "pending") {
|
|
3763
3871
|
consola.start(`Waiting for ${result.domain} to verify...`);
|
|
3764
3872
|
result = await waitForDomainVerification({ domain: result.domain, ...context });
|
|
3765
3873
|
}
|
|
3766
3874
|
consola.log(formatDomain(result));
|
|
3875
|
+
if (records) {
|
|
3876
|
+
consola.info(`Point ${created.domain} at this project with one of these DNS records:`);
|
|
3877
|
+
consola.log(records);
|
|
3878
|
+
consola.info(
|
|
3879
|
+
"Use the CNAME for a subdomain, or the A record for an apex domain. Save them now \u2014 only `domains add` returns them."
|
|
3880
|
+
);
|
|
3881
|
+
}
|
|
3882
|
+
if (result.verification_status === "pending") {
|
|
3883
|
+
consola.info(
|
|
3884
|
+
`Run \`catalyst domains status ${result.domain}\` to check verification progress.`
|
|
3885
|
+
);
|
|
3886
|
+
}
|
|
3767
3887
|
process.exit(0);
|
|
3768
3888
|
});
|
|
3769
3889
|
var list = new Command7("list").configureHelp({ showGlobalOptions: true }).description("List custom domains for the current Native Hosting project.").addHelpText(
|
|
@@ -3903,14 +4023,14 @@ Examples:
|
|
|
3903
4023
|
);
|
|
3904
4024
|
if (!owned) {
|
|
3905
4025
|
consola.start(`Locating the project that owns ${domain}...`);
|
|
3906
|
-
const
|
|
3907
|
-
const candidates =
|
|
4026
|
+
const projects2 = await fetchProjects(context.storeHash, context.accessToken, context.apiHost);
|
|
4027
|
+
const candidates = projects2.filter((project) => project.uuid !== context.projectUuid);
|
|
3908
4028
|
const matches = await Promise.all(
|
|
3909
|
-
candidates.map(async (
|
|
3910
|
-
project
|
|
4029
|
+
candidates.map(async (project) => ({
|
|
4030
|
+
project,
|
|
3911
4031
|
found: await findDomain(
|
|
3912
4032
|
domain,
|
|
3913
|
-
|
|
4033
|
+
project.uuid,
|
|
3914
4034
|
context.storeHash,
|
|
3915
4035
|
context.accessToken,
|
|
3916
4036
|
context.apiHost
|
|
@@ -4005,7 +4125,7 @@ Examples:
|
|
|
4005
4125
|
consola.success(`Domain ${current.domain} removed.`);
|
|
4006
4126
|
process.exit(0);
|
|
4007
4127
|
});
|
|
4008
|
-
var domains = new Command7("domains").configureHelp({ showGlobalOptions: true }).description("Manage custom domains for the current Native Hosting project.").addCommand(add).addCommand(list).addCommand(showStatus).addCommand(claim).addCommand(transfer).addCommand(remove);
|
|
4128
|
+
var domains = new Command7("domains").alias("domain").configureHelp({ showGlobalOptions: true }).description("Manage custom domains for the current Native Hosting project.").addCommand(add).addCommand(list).addCommand(showStatus).addCommand(claim).addCommand(transfer).addCommand(remove);
|
|
4009
4129
|
|
|
4010
4130
|
// src/cli/commands/env.ts
|
|
4011
4131
|
import { Command as Command8 } from "commander";
|
|
@@ -4083,7 +4203,6 @@ var env = new Command8("env").configureHelp({ showGlobalOptions: true }).descrip
|
|
|
4083
4203
|
import { Command as Command9, InvalidArgumentError as InvalidArgumentError4, Option as Option8 } from "commander";
|
|
4084
4204
|
import { colorize as colorize10 } from "consola/utils";
|
|
4085
4205
|
import { z as z16 } from "zod";
|
|
4086
|
-
var telemetry = new Telemetry();
|
|
4087
4206
|
var DEFAULT_CONNECTION_TTL_MS = 1 * 60 * 1e3;
|
|
4088
4207
|
var MAX_RETRIES = 5;
|
|
4089
4208
|
var isFatalStatusCode = (status) => status >= 400 && status < 500;
|
|
@@ -4118,8 +4237,19 @@ var StreamError = class extends Error {
|
|
|
4118
4237
|
}
|
|
4119
4238
|
};
|
|
4120
4239
|
var formatMessages = (messages) => messages.map((m) => typeof m === "string" ? m : JSON.stringify(m)).join(" ");
|
|
4240
|
+
var formatRequestLine = (event, entry) => {
|
|
4241
|
+
const { request } = event;
|
|
4242
|
+
const msg = entry ? formatMessages(entry.messages) : "";
|
|
4243
|
+
const msgPart = msg ? ` ${msg}` : "";
|
|
4244
|
+
const level = msg ? entry?.level.toUpperCase() : void 0;
|
|
4245
|
+
const levelPart = level ? ` [${colorize10(LEVEL_COLORS2[level] ?? "white", level)}]` : "";
|
|
4246
|
+
return `[${entry?.timestamp ?? event.timestamp}] ${request.method} ${request.url} (${request.status_code})${levelPart}${msgPart}`;
|
|
4247
|
+
};
|
|
4121
4248
|
var formatLogEvent = (event, format) => {
|
|
4122
|
-
const {
|
|
4249
|
+
const { logs: logEntries, exceptions } = event;
|
|
4250
|
+
if (format === "request" && logEntries.length === 0) {
|
|
4251
|
+
consola.log(formatRequestLine(event));
|
|
4252
|
+
}
|
|
4123
4253
|
logEntries.forEach((entry) => {
|
|
4124
4254
|
const msg = formatMessages(entry.messages);
|
|
4125
4255
|
const level = entry.level.toUpperCase();
|
|
@@ -4129,9 +4259,7 @@ var formatLogEvent = (event, format) => {
|
|
|
4129
4259
|
consola.log(msg);
|
|
4130
4260
|
break;
|
|
4131
4261
|
case "request":
|
|
4132
|
-
consola.log(
|
|
4133
|
-
`[${entry.timestamp}] [${coloredLevel}] ${request.method} ${request.url} (${request.status_code}) ${msg}`
|
|
4134
|
-
);
|
|
4262
|
+
consola.log(formatRequestLine(event, entry));
|
|
4135
4263
|
break;
|
|
4136
4264
|
default:
|
|
4137
4265
|
consola.log(`[${entry.timestamp}] [${coloredLevel}] ${msg}`);
|
|
@@ -4267,6 +4395,19 @@ var tailLogs = async (projectUuid, storeHash, accessToken, apiHost, format, conn
|
|
|
4267
4395
|
var tail = new Command9("tail").configureHelp({ showGlobalOptions: true }).description("Tail live logs from your deployed application.").addHelpText(
|
|
4268
4396
|
"after",
|
|
4269
4397
|
`
|
|
4398
|
+
Formats:
|
|
4399
|
+
default One line per log message: timestamp, level, and message.
|
|
4400
|
+
short Message text only.
|
|
4401
|
+
request One line per log message: timestamp, request method, URL, status
|
|
4402
|
+
code, level, and message. Requests that logged no messages are
|
|
4403
|
+
printed too, without the level and message.
|
|
4404
|
+
pretty Indented JSON of the whole event.
|
|
4405
|
+
json Raw JSON, one event per line (useful for piping to other tools).
|
|
4406
|
+
|
|
4407
|
+
The \`default\` and \`short\` formats only print requests that produced a log
|
|
4408
|
+
message. Use \`--format request\` (or \`json\`/\`pretty\`) to see every request,
|
|
4409
|
+
including ones with no message body.
|
|
4410
|
+
|
|
4270
4411
|
Examples:
|
|
4271
4412
|
$ catalyst logs tail
|
|
4272
4413
|
|
|
@@ -4282,7 +4423,7 @@ Examples:
|
|
|
4282
4423
|
const config2 = getProjectConfig();
|
|
4283
4424
|
const apiHost = resolveApiHost(options, config2);
|
|
4284
4425
|
const { storeHash, accessToken } = resolveCredentials(options, config2);
|
|
4285
|
-
await
|
|
4426
|
+
await getTelemetry().identify(storeHash);
|
|
4286
4427
|
const projectUuid = resolveProjectUuid(options);
|
|
4287
4428
|
await tailLogs(projectUuid, storeHash, accessToken, apiHost, options.format);
|
|
4288
4429
|
} catch (error) {
|
|
@@ -4297,17 +4438,74 @@ var parseIntInRange = (flag, min, max) => (value) => {
|
|
|
4297
4438
|
}
|
|
4298
4439
|
return parsed;
|
|
4299
4440
|
};
|
|
4441
|
+
function invocationPrefix() {
|
|
4442
|
+
const packageManager = process.env.npm_config_user_agent?.split("/")[0];
|
|
4443
|
+
switch (packageManager) {
|
|
4444
|
+
case "pnpm":
|
|
4445
|
+
case "yarn":
|
|
4446
|
+
return `${packageManager} catalyst`;
|
|
4447
|
+
case "bun":
|
|
4448
|
+
return "bunx catalyst";
|
|
4449
|
+
case "npm":
|
|
4450
|
+
return "npx catalyst";
|
|
4451
|
+
default:
|
|
4452
|
+
return "catalyst";
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
function printPaginationHints(pagination, start2, end, options) {
|
|
4456
|
+
const hasNextPage = Boolean(pagination?.links?.next) || pagination?.has_next_page === true;
|
|
4457
|
+
const hasPrevPage = Boolean(pagination?.links?.previous) || pagination?.has_prev_page === true;
|
|
4458
|
+
const endCursor = pagination?.end_cursor;
|
|
4459
|
+
const startCursor = pagination?.start_cursor;
|
|
4460
|
+
if (!(hasNextPage && endCursor) && !(hasPrevPage && startCursor)) return;
|
|
4461
|
+
const quoteArg = (value) => /\s/.test(value) ? `'${value}'` : value;
|
|
4462
|
+
const baseFlags = [
|
|
4463
|
+
`--start ${quoteArg(start2)}`,
|
|
4464
|
+
`--end ${quoteArg(end)}`,
|
|
4465
|
+
...options.method ? [`--method ${quoteArg(options.method)}`] : [],
|
|
4466
|
+
...options.statusCode != null ? [`--status-code ${options.statusCode}`] : [],
|
|
4467
|
+
...options.urlLike ? [`--url-like ${quoteArg(options.urlLike)}`] : [],
|
|
4468
|
+
...options.levelMin ? [`--level-min ${options.levelMin}`] : [],
|
|
4469
|
+
...options.limit != null ? [`--limit ${options.limit}`] : [],
|
|
4470
|
+
// The entry_type filter derives from --format (default/short request only
|
|
4471
|
+
// application logs), so echoing --format is enough to reproduce it.
|
|
4472
|
+
...options.format !== "default" ? [`--format ${options.format}`] : []
|
|
4473
|
+
];
|
|
4474
|
+
const command = `${invocationPrefix()} logs query ${baseFlags.join(" ")}`;
|
|
4475
|
+
if (hasNextPage && endCursor) {
|
|
4476
|
+
consola.info(`More results available. Next page:
|
|
4477
|
+
${command} --after ${quoteArg(endCursor)}`);
|
|
4478
|
+
}
|
|
4479
|
+
if (hasPrevPage && startCursor) {
|
|
4480
|
+
consola.info(
|
|
4481
|
+
`Newer results available. Previous page:
|
|
4482
|
+
${command} --before ${quoteArg(startCursor)}`
|
|
4483
|
+
);
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4300
4486
|
var query = new Command9("query").configureHelp({ showGlobalOptions: true }).description("Query historical logs from your deployed application.").addHelpText(
|
|
4301
4487
|
"after",
|
|
4302
4488
|
`
|
|
4303
4489
|
Specify a time window with \`--since\` (relative to now) or \`--start\`/\`--end\`
|
|
4304
4490
|
(ISO-8601 timestamps or Unix epoch seconds, UTC). The window may not exceed
|
|
4305
|
-
7 days. Entries print oldest-first; timestamps are UTC.
|
|
4491
|
+
7 days. Entries print oldest-first; timestamps are UTC. Page toward older
|
|
4492
|
+
entries by passing a previous page's end cursor to \`--after\` (the CLI prints
|
|
4493
|
+
a ready-to-run command when more entries are available), or toward newer
|
|
4494
|
+
entries with \`--before\`. Cursors are only valid with the same window and
|
|
4495
|
+
filters they came from. With \`--format json\`, the pagination cursors are
|
|
4496
|
+
emitted as a final \`{"meta": ...}\` line after the entries.
|
|
4497
|
+
|
|
4498
|
+
The \`default\` and \`short\` formats show only application log output,
|
|
4499
|
+
excluding Cloudflare's auto-generated per-request rows. Use
|
|
4500
|
+
\`--format request\` (or \`json\`/\`pretty\`) to include them.
|
|
4306
4501
|
|
|
4307
4502
|
Examples:
|
|
4308
4503
|
# Last hour of logs
|
|
4309
4504
|
$ catalyst logs query --since 1h
|
|
4310
4505
|
|
|
4506
|
+
# Newest 20 errors in the window (follow the printed --after hint for more)
|
|
4507
|
+
$ catalyst logs query --since 24h --level-min error --limit 20
|
|
4508
|
+
|
|
4311
4509
|
# Everything from today (UTC)
|
|
4312
4510
|
$ catalyst logs query --start 2026-06-11T00:00:00Z
|
|
4313
4511
|
|
|
@@ -4334,7 +4532,20 @@ Examples:
|
|
|
4334
4532
|
).option("--url-like <substring>", "Filter by URL substring (case-sensitive).").addOption(
|
|
4335
4533
|
new Option8("--level-min <level>", "Minimum log level.").choices(Array.from(LOG_LEVELS))
|
|
4336
4534
|
).addOption(
|
|
4337
|
-
new Option8(
|
|
4535
|
+
new Option8(
|
|
4536
|
+
"--limit <count>",
|
|
4537
|
+
"Maximum entries per page (1-500). Defaults to the API default (100)."
|
|
4538
|
+
).argParser(parseIntInRange("--limit", 1, 500))
|
|
4539
|
+
).addOption(
|
|
4540
|
+
new Option8(
|
|
4541
|
+
"--after <cursor>",
|
|
4542
|
+
"Return the page after (older than) this cursor, from a previous page's end_cursor."
|
|
4543
|
+
).conflicts("before")
|
|
4544
|
+
).addOption(
|
|
4545
|
+
new Option8(
|
|
4546
|
+
"--before <cursor>",
|
|
4547
|
+
"Return the page before (newer than) this cursor, from a previous page's start_cursor."
|
|
4548
|
+
)
|
|
4338
4549
|
).addOption(
|
|
4339
4550
|
new Option8("--format <format>", "Output format for log entries.").choices(["json", "pretty", "default", "short", "request"]).default("default")
|
|
4340
4551
|
).action(async (options) => {
|
|
@@ -4342,23 +4553,34 @@ Examples:
|
|
|
4342
4553
|
const config2 = getProjectConfig();
|
|
4343
4554
|
const apiHost = resolveApiHost(options, config2);
|
|
4344
4555
|
const { storeHash, accessToken } = resolveCredentials(options, config2);
|
|
4345
|
-
await
|
|
4556
|
+
await getTelemetry().identify(storeHash);
|
|
4346
4557
|
const projectUuid = resolveProjectUuid(options);
|
|
4347
4558
|
const { start: start2, end } = resolveTimeWindow(options);
|
|
4559
|
+
const hideRequestRows = options.format === "default" || options.format === "short";
|
|
4348
4560
|
const result = await queryLogs(projectUuid, storeHash, accessToken, apiHost, {
|
|
4349
4561
|
start: start2,
|
|
4350
4562
|
end,
|
|
4563
|
+
entryType: hideRequestRows ? "log" : void 0,
|
|
4351
4564
|
method: options.method,
|
|
4352
4565
|
statusCode: options.statusCode,
|
|
4353
4566
|
urlLike: options.urlLike,
|
|
4354
4567
|
levelMin: options.levelMin,
|
|
4355
|
-
limit: options.limit
|
|
4568
|
+
limit: options.limit,
|
|
4569
|
+
after: options.after,
|
|
4570
|
+
before: options.before
|
|
4356
4571
|
});
|
|
4357
4572
|
const entries = result.data;
|
|
4358
4573
|
const ordered = [...entries].reverse();
|
|
4359
4574
|
if (options.format === "json") {
|
|
4360
4575
|
ordered.forEach((entry) => process.stdout.write(`${JSON.stringify(entry)}
|
|
4361
4576
|
`));
|
|
4577
|
+
const cursorPagination = result.meta?.cursor_pagination;
|
|
4578
|
+
if (cursorPagination) {
|
|
4579
|
+
process.stdout.write(
|
|
4580
|
+
`${JSON.stringify({ meta: { cursor_pagination: cursorPagination } })}
|
|
4581
|
+
`
|
|
4582
|
+
);
|
|
4583
|
+
}
|
|
4362
4584
|
return;
|
|
4363
4585
|
}
|
|
4364
4586
|
if (options.format === "pretty") {
|
|
@@ -4370,23 +4592,22 @@ Examples:
|
|
|
4370
4592
|
return;
|
|
4371
4593
|
}
|
|
4372
4594
|
const lineFormat = options.format;
|
|
4373
|
-
ordered.
|
|
4595
|
+
const visible = hideRequestRows ? ordered.filter((entry) => !isRequestLogEntry(entry)) : ordered;
|
|
4596
|
+
const hiddenCount = ordered.length - visible.length;
|
|
4597
|
+
visible.forEach((entry) => consola.log(formatLogEntry(entry, lineFormat)));
|
|
4598
|
+
const shownPart = `${visible.length} ${visible.length === 1 ? "entry" : "entries"} shown`;
|
|
4374
4599
|
consola.info(
|
|
4375
|
-
`${
|
|
4600
|
+
hiddenCount > 0 ? `${shownPart}, ${hiddenCount} request ${hiddenCount === 1 ? "row" : "rows"} hidden (oldest first, times in UTC). Use --format request to see request rows.` : `${shownPart} (oldest first, times in UTC).`
|
|
4376
4601
|
);
|
|
4377
|
-
|
|
4378
|
-
consola.info(
|
|
4379
|
-
`Limit of ${options.limit} reached; older entries may exist. Narrow the time window or raise --limit (max 500) to see more.`
|
|
4380
|
-
);
|
|
4381
|
-
}
|
|
4602
|
+
printPaginationHints(result.meta?.cursor_pagination, start2, end, options);
|
|
4382
4603
|
} catch (error) {
|
|
4383
4604
|
consola.error(error instanceof Error ? error.message : error);
|
|
4384
4605
|
process.exit(1);
|
|
4385
4606
|
}
|
|
4386
4607
|
});
|
|
4387
|
-
var logs = new Command9("logs").configureHelp({ showGlobalOptions: true }).description("View logs from your deployed application.").addCommand(tail, { isDefault: true }).addCommand(query);
|
|
4608
|
+
var logs = new Command9("logs").alias("log").configureHelp({ showGlobalOptions: true }).description("View logs from your deployed application.").addCommand(tail, { isDefault: true }).addCommand(query);
|
|
4388
4609
|
|
|
4389
|
-
// src/cli/commands/
|
|
4610
|
+
// src/cli/commands/projects.ts
|
|
4390
4611
|
import { confirm as confirm5, input as input5, select as select7 } from "@inquirer/prompts";
|
|
4391
4612
|
import { Command as Command10 } from "commander";
|
|
4392
4613
|
import { colorize as colorize11 } from "consola/utils";
|
|
@@ -4415,22 +4636,22 @@ var list3 = new Command10("list").configureHelp({ showGlobalOptions: true }).des
|
|
|
4415
4636
|
"after",
|
|
4416
4637
|
`
|
|
4417
4638
|
Example:
|
|
4418
|
-
$ catalyst
|
|
4639
|
+
$ catalyst projects list`
|
|
4419
4640
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).action(async (options) => {
|
|
4420
4641
|
const config2 = getProjectConfig();
|
|
4421
4642
|
const apiHost = resolveApiHost(options, config2);
|
|
4422
4643
|
const { storeHash, accessToken } = resolveCredentials(options, config2);
|
|
4423
4644
|
await getTelemetry().identify(storeHash);
|
|
4424
4645
|
consola.start("Fetching projects...");
|
|
4425
|
-
const
|
|
4646
|
+
const storeProjects = await fetchProjects(storeHash, accessToken, apiHost);
|
|
4426
4647
|
consola.success("Projects fetched.");
|
|
4427
|
-
if (
|
|
4648
|
+
if (storeProjects.length === 0) {
|
|
4428
4649
|
consola.info("No projects found.");
|
|
4429
4650
|
process.exit(0);
|
|
4430
4651
|
return;
|
|
4431
4652
|
}
|
|
4432
4653
|
const linkedProjectUuid = config2.get("projectUuid");
|
|
4433
|
-
const projectList =
|
|
4654
|
+
const projectList = storeProjects.map((p) => {
|
|
4434
4655
|
const marker = p.uuid === linkedProjectUuid ? ` ${colorize11("green", "[linked]")}` : "";
|
|
4435
4656
|
const hostnames = p.deployment_hostnames.length === 0 ? [" (not deployed)"] : p.deployment_hostnames.map(
|
|
4436
4657
|
(hostname) => ` ${colorize11("blue", `https://${hostname}`)}`
|
|
@@ -4446,7 +4667,7 @@ var create3 = new Command10("create").configureHelp({ showGlobalOptions: true })
|
|
|
4446
4667
|
"after",
|
|
4447
4668
|
`
|
|
4448
4669
|
Example:
|
|
4449
|
-
$ catalyst
|
|
4670
|
+
$ catalyst projects create`
|
|
4450
4671
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(loginUrlOption()).action(async (options) => {
|
|
4451
4672
|
const config2 = getProjectConfig();
|
|
4452
4673
|
const apiHost = resolveApiHost(options, config2);
|
|
@@ -4466,7 +4687,7 @@ Example:
|
|
|
4466
4687
|
} catch (error) {
|
|
4467
4688
|
if (error instanceof LoginAbortedError) {
|
|
4468
4689
|
consola.info(
|
|
4469
|
-
"Login aborted. Re-run `catalyst
|
|
4690
|
+
"Login aborted. Re-run `catalyst projects create` when you have your credentials ready."
|
|
4470
4691
|
);
|
|
4471
4692
|
process.exit(0);
|
|
4472
4693
|
return;
|
|
@@ -4492,10 +4713,10 @@ var link2 = new Command10("link").configureHelp({ showGlobalOptions: true }).des
|
|
|
4492
4713
|
`
|
|
4493
4714
|
Examples:
|
|
4494
4715
|
# Link interactively (prompts to select or create)
|
|
4495
|
-
$ catalyst
|
|
4716
|
+
$ catalyst projects link
|
|
4496
4717
|
|
|
4497
4718
|
# Link using a project UUID directly
|
|
4498
|
-
$ catalyst
|
|
4719
|
+
$ catalyst projects link --project-uuid <UUID>`
|
|
4499
4720
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(projectUuidOption()).action(async (options) => {
|
|
4500
4721
|
const config2 = getProjectConfig();
|
|
4501
4722
|
const apiHost = resolveApiHost(options, config2);
|
|
@@ -4525,7 +4746,7 @@ Examples:
|
|
|
4525
4746
|
} catch (error) {
|
|
4526
4747
|
if (error instanceof NoLinkedProjectError) {
|
|
4527
4748
|
consola.info(
|
|
4528
|
-
"When you're ready to create a project, run `catalyst
|
|
4749
|
+
"When you're ready to create a project, run `catalyst projects create` or re-run `catalyst projects link`."
|
|
4529
4750
|
);
|
|
4530
4751
|
process.exit(0);
|
|
4531
4752
|
throw error;
|
|
@@ -4543,13 +4764,13 @@ var del = new Command10("delete").configureHelp({ showGlobalOptions: true }).des
|
|
|
4543
4764
|
`
|
|
4544
4765
|
Examples:
|
|
4545
4766
|
# Select a project to delete interactively
|
|
4546
|
-
$ catalyst
|
|
4767
|
+
$ catalyst projects delete
|
|
4547
4768
|
|
|
4548
4769
|
# Delete a specific project (still prompts for confirmation)
|
|
4549
|
-
$ catalyst
|
|
4770
|
+
$ catalyst projects delete --project-uuid <UUID>
|
|
4550
4771
|
|
|
4551
4772
|
# Skip the confirmation prompt
|
|
4552
|
-
$ catalyst
|
|
4773
|
+
$ catalyst projects delete --project-uuid <UUID> --force`
|
|
4553
4774
|
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(projectUuidOption()).option("--force", "Skip the confirmation prompt before deleting.").action(async (options) => {
|
|
4554
4775
|
const config2 = getProjectConfig();
|
|
4555
4776
|
const apiHost = resolveApiHost(options, config2);
|
|
@@ -4559,9 +4780,9 @@ Examples:
|
|
|
4559
4780
|
let targetName;
|
|
4560
4781
|
if (!targetUuid) {
|
|
4561
4782
|
consola.start("Fetching projects...");
|
|
4562
|
-
const
|
|
4783
|
+
const storeProjects = await fetchProjects(storeHash, accessToken, apiHost);
|
|
4563
4784
|
consola.success("Projects fetched.");
|
|
4564
|
-
if (
|
|
4785
|
+
if (storeProjects.length === 0) {
|
|
4565
4786
|
consola.info("No projects found.");
|
|
4566
4787
|
process.exit(0);
|
|
4567
4788
|
return;
|
|
@@ -4570,7 +4791,7 @@ Examples:
|
|
|
4570
4791
|
const selected = await select7({
|
|
4571
4792
|
message: "Select a project to delete (Press <enter> to select).",
|
|
4572
4793
|
choices: [
|
|
4573
|
-
...
|
|
4794
|
+
...storeProjects.map((p) => ({
|
|
4574
4795
|
name: p.uuid === linkedProjectUuid ? `${p.name} ${colorize11("green", "[linked]")}` : p.name,
|
|
4575
4796
|
value: p.uuid,
|
|
4576
4797
|
description: p.uuid
|
|
@@ -4583,7 +4804,7 @@ Examples:
|
|
|
4583
4804
|
process.exit(0);
|
|
4584
4805
|
return;
|
|
4585
4806
|
}
|
|
4586
|
-
const matched =
|
|
4807
|
+
const matched = storeProjects.find((p) => p.uuid === selected);
|
|
4587
4808
|
if (!matched) {
|
|
4588
4809
|
throw new Error(`Selected project ${String(selected)} not found in fetched list.`);
|
|
4589
4810
|
}
|
|
@@ -4611,13 +4832,13 @@ Examples:
|
|
|
4611
4832
|
}
|
|
4612
4833
|
process.exit(0);
|
|
4613
4834
|
});
|
|
4614
|
-
var
|
|
4835
|
+
var projects = new Command10("projects").alias("project").configureHelp({ showGlobalOptions: true }).description("Manage your BigCommerce infrastructure projects.").addCommand(create3).addCommand(list3).addCommand(link2).addCommand(del);
|
|
4615
4836
|
|
|
4616
4837
|
// src/cli/commands/start.ts
|
|
4617
4838
|
import { Command as Command11 } from "commander";
|
|
4618
4839
|
import { execa as execa3 } from "execa";
|
|
4619
4840
|
import { existsSync as existsSync6, lstatSync, symlinkSync } from "fs";
|
|
4620
|
-
import { join as
|
|
4841
|
+
import { join as join14, relative } from "path";
|
|
4621
4842
|
var start = new Command11("start").configureHelp({ showGlobalOptions: true }).description(
|
|
4622
4843
|
"Start a local preview of your Catalyst storefront using the OpenNext Cloudflare adapter."
|
|
4623
4844
|
).addHelpText(
|
|
@@ -4635,11 +4856,11 @@ Example:
|
|
|
4635
4856
|
});
|
|
4636
4857
|
return;
|
|
4637
4858
|
}
|
|
4638
|
-
const envLocal =
|
|
4639
|
-
const devVars =
|
|
4859
|
+
const envLocal = join14(process.cwd(), ".env.local");
|
|
4860
|
+
const devVars = join14(process.cwd(), ".bigcommerce", ".dev.vars");
|
|
4640
4861
|
if (existsSync6(envLocal)) {
|
|
4641
4862
|
if (!existsSync6(devVars)) {
|
|
4642
|
-
const target = relative(
|
|
4863
|
+
const target = relative(join14(process.cwd(), ".bigcommerce"), envLocal);
|
|
4643
4864
|
symlinkSync(target, devVars);
|
|
4644
4865
|
consola.success("Symlinked .bigcommerce/.dev.vars \u2192 .env.local");
|
|
4645
4866
|
} else if (!lstatSync(devVars).isSymbolicLink()) {
|
|
@@ -4659,7 +4880,7 @@ Example:
|
|
|
4659
4880
|
"opennextjs-cloudflare",
|
|
4660
4881
|
"preview",
|
|
4661
4882
|
"--config",
|
|
4662
|
-
|
|
4883
|
+
join14(".bigcommerce", "wrangler.jsonc")
|
|
4663
4884
|
],
|
|
4664
4885
|
{
|
|
4665
4886
|
stdio: "inherit",
|
|
@@ -4673,7 +4894,7 @@ import { Argument, Command as Command12, Option as Option9 } from "commander";
|
|
|
4673
4894
|
import { colorize as colorize12 } from "consola/utils";
|
|
4674
4895
|
var telemetryService = getTelemetry();
|
|
4675
4896
|
var isEnabled = telemetryService.isEnabled();
|
|
4676
|
-
var
|
|
4897
|
+
var telemetry = new Command12("telemetry").configureHelp({ showGlobalOptions: true }).description(
|
|
4677
4898
|
"View or change CLI telemetry collection status. Enabling telemetry helps BigCommerce support diagnose and troubleshoot errors you encounter when using the CLI."
|
|
4678
4899
|
).addHelpText(
|
|
4679
4900
|
"after",
|
|
@@ -4718,7 +4939,7 @@ import { Command as Command13, Option as Option10 } from "@commander-js/extra-ty
|
|
|
4718
4939
|
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
4719
4940
|
import { execa as execa4 } from "execa";
|
|
4720
4941
|
import {
|
|
4721
|
-
access as
|
|
4942
|
+
access as access3,
|
|
4722
4943
|
copyFile as copyFile2,
|
|
4723
4944
|
cp as cp2,
|
|
4724
4945
|
mkdir,
|
|
@@ -4730,7 +4951,8 @@ import {
|
|
|
4730
4951
|
writeFile as writeFile2
|
|
4731
4952
|
} from "fs/promises";
|
|
4732
4953
|
import { homedir, tmpdir } from "os";
|
|
4733
|
-
import { dirname as dirname5, join as
|
|
4954
|
+
import { dirname as dirname5, join as join15, relative as relative2 } from "path";
|
|
4955
|
+
import { minVersion, satisfies, lt as semverLt, validRange, valid as validSemver2 } from "semver";
|
|
4734
4956
|
import yoctoSpinner4 from "yocto-spinner";
|
|
4735
4957
|
import { z as z17 } from "zod";
|
|
4736
4958
|
var CorePackageJson = z17.object({
|
|
@@ -4738,6 +4960,20 @@ var CorePackageJson = z17.object({
|
|
|
4738
4960
|
version: z17.string(),
|
|
4739
4961
|
catalyst: z17.object({ version: z17.string(), ref: z17.string() }).optional()
|
|
4740
4962
|
});
|
|
4963
|
+
var DEP_FIELDS2 = [
|
|
4964
|
+
"dependencies",
|
|
4965
|
+
"devDependencies",
|
|
4966
|
+
"optionalDependencies",
|
|
4967
|
+
"peerDependencies"
|
|
4968
|
+
];
|
|
4969
|
+
var DepsPackageJson = z17.looseObject({
|
|
4970
|
+
dependencies: z17.record(z17.string(), z17.string()).optional(),
|
|
4971
|
+
devDependencies: z17.record(z17.string(), z17.string()).optional(),
|
|
4972
|
+
optionalDependencies: z17.record(z17.string(), z17.string()).optional(),
|
|
4973
|
+
peerDependencies: z17.record(z17.string(), z17.string()).optional()
|
|
4974
|
+
});
|
|
4975
|
+
var WorkspacePackageJson = z17.object({ name: z17.string(), version: z17.string() });
|
|
4976
|
+
var CATALYST_CLI_PACKAGE = "@bigcommerce/catalyst";
|
|
4741
4977
|
var DEFAULT_REPOSITORY = "bigcommerce/catalyst";
|
|
4742
4978
|
var MOVING_TAGS = /* @__PURE__ */ new Set(["latest", "canary", "alpha"]);
|
|
4743
4979
|
var KNOWN_FAMILIES = /* @__PURE__ */ new Set([
|
|
@@ -4746,14 +4982,14 @@ var KNOWN_FAMILIES = /* @__PURE__ */ new Set([
|
|
|
4746
4982
|
"@bigcommerce/catalyst-b2b-makeswift",
|
|
4747
4983
|
"@bigcommerce/catalyst-b2b"
|
|
4748
4984
|
]);
|
|
4749
|
-
var CACHE_DIR =
|
|
4750
|
-
var pathExists = (p) =>
|
|
4985
|
+
var CACHE_DIR = join15(homedir(), ".cache", "catalyst-cli", "cores");
|
|
4986
|
+
var pathExists = (p) => access3(p).then(() => true).catch(() => false);
|
|
4751
4987
|
async function listFiles(dir, prefix = "") {
|
|
4752
4988
|
const entries = await readdir2(dir, { withFileTypes: true }).catch(() => []);
|
|
4753
4989
|
const nested = await Promise.all(
|
|
4754
4990
|
entries.map((entry) => {
|
|
4755
4991
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
4756
|
-
return entry.isDirectory() ? listFiles(
|
|
4992
|
+
return entry.isDirectory() ? listFiles(join15(dir, entry.name), rel) : Promise.resolve([rel]);
|
|
4757
4993
|
})
|
|
4758
4994
|
);
|
|
4759
4995
|
return nested.flat();
|
|
@@ -4769,7 +5005,7 @@ async function computeBaseSimilarity(baseDir, destDir) {
|
|
|
4769
5005
|
const baseFiles = await listFiles(baseDir);
|
|
4770
5006
|
if (baseFiles.length === 0) return 0;
|
|
4771
5007
|
const matches = await Promise.all(
|
|
4772
|
-
baseFiles.map((rel) => filesEqual(
|
|
5008
|
+
baseFiles.map((rel) => filesEqual(join15(baseDir, rel), join15(destDir, rel)))
|
|
4773
5009
|
);
|
|
4774
5010
|
return matches.filter(Boolean).length / baseFiles.length;
|
|
4775
5011
|
}
|
|
@@ -4788,10 +5024,79 @@ function parseRef(ref) {
|
|
|
4788
5024
|
return { packageName: ref.slice(0, lastAt), version: ref.slice(lastAt + 1) };
|
|
4789
5025
|
}
|
|
4790
5026
|
async function readResolvedVersion(coreDir) {
|
|
4791
|
-
const raw = await readFile2(
|
|
5027
|
+
const raw = await readFile2(join15(coreDir, "package.json"), "utf-8");
|
|
4792
5028
|
const pkg = CorePackageJson.parse(JSON.parse(raw));
|
|
4793
5029
|
return pkg.catalyst?.version ?? pkg.version;
|
|
4794
5030
|
}
|
|
5031
|
+
var readDepSpecifiers = (raw) => {
|
|
5032
|
+
let parsed;
|
|
5033
|
+
try {
|
|
5034
|
+
parsed = DepsPackageJson.parse(JSON.parse(raw));
|
|
5035
|
+
} catch {
|
|
5036
|
+
return {};
|
|
5037
|
+
}
|
|
5038
|
+
return Object.fromEntries(DEP_FIELDS2.flatMap((field) => Object.entries(parsed[field] ?? {})));
|
|
5039
|
+
};
|
|
5040
|
+
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5041
|
+
var rewriteWorkspaceSpecifier = (raw, name, version2) => raw.replace(
|
|
5042
|
+
new RegExp(`("${escapeRegExp(name)}"\\s*:\\s*)"workspace:[^"]*"`, "g"),
|
|
5043
|
+
(_match, key) => `${key}"^${version2}"`
|
|
5044
|
+
);
|
|
5045
|
+
async function normalizeWorkspaceDeps(ourPkgRaw, baseDir, theirsDir, baseVersions, targetVersions) {
|
|
5046
|
+
const basePath = join15(baseDir, "package.json");
|
|
5047
|
+
const theirsPath = join15(theirsDir, "package.json");
|
|
5048
|
+
const [originalBase, originalTheirs] = await Promise.all([
|
|
5049
|
+
readFile2(basePath, "utf-8").catch(() => null),
|
|
5050
|
+
readFile2(theirsPath, "utf-8").catch(() => null)
|
|
5051
|
+
]);
|
|
5052
|
+
if (originalBase === null || originalTheirs === null) return { workspace: [], bumped: [] };
|
|
5053
|
+
const ourSpecifiers = readDepSpecifiers(ourPkgRaw);
|
|
5054
|
+
const names = new Set(
|
|
5055
|
+
[
|
|
5056
|
+
...Object.entries(readDepSpecifiers(originalBase)),
|
|
5057
|
+
...Object.entries(readDepSpecifiers(originalTheirs))
|
|
5058
|
+
].filter(([, range]) => range?.startsWith("workspace:")).map(([name]) => name)
|
|
5059
|
+
);
|
|
5060
|
+
const decisions = [...names].map((name) => ({
|
|
5061
|
+
name,
|
|
5062
|
+
ours: ourSpecifiers[name],
|
|
5063
|
+
baseVersion: baseVersions[name],
|
|
5064
|
+
targetVersion: targetVersions[name]
|
|
5065
|
+
}));
|
|
5066
|
+
const workspace = decisions.flatMap(
|
|
5067
|
+
({ name, ours, targetVersion }) => ours?.startsWith("workspace:") && targetVersion !== void 0 ? [{ name, ours, version: targetVersion }] : []
|
|
5068
|
+
);
|
|
5069
|
+
const normalizable = decisions.filter(({ ours }) => !ours?.startsWith("workspace:"));
|
|
5070
|
+
const baseRaw = normalizable.reduce(
|
|
5071
|
+
(acc, { name, baseVersion }) => baseVersion === void 0 ? acc : rewriteWorkspaceSpecifier(acc, name, baseVersion),
|
|
5072
|
+
originalBase
|
|
5073
|
+
);
|
|
5074
|
+
const theirsRaw = normalizable.reduce(
|
|
5075
|
+
(acc, { name, targetVersion }) => targetVersion === void 0 ? acc : rewriteWorkspaceSpecifier(acc, name, targetVersion),
|
|
5076
|
+
originalTheirs
|
|
5077
|
+
);
|
|
5078
|
+
const bumped = normalizable.filter(
|
|
5079
|
+
({ baseVersion, targetVersion }) => baseVersion !== void 0 && targetVersion !== void 0 && baseVersion !== targetVersion
|
|
5080
|
+
).map(({ name }) => name);
|
|
5081
|
+
await Promise.all([
|
|
5082
|
+
baseRaw === originalBase ? null : writeFile2(basePath, baseRaw),
|
|
5083
|
+
theirsRaw === originalTheirs ? null : writeFile2(theirsPath, theirsRaw)
|
|
5084
|
+
]);
|
|
5085
|
+
return { workspace, bumped };
|
|
5086
|
+
}
|
|
5087
|
+
var migrateWorkspaceDeps = (raw, findings) => findings.reduce((acc, { name, version: version2 }) => rewriteWorkspaceSpecifier(acc, name, version2), raw);
|
|
5088
|
+
async function findStaleCli(pkgRaw) {
|
|
5089
|
+
const range = readDepSpecifiers(pkgRaw)[CATALYST_CLI_PACKAGE];
|
|
5090
|
+
if (range === void 0 || !validRange(range)) return null;
|
|
5091
|
+
const body = await fetch(`https://registry.npmjs.org/${CATALYST_CLI_PACKAGE}/latest`, {
|
|
5092
|
+
// A hanging registry would otherwise stall the CLI indefinitely.
|
|
5093
|
+
signal: AbortSignal.timeout(5e3)
|
|
5094
|
+
}).then((res) => res.ok ? res.json() : null).catch(() => null);
|
|
5095
|
+
const latest = z17.object({ version: z17.string() }).safeParse(body).data?.version;
|
|
5096
|
+
if (latest === void 0 || !validSemver2(latest) || satisfies(latest, range)) return null;
|
|
5097
|
+
const current = minVersion(range)?.version;
|
|
5098
|
+
return current !== void 0 && semverLt(current, latest) ? { current, latest } : null;
|
|
5099
|
+
}
|
|
4795
5100
|
async function mergeFile(oursPath, basePath, theirsPath) {
|
|
4796
5101
|
const merged = await execa4(
|
|
4797
5102
|
"git",
|
|
@@ -4815,9 +5120,9 @@ async function mergeFile(oursPath, basePath, theirsPath) {
|
|
|
4815
5120
|
return (merged.exitCode ?? 0) > 0;
|
|
4816
5121
|
}
|
|
4817
5122
|
async function mergeModified(rel, baseDir, theirsDir, catalystRoot) {
|
|
4818
|
-
const basePath =
|
|
4819
|
-
const theirsPath =
|
|
4820
|
-
const oursPath =
|
|
5123
|
+
const basePath = join15(baseDir, rel);
|
|
5124
|
+
const theirsPath = join15(theirsDir, rel);
|
|
5125
|
+
const oursPath = join15(catalystRoot, rel);
|
|
4821
5126
|
if (await filesEqual(basePath, theirsPath)) return null;
|
|
4822
5127
|
if (!await pathExists(oursPath)) {
|
|
4823
5128
|
await copyInto(theirsPath, oursPath);
|
|
@@ -4833,8 +5138,8 @@ async function mergeModified(rel, baseDir, theirsDir, catalystRoot) {
|
|
|
4833
5138
|
return await mergeFile(oursPath, basePath, theirsPath) ? "conflicted" : "applied";
|
|
4834
5139
|
}
|
|
4835
5140
|
async function mergeAdded(rel, theirsDir, catalystRoot, emptyFile) {
|
|
4836
|
-
const theirsPath =
|
|
4837
|
-
const oursPath =
|
|
5141
|
+
const theirsPath = join15(theirsDir, rel);
|
|
5142
|
+
const oursPath = join15(catalystRoot, rel);
|
|
4838
5143
|
if (!await pathExists(oursPath)) {
|
|
4839
5144
|
await copyInto(theirsPath, oursPath);
|
|
4840
5145
|
return "added";
|
|
@@ -4845,8 +5150,8 @@ async function mergeAdded(rel, theirsDir, catalystRoot, emptyFile) {
|
|
|
4845
5150
|
return hadConflict ? "conflicted" : "applied";
|
|
4846
5151
|
}
|
|
4847
5152
|
async function mergeDeleted(rel, baseDir, catalystRoot) {
|
|
4848
|
-
const basePath =
|
|
4849
|
-
const oursPath =
|
|
5153
|
+
const basePath = join15(baseDir, rel);
|
|
5154
|
+
const oursPath = join15(catalystRoot, rel);
|
|
4850
5155
|
if (!await pathExists(oursPath)) return null;
|
|
4851
5156
|
if (await filesEqual(oursPath, basePath)) {
|
|
4852
5157
|
await rm2(oursPath, { force: true });
|
|
@@ -4892,15 +5197,15 @@ async function resolveStrategy(strategy) {
|
|
|
4892
5197
|
return "per-file";
|
|
4893
5198
|
}
|
|
4894
5199
|
async function mergeCoreTree(baseDir, theirsDir, catalystRoot) {
|
|
4895
|
-
const scratch = await mkdtemp(
|
|
5200
|
+
const scratch = await mkdtemp(join15(tmpdir(), "catalyst-merge-"));
|
|
4896
5201
|
try {
|
|
4897
5202
|
await execa4("git", ["init", "-q", scratch]);
|
|
4898
5203
|
await execa4("git", ["config", "core.autocrlf", "false"], {
|
|
4899
|
-
env: { ...process.env, GIT_DIR:
|
|
5204
|
+
env: { ...process.env, GIT_DIR: join15(scratch, ".git") }
|
|
4900
5205
|
});
|
|
4901
5206
|
const env2 = {
|
|
4902
5207
|
...process.env,
|
|
4903
|
-
GIT_DIR:
|
|
5208
|
+
GIT_DIR: join15(scratch, ".git"),
|
|
4904
5209
|
GIT_AUTHOR_NAME: "catalyst",
|
|
4905
5210
|
GIT_AUTHOR_EMAIL: "catalyst@bigcommerce.com",
|
|
4906
5211
|
GIT_COMMITTER_NAME: "catalyst",
|
|
@@ -4910,7 +5215,7 @@ async function mergeCoreTree(baseDir, theirsDir, catalystRoot) {
|
|
|
4910
5215
|
const sideEnv = {
|
|
4911
5216
|
...env2,
|
|
4912
5217
|
GIT_WORK_TREE: workTree,
|
|
4913
|
-
GIT_INDEX_FILE:
|
|
5218
|
+
GIT_INDEX_FILE: join15(scratch, `index.${tag}`)
|
|
4914
5219
|
};
|
|
4915
5220
|
await execa4("git", ["add", "-A"], { env: sideEnv });
|
|
4916
5221
|
return (await execa4("git", ["write-tree"], { env: sideEnv })).stdout.trim();
|
|
@@ -4954,7 +5259,7 @@ async function mergeCoreTree(baseDir, theirsDir, catalystRoot) {
|
|
|
4954
5259
|
const outEnv = {
|
|
4955
5260
|
...env2,
|
|
4956
5261
|
GIT_WORK_TREE: catalystRoot,
|
|
4957
|
-
GIT_INDEX_FILE:
|
|
5262
|
+
GIT_INDEX_FILE: join15(scratch, "index.out")
|
|
4958
5263
|
};
|
|
4959
5264
|
await execa4("git", ["read-tree", mergedTree], { env: outEnv });
|
|
4960
5265
|
await execa4("git", ["checkout-index", "-a", "-f"], { env: outEnv });
|
|
@@ -4973,7 +5278,7 @@ async function mergeCoreTree(baseDir, theirsDir, catalystRoot) {
|
|
|
4973
5278
|
}
|
|
4974
5279
|
}
|
|
4975
5280
|
const deleted = changes.filter((change) => change.status === "D").map((change) => change.path);
|
|
4976
|
-
await Promise.all(deleted.map((path) => rm2(
|
|
5281
|
+
await Promise.all(deleted.map((path) => rm2(join15(catalystRoot, path), { force: true })));
|
|
4977
5282
|
return {
|
|
4978
5283
|
applied: changes.filter((change) => change.status !== "A" && change.status !== "D").map((change) => change.path),
|
|
4979
5284
|
added: changes.filter((change) => change.status === "A").map((change) => change.path),
|
|
@@ -5016,9 +5321,9 @@ async function applyIndexState(gitRoot, relDir, baseDir, theirsDir, result, stam
|
|
|
5016
5321
|
stillConflicted.map(async (rel) => {
|
|
5017
5322
|
const repoPath = toRepoPath(rel);
|
|
5018
5323
|
const [base, ours, theirs] = await Promise.all([
|
|
5019
|
-
hashBlob(
|
|
5324
|
+
hashBlob(join15(baseDir, rel)),
|
|
5020
5325
|
headEntry(repoPath),
|
|
5021
|
-
hashBlob(
|
|
5326
|
+
hashBlob(join15(theirsDir, rel))
|
|
5022
5327
|
]);
|
|
5023
5328
|
return [
|
|
5024
5329
|
`0 ${NULL_OID} ${repoPath}`,
|
|
@@ -5041,10 +5346,10 @@ async function resolveProject2(cwd) {
|
|
|
5041
5346
|
} catch {
|
|
5042
5347
|
return null;
|
|
5043
5348
|
}
|
|
5044
|
-
const candidateDirs = [.../* @__PURE__ */ new Set([
|
|
5349
|
+
const candidateDirs = [.../* @__PURE__ */ new Set([join15(gitRoot, "core"), gitRoot, join15(cwd, "core"), cwd])];
|
|
5045
5350
|
const parsed = (await Promise.all(
|
|
5046
5351
|
candidateDirs.map(async (dir) => {
|
|
5047
|
-
const pkgPath =
|
|
5352
|
+
const pkgPath = join15(dir, "package.json");
|
|
5048
5353
|
const raw = await readFile2(pkgPath, "utf-8").catch(() => null);
|
|
5049
5354
|
if (!raw) return null;
|
|
5050
5355
|
let pkgJson;
|
|
@@ -5068,13 +5373,44 @@ async function resolveProject2(cwd) {
|
|
|
5068
5373
|
pkg: chosen.pkg
|
|
5069
5374
|
};
|
|
5070
5375
|
}
|
|
5376
|
+
var readWorkspaceVersions = async (repoDir) => {
|
|
5377
|
+
const packagesDir = join15(repoDir, "packages");
|
|
5378
|
+
const entries = await readdir2(packagesDir, { withFileTypes: true }).catch(() => []);
|
|
5379
|
+
const manifests = await Promise.all(
|
|
5380
|
+
entries.filter((entry) => entry.isDirectory()).map(async (entry) => {
|
|
5381
|
+
const raw = await readFile2(join15(packagesDir, entry.name, "package.json"), "utf-8").catch(
|
|
5382
|
+
() => null
|
|
5383
|
+
);
|
|
5384
|
+
if (raw === null) return null;
|
|
5385
|
+
try {
|
|
5386
|
+
return WorkspacePackageJson.parse(JSON.parse(raw));
|
|
5387
|
+
} catch {
|
|
5388
|
+
return null;
|
|
5389
|
+
}
|
|
5390
|
+
})
|
|
5391
|
+
);
|
|
5392
|
+
return Object.fromEntries(
|
|
5393
|
+
manifests.filter((pkg) => pkg !== null).map(({ name, version: version2 }) => [name, version2])
|
|
5394
|
+
);
|
|
5395
|
+
};
|
|
5396
|
+
var readCachedVersions = async (path) => {
|
|
5397
|
+
const raw = await readFile2(path, "utf-8").catch(() => null);
|
|
5398
|
+
if (raw === null) return null;
|
|
5399
|
+
try {
|
|
5400
|
+
return z17.record(z17.string(), z17.string()).parse(JSON.parse(raw));
|
|
5401
|
+
} catch {
|
|
5402
|
+
return null;
|
|
5403
|
+
}
|
|
5404
|
+
};
|
|
5071
5405
|
async function downloadCore(repository, ref, destDir, token) {
|
|
5072
5406
|
const cacheable = !MOVING_TAGS.has(parseRef(ref).version);
|
|
5073
5407
|
const cacheKey = `${repository.replace(/[^a-zA-Z0-9._-]/g, "_")}__${ref.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
5074
|
-
const cachePath =
|
|
5075
|
-
|
|
5408
|
+
const cachePath = join15(CACHE_DIR, cacheKey);
|
|
5409
|
+
const versionsPath = `${cachePath}.versions.json`;
|
|
5410
|
+
const cachedVersions = cacheable && await pathExists(join15(cachePath, "package.json")) ? await readCachedVersions(versionsPath) : null;
|
|
5411
|
+
if (cachedVersions) {
|
|
5076
5412
|
await cp2(cachePath, destDir, { recursive: true });
|
|
5077
|
-
return;
|
|
5413
|
+
return cachedVersions;
|
|
5078
5414
|
}
|
|
5079
5415
|
const url = `https://api.github.com/repos/${repository}/tarball/${encodeURIComponent(ref)}`;
|
|
5080
5416
|
const headers = {
|
|
@@ -5094,22 +5430,24 @@ async function downloadCore(repository, ref, destDir, token) {
|
|
|
5094
5430
|
await writeFile2(tarballPath, Buffer.from(await res.arrayBuffer()));
|
|
5095
5431
|
await mkdir(rawDir, { recursive: true });
|
|
5096
5432
|
await execa4("tar", ["-xzf", tarballPath, "-C", rawDir, "--strip-components=1"]);
|
|
5097
|
-
const coreDir =
|
|
5433
|
+
const coreDir = join15(rawDir, "core");
|
|
5098
5434
|
const sourceDir = await pathExists(coreDir) ? coreDir : rawDir;
|
|
5435
|
+
const workspaceVersions = await readWorkspaceVersions(rawDir);
|
|
5099
5436
|
await rename(sourceDir, destDir);
|
|
5100
5437
|
await rm2(tarballPath, { force: true });
|
|
5101
5438
|
await rm2(rawDir, { recursive: true, force: true });
|
|
5102
5439
|
if (cacheable) {
|
|
5103
5440
|
await mkdir(CACHE_DIR, { recursive: true });
|
|
5104
|
-
await cp2(destDir, cachePath, { recursive: true }).catch(() => {
|
|
5441
|
+
await cp2(destDir, cachePath, { recursive: true }).then(() => writeFile2(versionsPath, JSON.stringify(workspaceVersions))).catch(() => {
|
|
5105
5442
|
});
|
|
5106
5443
|
}
|
|
5444
|
+
return workspaceVersions;
|
|
5107
5445
|
}
|
|
5108
|
-
async function resolveBaseRef(
|
|
5109
|
-
if (
|
|
5446
|
+
async function resolveBaseRef(project, fromOption, assumeYes) {
|
|
5447
|
+
if (project.pkg.catalyst?.ref) return project.pkg.catalyst.ref;
|
|
5110
5448
|
if (fromOption) return fromOption;
|
|
5111
|
-
const family =
|
|
5112
|
-
const guess = `${family}@${
|
|
5449
|
+
const family = project.pkg.name && KNOWN_FAMILIES.has(project.pkg.name) ? project.pkg.name : "@bigcommerce/catalyst-core";
|
|
5450
|
+
const guess = `${family}@${project.pkg.version}`;
|
|
5113
5451
|
consola.warn(`No \`catalyst.ref\` found in package.json. Inferred base: ${guess}`);
|
|
5114
5452
|
if (assumeYes) return guess;
|
|
5115
5453
|
const ok = await confirm6({ message: `Upgrade from ${guess}?`, default: true }).catch(() => false);
|
|
@@ -5119,7 +5457,25 @@ async function resolveBaseRef(project2, fromOption, assumeYes) {
|
|
|
5119
5457
|
}
|
|
5120
5458
|
return guess;
|
|
5121
5459
|
}
|
|
5122
|
-
function
|
|
5460
|
+
function printWorkspaceFindings(findings) {
|
|
5461
|
+
if (findings.length === 0) return;
|
|
5462
|
+
const pad = Math.max(...findings.map((finding) => finding.name.length));
|
|
5463
|
+
const rows = findings.map((finding) => ` ${finding.name.padEnd(pad)} ${finding.ours} \u2192 ^${finding.version}`).join("\n");
|
|
5464
|
+
consola.warn(
|
|
5465
|
+
`Catalyst dependencies still using the workspace protocol (${findings.length}):
|
|
5466
|
+
${rows}
|
|
5467
|
+
|
|
5468
|
+
They resolve to your local packages/ copies, which \`catalyst upgrade\` does not update \u2014 so they never receive upgrades.`
|
|
5469
|
+
);
|
|
5470
|
+
}
|
|
5471
|
+
function printSummary({
|
|
5472
|
+
result,
|
|
5473
|
+
relDir,
|
|
5474
|
+
stampedPkg,
|
|
5475
|
+
migratedDeps,
|
|
5476
|
+
packageManager,
|
|
5477
|
+
staleCli
|
|
5478
|
+
}) {
|
|
5123
5479
|
const unresolved = result.conflicted.filter((f) => !(stampedPkg && f === "package.json"));
|
|
5124
5480
|
const parts = [
|
|
5125
5481
|
`${result.applied.length} updated`,
|
|
@@ -5129,18 +5485,31 @@ function printSummary(result, relDir, stampedPkg) {
|
|
|
5129
5485
|
if (unresolved.length) parts.push(`${unresolved.length} with conflicts`);
|
|
5130
5486
|
consola.log(`
|
|
5131
5487
|
${parts.join(", ")}`);
|
|
5488
|
+
const pkgConflicted = unresolved.includes("package.json");
|
|
5489
|
+
const depsChanged = migratedDeps > 0 || [...result.applied, ...result.added, ...result.conflicted].includes("package.json");
|
|
5490
|
+
if (depsChanged && !pkgConflicted) {
|
|
5491
|
+
consola.info(
|
|
5492
|
+
`Dependencies changed \u2014 run \`${packageManager} install\` to update your lockfile.`
|
|
5493
|
+
);
|
|
5494
|
+
}
|
|
5132
5495
|
if (unresolved.length) {
|
|
5133
5496
|
const files = unresolved.map((f) => ` ${f}`).join("\n");
|
|
5497
|
+
const install = depsChanged && pkgConflicted ? ` && ${packageManager} install` : "";
|
|
5134
5498
|
consola.warn(
|
|
5135
5499
|
`
|
|
5136
5500
|
Staged the clean changes. ${unresolved.length} file(s) need conflict resolution (the <<<ours/===/theirs>>> markers):
|
|
5137
5501
|
${files}
|
|
5138
5502
|
|
|
5139
|
-
Resolve them, then: git add ${relDir} && git commit`
|
|
5503
|
+
Resolve them, then: git add ${relDir} && git commit${install}`
|
|
5140
5504
|
);
|
|
5141
5505
|
} else {
|
|
5142
5506
|
consola.success("Staged all changes \u2014 review with `git diff --cached`, then commit.");
|
|
5143
5507
|
}
|
|
5508
|
+
if (staleCli) {
|
|
5509
|
+
consola.info(
|
|
5510
|
+
`Your Catalyst CLI is behind (${staleCli.current} \u2192 ${staleCli.latest}). Update it with \`${packageManager} add -D ${CATALYST_CLI_PACKAGE}@${staleCli.latest}\`.`
|
|
5511
|
+
);
|
|
5512
|
+
}
|
|
5144
5513
|
}
|
|
5145
5514
|
var upgrade = new Command13("upgrade").configureHelp({ showGlobalOptions: true }).aliases([
|
|
5146
5515
|
"up",
|
|
@@ -5181,15 +5550,15 @@ Conflicts are written as standard <<<ours/===/theirs>>> markers \u2014 the upgra
|
|
|
5181
5550
|
never aborts. Versions are git tags on the repository (not npm). Set GITHUB_TOKEN
|
|
5182
5551
|
to raise the GitHub API rate limit.`
|
|
5183
5552
|
).action(async (version2, options) => {
|
|
5184
|
-
const
|
|
5185
|
-
if (!
|
|
5553
|
+
const project = await resolveProject2(process.cwd());
|
|
5554
|
+
if (!project) {
|
|
5186
5555
|
consola.error(
|
|
5187
5556
|
"Run `catalyst upgrade` from inside a Catalyst git repository (flat core/ repo or a project containing core/)."
|
|
5188
5557
|
);
|
|
5189
5558
|
process.exit(1);
|
|
5190
5559
|
}
|
|
5191
|
-
const { gitRoot, catalystRoot, relDir, pkgPath } =
|
|
5192
|
-
const baseRef = await resolveBaseRef(
|
|
5560
|
+
const { gitRoot, catalystRoot, relDir, pkgPath } = project;
|
|
5561
|
+
const baseRef = await resolveBaseRef(project, options.from, options.yes ?? false);
|
|
5193
5562
|
if (!baseRef) process.exit(1);
|
|
5194
5563
|
let basePackage;
|
|
5195
5564
|
let upstreamRef;
|
|
@@ -5224,7 +5593,7 @@ to raise the GitHub API rate limit.`
|
|
|
5224
5593
|
process.exit(1);
|
|
5225
5594
|
}
|
|
5226
5595
|
}
|
|
5227
|
-
if (!
|
|
5596
|
+
if (!project.pkg.catalyst?.ref && !options.from && !options.dryRun) {
|
|
5228
5597
|
const { version: baseVersion } = parseRef(baseRef);
|
|
5229
5598
|
const rawPkg = await readFile2(pkgPath, "utf-8");
|
|
5230
5599
|
const parsedPkg = z17.record(z17.string(), z17.unknown()).parse(JSON.parse(rawPkg));
|
|
@@ -5235,15 +5604,18 @@ to raise the GitHub API rate limit.`
|
|
|
5235
5604
|
consola.success(`Added catalyst.ref \u2192 ${baseRef}`);
|
|
5236
5605
|
}
|
|
5237
5606
|
const token = process.env.GITHUB_TOKEN;
|
|
5238
|
-
const tmpDir = await mkdtemp(
|
|
5607
|
+
const tmpDir = await mkdtemp(join15(tmpdir(), "catalyst-upgrade-"));
|
|
5239
5608
|
try {
|
|
5240
|
-
const baseDir =
|
|
5241
|
-
const theirsDir =
|
|
5242
|
-
const emptyFile =
|
|
5609
|
+
const baseDir = join15(tmpDir, "base");
|
|
5610
|
+
const theirsDir = join15(tmpDir, "theirs");
|
|
5611
|
+
const emptyFile = join15(tmpDir, ".empty");
|
|
5243
5612
|
await writeFile2(emptyFile, "");
|
|
5613
|
+
const staleCliCheck = findStaleCli(project.rawContent).catch(() => null);
|
|
5244
5614
|
const downloadSpinner = yoctoSpinner4().start(`Downloading ${baseRef} and ${upstreamRef}...`);
|
|
5615
|
+
let baseVersions;
|
|
5616
|
+
let targetVersions;
|
|
5245
5617
|
try {
|
|
5246
|
-
await Promise.all([
|
|
5618
|
+
[baseVersions, targetVersions] = await Promise.all([
|
|
5247
5619
|
downloadCore(options.repository, baseRef, baseDir, token),
|
|
5248
5620
|
downloadCore(options.repository, upstreamRef, theirsDir, token)
|
|
5249
5621
|
]);
|
|
@@ -5252,7 +5624,7 @@ to raise the GitHub API rate limit.`
|
|
|
5252
5624
|
downloadSpinner.error("Download failed");
|
|
5253
5625
|
throw err;
|
|
5254
5626
|
}
|
|
5255
|
-
if (!
|
|
5627
|
+
if (!project.pkg.catalyst?.ref && !options.from) {
|
|
5256
5628
|
const similarity = await computeBaseSimilarity(baseDir, catalystRoot);
|
|
5257
5629
|
const pct = Math.round(similarity * 100);
|
|
5258
5630
|
if (similarity < 0.5) {
|
|
@@ -5263,6 +5635,13 @@ to raise the GitHub API rate limit.`
|
|
|
5263
5635
|
}
|
|
5264
5636
|
const resolvedVersion = MOVING_TAGS.has(upstreamTagVersion) ? await readResolvedVersion(theirsDir) : upstreamTagVersion;
|
|
5265
5637
|
const newRef = MOVING_TAGS.has(upstreamTagVersion) ? `${basePackage}@${resolvedVersion}` : upstreamRef;
|
|
5638
|
+
const { workspace: workspaceDeps, bumped } = await normalizeWorkspaceDeps(
|
|
5639
|
+
project.rawContent,
|
|
5640
|
+
baseDir,
|
|
5641
|
+
theirsDir,
|
|
5642
|
+
baseVersions,
|
|
5643
|
+
targetVersions
|
|
5644
|
+
);
|
|
5266
5645
|
if (options.dryRun) {
|
|
5267
5646
|
const diffSpinner = yoctoSpinner4().start("Generating diff...");
|
|
5268
5647
|
const diff = await execa4(
|
|
@@ -5282,6 +5661,7 @@ to raise the GitHub API rate limit.`
|
|
|
5282
5661
|
diffSpinner.success(`Diff ready \u2014 ${fileCount} file(s) affected.`);
|
|
5283
5662
|
consola.log("\nDiff preview (--dry-run, not applied):\n");
|
|
5284
5663
|
consola.log(diff.stdout);
|
|
5664
|
+
printWorkspaceFindings(workspaceDeps);
|
|
5285
5665
|
return;
|
|
5286
5666
|
}
|
|
5287
5667
|
const strategy = await resolveStrategy(options.strategy);
|
|
@@ -5298,13 +5678,13 @@ to raise the GitHub API rate limit.`
|
|
|
5298
5678
|
mergeSpinner.success("Merged cleanly.");
|
|
5299
5679
|
}
|
|
5300
5680
|
const patchedRaw = await readFile2(pkgPath, "utf-8");
|
|
5301
|
-
let
|
|
5681
|
+
let stampedText = null;
|
|
5302
5682
|
try {
|
|
5303
5683
|
const patchedPkg = z17.record(z17.string(), z17.unknown()).parse(JSON.parse(patchedRaw));
|
|
5304
5684
|
patchedPkg.catalyst = { version: resolvedVersion, ref: newRef };
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5685
|
+
stampedText = `${JSON.stringify(patchedPkg, null, 2)}
|
|
5686
|
+
`;
|
|
5687
|
+
await writeFile2(pkgPath, stampedText);
|
|
5308
5688
|
consola.success(`catalyst.ref updated \u2192 ${newRef}`);
|
|
5309
5689
|
} catch {
|
|
5310
5690
|
const catalystReplacement = JSON.stringify(
|
|
@@ -5329,14 +5709,35 @@ to raise the GitHub API rate limit.`
|
|
|
5329
5709
|
);
|
|
5330
5710
|
}
|
|
5331
5711
|
}
|
|
5712
|
+
printWorkspaceFindings(workspaceDeps);
|
|
5713
|
+
let migratedDeps = 0;
|
|
5714
|
+
if (workspaceDeps.length) {
|
|
5715
|
+
const accepted = stampedText !== null && (options.yes === true || Boolean(process.stdin.isTTY) && await confirm6({
|
|
5716
|
+
message: "Replace them with the published versions?",
|
|
5717
|
+
default: true
|
|
5718
|
+
}).catch(() => false));
|
|
5719
|
+
if (accepted && stampedText !== null) {
|
|
5720
|
+
await writeFile2(pkgPath, migrateWorkspaceDeps(stampedText, workspaceDeps));
|
|
5721
|
+
migratedDeps = workspaceDeps.length;
|
|
5722
|
+
consola.success(
|
|
5723
|
+
`Migrated ${migratedDeps} dependenc${migratedDeps === 1 ? "y" : "ies"} to published versions.`
|
|
5724
|
+
);
|
|
5725
|
+
} else {
|
|
5726
|
+
consola.info(
|
|
5727
|
+
"Keeping the workspace references. Switching abandons any local packages/ copy you've customized; otherwise apply the versions above in package.json and reinstall."
|
|
5728
|
+
);
|
|
5729
|
+
}
|
|
5730
|
+
}
|
|
5332
5731
|
try {
|
|
5333
|
-
await applyIndexState(gitRoot, relDir, baseDir, theirsDir, result,
|
|
5732
|
+
await applyIndexState(gitRoot, relDir, baseDir, theirsDir, result, stampedText !== null);
|
|
5334
5733
|
} catch (err) {
|
|
5335
5734
|
consola.warn(
|
|
5336
5735
|
`Couldn't auto-stage the changes (${err instanceof Error ? err.message : String(err)}). Your files are merged on disk \u2014 run \`git add ${relDir}\` yourself.`
|
|
5337
5736
|
);
|
|
5338
5737
|
}
|
|
5339
5738
|
const gitVersion = await execa4("git", ["--version"]).then((r) => r.stdout.trim()).catch(() => "unknown");
|
|
5739
|
+
const packageManager = await detectLockfileManager(gitRoot) ?? "pnpm";
|
|
5740
|
+
const staleCli = await staleCliCheck;
|
|
5340
5741
|
await getTelemetry().track("upgrade", {
|
|
5341
5742
|
strategy,
|
|
5342
5743
|
gitVersion,
|
|
@@ -5345,9 +5746,20 @@ to raise the GitHub API rate limit.`
|
|
|
5345
5746
|
added: result.added.length,
|
|
5346
5747
|
deleted: result.deleted.length,
|
|
5347
5748
|
conflicts: result.conflicted.length,
|
|
5348
|
-
hasConflicts: result.conflicted.length > 0
|
|
5749
|
+
hasConflicts: result.conflicted.length > 0,
|
|
5750
|
+
workspaceDepsFound: workspaceDeps.length,
|
|
5751
|
+
workspaceDepsMigrated: migratedDeps,
|
|
5752
|
+
catalystDepsBumped: bumped.length,
|
|
5753
|
+
cliOutdated: staleCli !== null
|
|
5754
|
+
});
|
|
5755
|
+
printSummary({
|
|
5756
|
+
result,
|
|
5757
|
+
relDir,
|
|
5758
|
+
stampedPkg: stampedText !== null,
|
|
5759
|
+
migratedDeps,
|
|
5760
|
+
packageManager,
|
|
5761
|
+
staleCli
|
|
5349
5762
|
});
|
|
5350
|
-
printSummary(result, relDir, stampedPkg);
|
|
5351
5763
|
} finally {
|
|
5352
5764
|
await rm2(tmpDir, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
|
|
5353
5765
|
}
|
|
@@ -5402,17 +5814,17 @@ function getCommandPath(cmd) {
|
|
|
5402
5814
|
return parts.join(" ");
|
|
5403
5815
|
}
|
|
5404
5816
|
var telemetryPreHook = async (thisCommand, actionCommand) => {
|
|
5405
|
-
const
|
|
5817
|
+
const telemetry2 = getTelemetry();
|
|
5406
5818
|
const commandName = getCommandPath(actionCommand);
|
|
5407
|
-
|
|
5408
|
-
return await
|
|
5819
|
+
telemetry2.commandName = commandName;
|
|
5820
|
+
return await telemetry2.track(commandName, {
|
|
5409
5821
|
...parseArguments(thisCommand.args)
|
|
5410
5822
|
});
|
|
5411
5823
|
};
|
|
5412
5824
|
var telemetryPostHook = async () => {
|
|
5413
|
-
const
|
|
5414
|
-
await
|
|
5415
|
-
await
|
|
5825
|
+
const telemetry2 = getTelemetry();
|
|
5826
|
+
await telemetry2.track("command_completed", { durationMs: telemetry2.durationMs() });
|
|
5827
|
+
await telemetry2.analytics.closeAndFlush();
|
|
5416
5828
|
};
|
|
5417
5829
|
|
|
5418
5830
|
// src/cli/program.ts
|
|
@@ -5424,21 +5836,21 @@ consola.log(colorize13("cyanBright", `\u25E2 ${package_default.name} v${package_
|
|
|
5424
5836
|
`));
|
|
5425
5837
|
program.name(package_default.name).version(package_default.version).summary("CLI tool for Catalyst development").description(
|
|
5426
5838
|
"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."
|
|
5427
|
-
).configureHelp({ showGlobalOptions: true }).addCommand(version).addCommand(create2).addCommand(start).addCommand(build).addCommand(deploy).addCommand(domains).addCommand(logs).addCommand(
|
|
5839
|
+
).configureHelp({ showGlobalOptions: true }).addCommand(version).addCommand(create2).addCommand(start).addCommand(build).addCommand(deploy).addCommand(domains).addCommand(logs).addCommand(projects).addCommand(env).addCommand(channels).addCommand(auth).addCommand(upgrade).addCommand(telemetry).addCommand(debug).hook("preAction", telemetryPreHook).hook("postAction", telemetryPostHook);
|
|
5428
5840
|
|
|
5429
5841
|
// src/cli/index.ts
|
|
5430
5842
|
var handleFatalError = async (error) => {
|
|
5431
|
-
const
|
|
5843
|
+
const telemetry2 = getTelemetry();
|
|
5432
5844
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5433
5845
|
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
5434
5846
|
try {
|
|
5435
|
-
await
|
|
5436
|
-
commandName:
|
|
5847
|
+
await telemetry2.track("error", {
|
|
5848
|
+
commandName: telemetry2.commandName,
|
|
5437
5849
|
errorMessage,
|
|
5438
5850
|
errorStack,
|
|
5439
|
-
durationMs:
|
|
5851
|
+
durationMs: telemetry2.durationMs()
|
|
5440
5852
|
});
|
|
5441
|
-
await
|
|
5853
|
+
await telemetry2.analytics.closeAndFlush();
|
|
5442
5854
|
} catch {
|
|
5443
5855
|
}
|
|
5444
5856
|
if (error instanceof UserActionableError) {
|
|
@@ -5446,9 +5858,9 @@ var handleFatalError = async (error) => {
|
|
|
5446
5858
|
process.exit(1);
|
|
5447
5859
|
}
|
|
5448
5860
|
consola.error(errorMessage);
|
|
5449
|
-
if (
|
|
5861
|
+
if (telemetry2.isEnabled()) {
|
|
5450
5862
|
consola.info(
|
|
5451
|
-
`Correlation ID: ${
|
|
5863
|
+
`Correlation ID: ${telemetry2.correlationId}
|
|
5452
5864
|
Share this Correlation ID with BigCommerce support.`
|
|
5453
5865
|
);
|
|
5454
5866
|
} else {
|