@bigcommerce/catalyst 1.0.0-alpha.5 → 1.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +305 -211
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -28,7 +28,7 @@ import { randomBytes, randomUUID } from "crypto";
|
|
|
28
28
|
// package.json
|
|
29
29
|
var package_default = {
|
|
30
30
|
name: "@bigcommerce/catalyst",
|
|
31
|
-
version: "1.0.0-alpha.
|
|
31
|
+
version: "1.0.0-alpha.6",
|
|
32
32
|
type: "module",
|
|
33
33
|
bin: {
|
|
34
34
|
catalyst: "dist/cli.js"
|
|
@@ -197,7 +197,7 @@ function getTelemetry() {
|
|
|
197
197
|
// src/cli/program.ts
|
|
198
198
|
import { Option as Option9 } from "@commander-js/extra-typings";
|
|
199
199
|
import { Command as Command12 } from "commander";
|
|
200
|
-
import { colorize as
|
|
200
|
+
import { colorize as colorize9 } from "consola/utils";
|
|
201
201
|
import { config } from "dotenv";
|
|
202
202
|
import { existsSync as existsSync5 } from "fs";
|
|
203
203
|
import { resolve } from "path";
|
|
@@ -207,7 +207,7 @@ import { Command, Option as Option2 } from "commander";
|
|
|
207
207
|
import { z as z4 } from "zod";
|
|
208
208
|
|
|
209
209
|
// src/cli/lib/login.ts
|
|
210
|
-
import { password } from "@inquirer/prompts";
|
|
210
|
+
import { confirm, input, password } from "@inquirer/prompts";
|
|
211
211
|
import { colorize } from "consola/utils";
|
|
212
212
|
import open from "open";
|
|
213
213
|
import yoctoSpinner from "yocto-spinner";
|
|
@@ -337,8 +337,8 @@ async function manualLogin(apiHost) {
|
|
|
337
337
|
Settings \u2192 API \u2192 Store-level API accounts \u2192 Create API account
|
|
338
338
|
Grant these OAuth scopes: ${DEVICE_OAUTH_SCOPES}`
|
|
339
339
|
);
|
|
340
|
-
const storeHashInput = await
|
|
341
|
-
const storeHash =
|
|
340
|
+
const storeHashInput = await input({ message: "Store hash:" });
|
|
341
|
+
const storeHash = storeHashInput.trim();
|
|
342
342
|
if (!storeHash) {
|
|
343
343
|
throw new Error("Store hash is required.");
|
|
344
344
|
}
|
|
@@ -366,10 +366,10 @@ async function login(loginUrl, apiHost) {
|
|
|
366
366
|
} catch (error) {
|
|
367
367
|
const message = error instanceof Error ? error.message : String(error);
|
|
368
368
|
consola.warn(`Browser login didn't work (${message}).`);
|
|
369
|
-
const shouldFallback = await
|
|
370
|
-
"Try logging in manually with a store hash and access token instead?",
|
|
371
|
-
|
|
372
|
-
);
|
|
369
|
+
const shouldFallback = await confirm({
|
|
370
|
+
message: "Try logging in manually with a store hash and access token instead?",
|
|
371
|
+
default: true
|
|
372
|
+
});
|
|
373
373
|
if (!shouldFallback) {
|
|
374
374
|
throw new LoginAbortedError();
|
|
375
375
|
}
|
|
@@ -783,12 +783,17 @@ function getProjectState(cwd = process.cwd()) {
|
|
|
783
783
|
}
|
|
784
784
|
|
|
785
785
|
// src/cli/lib/wrangler-config.ts
|
|
786
|
+
function getCompatibilityDate(now = /* @__PURE__ */ new Date()) {
|
|
787
|
+
const date = new Date(now);
|
|
788
|
+
date.setUTCMonth(date.getUTCMonth() - 1);
|
|
789
|
+
return date.toISOString().slice(0, 10);
|
|
790
|
+
}
|
|
786
791
|
function getWranglerConfig(projectUuid) {
|
|
787
792
|
return {
|
|
788
793
|
$schema: "node_modules/wrangler/config-schema.json",
|
|
789
794
|
main: "../.open-next/worker.js",
|
|
790
795
|
name: `project-${projectUuid}`,
|
|
791
|
-
compatibility_date:
|
|
796
|
+
compatibility_date: getCompatibilityDate(),
|
|
792
797
|
compatibility_flags: ["nodejs_compat", "global_fetch_strictly_public"],
|
|
793
798
|
observability: {
|
|
794
799
|
enabled: true,
|
|
@@ -935,7 +940,14 @@ Examples:
|
|
|
935
940
|
});
|
|
936
941
|
|
|
937
942
|
// src/cli/commands/channel.ts
|
|
938
|
-
import {
|
|
943
|
+
import { select as select3 } from "@inquirer/prompts";
|
|
944
|
+
import { Command as Command3, InvalidArgumentError, Option as Option4 } from "commander";
|
|
945
|
+
import { colorize as colorize3 } from "consola/utils";
|
|
946
|
+
import { outputFileSync } from "fs-extra/esm";
|
|
947
|
+
import { join as join6 } from "path";
|
|
948
|
+
|
|
949
|
+
// src/cli/lib/channel-site-flow.ts
|
|
950
|
+
import { select as select2 } from "@inquirer/prompts";
|
|
939
951
|
|
|
940
952
|
// src/cli/lib/channels.ts
|
|
941
953
|
import { z as z6 } from "zod";
|
|
@@ -958,6 +970,20 @@ var channelSchema = z6.object({
|
|
|
958
970
|
var channelsResponseSchema = z6.object({
|
|
959
971
|
data: z6.array(channelSchema)
|
|
960
972
|
});
|
|
973
|
+
var CHANNEL_PLATFORM_ORDER = ["catalyst", "next", "bigcommerce"];
|
|
974
|
+
function sortChannelsByPlatform(channels) {
|
|
975
|
+
return [...channels].sort((a, b) => {
|
|
976
|
+
const aIndex = CHANNEL_PLATFORM_ORDER.indexOf(a.platform);
|
|
977
|
+
const bIndex = CHANNEL_PLATFORM_ORDER.indexOf(b.platform);
|
|
978
|
+
if (aIndex === -1 && bIndex === -1) return 0;
|
|
979
|
+
if (aIndex === -1) return 1;
|
|
980
|
+
if (bIndex === -1) return -1;
|
|
981
|
+
return aIndex - bIndex;
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
function channelPlatformLabel(platform) {
|
|
985
|
+
return platform === "bigcommerce" ? "Stencil" : platform.charAt(0).toUpperCase() + platform.slice(1);
|
|
986
|
+
}
|
|
961
987
|
var initResponseSchema = z6.object({
|
|
962
988
|
data: z6.object({
|
|
963
989
|
storefront_api_token: z6.string(),
|
|
@@ -1078,7 +1104,7 @@ async function updateChannelSiteUrl(channelId, siteUrl, storeHash, accessToken,
|
|
|
1078
1104
|
}
|
|
1079
1105
|
|
|
1080
1106
|
// src/cli/lib/commerce-hosting.ts
|
|
1081
|
-
import { input, select, Separator } from "@inquirer/prompts";
|
|
1107
|
+
import { confirm as confirm2, input as input2, select, Separator } from "@inquirer/prompts";
|
|
1082
1108
|
import { colorize as colorize2 } from "consola/utils";
|
|
1083
1109
|
import {
|
|
1084
1110
|
existsSync as existsSync2,
|
|
@@ -1159,11 +1185,10 @@ var cleanupCloudflareIncompatibilities = async (projectDir) => {
|
|
|
1159
1185
|
);
|
|
1160
1186
|
return;
|
|
1161
1187
|
}
|
|
1162
|
-
const shouldRemove = await
|
|
1163
|
-
'Catalyst found core/instrumentation.ts, which is incompatible with the Cloudflare Workers bundle when it uses @vercel/otel (causes "Failed to prepare server" at cold start). Remove it and drop @vercel/otel from core/package.json?',
|
|
1164
|
-
|
|
1165
|
-
);
|
|
1166
|
-
consola.log("");
|
|
1188
|
+
const shouldRemove = await confirm2({
|
|
1189
|
+
message: 'Catalyst found core/instrumentation.ts, which is incompatible with the Cloudflare Workers bundle when it uses @vercel/otel (causes "Failed to prepare server" at cold start). Remove it and drop @vercel/otel from core/package.json?',
|
|
1190
|
+
default: true
|
|
1191
|
+
});
|
|
1167
1192
|
if (!shouldRemove) {
|
|
1168
1193
|
consola.info(
|
|
1169
1194
|
'Leaving core/instrumentation.ts in place. The Cloudflare worker will continue to log "Failed to prepare server" at cold start until this is resolved manually.'
|
|
@@ -1214,15 +1239,8 @@ var NoLinkedProjectError = class extends Error {
|
|
|
1214
1239
|
}
|
|
1215
1240
|
};
|
|
1216
1241
|
async function promptForNewProjectName(api) {
|
|
1217
|
-
const newProjectName = await
|
|
1218
|
-
|
|
1219
|
-
});
|
|
1220
|
-
const data = await createProject(
|
|
1221
|
-
String(newProjectName),
|
|
1222
|
-
api.storeHash,
|
|
1223
|
-
api.accessToken,
|
|
1224
|
-
api.apiHost
|
|
1225
|
-
);
|
|
1242
|
+
const newProjectName = await input2({ message: "Enter a name for the new project:" });
|
|
1243
|
+
const data = await createProject(newProjectName, api.storeHash, api.accessToken, api.apiHost);
|
|
1226
1244
|
consola.success(`Project "${data.name}" created successfully.`);
|
|
1227
1245
|
return { uuid: data.uuid, name: data.name, deployment_hostnames: [] };
|
|
1228
1246
|
}
|
|
@@ -1231,31 +1249,31 @@ async function selectOrCreateInfrastructureProject(api, linkedProjectUuid) {
|
|
|
1231
1249
|
const existingProjects = await fetchProjects(api.storeHash, api.accessToken, api.apiHost);
|
|
1232
1250
|
consola.success("Projects fetched.");
|
|
1233
1251
|
if (existingProjects.length === 0) {
|
|
1234
|
-
const shouldCreate = await
|
|
1235
|
-
"There are not any hosting projects that you can link to yet. Would you like to create one?",
|
|
1236
|
-
|
|
1237
|
-
);
|
|
1252
|
+
const shouldCreate = await confirm2({
|
|
1253
|
+
message: "There are not any hosting projects that you can link to yet. Would you like to create one?",
|
|
1254
|
+
default: true
|
|
1255
|
+
});
|
|
1238
1256
|
if (!shouldCreate) {
|
|
1239
1257
|
throw new NoLinkedProjectError();
|
|
1240
1258
|
}
|
|
1241
1259
|
return promptForNewProjectName(api);
|
|
1242
1260
|
}
|
|
1243
|
-
const
|
|
1261
|
+
const choices = [
|
|
1244
1262
|
...existingProjects.map((p) => ({
|
|
1245
|
-
|
|
1263
|
+
name: p.uuid === linkedProjectUuid ? `${p.name} ${colorize2("green", "[linked]")}` : p.name,
|
|
1246
1264
|
value: p.uuid,
|
|
1247
|
-
|
|
1265
|
+
description: p.uuid
|
|
1248
1266
|
})),
|
|
1249
1267
|
{
|
|
1250
|
-
|
|
1268
|
+
name: "Create a new project",
|
|
1251
1269
|
value: "create",
|
|
1252
|
-
|
|
1270
|
+
description: "Create a new hosting project for this Catalyst storefront."
|
|
1253
1271
|
}
|
|
1254
1272
|
];
|
|
1255
|
-
const selected = await
|
|
1256
|
-
"Select a project or create a new project (Press <enter> to select).",
|
|
1257
|
-
|
|
1258
|
-
);
|
|
1273
|
+
const selected = await select({
|
|
1274
|
+
message: "Select a project or create a new project (Press <enter> to select).",
|
|
1275
|
+
choices
|
|
1276
|
+
});
|
|
1259
1277
|
if (selected === "create") {
|
|
1260
1278
|
return promptForNewProjectName(api);
|
|
1261
1279
|
}
|
|
@@ -1325,7 +1343,7 @@ async function promptForCommerceHostingProject(api, defaultName, autoUseDefaultN
|
|
|
1325
1343
|
return selected;
|
|
1326
1344
|
}
|
|
1327
1345
|
async function promptAndCreateCommerceHostingProject(api, takenNames, defaultName) {
|
|
1328
|
-
const projectName = await
|
|
1346
|
+
const projectName = await input2({
|
|
1329
1347
|
message: "What would you like to name your Commerce Hosting project?",
|
|
1330
1348
|
default: defaultName,
|
|
1331
1349
|
validate: (value) => {
|
|
@@ -1439,16 +1457,14 @@ async function resolveChannel(options) {
|
|
|
1439
1457
|
"No Catalyst channels found on this store. Create one with `catalyst create` and try again."
|
|
1440
1458
|
);
|
|
1441
1459
|
}
|
|
1442
|
-
const
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
value:
|
|
1447
|
-
|
|
1448
|
-
}))
|
|
1449
|
-
cancel: "reject"
|
|
1460
|
+
const id = await select2({
|
|
1461
|
+
message: "Select the channel to update.",
|
|
1462
|
+
choices: catalystChannels.map((c) => ({
|
|
1463
|
+
name: c.name,
|
|
1464
|
+
value: c.id,
|
|
1465
|
+
description: `id: ${c.id}`
|
|
1466
|
+
}))
|
|
1450
1467
|
});
|
|
1451
|
-
const id = Number(selectedId);
|
|
1452
1468
|
const matched = catalystChannels.find((c) => c.id === id);
|
|
1453
1469
|
return { id, name: matched?.name };
|
|
1454
1470
|
}
|
|
@@ -1465,12 +1481,11 @@ async function resolveHostname(project2, options) {
|
|
|
1465
1481
|
...project2.deployment_hostnames.filter((h) => h === options.preferHostname),
|
|
1466
1482
|
...project2.deployment_hostnames.filter((h) => h !== options.preferHostname)
|
|
1467
1483
|
] : project2.deployment_hostnames;
|
|
1468
|
-
const selected = await
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
cancel: "reject"
|
|
1484
|
+
const selected = await select2({
|
|
1485
|
+
message: "Select the hostname to point the channel at.",
|
|
1486
|
+
choices: ordered.map((h) => ({ name: h, value: h }))
|
|
1472
1487
|
});
|
|
1473
|
-
return
|
|
1488
|
+
return selected;
|
|
1474
1489
|
}
|
|
1475
1490
|
async function runChannelSiteUrlFlow(options) {
|
|
1476
1491
|
const project2 = await resolveProject(options);
|
|
@@ -1488,6 +1503,38 @@ async function runChannelSiteUrlFlow(options) {
|
|
|
1488
1503
|
consola.success(`Updated channel ${channelLabel} site URL to ${siteUrl}.`);
|
|
1489
1504
|
}
|
|
1490
1505
|
|
|
1506
|
+
// src/cli/lib/env-config.ts
|
|
1507
|
+
var ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
1508
|
+
var parseEnvAssignment = (input5) => {
|
|
1509
|
+
const separatorIndex = input5.indexOf("=");
|
|
1510
|
+
if (separatorIndex === -1) {
|
|
1511
|
+
throw new Error(`Invalid env var format: ${input5}. Expected format: KEY=VALUE`);
|
|
1512
|
+
}
|
|
1513
|
+
const key = input5.slice(0, separatorIndex).trim();
|
|
1514
|
+
const value = input5.slice(separatorIndex + 1).trim();
|
|
1515
|
+
if (!key || !value) {
|
|
1516
|
+
throw new Error(`Invalid env var format: ${input5}. Expected format: KEY=VALUE`);
|
|
1517
|
+
}
|
|
1518
|
+
if (!ENV_KEY_PATTERN.test(key)) {
|
|
1519
|
+
throw new Error(
|
|
1520
|
+
`Invalid env var name: ${key}. Names must start with a letter or underscore and contain only letters, numbers, and underscores.`
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
return { key, value };
|
|
1524
|
+
};
|
|
1525
|
+
var getStoredEnv = (config2) => {
|
|
1526
|
+
return config2.get("env") ?? {};
|
|
1527
|
+
};
|
|
1528
|
+
var toDeploymentSecrets = (envVars) => {
|
|
1529
|
+
return Object.entries(envVars).map(([key, value]) => ({ type: "secret", key, value }));
|
|
1530
|
+
};
|
|
1531
|
+
var mergeDeploymentSecrets = (persisted, flagSecrets) => {
|
|
1532
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1533
|
+
persisted.forEach((secret) => byKey.set(secret.key, secret));
|
|
1534
|
+
flagSecrets.forEach((secret) => byKey.set(secret.key, secret));
|
|
1535
|
+
return Array.from(byKey.values());
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1491
1538
|
// src/cli/lib/resolve-credentials.ts
|
|
1492
1539
|
function resolveCredentials(options, config2) {
|
|
1493
1540
|
const storeHash = options.storeHash ?? config2.get("storeHash");
|
|
@@ -1504,6 +1551,31 @@ function resolveCredentials(options, config2) {
|
|
|
1504
1551
|
}
|
|
1505
1552
|
|
|
1506
1553
|
// src/cli/commands/channel.ts
|
|
1554
|
+
var parseChannelId = (value) => {
|
|
1555
|
+
const parsed = Number.parseInt(value, 10);
|
|
1556
|
+
if (Number.isNaN(parsed)) {
|
|
1557
|
+
throw new InvalidArgumentError(`"${value}" is not a valid channel ID (expected a number).`);
|
|
1558
|
+
}
|
|
1559
|
+
return parsed;
|
|
1560
|
+
};
|
|
1561
|
+
async function resolveCredentialsWithLogin(options, config2) {
|
|
1562
|
+
const storeHash = options.storeHash ?? config2.get("storeHash");
|
|
1563
|
+
const accessToken = options.accessToken ?? config2.get("accessToken");
|
|
1564
|
+
if (storeHash && accessToken) {
|
|
1565
|
+
return { storeHash, accessToken };
|
|
1566
|
+
}
|
|
1567
|
+
try {
|
|
1568
|
+
const credentials = await login(options.loginUrl, options.apiHost);
|
|
1569
|
+
config2.set("storeHash", credentials.storeHash);
|
|
1570
|
+
config2.set("accessToken", credentials.accessToken);
|
|
1571
|
+
return credentials;
|
|
1572
|
+
} catch (error) {
|
|
1573
|
+
if (error instanceof LoginAbortedError) {
|
|
1574
|
+
return null;
|
|
1575
|
+
}
|
|
1576
|
+
throw error;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1507
1579
|
var update = new Command3("update").configureHelp({ showGlobalOptions: true }).description(
|
|
1508
1580
|
"Update a BigCommerce channel's site URL to point at one of your project's deployment hostnames."
|
|
1509
1581
|
).addHelpText(
|
|
@@ -1550,33 +1622,111 @@ Examples:
|
|
|
1550
1622
|
}
|
|
1551
1623
|
process.exit(0);
|
|
1552
1624
|
});
|
|
1553
|
-
var
|
|
1625
|
+
var link = new Command3("link").configureHelp({ showGlobalOptions: true }).description(
|
|
1626
|
+
"Link this Catalyst project to a BigCommerce channel and write its credentials to .env.local."
|
|
1627
|
+
).addHelpText(
|
|
1628
|
+
"after",
|
|
1629
|
+
`
|
|
1630
|
+
Examples:
|
|
1631
|
+
# Pick a channel interactively (logs you in if needed)
|
|
1632
|
+
$ catalyst channel link
|
|
1633
|
+
|
|
1634
|
+
# Non-interactive
|
|
1635
|
+
$ catalyst channel link --store-hash <hash> --access-token <token> --channel-id 123
|
|
1636
|
+
|
|
1637
|
+
# Append extra environment variables to .env.local
|
|
1638
|
+
$ catalyst channel link --channel-id 123 --env MY_FLAG=1`
|
|
1639
|
+
).addOption(storeHashOption()).addOption(accessTokenOption()).addOption(apiHostOption()).addOption(loginUrlOption()).addOption(
|
|
1640
|
+
new Option4("--channel-id <id>", "Link this channel directly, skipping the picker.").argParser(
|
|
1641
|
+
parseChannelId
|
|
1642
|
+
)
|
|
1643
|
+
).option(
|
|
1644
|
+
"--env <vars...>",
|
|
1645
|
+
"Arbitrary environment variables to set in .env.local. Format: KEY=VALUE (repeatable)."
|
|
1646
|
+
).addOption(
|
|
1647
|
+
new Option4("--cli-api-origin <origin>", "Catalyst CLI API origin").default("https://cxm-prd.bigcommerceapp.com").hideHelp()
|
|
1648
|
+
).action(async (options) => {
|
|
1649
|
+
const config2 = getProjectConfig();
|
|
1650
|
+
const credentials = await resolveCredentialsWithLogin(options, config2);
|
|
1651
|
+
if (!credentials) {
|
|
1652
|
+
consola.info(
|
|
1653
|
+
"Login aborted. Re-run `catalyst channel link` when you have your credentials ready."
|
|
1654
|
+
);
|
|
1655
|
+
process.exit(0);
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
const { storeHash, accessToken } = credentials;
|
|
1659
|
+
await getTelemetry().identify(storeHash);
|
|
1660
|
+
let channelId = options.channelId;
|
|
1661
|
+
let channelName;
|
|
1662
|
+
if (channelId === void 0) {
|
|
1663
|
+
const channels = await fetchAvailableChannels(storeHash, accessToken, options.apiHost);
|
|
1664
|
+
if (channels.length === 0) {
|
|
1665
|
+
consola.info(
|
|
1666
|
+
"No storefront channels found on this store. Create one with `catalyst create` and try again."
|
|
1667
|
+
);
|
|
1668
|
+
process.exit(0);
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
channelId = await select3({
|
|
1672
|
+
message: "Which channel would you like to link?",
|
|
1673
|
+
choices: sortChannelsByPlatform(channels).map((c) => ({
|
|
1674
|
+
name: c.name,
|
|
1675
|
+
value: c.id,
|
|
1676
|
+
description: channelPlatformLabel(c.platform)
|
|
1677
|
+
}))
|
|
1678
|
+
});
|
|
1679
|
+
channelName = channels.find((c) => c.id === channelId)?.name;
|
|
1680
|
+
}
|
|
1681
|
+
const initData = await getChannelInit(channelId, storeHash, accessToken, options.cliApiOrigin);
|
|
1682
|
+
const envVars = { ...initData.envVars };
|
|
1683
|
+
if (options.env) {
|
|
1684
|
+
options.env.forEach((entry) => {
|
|
1685
|
+
const { key, value } = parseEnvAssignment(entry);
|
|
1686
|
+
envVars[key] = value;
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
outputFileSync(
|
|
1690
|
+
join6(process.cwd(), ".env.local"),
|
|
1691
|
+
`${Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n")}
|
|
1692
|
+
`
|
|
1693
|
+
);
|
|
1694
|
+
const label = channelName ? `"${channelName}" (${channelId})` : `${channelId}`;
|
|
1695
|
+
consola.success(
|
|
1696
|
+
`Linked to channel ${label} and wrote ${colorize3("cyanBright", ".env.local")}.`
|
|
1697
|
+
);
|
|
1698
|
+
consola.log(`Next steps:
|
|
1699
|
+
|
|
1700
|
+
${colorize3("yellow", "pnpm run dev")}`);
|
|
1701
|
+
process.exit(0);
|
|
1702
|
+
});
|
|
1703
|
+
var channel = new Command3("channel").configureHelp({ showGlobalOptions: true }).description("Manage BigCommerce channels.").addCommand(link).addCommand(update);
|
|
1554
1704
|
|
|
1555
1705
|
// src/cli/commands/create.ts
|
|
1556
|
-
import { Command as Command4, InvalidArgumentError, Option as Option5 } from "@commander-js/extra-typings";
|
|
1557
|
-
import { input as
|
|
1706
|
+
import { Command as Command4, InvalidArgumentError as InvalidArgumentError2, Option as Option5 } from "@commander-js/extra-typings";
|
|
1707
|
+
import { checkbox, input as input3, select as select4 } from "@inquirer/prompts";
|
|
1558
1708
|
import { execSync as execSync4 } from "child_process";
|
|
1559
|
-
import { colorize as
|
|
1709
|
+
import { colorize as colorize4 } from "consola/utils";
|
|
1560
1710
|
import { pathExistsSync } from "fs-extra/esm";
|
|
1561
1711
|
import kebabCase from "lodash.kebabcase";
|
|
1562
|
-
import { join as
|
|
1712
|
+
import { join as join10 } from "path";
|
|
1563
1713
|
|
|
1564
1714
|
// src/cli/lib/build-workspace-packages.ts
|
|
1565
1715
|
import { execSync } from "child_process";
|
|
1566
1716
|
import { existsSync as existsSync3 } from "fs";
|
|
1567
|
-
import { join as
|
|
1717
|
+
import { join as join7 } from "path";
|
|
1568
1718
|
import yoctoSpinner2 from "yocto-spinner";
|
|
1569
1719
|
var WORKSPACE_PACKAGES = ["packages/catalyst", "packages/client"];
|
|
1570
1720
|
var buildWorkspacePackages = (projectDir) => {
|
|
1571
|
-
const hasCore = existsSync3(
|
|
1721
|
+
const hasCore = existsSync3(join7(projectDir, "core"));
|
|
1572
1722
|
const hasAllWorkspacePackages = WORKSPACE_PACKAGES.every(
|
|
1573
|
-
(pkg) => existsSync3(
|
|
1723
|
+
(pkg) => existsSync3(join7(projectDir, pkg))
|
|
1574
1724
|
);
|
|
1575
1725
|
if (!hasCore || !hasAllWorkspacePackages) return;
|
|
1576
1726
|
WORKSPACE_PACKAGES.forEach((pkg) => {
|
|
1577
1727
|
const spinner = yoctoSpinner2().start(`Building ${pkg}...`);
|
|
1578
1728
|
try {
|
|
1579
|
-
execSync("pnpm build", { cwd:
|
|
1729
|
+
execSync("pnpm build", { cwd: join7(projectDir, pkg), stdio: "ignore" });
|
|
1580
1730
|
spinner.success(`Built ${pkg}.`);
|
|
1581
1731
|
} catch (error) {
|
|
1582
1732
|
const message = error instanceof Error ? error.message : "unknown error";
|
|
@@ -1758,7 +1908,7 @@ var getAvailableLocales = async (storeHash, accessToken, apiHost) => {
|
|
|
1758
1908
|
|
|
1759
1909
|
// src/cli/lib/setup-core-project.ts
|
|
1760
1910
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1761
|
-
import { dirname as dirname3, join as
|
|
1911
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
1762
1912
|
import { z as z9 } from "zod";
|
|
1763
1913
|
var corePackageJsonSchema2 = z9.looseObject({
|
|
1764
1914
|
scripts: z9.record(z9.string(), z9.string()).optional(),
|
|
@@ -1770,7 +1920,7 @@ var writeJson2 = (path, value) => {
|
|
|
1770
1920
|
`);
|
|
1771
1921
|
};
|
|
1772
1922
|
var setupCoreProject = (projectDir) => {
|
|
1773
|
-
const corePackageJsonPath =
|
|
1923
|
+
const corePackageJsonPath = join8(projectDir, "core", "package.json");
|
|
1774
1924
|
const pkg = corePackageJsonSchema2.parse(JSON.parse(readFileSync3(corePackageJsonPath, "utf-8")));
|
|
1775
1925
|
pkg.scripts = {
|
|
1776
1926
|
...pkg.scripts,
|
|
@@ -1786,11 +1936,11 @@ var setupCoreProject = (projectDir) => {
|
|
|
1786
1936
|
};
|
|
1787
1937
|
|
|
1788
1938
|
// src/cli/lib/write-env.ts
|
|
1789
|
-
import { outputFileSync } from "fs-extra/esm";
|
|
1790
|
-
import { join as
|
|
1939
|
+
import { outputFileSync as outputFileSync2 } from "fs-extra/esm";
|
|
1940
|
+
import { join as join9 } from "path";
|
|
1791
1941
|
var writeEnv = (projectDir, envVars) => {
|
|
1792
|
-
|
|
1793
|
-
|
|
1942
|
+
outputFileSync2(
|
|
1943
|
+
join9(projectDir, "core", ".env.local"),
|
|
1794
1944
|
`${Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n")}
|
|
1795
1945
|
`
|
|
1796
1946
|
);
|
|
@@ -1801,41 +1951,41 @@ function getPlatformCheckCommand(command) {
|
|
|
1801
1951
|
const isWindows = process.platform === "win32";
|
|
1802
1952
|
return isWindows ? `where.exe ${command}` : `which ${command}`;
|
|
1803
1953
|
}
|
|
1804
|
-
function
|
|
1954
|
+
function parseChannelId2(value) {
|
|
1805
1955
|
const parsed = parseInt(value, 10);
|
|
1806
1956
|
if (Number.isNaN(parsed)) {
|
|
1807
|
-
throw new
|
|
1957
|
+
throw new InvalidArgumentError2(`"${value}" is not a valid channel ID (expected a number).`);
|
|
1808
1958
|
}
|
|
1809
1959
|
return parsed;
|
|
1810
1960
|
}
|
|
1811
1961
|
function parseEnvFlag(value, previous = {}) {
|
|
1812
1962
|
const eqIdx = value.indexOf("=");
|
|
1813
1963
|
if (eqIdx <= 0) {
|
|
1814
|
-
throw new
|
|
1964
|
+
throw new InvalidArgumentError2(`Expected KEY=VALUE, got "${value}".`);
|
|
1815
1965
|
}
|
|
1816
1966
|
const key = value.substring(0, eqIdx);
|
|
1817
1967
|
const val = value.substring(eqIdx + 1);
|
|
1818
1968
|
if (!val) {
|
|
1819
|
-
throw new
|
|
1969
|
+
throw new InvalidArgumentError2(`Expected KEY=VALUE with non-empty value, got "${value}".`);
|
|
1820
1970
|
}
|
|
1821
1971
|
return { ...previous, [key]: val };
|
|
1822
1972
|
}
|
|
1823
1973
|
async function handleChannelCreation(storeHash, accessToken, apiHost, cliApiOrigin) {
|
|
1824
|
-
const newChannelName = await
|
|
1974
|
+
const newChannelName = await input3({
|
|
1825
1975
|
message: "What would you like to name your new channel?"
|
|
1826
1976
|
});
|
|
1827
1977
|
const availableLocales = await getAvailableLocales(storeHash, accessToken, apiHost);
|
|
1828
|
-
const storefrontLocale = await
|
|
1978
|
+
const storefrontLocale = await select4({
|
|
1829
1979
|
message: "Which default language would you like to set for your channel?",
|
|
1830
1980
|
default: "en",
|
|
1831
1981
|
choices: availableLocales,
|
|
1832
1982
|
theme: {
|
|
1833
1983
|
style: {
|
|
1834
|
-
help: () =>
|
|
1984
|
+
help: () => colorize4("dim", "(Select locale from the list or start typing the name)")
|
|
1835
1985
|
}
|
|
1836
1986
|
}
|
|
1837
1987
|
});
|
|
1838
|
-
const shouldAddAdditionalLocales = await
|
|
1988
|
+
const shouldAddAdditionalLocales = await select4({
|
|
1839
1989
|
message: "Would you like to add additional languages?",
|
|
1840
1990
|
choices: [
|
|
1841
1991
|
{ name: "Yes", value: true },
|
|
@@ -1844,21 +1994,14 @@ async function handleChannelCreation(storeHash, accessToken, apiHost, cliApiOrig
|
|
|
1844
1994
|
});
|
|
1845
1995
|
let additionalLocales = [];
|
|
1846
1996
|
if (shouldAddAdditionalLocales) {
|
|
1847
|
-
const
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
if (selected.length > 4) {
|
|
1854
|
-
consola.warn("You can only select up to 4 additional languages. Please try again.");
|
|
1855
|
-
return pickLocales();
|
|
1856
|
-
}
|
|
1857
|
-
return selected;
|
|
1858
|
-
};
|
|
1859
|
-
additionalLocales = await pickLocales();
|
|
1997
|
+
const localeChoices = availableLocales.filter(({ value }) => value !== storefrontLocale).map(({ name, value }) => ({ name, value, description: value }));
|
|
1998
|
+
additionalLocales = await checkbox({
|
|
1999
|
+
message: "Which additional languages would you like to add to your channel?",
|
|
2000
|
+
choices: localeChoices,
|
|
2001
|
+
validate: (items) => items.length <= 4 || "You can only select up to 4 additional languages."
|
|
2002
|
+
});
|
|
1860
2003
|
}
|
|
1861
|
-
const shouldInstallSampleData = await
|
|
2004
|
+
const shouldInstallSampleData = await select4({
|
|
1862
2005
|
message: "Would you like to install sample data?",
|
|
1863
2006
|
choices: [
|
|
1864
2007
|
{ name: "Yes", value: true },
|
|
@@ -1876,23 +2019,13 @@ async function handleChannelCreation(storeHash, accessToken, apiHost, cliApiOrig
|
|
|
1876
2019
|
);
|
|
1877
2020
|
}
|
|
1878
2021
|
async function handleChannelSelection(storeHash, accessToken, apiHost) {
|
|
1879
|
-
const channelSortOrder = ["catalyst", "next", "bigcommerce"];
|
|
1880
2022
|
const channels = await fetchAvailableChannels(storeHash, accessToken, apiHost);
|
|
1881
|
-
const existingChannel = await
|
|
2023
|
+
const existingChannel = await select4({
|
|
1882
2024
|
message: "Which channel would you like to use?",
|
|
1883
|
-
choices: channels.
|
|
1884
|
-
const aIndex = channelSortOrder.indexOf(a.platform);
|
|
1885
|
-
const bIndex = channelSortOrder.indexOf(b.platform);
|
|
1886
|
-
if (aIndex === -1 && bIndex === -1) {
|
|
1887
|
-
return 0;
|
|
1888
|
-
}
|
|
1889
|
-
if (aIndex === -1) return 1;
|
|
1890
|
-
if (bIndex === -1) return -1;
|
|
1891
|
-
return aIndex - bIndex;
|
|
1892
|
-
}).map((ch) => ({
|
|
2025
|
+
choices: sortChannelsByPlatform(channels).map((ch) => ({
|
|
1893
2026
|
name: ch.name,
|
|
1894
2027
|
value: ch,
|
|
1895
|
-
description: `Channel Platform: ${
|
|
2028
|
+
description: `Channel Platform: ${channelPlatformLabel(ch.platform)}`
|
|
1896
2029
|
}))
|
|
1897
2030
|
});
|
|
1898
2031
|
return existingChannel.id;
|
|
@@ -1905,7 +2038,7 @@ async function setupProject(options) {
|
|
|
1905
2038
|
}
|
|
1906
2039
|
if (projectName) {
|
|
1907
2040
|
projectName = kebabCase(projectName);
|
|
1908
|
-
projectDir =
|
|
2041
|
+
projectDir = join10(options.projectDir, projectName);
|
|
1909
2042
|
if (pathExistsSync(projectDir)) {
|
|
1910
2043
|
consola.error(`${projectDir} already exists`);
|
|
1911
2044
|
process.exit(1);
|
|
@@ -1915,13 +2048,13 @@ async function setupProject(options) {
|
|
|
1915
2048
|
const validateProjectName = (i) => {
|
|
1916
2049
|
const formatted = kebabCase(i);
|
|
1917
2050
|
if (!formatted) return "Project name is required";
|
|
1918
|
-
const targetDir =
|
|
2051
|
+
const targetDir = join10(options.projectDir, formatted);
|
|
1919
2052
|
if (pathExistsSync(targetDir)) return `Destination '${targetDir}' already exists`;
|
|
1920
2053
|
projectName = formatted;
|
|
1921
2054
|
projectDir = targetDir;
|
|
1922
2055
|
return true;
|
|
1923
2056
|
};
|
|
1924
|
-
await
|
|
2057
|
+
await input3({
|
|
1925
2058
|
message: "What do you want to name your project directory?",
|
|
1926
2059
|
default: "my-catalyst-app",
|
|
1927
2060
|
validate: validateProjectName
|
|
@@ -1959,7 +2092,7 @@ Examples:
|
|
|
1959
2092
|
|
|
1960
2093
|
# Eagerly set up Commerce Hosting at create time
|
|
1961
2094
|
$ catalyst create --project-name my-store --hosting commerce`
|
|
1962
|
-
).option("--project-name <name>", "Name of your Catalyst project").option("--project-dir <dir>", "Directory in which to create your project", process.cwd()).addOption(storeHashOption()).addOption(accessTokenOption()).option("--channel-id <id>", "BigCommerce channel ID",
|
|
2095
|
+
).option("--project-name <name>", "Name of your Catalyst project").option("--project-dir <dir>", "Directory in which to create your project", process.cwd()).addOption(storeHashOption()).addOption(accessTokenOption()).option("--channel-id <id>", "BigCommerce channel ID", parseChannelId2).option("--storefront-token <token>", "BigCommerce storefront token").option(
|
|
1963
2096
|
"--gh-ref <ref>",
|
|
1964
2097
|
"Clone a specific ref from the source repository",
|
|
1965
2098
|
"@bigcommerce/catalyst-core@latest"
|
|
@@ -2034,7 +2167,7 @@ Examples:
|
|
|
2034
2167
|
}
|
|
2035
2168
|
let shouldCreateChannel;
|
|
2036
2169
|
if (eligibility.eligible) {
|
|
2037
|
-
shouldCreateChannel = await
|
|
2170
|
+
shouldCreateChannel = await select4({
|
|
2038
2171
|
message: "Would you like to create a new channel?",
|
|
2039
2172
|
choices: [
|
|
2040
2173
|
{ name: "Yes", value: true },
|
|
@@ -2116,24 +2249,26 @@ Examples:
|
|
|
2116
2249
|
throw error;
|
|
2117
2250
|
}
|
|
2118
2251
|
consola.success(`Created '${projectName}' at '${projectDir}'`);
|
|
2119
|
-
|
|
2120
|
-
consola.info(colorize3("yellow", ` cd ${projectName}/core && pnpm run dev`));
|
|
2252
|
+
const steps = [`cd ${projectName}/core && pnpm run dev`];
|
|
2121
2253
|
if (useCommerceHosting) {
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
"yellow",
|
|
2125
|
-
` Run 'cd ${projectName}/core && pnpm run deploy' when ready to deploy to Commerce Hosting.`
|
|
2126
|
-
)
|
|
2254
|
+
steps.push(
|
|
2255
|
+
`Run 'cd ${projectName}/core && pnpm run deploy' when ready to deploy to Commerce Hosting.`
|
|
2127
2256
|
);
|
|
2128
2257
|
}
|
|
2258
|
+
consola.log(
|
|
2259
|
+
`Next steps:
|
|
2260
|
+
|
|
2261
|
+
${steps.map((step) => ` ${colorize4("yellow", step)}`).join("\n")}`
|
|
2262
|
+
);
|
|
2129
2263
|
});
|
|
2130
2264
|
|
|
2131
2265
|
// src/cli/commands/deploy.ts
|
|
2266
|
+
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
2132
2267
|
import AdmZip from "adm-zip";
|
|
2133
2268
|
import { Command as Command5, Option as Option6 } from "commander";
|
|
2134
|
-
import { colorize as
|
|
2269
|
+
import { colorize as colorize5 } from "consola/utils";
|
|
2135
2270
|
import { access, readdir, readFile } from "fs/promises";
|
|
2136
|
-
import { dirname as dirname4, join as
|
|
2271
|
+
import { dirname as dirname4, join as join11 } from "path";
|
|
2137
2272
|
import yoctoSpinner4 from "yocto-spinner";
|
|
2138
2273
|
import { z as z10 } from "zod";
|
|
2139
2274
|
|
|
@@ -2153,38 +2288,6 @@ function getDeploymentErrorMessage(code) {
|
|
|
2153
2288
|
return ERROR_MESSAGES[code] ?? `Deployment failed with an unexpected error (code: ${code}). Please try again. If the issue persists, contact support.`;
|
|
2154
2289
|
}
|
|
2155
2290
|
|
|
2156
|
-
// src/cli/lib/env-config.ts
|
|
2157
|
-
var ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2158
|
-
var parseEnvAssignment = (input3) => {
|
|
2159
|
-
const separatorIndex = input3.indexOf("=");
|
|
2160
|
-
if (separatorIndex === -1) {
|
|
2161
|
-
throw new Error(`Invalid env var format: ${input3}. Expected format: KEY=VALUE`);
|
|
2162
|
-
}
|
|
2163
|
-
const key = input3.slice(0, separatorIndex).trim();
|
|
2164
|
-
const value = input3.slice(separatorIndex + 1).trim();
|
|
2165
|
-
if (!key || !value) {
|
|
2166
|
-
throw new Error(`Invalid env var format: ${input3}. Expected format: KEY=VALUE`);
|
|
2167
|
-
}
|
|
2168
|
-
if (!ENV_KEY_PATTERN.test(key)) {
|
|
2169
|
-
throw new Error(
|
|
2170
|
-
`Invalid env var name: ${key}. Names must start with a letter or underscore and contain only letters, numbers, and underscores.`
|
|
2171
|
-
);
|
|
2172
|
-
}
|
|
2173
|
-
return { key, value };
|
|
2174
|
-
};
|
|
2175
|
-
var getStoredEnv = (config2) => {
|
|
2176
|
-
return config2.get("env") ?? {};
|
|
2177
|
-
};
|
|
2178
|
-
var toDeploymentSecrets = (envVars) => {
|
|
2179
|
-
return Object.entries(envVars).map(([key, value]) => ({ type: "secret", key, value }));
|
|
2180
|
-
};
|
|
2181
|
-
var mergeDeploymentSecrets = (persisted, flagSecrets) => {
|
|
2182
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
2183
|
-
persisted.forEach((secret) => byKey.set(secret.key, secret));
|
|
2184
|
-
flagSecrets.forEach((secret) => byKey.set(secret.key, secret));
|
|
2185
|
-
return Array.from(byKey.values());
|
|
2186
|
-
};
|
|
2187
|
-
|
|
2188
2291
|
// src/cli/commands/deploy.ts
|
|
2189
2292
|
var stepsEnum = z10.enum([
|
|
2190
2293
|
"initializing",
|
|
@@ -2237,8 +2340,8 @@ var DeploymentStatusSchema = z10.object({
|
|
|
2237
2340
|
});
|
|
2238
2341
|
var generateBundleZip = async () => {
|
|
2239
2342
|
consola.info("Generating bundle...");
|
|
2240
|
-
const bigcommerceDir =
|
|
2241
|
-
const distDir =
|
|
2343
|
+
const bigcommerceDir = join11(process.cwd(), ".bigcommerce");
|
|
2344
|
+
const distDir = join11(process.cwd(), ".bigcommerce", "dist");
|
|
2242
2345
|
try {
|
|
2243
2346
|
await access(distDir);
|
|
2244
2347
|
} catch {
|
|
@@ -2248,7 +2351,7 @@ var generateBundleZip = async () => {
|
|
|
2248
2351
|
if (buildDirContents.length === 0) {
|
|
2249
2352
|
throw new Error(`Dist directory is empty: ${distDir}`);
|
|
2250
2353
|
}
|
|
2251
|
-
const outputZip =
|
|
2354
|
+
const outputZip = join11(bigcommerceDir, "bundle.zip");
|
|
2252
2355
|
const zip = new AdmZip();
|
|
2253
2356
|
zip.addLocalFolder(distDir, "output");
|
|
2254
2357
|
zip.writeZip(outputZip);
|
|
@@ -2280,7 +2383,7 @@ var generateUploadSignature = async (storeHash, accessToken, apiHost) => {
|
|
|
2280
2383
|
};
|
|
2281
2384
|
var uploadBundleZip = async (uploadUrl) => {
|
|
2282
2385
|
consola.info("Uploading bundle...");
|
|
2283
|
-
const zipPath =
|
|
2386
|
+
const zipPath = join11(process.cwd(), ".bigcommerce", "bundle.zip");
|
|
2284
2387
|
const fileBuffer = await readFile(zipPath);
|
|
2285
2388
|
const response = await fetch(uploadUrl, {
|
|
2286
2389
|
method: "PUT",
|
|
@@ -2391,7 +2494,7 @@ var getDeploymentStatus = async (deploymentUuid, storeHash, accessToken, apiHost
|
|
|
2391
2494
|
spinner.success("Deployment completed successfully.");
|
|
2392
2495
|
if (deploymentHostname) {
|
|
2393
2496
|
consola.success(
|
|
2394
|
-
`View your deployment at: ${
|
|
2497
|
+
`View your deployment at: ${colorize5("blue", `https://${deploymentHostname}`)}`
|
|
2395
2498
|
);
|
|
2396
2499
|
}
|
|
2397
2500
|
return deploymentHostname;
|
|
@@ -2488,10 +2591,10 @@ Example:
|
|
|
2488
2591
|
consola.success(`Linked project "${selected.name}".`);
|
|
2489
2592
|
}
|
|
2490
2593
|
if (!getProjectState().isTransformed) {
|
|
2491
|
-
const shouldSetup = await
|
|
2492
|
-
"Your project is not yet set up for Commerce Hosting deployments. Would you like to run the Commerce Hosting setup now?",
|
|
2493
|
-
|
|
2494
|
-
);
|
|
2594
|
+
const shouldSetup = await confirm3({
|
|
2595
|
+
message: "Your project is not yet set up for Commerce Hosting deployments. Would you like to run the Commerce Hosting setup now?",
|
|
2596
|
+
default: true
|
|
2597
|
+
});
|
|
2495
2598
|
if (!shouldSetup) {
|
|
2496
2599
|
consola.info("When you're ready to deploy, re-run `catalyst deploy` to complete setup.");
|
|
2497
2600
|
process.exit(0);
|
|
@@ -2504,7 +2607,7 @@ Example:
|
|
|
2504
2607
|
await cleanupCloudflareIncompatibilities(dirname4(process.cwd()));
|
|
2505
2608
|
}
|
|
2506
2609
|
if (options.prebuilt) {
|
|
2507
|
-
const distDir =
|
|
2610
|
+
const distDir = join11(process.cwd(), ".bigcommerce", "dist");
|
|
2508
2611
|
try {
|
|
2509
2612
|
await access(distDir);
|
|
2510
2613
|
} catch {
|
|
@@ -2646,7 +2749,7 @@ var env = new Command6("env").configureHelp({ showGlobalOptions: true }).descrip
|
|
|
2646
2749
|
|
|
2647
2750
|
// src/cli/commands/logs.ts
|
|
2648
2751
|
import { Command as Command7, Option as Option7 } from "commander";
|
|
2649
|
-
import { colorize as
|
|
2752
|
+
import { colorize as colorize6 } from "consola/utils";
|
|
2650
2753
|
import { z as z11 } from "zod";
|
|
2651
2754
|
var telemetry = new Telemetry();
|
|
2652
2755
|
var DEFAULT_CONNECTION_TTL_MS = 1 * 60 * 1e3;
|
|
@@ -2688,7 +2791,7 @@ var formatLogEvent = (event, format) => {
|
|
|
2688
2791
|
logEntries.forEach((entry) => {
|
|
2689
2792
|
const msg = formatMessages(entry.messages);
|
|
2690
2793
|
const level = entry.level.toUpperCase();
|
|
2691
|
-
const coloredLevel =
|
|
2794
|
+
const coloredLevel = colorize6(LEVEL_COLORS[level] ?? "white", level);
|
|
2692
2795
|
switch (format) {
|
|
2693
2796
|
case "short":
|
|
2694
2797
|
consola.log(msg);
|
|
@@ -2870,8 +2973,9 @@ Example:
|
|
|
2870
2973
|
var logs = new Command7("logs").configureHelp({ showGlobalOptions: true }).description("View logs from your deployed application.").addCommand(tail, { isDefault: true }).addCommand(query);
|
|
2871
2974
|
|
|
2872
2975
|
// src/cli/commands/project.ts
|
|
2976
|
+
import { confirm as confirm4, input as input4, select as select5 } from "@inquirer/prompts";
|
|
2873
2977
|
import { Command as Command8 } from "commander";
|
|
2874
|
-
import { colorize as
|
|
2978
|
+
import { colorize as colorize7 } from "consola/utils";
|
|
2875
2979
|
import { dirname as dirname5 } from "path";
|
|
2876
2980
|
async function offerCommerceHostingSetup(projectUuid, credentials) {
|
|
2877
2981
|
const projectDir = dirname5(process.cwd());
|
|
@@ -2879,10 +2983,10 @@ async function offerCommerceHostingSetup(projectUuid, credentials) {
|
|
|
2879
2983
|
await cleanupCloudflareIncompatibilities(projectDir);
|
|
2880
2984
|
return;
|
|
2881
2985
|
}
|
|
2882
|
-
const shouldSetup = await
|
|
2883
|
-
"Your project has been linked, but is not fully set up for Commerce Hosting deployments yet. Would you like to run the setup now?",
|
|
2884
|
-
|
|
2885
|
-
);
|
|
2986
|
+
const shouldSetup = await confirm4({
|
|
2987
|
+
message: "Your project has been linked, but is not fully set up for Commerce Hosting deployments yet. Would you like to run the setup now?",
|
|
2988
|
+
default: true
|
|
2989
|
+
});
|
|
2886
2990
|
if (!shouldSetup) return;
|
|
2887
2991
|
await setupCommerceHosting({
|
|
2888
2992
|
projectDir,
|
|
@@ -2911,18 +3015,14 @@ Example:
|
|
|
2911
3015
|
return;
|
|
2912
3016
|
}
|
|
2913
3017
|
const linkedProjectUuid = config2.get("projectUuid");
|
|
2914
|
-
projects.
|
|
2915
|
-
const marker = p.uuid === linkedProjectUuid ? ` ${
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
}
|
|
2920
|
-
p.deployment_hostnames.forEach((hostname) => {
|
|
2921
|
-
consola.log(` ${colorize6("blue", `https://${hostname}`)}`);
|
|
2922
|
-
});
|
|
2923
|
-
}
|
|
2924
|
-
consola.log("");
|
|
3018
|
+
const projectList = projects.map((p) => {
|
|
3019
|
+
const marker = p.uuid === linkedProjectUuid ? ` ${colorize7("green", "[linked]")}` : "";
|
|
3020
|
+
const hostnames = p.deployment_hostnames.length === 0 ? [" (not deployed)"] : p.deployment_hostnames.map(
|
|
3021
|
+
(hostname) => ` ${colorize7("blue", `https://${hostname}`)}`
|
|
3022
|
+
);
|
|
3023
|
+
return [`${p.name} (${p.uuid})${marker}`, ...hostnames].join("\n");
|
|
2925
3024
|
});
|
|
3025
|
+
consola.log(projectList.join("\n\n"));
|
|
2926
3026
|
process.exit(0);
|
|
2927
3027
|
});
|
|
2928
3028
|
var create2 = new Command8("create").configureHelp({ showGlobalOptions: true }).description(
|
|
@@ -2959,9 +3059,7 @@ Example:
|
|
|
2959
3059
|
}
|
|
2960
3060
|
}
|
|
2961
3061
|
await getTelemetry().identify(storeHash);
|
|
2962
|
-
const newProjectName = await
|
|
2963
|
-
type: "text"
|
|
2964
|
-
});
|
|
3062
|
+
const newProjectName = await input4({ message: "Enter a name for the new project:" });
|
|
2965
3063
|
const data = await createProject(newProjectName, storeHash, accessToken, options.apiHost);
|
|
2966
3064
|
consola.success(`Project "${data.name}" created successfully.`);
|
|
2967
3065
|
consola.start("Writing project UUID to .bigcommerce/project.json...");
|
|
@@ -2971,7 +3069,7 @@ Example:
|
|
|
2971
3069
|
consola.success("Project UUID written to .bigcommerce/project.json.");
|
|
2972
3070
|
process.exit(0);
|
|
2973
3071
|
});
|
|
2974
|
-
var
|
|
3072
|
+
var link2 = new Command8("link").configureHelp({ showGlobalOptions: true }).description(
|
|
2975
3073
|
"Link your local Catalyst project to a BigCommerce infrastructure project. You can provide a project UUID directly, or fetch and select from available projects using your store credentials."
|
|
2976
3074
|
).addHelpText(
|
|
2977
3075
|
"after",
|
|
@@ -3051,21 +3149,17 @@ Examples:
|
|
|
3051
3149
|
return;
|
|
3052
3150
|
}
|
|
3053
3151
|
const linkedProjectUuid = config2.get("projectUuid");
|
|
3054
|
-
const selected = await
|
|
3055
|
-
"Select a project to delete (Press <enter> to select).",
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
],
|
|
3066
|
-
cancel: "reject"
|
|
3067
|
-
}
|
|
3068
|
-
);
|
|
3152
|
+
const selected = await select5({
|
|
3153
|
+
message: "Select a project to delete (Press <enter> to select).",
|
|
3154
|
+
choices: [
|
|
3155
|
+
...projects.map((p) => ({
|
|
3156
|
+
name: p.uuid === linkedProjectUuid ? `${p.name} ${colorize7("green", "[linked]")}` : p.name,
|
|
3157
|
+
value: p.uuid,
|
|
3158
|
+
description: p.uuid
|
|
3159
|
+
})),
|
|
3160
|
+
{ name: "Cancel", value: "cancel", description: "Exit without deleting any project." }
|
|
3161
|
+
]
|
|
3162
|
+
});
|
|
3069
3163
|
if (selected === "cancel") {
|
|
3070
3164
|
consola.info("Aborted. No project was deleted.");
|
|
3071
3165
|
process.exit(0);
|
|
@@ -3080,10 +3174,10 @@ Examples:
|
|
|
3080
3174
|
}
|
|
3081
3175
|
if (!options.force) {
|
|
3082
3176
|
const label = targetName ? `"${targetName}" (${targetUuid})` : targetUuid;
|
|
3083
|
-
const confirmed = await
|
|
3084
|
-
`Are you sure you want to delete project ${label}? This action is irreversible and will permanently destroy the project and all of its data.`,
|
|
3085
|
-
|
|
3086
|
-
);
|
|
3177
|
+
const confirmed = await confirm4({
|
|
3178
|
+
message: `Are you sure you want to delete project ${label}? This action is irreversible and will permanently destroy the project and all of its data.`,
|
|
3179
|
+
default: false
|
|
3180
|
+
});
|
|
3087
3181
|
if (!confirmed) {
|
|
3088
3182
|
consola.info("Aborted. No project was deleted.");
|
|
3089
3183
|
process.exit(0);
|
|
@@ -3099,13 +3193,13 @@ Examples:
|
|
|
3099
3193
|
}
|
|
3100
3194
|
process.exit(0);
|
|
3101
3195
|
});
|
|
3102
|
-
var project = new Command8("project").configureHelp({ showGlobalOptions: true }).description("Manage your BigCommerce infrastructure project.").addCommand(create2).addCommand(list2).addCommand(
|
|
3196
|
+
var project = new Command8("project").configureHelp({ showGlobalOptions: true }).description("Manage your BigCommerce infrastructure project.").addCommand(create2).addCommand(list2).addCommand(link2).addCommand(del);
|
|
3103
3197
|
|
|
3104
3198
|
// src/cli/commands/start.ts
|
|
3105
3199
|
import { Command as Command9 } from "commander";
|
|
3106
3200
|
import { execa as execa2 } from "execa";
|
|
3107
3201
|
import { existsSync as existsSync4, lstatSync as lstatSync2, symlinkSync as symlinkSync2 } from "fs";
|
|
3108
|
-
import { join as
|
|
3202
|
+
import { join as join12, relative } from "path";
|
|
3109
3203
|
var start = new Command9("start").configureHelp({ showGlobalOptions: true }).description(
|
|
3110
3204
|
"Start a local preview of your Catalyst storefront using the OpenNext Cloudflare adapter."
|
|
3111
3205
|
).addHelpText(
|
|
@@ -3123,11 +3217,11 @@ Example:
|
|
|
3123
3217
|
});
|
|
3124
3218
|
return;
|
|
3125
3219
|
}
|
|
3126
|
-
const envLocal =
|
|
3127
|
-
const devVars =
|
|
3220
|
+
const envLocal = join12(process.cwd(), ".env.local");
|
|
3221
|
+
const devVars = join12(process.cwd(), ".bigcommerce", ".dev.vars");
|
|
3128
3222
|
if (existsSync4(envLocal)) {
|
|
3129
3223
|
if (!existsSync4(devVars)) {
|
|
3130
|
-
const target = relative(
|
|
3224
|
+
const target = relative(join12(process.cwd(), ".bigcommerce"), envLocal);
|
|
3131
3225
|
symlinkSync2(target, devVars);
|
|
3132
3226
|
consola.success("Symlinked .bigcommerce/.dev.vars \u2192 .env.local");
|
|
3133
3227
|
} else if (!lstatSync2(devVars).isSymbolicLink()) {
|
|
@@ -3147,7 +3241,7 @@ Example:
|
|
|
3147
3241
|
"opennextjs-cloudflare",
|
|
3148
3242
|
"preview",
|
|
3149
3243
|
"--config",
|
|
3150
|
-
|
|
3244
|
+
join12(".bigcommerce", "wrangler.jsonc")
|
|
3151
3245
|
],
|
|
3152
3246
|
{
|
|
3153
3247
|
stdio: "inherit",
|
|
@@ -3158,7 +3252,7 @@ Example:
|
|
|
3158
3252
|
|
|
3159
3253
|
// src/cli/commands/telemetry.ts
|
|
3160
3254
|
import { Argument, Command as Command10, Option as Option8 } from "commander";
|
|
3161
|
-
import { colorize as
|
|
3255
|
+
import { colorize as colorize8 } from "consola/utils";
|
|
3162
3256
|
var telemetryService = getTelemetry();
|
|
3163
3257
|
var isEnabled = telemetryService.isEnabled();
|
|
3164
3258
|
var telemetry2 = new Command10("telemetry").configureHelp({ showGlobalOptions: true }).description(
|
|
@@ -3192,7 +3286,7 @@ Examples:
|
|
|
3192
3286
|
consola.info("Catalyst CLI Telemetry\n");
|
|
3193
3287
|
}
|
|
3194
3288
|
consola.info(
|
|
3195
|
-
`Status: ${
|
|
3289
|
+
`Status: ${colorize8("bold", isEnabled ? colorize8("green", "Enabled") : colorize8("red", "Disabled"))}`
|
|
3196
3290
|
);
|
|
3197
3291
|
if (!isEnabled) {
|
|
3198
3292
|
consola.info(
|
|
@@ -3272,7 +3366,7 @@ if (!process.env.CATALYST_STORE_HASH && process.env.BIGCOMMERCE_STORE_HASH) {
|
|
|
3272
3366
|
process.env.CATALYST_STORE_HASH = process.env.BIGCOMMERCE_STORE_HASH;
|
|
3273
3367
|
}
|
|
3274
3368
|
var program = new Command12();
|
|
3275
|
-
consola.log(
|
|
3369
|
+
consola.log(colorize9("cyanBright", `\u25E2 ${package_default.name} v${package_default.version}
|
|
3276
3370
|
`));
|
|
3277
3371
|
program.name(package_default.name).version(package_default.version).summary("CLI tool for Catalyst development").description(
|
|
3278
3372
|
"CLI tool for Catalyst development.\n\nConfiguration priority: flags > env file (--env-path) > process.env > .env.local (auto-loaded from cwd) > .bigcommerce/project.json.\n\nCATALYST_STORE_HASH falls back to BIGCOMMERCE_STORE_HASH if unset.\n\nRun `catalyst <command> --help` for details on a specific command."
|
|
@@ -3293,7 +3387,7 @@ program.name(package_default.name).version(package_default.version).summary("CLI
|
|
|
3293
3387
|
const message = errCode === "ENOENT" ? `Env file not found: ${envFilePath}` : `Failed to load --env-path ${value}: ${result.error.message}`;
|
|
3294
3388
|
throw new Error(message);
|
|
3295
3389
|
}
|
|
3296
|
-
consola.log(
|
|
3390
|
+
consola.log(colorize9("cyanBright", `Loaded environment variables from ${envFilePath}
|
|
3297
3391
|
`));
|
|
3298
3392
|
}
|
|
3299
3393
|
return value;
|