create-brainerce-store 1.22.0 → 1.24.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 +92 -49
- 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.24.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",
|
|
@@ -326,7 +327,7 @@ async function scaffold(options) {
|
|
|
326
327
|
fontImport: fontConfig.fontImport,
|
|
327
328
|
fontVariable: fontConfig.fontVariable,
|
|
328
329
|
ogLocale,
|
|
329
|
-
apiBaseUrl: "https://api.brainerce.com",
|
|
330
|
+
apiBaseUrl: options.apiBaseUrl || "https://api.brainerce.com",
|
|
330
331
|
i18nEnabled: isMultiLocale,
|
|
331
332
|
supportedLocales: JSON.stringify(supportedLocales),
|
|
332
333
|
defaultLocale
|
|
@@ -410,47 +411,76 @@ async function copyWithEjs(srcDir, destDir, vars) {
|
|
|
410
411
|
}
|
|
411
412
|
|
|
412
413
|
// src/fetch-store-info.ts
|
|
413
|
-
var
|
|
414
|
-
|
|
415
|
-
|
|
414
|
+
var KNOWN_API_URLS = {
|
|
415
|
+
production: "https://api.brainerce.com",
|
|
416
|
+
staging: "https://api-staging.brainerce.com"
|
|
417
|
+
};
|
|
418
|
+
var ConnectionNotFoundError = class extends Error {
|
|
419
|
+
constructor(connectionId, baseUrl) {
|
|
420
|
+
super(`Connection "${connectionId}" not found at ${baseUrl}`);
|
|
421
|
+
this.code = "NOT_FOUND";
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
async function fetchStoreInfo(connectionId, baseUrl = KNOWN_API_URLS.production) {
|
|
416
425
|
const url = `${baseUrl}/api/vc/${connectionId}/info`;
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
}
|
|
426
|
+
const controller = new AbortController();
|
|
427
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
428
|
+
let res;
|
|
429
|
+
try {
|
|
430
|
+
res = await fetch(url, { signal: controller.signal });
|
|
431
|
+
} catch (err) {
|
|
432
|
+
if (err.name === "AbortError") {
|
|
433
|
+
throw new Error(`Request to ${baseUrl} timed out`);
|
|
434
|
+
}
|
|
435
|
+
throw new Error(`Failed to connect to ${baseUrl}: ${err.message}`);
|
|
436
|
+
} finally {
|
|
437
|
+
clearTimeout(timeout);
|
|
438
|
+
}
|
|
439
|
+
if (res.status === 404) {
|
|
440
|
+
throw new ConnectionNotFoundError(connectionId, baseUrl);
|
|
441
|
+
}
|
|
442
|
+
if (!res.ok) {
|
|
443
|
+
throw new Error(`${baseUrl} returned status ${res.status}`);
|
|
444
|
+
}
|
|
445
|
+
let json;
|
|
446
|
+
try {
|
|
447
|
+
json = await res.json();
|
|
448
|
+
} catch {
|
|
449
|
+
throw new Error(`Invalid response from ${baseUrl}`);
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
name: json.name || json.storeName || "My Store",
|
|
453
|
+
currency: json.currency || "USD",
|
|
454
|
+
language: json.language || "en",
|
|
455
|
+
...json.i18n ? { i18n: json.i18n } : {}
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
async function resolveStoreInfo(connectionId, candidateUrls) {
|
|
459
|
+
const urls = candidateUrls.filter((u, i) => u && candidateUrls.indexOf(u) === i);
|
|
460
|
+
if (urls.length === 0) {
|
|
461
|
+
throw new Error("No API URLs to try");
|
|
462
|
+
}
|
|
463
|
+
let lastError;
|
|
464
|
+
let allNotFound = true;
|
|
465
|
+
for (let i = 0; i < urls.length; i++) {
|
|
466
|
+
const baseUrl = urls[i];
|
|
467
|
+
try {
|
|
468
|
+
const info = await fetchStoreInfo(connectionId, baseUrl);
|
|
469
|
+
return { info, apiBaseUrl: baseUrl, fellBack: i > 0 };
|
|
470
|
+
} catch (err) {
|
|
471
|
+
lastError = err;
|
|
472
|
+
const isNotFound = err.code === "NOT_FOUND";
|
|
473
|
+
if (!isNotFound) {
|
|
474
|
+
allNotFound = false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (allNotFound) {
|
|
479
|
+
throw new Error(
|
|
480
|
+
`Connection "${connectionId}" not found in any known environment (${urls.join(", ")}). Check your dashboard.`
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
throw lastError || new Error("Failed to resolve store info");
|
|
454
484
|
}
|
|
455
485
|
|
|
456
486
|
// src/utils/logger.ts
|
|
@@ -502,9 +532,9 @@ function createSpinner(text) {
|
|
|
502
532
|
var pkg = require_package();
|
|
503
533
|
async function checkForUpdate(name, current) {
|
|
504
534
|
try {
|
|
505
|
-
const
|
|
535
|
+
const https = require("https");
|
|
506
536
|
return await new Promise((resolve) => {
|
|
507
|
-
const req =
|
|
537
|
+
const req = https.get(
|
|
508
538
|
`https://registry.npmjs.org/${name}/latest`,
|
|
509
539
|
{ timeout: 3e3 },
|
|
510
540
|
(res) => {
|
|
@@ -531,7 +561,10 @@ async function checkForUpdate(name, current) {
|
|
|
531
561
|
}
|
|
532
562
|
}
|
|
533
563
|
var program = new import_commander.Command();
|
|
534
|
-
program.name("create-brainerce-store").description("Scaffold a production-ready e-commerce storefront connected to Brainerce").version(pkg.version).argument("[project-name]", "Name for the project directory").option("--connection-id <id>", "Brainerce vibe-coded connection ID (vc_*)").option(
|
|
564
|
+
program.name("create-brainerce-store").description("Scaffold a production-ready e-commerce storefront connected to Brainerce").version(pkg.version).argument("[project-name]", "Name for the project directory").option("--connection-id <id>", "Brainerce vibe-coded connection ID (vc_*)").option(
|
|
565
|
+
"--api-url <url>",
|
|
566
|
+
"Brainerce API base URL (overrides BRAINERCE_API_URL env, defaults to https://api.brainerce.com)"
|
|
567
|
+
).option("--language <lang>", "Store language (en, he)").option("--framework <framework>", "Framework to use", "nextjs").option("--theme <theme>", "Theme to apply", "minimal").option("--pkg-manager <manager>", "Package manager (npm, pnpm, yarn, bun)").option("--no-git", "Skip git initialization").option("--no-install", "Skip dependency installation").action(async (projectNameArg, options) => {
|
|
535
568
|
try {
|
|
536
569
|
logger.banner(pkg.version);
|
|
537
570
|
const updateCheck = checkForUpdate(pkg.name, pkg.version);
|
|
@@ -542,6 +575,8 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
|
|
|
542
575
|
scaffoldInPlace = true;
|
|
543
576
|
}
|
|
544
577
|
let connectionId = options.connectionId;
|
|
578
|
+
const explicitApiUrl = (options.apiUrl || process.env.BRAINERCE_API_URL || "").replace(/\/$/, "");
|
|
579
|
+
const candidateApiUrls = explicitApiUrl ? [explicitApiUrl] : [KNOWN_API_URLS.production, KNOWN_API_URLS.staging];
|
|
545
580
|
let language = options.language;
|
|
546
581
|
let framework = options.framework;
|
|
547
582
|
let theme = options.theme;
|
|
@@ -577,16 +612,23 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
|
|
|
577
612
|
const spinner = createSpinner("Fetching store info...");
|
|
578
613
|
spinner.start();
|
|
579
614
|
let storeInfo;
|
|
615
|
+
let resolvedApiUrl = candidateApiUrls[0];
|
|
580
616
|
try {
|
|
581
|
-
|
|
617
|
+
const resolved = await resolveStoreInfo(connectionId, candidateApiUrls);
|
|
618
|
+
storeInfo = resolved.info;
|
|
619
|
+
resolvedApiUrl = resolved.apiBaseUrl;
|
|
620
|
+
const envLabel = resolved.apiBaseUrl === KNOWN_API_URLS.staging ? " [staging]" : resolved.apiBaseUrl === KNOWN_API_URLS.production ? "" : ` [${resolved.apiBaseUrl}]`;
|
|
582
621
|
const i18nStatus = storeInfo.i18n?.enabled && storeInfo.i18n.supportedLocales.length > 1 ? ` | i18n: ${storeInfo.i18n.supportedLocales.join(", ")}` : "";
|
|
583
622
|
spinner.succeed(
|
|
584
|
-
`Store: "${storeInfo.name}" | ${storeInfo.currency} | ${storeInfo.language}${i18nStatus}`
|
|
623
|
+
`Store: "${storeInfo.name}" | ${storeInfo.currency} | ${storeInfo.language}${i18nStatus}${envLabel}`
|
|
585
624
|
);
|
|
625
|
+
if (resolved.fellBack) {
|
|
626
|
+
logger.info(` Detected ${envLabel.trim() || "alternate"} environment \u2014 using ${resolved.apiBaseUrl}`);
|
|
627
|
+
}
|
|
586
628
|
} catch (err) {
|
|
587
629
|
spinner.fail("Could not fetch store info");
|
|
588
630
|
logger.warn(
|
|
589
|
-
"Using defaults. Make sure the connection ID is correct and the Brainerce API is reachable."
|
|
631
|
+
err instanceof Error ? err.message : "Using defaults. Make sure the connection ID is correct and the Brainerce API is reachable."
|
|
590
632
|
);
|
|
591
633
|
storeInfo = { name: projectName, currency: "USD", language: "en" };
|
|
592
634
|
}
|
|
@@ -598,6 +640,7 @@ program.name("create-brainerce-store").description("Scaffold a production-ready
|
|
|
598
640
|
await scaffold({
|
|
599
641
|
projectName,
|
|
600
642
|
connectionId,
|
|
643
|
+
apiBaseUrl: resolvedApiUrl,
|
|
601
644
|
framework,
|
|
602
645
|
theme,
|
|
603
646
|
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.24.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",
|