create-brainerce-store 1.23.0 → 1.25.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 +110 -27
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "create-brainerce-store",
|
|
34
|
-
version: "1.
|
|
34
|
+
version: "1.25.0",
|
|
35
35
|
description: "Scaffold a production-ready e-commerce storefront connected to Brainerce",
|
|
36
36
|
bin: {
|
|
37
37
|
"create-brainerce-store": "dist/index.js"
|
|
@@ -44,7 +44,8 @@ var require_package = __commonJS({
|
|
|
44
44
|
scripts: {
|
|
45
45
|
build: "tsup src/index.ts --format cjs --dts --clean",
|
|
46
46
|
dev: "tsup src/index.ts --format cjs --dts --watch",
|
|
47
|
-
clean: "rimraf dist"
|
|
47
|
+
clean: "rimraf dist",
|
|
48
|
+
prepublishOnly: "npm run build"
|
|
48
49
|
},
|
|
49
50
|
dependencies: {
|
|
50
51
|
chalk: "^4.1.2",
|
|
@@ -173,6 +174,17 @@ async function runInteractive(defaults) {
|
|
|
173
174
|
return error || true;
|
|
174
175
|
}
|
|
175
176
|
});
|
|
177
|
+
} else {
|
|
178
|
+
questions.push({
|
|
179
|
+
type: "text",
|
|
180
|
+
name: "projectName",
|
|
181
|
+
message: "Project name:",
|
|
182
|
+
initial: defaults.projectName,
|
|
183
|
+
validate: (value) => {
|
|
184
|
+
const error = validateProjectName(value);
|
|
185
|
+
return error || true;
|
|
186
|
+
}
|
|
187
|
+
});
|
|
176
188
|
}
|
|
177
189
|
if (!defaults.connectionId) {
|
|
178
190
|
questions.push({
|
|
@@ -410,7 +422,17 @@ async function copyWithEjs(srcDir, destDir, vars) {
|
|
|
410
422
|
}
|
|
411
423
|
|
|
412
424
|
// src/fetch-store-info.ts
|
|
413
|
-
|
|
425
|
+
var KNOWN_API_URLS = {
|
|
426
|
+
production: "https://api.brainerce.com",
|
|
427
|
+
staging: "https://api-staging.brainerce.com"
|
|
428
|
+
};
|
|
429
|
+
var ConnectionNotFoundError = class extends Error {
|
|
430
|
+
constructor(connectionId, baseUrl) {
|
|
431
|
+
super(`Connection "${connectionId}" not found at ${baseUrl}`);
|
|
432
|
+
this.code = "NOT_FOUND";
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
async function fetchStoreInfo(connectionId, baseUrl = KNOWN_API_URLS.production) {
|
|
414
436
|
const url = `${baseUrl}/api/vc/${connectionId}/info`;
|
|
415
437
|
const controller = new AbortController();
|
|
416
438
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
@@ -419,23 +441,23 @@ async function fetchStoreInfo(connectionId, baseUrl = "https://api.brainerce.com
|
|
|
419
441
|
res = await fetch(url, { signal: controller.signal });
|
|
420
442
|
} catch (err) {
|
|
421
443
|
if (err.name === "AbortError") {
|
|
422
|
-
throw new Error(
|
|
444
|
+
throw new Error(`Request to ${baseUrl} timed out`);
|
|
423
445
|
}
|
|
424
|
-
throw new Error(`Failed to connect to
|
|
446
|
+
throw new Error(`Failed to connect to ${baseUrl}: ${err.message}`);
|
|
425
447
|
} finally {
|
|
426
448
|
clearTimeout(timeout);
|
|
427
449
|
}
|
|
428
450
|
if (res.status === 404) {
|
|
429
|
-
throw new
|
|
451
|
+
throw new ConnectionNotFoundError(connectionId, baseUrl);
|
|
430
452
|
}
|
|
431
453
|
if (!res.ok) {
|
|
432
|
-
throw new Error(
|
|
454
|
+
throw new Error(`${baseUrl} returned status ${res.status}`);
|
|
433
455
|
}
|
|
434
456
|
let json;
|
|
435
457
|
try {
|
|
436
458
|
json = await res.json();
|
|
437
459
|
} catch {
|
|
438
|
-
throw new Error(
|
|
460
|
+
throw new Error(`Invalid response from ${baseUrl}`);
|
|
439
461
|
}
|
|
440
462
|
return {
|
|
441
463
|
name: json.name || json.storeName || "My Store",
|
|
@@ -444,6 +466,33 @@ async function fetchStoreInfo(connectionId, baseUrl = "https://api.brainerce.com
|
|
|
444
466
|
...json.i18n ? { i18n: json.i18n } : {}
|
|
445
467
|
};
|
|
446
468
|
}
|
|
469
|
+
async function resolveStoreInfo(connectionId, candidateUrls) {
|
|
470
|
+
const urls = candidateUrls.filter((u, i) => u && candidateUrls.indexOf(u) === i);
|
|
471
|
+
if (urls.length === 0) {
|
|
472
|
+
throw new Error("No API URLs to try");
|
|
473
|
+
}
|
|
474
|
+
let lastError;
|
|
475
|
+
let allNotFound = true;
|
|
476
|
+
for (let i = 0; i < urls.length; i++) {
|
|
477
|
+
const baseUrl = urls[i];
|
|
478
|
+
try {
|
|
479
|
+
const info = await fetchStoreInfo(connectionId, baseUrl);
|
|
480
|
+
return { info, apiBaseUrl: baseUrl, fellBack: i > 0 };
|
|
481
|
+
} catch (err) {
|
|
482
|
+
lastError = err;
|
|
483
|
+
const isNotFound = err.code === "NOT_FOUND";
|
|
484
|
+
if (!isNotFound) {
|
|
485
|
+
allNotFound = false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (allNotFound) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
`Connection "${connectionId}" not found in any known environment (${urls.join(", ")}). Check your dashboard.`
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
throw lastError || new Error("Failed to resolve store info");
|
|
495
|
+
}
|
|
447
496
|
|
|
448
497
|
// src/utils/logger.ts
|
|
449
498
|
var import_chalk = __toESM(require("chalk"));
|
|
@@ -537,18 +586,48 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
|
|
|
537
586
|
scaffoldInPlace = true;
|
|
538
587
|
}
|
|
539
588
|
let connectionId = options.connectionId;
|
|
540
|
-
const
|
|
589
|
+
const explicitApiUrl = (options.apiUrl || process.env.BRAINERCE_API_URL || "").replace(/\/$/, "");
|
|
590
|
+
const candidateApiUrls = explicitApiUrl ? [explicitApiUrl] : [KNOWN_API_URLS.production, KNOWN_API_URLS.staging];
|
|
541
591
|
let language = options.language;
|
|
542
592
|
let framework = options.framework;
|
|
543
593
|
let theme = options.theme;
|
|
544
594
|
let pkgManager = options.pkgManager;
|
|
545
595
|
const skipGit = options.git === false;
|
|
546
596
|
const skipInstall = options.install === false;
|
|
597
|
+
let storeInfo = null;
|
|
598
|
+
let resolvedApiUrl = candidateApiUrls[0];
|
|
599
|
+
if (connectionId) {
|
|
600
|
+
const connError2 = validateConnectionId(connectionId);
|
|
601
|
+
if (connError2) {
|
|
602
|
+
logger.error(connError2);
|
|
603
|
+
process.exit(1);
|
|
604
|
+
}
|
|
605
|
+
const prefetchSpinner = createSpinner("Fetching store info...");
|
|
606
|
+
prefetchSpinner.start();
|
|
607
|
+
try {
|
|
608
|
+
const resolved = await resolveStoreInfo(connectionId, candidateApiUrls);
|
|
609
|
+
storeInfo = resolved.info;
|
|
610
|
+
resolvedApiUrl = resolved.apiBaseUrl;
|
|
611
|
+
const envLabel = resolved.apiBaseUrl === KNOWN_API_URLS.staging ? " [staging]" : resolved.apiBaseUrl === KNOWN_API_URLS.production ? "" : ` [${resolved.apiBaseUrl}]`;
|
|
612
|
+
const i18nStatus = storeInfo.i18n?.enabled && storeInfo.i18n.supportedLocales.length > 1 ? ` | i18n: ${storeInfo.i18n.supportedLocales.join(", ")}` : "";
|
|
613
|
+
prefetchSpinner.succeed(
|
|
614
|
+
`Store: "${storeInfo.name}" | ${storeInfo.currency} | ${storeInfo.language}${i18nStatus}${envLabel}`
|
|
615
|
+
);
|
|
616
|
+
} catch (err) {
|
|
617
|
+
prefetchSpinner.fail("Could not fetch store info");
|
|
618
|
+
logger.warn(
|
|
619
|
+
err instanceof Error ? err.message : "Using defaults. Make sure the connection ID is correct and the Brainerce API is reachable."
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
const slugify = (s) => s.toLowerCase().trim().replace(/[^a-z0-9\u0590-\u05FF]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50);
|
|
624
|
+
const projectNameDefault = projectName || (storeInfo ? slugify(storeInfo.name) : void 0);
|
|
625
|
+
const languageDefault = language || storeInfo?.language;
|
|
547
626
|
if (!projectName || !connectionId || !language) {
|
|
548
627
|
const answers = await runInteractive({
|
|
549
|
-
projectName,
|
|
628
|
+
projectName: projectNameDefault,
|
|
550
629
|
connectionId,
|
|
551
|
-
language,
|
|
630
|
+
language: languageDefault,
|
|
552
631
|
framework,
|
|
553
632
|
theme,
|
|
554
633
|
pkgManager
|
|
@@ -570,21 +649,25 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
|
|
|
570
649
|
logger.error(connError);
|
|
571
650
|
process.exit(1);
|
|
572
651
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
652
|
+
if (!storeInfo) {
|
|
653
|
+
const spinner = createSpinner("Fetching store info...");
|
|
654
|
+
spinner.start();
|
|
655
|
+
try {
|
|
656
|
+
const resolved = await resolveStoreInfo(connectionId, candidateApiUrls);
|
|
657
|
+
storeInfo = resolved.info;
|
|
658
|
+
resolvedApiUrl = resolved.apiBaseUrl;
|
|
659
|
+
const envLabel = resolved.apiBaseUrl === KNOWN_API_URLS.staging ? " [staging]" : resolved.apiBaseUrl === KNOWN_API_URLS.production ? "" : ` [${resolved.apiBaseUrl}]`;
|
|
660
|
+
const i18nStatus = storeInfo.i18n?.enabled && storeInfo.i18n.supportedLocales.length > 1 ? ` | i18n: ${storeInfo.i18n.supportedLocales.join(", ")}` : "";
|
|
661
|
+
spinner.succeed(
|
|
662
|
+
`Store: "${storeInfo.name}" | ${storeInfo.currency} | ${storeInfo.language}${i18nStatus}${envLabel}`
|
|
663
|
+
);
|
|
664
|
+
} catch (err) {
|
|
665
|
+
spinner.fail("Could not fetch store info");
|
|
666
|
+
logger.warn(
|
|
667
|
+
err instanceof Error ? err.message : "Using defaults. Make sure the connection ID is correct and the Brainerce API is reachable."
|
|
668
|
+
);
|
|
669
|
+
storeInfo = { name: projectName, currency: "USD", language: "en" };
|
|
670
|
+
}
|
|
588
671
|
}
|
|
589
672
|
if (!pkgManager) {
|
|
590
673
|
pkgManager = detectPackageManager();
|
|
@@ -594,7 +677,7 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
|
|
|
594
677
|
await scaffold({
|
|
595
678
|
projectName,
|
|
596
679
|
connectionId,
|
|
597
|
-
apiBaseUrl,
|
|
680
|
+
apiBaseUrl: resolvedApiUrl,
|
|
598
681
|
framework,
|
|
599
682
|
theme,
|
|
600
683
|
storeName: storeInfo.name,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-brainerce-store",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Scaffold a production-ready e-commerce storefront connected to Brainerce",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-brainerce-store": "dist/index.js"
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsup src/index.ts --format cjs --dts --clean",
|
|
15
15
|
"dev": "tsup src/index.ts --format cjs --dts --watch",
|
|
16
|
-
"clean": "rimraf dist"
|
|
16
|
+
"clean": "rimraf dist",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
20
|
"chalk": "^4.1.2",
|