@bigcommerce/create-catalyst 0.17.1 → 0.19.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 +708 -595
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
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
|
|
56
|
+
import chalk6 from "chalk";
|
|
57
57
|
|
|
58
58
|
// package.json
|
|
59
59
|
var package_default = {
|
|
60
60
|
name: "@bigcommerce/create-catalyst",
|
|
61
|
-
version: "0.
|
|
61
|
+
version: "0.19.0",
|
|
62
62
|
type: "module",
|
|
63
63
|
bin: "bin/index.cjs",
|
|
64
64
|
files: [
|
|
@@ -77,6 +77,7 @@ var package_default = {
|
|
|
77
77
|
},
|
|
78
78
|
dependencies: {
|
|
79
79
|
"@commander-js/extra-typings": "^12.1.0",
|
|
80
|
+
"@iarna/toml": "^2.2.5",
|
|
80
81
|
"@inquirer/prompts": "^7.2.0",
|
|
81
82
|
"@segment/analytics-node": "^2.2.0",
|
|
82
83
|
chalk: "^5.3.0",
|
|
@@ -87,10 +88,11 @@ var package_default = {
|
|
|
87
88
|
giget: "^1.2.3",
|
|
88
89
|
"lodash.kebabcase": "^4.1.1",
|
|
89
90
|
nypm: "^0.4.1",
|
|
91
|
+
open: "^10.1.0",
|
|
90
92
|
ora: "^8.1.1",
|
|
91
93
|
semver: "^7.6.3",
|
|
92
94
|
"std-env": "^3.8.0",
|
|
93
|
-
zod: "^3.
|
|
95
|
+
zod: "^3.24.1",
|
|
94
96
|
"zod-validation-error": "^3.4.0"
|
|
95
97
|
},
|
|
96
98
|
devDependencies: {
|
|
@@ -101,12 +103,12 @@ var package_default = {
|
|
|
101
103
|
"@types/fs-extra": "^11.0.4",
|
|
102
104
|
"@types/jest": "^29.5.14",
|
|
103
105
|
"@types/lodash.kebabcase": "^4.1.9",
|
|
104
|
-
"@types/node": "^20.17.
|
|
106
|
+
"@types/node": "^20.17.10",
|
|
105
107
|
"@types/prompts": "^2.4.9",
|
|
106
108
|
"@types/semver": "^7.5.8",
|
|
107
109
|
eslint: "^8.57.1",
|
|
108
110
|
jest: "^29.7.0",
|
|
109
|
-
msw: "^2.6.
|
|
111
|
+
msw: "^2.6.9",
|
|
110
112
|
prettier: "^3.4.2",
|
|
111
113
|
tsup: "^8.3.5",
|
|
112
114
|
typescript: "^5.7.2"
|
|
@@ -115,16 +117,125 @@ var package_default = {
|
|
|
115
117
|
|
|
116
118
|
// src/commands/create.ts
|
|
117
119
|
import { Command, Option } from "@commander-js/extra-typings";
|
|
118
|
-
import { input, select
|
|
119
|
-
import
|
|
120
|
-
import { execSync as
|
|
120
|
+
import { input, select } from "@inquirer/prompts";
|
|
121
|
+
import chalk3 from "chalk";
|
|
122
|
+
import { execSync as execSync5 } from "child_process";
|
|
121
123
|
import { pathExistsSync } from "fs-extra/esm";
|
|
122
124
|
import kebabCase from "lodash.kebabcase";
|
|
123
|
-
import { join as
|
|
124
|
-
|
|
125
|
+
import { join as join3 } from "path";
|
|
126
|
+
|
|
127
|
+
// src/utils/user-agent.ts
|
|
128
|
+
import {
|
|
129
|
+
isDevelopment,
|
|
130
|
+
isLinux,
|
|
131
|
+
isMacOS,
|
|
132
|
+
isProduction,
|
|
133
|
+
isTest,
|
|
134
|
+
isWindows,
|
|
135
|
+
nodeVersion,
|
|
136
|
+
process as process2,
|
|
137
|
+
provider,
|
|
138
|
+
runtime
|
|
139
|
+
} from "std-env";
|
|
140
|
+
var { name, version } = package_default;
|
|
141
|
+
var getOS = () => {
|
|
142
|
+
if (isWindows) return "Windows";
|
|
143
|
+
if (isMacOS) return "macOS";
|
|
144
|
+
if (isLinux) return "Linux";
|
|
145
|
+
return "Unknown OS";
|
|
146
|
+
};
|
|
147
|
+
var getEnv = () => {
|
|
148
|
+
if (isDevelopment) return "Development";
|
|
149
|
+
if (isTest) return "Test";
|
|
150
|
+
if (isProduction) return "Production";
|
|
151
|
+
};
|
|
152
|
+
var getPlatform = () => {
|
|
153
|
+
const os = getOS();
|
|
154
|
+
const env = getEnv();
|
|
155
|
+
const keysOfInterest = [
|
|
156
|
+
os,
|
|
157
|
+
env,
|
|
158
|
+
runtime,
|
|
159
|
+
provider,
|
|
160
|
+
`Node ${nodeVersion}`,
|
|
161
|
+
process2.env.NODE_ENV
|
|
162
|
+
].filter(Boolean);
|
|
163
|
+
return keysOfInterest.join("; ");
|
|
164
|
+
};
|
|
165
|
+
var detectedPlatform = getPlatform();
|
|
166
|
+
var getCLIUserAgent = (platform, extensions) => {
|
|
167
|
+
const userAgentParts = [`${name}/${version}`];
|
|
168
|
+
const platformValue = platform != null ? platform : detectedPlatform;
|
|
169
|
+
userAgentParts.push(`(${platformValue})`);
|
|
170
|
+
if (extensions) {
|
|
171
|
+
userAgentParts.push(extensions);
|
|
172
|
+
}
|
|
173
|
+
return userAgentParts.join(" ");
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/utils/https.ts
|
|
177
|
+
var Https = class {
|
|
178
|
+
constructor({ baseUrl, accessToken }) {
|
|
179
|
+
this.baseUrl = baseUrl;
|
|
180
|
+
this.accessToken = accessToken;
|
|
181
|
+
this.userAgent = getCLIUserAgent();
|
|
182
|
+
}
|
|
183
|
+
fetch(_0) {
|
|
184
|
+
return __async(this, arguments, function* (path, opts = {}) {
|
|
185
|
+
const _a = opts, { headers = {} } = _a, rest = __objRest(_a, ["headers"]);
|
|
186
|
+
const options = __spreadValues({
|
|
187
|
+
headers: __spreadValues(__spreadProps(__spreadValues({}, headers), {
|
|
188
|
+
Accept: "application/json",
|
|
189
|
+
"User-Agent": this.userAgent
|
|
190
|
+
}), this.accessToken && { "X-Auth-Token": this.accessToken })
|
|
191
|
+
}, rest);
|
|
192
|
+
return fetch(`${this.baseUrl}${path}`, options);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// src/utils/cli-api.ts
|
|
198
|
+
var CliApi = class {
|
|
199
|
+
constructor({ origin, storeHash, accessToken }) {
|
|
200
|
+
this.client = new Https({
|
|
201
|
+
baseUrl: `${origin}/stores/${storeHash}/cli-api/v3`,
|
|
202
|
+
accessToken
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
getChannelInit(channelId) {
|
|
206
|
+
return __async(this, null, function* () {
|
|
207
|
+
return this.client.fetch(`/channels/${channelId}/init`, {
|
|
208
|
+
method: "GET"
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
checkEligibility() {
|
|
213
|
+
return __async(this, null, function* () {
|
|
214
|
+
return this.client.fetch("/channels/catalyst/eligibility", {
|
|
215
|
+
method: "GET"
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
createChannel(name2, installSampleData = false) {
|
|
220
|
+
return __async(this, null, function* () {
|
|
221
|
+
return this.client.fetch("/channels/catalyst", {
|
|
222
|
+
method: "POST",
|
|
223
|
+
headers: { "Content-Type": "application/json" },
|
|
224
|
+
body: JSON.stringify({
|
|
225
|
+
name: name2,
|
|
226
|
+
initialData: {
|
|
227
|
+
type: installSampleData ? "sample" : "none"
|
|
228
|
+
},
|
|
229
|
+
deployStorefront: true,
|
|
230
|
+
devOrigin: "http://localhost:3000"
|
|
231
|
+
})
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
};
|
|
125
236
|
|
|
126
237
|
// src/utils/clone-catalyst.ts
|
|
127
|
-
import { execSync as
|
|
238
|
+
import { execSync as execSync4 } from "child_process";
|
|
128
239
|
|
|
129
240
|
// src/utils/checkout-ref.ts
|
|
130
241
|
import { execSync } from "node:child_process";
|
|
@@ -181,29 +292,75 @@ function hasGitHubSSH() {
|
|
|
181
292
|
}
|
|
182
293
|
}
|
|
183
294
|
|
|
295
|
+
// src/utils/reset-branch-to-ref.ts
|
|
296
|
+
import { execSync as execSync3 } from "node:child_process";
|
|
297
|
+
function resetBranchToRef(projectDir, ghRef) {
|
|
298
|
+
execSync3(`git reset --hard ${ghRef}`, {
|
|
299
|
+
cwd: projectDir,
|
|
300
|
+
stdio: "inherit",
|
|
301
|
+
encoding: "utf8"
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
184
305
|
// src/utils/clone-catalyst.ts
|
|
185
306
|
var cloneCatalyst = ({
|
|
186
307
|
repository,
|
|
187
308
|
projectName,
|
|
188
309
|
projectDir,
|
|
189
|
-
ghRef
|
|
310
|
+
ghRef,
|
|
311
|
+
resetMain = false
|
|
190
312
|
}) => {
|
|
191
313
|
const useSSH = hasGitHubSSH();
|
|
192
314
|
console.log(`Cloning ${repository} using ${useSSH ? "SSH" : "HTTPS"}...
|
|
193
315
|
`);
|
|
194
316
|
const cloneCommand = `git clone ${useSSH ? `git@github.com:${repository}` : `https://github.com/${repository}`}.git${projectName ? ` ${projectName}` : ""}`;
|
|
195
|
-
|
|
317
|
+
execSync4(cloneCommand, { stdio: "inherit" });
|
|
196
318
|
console.log();
|
|
197
|
-
|
|
319
|
+
execSync4("git remote rename origin upstream", { cwd: projectDir, stdio: "inherit" });
|
|
198
320
|
console.log();
|
|
199
321
|
if (ghRef) {
|
|
322
|
+
if (resetMain) {
|
|
323
|
+
checkoutRef(projectDir, "main");
|
|
324
|
+
resetBranchToRef(projectDir, ghRef);
|
|
325
|
+
console.log(`Reset main to ${ghRef} successfully.`);
|
|
326
|
+
console.log();
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
200
329
|
checkoutRef(projectDir, ghRef);
|
|
201
330
|
console.log();
|
|
202
331
|
}
|
|
203
332
|
};
|
|
204
333
|
|
|
205
|
-
// src/utils/
|
|
334
|
+
// src/utils/install-dependencies.ts
|
|
206
335
|
import chalk from "chalk";
|
|
336
|
+
import { installDependencies as installDeps } from "nypm";
|
|
337
|
+
|
|
338
|
+
// src/utils/spinner.ts
|
|
339
|
+
import { oraPromise } from "ora";
|
|
340
|
+
var spinner = (action, oraOpts) => __async(void 0, null, function* () {
|
|
341
|
+
return oraPromise(action, __spreadValues({
|
|
342
|
+
spinner: "triangle"
|
|
343
|
+
}, oraOpts)).catch(() => process.exit(1));
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// src/utils/install-dependencies.ts
|
|
347
|
+
var installAllDeps = (projectDir) => __async(void 0, null, function* () {
|
|
348
|
+
yield installDeps({ cwd: projectDir, silent: true, packageManager: "pnpm" });
|
|
349
|
+
});
|
|
350
|
+
var installDependencies = (projectDir) => __async(void 0, null, function* () {
|
|
351
|
+
return spinner(installAllDeps(projectDir), {
|
|
352
|
+
text: `Installing dependencies. This could take a minute...`,
|
|
353
|
+
successText: `Dependencies installed successfully`,
|
|
354
|
+
failText: (err) => chalk.red(`Failed to install dependencies: ${err.message}`)
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// src/utils/login.ts
|
|
359
|
+
import chalk2 from "chalk";
|
|
360
|
+
import open from "open";
|
|
361
|
+
import { createInterface } from "readline";
|
|
362
|
+
|
|
363
|
+
// src/utils/auth.ts
|
|
207
364
|
import { z as z2 } from "zod";
|
|
208
365
|
|
|
209
366
|
// src/utils/parse.ts
|
|
@@ -220,113 +377,17 @@ var parse = (data, schema) => {
|
|
|
220
377
|
}
|
|
221
378
|
};
|
|
222
379
|
|
|
223
|
-
// src/utils/
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
isProduction,
|
|
229
|
-
isTest,
|
|
230
|
-
isWindows,
|
|
231
|
-
nodeVersion,
|
|
232
|
-
process as process2,
|
|
233
|
-
provider,
|
|
234
|
-
runtime
|
|
235
|
-
} from "std-env";
|
|
236
|
-
var { name, version } = package_default;
|
|
237
|
-
var getOS = () => {
|
|
238
|
-
if (isWindows) return "Windows";
|
|
239
|
-
if (isMacOS) return "macOS";
|
|
240
|
-
if (isLinux) return "Linux";
|
|
241
|
-
return "Unknown OS";
|
|
242
|
-
};
|
|
243
|
-
var getEnv = () => {
|
|
244
|
-
if (isDevelopment) return "Development";
|
|
245
|
-
if (isTest) return "Test";
|
|
246
|
-
if (isProduction) return "Production";
|
|
247
|
-
};
|
|
248
|
-
var getPlatform = () => {
|
|
249
|
-
const os = getOS();
|
|
250
|
-
const env = getEnv();
|
|
251
|
-
const keysOfInterest = [
|
|
252
|
-
os,
|
|
253
|
-
env,
|
|
254
|
-
runtime,
|
|
255
|
-
provider,
|
|
256
|
-
`Node ${nodeVersion}`,
|
|
257
|
-
process2.env.NODE_ENV
|
|
258
|
-
].filter(Boolean);
|
|
259
|
-
return keysOfInterest.join("; ");
|
|
260
|
-
};
|
|
261
|
-
var detectedPlatform = getPlatform();
|
|
262
|
-
var getCLIUserAgent = (platform, extensions) => {
|
|
263
|
-
const userAgentParts = [`${name}/${version}`];
|
|
264
|
-
const platformValue = platform != null ? platform : detectedPlatform;
|
|
265
|
-
userAgentParts.push(`(${platformValue})`);
|
|
266
|
-
if (extensions) {
|
|
267
|
-
userAgentParts.push(extensions);
|
|
268
|
-
}
|
|
269
|
-
return userAgentParts.join(" ");
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
// src/utils/https.ts
|
|
273
|
-
var BigCommerceStoreInfo = z2.object({
|
|
274
|
-
features: z2.object({
|
|
275
|
-
storefront_limits: z2.object({
|
|
276
|
-
active: z2.number(),
|
|
277
|
-
total_including_inactive: z2.number()
|
|
278
|
-
})
|
|
279
|
-
})
|
|
280
|
-
});
|
|
281
|
-
var BigCommerceV3ApiResponseSchema = (schema) => z2.object({
|
|
282
|
-
data: schema,
|
|
283
|
-
meta: z2.object({})
|
|
284
|
-
});
|
|
285
|
-
var BigCommerceChannelsV3ResponseSchema = BigCommerceV3ApiResponseSchema(
|
|
286
|
-
z2.array(
|
|
287
|
-
z2.object({
|
|
288
|
-
id: z2.number(),
|
|
289
|
-
name: z2.string(),
|
|
290
|
-
status: z2.string(),
|
|
291
|
-
platform: z2.string()
|
|
292
|
-
})
|
|
293
|
-
)
|
|
294
|
-
);
|
|
295
|
-
var Https = class {
|
|
296
|
-
constructor({
|
|
297
|
-
bigCommerceApiUrl,
|
|
298
|
-
bigCommerceAuthUrl,
|
|
299
|
-
sampleDataApiUrl,
|
|
300
|
-
storeHash,
|
|
301
|
-
accessToken
|
|
302
|
-
}) {
|
|
303
|
-
this.DEVICE_OAUTH_CLIENT_ID = "acse0vvawm9r1n0evag4b8e1ea1fo90";
|
|
304
|
-
this.MAX_EPOC_EXPIRES_AT = 2147483647;
|
|
305
|
-
this.bigCommerceApiUrl = bigCommerceApiUrl != null ? bigCommerceApiUrl : "";
|
|
306
|
-
this.bigCommerceAuthUrl = bigCommerceAuthUrl != null ? bigCommerceAuthUrl : "";
|
|
307
|
-
this.sampleDataApiUrl = sampleDataApiUrl != null ? sampleDataApiUrl : "";
|
|
308
|
-
this.storeHash = storeHash != null ? storeHash : "";
|
|
309
|
-
this.accessToken = accessToken != null ? accessToken : "";
|
|
310
|
-
this.userAgent = getCLIUserAgent();
|
|
311
|
-
}
|
|
312
|
-
auth(path, opts = {}) {
|
|
313
|
-
if (!this.bigCommerceAuthUrl) {
|
|
314
|
-
throw new Error("bigCommerceAuthUrl is required to make API requests");
|
|
315
|
-
}
|
|
316
|
-
const _a = opts, { headers = {} } = _a, rest = __objRest(_a, ["headers"]);
|
|
317
|
-
const options = __spreadValues({
|
|
318
|
-
method: "POST",
|
|
319
|
-
headers: __spreadProps(__spreadValues({}, headers), {
|
|
320
|
-
Accept: "application/json",
|
|
321
|
-
"Content-Type": "application/json",
|
|
322
|
-
"User-Agent": this.userAgent
|
|
323
|
-
})
|
|
324
|
-
}, rest);
|
|
325
|
-
return fetch(`${this.bigCommerceAuthUrl}${path}`, options);
|
|
380
|
+
// src/utils/auth.ts
|
|
381
|
+
var Auth = class {
|
|
382
|
+
constructor({ baseUrl }) {
|
|
383
|
+
this.DEVICE_OAUTH_CLIENT_ID = "s1q4io7mah2lm1i6uwp9yl1eit80n3b";
|
|
384
|
+
this.client = new Https({ baseUrl });
|
|
326
385
|
}
|
|
327
386
|
getDeviceCode() {
|
|
328
387
|
return __async(this, null, function* () {
|
|
329
|
-
const response = yield this.
|
|
388
|
+
const response = yield this.client.fetch("/device/token", {
|
|
389
|
+
method: "POST",
|
|
390
|
+
headers: { "Content-Type": "application/json" },
|
|
330
391
|
body: JSON.stringify({
|
|
331
392
|
scopes: [
|
|
332
393
|
"store_channel_settings",
|
|
@@ -340,14 +401,6 @@ var Https = class {
|
|
|
340
401
|
client_id: this.DEVICE_OAUTH_CLIENT_ID
|
|
341
402
|
})
|
|
342
403
|
});
|
|
343
|
-
if (!response.ok) {
|
|
344
|
-
console.error(
|
|
345
|
-
chalk.red(`
|
|
346
|
-
POST /device/token failed: ${response.status} ${response.statusText}
|
|
347
|
-
`)
|
|
348
|
-
);
|
|
349
|
-
process.exit(1);
|
|
350
|
-
}
|
|
351
404
|
const DeviceCodeSchema = z2.object({
|
|
352
405
|
device_code: z2.string(),
|
|
353
406
|
user_code: z2.string(),
|
|
@@ -360,7 +413,9 @@ POST /device/token failed: ${response.status} ${response.statusText}
|
|
|
360
413
|
}
|
|
361
414
|
checkDeviceCode(deviceCode) {
|
|
362
415
|
return __async(this, null, function* () {
|
|
363
|
-
const response = yield this.
|
|
416
|
+
const response = yield this.client.fetch("/device/token", {
|
|
417
|
+
method: "POST",
|
|
418
|
+
headers: { "Content-Type": "application/json" },
|
|
364
419
|
body: JSON.stringify({
|
|
365
420
|
device_code: deviceCode,
|
|
366
421
|
client_id: this.DEVICE_OAUTH_CLIENT_ID
|
|
@@ -378,243 +433,155 @@ POST /device/token failed: ${response.status} ${response.statusText}
|
|
|
378
433
|
return parse(yield response.json(), DeviceCodeSuccessSchema);
|
|
379
434
|
});
|
|
380
435
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// src/utils/config.ts
|
|
439
|
+
import { parse as parseTOML, stringify as stringifyTOML } from "@iarna/toml";
|
|
440
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
441
|
+
import { dirname, join } from "path";
|
|
442
|
+
function isRecord(value) {
|
|
443
|
+
return typeof value === "object" && value !== null;
|
|
444
|
+
}
|
|
445
|
+
function isCatalystConfig(obj) {
|
|
446
|
+
if (!isRecord(obj)) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if ("auth" in obj) {
|
|
450
|
+
if (!isRecord(obj.auth)) {
|
|
451
|
+
return false;
|
|
386
452
|
}
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
headers: __spreadProps(__spreadValues({}, headers), {
|
|
390
|
-
Accept: "application/json",
|
|
391
|
-
"X-Auth-Token": this.accessToken,
|
|
392
|
-
"User-Agent": this.userAgent
|
|
393
|
-
})
|
|
394
|
-
}, rest);
|
|
395
|
-
return fetch(`${this.bigCommerceApiUrl}/stores/${this.storeHash}${path}`, options);
|
|
453
|
+
const { storeHash, accessToken } = obj.auth;
|
|
454
|
+
return (storeHash === void 0 || typeof storeHash === "string") && (accessToken === void 0 || typeof accessToken === "string");
|
|
396
455
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
`));
|
|
404
|
-
process.exit(1);
|
|
405
|
-
}
|
|
406
|
-
return parse(yield res.json(), BigCommerceStoreInfo);
|
|
407
|
-
});
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
var Config = class {
|
|
459
|
+
constructor(projectDir) {
|
|
460
|
+
this.configPath = join(projectDir, ".catalyst");
|
|
461
|
+
this.config = this.read();
|
|
408
462
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (!res.ok) {
|
|
413
|
-
console.error(chalk.red(`
|
|
414
|
-
GET /v3/channels failed: ${res.status} ${res.statusText}
|
|
415
|
-
`));
|
|
416
|
-
process.exit(1);
|
|
417
|
-
}
|
|
418
|
-
return parse(yield res.json(), BigCommerceChannelsV3ResponseSchema);
|
|
419
|
-
});
|
|
463
|
+
getAuth() {
|
|
464
|
+
var _a;
|
|
465
|
+
return (_a = this.config.auth) != null ? _a : {};
|
|
420
466
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
method: "POST",
|
|
425
|
-
headers: { "Content-Type": "application/json" },
|
|
426
|
-
body: JSON.stringify({
|
|
427
|
-
bigcommerce_protected_app_sections: [
|
|
428
|
-
"storefront_settings",
|
|
429
|
-
"currencies",
|
|
430
|
-
"domains",
|
|
431
|
-
"notifications",
|
|
432
|
-
"social"
|
|
433
|
-
]
|
|
434
|
-
})
|
|
435
|
-
});
|
|
436
|
-
if (!res.ok) {
|
|
437
|
-
console.warn(
|
|
438
|
-
chalk.yellow(
|
|
439
|
-
`
|
|
440
|
-
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
|
|
441
|
-
`
|
|
442
|
-
)
|
|
443
|
-
);
|
|
444
|
-
}
|
|
445
|
-
});
|
|
467
|
+
setAuth(storeHash, accessToken) {
|
|
468
|
+
this.config.auth = { storeHash, accessToken };
|
|
469
|
+
this.save();
|
|
446
470
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
console.error(
|
|
456
|
-
chalk.red(`
|
|
457
|
-
POST /v3/storefront/api-token failed: ${res.status} ${res.statusText}
|
|
458
|
-
`)
|
|
459
|
-
);
|
|
460
|
-
process.exit(1);
|
|
461
|
-
}
|
|
462
|
-
const BigCommerceStorefrontTokenSchema = z2.object({
|
|
463
|
-
data: z2.object({
|
|
464
|
-
token: z2.string()
|
|
465
|
-
})
|
|
466
|
-
});
|
|
467
|
-
return parse(yield res.json(), BigCommerceStorefrontTokenSchema);
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
sampleDataApi(path, opts = {}) {
|
|
471
|
-
if (!this.sampleDataApiUrl || !this.storeHash || !this.accessToken) {
|
|
472
|
-
throw new Error(
|
|
473
|
-
"sampleDataApiUrl, storeHash, and accessToken are required to make API requests"
|
|
474
|
-
);
|
|
471
|
+
save() {
|
|
472
|
+
var _a;
|
|
473
|
+
const configObj = {};
|
|
474
|
+
if (((_a = this.config.auth) == null ? void 0 : _a.storeHash) && this.config.auth.accessToken) {
|
|
475
|
+
configObj.auth = {
|
|
476
|
+
storeHash: this.config.auth.storeHash,
|
|
477
|
+
accessToken: this.config.auth.accessToken
|
|
478
|
+
};
|
|
475
479
|
}
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
}
|
|
488
|
-
checkEligibility() {
|
|
489
|
-
return __async(this, null, function* () {
|
|
490
|
-
const res = yield this.sampleDataApi("/v3/channels/catalyst/eligibility", {
|
|
491
|
-
method: "GET"
|
|
492
|
-
});
|
|
493
|
-
if (!res.ok) {
|
|
494
|
-
console.error(
|
|
495
|
-
chalk.red(
|
|
496
|
-
`
|
|
497
|
-
GET /v3/channels/catalyst/eligibility failed: ${res.status} ${res.statusText}
|
|
498
|
-
`
|
|
499
|
-
)
|
|
500
|
-
);
|
|
501
|
-
process.exit(1);
|
|
502
|
-
}
|
|
503
|
-
const CheckEligibilitySchema = z2.object({
|
|
504
|
-
data: z2.object({
|
|
505
|
-
eligible: z2.boolean(),
|
|
506
|
-
message: z2.string()
|
|
507
|
-
})
|
|
508
|
-
});
|
|
509
|
-
return parse(yield res.json(), CheckEligibilitySchema);
|
|
510
|
-
});
|
|
480
|
+
const dir = dirname(this.configPath);
|
|
481
|
+
if (!existsSync(dir)) {
|
|
482
|
+
mkdirSync(dir, { recursive: true });
|
|
483
|
+
}
|
|
484
|
+
const preamble = `# DO NOT commit this file to your repository!
|
|
485
|
+
# This file contains sensitive configuration specific to your local CLI setup.
|
|
486
|
+
# It includes authentication tokens and store-specific information.
|
|
487
|
+
# If using version control, make sure to add .catalyst to your .gitignore file.
|
|
488
|
+
|
|
489
|
+
`;
|
|
490
|
+
writeFileSync(this.configPath, preamble + stringifyTOML(configObj));
|
|
511
491
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
`)
|
|
522
|
-
);
|
|
523
|
-
process.exit(1);
|
|
492
|
+
read() {
|
|
493
|
+
if (!existsSync(this.configPath)) {
|
|
494
|
+
return {};
|
|
495
|
+
}
|
|
496
|
+
try {
|
|
497
|
+
const contents = readFileSync(this.configPath, "utf-8");
|
|
498
|
+
const parsed = parseTOML(contents);
|
|
499
|
+
if (isCatalystConfig(parsed)) {
|
|
500
|
+
return parsed;
|
|
524
501
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
});
|
|
532
|
-
return parse(yield res.json(), SampleDataChannelCreateSchema);
|
|
533
|
-
});
|
|
502
|
+
console.warn("Invalid config format in .catalyst file, using defaults");
|
|
503
|
+
return {};
|
|
504
|
+
} catch (e) {
|
|
505
|
+
console.warn("Failed to parse .catalyst config file, using defaults");
|
|
506
|
+
return {};
|
|
507
|
+
}
|
|
534
508
|
}
|
|
535
509
|
};
|
|
536
510
|
|
|
537
|
-
// src/utils/install-dependencies.ts
|
|
538
|
-
import chalk2 from "chalk";
|
|
539
|
-
import { installDependencies as installDeps } from "nypm";
|
|
540
|
-
|
|
541
|
-
// src/utils/spinner.ts
|
|
542
|
-
import { oraPromise } from "ora";
|
|
543
|
-
var spinner = (action, oraOpts) => __async(void 0, null, function* () {
|
|
544
|
-
return oraPromise(action, __spreadValues({
|
|
545
|
-
spinner: "triangle"
|
|
546
|
-
}, oraOpts)).catch(() => process.exit(1));
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
// src/utils/install-dependencies.ts
|
|
550
|
-
var installAllDeps = (projectDir) => __async(void 0, null, function* () {
|
|
551
|
-
yield installDeps({ cwd: projectDir, silent: true, packageManager: "pnpm" });
|
|
552
|
-
});
|
|
553
|
-
var installDependencies = (projectDir) => __async(void 0, null, function* () {
|
|
554
|
-
return spinner(installAllDeps(projectDir), {
|
|
555
|
-
text: `Installing dependencies. This could take a minute...`,
|
|
556
|
-
successText: `Dependencies installed successfully`,
|
|
557
|
-
failText: (err) => chalk2.red(`Failed to install dependencies: ${err.message}`)
|
|
558
|
-
});
|
|
559
|
-
});
|
|
560
|
-
|
|
561
511
|
// src/utils/login.ts
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
var poll = (auth, deviceCode, interval, expiresIn) => __async(void 0, null, function* () {
|
|
565
|
-
const intervalMs = interval * 1e3;
|
|
566
|
-
const expiresAtMs = expiresIn * 1e3;
|
|
567
|
-
const retries = expiresAtMs / intervalMs;
|
|
568
|
-
for (let i = 0; i < retries; i += 1) {
|
|
512
|
+
function pollDeviceCode(auth, deviceCode, interval) {
|
|
513
|
+
return __async(this, null, function* () {
|
|
569
514
|
try {
|
|
570
|
-
|
|
515
|
+
const credentials = yield auth.checkDeviceCode(deviceCode);
|
|
516
|
+
return credentials;
|
|
571
517
|
} catch (e) {
|
|
518
|
+
yield new Promise((resolve) => setTimeout(resolve, interval * 1e3));
|
|
519
|
+
return null;
|
|
572
520
|
}
|
|
573
|
-
yield new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
574
|
-
}
|
|
575
|
-
console.error(chalk3.red("\nDevice code expired. Please try again.\n"));
|
|
576
|
-
process.exit(1);
|
|
577
|
-
});
|
|
578
|
-
var login = (bigCommerceAuthUrl, storeHash, accessToken) => __async(void 0, null, function* () {
|
|
579
|
-
if (storeHash && accessToken) {
|
|
580
|
-
return { storeHash, accessToken };
|
|
581
|
-
}
|
|
582
|
-
const shouldLogin = yield select({
|
|
583
|
-
message: "Would you like to connect to a BigCommerce store?",
|
|
584
|
-
choices: [
|
|
585
|
-
{ name: "Yes", value: true },
|
|
586
|
-
{ name: "No", value: false }
|
|
587
|
-
]
|
|
588
521
|
});
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
[
|
|
596
|
-
`
|
|
597
|
-
Please visit ${chalk3.cyan(deviceCode.verification_uri)} and enter the code: ${chalk3.yellow(
|
|
598
|
-
deviceCode.user_code
|
|
599
|
-
)}
|
|
600
|
-
`,
|
|
601
|
-
`The code will expire in ${chalk3.yellow(`${deviceCode.expires_in / 60} minutes`)}
|
|
602
|
-
`
|
|
603
|
-
].join("\n")
|
|
604
|
-
);
|
|
605
|
-
const { store_hash, access_token } = yield spinner(
|
|
606
|
-
poll(auth, deviceCode.device_code, deviceCode.interval, deviceCode.expires_in),
|
|
607
|
-
{
|
|
608
|
-
text: "Waiting for device code to be authorized",
|
|
609
|
-
successText: "Device code authorized\n",
|
|
610
|
-
failText: "Device code expired\n"
|
|
522
|
+
}
|
|
523
|
+
function waitForCredentials(auth, deviceCode, interval) {
|
|
524
|
+
return __async(this, null, function* () {
|
|
525
|
+
const credentials = yield pollDeviceCode(auth, deviceCode, interval);
|
|
526
|
+
if (credentials) {
|
|
527
|
+
return credentials;
|
|
611
528
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
529
|
+
return waitForCredentials(auth, deviceCode, interval);
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
function waitForKeyPress(prompt) {
|
|
533
|
+
return __async(this, null, function* () {
|
|
534
|
+
const rl = createInterface({
|
|
535
|
+
input: process.stdin,
|
|
536
|
+
output: process.stdout
|
|
537
|
+
});
|
|
538
|
+
process.stdin.setRawMode(true);
|
|
539
|
+
process.stdin.resume();
|
|
540
|
+
return new Promise((resolve) => {
|
|
541
|
+
process.stdin.once("data", (data) => {
|
|
542
|
+
process.stdin.setRawMode(false);
|
|
543
|
+
process.stdin.pause();
|
|
544
|
+
rl.close();
|
|
545
|
+
const shouldProceed = data[0] !== 27;
|
|
546
|
+
process.stdout.write("\n");
|
|
547
|
+
resolve(shouldProceed);
|
|
548
|
+
});
|
|
549
|
+
rl.write(prompt);
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
function login(baseUrl) {
|
|
554
|
+
return __async(this, null, function* () {
|
|
555
|
+
const auth = new Auth({ baseUrl });
|
|
556
|
+
const deviceCode = yield auth.getDeviceCode();
|
|
557
|
+
console.log(
|
|
558
|
+
chalk2.cyan("\nPlease visit the following URL to authenticate with your BigCommerce store:")
|
|
559
|
+
);
|
|
560
|
+
console.log(chalk2.yellow(`
|
|
561
|
+
${deviceCode.verification_uri}
|
|
562
|
+
`));
|
|
563
|
+
console.log(chalk2.cyan(`Enter code: `) + chalk2.yellow(`${deviceCode.user_code}
|
|
564
|
+
`));
|
|
565
|
+
const shouldOpenUrl = yield waitForKeyPress(
|
|
566
|
+
"Press any key to open the URL in your browser (or ESC to skip)..."
|
|
567
|
+
);
|
|
568
|
+
if (shouldOpenUrl) {
|
|
569
|
+
yield open(deviceCode.verification_uri);
|
|
570
|
+
}
|
|
571
|
+
const credentials = yield spinner(
|
|
572
|
+
() => waitForCredentials(auth, deviceCode.device_code, deviceCode.interval),
|
|
573
|
+
{ text: "Waiting for authentication...", successText: "Authentication successful!" }
|
|
574
|
+
);
|
|
575
|
+
return {
|
|
576
|
+
storeHash: credentials.store_hash,
|
|
577
|
+
accessToken: credentials.access_token
|
|
578
|
+
};
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
function storeCredentials(projectDir, credentials) {
|
|
582
|
+
const config = new Config(projectDir);
|
|
583
|
+
config.setAuth(credentials.storeHash, credentials.accessToken);
|
|
584
|
+
}
|
|
618
585
|
|
|
619
586
|
// src/utils/telemetry/telemetry.ts
|
|
620
587
|
import { Analytics } from "@segment/analytics-node";
|
|
@@ -702,28 +669,13 @@ var Telemetry = class {
|
|
|
702
669
|
};
|
|
703
670
|
|
|
704
671
|
// src/utils/write-env.ts
|
|
705
|
-
import { randomBytes as randomBytes2 } from "crypto";
|
|
706
672
|
import { outputFileSync } from "fs-extra/esm";
|
|
707
|
-
import { join } from "path";
|
|
708
|
-
var writeEnv = (projectDir, {
|
|
709
|
-
channelId,
|
|
710
|
-
storeHash,
|
|
711
|
-
storefrontToken,
|
|
712
|
-
arbitraryEnv
|
|
713
|
-
}) => {
|
|
673
|
+
import { join as join2 } from "path";
|
|
674
|
+
var writeEnv = (projectDir, envVars) => {
|
|
714
675
|
outputFileSync(
|
|
715
|
-
|
|
716
|
-
[
|
|
717
|
-
|
|
718
|
-
`BIGCOMMERCE_CHANNEL_ID=${channelId}`,
|
|
719
|
-
`BIGCOMMERCE_STOREFRONT_TOKEN=${storefrontToken}`,
|
|
720
|
-
"",
|
|
721
|
-
`AUTH_SECRET=${randomBytes2(32).toString("hex")}`,
|
|
722
|
-
`CLIENT_LOGGER=false`,
|
|
723
|
-
`ENABLE_ADMIN_ROUTE=true`,
|
|
724
|
-
`DEFAULT_REVALIDATE_TARGET=3600`,
|
|
725
|
-
arbitraryEnv == null ? void 0 : arbitraryEnv.map((env) => env).join("\n")
|
|
726
|
-
].join("\n")
|
|
676
|
+
join2(projectDir, ".env.local"),
|
|
677
|
+
`${Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n")}
|
|
678
|
+
`
|
|
727
679
|
);
|
|
728
680
|
};
|
|
729
681
|
|
|
@@ -733,284 +685,445 @@ function getPlatformCheckCommand(command) {
|
|
|
733
685
|
return isWindows2 ? `where.exe ${command}` : `which ${command}`;
|
|
734
686
|
}
|
|
735
687
|
var telemetry = new Telemetry();
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
)
|
|
741
|
-
|
|
688
|
+
function handleChannelCreation(cliApi) {
|
|
689
|
+
return __async(this, null, function* () {
|
|
690
|
+
const newChannelName = yield input({
|
|
691
|
+
message: "What would you like to name your new channel?"
|
|
692
|
+
});
|
|
693
|
+
const shouldInstallSampleData = yield select({
|
|
694
|
+
message: "Would you like to install sample data?",
|
|
695
|
+
choices: [
|
|
696
|
+
{ name: "Yes", value: true },
|
|
697
|
+
{ name: "No", value: false }
|
|
698
|
+
]
|
|
699
|
+
});
|
|
700
|
+
const response = yield cliApi.createChannel(newChannelName, shouldInstallSampleData);
|
|
701
|
+
if (!response.ok) {
|
|
702
|
+
console.error(
|
|
703
|
+
chalk3.red(`
|
|
704
|
+
POST /channels/catalyst failed: ${response.status} ${response.statusText}
|
|
705
|
+
`)
|
|
706
|
+
);
|
|
707
|
+
process.exit(1);
|
|
708
|
+
}
|
|
709
|
+
const channelData = yield response.json();
|
|
710
|
+
if (!isCreateChannelResponse(channelData)) {
|
|
711
|
+
console.error(chalk3.red("\nUnexpected response format from create channel endpoint\n"));
|
|
712
|
+
process.exit(1);
|
|
713
|
+
}
|
|
714
|
+
return {
|
|
715
|
+
channelId: channelData.data.id,
|
|
716
|
+
storefrontToken: channelData.data.storefront_api_token,
|
|
717
|
+
envVars: channelData.data.envVars
|
|
718
|
+
};
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
function handleChannelSelection(bc) {
|
|
722
|
+
return __async(this, null, function* () {
|
|
723
|
+
const channelSortOrder = ["catalyst", "next", "bigcommerce"];
|
|
724
|
+
const channelsResponse = yield bc.fetch("/v3/channels?available=true&type=storefront");
|
|
725
|
+
if (!channelsResponse.ok) {
|
|
726
|
+
console.error(
|
|
727
|
+
chalk3.red(
|
|
728
|
+
`
|
|
729
|
+
GET /v3/channels failed: ${channelsResponse.status} ${channelsResponse.statusText}
|
|
730
|
+
`
|
|
731
|
+
)
|
|
732
|
+
);
|
|
733
|
+
process.exit(1);
|
|
734
|
+
}
|
|
735
|
+
const availableChannels = yield channelsResponse.json();
|
|
736
|
+
if (!isChannelsResponse(availableChannels)) {
|
|
737
|
+
console.error(chalk3.red("\nUnexpected response format from channels endpoint\n"));
|
|
738
|
+
process.exit(1);
|
|
739
|
+
}
|
|
740
|
+
const existingChannel = yield select({
|
|
741
|
+
message: "Which channel would you like to use?",
|
|
742
|
+
choices: availableChannels.data.sort((a, b) => {
|
|
743
|
+
const aIndex = channelSortOrder.indexOf(a.platform);
|
|
744
|
+
const bIndex = channelSortOrder.indexOf(b.platform);
|
|
745
|
+
if (aIndex === -1 && bIndex === -1) {
|
|
746
|
+
return 0;
|
|
747
|
+
}
|
|
748
|
+
if (aIndex === -1) return 1;
|
|
749
|
+
if (bIndex === -1) return -1;
|
|
750
|
+
return aIndex - bIndex;
|
|
751
|
+
}).map((ch) => ({
|
|
752
|
+
name: ch.name,
|
|
753
|
+
value: ch,
|
|
754
|
+
description: `Channel Platform: ${ch.platform === "bigcommerce" ? "Stencil" : ch.platform.charAt(0).toUpperCase() + ch.platform.slice(1)}`
|
|
755
|
+
}))
|
|
756
|
+
});
|
|
757
|
+
return existingChannel.id;
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
function getChannelInit(cliApi, channelId) {
|
|
761
|
+
return __async(this, null, function* () {
|
|
762
|
+
const initResponse = yield cliApi.getChannelInit(channelId);
|
|
763
|
+
if (!initResponse.ok) {
|
|
764
|
+
console.error(
|
|
765
|
+
chalk3.red(
|
|
766
|
+
`
|
|
767
|
+
GET /channels/${channelId}/init failed: ${initResponse.status} ${initResponse.statusText}
|
|
768
|
+
`
|
|
769
|
+
)
|
|
770
|
+
);
|
|
771
|
+
process.exit(1);
|
|
772
|
+
}
|
|
773
|
+
const initData = yield initResponse.json();
|
|
774
|
+
if (!isInitResponse(initData)) {
|
|
775
|
+
console.error(chalk3.red("\nUnexpected response format from init endpoint\n"));
|
|
776
|
+
process.exit(1);
|
|
777
|
+
}
|
|
778
|
+
return {
|
|
779
|
+
storefrontToken: initData.data.storefront_api_token,
|
|
780
|
+
envVars: initData.data.envVars
|
|
781
|
+
};
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
function setupProject(options) {
|
|
785
|
+
return __async(this, null, function* () {
|
|
786
|
+
let { projectName, projectDir } = options;
|
|
787
|
+
if (!pathExistsSync(projectDir)) {
|
|
788
|
+
console.error(chalk3.red(`Error: --projectDir ${projectDir} is not a valid path
|
|
789
|
+
`));
|
|
790
|
+
process.exit(1);
|
|
791
|
+
}
|
|
792
|
+
if (projectName) {
|
|
793
|
+
projectName = kebabCase(projectName);
|
|
794
|
+
projectDir = join3(options.projectDir, projectName);
|
|
795
|
+
if (pathExistsSync(projectDir)) {
|
|
796
|
+
console.error(chalk3.red(`Error: ${projectDir} already exists
|
|
797
|
+
`));
|
|
798
|
+
process.exit(1);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
if (!projectName) {
|
|
802
|
+
const validateProjectName = (i) => {
|
|
803
|
+
const formatted = kebabCase(i);
|
|
804
|
+
if (!formatted) return "Project name is required";
|
|
805
|
+
const targetDir = join3(options.projectDir, formatted);
|
|
806
|
+
if (pathExistsSync(targetDir)) return `Destination '${targetDir}' already exists`;
|
|
807
|
+
projectName = formatted;
|
|
808
|
+
projectDir = targetDir;
|
|
809
|
+
return true;
|
|
810
|
+
};
|
|
811
|
+
yield input({
|
|
812
|
+
message: "What is the name of your project?",
|
|
813
|
+
default: "my-catalyst-app",
|
|
814
|
+
validate: validateProjectName
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
if (!projectName) throw new Error("Something went wrong, projectName is not defined");
|
|
818
|
+
if (!projectDir) throw new Error("Something went wrong, projectDir is not defined");
|
|
819
|
+
return { projectName, projectDir };
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
function checkRequiredTools() {
|
|
742
823
|
try {
|
|
743
|
-
|
|
824
|
+
execSync5(getPlatformCheckCommand("git"), { stdio: "ignore" });
|
|
744
825
|
} catch (e) {
|
|
745
|
-
console.error(
|
|
826
|
+
console.error(chalk3.red("Error: git is required to create a Catalyst project\n"));
|
|
746
827
|
process.exit(1);
|
|
747
828
|
}
|
|
748
829
|
try {
|
|
749
|
-
|
|
830
|
+
execSync5(getPlatformCheckCommand("pnpm"), { stdio: "ignore" });
|
|
750
831
|
} catch (e) {
|
|
751
|
-
console.error(
|
|
752
|
-
console.error(
|
|
832
|
+
console.error(chalk3.red("Error: pnpm is required to create a Catalyst project\n"));
|
|
833
|
+
console.error(chalk3.yellow("Tip: Enable it by running `corepack enable pnpm`\n"));
|
|
753
834
|
process.exit(1);
|
|
754
835
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
836
|
+
}
|
|
837
|
+
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("--storefront-token <token>", "BigCommerce storefront token").option("--gh-ref <ref>", "Clone a specific ref from the source repository").option("--reset-main", "Reset the main branch to the gh-ref").option("--repository <repository>", "GitHub repository to clone from", "bigcommerce/catalyst").option("--env <vars...>", "Arbitrary environment variables to set in .env.local").addOption(
|
|
838
|
+
new Option("--bigcommerce-hostname <hostname>", "BigCommerce hostname").default("bigcommerce.com").hideHelp()
|
|
839
|
+
).addOption(
|
|
840
|
+
new Option("--cli-api-origin <origin>", "Catalyst CLI API origin").default("https://cxm-prd.bigcommerceapp.com").hideHelp()
|
|
841
|
+
).action((options) => __async(void 0, null, function* () {
|
|
842
|
+
const { ghRef, repository } = options;
|
|
843
|
+
checkRequiredTools();
|
|
844
|
+
const { projectName, projectDir } = yield setupProject({
|
|
845
|
+
projectName: options.projectName,
|
|
846
|
+
projectDir: options.projectDir
|
|
847
|
+
});
|
|
761
848
|
let storeHash = options.storeHash;
|
|
762
849
|
let accessToken = options.accessToken;
|
|
763
850
|
let channelId;
|
|
764
851
|
let storefrontToken = options.storefrontToken;
|
|
852
|
+
let credentials;
|
|
765
853
|
if (options.channelId) {
|
|
766
854
|
channelId = parseInt(options.channelId, 10);
|
|
767
855
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
`)
|
|
771
|
-
process.exit(1);
|
|
772
|
-
}
|
|
773
|
-
if (options.projectName) {
|
|
774
|
-
projectName = kebabCase(options.projectName);
|
|
775
|
-
projectDir = join2(options.projectDir, projectName);
|
|
776
|
-
if (pathExistsSync(projectDir)) {
|
|
777
|
-
console.error(chalk4.red(`Error: ${projectDir} already exists
|
|
778
|
-
`));
|
|
779
|
-
process.exit(1);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
if (!options.projectName) {
|
|
783
|
-
const validateProjectName = (i) => {
|
|
784
|
-
const formatted = kebabCase(i);
|
|
785
|
-
if (!formatted) return "Project name is required";
|
|
786
|
-
const targetDir = join2(options.projectDir, formatted);
|
|
787
|
-
if (pathExistsSync(targetDir)) return `Destination '${targetDir}' already exists`;
|
|
788
|
-
projectName = formatted;
|
|
789
|
-
projectDir = targetDir;
|
|
790
|
-
return true;
|
|
791
|
-
};
|
|
792
|
-
yield input({
|
|
793
|
-
message: "What is the name of your project?",
|
|
794
|
-
default: "my-catalyst-app",
|
|
795
|
-
validate: validateProjectName
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
if (!projectName) throw new Error("Something went wrong, projectName is not defined");
|
|
799
|
-
if (!projectDir) throw new Error("Something went wrong, projectDir is not defined");
|
|
800
|
-
if (storeHash && channelId && storefrontToken) {
|
|
801
|
-
console.log(`
|
|
802
|
-
Creating '${projectName}' at '${projectDir}'
|
|
803
|
-
`);
|
|
804
|
-
cloneCatalyst({ repository, projectName, projectDir, ghRef });
|
|
805
|
-
writeEnv(projectDir, {
|
|
806
|
-
channelId: channelId.toString(),
|
|
807
|
-
storeHash,
|
|
808
|
-
storefrontToken,
|
|
809
|
-
arbitraryEnv: options.env
|
|
810
|
-
});
|
|
811
|
-
yield installDependencies(projectDir);
|
|
812
|
-
console.log(
|
|
813
|
-
`
|
|
814
|
-
${chalk4.green("Success!")} Created '${projectName}' at '${projectDir}'
|
|
815
|
-
`,
|
|
816
|
-
"\nNext steps:\n",
|
|
817
|
-
chalk4.yellow(`
|
|
818
|
-
cd ${projectName} && pnpm run dev
|
|
819
|
-
`)
|
|
820
|
-
);
|
|
821
|
-
process.exit(0);
|
|
822
|
-
}
|
|
823
|
-
if (!options.storeHash || !options.accessToken) {
|
|
824
|
-
const credentials = yield login(bigcommerceAuthUrl);
|
|
856
|
+
let envVars = {};
|
|
857
|
+
if ((!storeHash || !accessToken) && (!channelId || !storefrontToken)) {
|
|
858
|
+
credentials = yield login(`https://login.${options.bigcommerceHostname}`);
|
|
825
859
|
storeHash = credentials.storeHash;
|
|
826
860
|
accessToken = credentials.accessToken;
|
|
827
861
|
}
|
|
828
|
-
if (
|
|
829
|
-
|
|
862
|
+
if (storeHash && channelId && storefrontToken) {
|
|
863
|
+
envVars.BIGCOMMERCE_STORE_HASH = storeHash;
|
|
864
|
+
envVars.BIGCOMMERCE_CHANNEL_ID = channelId.toString();
|
|
865
|
+
envVars.BIGCOMMERCE_STOREFRONT_API_TOKEN = storefrontToken;
|
|
866
|
+
} else {
|
|
867
|
+
if (!storeHash || !accessToken) {
|
|
868
|
+
console.log(`
|
|
830
869
|
Creating '${projectName}' at '${projectDir}'
|
|
831
870
|
`);
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
871
|
+
cloneCatalyst({ repository, projectName, projectDir, ghRef, resetMain: options.resetMain });
|
|
872
|
+
yield installDependencies(projectDir);
|
|
873
|
+
if (options.env) {
|
|
874
|
+
const cliEnvVars = options.env.reduce((acc, env) => {
|
|
875
|
+
const [key, value] = env.split("=");
|
|
876
|
+
if (key && value) {
|
|
877
|
+
acc[key] = value;
|
|
878
|
+
}
|
|
879
|
+
return acc;
|
|
880
|
+
}, {});
|
|
881
|
+
Object.assign(envVars, cliEnvVars);
|
|
882
|
+
}
|
|
883
|
+
writeEnv(projectDir, envVars);
|
|
884
|
+
console.log(
|
|
885
|
+
[
|
|
886
|
+
`
|
|
887
|
+
${chalk3.green("Success!")} Created '${projectName}' at '${projectDir}'
|
|
838
888
|
`,
|
|
839
|
-
|
|
840
|
-
|
|
889
|
+
`Next steps:`,
|
|
890
|
+
Object.keys(envVars).length > 0 ? chalk3.yellow(`
|
|
891
|
+
- cd ${projectName} && pnpm run dev
|
|
892
|
+
`) : [
|
|
893
|
+
chalk3.yellow(`
|
|
841
894
|
- cd ${projectName} && cp .env.example .env.local`),
|
|
842
|
-
|
|
895
|
+
chalk3.yellow(`
|
|
843
896
|
- Populate .env.local with your BigCommerce API credentials
|
|
844
897
|
`)
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
yield telemetry.identify(storeHash);
|
|
850
|
-
if (!channelId || !storefrontToken) {
|
|
851
|
-
const bc = new Https({ bigCommerceApiUrl: bigcommerceApiUrl, storeHash, accessToken });
|
|
852
|
-
const sampleDataApi = new Https({
|
|
853
|
-
sampleDataApiUrl,
|
|
854
|
-
storeHash,
|
|
855
|
-
accessToken
|
|
856
|
-
});
|
|
857
|
-
const eligibilityResponse = yield sampleDataApi.checkEligibility();
|
|
858
|
-
if (!eligibilityResponse.data.eligible) {
|
|
859
|
-
console.warn(chalk4.yellow(eligibilityResponse.data.message));
|
|
860
|
-
}
|
|
861
|
-
let shouldCreateChannel;
|
|
862
|
-
if (eligibilityResponse.data.eligible) {
|
|
863
|
-
shouldCreateChannel = yield select2({
|
|
864
|
-
message: "Would you like to create a new channel?",
|
|
865
|
-
choices: [
|
|
866
|
-
{ name: "Yes", value: true },
|
|
867
|
-
{ name: "No", value: false }
|
|
868
|
-
]
|
|
869
|
-
});
|
|
898
|
+
].join("")
|
|
899
|
+
].join("\n")
|
|
900
|
+
);
|
|
901
|
+
process.exit(0);
|
|
870
902
|
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
903
|
+
yield telemetry.identify(storeHash);
|
|
904
|
+
if (!channelId || !storefrontToken) {
|
|
905
|
+
const bc = new Https({
|
|
906
|
+
baseUrl: `https://api.${options.bigcommerceHostname}/stores/${storeHash}`,
|
|
907
|
+
accessToken
|
|
874
908
|
});
|
|
875
|
-
const {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
channelId = createdChannelId;
|
|
880
|
-
storefrontToken = storefrontApiToken;
|
|
881
|
-
}
|
|
882
|
-
if (!shouldCreateChannel) {
|
|
883
|
-
const channelSortOrder = ["catalyst", "next", "bigcommerce"];
|
|
884
|
-
const availableChannels = yield bc.channels("?available=true&type=storefront");
|
|
885
|
-
const existingChannel = yield select2({
|
|
886
|
-
message: "Which channel would you like to use?",
|
|
887
|
-
choices: availableChannels.data.sort(
|
|
888
|
-
(a, b) => channelSortOrder.indexOf(a.platform) - channelSortOrder.indexOf(b.platform)
|
|
889
|
-
).map((ch) => ({
|
|
890
|
-
name: ch.name,
|
|
891
|
-
value: ch,
|
|
892
|
-
description: `Channel Platform: ${ch.platform === "bigcommerce" ? "Stencil" : ch.platform.charAt(0).toUpperCase() + ch.platform.slice(1)}`
|
|
893
|
-
}))
|
|
909
|
+
const cliApi = new CliApi({
|
|
910
|
+
origin: options.cliApiOrigin,
|
|
911
|
+
storeHash,
|
|
912
|
+
accessToken
|
|
894
913
|
});
|
|
895
|
-
channelId
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
914
|
+
if (channelId && !storefrontToken) {
|
|
915
|
+
const initData = yield getChannelInit(cliApi, channelId);
|
|
916
|
+
envVars = __spreadValues({}, initData.envVars);
|
|
917
|
+
storefrontToken = initData.storefrontToken;
|
|
918
|
+
} else if (!channelId) {
|
|
919
|
+
const eligibilityResponse = yield cliApi.checkEligibility();
|
|
920
|
+
if (!eligibilityResponse.ok) {
|
|
921
|
+
console.error(
|
|
922
|
+
chalk3.red(
|
|
923
|
+
`
|
|
924
|
+
GET /channels/catalyst/eligibility failed: ${eligibilityResponse.status} ${eligibilityResponse.statusText}
|
|
925
|
+
`
|
|
926
|
+
)
|
|
927
|
+
);
|
|
928
|
+
process.exit(1);
|
|
929
|
+
}
|
|
930
|
+
const eligibilityData = yield eligibilityResponse.json();
|
|
931
|
+
if (!isEligibilityResponse(eligibilityData)) {
|
|
932
|
+
console.error(chalk3.red("\nUnexpected response format from eligibility endpoint\n"));
|
|
933
|
+
process.exit(1);
|
|
934
|
+
}
|
|
935
|
+
if (!eligibilityData.data.eligible) {
|
|
936
|
+
console.warn(chalk3.yellow(eligibilityData.data.message));
|
|
937
|
+
}
|
|
938
|
+
let shouldCreateChannel;
|
|
939
|
+
if (eligibilityData.data.eligible) {
|
|
940
|
+
shouldCreateChannel = yield select({
|
|
941
|
+
message: "Would you like to create a new channel?",
|
|
942
|
+
choices: [
|
|
943
|
+
{ name: "Yes", value: true },
|
|
944
|
+
{ name: "No", value: false }
|
|
945
|
+
]
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
if (shouldCreateChannel) {
|
|
949
|
+
const channelData = yield handleChannelCreation(cliApi);
|
|
950
|
+
channelId = channelData.channelId;
|
|
951
|
+
storefrontToken = channelData.storefrontToken;
|
|
952
|
+
envVars = __spreadValues({}, channelData.envVars);
|
|
953
|
+
console.log(chalk3.green(`Channel created successfully`));
|
|
954
|
+
}
|
|
955
|
+
if (!shouldCreateChannel) {
|
|
956
|
+
channelId = yield handleChannelSelection(bc);
|
|
957
|
+
const initData = yield getChannelInit(cliApi, channelId);
|
|
958
|
+
envVars = __spreadValues({}, initData.envVars);
|
|
959
|
+
storefrontToken = initData.storefrontToken;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
900
962
|
}
|
|
901
963
|
}
|
|
964
|
+
if (options.env) {
|
|
965
|
+
const cliEnvVars = options.env.reduce((acc, env) => {
|
|
966
|
+
const [key, value] = env.split("=");
|
|
967
|
+
if (key && value) {
|
|
968
|
+
acc[key] = value;
|
|
969
|
+
}
|
|
970
|
+
return acc;
|
|
971
|
+
}, {});
|
|
972
|
+
Object.assign(envVars, cliEnvVars);
|
|
973
|
+
}
|
|
974
|
+
if (options.storeHash) {
|
|
975
|
+
envVars.BIGCOMMERCE_STORE_HASH = options.storeHash;
|
|
976
|
+
}
|
|
977
|
+
if (options.channelId) {
|
|
978
|
+
envVars.BIGCOMMERCE_CHANNEL_ID = options.channelId;
|
|
979
|
+
}
|
|
980
|
+
if (options.storefrontToken) {
|
|
981
|
+
envVars.BIGCOMMERCE_STOREFRONT_TOKEN = options.storefrontToken;
|
|
982
|
+
}
|
|
902
983
|
if (!channelId) throw new Error("Something went wrong, channelId is not defined");
|
|
903
984
|
if (!storefrontToken) throw new Error("Something went wrong, storefrontToken is not defined");
|
|
904
985
|
console.log(`
|
|
905
986
|
Creating '${projectName}' at '${projectDir}'
|
|
906
987
|
`);
|
|
907
|
-
cloneCatalyst({ repository, projectName, projectDir, ghRef });
|
|
908
|
-
writeEnv(projectDir, {
|
|
909
|
-
channelId: channelId.toString(),
|
|
910
|
-
storeHash,
|
|
911
|
-
storefrontToken,
|
|
912
|
-
arbitraryEnv: options.env
|
|
913
|
-
});
|
|
988
|
+
cloneCatalyst({ repository, projectName, projectDir, ghRef, resetMain: options.resetMain });
|
|
914
989
|
yield installDependencies(projectDir);
|
|
990
|
+
writeEnv(projectDir, envVars);
|
|
991
|
+
if (credentials) {
|
|
992
|
+
storeCredentials(projectDir, credentials);
|
|
993
|
+
}
|
|
915
994
|
console.log(
|
|
916
995
|
`
|
|
917
|
-
${
|
|
996
|
+
${chalk3.green("Success!")} Created '${projectName}' at '${projectDir}'
|
|
918
997
|
`,
|
|
919
998
|
"\nNext steps:\n",
|
|
920
|
-
|
|
999
|
+
chalk3.yellow(`
|
|
921
1000
|
cd ${projectName} && pnpm run dev
|
|
922
1001
|
`)
|
|
923
1002
|
);
|
|
924
1003
|
}));
|
|
1004
|
+
function isInitResponse(response) {
|
|
1005
|
+
return typeof response === "object" && response !== null && "data" in response && typeof response.data === "object" && response.data !== null && "storefront_api_token" in response.data && "envVars" in response.data;
|
|
1006
|
+
}
|
|
1007
|
+
function isEligibilityResponse(response) {
|
|
1008
|
+
return typeof response === "object" && response !== null && "data" in response && typeof response.data === "object" && response.data !== null && "eligible" in response.data && "message" in response.data;
|
|
1009
|
+
}
|
|
1010
|
+
function isCreateChannelResponse(response) {
|
|
1011
|
+
return typeof response === "object" && response !== null && "data" in response && typeof response.data === "object" && response.data !== null && "id" in response.data && "storefront_api_token" in response.data && "envVars" in response.data;
|
|
1012
|
+
}
|
|
1013
|
+
function isChannelsResponse(response) {
|
|
1014
|
+
return typeof response === "object" && response !== null && "data" in response && Array.isArray(response.data) && response.data.every(
|
|
1015
|
+
(item) => typeof item === "object" && item !== null && "id" in item && "name" in item && "platform" in item
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
925
1018
|
|
|
926
1019
|
// src/commands/init.ts
|
|
927
1020
|
import { Command as Command2, Option as Option2 } from "@commander-js/extra-typings";
|
|
928
|
-
import {
|
|
929
|
-
import
|
|
930
|
-
|
|
1021
|
+
import { select as select2 } from "@inquirer/prompts";
|
|
1022
|
+
import chalk4 from "chalk";
|
|
1023
|
+
function isChannelsResponse2(response) {
|
|
1024
|
+
return typeof response === "object" && response !== null && "data" in response && Array.isArray(response.data) && response.data.every(
|
|
1025
|
+
(item) => typeof item === "object" && item !== null && "id" in item && "name" in item && "platform" in item
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
function isInitResponse2(response) {
|
|
1029
|
+
return typeof response === "object" && response !== null && "data" in response && typeof response.data === "object" && response.data !== null && "storefront_api_token" in response.data && "envVars" in response.data;
|
|
1030
|
+
}
|
|
931
1031
|
var telemetry2 = new Telemetry();
|
|
932
|
-
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(
|
|
1032
|
+
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").option("--env <vars...>", "Arbitrary environment variables to set in .env.local").addOption(
|
|
933
1033
|
new Option2("--bigcommerce-hostname <hostname>", "BigCommerce hostname").default("bigcommerce.com").hideHelp()
|
|
934
1034
|
).addOption(
|
|
935
|
-
new Option2("--
|
|
1035
|
+
new Option2("--cli-api-origin <origin>", "Catalyst CLI API origin").default("https://cxm-prd.bigcommerceapp.com").hideHelp()
|
|
936
1036
|
).action((options) => __async(void 0, null, function* () {
|
|
937
1037
|
const projectDir = process.cwd();
|
|
938
|
-
const URLSchema = z4.string().url();
|
|
939
|
-
const sampleDataApiUrl = parse(options.sampleDataApiUrl, URLSchema);
|
|
940
|
-
const bigCommerceApiUrl = `https://api.${options.bigcommerceHostname}`;
|
|
941
|
-
const bigCommerceAuthUrl = `https://login.${options.bigcommerceHostname}`;
|
|
942
1038
|
let storeHash = options.storeHash;
|
|
943
1039
|
let accessToken = options.accessToken;
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
accessToken = credentials.accessToken;
|
|
1040
|
+
if (!storeHash || !accessToken) {
|
|
1041
|
+
const config = new Config(projectDir);
|
|
1042
|
+
const storedAuth = config.getAuth();
|
|
1043
|
+
storeHash = storeHash != null ? storeHash : storedAuth.storeHash;
|
|
1044
|
+
accessToken = accessToken != null ? accessToken : storedAuth.accessToken;
|
|
950
1045
|
}
|
|
951
1046
|
if (!storeHash || !accessToken) {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1047
|
+
const credentials = yield login(`https://login.${options.bigcommerceHostname}`);
|
|
1048
|
+
storeHash = credentials.storeHash;
|
|
1049
|
+
accessToken = credentials.accessToken;
|
|
1050
|
+
storeCredentials(projectDir, credentials);
|
|
956
1051
|
}
|
|
957
1052
|
yield telemetry2.identify(storeHash);
|
|
958
|
-
const bc = new Https({
|
|
959
|
-
|
|
960
|
-
|
|
1053
|
+
const bc = new Https({
|
|
1054
|
+
baseUrl: `https://api.${options.bigcommerceHostname}/stores/${storeHash}`,
|
|
1055
|
+
accessToken
|
|
1056
|
+
});
|
|
1057
|
+
const cliApi = new CliApi({
|
|
1058
|
+
origin: options.cliApiOrigin,
|
|
961
1059
|
storeHash,
|
|
962
1060
|
accessToken
|
|
963
1061
|
});
|
|
964
|
-
const
|
|
965
|
-
|
|
966
|
-
|
|
1062
|
+
const channelSortOrder = ["catalyst", "next", "bigcommerce"];
|
|
1063
|
+
const channelsResponse = yield bc.fetch("/v3/channels?available=true&type=storefront");
|
|
1064
|
+
if (!channelsResponse.ok) {
|
|
1065
|
+
console.error(
|
|
1066
|
+
chalk4.red(
|
|
1067
|
+
`
|
|
1068
|
+
GET /v3/channels failed: ${channelsResponse.status} ${channelsResponse.statusText}
|
|
1069
|
+
`
|
|
1070
|
+
)
|
|
1071
|
+
);
|
|
1072
|
+
process.exit(1);
|
|
967
1073
|
}
|
|
968
|
-
|
|
969
|
-
if (
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
choices: [
|
|
973
|
-
{ name: "Yes", value: true },
|
|
974
|
-
{ name: "No", value: false }
|
|
975
|
-
]
|
|
976
|
-
});
|
|
1074
|
+
const availableChannels = yield channelsResponse.json();
|
|
1075
|
+
if (!isChannelsResponse2(availableChannels)) {
|
|
1076
|
+
console.error(chalk4.red("\nUnexpected response format from channels endpoint\n"));
|
|
1077
|
+
process.exit(1);
|
|
977
1078
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1079
|
+
const existingChannel = yield select2({
|
|
1080
|
+
message: "Which channel would you like to use?",
|
|
1081
|
+
choices: availableChannels.data.sort(
|
|
1082
|
+
(a, b) => channelSortOrder.indexOf(a.platform) - channelSortOrder.indexOf(b.platform)
|
|
1083
|
+
).map((ch) => ({
|
|
1084
|
+
name: ch.name,
|
|
1085
|
+
value: ch,
|
|
1086
|
+
description: `Channel Platform: ${ch.platform === "bigcommerce" ? "Stencil" : ch.platform.charAt(0).toUpperCase() + ch.platform.slice(1)}`
|
|
1087
|
+
}))
|
|
1088
|
+
});
|
|
1089
|
+
const channelId = existingChannel.id;
|
|
1090
|
+
const initResponse = yield cliApi.getChannelInit(channelId);
|
|
1091
|
+
if (!initResponse.ok) {
|
|
1092
|
+
console.error(
|
|
1093
|
+
chalk4.red(
|
|
1094
|
+
`
|
|
1095
|
+
GET /channels/${channelId}/init failed: ${initResponse.status} ${initResponse.statusText}
|
|
1096
|
+
`
|
|
1097
|
+
)
|
|
1098
|
+
);
|
|
1099
|
+
process.exit(1);
|
|
987
1100
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
message: "Which channel would you like to use?",
|
|
993
|
-
choices: availableChannels.data.sort(
|
|
994
|
-
(a, b) => channelSortOrder.indexOf(a.platform) - channelSortOrder.indexOf(b.platform)
|
|
995
|
-
).map((ch) => ({
|
|
996
|
-
name: ch.name,
|
|
997
|
-
value: ch,
|
|
998
|
-
description: `Channel Platform: ${ch.platform === "bigcommerce" ? "Stencil" : ch.platform.charAt(0).toUpperCase() + ch.platform.slice(1)}`
|
|
999
|
-
}))
|
|
1000
|
-
});
|
|
1001
|
-
channelId = existingChannel.id;
|
|
1002
|
-
const {
|
|
1003
|
-
data: { token: sfToken }
|
|
1004
|
-
} = yield bc.storefrontToken();
|
|
1005
|
-
storefrontToken = sfToken;
|
|
1101
|
+
const initData = yield initResponse.json();
|
|
1102
|
+
if (!isInitResponse2(initData)) {
|
|
1103
|
+
console.error(chalk4.red("\nUnexpected response format from init endpoint\n"));
|
|
1104
|
+
process.exit(1);
|
|
1006
1105
|
}
|
|
1007
|
-
|
|
1008
|
-
if (
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1106
|
+
const envVars = __spreadValues({}, initData.data.envVars);
|
|
1107
|
+
if (options.env) {
|
|
1108
|
+
const cliEnvVars = options.env.reduce((acc, env) => {
|
|
1109
|
+
const [key, value] = env.split("=");
|
|
1110
|
+
if (key && value) {
|
|
1111
|
+
acc[key] = value;
|
|
1112
|
+
}
|
|
1113
|
+
return acc;
|
|
1114
|
+
}, {});
|
|
1115
|
+
Object.assign(envVars, cliEnvVars);
|
|
1116
|
+
}
|
|
1117
|
+
writeEnv(projectDir, envVars);
|
|
1118
|
+
console.log(chalk4.green(`
|
|
1119
|
+
.env.local file created for channel ${existingChannel.name}!
|
|
1120
|
+
`));
|
|
1121
|
+
console.log(chalk4.green(`
|
|
1122
|
+
Next steps:
|
|
1123
|
+
`));
|
|
1124
|
+
console.log(chalk4.yellow(`
|
|
1125
|
+
pnpm run dev
|
|
1126
|
+
`));
|
|
1014
1127
|
}));
|
|
1015
1128
|
|
|
1016
1129
|
// src/commands/integration.ts
|
|
@@ -1021,16 +1134,16 @@ import { outputFileSync as outputFileSync2, writeJsonSync } from "fs-extra/esm";
|
|
|
1021
1134
|
import kebabCase2 from "lodash.kebabcase";
|
|
1022
1135
|
import { coerce, compare } from "semver";
|
|
1023
1136
|
import { promisify } from "util";
|
|
1024
|
-
import { z as
|
|
1137
|
+
import { z as z3 } from "zod";
|
|
1025
1138
|
var exec = promisify(execCb);
|
|
1026
|
-
var ManifestSchema =
|
|
1027
|
-
name:
|
|
1028
|
-
dependencies:
|
|
1029
|
-
devDependencies:
|
|
1030
|
-
environmentVariables:
|
|
1139
|
+
var ManifestSchema = z3.object({
|
|
1140
|
+
name: z3.string(),
|
|
1141
|
+
dependencies: z3.object({ add: z3.array(z3.string()) }),
|
|
1142
|
+
devDependencies: z3.object({ add: z3.array(z3.string()) }),
|
|
1143
|
+
environmentVariables: z3.array(z3.string())
|
|
1031
1144
|
});
|
|
1032
1145
|
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* () {
|
|
1033
|
-
const integrationName =
|
|
1146
|
+
const integrationName = z3.string().transform(kebabCase2).parse(integrationNameRaw);
|
|
1034
1147
|
const manifest = {
|
|
1035
1148
|
name: integrationName,
|
|
1036
1149
|
dependencies: { add: [] },
|
|
@@ -1052,9 +1165,9 @@ var integration = new Command3("integration").argument("<integration-name>", "Fo
|
|
|
1052
1165
|
}
|
|
1053
1166
|
return 0;
|
|
1054
1167
|
}).reverse();
|
|
1055
|
-
const PackageDependenciesSchema =
|
|
1056
|
-
dependencies:
|
|
1057
|
-
devDependencies:
|
|
1168
|
+
const PackageDependenciesSchema = z3.object({
|
|
1169
|
+
dependencies: z3.object({}).passthrough(),
|
|
1170
|
+
devDependencies: z3.object({}).passthrough()
|
|
1058
1171
|
});
|
|
1059
1172
|
const getPackageDeps = (ref) => __async(void 0, null, function* () {
|
|
1060
1173
|
const { stdout } = yield exec(`git show ${ref}:core/package.json`);
|
|
@@ -1090,7 +1203,7 @@ var integration = new Command3("integration").argument("<integration-name>", "Fo
|
|
|
1090
1203
|
import { Argument, Command as Command4, Option as Option3 } from "@commander-js/extra-typings";
|
|
1091
1204
|
|
|
1092
1205
|
// src/utils/telemetry/index.ts
|
|
1093
|
-
import
|
|
1206
|
+
import chalk5 from "chalk";
|
|
1094
1207
|
var telemetry3 = new Telemetry();
|
|
1095
1208
|
var isEnabled = telemetry3.isEnabled();
|
|
1096
1209
|
var catalystTelemetry = (options, arg) => {
|
|
@@ -1111,7 +1224,7 @@ var catalystTelemetry = (options, arg) => {
|
|
|
1111
1224
|
}
|
|
1112
1225
|
console.log(
|
|
1113
1226
|
`
|
|
1114
|
-
Status: ${
|
|
1227
|
+
Status: ${chalk5.bold(isEnabled ? chalk5.green("Enabled") : chalk5.red("Disabled"))}`
|
|
1115
1228
|
);
|
|
1116
1229
|
if (!isEnabled) {
|
|
1117
1230
|
console.log(
|
|
@@ -1164,7 +1277,7 @@ var telemetryPostHook = () => __async(void 0, null, function* () {
|
|
|
1164
1277
|
});
|
|
1165
1278
|
|
|
1166
1279
|
// src/index.ts
|
|
1167
|
-
console.log(
|
|
1280
|
+
console.log(chalk6.cyanBright(`
|
|
1168
1281
|
\u25E2 ${package_default.name} v${package_default.version}
|
|
1169
1282
|
`));
|
|
1170
1283
|
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).addCommand(telemetry4).hook("preAction", telemetryPreHook).hook("postAction", telemetryPostHook);
|