@bigcommerce/create-catalyst 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -53,12 +53,12 @@ var __async = (__this, __arguments, generator) => {
53
53
 
54
54
  // src/index.ts
55
55
  import { program } from "@commander-js/extra-typings";
56
- import chalk8 from "chalk";
56
+ import chalk7 from "chalk";
57
57
 
58
58
  // package.json
59
59
  var package_default = {
60
60
  name: "@bigcommerce/create-catalyst",
61
- version: "0.12.0",
61
+ version: "0.13.0",
62
62
  type: "module",
63
63
  bin: "bin/index.cjs",
64
64
  files: [
@@ -77,209 +77,48 @@ var package_default = {
77
77
  },
78
78
  dependencies: {
79
79
  "@commander-js/extra-typings": "^12.1.0",
80
- "@inquirer/prompts": "^5.5.0",
80
+ "@inquirer/prompts": "^7.0.0",
81
81
  chalk: "^5.3.0",
82
82
  commander: "^12.1.0",
83
83
  dotenv: "^16.4.5",
84
84
  "fs-extra": "^11.2.0",
85
85
  giget: "^1.2.3",
86
86
  "lodash.kebabcase": "^4.1.1",
87
- "lodash.merge": "^4.6.2",
88
- nypm: "^0.3.11",
87
+ nypm: "^0.3.12",
89
88
  ora: "^8.1.0",
90
89
  semver: "^7.6.3",
91
90
  zod: "^3.23.8",
92
- "zod-validation-error": "^3.3.1"
91
+ "zod-validation-error": "^3.4.0"
93
92
  },
94
93
  devDependencies: {
95
94
  "@bigcommerce/eslint-config": "^2.9.1",
96
95
  "@bigcommerce/eslint-config-catalyst": "workspace:^",
97
- "@swc/core": "^1.7.24",
96
+ "@swc/core": "^1.7.26",
98
97
  "@swc/jest": "^0.2.36",
99
98
  "@types/fs-extra": "^11.0.4",
100
- "@types/jest": "^29.5.12",
99
+ "@types/jest": "^29.5.13",
101
100
  "@types/lodash.kebabcase": "^4.1.9",
102
- "@types/lodash.merge": "^4.6.9",
103
- "@types/node": "^20.16.5",
101
+ "@types/node": "^20.16.10",
104
102
  "@types/prompts": "^2.4.9",
105
103
  "@types/semver": "^7.5.8",
106
- eslint: "^8.57.0",
104
+ eslint: "^8.57.1",
107
105
  jest: "^29.7.0",
108
- msw: "^2.4.4",
106
+ msw: "^2.4.9",
109
107
  prettier: "^3.3.3",
110
- tsup: "^8.2.4",
111
- typescript: "^5.5.4"
108
+ tsup: "^8.3.0",
109
+ typescript: "^5.6.2"
112
110
  }
113
111
  };
114
112
 
115
113
  // src/commands/create.ts
116
- import { Command as Command2, Option } from "@commander-js/extra-typings";
114
+ import { Command, Option } from "@commander-js/extra-typings";
117
115
  import { input, select as select2 } from "@inquirer/prompts";
118
- import chalk6 from "chalk";
119
- import { exec as execCallback2 } from "child_process";
116
+ import chalk5 from "chalk";
117
+ import { execSync as execSync4 } from "child_process";
120
118
  import { pathExistsSync } from "fs-extra/esm";
121
- import kebabCase2 from "lodash.kebabcase";
122
- import { join as join4 } from "path";
123
- import { promisify as promisify3 } from "util";
124
- import { z as z6 } from "zod";
125
-
126
- // src/utils/apply-integration.ts
127
- import { exec as execCallback } from "child_process";
128
- import { readJsonSync } from "fs-extra/esm";
129
- import { downloadTemplate } from "giget";
130
- import { addDependency, addDevDependency } from "nypm";
131
- import { join } from "path";
132
- import { promisify as promisify2 } from "util";
133
-
134
- // src/commands/integration.ts
135
- import { Command } from "@commander-js/extra-typings";
136
- import { exec as execCb } from "child_process";
137
- import { parse } from "dotenv";
138
- import { outputFileSync, writeJsonSync } from "fs-extra/esm";
139
119
  import kebabCase from "lodash.kebabcase";
140
- import { coerce, compare } from "semver";
141
- import { promisify } from "util";
142
- import { z } from "zod";
143
- var exec = promisify(execCb);
144
- var ManifestSchema = z.object({
145
- name: z.string(),
146
- dependencies: z.object({ add: z.array(z.string()) }),
147
- devDependencies: z.object({ add: z.array(z.string()) }),
148
- environmentVariables: z.array(z.string())
149
- });
150
- var integration = new Command("integration").argument("<integration-name>", "Formatted name of the integration").option("--commit-hash <hash>", "Override integration source branch with a specific commit hash").action((integrationNameRaw, options) => __async(void 0, null, function* () {
151
- const integrationName = z.string().transform(kebabCase).parse(integrationNameRaw);
152
- const manifest = {
153
- name: integrationName,
154
- dependencies: { add: [] },
155
- devDependencies: { add: [] },
156
- environmentVariables: []
157
- };
158
- yield exec("git fetch --tags");
159
- const { stdout: headRefStdOut } = yield exec("git rev-parse --abbrev-ref HEAD");
160
- let [sourceRef] = headRefStdOut.split("\n");
161
- if (options.commitHash) {
162
- sourceRef = options.commitHash;
163
- }
164
- const { stdout: catalystTags } = yield exec("git tag --list @bigcommerce/catalyst-core@\\*");
165
- const [latestCoreTag] = catalystTags.split("\n").filter(Boolean).sort((a, b) => {
166
- const versionA = coerce(a.replace("@bigcommerce/catalyst-core@", ""));
167
- const versionB = coerce(b.replace("@bigcommerce/catalyst-core@", ""));
168
- if (versionA && versionB) {
169
- return compare(versionA, versionB);
170
- }
171
- return 0;
172
- }).reverse();
173
- const PackageDependenciesSchema = z.object({
174
- dependencies: z.object({}).passthrough(),
175
- devDependencies: z.object({}).passthrough()
176
- });
177
- const getPackageDeps = (ref) => __async(void 0, null, function* () {
178
- const { stdout } = yield exec(`git show ${ref}:core/package.json`);
179
- return PackageDependenciesSchema.parse(JSON.parse(stdout));
180
- });
181
- const integrationJson = yield getPackageDeps(sourceRef);
182
- const latestCoreTagJson = yield getPackageDeps(latestCoreTag);
183
- const diffObjectKeys = (a, b) => {
184
- return Object.keys(a).filter((key) => !Object.keys(b).includes(key));
185
- };
186
- manifest.dependencies.add = diffObjectKeys(
187
- integrationJson.dependencies,
188
- latestCoreTagJson.dependencies
189
- );
190
- manifest.devDependencies.add = diffObjectKeys(
191
- integrationJson.devDependencies,
192
- latestCoreTagJson.devDependencies
193
- );
194
- const { stdout: latestCoreEnv } = yield exec(`git show ${latestCoreTag}:core/.env.example`);
195
- const { stdout: integrationEnv } = yield exec(`git show ${sourceRef}:core/.env.example`);
196
- manifest.environmentVariables = diffObjectKeys(parse(integrationEnv), parse(latestCoreEnv));
197
- const { stdout: integrationDiff } = yield exec(
198
- `git diff ${latestCoreTag}...${sourceRef} -- ':(exclude)core/package.json' ':(exclude)pnpm-lock.yaml'`
199
- );
200
- outputFileSync(`integrations/${integrationName}/integration.patch`, integrationDiff);
201
- writeJsonSync(`integrations/${integrationName}/manifest.json`, manifest, {
202
- spaces: 2
203
- });
204
- console.log("Integration created successfully.");
205
- }));
206
-
207
- // src/utils/spinner.ts
208
- import { oraPromise } from "ora";
209
- var spinner = (action, oraOpts) => __async(void 0, null, function* () {
210
- return oraPromise(action, __spreadValues({
211
- spinner: "triangle"
212
- }, oraOpts)).catch(() => process.exit(1));
213
- });
214
-
215
- // src/utils/apply-integration.ts
216
- var exec2 = promisify2(execCallback);
217
- function applyIntegration(_0, _1) {
218
- return __async(this, arguments, function* (integration2, { projectDir, packageManager }) {
219
- if (!integration2) {
220
- return;
221
- }
222
- const integrationDir = join(projectDir, "integrations", integration2);
223
- yield spinner(
224
- downloadTemplate(`github:bigcommerce/catalyst/integrations/${integration2}#main`, {
225
- dir: integrationDir,
226
- offline: false
227
- }),
228
- {
229
- text: `Cloning ${integration2} integration...`,
230
- successText: `${integration2} integration cloned successfully`,
231
- failText: (err) => `Failed to clone ${integration2} integration: ${err.message}`
232
- }
233
- );
234
- try {
235
- readJsonSync(join(integrationDir, "manifest.json"));
236
- } catch (e) {
237
- console.error(
238
- `
239
- No manifest.json found in the ${integration2} integration folder. Please check that the integration exists in the Catalyst monorepo: https://github.com/bigcommerce/catalyst`
240
- );
241
- return;
242
- }
243
- const manifest = ManifestSchema.parse(readJsonSync(join(integrationDir, "manifest.json")));
244
- if (manifest.dependencies.add.length) {
245
- yield spinner(
246
- addDependency(manifest.dependencies.add, {
247
- cwd: projectDir,
248
- silent: true,
249
- packageManager
250
- }),
251
- {
252
- text: "Installing integration dependencies...",
253
- successText: "Integration dependencies installed successfully",
254
- failText: (err) => `Failed to install dependencies: ${err.message}`
255
- }
256
- );
257
- }
258
- if (manifest.devDependencies.add.length) {
259
- yield spinner(
260
- addDevDependency(manifest.devDependencies.add, {
261
- cwd: projectDir,
262
- silent: true,
263
- packageManager
264
- }),
265
- {
266
- text: "Installing integration development dependencies...",
267
- successText: "Integration development dependencies installed successfully",
268
- failText: (err) => `Failed to install integration development dependencies: ${err.message}`
269
- }
270
- );
271
- }
272
- yield spinner(
273
- exec2(`git apply -p2 ${join(integrationDir, "integration.patch")}`, { cwd: projectDir }),
274
- {
275
- text: "Applying integration patch...",
276
- successText: "Integration patch applied successfully",
277
- failText: (err) => `Failed to apply integration patch: ${err.message}`
278
- }
279
- );
280
- console.log("\nIntegration applied successfully! Feel free to delete the `integrations` folder.");
281
- });
282
- }
120
+ import { join as join2 } from "path";
121
+ import { z as z3 } from "zod";
283
122
 
284
123
  // src/utils/check-storefront-limit.ts
285
124
  import chalk from "chalk";
@@ -310,106 +149,97 @@ var checkStorefrontLimit = (channels, storeInfo) => {
310
149
  };
311
150
 
312
151
  // src/utils/clone-catalyst.ts
313
- import chalk2 from "chalk";
314
- import { readFile, writeFile } from "fs/promises";
315
- import { ensureDir, readJsonSync as readJsonSync2, removeSync, writeJsonSync as writeJsonSync2 } from "fs-extra/esm";
316
- import { downloadTemplate as downloadTemplate2 } from "giget";
317
- import merge from "lodash.merge";
318
- import { join as join2 } from "path";
319
- import * as z2 from "zod";
320
- var cloneCatalyst = (_0) => __async(void 0, [_0], function* ({
321
- codeEditor,
322
- includeFunctionalTests,
323
- projectDir,
324
- projectName,
325
- ghRef = "main"
326
- }) {
327
- var _a;
328
- yield spinner(
329
- downloadTemplate2(`github:bigcommerce/catalyst/core#${ghRef}`, {
330
- dir: projectDir,
331
- offline: false
332
- }),
333
- {
334
- text: "Cloning Catalyst template...",
335
- successText: "Catalyst template cloned successfully",
336
- failText: (err) => chalk2.red(`Failed to clone Catalyst template: ${err.message}`)
152
+ import { execSync as execSync3 } from "child_process";
153
+
154
+ // src/utils/checkout-ref.ts
155
+ import { execSync } from "child_process";
156
+
157
+ // src/utils/is-exec-exception.ts
158
+ function isExecException(error) {
159
+ return typeof error === "object" && error !== null && "stdout" in error && "stderr" in error;
160
+ }
161
+
162
+ // src/utils/checkout-ref.ts
163
+ function checkoutRef(repoDir, ref) {
164
+ try {
165
+ execSync(`git checkout ${ref}`, {
166
+ cwd: repoDir,
167
+ stdio: "inherit",
168
+ encoding: "utf8"
169
+ });
170
+ console.log(`Checked out ref ${ref} successfully.`);
171
+ } catch (error) {
172
+ if (isExecException(error)) {
173
+ const stderr = error.stderr ? error.stderr.toString() : "";
174
+ if (stderr.includes(`fatal: reference is not a tree: ${ref}`) || stderr.includes(`fatal: ambiguous argument '${ref}'`) || stderr.includes(`unknown revision or path not in the working tree`)) {
175
+ console.error(`Ref '${ref}' not found in the repository.`);
176
+ } else {
177
+ console.error(`Error checking out ref '${ref}':`, stderr.trim());
178
+ }
179
+ } else if (error instanceof Error) {
180
+ console.error(`Error checking out ref '${ref}':`, error.message);
181
+ } else {
182
+ console.error(`Unknown error occurred while checking out ref '${ref}'.`);
337
183
  }
338
- );
339
- switch (codeEditor) {
340
- case "vscode":
341
- yield ensureDir(join2(projectDir, ".vscode"));
342
- writeJsonSync2(
343
- join2(projectDir, ".vscode/settings.json"),
344
- { "typescript.tsdk": "node_modules/typescript/lib" },
345
- { spaces: 2 }
346
- );
347
- break;
348
- default:
349
- break;
350
- }
351
- const packageJson = z2.object({
352
- name: z2.string(),
353
- description: z2.string(),
354
- version: z2.string(),
355
- scripts: z2.object({}).passthrough().optional(),
356
- dependencies: z2.object({}).passthrough(),
357
- devDependencies: z2.object({}).passthrough()
358
- }).passthrough().parse(
359
- merge({}, readJsonSync2(join2(projectDir, "package.json")), {
360
- name: projectName,
361
- description: ""
362
- })
363
- );
364
- delete packageJson.dependencies["@bigcommerce/catalyst-client"];
365
- delete packageJson.devDependencies["@bigcommerce/eslint-config-catalyst"];
366
- if (!includeFunctionalTests) {
367
- delete packageJson.devDependencies["@faker-js/faker"];
368
- delete packageJson.devDependencies["@playwright/test"];
369
- }
370
- writeJsonSync2(join2(projectDir, "package.json"), packageJson, { spaces: 2 });
371
- if (!includeFunctionalTests) {
372
- const tsConfigJson = z2.object({
373
- include: z2.array(z2.string()).optional()
374
- }).passthrough().parse(readJsonSync2(join2(projectDir, "tsconfig.json")));
375
- tsConfigJson.include = (_a = tsConfigJson.include) == null ? void 0 : _a.filter(
376
- (include) => !["tests/**/*", "playwright.config.ts"].includes(include)
377
- );
378
- writeJsonSync2(join2(projectDir, "tsconfig.json"), tsConfigJson, { spaces: 2 });
379
- }
380
- if (!includeFunctionalTests) {
381
- const eslint = (yield readFile(join2(projectDir, ".eslintrc.cjs"), { encoding: "utf-8" })).replace(/['"]playwright-report\/\*\*['"],?/, "").replace(/['"]test-results\/\*\*['"],?/, "");
382
- yield writeFile(join2(projectDir, ".eslintrc.cjs"), eslint);
383
- removeSync(join2(projectDir, "tests"));
384
- removeSync(join2(projectDir, "playwright.config.ts"));
184
+ process.exit(1);
385
185
  }
386
- });
186
+ }
387
187
 
388
- // src/utils/get-latest-core-tag.ts
389
- import * as z3 from "zod";
390
- var getLatestCoreTag = () => __async(void 0, null, function* () {
391
- const rawPackageJsonUrl = "https://raw.githubusercontent.com/bigcommerce/catalyst/main/core/package.json";
392
- const response = yield fetch(rawPackageJsonUrl);
188
+ // src/utils/has-github-ssh.ts
189
+ import { execSync as execSync2 } from "child_process";
190
+ function hasGitHubSSH() {
393
191
  try {
394
- const { version } = z3.object({ version: z3.string() }).parse(yield response.json());
395
- return `@bigcommerce/catalyst-core@${version}`;
396
- } catch (e) {
397
- throw new Error("Unable to determine the latest valid Catalyst release");
192
+ const output = execSync2("ssh -T git@github.com", {
193
+ encoding: "utf8",
194
+ stdio: "pipe"
195
+ }).toString();
196
+ return output.includes("successfully authenticated");
197
+ } catch (error) {
198
+ if (isExecException(error)) {
199
+ const stdout = error.stdout ? error.stdout.toString() : "";
200
+ const stderr = error.stderr ? error.stderr.toString() : "";
201
+ const combinedOutput = stdout + stderr;
202
+ if (combinedOutput.includes("successfully authenticated")) {
203
+ return true;
204
+ }
205
+ }
206
+ return false;
398
207
  }
399
- });
208
+ }
209
+
210
+ // src/utils/clone-catalyst.ts
211
+ var cloneCatalyst = ({
212
+ projectName,
213
+ projectDir,
214
+ ghRef
215
+ }) => {
216
+ const repositoryName = "bigcommerce/catalyst";
217
+ const useSSH = hasGitHubSSH();
218
+ console.log(`Cloning ${repositoryName} using ${useSSH ? "SSH" : "HTTPS"}...
219
+ `);
220
+ const cloneCommand = `git clone ${useSSH ? `git@github.com:${repositoryName}` : `https://github.com/${repositoryName}`}.git${projectName ? ` ${projectName}` : ""}`;
221
+ execSync3(cloneCommand, { stdio: "inherit" });
222
+ console.log();
223
+ execSync3("git remote rename origin upstream", { cwd: projectDir, stdio: "inherit" });
224
+ console.log();
225
+ if (ghRef) {
226
+ checkoutRef(projectDir, ghRef);
227
+ console.log();
228
+ }
229
+ };
400
230
 
401
231
  // src/utils/https.ts
402
- import chalk3 from "chalk";
403
- import { z as z5 } from "zod";
232
+ import chalk2 from "chalk";
233
+ import { z as z2 } from "zod";
404
234
 
405
235
  // src/utils/parse.ts
406
- import * as z4 from "zod";
236
+ import * as z from "zod";
407
237
  import { fromZodError } from "zod-validation-error";
408
- var parse2 = (data, schema) => {
238
+ var parse = (data, schema) => {
409
239
  try {
410
240
  return schema.parse(data);
411
241
  } catch (error) {
412
- if (error instanceof z4.ZodError) {
242
+ if (error instanceof z.ZodError) {
413
243
  console.error(fromZodError(error).toString());
414
244
  }
415
245
  process.exit(1);
@@ -417,25 +247,25 @@ var parse2 = (data, schema) => {
417
247
  };
418
248
 
419
249
  // src/utils/https.ts
420
- var BigCommerceStoreInfo = z5.object({
421
- features: z5.object({
422
- storefront_limits: z5.object({
423
- active: z5.number(),
424
- total_including_inactive: z5.number()
250
+ var BigCommerceStoreInfo = z2.object({
251
+ features: z2.object({
252
+ storefront_limits: z2.object({
253
+ active: z2.number(),
254
+ total_including_inactive: z2.number()
425
255
  })
426
256
  })
427
257
  });
428
- var BigCommerceV3ApiResponseSchema = (schema) => z5.object({
258
+ var BigCommerceV3ApiResponseSchema = (schema) => z2.object({
429
259
  data: schema,
430
- meta: z5.object({})
260
+ meta: z2.object({})
431
261
  });
432
262
  var BigCommerceChannelsV3ResponseSchema = BigCommerceV3ApiResponseSchema(
433
- z5.array(
434
- z5.object({
435
- id: z5.number(),
436
- name: z5.string(),
437
- status: z5.string(),
438
- platform: z5.string()
263
+ z2.array(
264
+ z2.object({
265
+ id: z2.number(),
266
+ name: z2.string(),
267
+ status: z2.string(),
268
+ platform: z2.string()
439
269
  })
440
270
  )
441
271
  );
@@ -486,20 +316,20 @@ var Https = class {
486
316
  });
487
317
  if (!response.ok) {
488
318
  console.error(
489
- chalk3.red(`
319
+ chalk2.red(`
490
320
  POST /device/token failed: ${response.status} ${response.statusText}
491
321
  `)
492
322
  );
493
323
  process.exit(1);
494
324
  }
495
- const DeviceCodeSchema = z5.object({
496
- device_code: z5.string(),
497
- user_code: z5.string(),
498
- verification_uri: z5.string(),
499
- expires_in: z5.number(),
500
- interval: z5.number()
325
+ const DeviceCodeSchema = z2.object({
326
+ device_code: z2.string(),
327
+ user_code: z2.string(),
328
+ verification_uri: z2.string(),
329
+ expires_in: z2.number(),
330
+ interval: z2.number()
501
331
  });
502
- return parse2(yield response.json(), DeviceCodeSchema);
332
+ return parse(yield response.json(), DeviceCodeSchema);
503
333
  });
504
334
  }
505
335
  checkDeviceCode(deviceCode) {
@@ -513,13 +343,13 @@ POST /device/token failed: ${response.status} ${response.statusText}
513
343
  if (response.status !== 200) {
514
344
  throw new Error("Device code not yet verified");
515
345
  }
516
- const DeviceCodeSuccessSchema = z5.object({
517
- access_token: z5.string(),
518
- store_hash: z5.string(),
519
- context: z5.string(),
520
- api_uri: z5.string().url()
346
+ const DeviceCodeSuccessSchema = z2.object({
347
+ access_token: z2.string(),
348
+ store_hash: z2.string(),
349
+ context: z2.string(),
350
+ api_uri: z2.string().url()
521
351
  });
522
- return parse2(yield response.json(), DeviceCodeSuccessSchema);
352
+ return parse(yield response.json(), DeviceCodeSuccessSchema);
523
353
  });
524
354
  }
525
355
  api(path, opts = {}) {
@@ -541,24 +371,24 @@ POST /device/token failed: ${response.status} ${response.statusText}
541
371
  return __async(this, null, function* () {
542
372
  const res = yield this.api("/v2/store");
543
373
  if (!res.ok) {
544
- console.error(chalk3.red(`
374
+ console.error(chalk2.red(`
545
375
  GET /v2/store failed: ${res.status} ${res.statusText}
546
376
  `));
547
377
  process.exit(1);
548
378
  }
549
- return parse2(yield res.json(), BigCommerceStoreInfo);
379
+ return parse(yield res.json(), BigCommerceStoreInfo);
550
380
  });
551
381
  }
552
382
  channels(query = "") {
553
383
  return __async(this, null, function* () {
554
384
  const res = yield this.api(`/v3/channels${query}`);
555
385
  if (!res.ok) {
556
- console.error(chalk3.red(`
386
+ console.error(chalk2.red(`
557
387
  GET /v3/channels failed: ${res.status} ${res.statusText}
558
388
  `));
559
389
  process.exit(1);
560
390
  }
561
- return parse2(yield res.json(), BigCommerceChannelsV3ResponseSchema);
391
+ return parse(yield res.json(), BigCommerceChannelsV3ResponseSchema);
562
392
  });
563
393
  }
564
394
  createChannelMenus(channelId) {
@@ -578,7 +408,7 @@ GET /v3/channels failed: ${res.status} ${res.statusText}
578
408
  });
579
409
  if (!res.ok) {
580
410
  console.warn(
581
- chalk3.yellow(
411
+ chalk2.yellow(
582
412
  `
583
413
  Failed to create channel menus: ${res.status} ${res.statusText}. You may want to create these later: https://developer.bigcommerce.com/docs/rest-management/channels/menus#create-channel-menus
584
414
  `
@@ -596,7 +426,7 @@ Failed to create channel menus: ${res.status} ${res.statusText}. You may want to
596
426
  });
597
427
  if (!res.ok) {
598
428
  console.error(
599
- chalk3.red(
429
+ chalk2.red(
600
430
  `
601
431
  POST /v3/storefront/api-token-customer-impersonation failed: ${res.status} ${res.statusText}
602
432
  `
@@ -604,12 +434,12 @@ POST /v3/storefront/api-token-customer-impersonation failed: ${res.status} ${res
604
434
  );
605
435
  process.exit(1);
606
436
  }
607
- const BigCommerceCustomerImpersonationTokenSchema = z5.object({
608
- data: z5.object({
609
- token: z5.string()
437
+ const BigCommerceCustomerImpersonationTokenSchema = z2.object({
438
+ data: z2.object({
439
+ token: z2.string()
610
440
  })
611
441
  });
612
- return parse2(yield res.json(), BigCommerceCustomerImpersonationTokenSchema);
442
+ return parse(yield res.json(), BigCommerceCustomerImpersonationTokenSchema);
613
443
  });
614
444
  }
615
445
  sampleDataApi(path, opts = {}) {
@@ -636,51 +466,51 @@ POST /v3/storefront/api-token-customer-impersonation failed: ${res.status} ${res
636
466
  });
637
467
  if (!res.ok) {
638
468
  console.error(
639
- chalk3.red(`
469
+ chalk2.red(`
640
470
  POST /v3/channels/catalyst failed: ${res.status} ${res.statusText}
641
471
  `)
642
472
  );
643
473
  process.exit(1);
644
474
  }
645
- const SampleDataChannelCreateSchema = z5.object({
646
- data: z5.object({
647
- id: z5.number(),
648
- name: z5.string().min(1),
649
- storefront_api_token: z5.string()
475
+ const SampleDataChannelCreateSchema = z2.object({
476
+ data: z2.object({
477
+ id: z2.number(),
478
+ name: z2.string().min(1),
479
+ storefront_api_token: z2.string()
650
480
  })
651
481
  });
652
- return parse2(yield res.json(), SampleDataChannelCreateSchema);
482
+ return parse(yield res.json(), SampleDataChannelCreateSchema);
653
483
  });
654
484
  }
655
485
  };
656
486
 
657
487
  // src/utils/install-dependencies.ts
658
- import chalk4 from "chalk";
659
- import { addDependency as addDependency2, addDevDependency as addDevDependency2, installDependencies as installDeps } from "nypm";
660
- var installAllDeps = (projectDir, packageManager) => __async(void 0, null, function* () {
661
- yield installDeps({ cwd: projectDir, silent: true, packageManager });
662
- yield addDependency2("@bigcommerce/catalyst-client", {
663
- cwd: projectDir,
664
- silent: true,
665
- packageManager
666
- });
667
- yield addDevDependency2("@bigcommerce/eslint-config-catalyst", {
668
- cwd: projectDir,
669
- silent: true,
670
- packageManager
671
- });
488
+ import chalk3 from "chalk";
489
+ import { installDependencies as installDeps } from "nypm";
490
+
491
+ // src/utils/spinner.ts
492
+ import { oraPromise } from "ora";
493
+ var spinner = (action, oraOpts) => __async(void 0, null, function* () {
494
+ return oraPromise(action, __spreadValues({
495
+ spinner: "triangle"
496
+ }, oraOpts)).catch(() => process.exit(1));
672
497
  });
673
- var installDependencies = (projectDir, packageManager) => __async(void 0, null, function* () {
674
- return spinner(installAllDeps(projectDir, packageManager), {
498
+
499
+ // src/utils/install-dependencies.ts
500
+ var installAllDeps = (projectDir) => __async(void 0, null, function* () {
501
+ yield installDeps({ cwd: projectDir, silent: true, packageManager: "pnpm" });
502
+ });
503
+ var installDependencies = (projectDir) => __async(void 0, null, function* () {
504
+ return spinner(installAllDeps(projectDir), {
675
505
  text: `Installing dependencies. This could take a minute...`,
676
506
  successText: `Dependencies installed successfully`,
677
- failText: (err) => chalk4.red(`Failed to install dependencies: ${err.message}`)
507
+ failText: (err) => chalk3.red(`Failed to install dependencies: ${err.message}`)
678
508
  });
679
509
  });
680
510
 
681
511
  // src/utils/login.ts
682
512
  import { select } from "@inquirer/prompts";
683
- import chalk5 from "chalk";
513
+ import chalk4 from "chalk";
684
514
  var poll = (auth, deviceCode, interval, expiresIn) => __async(void 0, null, function* () {
685
515
  const intervalMs = interval * 1e3;
686
516
  const expiresAtMs = expiresIn * 1e3;
@@ -692,7 +522,7 @@ var poll = (auth, deviceCode, interval, expiresIn) => __async(void 0, null, func
692
522
  }
693
523
  yield new Promise((resolve) => setTimeout(resolve, intervalMs));
694
524
  }
695
- console.error(chalk5.red("\nDevice code expired. Please try again.\n"));
525
+ console.error(chalk4.red("\nDevice code expired. Please try again.\n"));
696
526
  process.exit(1);
697
527
  });
698
528
  var login = (bigCommerceAuthUrl, storeHash, accessToken) => __async(void 0, null, function* () {
@@ -714,11 +544,11 @@ var login = (bigCommerceAuthUrl, storeHash, accessToken) => __async(void 0, null
714
544
  console.log(
715
545
  [
716
546
  `
717
- Please visit ${chalk5.cyan(deviceCode.verification_uri)} and enter the code: ${chalk5.yellow(
547
+ Please visit ${chalk4.cyan(deviceCode.verification_uri)} and enter the code: ${chalk4.yellow(
718
548
  deviceCode.user_code
719
549
  )}
720
550
  `,
721
- `The code will expire in ${chalk5.yellow(`${deviceCode.expires_in / 60} minutes`)}
551
+ `The code will expire in ${chalk4.yellow(`${deviceCode.expires_in / 60} minutes`)}
722
552
  `
723
553
  ].join("\n")
724
554
  );
@@ -736,31 +566,17 @@ Please visit ${chalk5.cyan(deviceCode.verification_uri)} and enter the code: ${c
736
566
  };
737
567
  });
738
568
 
739
- // src/utils/pm.ts
740
- var packageManagerChoices = ["npm", "pnpm", "yarn"];
741
- function getPackageManager() {
742
- var _a;
743
- const userAgent = (_a = process.env.npm_config_user_agent) != null ? _a : "";
744
- if (userAgent.startsWith("yarn")) {
745
- return "yarn";
746
- }
747
- if (userAgent.startsWith("pnpm")) {
748
- return "pnpm";
749
- }
750
- return "npm";
751
- }
752
-
753
569
  // src/utils/write-env.ts
754
570
  import { randomBytes } from "crypto";
755
- import { outputFileSync as outputFileSync2 } from "fs-extra/esm";
756
- import { join as join3 } from "path";
571
+ import { outputFileSync } from "fs-extra/esm";
572
+ import { join } from "path";
757
573
  var writeEnv = (projectDir, {
758
574
  channelId,
759
575
  storeHash,
760
576
  customerImpersonationToken
761
577
  }) => {
762
- outputFileSync2(
763
- join3(projectDir, ".env.local"),
578
+ outputFileSync(
579
+ join(projectDir, ".env.local"),
764
580
  [
765
581
  `BIGCOMMERCE_STORE_HASH=${storeHash}`,
766
582
  `BIGCOMMERCE_CHANNEL_ID=${channelId}`,
@@ -775,34 +591,29 @@ var writeEnv = (projectDir, {
775
591
  };
776
592
 
777
593
  // src/commands/create.ts
778
- var exec3 = promisify3(execCallback2);
779
- var create = new Command2("create").description("Command to scaffold and connect a Catalyst storefront to your BigCommerce store").option("--project-name <name>", "Name of your Catalyst project").option("--project-dir <dir>", "Directory in which to create your project", process.cwd()).option("--store-hash <hash>", "BigCommerce store hash").option("--access-token <token>", "BigCommerce access token").option("--channel-id <id>", "BigCommerce channel ID").option("--customer-impersonation-token <token>", "BigCommerce customer impersonation token").option("--integration <provider>", "Integration to apply to your new storefront").addOption(
780
- new Option(
781
- "--gh-ref <ref>",
782
- "Clone a specific ref from the bigcommerce/catalyst repository"
783
- ).default(getLatestCoreTag)
784
- ).addOption(
594
+ var create = new Command("create").description("Command to scaffold and connect a Catalyst storefront to your BigCommerce store").option("--project-name <name>", "Name of your Catalyst project").option("--project-dir <dir>", "Directory in which to create your project", process.cwd()).option("--store-hash <hash>", "BigCommerce store hash").option("--access-token <token>", "BigCommerce access token").option("--channel-id <id>", "BigCommerce channel ID").option("--customer-impersonation-token <token>", "BigCommerce customer impersonation token").option("--gh-ref <ref>", "Clone a specific ref from the bigcommerce/catalyst repository").addOption(
785
595
  new Option("--bigcommerce-hostname <hostname>", "BigCommerce hostname").default("bigcommerce.com").hideHelp()
786
596
  ).addOption(
787
597
  new Option("--sample-data-api-url <url>", "BigCommerce sample data API URL").default("https://api.bc-sample.store").hideHelp()
788
- ).addOption(
789
- new Option("--package-manager <pm>", "Override detected package manager").choices(packageManagerChoices).default(getPackageManager()).hideHelp()
790
- ).addOption(
791
- new Option("--code-editor <editor>", "Your preferred code editor").choices(["vscode"]).default("vscode").hideHelp()
792
- ).addOption(
793
- new Option("--include-functional-tests", "Include the functional test suite").default(false).hideHelp()
794
598
  ).action((options) => __async(void 0, null, function* () {
795
- const { packageManager, codeEditor, includeFunctionalTests } = options;
796
- const URLSchema = z6.string().url();
797
- const sampleDataApiUrl = parse2(options.sampleDataApiUrl, URLSchema);
798
- const bigcommerceApiUrl = parse2(`https://api.${options.bigcommerceHostname}`, URLSchema);
799
- const bigcommerceAuthUrl = parse2(`https://login.${options.bigcommerceHostname}`, URLSchema);
800
- let ghRef;
801
- if (options.ghRef instanceof Function) {
802
- ghRef = yield options.ghRef();
803
- } else {
804
- ghRef = options.ghRef;
599
+ const { ghRef } = options;
600
+ try {
601
+ execSync4("which git", { stdio: "ignore" });
602
+ } catch (e) {
603
+ console.error(chalk5.red("Error: git is required to create a Catalyst project\n"));
604
+ process.exit(1);
805
605
  }
606
+ try {
607
+ execSync4("which pnpm", { stdio: "ignore" });
608
+ } catch (e) {
609
+ console.error(chalk5.red("Error: pnpm is required to create a Catalyst project\n"));
610
+ console.error(chalk5.yellow("Tip: Enable it by running `corepack enable pnpm`\n"));
611
+ process.exit(1);
612
+ }
613
+ const URLSchema = z3.string().url();
614
+ const sampleDataApiUrl = parse(options.sampleDataApiUrl, URLSchema);
615
+ const bigcommerceApiUrl = parse(`https://api.${options.bigcommerceHostname}`, URLSchema);
616
+ const bigcommerceAuthUrl = parse(`https://login.${options.bigcommerceHostname}`, URLSchema);
806
617
  let projectName;
807
618
  let projectDir;
808
619
  let storeHash = options.storeHash;
@@ -813,24 +624,24 @@ var create = new Command2("create").description("Command to scaffold and connect
813
624
  channelId = parseInt(options.channelId, 10);
814
625
  }
815
626
  if (!pathExistsSync(options.projectDir)) {
816
- console.error(chalk6.red(`Error: --projectDir ${options.projectDir} is not a valid path
627
+ console.error(chalk5.red(`Error: --projectDir ${options.projectDir} is not a valid path
817
628
  `));
818
629
  process.exit(1);
819
630
  }
820
631
  if (options.projectName) {
821
- projectName = kebabCase2(options.projectName);
822
- projectDir = join4(options.projectDir, projectName);
632
+ projectName = kebabCase(options.projectName);
633
+ projectDir = join2(options.projectDir, projectName);
823
634
  if (pathExistsSync(projectDir)) {
824
- console.error(chalk6.red(`Error: ${projectDir} already exists
635
+ console.error(chalk5.red(`Error: ${projectDir} already exists
825
636
  `));
826
637
  process.exit(1);
827
638
  }
828
639
  }
829
640
  if (!options.projectName) {
830
641
  const validateProjectName = (i) => {
831
- const formatted = kebabCase2(i);
642
+ const formatted = kebabCase(i);
832
643
  if (!formatted) return "Project name is required";
833
- const targetDir = join4(options.projectDir, formatted);
644
+ const targetDir = join2(options.projectDir, formatted);
834
645
  if (pathExistsSync(targetDir)) return `Destination '${targetDir}' already exists`;
835
646
  projectName = formatted;
836
647
  projectDir = targetDir;
@@ -853,21 +664,17 @@ var create = new Command2("create").description("Command to scaffold and connect
853
664
  console.log(`
854
665
  Creating '${projectName}' at '${projectDir}'
855
666
  `);
856
- yield cloneCatalyst({ projectDir, projectName, ghRef, codeEditor, includeFunctionalTests });
857
- console.log(`
858
- Using ${chalk6.bold(packageManager)}
859
- `);
860
- yield installDependencies(projectDir, packageManager);
861
- yield applyIntegration(options.integration, { projectDir, packageManager });
667
+ cloneCatalyst({ projectDir, projectName, ghRef });
668
+ yield installDependencies(projectDir);
862
669
  console.log(
863
670
  [
864
671
  `
865
- ${chalk6.green("Success!")} Created '${projectName}' at '${projectDir}'
672
+ ${chalk5.green("Success!")} Created '${projectName}' at '${projectDir}'
866
673
  `,
867
674
  `Next steps:`,
868
- chalk6.yellow(`
675
+ chalk5.yellow(`
869
676
  - cd ${projectName} && cp .env.example .env.local`),
870
- chalk6.yellow(`
677
+ chalk5.yellow(`
871
678
  - Populate .env.local with your BigCommerce API credentials
872
679
  `)
873
680
  ].join("\n")
@@ -930,46 +737,37 @@ ${chalk6.green("Success!")} Created '${projectName}' at '${projectDir}'
930
737
  console.log(`
931
738
  Creating '${projectName}' at '${projectDir}'
932
739
  `);
933
- yield cloneCatalyst({ projectDir, projectName, ghRef, codeEditor, includeFunctionalTests });
740
+ cloneCatalyst({ projectDir, projectName, ghRef });
934
741
  writeEnv(projectDir, {
935
742
  channelId: channelId.toString(),
936
743
  storeHash,
937
744
  customerImpersonationToken
938
745
  });
939
- console.log(`
940
- Using ${chalk6.bold(packageManager)}
941
- `);
942
- yield installDependencies(projectDir, packageManager);
943
- yield spinner(exec3(`${packageManager} run --prefix ${projectDir} generate`), {
944
- text: "Creating GraphQL schema...",
945
- successText: "Created GraphQL schema",
946
- failText: (err) => chalk6.red(`Failed to create GraphQL schema: ${err.message}`)
947
- });
948
- yield applyIntegration(options.integration, { projectDir, packageManager });
746
+ yield installDependencies(projectDir);
949
747
  console.log(
950
748
  `
951
- ${chalk6.green("Success!")} Created '${projectName}' at '${projectDir}'
749
+ ${chalk5.green("Success!")} Created '${projectName}' at '${projectDir}'
952
750
  `,
953
751
  "\nNext steps:\n",
954
- chalk6.yellow(`
955
- cd ${projectName} && ${packageManager} run dev
752
+ chalk5.yellow(`
753
+ cd ${projectName} && pnpm run dev
956
754
  `)
957
755
  );
958
756
  }));
959
757
 
960
758
  // src/commands/init.ts
961
- import { Command as Command3, Option as Option2 } from "@commander-js/extra-typings";
759
+ import { Command as Command2, Option as Option2 } from "@commander-js/extra-typings";
962
760
  import { input as input2, select as select3 } from "@inquirer/prompts";
963
- import chalk7 from "chalk";
964
- import * as z7 from "zod";
965
- var init = new Command3("init").description("Connect a BigCommerce store with an existing Catalyst project").option("--store-hash <hash>", "BigCommerce store hash").option("--access-token <token>", "BigCommerce access token").addOption(
761
+ import chalk6 from "chalk";
762
+ import * as z4 from "zod";
763
+ var init = new Command2("init").description("Connect a BigCommerce store with an existing Catalyst project").option("--store-hash <hash>", "BigCommerce store hash").option("--access-token <token>", "BigCommerce access token").addOption(
966
764
  new Option2("--bigcommerce-hostname <hostname>", "BigCommerce hostname").default("bigcommerce.com").hideHelp()
967
765
  ).addOption(
968
766
  new Option2("--sample-data-api-url <url>", "BigCommerce sample data API URL").default("https://api.bc-sample.store").hideHelp()
969
767
  ).action((options) => __async(void 0, null, function* () {
970
768
  const projectDir = process.cwd();
971
- const URLSchema = z7.string().url();
972
- const sampleDataApiUrl = parse2(options.sampleDataApiUrl, URLSchema);
769
+ const URLSchema = z4.string().url();
770
+ const sampleDataApiUrl = parse(options.sampleDataApiUrl, URLSchema);
973
771
  const bigCommerceApiUrl = `https://api.${options.bigcommerceHostname}`;
974
772
  const bigCommerceAuthUrl = `https://login.${options.bigcommerceHostname}`;
975
773
  let storeHash = options.storeHash;
@@ -983,7 +781,7 @@ var init = new Command3("init").description("Connect a BigCommerce store with an
983
781
  }
984
782
  if (!storeHash || !accessToken) {
985
783
  console.log(
986
- chalk7.yellow("\nYou must authenticate with a store to overwrite your local environment.\n")
784
+ chalk6.yellow("\nYou must authenticate with a store to overwrite your local environment.\n")
987
785
  );
988
786
  process.exit(1);
989
787
  }
@@ -1044,8 +842,81 @@ var init = new Command3("init").description("Connect a BigCommerce store with an
1044
842
  });
1045
843
  }));
1046
844
 
845
+ // src/commands/integration.ts
846
+ import { Command as Command3 } from "@commander-js/extra-typings";
847
+ import { exec as execCb } from "child_process";
848
+ import { parse as parse2 } from "dotenv";
849
+ import { outputFileSync as outputFileSync2, writeJsonSync } from "fs-extra/esm";
850
+ import kebabCase2 from "lodash.kebabcase";
851
+ import { coerce, compare } from "semver";
852
+ import { promisify } from "util";
853
+ import { z as z5 } from "zod";
854
+ var exec = promisify(execCb);
855
+ var ManifestSchema = z5.object({
856
+ name: z5.string(),
857
+ dependencies: z5.object({ add: z5.array(z5.string()) }),
858
+ devDependencies: z5.object({ add: z5.array(z5.string()) }),
859
+ environmentVariables: z5.array(z5.string())
860
+ });
861
+ var integration = new Command3("integration").argument("<integration-name>", "Formatted name of the integration").option("--commit-hash <hash>", "Override integration source branch with a specific commit hash").action((integrationNameRaw, options) => __async(void 0, null, function* () {
862
+ const integrationName = z5.string().transform(kebabCase2).parse(integrationNameRaw);
863
+ const manifest = {
864
+ name: integrationName,
865
+ dependencies: { add: [] },
866
+ devDependencies: { add: [] },
867
+ environmentVariables: []
868
+ };
869
+ yield exec("git fetch --tags");
870
+ const { stdout: headRefStdOut } = yield exec("git rev-parse --abbrev-ref HEAD");
871
+ let [sourceRef] = headRefStdOut.split("\n");
872
+ if (options.commitHash) {
873
+ sourceRef = options.commitHash;
874
+ }
875
+ const { stdout: catalystTags } = yield exec("git tag --list @bigcommerce/catalyst-core@\\*");
876
+ const [latestCoreTag] = catalystTags.split("\n").filter(Boolean).sort((a, b) => {
877
+ const versionA = coerce(a.replace("@bigcommerce/catalyst-core@", ""));
878
+ const versionB = coerce(b.replace("@bigcommerce/catalyst-core@", ""));
879
+ if (versionA && versionB) {
880
+ return compare(versionA, versionB);
881
+ }
882
+ return 0;
883
+ }).reverse();
884
+ const PackageDependenciesSchema = z5.object({
885
+ dependencies: z5.object({}).passthrough(),
886
+ devDependencies: z5.object({}).passthrough()
887
+ });
888
+ const getPackageDeps = (ref) => __async(void 0, null, function* () {
889
+ const { stdout } = yield exec(`git show ${ref}:core/package.json`);
890
+ return PackageDependenciesSchema.parse(JSON.parse(stdout));
891
+ });
892
+ const integrationJson = yield getPackageDeps(sourceRef);
893
+ const latestCoreTagJson = yield getPackageDeps(latestCoreTag);
894
+ const diffObjectKeys = (a, b) => {
895
+ return Object.keys(a).filter((key) => !Object.keys(b).includes(key));
896
+ };
897
+ manifest.dependencies.add = diffObjectKeys(
898
+ integrationJson.dependencies,
899
+ latestCoreTagJson.dependencies
900
+ );
901
+ manifest.devDependencies.add = diffObjectKeys(
902
+ integrationJson.devDependencies,
903
+ latestCoreTagJson.devDependencies
904
+ );
905
+ const { stdout: latestCoreEnv } = yield exec(`git show ${latestCoreTag}:core/.env.example`);
906
+ const { stdout: integrationEnv } = yield exec(`git show ${sourceRef}:core/.env.example`);
907
+ manifest.environmentVariables = diffObjectKeys(parse2(integrationEnv), parse2(latestCoreEnv));
908
+ const { stdout: integrationDiff } = yield exec(
909
+ `git diff ${latestCoreTag}...${sourceRef} -- ':(exclude)core/package.json' ':(exclude)pnpm-lock.yaml'`
910
+ );
911
+ outputFileSync2(`integrations/${integrationName}/integration.patch`, integrationDiff);
912
+ writeJsonSync(`integrations/${integrationName}/manifest.json`, manifest, {
913
+ spaces: 2
914
+ });
915
+ console.log("Integration created successfully.");
916
+ }));
917
+
1047
918
  // src/index.ts
1048
- console.log(chalk8.cyanBright(`
919
+ console.log(chalk7.cyanBright(`
1049
920
  \u25E2 ${package_default.name} v${package_default.version}
1050
921
  `));
1051
922
  program.name(package_default.name).version(package_default.version).description("A command line tool to create a new Catalyst project.").addCommand(create, { isDefault: true }).addCommand(init).addCommand(integration);