@bigcommerce/create-catalyst 0.11.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.11.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.3.8",
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.9",
89
- ora: "^8.0.1",
87
+ nypm: "^0.3.12",
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
- "@bigcommerce/eslint-config": "^2.9.0",
94
+ "@bigcommerce/eslint-config": "^2.9.1",
96
95
  "@bigcommerce/eslint-config-catalyst": "workspace:^",
97
- "@swc/core": "^1.7.3",
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.14.15",
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.3.5",
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 (err) {
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 (err) {
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));
497
+ });
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" });
672
502
  });
673
- var installDependencies = (projectDir, packageManager) => __async(void 0, null, function* () {
674
- return spinner(installAllDeps(projectDir, packageManager), {
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;
@@ -688,11 +518,11 @@ var poll = (auth, deviceCode, interval, expiresIn) => __async(void 0, null, func
688
518
  for (let i = 0; i < retries; i += 1) {
689
519
  try {
690
520
  return yield auth.checkDeviceCode(deviceCode);
691
- } catch (err) {
521
+ } catch (e) {
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,74 +566,54 @@ 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
- accessToken,
761
576
  customerImpersonationToken
762
577
  }) => {
763
- outputFileSync2(
764
- join3(projectDir, ".env.local"),
578
+ outputFileSync(
579
+ join(projectDir, ".env.local"),
765
580
  [
766
- `AUTH_SECRET=${randomBytes(32).toString("hex")}`,
767
581
  `BIGCOMMERCE_STORE_HASH=${storeHash}`,
768
582
  `BIGCOMMERCE_CHANNEL_ID=${channelId}`,
769
- `BIGCOMMERCE_ACCESS_TOKEN=${accessToken}`,
770
583
  `BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN=${customerImpersonationToken}`,
584
+ "",
585
+ `AUTH_SECRET=${randomBytes(32).toString("hex")}`,
771
586
  `CLIENT_LOGGER=false`,
772
587
  `ENABLE_ADMIN_ROUTE=true`,
773
- `NEXT_PUBLIC_DEFAULT_REVALIDATE_TARGET=3600`
588
+ `DEFAULT_REVALIDATE_TARGET=3600`
774
589
  ].join("\n")
775
590
  );
776
591
  };
777
592
 
778
593
  // src/commands/create.ts
779
- var exec3 = promisify3(execCallback2);
780
- 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(
781
- new Option(
782
- "--gh-ref <ref>",
783
- "Clone a specific ref from the bigcommerce/catalyst repository"
784
- ).default(getLatestCoreTag)
785
- ).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(
786
595
  new Option("--bigcommerce-hostname <hostname>", "BigCommerce hostname").default("bigcommerce.com").hideHelp()
787
596
  ).addOption(
788
597
  new Option("--sample-data-api-url <url>", "BigCommerce sample data API URL").default("https://api.bc-sample.store").hideHelp()
789
- ).addOption(
790
- new Option("--package-manager <pm>", "Override detected package manager").choices(packageManagerChoices).default(getPackageManager()).hideHelp()
791
- ).addOption(
792
- new Option("--code-editor <editor>", "Your preferred code editor").choices(["vscode"]).default("vscode").hideHelp()
793
- ).addOption(
794
- new Option("--include-functional-tests", "Include the functional test suite").default(false).hideHelp()
795
598
  ).action((options) => __async(void 0, null, function* () {
796
- const { packageManager, codeEditor, includeFunctionalTests } = options;
797
- const URLSchema = z6.string().url();
798
- const sampleDataApiUrl = parse2(options.sampleDataApiUrl, URLSchema);
799
- const bigcommerceApiUrl = parse2(`https://api.${options.bigcommerceHostname}`, URLSchema);
800
- const bigcommerceAuthUrl = parse2(`https://login.${options.bigcommerceHostname}`, URLSchema);
801
- let ghRef;
802
- if (options.ghRef instanceof Function) {
803
- ghRef = yield options.ghRef();
804
- } else {
805
- 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);
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);
806
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);
807
617
  let projectName;
808
618
  let projectDir;
809
619
  let storeHash = options.storeHash;
@@ -814,24 +624,24 @@ var create = new Command2("create").description("Command to scaffold and connect
814
624
  channelId = parseInt(options.channelId, 10);
815
625
  }
816
626
  if (!pathExistsSync(options.projectDir)) {
817
- 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
818
628
  `));
819
629
  process.exit(1);
820
630
  }
821
631
  if (options.projectName) {
822
- projectName = kebabCase2(options.projectName);
823
- projectDir = join4(options.projectDir, projectName);
632
+ projectName = kebabCase(options.projectName);
633
+ projectDir = join2(options.projectDir, projectName);
824
634
  if (pathExistsSync(projectDir)) {
825
- console.error(chalk6.red(`Error: ${projectDir} already exists
635
+ console.error(chalk5.red(`Error: ${projectDir} already exists
826
636
  `));
827
637
  process.exit(1);
828
638
  }
829
639
  }
830
640
  if (!options.projectName) {
831
641
  const validateProjectName = (i) => {
832
- const formatted = kebabCase2(i);
642
+ const formatted = kebabCase(i);
833
643
  if (!formatted) return "Project name is required";
834
- const targetDir = join4(options.projectDir, formatted);
644
+ const targetDir = join2(options.projectDir, formatted);
835
645
  if (pathExistsSync(targetDir)) return `Destination '${targetDir}' already exists`;
836
646
  projectName = formatted;
837
647
  projectDir = targetDir;
@@ -854,21 +664,17 @@ var create = new Command2("create").description("Command to scaffold and connect
854
664
  console.log(`
855
665
  Creating '${projectName}' at '${projectDir}'
856
666
  `);
857
- yield cloneCatalyst({ projectDir, projectName, ghRef, codeEditor, includeFunctionalTests });
858
- console.log(`
859
- Using ${chalk6.bold(packageManager)}
860
- `);
861
- yield installDependencies(projectDir, packageManager);
862
- yield applyIntegration(options.integration, { projectDir, packageManager });
667
+ cloneCatalyst({ projectDir, projectName, ghRef });
668
+ yield installDependencies(projectDir);
863
669
  console.log(
864
670
  [
865
671
  `
866
- ${chalk6.green("Success!")} Created '${projectName}' at '${projectDir}'
672
+ ${chalk5.green("Success!")} Created '${projectName}' at '${projectDir}'
867
673
  `,
868
674
  `Next steps:`,
869
- chalk6.yellow(`
675
+ chalk5.yellow(`
870
676
  - cd ${projectName} && cp .env.example .env.local`),
871
- chalk6.yellow(`
677
+ chalk5.yellow(`
872
678
  - Populate .env.local with your BigCommerce API credentials
873
679
  `)
874
680
  ].join("\n")
@@ -931,47 +737,37 @@ ${chalk6.green("Success!")} Created '${projectName}' at '${projectDir}'
931
737
  console.log(`
932
738
  Creating '${projectName}' at '${projectDir}'
933
739
  `);
934
- yield cloneCatalyst({ projectDir, projectName, ghRef, codeEditor, includeFunctionalTests });
740
+ cloneCatalyst({ projectDir, projectName, ghRef });
935
741
  writeEnv(projectDir, {
936
742
  channelId: channelId.toString(),
937
743
  storeHash,
938
- accessToken,
939
744
  customerImpersonationToken
940
745
  });
941
- console.log(`
942
- Using ${chalk6.bold(packageManager)}
943
- `);
944
- yield installDependencies(projectDir, packageManager);
945
- yield spinner(exec3(`${packageManager} run --prefix ${projectDir} generate`), {
946
- text: "Creating GraphQL schema...",
947
- successText: "Created GraphQL schema",
948
- failText: (err) => chalk6.red(`Failed to create GraphQL schema: ${err.message}`)
949
- });
950
- yield applyIntegration(options.integration, { projectDir, packageManager });
746
+ yield installDependencies(projectDir);
951
747
  console.log(
952
748
  `
953
- ${chalk6.green("Success!")} Created '${projectName}' at '${projectDir}'
749
+ ${chalk5.green("Success!")} Created '${projectName}' at '${projectDir}'
954
750
  `,
955
751
  "\nNext steps:\n",
956
- chalk6.yellow(`
957
- cd ${projectName} && ${packageManager} run dev
752
+ chalk5.yellow(`
753
+ cd ${projectName} && pnpm run dev
958
754
  `)
959
755
  );
960
756
  }));
961
757
 
962
758
  // src/commands/init.ts
963
- 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";
964
760
  import { input as input2, select as select3 } from "@inquirer/prompts";
965
- import chalk7 from "chalk";
966
- import * as z7 from "zod";
967
- 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(
968
764
  new Option2("--bigcommerce-hostname <hostname>", "BigCommerce hostname").default("bigcommerce.com").hideHelp()
969
765
  ).addOption(
970
766
  new Option2("--sample-data-api-url <url>", "BigCommerce sample data API URL").default("https://api.bc-sample.store").hideHelp()
971
767
  ).action((options) => __async(void 0, null, function* () {
972
768
  const projectDir = process.cwd();
973
- const URLSchema = z7.string().url();
974
- const sampleDataApiUrl = parse2(options.sampleDataApiUrl, URLSchema);
769
+ const URLSchema = z4.string().url();
770
+ const sampleDataApiUrl = parse(options.sampleDataApiUrl, URLSchema);
975
771
  const bigCommerceApiUrl = `https://api.${options.bigcommerceHostname}`;
976
772
  const bigCommerceAuthUrl = `https://login.${options.bigcommerceHostname}`;
977
773
  let storeHash = options.storeHash;
@@ -985,7 +781,7 @@ var init = new Command3("init").description("Connect a BigCommerce store with an
985
781
  }
986
782
  if (!storeHash || !accessToken) {
987
783
  console.log(
988
- 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")
989
785
  );
990
786
  process.exit(1);
991
787
  }
@@ -1042,13 +838,85 @@ var init = new Command3("init").description("Connect a BigCommerce store with an
1042
838
  writeEnv(projectDir, {
1043
839
  channelId: channelId.toString(),
1044
840
  storeHash,
1045
- accessToken,
1046
841
  customerImpersonationToken
1047
842
  });
1048
843
  }));
1049
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
+
1050
918
  // src/index.ts
1051
- console.log(chalk8.cyanBright(`
919
+ console.log(chalk7.cyanBright(`
1052
920
  \u25E2 ${package_default.name} v${package_default.version}
1053
921
  `));
1054
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);