@nextsparkjs/cli 0.1.0-beta.5 → 0.1.0-beta.50
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/cli.js +511 -254
- package/package.json +6 -5
- package/dist/add-plugin-GCPJ4FHE.js +0 -8
- package/dist/chunk-EE6EJYHE.js +0 -704
package/dist/cli.js
CHANGED
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
} from "./chunk-ALB2C27N.js";
|
|
11
11
|
|
|
12
12
|
// src/cli.ts
|
|
13
|
+
import { config } from "dotenv";
|
|
13
14
|
import { Command } from "commander";
|
|
14
|
-
import
|
|
15
|
+
import chalk16 from "chalk";
|
|
15
16
|
|
|
16
17
|
// src/commands/dev.ts
|
|
17
18
|
import { spawn } from "child_process";
|
|
@@ -61,8 +62,8 @@ async function devCommand(options) {
|
|
|
61
62
|
spinner.succeed(`Core found at: ${coreDir} (${mode} mode)`);
|
|
62
63
|
const processes = [];
|
|
63
64
|
if (options.registry) {
|
|
64
|
-
console.log(chalk.blue("\n[Registry] Starting registry
|
|
65
|
-
const registryProcess = spawn("node", ["scripts/registry
|
|
65
|
+
console.log(chalk.blue("\n[Registry] Starting registry builder with watch mode..."));
|
|
66
|
+
const registryProcess = spawn("node", ["scripts/build/registry.mjs", "--watch"], {
|
|
66
67
|
cwd: coreDir,
|
|
67
68
|
stdio: "inherit",
|
|
68
69
|
env: {
|
|
@@ -422,8 +423,8 @@ Watcher exited with code ${code}`));
|
|
|
422
423
|
}
|
|
423
424
|
|
|
424
425
|
// src/commands/init.ts
|
|
425
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as
|
|
426
|
-
import { join as
|
|
426
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync7 } from "fs";
|
|
427
|
+
import { join as join8 } from "path";
|
|
427
428
|
import chalk12 from "chalk";
|
|
428
429
|
import ora8 from "ora";
|
|
429
430
|
|
|
@@ -433,10 +434,35 @@ import ora7 from "ora";
|
|
|
433
434
|
import { confirm as confirm5 } from "@inquirer/prompts";
|
|
434
435
|
import { execSync } from "child_process";
|
|
435
436
|
import { existsSync as existsSync7, readdirSync } from "fs";
|
|
436
|
-
import { join as
|
|
437
|
+
import { join as join7 } from "path";
|
|
437
438
|
|
|
438
439
|
// src/wizard/banner.ts
|
|
439
440
|
import chalk5 from "chalk";
|
|
441
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
442
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
443
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
444
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
445
|
+
var __dirname2 = dirname2(__filename2);
|
|
446
|
+
function getCliVersion() {
|
|
447
|
+
const possiblePaths = [
|
|
448
|
+
join4(__dirname2, "../package.json"),
|
|
449
|
+
// from dist/
|
|
450
|
+
join4(__dirname2, "../../package.json"),
|
|
451
|
+
// from dist/wizard/ or src/wizard/
|
|
452
|
+
join4(__dirname2, "../../../package.json")
|
|
453
|
+
// fallback
|
|
454
|
+
];
|
|
455
|
+
for (const packageJsonPath of possiblePaths) {
|
|
456
|
+
try {
|
|
457
|
+
const packageJson = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
|
|
458
|
+
if (packageJson.name === "@nextsparkjs/cli" && packageJson.version) {
|
|
459
|
+
return packageJson.version;
|
|
460
|
+
}
|
|
461
|
+
} catch {
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return "unknown";
|
|
465
|
+
}
|
|
440
466
|
var BANNER = `
|
|
441
467
|
_ __ __ _____ __
|
|
442
468
|
/ | / /__ _ __/ /_/ ___/____ ____ ______/ /__
|
|
@@ -446,9 +472,11 @@ var BANNER = `
|
|
|
446
472
|
/_/
|
|
447
473
|
`;
|
|
448
474
|
function showBanner() {
|
|
475
|
+
const version = getCliVersion();
|
|
449
476
|
console.log(chalk5.cyan(BANNER));
|
|
450
477
|
console.log(chalk5.bold.white(" Welcome to NextSpark - The Complete SaaS Framework for Next.js"));
|
|
451
|
-
console.log(chalk5.gray(
|
|
478
|
+
console.log(chalk5.gray(` Version ${version} - Create production-ready SaaS applications in minutes
|
|
479
|
+
`));
|
|
452
480
|
console.log(chalk5.gray(" " + "=".repeat(60) + "\n"));
|
|
453
481
|
}
|
|
454
482
|
function showSection(title, step, totalSteps) {
|
|
@@ -1151,22 +1179,22 @@ async function runExpertPrompts() {
|
|
|
1151
1179
|
// src/wizard/generators/index.ts
|
|
1152
1180
|
import fs7 from "fs-extra";
|
|
1153
1181
|
import path5 from "path";
|
|
1154
|
-
import { fileURLToPath as
|
|
1182
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1155
1183
|
|
|
1156
1184
|
// src/wizard/generators/theme-renamer.ts
|
|
1157
1185
|
import fs from "fs-extra";
|
|
1158
1186
|
import path from "path";
|
|
1159
|
-
import { fileURLToPath as
|
|
1160
|
-
var
|
|
1161
|
-
var
|
|
1187
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1188
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
1189
|
+
var __dirname3 = path.dirname(__filename3);
|
|
1162
1190
|
function getTemplatesDir() {
|
|
1163
1191
|
try {
|
|
1164
1192
|
const corePkgPath = __require.resolve("@nextsparkjs/core/package.json");
|
|
1165
1193
|
return path.join(path.dirname(corePkgPath), "templates");
|
|
1166
1194
|
} catch {
|
|
1167
1195
|
const possiblePaths = [
|
|
1168
|
-
path.resolve(
|
|
1169
|
-
path.resolve(
|
|
1196
|
+
path.resolve(__dirname3, "../../../../../core/templates"),
|
|
1197
|
+
path.resolve(__dirname3, "../../../../core/templates"),
|
|
1170
1198
|
path.resolve(process.cwd(), "node_modules/@nextsparkjs/core/templates")
|
|
1171
1199
|
];
|
|
1172
1200
|
for (const p of possiblePaths) {
|
|
@@ -1180,11 +1208,11 @@ function getTemplatesDir() {
|
|
|
1180
1208
|
function getTargetThemesDir() {
|
|
1181
1209
|
return path.resolve(process.cwd(), "contents", "themes");
|
|
1182
1210
|
}
|
|
1183
|
-
async function copyStarterTheme(
|
|
1211
|
+
async function copyStarterTheme(config2) {
|
|
1184
1212
|
const templatesDir = getTemplatesDir();
|
|
1185
1213
|
const starterThemePath = path.join(templatesDir, "contents", "themes", "starter");
|
|
1186
1214
|
const targetThemesDir = getTargetThemesDir();
|
|
1187
|
-
const newThemePath = path.join(targetThemesDir,
|
|
1215
|
+
const newThemePath = path.join(targetThemesDir, config2.projectSlug);
|
|
1188
1216
|
if (!await fs.pathExists(starterThemePath)) {
|
|
1189
1217
|
throw new Error(`Starter theme not found at: ${starterThemePath}`);
|
|
1190
1218
|
}
|
|
@@ -1194,99 +1222,97 @@ async function copyStarterTheme(config) {
|
|
|
1194
1222
|
await fs.ensureDir(targetThemesDir);
|
|
1195
1223
|
await fs.copy(starterThemePath, newThemePath);
|
|
1196
1224
|
}
|
|
1197
|
-
async function updateThemeConfig(
|
|
1198
|
-
const themeConfigPath = path.join(getTargetThemesDir(),
|
|
1225
|
+
async function updateThemeConfig(config2) {
|
|
1226
|
+
const themeConfigPath = path.join(getTargetThemesDir(), config2.projectSlug, "config", "theme.config.ts");
|
|
1199
1227
|
if (!await fs.pathExists(themeConfigPath)) {
|
|
1200
1228
|
throw new Error(`theme.config.ts not found at: ${themeConfigPath}`);
|
|
1201
1229
|
}
|
|
1202
1230
|
let content = await fs.readFile(themeConfigPath, "utf-8");
|
|
1203
1231
|
content = content.replace(
|
|
1204
1232
|
/name:\s*['"]starter['"]/g,
|
|
1205
|
-
`name: '${
|
|
1233
|
+
`name: '${config2.projectSlug}'`
|
|
1206
1234
|
);
|
|
1207
1235
|
content = content.replace(
|
|
1208
1236
|
/displayName:\s*['"]Starter['"]/g,
|
|
1209
|
-
`displayName: '${
|
|
1237
|
+
`displayName: '${config2.projectName}'`
|
|
1210
1238
|
);
|
|
1211
1239
|
content = content.replace(
|
|
1212
1240
|
/description:\s*['"]Minimal starter theme for NextSpark['"]/g,
|
|
1213
|
-
`description: '${
|
|
1241
|
+
`description: '${config2.projectDescription}'`
|
|
1214
1242
|
);
|
|
1215
1243
|
content = content.replace(
|
|
1216
1244
|
/export const starterThemeConfig/g,
|
|
1217
|
-
`export const ${toCamelCase(
|
|
1245
|
+
`export const ${toCamelCase(config2.projectSlug)}ThemeConfig`
|
|
1218
1246
|
);
|
|
1219
1247
|
content = content.replace(
|
|
1220
1248
|
/export default starterThemeConfig/g,
|
|
1221
|
-
`export default ${toCamelCase(
|
|
1249
|
+
`export default ${toCamelCase(config2.projectSlug)}ThemeConfig`
|
|
1222
1250
|
);
|
|
1223
1251
|
await fs.writeFile(themeConfigPath, content, "utf-8");
|
|
1224
1252
|
}
|
|
1225
|
-
async function updateDevConfig(
|
|
1226
|
-
const devConfigPath = path.join(getTargetThemesDir(),
|
|
1253
|
+
async function updateDevConfig(config2) {
|
|
1254
|
+
const devConfigPath = path.join(getTargetThemesDir(), config2.projectSlug, "config", "dev.config.ts");
|
|
1227
1255
|
if (!await fs.pathExists(devConfigPath)) {
|
|
1228
1256
|
return;
|
|
1229
1257
|
}
|
|
1230
1258
|
let content = await fs.readFile(devConfigPath, "utf-8");
|
|
1231
|
-
content = content.replace(
|
|
1232
|
-
content = content.replace(/
|
|
1233
|
-
content = content.replace(/Starter Theme/g, config.projectName);
|
|
1234
|
-
content = content.replace(/Starter Team/g, `${config.projectName} Team`);
|
|
1259
|
+
content = content.replace(/STARTER THEME/g, `${config2.projectName.toUpperCase()}`);
|
|
1260
|
+
content = content.replace(/Starter Theme/g, config2.projectName);
|
|
1235
1261
|
await fs.writeFile(devConfigPath, content, "utf-8");
|
|
1236
1262
|
}
|
|
1237
|
-
async function updateAppConfig(
|
|
1238
|
-
const appConfigPath = path.join(getTargetThemesDir(),
|
|
1263
|
+
async function updateAppConfig(config2) {
|
|
1264
|
+
const appConfigPath = path.join(getTargetThemesDir(), config2.projectSlug, "config", "app.config.ts");
|
|
1239
1265
|
if (!await fs.pathExists(appConfigPath)) {
|
|
1240
1266
|
throw new Error(`app.config.ts not found at: ${appConfigPath}`);
|
|
1241
1267
|
}
|
|
1242
1268
|
let content = await fs.readFile(appConfigPath, "utf-8");
|
|
1243
1269
|
content = content.replace(
|
|
1244
1270
|
/name:\s*['"]Starter['"]/g,
|
|
1245
|
-
`name: '${
|
|
1271
|
+
`name: '${config2.projectName}'`
|
|
1246
1272
|
);
|
|
1247
1273
|
content = content.replace(
|
|
1248
1274
|
/mode:\s*['"]multi-tenant['"]\s*as\s*const/g,
|
|
1249
|
-
`mode: '${
|
|
1275
|
+
`mode: '${config2.teamMode}' as const`
|
|
1250
1276
|
);
|
|
1251
|
-
const localesArray =
|
|
1277
|
+
const localesArray = config2.supportedLocales.map((l) => `'${l}'`).join(", ");
|
|
1252
1278
|
content = content.replace(
|
|
1253
1279
|
/supportedLocales:\s*\[.*?\]/g,
|
|
1254
1280
|
`supportedLocales: [${localesArray}]`
|
|
1255
1281
|
);
|
|
1256
1282
|
content = content.replace(
|
|
1257
1283
|
/defaultLocale:\s*['"]en['"]\s*as\s*const/g,
|
|
1258
|
-
`defaultLocale: '${
|
|
1284
|
+
`defaultLocale: '${config2.defaultLocale}' as const`
|
|
1259
1285
|
);
|
|
1260
1286
|
content = content.replace(
|
|
1261
1287
|
/label:\s*['"]Starter['"]/g,
|
|
1262
|
-
`label: '${
|
|
1288
|
+
`label: '${config2.projectName}'`
|
|
1263
1289
|
);
|
|
1264
1290
|
await fs.writeFile(appConfigPath, content, "utf-8");
|
|
1265
1291
|
}
|
|
1266
|
-
async function updateRolesConfig(
|
|
1267
|
-
const appConfigPath = path.join(getTargetThemesDir(),
|
|
1292
|
+
async function updateRolesConfig(config2) {
|
|
1293
|
+
const appConfigPath = path.join(getTargetThemesDir(), config2.projectSlug, "config", "app.config.ts");
|
|
1268
1294
|
if (!await fs.pathExists(appConfigPath)) {
|
|
1269
1295
|
return;
|
|
1270
1296
|
}
|
|
1271
1297
|
let content = await fs.readFile(appConfigPath, "utf-8");
|
|
1272
|
-
const rolesArray =
|
|
1298
|
+
const rolesArray = config2.teamRoles.map((r) => `'${r}'`).join(", ");
|
|
1273
1299
|
content = content.replace(
|
|
1274
1300
|
/availableTeamRoles:\s*\[.*?\]/g,
|
|
1275
1301
|
`availableTeamRoles: [${rolesArray}]`
|
|
1276
1302
|
);
|
|
1277
1303
|
await fs.writeFile(appConfigPath, content, "utf-8");
|
|
1278
1304
|
}
|
|
1279
|
-
async function updateBillingConfig(
|
|
1280
|
-
const billingConfigPath = path.join(getTargetThemesDir(),
|
|
1305
|
+
async function updateBillingConfig(config2) {
|
|
1306
|
+
const billingConfigPath = path.join(getTargetThemesDir(), config2.projectSlug, "config", "billing.config.ts");
|
|
1281
1307
|
if (!await fs.pathExists(billingConfigPath)) {
|
|
1282
1308
|
return;
|
|
1283
1309
|
}
|
|
1284
1310
|
let content = await fs.readFile(billingConfigPath, "utf-8");
|
|
1285
1311
|
content = content.replace(
|
|
1286
1312
|
/currency:\s*['"]usd['"]/g,
|
|
1287
|
-
`currency: '${
|
|
1313
|
+
`currency: '${config2.currency}'`
|
|
1288
1314
|
);
|
|
1289
|
-
const plansContent = generateBillingPlans(
|
|
1315
|
+
const plansContent = generateBillingPlans(config2.billingModel, config2.currency);
|
|
1290
1316
|
content = content.replace(
|
|
1291
1317
|
/plans:\s*\[[\s\S]*?\],\s*\n\s*\/\/ ===+\s*\n\s*\/\/ ACTION MAPPINGS/,
|
|
1292
1318
|
`plans: ${plansContent},
|
|
@@ -1436,8 +1462,8 @@ function generateBillingPlans(billingModel, currency) {
|
|
|
1436
1462
|
},
|
|
1437
1463
|
]`;
|
|
1438
1464
|
}
|
|
1439
|
-
async function updateMigrations(
|
|
1440
|
-
const migrationsDir = path.join(getTargetThemesDir(),
|
|
1465
|
+
async function updateMigrations(config2) {
|
|
1466
|
+
const migrationsDir = path.join(getTargetThemesDir(), config2.projectSlug, "migrations");
|
|
1441
1467
|
if (!await fs.pathExists(migrationsDir)) {
|
|
1442
1468
|
return;
|
|
1443
1469
|
}
|
|
@@ -1446,12 +1472,39 @@ async function updateMigrations(config) {
|
|
|
1446
1472
|
for (const file of sqlFiles) {
|
|
1447
1473
|
const filePath = path.join(migrationsDir, file);
|
|
1448
1474
|
let content = await fs.readFile(filePath, "utf-8");
|
|
1449
|
-
content = content.replace(/@starter\.dev/g, `@${
|
|
1450
|
-
content = content.replace(/Starter Theme/g,
|
|
1451
|
-
content = content.replace(/starter theme/g,
|
|
1475
|
+
content = content.replace(/@starter\.dev/g, `@${config2.projectSlug}.dev`);
|
|
1476
|
+
content = content.replace(/Starter Theme/g, config2.projectName);
|
|
1477
|
+
content = content.replace(/starter theme/g, config2.projectSlug);
|
|
1452
1478
|
await fs.writeFile(filePath, content, "utf-8");
|
|
1453
1479
|
}
|
|
1454
1480
|
}
|
|
1481
|
+
async function updateTestFiles(config2) {
|
|
1482
|
+
const testsDir = path.join(getTargetThemesDir(), config2.projectSlug, "tests");
|
|
1483
|
+
if (!await fs.pathExists(testsDir)) {
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
const processDir = async (dir) => {
|
|
1487
|
+
const items = await fs.readdir(dir);
|
|
1488
|
+
for (const item of items) {
|
|
1489
|
+
const itemPath = path.join(dir, item);
|
|
1490
|
+
const stat = await fs.stat(itemPath);
|
|
1491
|
+
if (stat.isDirectory()) {
|
|
1492
|
+
await processDir(itemPath);
|
|
1493
|
+
} else if (item.endsWith(".ts") || item.endsWith(".tsx")) {
|
|
1494
|
+
let content = await fs.readFile(itemPath, "utf-8");
|
|
1495
|
+
const hasChanges = content.includes("@/contents/themes/starter/");
|
|
1496
|
+
if (hasChanges) {
|
|
1497
|
+
content = content.replace(
|
|
1498
|
+
/@\/contents\/themes\/starter\//g,
|
|
1499
|
+
`@/contents/themes/${config2.projectSlug}/`
|
|
1500
|
+
);
|
|
1501
|
+
await fs.writeFile(itemPath, content, "utf-8");
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1506
|
+
await processDir(testsDir);
|
|
1507
|
+
}
|
|
1455
1508
|
function toCamelCase(str) {
|
|
1456
1509
|
return str.split("-").map((word, index) => {
|
|
1457
1510
|
if (index === 0) {
|
|
@@ -1467,10 +1520,10 @@ import path2 from "path";
|
|
|
1467
1520
|
function getTargetThemesDir2() {
|
|
1468
1521
|
return path2.resolve(process.cwd(), "contents", "themes");
|
|
1469
1522
|
}
|
|
1470
|
-
async function updateAuthConfig(
|
|
1523
|
+
async function updateAuthConfig(config2) {
|
|
1471
1524
|
const authConfigPath = path2.join(
|
|
1472
1525
|
getTargetThemesDir2(),
|
|
1473
|
-
|
|
1526
|
+
config2.projectSlug,
|
|
1474
1527
|
"config",
|
|
1475
1528
|
"auth.config.ts"
|
|
1476
1529
|
);
|
|
@@ -1480,22 +1533,22 @@ async function updateAuthConfig(config) {
|
|
|
1480
1533
|
let content = await fs2.readFile(authConfigPath, "utf-8");
|
|
1481
1534
|
content = content.replace(
|
|
1482
1535
|
/(emailPassword:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1483
|
-
`$1${
|
|
1536
|
+
`$1${config2.auth.emailPassword}`
|
|
1484
1537
|
);
|
|
1485
1538
|
content = content.replace(
|
|
1486
1539
|
/(google:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1487
|
-
`$1${
|
|
1540
|
+
`$1${config2.auth.googleOAuth}`
|
|
1488
1541
|
);
|
|
1489
1542
|
content = content.replace(
|
|
1490
1543
|
/(emailVerification:\s*)(?:true|false)/g,
|
|
1491
|
-
`$1${
|
|
1544
|
+
`$1${config2.auth.emailVerification}`
|
|
1492
1545
|
);
|
|
1493
1546
|
await fs2.writeFile(authConfigPath, content, "utf-8");
|
|
1494
1547
|
}
|
|
1495
|
-
async function updateDashboardUIConfig(
|
|
1548
|
+
async function updateDashboardUIConfig(config2) {
|
|
1496
1549
|
const dashboardConfigPath = path2.join(
|
|
1497
1550
|
getTargetThemesDir2(),
|
|
1498
|
-
|
|
1551
|
+
config2.projectSlug,
|
|
1499
1552
|
"config",
|
|
1500
1553
|
"dashboard.config.ts"
|
|
1501
1554
|
);
|
|
@@ -1505,42 +1558,42 @@ async function updateDashboardUIConfig(config) {
|
|
|
1505
1558
|
let content = await fs2.readFile(dashboardConfigPath, "utf-8");
|
|
1506
1559
|
content = content.replace(
|
|
1507
1560
|
/(search:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1508
|
-
`$1${
|
|
1561
|
+
`$1${config2.dashboard.search}`
|
|
1509
1562
|
);
|
|
1510
1563
|
content = content.replace(
|
|
1511
1564
|
/(notifications:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1512
|
-
`$1${
|
|
1565
|
+
`$1${config2.dashboard.notifications}`
|
|
1513
1566
|
);
|
|
1514
1567
|
content = content.replace(
|
|
1515
1568
|
/(themeToggle:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1516
|
-
`$1${
|
|
1569
|
+
`$1${config2.dashboard.themeToggle}`
|
|
1517
1570
|
);
|
|
1518
1571
|
content = content.replace(
|
|
1519
1572
|
/(support:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1520
|
-
`$1${
|
|
1573
|
+
`$1${config2.dashboard.support}`
|
|
1521
1574
|
);
|
|
1522
1575
|
content = content.replace(
|
|
1523
1576
|
/(quickCreate:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1524
|
-
`$1${
|
|
1577
|
+
`$1${config2.dashboard.quickCreate}`
|
|
1525
1578
|
);
|
|
1526
1579
|
content = content.replace(
|
|
1527
1580
|
/(adminAccess:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1528
|
-
`$1${
|
|
1581
|
+
`$1${config2.dashboard.superadminAccess}`
|
|
1529
1582
|
);
|
|
1530
1583
|
content = content.replace(
|
|
1531
1584
|
/(devtoolsAccess:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1532
|
-
`$1${
|
|
1585
|
+
`$1${config2.dashboard.devtoolsAccess}`
|
|
1533
1586
|
);
|
|
1534
1587
|
content = content.replace(
|
|
1535
1588
|
/(defaultCollapsed:\s*)(?:true|false)/g,
|
|
1536
|
-
`$1${
|
|
1589
|
+
`$1${config2.dashboard.sidebarCollapsed}`
|
|
1537
1590
|
);
|
|
1538
1591
|
await fs2.writeFile(dashboardConfigPath, content, "utf-8");
|
|
1539
1592
|
}
|
|
1540
|
-
async function updateDevToolsConfig(
|
|
1593
|
+
async function updateDevToolsConfig(config2) {
|
|
1541
1594
|
const devConfigPath = path2.join(
|
|
1542
1595
|
getTargetThemesDir2(),
|
|
1543
|
-
|
|
1596
|
+
config2.projectSlug,
|
|
1544
1597
|
"config",
|
|
1545
1598
|
"dev.config.ts"
|
|
1546
1599
|
);
|
|
@@ -1550,18 +1603,18 @@ async function updateDevToolsConfig(config) {
|
|
|
1550
1603
|
let content = await fs2.readFile(devConfigPath, "utf-8");
|
|
1551
1604
|
content = content.replace(
|
|
1552
1605
|
/(devKeyring:\s*{[^}]*enabled:\s*)(?:true|false)/gs,
|
|
1553
|
-
`$1${
|
|
1606
|
+
`$1${config2.dev.devKeyring}`
|
|
1554
1607
|
);
|
|
1555
1608
|
content = content.replace(
|
|
1556
1609
|
/(debugMode:\s*)(?:true|false)/g,
|
|
1557
|
-
`$1${
|
|
1610
|
+
`$1${config2.dev.debugMode}`
|
|
1558
1611
|
);
|
|
1559
1612
|
await fs2.writeFile(devConfigPath, content, "utf-8");
|
|
1560
1613
|
}
|
|
1561
|
-
async function updatePermissionsConfig(
|
|
1614
|
+
async function updatePermissionsConfig(config2) {
|
|
1562
1615
|
const permissionsConfigPath = path2.join(
|
|
1563
1616
|
getTargetThemesDir2(),
|
|
1564
|
-
|
|
1617
|
+
config2.projectSlug,
|
|
1565
1618
|
"config",
|
|
1566
1619
|
"permissions.config.ts"
|
|
1567
1620
|
);
|
|
@@ -1569,7 +1622,7 @@ async function updatePermissionsConfig(config) {
|
|
|
1569
1622
|
return;
|
|
1570
1623
|
}
|
|
1571
1624
|
let content = await fs2.readFile(permissionsConfigPath, "utf-8");
|
|
1572
|
-
const availableRoles =
|
|
1625
|
+
const availableRoles = config2.teamRoles;
|
|
1573
1626
|
const roleArrayPattern = /roles:\s*\[(.*?)\]/g;
|
|
1574
1627
|
content = content.replace(roleArrayPattern, (match, rolesStr) => {
|
|
1575
1628
|
const currentRoles = rolesStr.split(",").map((r) => r.trim().replace(/['"]/g, "")).filter((r) => r.length > 0);
|
|
@@ -1581,10 +1634,48 @@ async function updatePermissionsConfig(config) {
|
|
|
1581
1634
|
});
|
|
1582
1635
|
await fs2.writeFile(permissionsConfigPath, content, "utf-8");
|
|
1583
1636
|
}
|
|
1584
|
-
async function
|
|
1637
|
+
async function updateEntityPermissions(config2) {
|
|
1638
|
+
const permissionsConfigPath = path2.join(
|
|
1639
|
+
getTargetThemesDir2(),
|
|
1640
|
+
config2.projectSlug,
|
|
1641
|
+
"config",
|
|
1642
|
+
"permissions.config.ts"
|
|
1643
|
+
);
|
|
1644
|
+
if (!await fs2.pathExists(permissionsConfigPath)) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
let content = await fs2.readFile(permissionsConfigPath, "utf-8");
|
|
1648
|
+
if (config2.contentFeatures.pages) {
|
|
1649
|
+
content = uncommentPermissionBlock(content, "PAGES");
|
|
1650
|
+
}
|
|
1651
|
+
if (config2.contentFeatures.blog) {
|
|
1652
|
+
content = uncommentPermissionBlock(content, "POSTS");
|
|
1653
|
+
}
|
|
1654
|
+
await fs2.writeFile(permissionsConfigPath, content, "utf-8");
|
|
1655
|
+
}
|
|
1656
|
+
function uncommentPermissionBlock(content, markerName) {
|
|
1657
|
+
const startMarker = `// __${markerName}_PERMISSIONS_START__`;
|
|
1658
|
+
const endMarker = `// __${markerName}_PERMISSIONS_END__`;
|
|
1659
|
+
const startIndex = content.indexOf(startMarker);
|
|
1660
|
+
const endIndex = content.indexOf(endMarker);
|
|
1661
|
+
if (startIndex === -1 || endIndex === -1) {
|
|
1662
|
+
return content;
|
|
1663
|
+
}
|
|
1664
|
+
const beforeBlock = content.slice(0, startIndex);
|
|
1665
|
+
const block = content.slice(startIndex + startMarker.length, endIndex);
|
|
1666
|
+
const afterBlock = content.slice(endIndex + endMarker.length);
|
|
1667
|
+
const uncommentedBlock = block.split("\n").map((line) => {
|
|
1668
|
+
if (line.match(/^\s*\/\/\s+/)) {
|
|
1669
|
+
return line.replace(/^(\s*)\/\/\s*/, "$1");
|
|
1670
|
+
}
|
|
1671
|
+
return line;
|
|
1672
|
+
}).join("\n");
|
|
1673
|
+
return beforeBlock + uncommentedBlock + afterBlock;
|
|
1674
|
+
}
|
|
1675
|
+
async function updateDashboardConfig(config2) {
|
|
1585
1676
|
const dashboardConfigPath = path2.join(
|
|
1586
1677
|
getTargetThemesDir2(),
|
|
1587
|
-
|
|
1678
|
+
config2.projectSlug,
|
|
1588
1679
|
"config",
|
|
1589
1680
|
"dashboard.config.ts"
|
|
1590
1681
|
);
|
|
@@ -1592,19 +1683,19 @@ async function updateDashboardConfig(config) {
|
|
|
1592
1683
|
return;
|
|
1593
1684
|
}
|
|
1594
1685
|
let content = await fs2.readFile(dashboardConfigPath, "utf-8");
|
|
1595
|
-
if (!
|
|
1686
|
+
if (!config2.features.analytics) {
|
|
1596
1687
|
content = content.replace(
|
|
1597
1688
|
/(id:\s*['"]analytics['"].*?enabled:\s*)true/gs,
|
|
1598
1689
|
"$1false"
|
|
1599
1690
|
);
|
|
1600
1691
|
}
|
|
1601
|
-
if (!
|
|
1692
|
+
if (!config2.features.billing) {
|
|
1602
1693
|
content = content.replace(
|
|
1603
1694
|
/(id:\s*['"]billing['"].*?enabled:\s*)true/gs,
|
|
1604
1695
|
"$1false"
|
|
1605
1696
|
);
|
|
1606
1697
|
}
|
|
1607
|
-
if (
|
|
1698
|
+
if (config2.teamMode === "single-user") {
|
|
1608
1699
|
content = content.replace(
|
|
1609
1700
|
/(id:\s*['"]team['"].*?enabled:\s*)true/gs,
|
|
1610
1701
|
"$1false"
|
|
@@ -1616,10 +1707,10 @@ async function updateDashboardConfig(config) {
|
|
|
1616
1707
|
}
|
|
1617
1708
|
await fs2.writeFile(dashboardConfigPath, content, "utf-8");
|
|
1618
1709
|
}
|
|
1619
|
-
async function generateEnvExample(
|
|
1710
|
+
async function generateEnvExample(config2) {
|
|
1620
1711
|
const envExamplePath = path2.resolve(process.cwd(), ".env.example");
|
|
1621
1712
|
let oauthSection = "";
|
|
1622
|
-
if (
|
|
1713
|
+
if (config2.auth.googleOAuth) {
|
|
1623
1714
|
oauthSection = `# =============================================================================
|
|
1624
1715
|
# OAUTH PROVIDERS
|
|
1625
1716
|
# =============================================================================
|
|
@@ -1635,7 +1726,7 @@ GOOGLE_CLIENT_SECRET="your-google-client-secret"
|
|
|
1635
1726
|
`;
|
|
1636
1727
|
}
|
|
1637
1728
|
const envContent = `# NextSpark Environment Configuration
|
|
1638
|
-
# Generated for: ${
|
|
1729
|
+
# Generated for: ${config2.projectName}
|
|
1639
1730
|
|
|
1640
1731
|
# =============================================================================
|
|
1641
1732
|
# DATABASE
|
|
@@ -1651,7 +1742,7 @@ BETTER_AUTH_SECRET="your-secret-key-here"
|
|
|
1651
1742
|
# =============================================================================
|
|
1652
1743
|
# THEME
|
|
1653
1744
|
# =============================================================================
|
|
1654
|
-
NEXT_PUBLIC_ACTIVE_THEME="${
|
|
1745
|
+
NEXT_PUBLIC_ACTIVE_THEME="${config2.projectSlug}"
|
|
1655
1746
|
|
|
1656
1747
|
# =============================================================================
|
|
1657
1748
|
# APPLICATION
|
|
@@ -1659,7 +1750,7 @@ NEXT_PUBLIC_ACTIVE_THEME="${config.projectSlug}"
|
|
|
1659
1750
|
NEXT_PUBLIC_APP_URL="http://localhost:3000"
|
|
1660
1751
|
NODE_ENV="development"
|
|
1661
1752
|
|
|
1662
|
-
${
|
|
1753
|
+
${config2.features.billing ? `# =============================================================================
|
|
1663
1754
|
# STRIPE (Billing)
|
|
1664
1755
|
# =============================================================================
|
|
1665
1756
|
STRIPE_SECRET_KEY="sk_test_..."
|
|
@@ -1677,19 +1768,39 @@ ${oauthSection}`;
|
|
|
1677
1768
|
await fs2.writeFile(envExamplePath, envContent, "utf-8");
|
|
1678
1769
|
}
|
|
1679
1770
|
}
|
|
1680
|
-
async function updateReadme(
|
|
1681
|
-
const readmePath = path2.join(getTargetThemesDir2(),
|
|
1771
|
+
async function updateReadme(config2) {
|
|
1772
|
+
const readmePath = path2.join(getTargetThemesDir2(), config2.projectSlug, "README.md");
|
|
1682
1773
|
if (!await fs2.pathExists(readmePath)) {
|
|
1683
1774
|
return;
|
|
1684
1775
|
}
|
|
1685
1776
|
let content = await fs2.readFile(readmePath, "utf-8");
|
|
1686
|
-
content = content.replace(/# Starter Theme/g, `# ${
|
|
1777
|
+
content = content.replace(/# Starter Theme/g, `# ${config2.projectName}`);
|
|
1687
1778
|
content = content.replace(
|
|
1688
1779
|
/Minimal starter theme for NextSpark/g,
|
|
1689
|
-
|
|
1780
|
+
config2.projectDescription
|
|
1690
1781
|
);
|
|
1691
1782
|
await fs2.writeFile(readmePath, content, "utf-8");
|
|
1692
1783
|
}
|
|
1784
|
+
async function copyEnvExampleToEnv() {
|
|
1785
|
+
const projectRoot = process.cwd();
|
|
1786
|
+
const envExamplePath = path2.resolve(projectRoot, ".env.example");
|
|
1787
|
+
const envPath = path2.resolve(projectRoot, ".env");
|
|
1788
|
+
if (await fs2.pathExists(envExamplePath) && !await fs2.pathExists(envPath)) {
|
|
1789
|
+
await fs2.copy(envExamplePath, envPath);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
async function updateGlobalsCss(config2) {
|
|
1793
|
+
const globalsCssPath = path2.resolve(process.cwd(), "app", "globals.css");
|
|
1794
|
+
if (!await fs2.pathExists(globalsCssPath)) {
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
let content = await fs2.readFile(globalsCssPath, "utf-8");
|
|
1798
|
+
content = content.replace(
|
|
1799
|
+
/@import\s+["']\.\.\/contents\/themes\/[^/]+\/styles\/globals\.css["'];?/,
|
|
1800
|
+
`@import "../contents/themes/${config2.projectSlug}/styles/globals.css";`
|
|
1801
|
+
);
|
|
1802
|
+
await fs2.writeFile(globalsCssPath, content, "utf-8");
|
|
1803
|
+
}
|
|
1693
1804
|
|
|
1694
1805
|
// src/wizard/generators/messages-generator.ts
|
|
1695
1806
|
import fs3 from "fs-extra";
|
|
@@ -1697,8 +1808,8 @@ import path3 from "path";
|
|
|
1697
1808
|
function getTargetThemesDir3() {
|
|
1698
1809
|
return path3.resolve(process.cwd(), "contents", "themes");
|
|
1699
1810
|
}
|
|
1700
|
-
async function removeUnusedLanguages(
|
|
1701
|
-
const messagesDir = path3.join(getTargetThemesDir3(),
|
|
1811
|
+
async function removeUnusedLanguages(config2) {
|
|
1812
|
+
const messagesDir = path3.join(getTargetThemesDir3(), config2.projectSlug, "messages");
|
|
1702
1813
|
if (!await fs3.pathExists(messagesDir)) {
|
|
1703
1814
|
return;
|
|
1704
1815
|
}
|
|
@@ -1708,13 +1819,13 @@ async function removeUnusedLanguages(config) {
|
|
|
1708
1819
|
return fs3.statSync(folderPath).isDirectory() && Object.keys(AVAILABLE_LOCALES).includes(f);
|
|
1709
1820
|
});
|
|
1710
1821
|
for (const folder of languageFolders) {
|
|
1711
|
-
if (!
|
|
1822
|
+
if (!config2.supportedLocales.includes(folder)) {
|
|
1712
1823
|
await fs3.remove(path3.join(messagesDir, folder));
|
|
1713
1824
|
}
|
|
1714
1825
|
}
|
|
1715
1826
|
}
|
|
1716
|
-
async function removeUnusedEntityMessages(
|
|
1717
|
-
const entitiesDir = path3.join(getTargetThemesDir3(),
|
|
1827
|
+
async function removeUnusedEntityMessages(config2) {
|
|
1828
|
+
const entitiesDir = path3.join(getTargetThemesDir3(), config2.projectSlug, "entities");
|
|
1718
1829
|
if (!await fs3.pathExists(entitiesDir)) {
|
|
1719
1830
|
return;
|
|
1720
1831
|
}
|
|
@@ -1727,45 +1838,45 @@ async function removeUnusedEntityMessages(config) {
|
|
|
1727
1838
|
const files = await fs3.readdir(messagesDir);
|
|
1728
1839
|
for (const file of files) {
|
|
1729
1840
|
const locale = path3.basename(file, ".json");
|
|
1730
|
-
if (Object.keys(AVAILABLE_LOCALES).includes(locale) && !
|
|
1841
|
+
if (Object.keys(AVAILABLE_LOCALES).includes(locale) && !config2.supportedLocales.includes(locale)) {
|
|
1731
1842
|
await fs3.remove(path3.join(messagesDir, file));
|
|
1732
1843
|
}
|
|
1733
1844
|
}
|
|
1734
1845
|
}
|
|
1735
1846
|
}
|
|
1736
|
-
async function ensureLanguageFolders(
|
|
1737
|
-
const messagesDir = path3.join(getTargetThemesDir3(),
|
|
1847
|
+
async function ensureLanguageFolders(config2) {
|
|
1848
|
+
const messagesDir = path3.join(getTargetThemesDir3(), config2.projectSlug, "messages");
|
|
1738
1849
|
if (!await fs3.pathExists(messagesDir)) {
|
|
1739
1850
|
return;
|
|
1740
1851
|
}
|
|
1741
|
-
const defaultLocaleDir = path3.join(messagesDir,
|
|
1852
|
+
const defaultLocaleDir = path3.join(messagesDir, config2.defaultLocale);
|
|
1742
1853
|
if (!await fs3.pathExists(defaultLocaleDir)) {
|
|
1743
1854
|
const enDir = path3.join(messagesDir, "en");
|
|
1744
1855
|
if (await fs3.pathExists(enDir)) {
|
|
1745
1856
|
await fs3.copy(enDir, defaultLocaleDir);
|
|
1746
1857
|
}
|
|
1747
1858
|
}
|
|
1748
|
-
for (const locale of
|
|
1859
|
+
for (const locale of config2.supportedLocales) {
|
|
1749
1860
|
const localeDir = path3.join(messagesDir, locale);
|
|
1750
1861
|
if (!await fs3.pathExists(localeDir) && await fs3.pathExists(defaultLocaleDir)) {
|
|
1751
1862
|
await fs3.copy(defaultLocaleDir, localeDir);
|
|
1752
1863
|
}
|
|
1753
1864
|
}
|
|
1754
1865
|
}
|
|
1755
|
-
async function updateMessageFiles(
|
|
1756
|
-
const messagesDir = path3.join(getTargetThemesDir3(),
|
|
1866
|
+
async function updateMessageFiles(config2) {
|
|
1867
|
+
const messagesDir = path3.join(getTargetThemesDir3(), config2.projectSlug, "messages");
|
|
1757
1868
|
if (!await fs3.pathExists(messagesDir)) {
|
|
1758
1869
|
return;
|
|
1759
1870
|
}
|
|
1760
|
-
for (const locale of
|
|
1871
|
+
for (const locale of config2.supportedLocales) {
|
|
1761
1872
|
const commonPath = path3.join(messagesDir, locale, "common.json");
|
|
1762
1873
|
if (await fs3.pathExists(commonPath)) {
|
|
1763
1874
|
try {
|
|
1764
1875
|
const content = await fs3.readJson(commonPath);
|
|
1765
1876
|
if (content.app) {
|
|
1766
|
-
content.app.name =
|
|
1877
|
+
content.app.name = config2.projectName;
|
|
1767
1878
|
if (content.app.description) {
|
|
1768
|
-
content.app.description =
|
|
1879
|
+
content.app.description = config2.projectDescription;
|
|
1769
1880
|
}
|
|
1770
1881
|
}
|
|
1771
1882
|
await fs3.writeJson(commonPath, content, { spaces: 2 });
|
|
@@ -1774,27 +1885,27 @@ async function updateMessageFiles(config) {
|
|
|
1774
1885
|
}
|
|
1775
1886
|
}
|
|
1776
1887
|
}
|
|
1777
|
-
async function processI18n(
|
|
1778
|
-
await removeUnusedLanguages(
|
|
1779
|
-
await removeUnusedEntityMessages(
|
|
1780
|
-
await ensureLanguageFolders(
|
|
1781
|
-
await updateMessageFiles(
|
|
1888
|
+
async function processI18n(config2) {
|
|
1889
|
+
await removeUnusedLanguages(config2);
|
|
1890
|
+
await removeUnusedEntityMessages(config2);
|
|
1891
|
+
await ensureLanguageFolders(config2);
|
|
1892
|
+
await updateMessageFiles(config2);
|
|
1782
1893
|
}
|
|
1783
1894
|
|
|
1784
1895
|
// src/wizard/generators/content-features-generator.ts
|
|
1785
1896
|
import fs4 from "fs-extra";
|
|
1786
1897
|
import path4 from "path";
|
|
1787
|
-
import { fileURLToPath as
|
|
1788
|
-
var
|
|
1789
|
-
var
|
|
1898
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
1899
|
+
var __filename4 = fileURLToPath4(import.meta.url);
|
|
1900
|
+
var __dirname4 = path4.dirname(__filename4);
|
|
1790
1901
|
function getTemplatesDir2() {
|
|
1791
1902
|
try {
|
|
1792
1903
|
const corePkgPath = __require.resolve("@nextsparkjs/core/package.json");
|
|
1793
1904
|
return path4.join(path4.dirname(corePkgPath), "templates");
|
|
1794
1905
|
} catch {
|
|
1795
1906
|
const possiblePaths = [
|
|
1796
|
-
path4.resolve(
|
|
1797
|
-
path4.resolve(
|
|
1907
|
+
path4.resolve(__dirname4, "../../../../../core/templates"),
|
|
1908
|
+
path4.resolve(__dirname4, "../../../../core/templates"),
|
|
1798
1909
|
path4.resolve(process.cwd(), "node_modules/@nextsparkjs/core/templates")
|
|
1799
1910
|
];
|
|
1800
1911
|
for (const p of possiblePaths) {
|
|
@@ -1811,20 +1922,27 @@ function getFeaturesDir() {
|
|
|
1811
1922
|
function getTargetThemeDir(projectSlug) {
|
|
1812
1923
|
return path4.resolve(process.cwd(), "contents", "themes", projectSlug);
|
|
1813
1924
|
}
|
|
1814
|
-
async function copyPagesFeature(
|
|
1925
|
+
async function copyPagesFeature(config2) {
|
|
1815
1926
|
const featuresDir = getFeaturesDir();
|
|
1816
|
-
const targetThemeDir = getTargetThemeDir(
|
|
1927
|
+
const targetThemeDir = getTargetThemeDir(config2.projectSlug);
|
|
1817
1928
|
const sourcePagesEntity = path4.join(featuresDir, "pages", "entities", "pages");
|
|
1818
1929
|
const targetEntitiesDir = path4.join(targetThemeDir, "entities", "pages");
|
|
1819
|
-
if (
|
|
1930
|
+
if (await fs4.pathExists(sourcePagesEntity)) {
|
|
1931
|
+
await fs4.copy(sourcePagesEntity, targetEntitiesDir);
|
|
1932
|
+
} else {
|
|
1820
1933
|
console.warn(`Warning: Pages entity not found at: ${sourcePagesEntity}`);
|
|
1821
|
-
return;
|
|
1822
1934
|
}
|
|
1823
|
-
|
|
1935
|
+
const sourceHeroBlock = path4.join(featuresDir, "pages", "blocks", "hero");
|
|
1936
|
+
const targetHeroBlock = path4.join(targetThemeDir, "blocks", "hero");
|
|
1937
|
+
if (await fs4.pathExists(sourceHeroBlock)) {
|
|
1938
|
+
await fs4.copy(sourceHeroBlock, targetHeroBlock);
|
|
1939
|
+
} else {
|
|
1940
|
+
console.warn(`Warning: Hero block not found at: ${sourceHeroBlock}`);
|
|
1941
|
+
}
|
|
1824
1942
|
}
|
|
1825
|
-
async function copyBlogFeature(
|
|
1943
|
+
async function copyBlogFeature(config2) {
|
|
1826
1944
|
const featuresDir = getFeaturesDir();
|
|
1827
|
-
const targetThemeDir = getTargetThemeDir(
|
|
1945
|
+
const targetThemeDir = getTargetThemeDir(config2.projectSlug);
|
|
1828
1946
|
const sourcePostsEntity = path4.join(featuresDir, "blog", "entities", "posts");
|
|
1829
1947
|
const targetPostsEntity = path4.join(targetThemeDir, "entities", "posts");
|
|
1830
1948
|
if (await fs4.pathExists(sourcePostsEntity)) {
|
|
@@ -1840,34 +1958,34 @@ async function copyBlogFeature(config) {
|
|
|
1840
1958
|
console.warn(`Warning: Post-content block not found at: ${sourcePostContentBlock}`);
|
|
1841
1959
|
}
|
|
1842
1960
|
}
|
|
1843
|
-
async function copyContentFeatures(
|
|
1844
|
-
if (!
|
|
1961
|
+
async function copyContentFeatures(config2) {
|
|
1962
|
+
if (!config2.contentFeatures.pages && !config2.contentFeatures.blog) {
|
|
1845
1963
|
return;
|
|
1846
1964
|
}
|
|
1847
|
-
if (
|
|
1848
|
-
await copyPagesFeature(
|
|
1965
|
+
if (config2.contentFeatures.pages) {
|
|
1966
|
+
await copyPagesFeature(config2);
|
|
1849
1967
|
}
|
|
1850
|
-
if (
|
|
1851
|
-
await copyBlogFeature(
|
|
1968
|
+
if (config2.contentFeatures.blog) {
|
|
1969
|
+
await copyBlogFeature(config2);
|
|
1852
1970
|
}
|
|
1853
1971
|
}
|
|
1854
1972
|
|
|
1855
1973
|
// src/wizard/generators/theme-plugins-installer.ts
|
|
1856
|
-
import { existsSync as existsSync6, cpSync, mkdirSync, readFileSync as
|
|
1857
|
-
import { join as
|
|
1974
|
+
import { existsSync as existsSync6, cpSync, mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
|
|
1975
|
+
import { join as join6, resolve as resolve2 } from "path";
|
|
1858
1976
|
import chalk9 from "chalk";
|
|
1859
1977
|
import ora6 from "ora";
|
|
1860
1978
|
|
|
1861
1979
|
// src/commands/add-theme.ts
|
|
1862
1980
|
import chalk8 from "chalk";
|
|
1863
1981
|
import ora5 from "ora";
|
|
1864
|
-
import { existsSync as existsSync5, readFileSync as
|
|
1865
|
-
import { join as
|
|
1982
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
1983
|
+
import { join as join5 } from "path";
|
|
1866
1984
|
async function addTheme(packageSpec, options = {}) {
|
|
1867
1985
|
const spinner = ora5(`Adding theme ${packageSpec}`).start();
|
|
1868
1986
|
let cleanup = null;
|
|
1869
1987
|
try {
|
|
1870
|
-
const contentsDir =
|
|
1988
|
+
const contentsDir = join5(process.cwd(), "contents");
|
|
1871
1989
|
if (!existsSync5(contentsDir)) {
|
|
1872
1990
|
spinner.fail('contents/ directory not found. Run "nextspark init" first.');
|
|
1873
1991
|
return;
|
|
@@ -1930,13 +2048,13 @@ async function addTheme(packageSpec, options = {}) {
|
|
|
1930
2048
|
}
|
|
1931
2049
|
function checkPluginExists(pluginName) {
|
|
1932
2050
|
const name = pluginName.replace(/^@[^/]+\//, "").replace(/^nextspark-plugin-/, "").replace(/^plugin-/, "");
|
|
1933
|
-
return existsSync5(
|
|
2051
|
+
return existsSync5(join5(process.cwd(), "contents", "plugins", name));
|
|
1934
2052
|
}
|
|
1935
2053
|
function getCoreVersion() {
|
|
1936
|
-
const pkgPath =
|
|
2054
|
+
const pkgPath = join5(process.cwd(), "node_modules", "@nextsparkjs", "core", "package.json");
|
|
1937
2055
|
if (existsSync5(pkgPath)) {
|
|
1938
2056
|
try {
|
|
1939
|
-
const pkg = JSON.parse(
|
|
2057
|
+
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
1940
2058
|
return pkg.version || "0.0.0";
|
|
1941
2059
|
} catch {
|
|
1942
2060
|
return "0.0.0";
|
|
@@ -1974,20 +2092,20 @@ var THEME_REQUIRED_PLUGINS2 = {
|
|
|
1974
2092
|
};
|
|
1975
2093
|
function isMonorepoMode2() {
|
|
1976
2094
|
const possiblePaths = [
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2095
|
+
join6(process.cwd(), "pnpm-workspace.yaml"),
|
|
2096
|
+
join6(process.cwd(), "..", "pnpm-workspace.yaml"),
|
|
2097
|
+
join6(process.cwd(), "..", "..", "pnpm-workspace.yaml")
|
|
1980
2098
|
];
|
|
1981
2099
|
return possiblePaths.some((p) => existsSync6(p));
|
|
1982
2100
|
}
|
|
1983
2101
|
function getMonorepoRoot() {
|
|
1984
2102
|
const possibleRoots = [
|
|
1985
2103
|
process.cwd(),
|
|
1986
|
-
|
|
1987
|
-
|
|
2104
|
+
join6(process.cwd(), ".."),
|
|
2105
|
+
join6(process.cwd(), "..", "..")
|
|
1988
2106
|
];
|
|
1989
2107
|
for (const root of possibleRoots) {
|
|
1990
|
-
if (existsSync6(
|
|
2108
|
+
if (existsSync6(join6(root, "pnpm-workspace.yaml"))) {
|
|
1991
2109
|
return resolve2(root);
|
|
1992
2110
|
}
|
|
1993
2111
|
}
|
|
@@ -1997,15 +2115,15 @@ function getLocalPackageDir(type, name) {
|
|
|
1997
2115
|
const monorepoRoot = getMonorepoRoot();
|
|
1998
2116
|
if (!monorepoRoot) return null;
|
|
1999
2117
|
const baseDir = type === "theme" ? "themes" : "plugins";
|
|
2000
|
-
const packageDir =
|
|
2001
|
-
if (existsSync6(packageDir) && existsSync6(
|
|
2118
|
+
const packageDir = join6(monorepoRoot, baseDir, name);
|
|
2119
|
+
if (existsSync6(packageDir) && existsSync6(join6(packageDir, "package.json"))) {
|
|
2002
2120
|
return packageDir;
|
|
2003
2121
|
}
|
|
2004
2122
|
return null;
|
|
2005
2123
|
}
|
|
2006
2124
|
async function copyLocalTheme(name, sourceDir) {
|
|
2007
|
-
const targetDir =
|
|
2008
|
-
const themesDir =
|
|
2125
|
+
const targetDir = join6(process.cwd(), "contents", "themes", name);
|
|
2126
|
+
const themesDir = join6(process.cwd(), "contents", "themes");
|
|
2009
2127
|
if (!existsSync6(themesDir)) {
|
|
2010
2128
|
mkdirSync(themesDir, { recursive: true });
|
|
2011
2129
|
}
|
|
@@ -2018,8 +2136,8 @@ async function copyLocalTheme(name, sourceDir) {
|
|
|
2018
2136
|
return true;
|
|
2019
2137
|
}
|
|
2020
2138
|
async function copyLocalPlugin(name, sourceDir) {
|
|
2021
|
-
const targetDir =
|
|
2022
|
-
const pluginsDir =
|
|
2139
|
+
const targetDir = join6(process.cwd(), "contents", "plugins", name);
|
|
2140
|
+
const pluginsDir = join6(process.cwd(), "contents", "plugins");
|
|
2023
2141
|
if (!existsSync6(pluginsDir)) {
|
|
2024
2142
|
mkdirSync(pluginsDir, { recursive: true });
|
|
2025
2143
|
}
|
|
@@ -2032,12 +2150,12 @@ async function copyLocalPlugin(name, sourceDir) {
|
|
|
2032
2150
|
return true;
|
|
2033
2151
|
}
|
|
2034
2152
|
async function updateTsConfigPaths(name, type) {
|
|
2035
|
-
const tsconfigPath =
|
|
2153
|
+
const tsconfigPath = join6(process.cwd(), "tsconfig.json");
|
|
2036
2154
|
if (!existsSync6(tsconfigPath)) {
|
|
2037
2155
|
return;
|
|
2038
2156
|
}
|
|
2039
2157
|
try {
|
|
2040
|
-
const content =
|
|
2158
|
+
const content = readFileSync6(tsconfigPath, "utf-8");
|
|
2041
2159
|
const tsconfig = JSON.parse(content);
|
|
2042
2160
|
if (!tsconfig.compilerOptions) {
|
|
2043
2161
|
tsconfig.compilerOptions = {};
|
|
@@ -2077,7 +2195,7 @@ async function installTheme2(theme) {
|
|
|
2077
2195
|
prefixText: " "
|
|
2078
2196
|
}).start();
|
|
2079
2197
|
try {
|
|
2080
|
-
const targetDir =
|
|
2198
|
+
const targetDir = join6(process.cwd(), "contents", "themes", theme);
|
|
2081
2199
|
if (existsSync6(targetDir)) {
|
|
2082
2200
|
spinner.info(chalk9.gray(`Reference theme ${theme} already exists`));
|
|
2083
2201
|
return true;
|
|
@@ -2130,7 +2248,7 @@ async function installPlugins(plugins) {
|
|
|
2130
2248
|
prefixText: " "
|
|
2131
2249
|
}).start();
|
|
2132
2250
|
try {
|
|
2133
|
-
const pluginDir =
|
|
2251
|
+
const pluginDir = join6(process.cwd(), "contents", "plugins", plugin);
|
|
2134
2252
|
if (existsSync6(pluginDir)) {
|
|
2135
2253
|
spinner.info(chalk9.gray(`Plugin ${plugin} already installed`));
|
|
2136
2254
|
continue;
|
|
@@ -2195,16 +2313,16 @@ import fs5 from "fs-extra";
|
|
|
2195
2313
|
import fs6 from "fs-extra";
|
|
2196
2314
|
|
|
2197
2315
|
// src/wizard/generators/index.ts
|
|
2198
|
-
var
|
|
2199
|
-
var
|
|
2316
|
+
var __filename5 = fileURLToPath5(import.meta.url);
|
|
2317
|
+
var __dirname5 = path5.dirname(__filename5);
|
|
2200
2318
|
function getTemplatesDir3() {
|
|
2201
2319
|
try {
|
|
2202
2320
|
const corePkgPath = __require.resolve("@nextsparkjs/core/package.json");
|
|
2203
2321
|
return path5.join(path5.dirname(corePkgPath), "templates");
|
|
2204
2322
|
} catch {
|
|
2205
2323
|
const possiblePaths = [
|
|
2206
|
-
path5.resolve(
|
|
2207
|
-
path5.resolve(
|
|
2324
|
+
path5.resolve(__dirname5, "../../../../../core/templates"),
|
|
2325
|
+
path5.resolve(__dirname5, "../../../../core/templates"),
|
|
2208
2326
|
path5.resolve(process.cwd(), "node_modules/@nextsparkjs/core/templates")
|
|
2209
2327
|
];
|
|
2210
2328
|
for (const p of possiblePaths) {
|
|
@@ -2228,7 +2346,8 @@ async function copyProjectFiles() {
|
|
|
2228
2346
|
{ src: "npmrc", dest: ".npmrc", force: false },
|
|
2229
2347
|
{ src: "tsconfig.cypress.json", dest: "tsconfig.cypress.json", force: false },
|
|
2230
2348
|
{ src: "cypress.d.ts", dest: "cypress.d.ts", force: false },
|
|
2231
|
-
{ src: "eslint.config.mjs", dest: "eslint.config.mjs", force: false }
|
|
2349
|
+
{ src: "eslint.config.mjs", dest: "eslint.config.mjs", force: false },
|
|
2350
|
+
{ src: "scripts/cy-run-prod.cjs", dest: "scripts/cy-run-prod.cjs", force: false }
|
|
2232
2351
|
];
|
|
2233
2352
|
for (const item of itemsToCopy) {
|
|
2234
2353
|
const srcPath = path5.join(templatesDir, item.src);
|
|
@@ -2240,12 +2359,12 @@ async function copyProjectFiles() {
|
|
|
2240
2359
|
}
|
|
2241
2360
|
}
|
|
2242
2361
|
}
|
|
2243
|
-
async function updatePackageJson(
|
|
2362
|
+
async function updatePackageJson(config2) {
|
|
2244
2363
|
const packageJsonPath = path5.resolve(process.cwd(), "package.json");
|
|
2245
2364
|
let packageJson;
|
|
2246
2365
|
if (!await fs7.pathExists(packageJsonPath)) {
|
|
2247
2366
|
packageJson = {
|
|
2248
|
-
name:
|
|
2367
|
+
name: config2.projectSlug,
|
|
2249
2368
|
version: "0.1.0",
|
|
2250
2369
|
private: true,
|
|
2251
2370
|
scripts: {},
|
|
@@ -2264,11 +2383,13 @@ async function updatePackageJson(config) {
|
|
|
2264
2383
|
"build:registries": "nextspark registry:build",
|
|
2265
2384
|
"db:migrate": "nextspark db:migrate",
|
|
2266
2385
|
"db:seed": "nextspark db:seed",
|
|
2267
|
-
"test
|
|
2268
|
-
"cy:open":
|
|
2269
|
-
"cy:run":
|
|
2270
|
-
"
|
|
2271
|
-
"
|
|
2386
|
+
"test": "node node_modules/@nextsparkjs/core/scripts/test/jest-theme.mjs",
|
|
2387
|
+
"cy:open": "node node_modules/@nextsparkjs/core/scripts/test/cy.mjs open",
|
|
2388
|
+
"cy:run": "node node_modules/@nextsparkjs/core/scripts/test/cy.mjs run",
|
|
2389
|
+
"cy:tags": "node node_modules/@nextsparkjs/core/scripts/test/cy.mjs tags",
|
|
2390
|
+
"cy:run:prod": "node scripts/cy-run-prod.cjs",
|
|
2391
|
+
"allure:generate": `allure generate contents/themes/${config2.projectSlug}/tests/cypress/allure-results --clean -o contents/themes/${config2.projectSlug}/tests/cypress/allure-report`,
|
|
2392
|
+
"allure:open": `allure open contents/themes/${config2.projectSlug}/tests/cypress/allure-report`
|
|
2272
2393
|
};
|
|
2273
2394
|
for (const [name, command] of Object.entries(scriptsToAdd)) {
|
|
2274
2395
|
if (!packageJson.scripts[name]) {
|
|
@@ -2278,8 +2399,8 @@ async function updatePackageJson(config) {
|
|
|
2278
2399
|
packageJson.dependencies = packageJson.dependencies || {};
|
|
2279
2400
|
const depsToAdd = {
|
|
2280
2401
|
// NextSpark
|
|
2281
|
-
"@nextsparkjs/core": "
|
|
2282
|
-
"@nextsparkjs/cli": "
|
|
2402
|
+
"@nextsparkjs/core": "latest",
|
|
2403
|
+
"@nextsparkjs/cli": "latest",
|
|
2283
2404
|
// Next.js + React
|
|
2284
2405
|
"next": "^15.1.0",
|
|
2285
2406
|
"react": "^19.0.0",
|
|
@@ -2338,14 +2459,16 @@ async function updatePackageJson(config) {
|
|
|
2338
2459
|
"@testing-library/react": "^16.3.0",
|
|
2339
2460
|
"jest-environment-jsdom": "^29.7.0",
|
|
2340
2461
|
// Cypress
|
|
2341
|
-
"cypress": "^
|
|
2462
|
+
"cypress": "^15.8.2",
|
|
2342
2463
|
"@testing-library/cypress": "^10.0.2",
|
|
2343
2464
|
"@cypress/webpack-preprocessor": "^6.0.2",
|
|
2344
|
-
"@cypress/grep": "^
|
|
2465
|
+
"@cypress/grep": "^5.0.1",
|
|
2345
2466
|
"ts-loader": "^9.5.1",
|
|
2346
2467
|
"webpack": "^5.97.0",
|
|
2347
2468
|
"allure-cypress": "^3.0.0",
|
|
2348
|
-
"allure-commandline": "^2.27.0"
|
|
2469
|
+
"allure-commandline": "^2.27.0",
|
|
2470
|
+
// NextSpark Testing
|
|
2471
|
+
"@nextsparkjs/testing": "latest"
|
|
2349
2472
|
};
|
|
2350
2473
|
for (const [name, version] of Object.entries(devDepsToAdd)) {
|
|
2351
2474
|
if (!packageJson.devDependencies[name]) {
|
|
@@ -2354,7 +2477,7 @@ async function updatePackageJson(config) {
|
|
|
2354
2477
|
}
|
|
2355
2478
|
await fs7.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
2356
2479
|
}
|
|
2357
|
-
async function updateGitignore(
|
|
2480
|
+
async function updateGitignore(config2) {
|
|
2358
2481
|
const gitignorePath = path5.resolve(process.cwd(), ".gitignore");
|
|
2359
2482
|
const entriesToAdd = `
|
|
2360
2483
|
# NextSpark
|
|
@@ -2382,26 +2505,30 @@ contents/themes/*/tests/jest/coverage
|
|
|
2382
2505
|
await fs7.writeFile(gitignorePath, entriesToAdd.trim());
|
|
2383
2506
|
}
|
|
2384
2507
|
}
|
|
2385
|
-
async function generateProject(
|
|
2508
|
+
async function generateProject(config2) {
|
|
2386
2509
|
await copyProjectFiles();
|
|
2387
|
-
await
|
|
2388
|
-
await
|
|
2389
|
-
await
|
|
2390
|
-
await
|
|
2391
|
-
await
|
|
2392
|
-
await
|
|
2393
|
-
await
|
|
2394
|
-
await
|
|
2395
|
-
await
|
|
2396
|
-
await
|
|
2397
|
-
await
|
|
2398
|
-
await
|
|
2399
|
-
await
|
|
2400
|
-
await
|
|
2401
|
-
await
|
|
2402
|
-
await
|
|
2403
|
-
await
|
|
2404
|
-
await
|
|
2510
|
+
await updateGlobalsCss(config2);
|
|
2511
|
+
await copyStarterTheme(config2);
|
|
2512
|
+
await copyContentFeatures(config2);
|
|
2513
|
+
await updateThemeConfig(config2);
|
|
2514
|
+
await updateDevConfig(config2);
|
|
2515
|
+
await updateAppConfig(config2);
|
|
2516
|
+
await updateBillingConfig(config2);
|
|
2517
|
+
await updateRolesConfig(config2);
|
|
2518
|
+
await updateMigrations(config2);
|
|
2519
|
+
await updateTestFiles(config2);
|
|
2520
|
+
await updatePermissionsConfig(config2);
|
|
2521
|
+
await updateEntityPermissions(config2);
|
|
2522
|
+
await updateDashboardConfig(config2);
|
|
2523
|
+
await updateAuthConfig(config2);
|
|
2524
|
+
await updateDashboardUIConfig(config2);
|
|
2525
|
+
await updateDevToolsConfig(config2);
|
|
2526
|
+
await processI18n(config2);
|
|
2527
|
+
await updatePackageJson(config2);
|
|
2528
|
+
await updateGitignore(config2);
|
|
2529
|
+
await generateEnvExample(config2);
|
|
2530
|
+
await updateReadme(config2);
|
|
2531
|
+
await copyEnvExampleToEnv();
|
|
2405
2532
|
}
|
|
2406
2533
|
|
|
2407
2534
|
// src/wizard/presets.ts
|
|
@@ -2564,9 +2691,9 @@ var BOX = {
|
|
|
2564
2691
|
bottomRight: "\u2518"
|
|
2565
2692
|
// bottom-right corner
|
|
2566
2693
|
};
|
|
2567
|
-
function getFileTree(
|
|
2694
|
+
function getFileTree(config2) {
|
|
2568
2695
|
const files = [];
|
|
2569
|
-
const themeDir = `contents/themes/${
|
|
2696
|
+
const themeDir = `contents/themes/${config2.projectSlug}`;
|
|
2570
2697
|
files.push(`${themeDir}/config/app.config.ts`);
|
|
2571
2698
|
files.push(`${themeDir}/config/billing.config.ts`);
|
|
2572
2699
|
files.push(`${themeDir}/config/dashboard.config.ts`);
|
|
@@ -2582,7 +2709,7 @@ function getFileTree(config) {
|
|
|
2582
2709
|
files.push(`${themeDir}/blocks/hero/block.tsx`);
|
|
2583
2710
|
files.push(`${themeDir}/blocks/hero/schema.ts`);
|
|
2584
2711
|
files.push(`${themeDir}/blocks/hero/styles.ts`);
|
|
2585
|
-
for (const locale of
|
|
2712
|
+
for (const locale of config2.supportedLocales) {
|
|
2586
2713
|
files.push(`${themeDir}/messages/${locale}/common.json`);
|
|
2587
2714
|
files.push(`${themeDir}/messages/${locale}/auth.json`);
|
|
2588
2715
|
files.push(`${themeDir}/messages/${locale}/dashboard.json`);
|
|
@@ -2595,7 +2722,7 @@ function getFileTree(config) {
|
|
|
2595
2722
|
files.push(`${themeDir}/styles/theme.css`);
|
|
2596
2723
|
files.push(`${themeDir}/styles/components.css`);
|
|
2597
2724
|
files.push(`${themeDir}/tests/cypress.config.ts`);
|
|
2598
|
-
files.push(`${themeDir}/tests/jest/jest.config.
|
|
2725
|
+
files.push(`${themeDir}/tests/jest/jest.config.cjs`);
|
|
2599
2726
|
files.push(`${themeDir}/tests/cypress/e2e/auth.cy.ts`);
|
|
2600
2727
|
files.push(`${themeDir}/tests/cypress/e2e/dashboard.cy.ts`);
|
|
2601
2728
|
files.push(`${themeDir}/tests/jest/components/hero.test.tsx`);
|
|
@@ -2633,10 +2760,10 @@ function groupFilesByCategory(files) {
|
|
|
2633
2760
|
function formatFilePath(file, themeDir) {
|
|
2634
2761
|
return file.replace(`${themeDir}/`, "");
|
|
2635
2762
|
}
|
|
2636
|
-
function showConfigPreview(
|
|
2637
|
-
const files = getFileTree(
|
|
2763
|
+
function showConfigPreview(config2) {
|
|
2764
|
+
const files = getFileTree(config2);
|
|
2638
2765
|
const groups = groupFilesByCategory(files);
|
|
2639
|
-
const themeDir = `contents/themes/${
|
|
2766
|
+
const themeDir = `contents/themes/${config2.projectSlug}`;
|
|
2640
2767
|
console.log("");
|
|
2641
2768
|
console.log(chalk10.cyan.bold(" Theme Preview"));
|
|
2642
2769
|
console.log(chalk10.gray(" " + "=".repeat(50)));
|
|
@@ -2698,8 +2825,8 @@ function showConfigPreview(config) {
|
|
|
2698
2825
|
}
|
|
2699
2826
|
console.log("");
|
|
2700
2827
|
console.log(chalk10.gray(" Locales configured:"));
|
|
2701
|
-
for (const locale of
|
|
2702
|
-
const isDefault = locale ===
|
|
2828
|
+
for (const locale of config2.supportedLocales) {
|
|
2829
|
+
const isDefault = locale === config2.defaultLocale;
|
|
2703
2830
|
const suffix = isDefault ? chalk10.cyan(" (default)") : "";
|
|
2704
2831
|
console.log(chalk10.gray(` - `) + chalk10.white(locale) + suffix);
|
|
2705
2832
|
}
|
|
@@ -2741,25 +2868,25 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
2741
2868
|
selectedPlugins = getRequiredPlugins(selectedTheme);
|
|
2742
2869
|
}
|
|
2743
2870
|
}
|
|
2744
|
-
let
|
|
2871
|
+
let config2;
|
|
2745
2872
|
if (options.preset) {
|
|
2746
|
-
|
|
2873
|
+
config2 = await runPresetMode(options.preset, options);
|
|
2747
2874
|
} else {
|
|
2748
2875
|
switch (options.mode) {
|
|
2749
2876
|
case "quick":
|
|
2750
|
-
|
|
2877
|
+
config2 = await runQuickPrompts();
|
|
2751
2878
|
break;
|
|
2752
2879
|
case "expert":
|
|
2753
|
-
|
|
2880
|
+
config2 = await runExpertPrompts();
|
|
2754
2881
|
break;
|
|
2755
2882
|
case "interactive":
|
|
2756
2883
|
default:
|
|
2757
|
-
|
|
2884
|
+
config2 = await runAllPrompts();
|
|
2758
2885
|
break;
|
|
2759
2886
|
}
|
|
2760
2887
|
}
|
|
2761
|
-
showConfigSummary(
|
|
2762
|
-
showConfigPreview(
|
|
2888
|
+
showConfigSummary(config2);
|
|
2889
|
+
showConfigPreview(config2);
|
|
2763
2890
|
if (!options.yes) {
|
|
2764
2891
|
console.log("");
|
|
2765
2892
|
const proceed = await confirm5({
|
|
@@ -2785,7 +2912,7 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
2785
2912
|
prefixText: " "
|
|
2786
2913
|
}).start();
|
|
2787
2914
|
try {
|
|
2788
|
-
await generateProject(
|
|
2915
|
+
await generateProject(config2);
|
|
2789
2916
|
spinner.succeed("Project generated successfully!");
|
|
2790
2917
|
} catch (error) {
|
|
2791
2918
|
spinner.fail("Failed to generate project");
|
|
@@ -2794,7 +2921,41 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
2794
2921
|
if (selectedTheme || selectedPlugins.length > 0) {
|
|
2795
2922
|
await installThemeAndPlugins(selectedTheme, selectedPlugins);
|
|
2796
2923
|
}
|
|
2797
|
-
|
|
2924
|
+
const installSpinner = ora7({
|
|
2925
|
+
text: "Installing dependencies...",
|
|
2926
|
+
prefixText: " "
|
|
2927
|
+
}).start();
|
|
2928
|
+
try {
|
|
2929
|
+
execSync("pnpm install --force", {
|
|
2930
|
+
cwd: process.cwd(),
|
|
2931
|
+
stdio: "pipe"
|
|
2932
|
+
});
|
|
2933
|
+
installSpinner.succeed("Dependencies installed!");
|
|
2934
|
+
} catch (error) {
|
|
2935
|
+
installSpinner.fail("Failed to install dependencies");
|
|
2936
|
+
console.log(chalk11.yellow(' Run "pnpm install" manually to install dependencies'));
|
|
2937
|
+
}
|
|
2938
|
+
const registrySpinner = ora7({
|
|
2939
|
+
text: "Building registries...",
|
|
2940
|
+
prefixText: " "
|
|
2941
|
+
}).start();
|
|
2942
|
+
try {
|
|
2943
|
+
const projectRoot = process.cwd();
|
|
2944
|
+
const registryScript = join7(projectRoot, "node_modules/@nextsparkjs/core/scripts/build/registry.mjs");
|
|
2945
|
+
execSync(`node "${registryScript}" --build`, {
|
|
2946
|
+
cwd: projectRoot,
|
|
2947
|
+
stdio: "pipe",
|
|
2948
|
+
env: {
|
|
2949
|
+
...process.env,
|
|
2950
|
+
NEXTSPARK_PROJECT_ROOT: projectRoot
|
|
2951
|
+
}
|
|
2952
|
+
});
|
|
2953
|
+
registrySpinner.succeed("Registries built!");
|
|
2954
|
+
} catch (error) {
|
|
2955
|
+
registrySpinner.fail("Failed to build registries");
|
|
2956
|
+
console.log(chalk11.yellow(' Registries will be built automatically when you run "pnpm dev"'));
|
|
2957
|
+
}
|
|
2958
|
+
showNextSteps(config2, selectedTheme);
|
|
2798
2959
|
} catch (error) {
|
|
2799
2960
|
if (error instanceof Error) {
|
|
2800
2961
|
if (error.message.includes("User force closed")) {
|
|
@@ -2834,46 +2995,46 @@ async function runPresetMode(presetName, options) {
|
|
|
2834
2995
|
console.log("");
|
|
2835
2996
|
projectInfo = await promptProjectInfo();
|
|
2836
2997
|
}
|
|
2837
|
-
const
|
|
2838
|
-
return
|
|
2998
|
+
const config2 = applyPreset(projectInfo, presetName);
|
|
2999
|
+
return config2;
|
|
2839
3000
|
}
|
|
2840
|
-
function showConfigSummary(
|
|
3001
|
+
function showConfigSummary(config2) {
|
|
2841
3002
|
console.log("");
|
|
2842
3003
|
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
2843
3004
|
console.log(chalk11.bold.white(" Configuration Summary"));
|
|
2844
3005
|
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
2845
3006
|
console.log("");
|
|
2846
3007
|
console.log(chalk11.white(" Project:"));
|
|
2847
|
-
console.log(chalk11.gray(` Name: ${chalk11.white(
|
|
2848
|
-
console.log(chalk11.gray(` Slug: ${chalk11.white(
|
|
2849
|
-
console.log(chalk11.gray(` Description: ${chalk11.white(
|
|
3008
|
+
console.log(chalk11.gray(` Name: ${chalk11.white(config2.projectName)}`));
|
|
3009
|
+
console.log(chalk11.gray(` Slug: ${chalk11.white(config2.projectSlug)}`));
|
|
3010
|
+
console.log(chalk11.gray(` Description: ${chalk11.white(config2.projectDescription)}`));
|
|
2850
3011
|
console.log("");
|
|
2851
3012
|
console.log(chalk11.white(" Team Mode:"));
|
|
2852
|
-
console.log(chalk11.gray(` Mode: ${chalk11.white(
|
|
2853
|
-
console.log(chalk11.gray(` Roles: ${chalk11.white(
|
|
3013
|
+
console.log(chalk11.gray(` Mode: ${chalk11.white(config2.teamMode)}`));
|
|
3014
|
+
console.log(chalk11.gray(` Roles: ${chalk11.white(config2.teamRoles.join(", "))}`));
|
|
2854
3015
|
console.log("");
|
|
2855
3016
|
console.log(chalk11.white(" Internationalization:"));
|
|
2856
|
-
console.log(chalk11.gray(` Default: ${chalk11.white(
|
|
2857
|
-
console.log(chalk11.gray(` Languages: ${chalk11.white(
|
|
3017
|
+
console.log(chalk11.gray(` Default: ${chalk11.white(config2.defaultLocale)}`));
|
|
3018
|
+
console.log(chalk11.gray(` Languages: ${chalk11.white(config2.supportedLocales.join(", "))}`));
|
|
2858
3019
|
console.log("");
|
|
2859
3020
|
console.log(chalk11.white(" Billing:"));
|
|
2860
|
-
console.log(chalk11.gray(` Model: ${chalk11.white(
|
|
2861
|
-
console.log(chalk11.gray(` Currency: ${chalk11.white(
|
|
3021
|
+
console.log(chalk11.gray(` Model: ${chalk11.white(config2.billingModel)}`));
|
|
3022
|
+
console.log(chalk11.gray(` Currency: ${chalk11.white(config2.currency.toUpperCase())}`));
|
|
2862
3023
|
console.log("");
|
|
2863
3024
|
console.log(chalk11.white(" Features:"));
|
|
2864
|
-
const enabledFeatures = Object.entries(
|
|
3025
|
+
const enabledFeatures = Object.entries(config2.features).filter(([_, enabled]) => enabled).map(([feature]) => feature);
|
|
2865
3026
|
console.log(chalk11.gray(` Enabled: ${chalk11.white(enabledFeatures.join(", ") || "None")}`));
|
|
2866
3027
|
console.log("");
|
|
2867
3028
|
console.log(chalk11.white(" Authentication:"));
|
|
2868
|
-
const enabledAuth = Object.entries(
|
|
3029
|
+
const enabledAuth = Object.entries(config2.auth).filter(([_, enabled]) => enabled).map(([method]) => formatAuthMethod(method));
|
|
2869
3030
|
console.log(chalk11.gray(` Methods: ${chalk11.white(enabledAuth.join(", ") || "None")}`));
|
|
2870
3031
|
console.log("");
|
|
2871
3032
|
console.log(chalk11.white(" Dashboard:"));
|
|
2872
|
-
const enabledDashboard = Object.entries(
|
|
3033
|
+
const enabledDashboard = Object.entries(config2.dashboard).filter(([_, enabled]) => enabled).map(([feature]) => formatDashboardFeature(feature));
|
|
2873
3034
|
console.log(chalk11.gray(` Features: ${chalk11.white(enabledDashboard.join(", ") || "None")}`));
|
|
2874
3035
|
console.log("");
|
|
2875
3036
|
console.log(chalk11.white(" Dev Tools:"));
|
|
2876
|
-
const enabledDevTools = Object.entries(
|
|
3037
|
+
const enabledDevTools = Object.entries(config2.dev).filter(([_, enabled]) => enabled).map(([tool]) => formatDevTool(tool));
|
|
2877
3038
|
console.log(chalk11.gray(` Enabled: ${chalk11.white(enabledDevTools.join(", ") || "None")}`));
|
|
2878
3039
|
}
|
|
2879
3040
|
function formatAuthMethod(method) {
|
|
@@ -2900,38 +3061,38 @@ function formatDevTool(tool) {
|
|
|
2900
3061
|
};
|
|
2901
3062
|
return mapping[tool] || tool;
|
|
2902
3063
|
}
|
|
2903
|
-
function showNextSteps(
|
|
3064
|
+
function showNextSteps(config2, referenceTheme = null) {
|
|
2904
3065
|
console.log("");
|
|
2905
3066
|
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
2906
|
-
console.log(chalk11.bold.green(" \u2728 NextSpark project
|
|
3067
|
+
console.log(chalk11.bold.green(" \u2728 NextSpark project ready!"));
|
|
2907
3068
|
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
2908
3069
|
console.log("");
|
|
2909
3070
|
console.log(chalk11.bold.white(" Next steps:"));
|
|
2910
3071
|
console.log("");
|
|
2911
|
-
console.log(chalk11.white(" 1.
|
|
2912
|
-
console.log(chalk11.
|
|
3072
|
+
console.log(chalk11.white(" 1. Configure your .env file:"));
|
|
3073
|
+
console.log(chalk11.gray(" Edit these values in .env:"));
|
|
2913
3074
|
console.log("");
|
|
2914
|
-
console.log(chalk11.
|
|
2915
|
-
console.log(chalk11.gray("
|
|
2916
|
-
console.log(chalk11.
|
|
2917
|
-
console.log(chalk11.yellow(" - BETTER_AUTH_SECRET"));
|
|
2918
|
-
console.log(chalk11.yellow(` - NEXT_PUBLIC_ACTIVE_THEME=${config.projectSlug}`));
|
|
3075
|
+
console.log(chalk11.yellow(" DATABASE_URL"));
|
|
3076
|
+
console.log(chalk11.gray(" PostgreSQL connection string"));
|
|
3077
|
+
console.log(chalk11.dim(" Example: postgresql://user:pass@localhost:5432/mydb"));
|
|
2919
3078
|
console.log("");
|
|
2920
|
-
console.log(chalk11.
|
|
2921
|
-
console.log(chalk11.
|
|
3079
|
+
console.log(chalk11.yellow(" BETTER_AUTH_SECRET"));
|
|
3080
|
+
console.log(chalk11.gray(" Generate with:"));
|
|
3081
|
+
console.log(chalk11.cyan(" openssl rand -base64 32"));
|
|
2922
3082
|
console.log("");
|
|
2923
|
-
console.log(chalk11.white("
|
|
3083
|
+
console.log(chalk11.white(" 2. Run database migrations:"));
|
|
2924
3084
|
console.log(chalk11.cyan(" pnpm db:migrate"));
|
|
2925
3085
|
console.log("");
|
|
2926
|
-
console.log(chalk11.white("
|
|
3086
|
+
console.log(chalk11.white(" 3. Start the development server:"));
|
|
2927
3087
|
console.log(chalk11.cyan(" pnpm dev"));
|
|
2928
3088
|
console.log("");
|
|
2929
3089
|
console.log(chalk11.gray(" " + "-".repeat(60)));
|
|
2930
|
-
console.log(chalk11.gray(`
|
|
3090
|
+
console.log(chalk11.gray(` Theme: ${chalk11.white(`contents/themes/${config2.projectSlug}/`)}`));
|
|
3091
|
+
console.log(chalk11.gray(` Active theme: ${chalk11.green(`NEXT_PUBLIC_ACTIVE_THEME=${config2.projectSlug}`)}`));
|
|
2931
3092
|
if (referenceTheme) {
|
|
2932
|
-
console.log(chalk11.gray(` Reference
|
|
3093
|
+
console.log(chalk11.gray(` Reference: ${chalk11.white(`contents/themes/${referenceTheme}/`)}`));
|
|
2933
3094
|
}
|
|
2934
|
-
console.log(chalk11.gray("
|
|
3095
|
+
console.log(chalk11.gray(" Docs: https://nextspark.dev/docs"));
|
|
2935
3096
|
console.log("");
|
|
2936
3097
|
}
|
|
2937
3098
|
function findLocalCoreTarball() {
|
|
@@ -2942,14 +3103,14 @@ function findLocalCoreTarball() {
|
|
|
2942
3103
|
(f) => f.includes("nextsparkjs-core") && f.endsWith(".tgz")
|
|
2943
3104
|
);
|
|
2944
3105
|
if (coreTarball) {
|
|
2945
|
-
return
|
|
3106
|
+
return join7(cwd, coreTarball);
|
|
2946
3107
|
}
|
|
2947
3108
|
} catch {
|
|
2948
3109
|
}
|
|
2949
3110
|
return null;
|
|
2950
3111
|
}
|
|
2951
3112
|
function isCoreInstalled() {
|
|
2952
|
-
const corePath =
|
|
3113
|
+
const corePath = join7(process.cwd(), "node_modules", "@nextsparkjs", "core");
|
|
2953
3114
|
return existsSync7(corePath);
|
|
2954
3115
|
}
|
|
2955
3116
|
async function installCore() {
|
|
@@ -2967,8 +3128,8 @@ async function installCore() {
|
|
|
2967
3128
|
packageSpec = localTarball;
|
|
2968
3129
|
spinner.text = "Installing @nextsparkjs/core from local tarball...";
|
|
2969
3130
|
}
|
|
2970
|
-
const useYarn = existsSync7(
|
|
2971
|
-
const usePnpm = existsSync7(
|
|
3131
|
+
const useYarn = existsSync7(join7(process.cwd(), "yarn.lock"));
|
|
3132
|
+
const usePnpm = existsSync7(join7(process.cwd(), "pnpm-lock.yaml"));
|
|
2972
3133
|
let installCmd;
|
|
2973
3134
|
if (usePnpm) {
|
|
2974
3135
|
installCmd = `pnpm add ${packageSpec}`;
|
|
@@ -2993,7 +3154,7 @@ async function installCore() {
|
|
|
2993
3154
|
}
|
|
2994
3155
|
}
|
|
2995
3156
|
async function copyNpmrc() {
|
|
2996
|
-
const npmrcPath =
|
|
3157
|
+
const npmrcPath = join7(process.cwd(), ".npmrc");
|
|
2997
3158
|
if (existsSync7(npmrcPath)) {
|
|
2998
3159
|
return;
|
|
2999
3160
|
}
|
|
@@ -3017,10 +3178,10 @@ function parsePlugins(pluginsStr) {
|
|
|
3017
3178
|
}
|
|
3018
3179
|
function hasExistingProject() {
|
|
3019
3180
|
const projectRoot = process.cwd();
|
|
3020
|
-
return existsSync8(
|
|
3181
|
+
return existsSync8(join8(projectRoot, "contents")) || existsSync8(join8(projectRoot, ".nextspark"));
|
|
3021
3182
|
}
|
|
3022
3183
|
function generateInitialRegistries(registriesDir) {
|
|
3023
|
-
writeFileSync2(
|
|
3184
|
+
writeFileSync2(join8(registriesDir, "block-registry.ts"), `// Auto-generated by nextspark init
|
|
3024
3185
|
import type { ComponentType } from 'react'
|
|
3025
3186
|
|
|
3026
3187
|
export const BLOCK_REGISTRY: Record<string, {
|
|
@@ -3033,26 +3194,26 @@ export const BLOCK_REGISTRY: Record<string, {
|
|
|
3033
3194
|
|
|
3034
3195
|
export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<ComponentType<any>>> = {}
|
|
3035
3196
|
`);
|
|
3036
|
-
writeFileSync2(
|
|
3197
|
+
writeFileSync2(join8(registriesDir, "theme-registry.ts"), `// Auto-generated by nextspark init
|
|
3037
3198
|
export const THEME_REGISTRY: Record<string, unknown> = {}
|
|
3038
3199
|
`);
|
|
3039
|
-
writeFileSync2(
|
|
3200
|
+
writeFileSync2(join8(registriesDir, "entity-registry.ts"), `// Auto-generated by nextspark init
|
|
3040
3201
|
export const ENTITY_REGISTRY: Record<string, unknown> = {}
|
|
3041
3202
|
`);
|
|
3042
|
-
writeFileSync2(
|
|
3203
|
+
writeFileSync2(join8(registriesDir, "entity-registry.client.ts"), `// Auto-generated by nextspark init
|
|
3043
3204
|
export const CLIENT_ENTITY_REGISTRY: Record<string, unknown> = {}
|
|
3044
3205
|
export function parseChildEntity(path: string) { return null }
|
|
3045
3206
|
export function getEntityApiPath(entity: string) { return \`/api/\${entity}\` }
|
|
3046
3207
|
export function clientMetaSystemAdapter() { return {} }
|
|
3047
3208
|
export type ClientEntityConfig = Record<string, unknown>
|
|
3048
3209
|
`);
|
|
3049
|
-
writeFileSync2(
|
|
3210
|
+
writeFileSync2(join8(registriesDir, "billing-registry.ts"), `// Auto-generated by nextspark init
|
|
3050
3211
|
export const BILLING_REGISTRY = { plans: [], features: [] }
|
|
3051
3212
|
`);
|
|
3052
|
-
writeFileSync2(
|
|
3213
|
+
writeFileSync2(join8(registriesDir, "plugin-registry.ts"), `// Auto-generated by nextspark init
|
|
3053
3214
|
export const PLUGIN_REGISTRY: Record<string, unknown> = {}
|
|
3054
3215
|
`);
|
|
3055
|
-
writeFileSync2(
|
|
3216
|
+
writeFileSync2(join8(registriesDir, "testing-registry.ts"), `// Auto-generated by nextspark init
|
|
3056
3217
|
export const FLOW_REGISTRY: Record<string, unknown> = {}
|
|
3057
3218
|
export const FEATURE_REGISTRY: Record<string, unknown> = {}
|
|
3058
3219
|
export const TAGS_REGISTRY: Record<string, unknown> = {}
|
|
@@ -3060,11 +3221,11 @@ export const COVERAGE_SUMMARY = { total: 0, covered: 0 }
|
|
|
3060
3221
|
export type FlowEntry = unknown
|
|
3061
3222
|
export type FeatureEntry = unknown
|
|
3062
3223
|
`);
|
|
3063
|
-
writeFileSync2(
|
|
3224
|
+
writeFileSync2(join8(registriesDir, "docs-registry.ts"), `// Auto-generated by nextspark init
|
|
3064
3225
|
export const DOCS_REGISTRY = { sections: [], pages: [] }
|
|
3065
3226
|
export type DocSectionMeta = { title: string; slug: string }
|
|
3066
3227
|
`);
|
|
3067
|
-
writeFileSync2(
|
|
3228
|
+
writeFileSync2(join8(registriesDir, "index.ts"), `// Auto-generated by nextspark init
|
|
3068
3229
|
export * from './block-registry'
|
|
3069
3230
|
export * from './theme-registry'
|
|
3070
3231
|
export * from './entity-registry'
|
|
@@ -3079,18 +3240,18 @@ async function simpleInit(options) {
|
|
|
3079
3240
|
const spinner = ora8("Initializing NextSpark project...").start();
|
|
3080
3241
|
const projectRoot = process.cwd();
|
|
3081
3242
|
try {
|
|
3082
|
-
const nextspark =
|
|
3083
|
-
const registriesDir =
|
|
3243
|
+
const nextspark = join8(projectRoot, ".nextspark");
|
|
3244
|
+
const registriesDir = join8(nextspark, "registries");
|
|
3084
3245
|
if (!existsSync8(registriesDir) || options.force) {
|
|
3085
3246
|
mkdirSync2(registriesDir, { recursive: true });
|
|
3086
3247
|
spinner.text = "Creating .nextspark/registries/";
|
|
3087
3248
|
generateInitialRegistries(registriesDir);
|
|
3088
3249
|
spinner.text = "Generated initial registries";
|
|
3089
3250
|
}
|
|
3090
|
-
const tsconfigPath =
|
|
3251
|
+
const tsconfigPath = join8(projectRoot, "tsconfig.json");
|
|
3091
3252
|
if (existsSync8(tsconfigPath)) {
|
|
3092
3253
|
spinner.text = "Updating tsconfig.json paths...";
|
|
3093
|
-
const tsconfig = JSON.parse(
|
|
3254
|
+
const tsconfig = JSON.parse(readFileSync7(tsconfigPath, "utf-8"));
|
|
3094
3255
|
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
3095
3256
|
tsconfig.compilerOptions.paths = {
|
|
3096
3257
|
...tsconfig.compilerOptions.paths,
|
|
@@ -3099,7 +3260,7 @@ async function simpleInit(options) {
|
|
|
3099
3260
|
};
|
|
3100
3261
|
writeFileSync2(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
3101
3262
|
}
|
|
3102
|
-
const envExample =
|
|
3263
|
+
const envExample = join8(projectRoot, ".env.example");
|
|
3103
3264
|
if (!existsSync8(envExample)) {
|
|
3104
3265
|
const envContent = `# NextSpark Configuration
|
|
3105
3266
|
DATABASE_URL="postgresql://user:password@localhost:5432/db"
|
|
@@ -3608,10 +3769,101 @@ async function doctorCommand() {
|
|
|
3608
3769
|
}
|
|
3609
3770
|
}
|
|
3610
3771
|
|
|
3772
|
+
// src/commands/db.ts
|
|
3773
|
+
import { spawn as spawn5 } from "child_process";
|
|
3774
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
|
|
3775
|
+
import { join as join9 } from "path";
|
|
3776
|
+
import chalk15 from "chalk";
|
|
3777
|
+
import ora9 from "ora";
|
|
3778
|
+
function loadProjectEnv4(projectRoot) {
|
|
3779
|
+
const envPath = join9(projectRoot, ".env");
|
|
3780
|
+
const envVars = {};
|
|
3781
|
+
if (existsSync9(envPath)) {
|
|
3782
|
+
const content = readFileSync8(envPath, "utf-8");
|
|
3783
|
+
for (const line of content.split("\n")) {
|
|
3784
|
+
const trimmed = line.trim();
|
|
3785
|
+
if (trimmed && !trimmed.startsWith("#")) {
|
|
3786
|
+
const [key, ...valueParts] = trimmed.split("=");
|
|
3787
|
+
if (key && valueParts.length > 0) {
|
|
3788
|
+
let value = valueParts.join("=");
|
|
3789
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
3790
|
+
value = value.slice(1, -1);
|
|
3791
|
+
}
|
|
3792
|
+
envVars[key] = value;
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
return envVars;
|
|
3798
|
+
}
|
|
3799
|
+
async function dbMigrateCommand() {
|
|
3800
|
+
const spinner = ora9("Preparing to run migrations...").start();
|
|
3801
|
+
try {
|
|
3802
|
+
const coreDir = getCoreDir();
|
|
3803
|
+
const projectRoot = getProjectRoot();
|
|
3804
|
+
const migrationsScript = join9(coreDir, "scripts", "db", "run-migrations.mjs");
|
|
3805
|
+
if (!existsSync9(migrationsScript)) {
|
|
3806
|
+
spinner.fail("Migrations script not found");
|
|
3807
|
+
console.error(chalk15.red(`Expected script at: ${migrationsScript}`));
|
|
3808
|
+
process.exit(1);
|
|
3809
|
+
}
|
|
3810
|
+
spinner.succeed("Core package found");
|
|
3811
|
+
const projectEnv = loadProjectEnv4(projectRoot);
|
|
3812
|
+
if (!projectEnv.DATABASE_URL) {
|
|
3813
|
+
spinner.fail("DATABASE_URL not found in .env file");
|
|
3814
|
+
console.error(chalk15.red("Please configure DATABASE_URL in your .env file"));
|
|
3815
|
+
process.exit(1);
|
|
3816
|
+
}
|
|
3817
|
+
if (!projectEnv.NEXT_PUBLIC_ACTIVE_THEME) {
|
|
3818
|
+
spinner.fail("NEXT_PUBLIC_ACTIVE_THEME not found in .env file");
|
|
3819
|
+
console.error(chalk15.red("Please configure NEXT_PUBLIC_ACTIVE_THEME in your .env file"));
|
|
3820
|
+
process.exit(1);
|
|
3821
|
+
}
|
|
3822
|
+
spinner.start("Running database migrations...");
|
|
3823
|
+
const migrateProcess = spawn5("node", [migrationsScript], {
|
|
3824
|
+
cwd: projectRoot,
|
|
3825
|
+
stdio: "inherit",
|
|
3826
|
+
env: {
|
|
3827
|
+
...projectEnv,
|
|
3828
|
+
...process.env,
|
|
3829
|
+
NEXTSPARK_PROJECT_ROOT: projectRoot,
|
|
3830
|
+
NEXTSPARK_CORE_DIR: coreDir
|
|
3831
|
+
}
|
|
3832
|
+
});
|
|
3833
|
+
migrateProcess.on("error", (err) => {
|
|
3834
|
+
spinner.fail("Migration failed");
|
|
3835
|
+
console.error(chalk15.red(err.message));
|
|
3836
|
+
process.exit(1);
|
|
3837
|
+
});
|
|
3838
|
+
migrateProcess.on("close", (code) => {
|
|
3839
|
+
if (code === 0) {
|
|
3840
|
+
console.log(chalk15.green("\n\u2705 Migrations completed successfully!"));
|
|
3841
|
+
process.exit(0);
|
|
3842
|
+
} else {
|
|
3843
|
+
console.error(chalk15.red(`
|
|
3844
|
+
\u274C Migrations failed with exit code ${code}`));
|
|
3845
|
+
process.exit(code ?? 1);
|
|
3846
|
+
}
|
|
3847
|
+
});
|
|
3848
|
+
} catch (error) {
|
|
3849
|
+
spinner.fail("Migration preparation failed");
|
|
3850
|
+
if (error instanceof Error) {
|
|
3851
|
+
console.error(chalk15.red(error.message));
|
|
3852
|
+
}
|
|
3853
|
+
process.exit(1);
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
async function dbSeedCommand() {
|
|
3857
|
+
console.log(chalk15.cyan("\u2139\uFE0F Sample data is included as part of the migration process."));
|
|
3858
|
+
console.log(chalk15.cyan(" Running db:migrate to apply all migrations including sample data...\n"));
|
|
3859
|
+
await dbMigrateCommand();
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3611
3862
|
// src/cli.ts
|
|
3863
|
+
config();
|
|
3612
3864
|
var program = new Command();
|
|
3613
3865
|
program.name("nextspark").description("NextSpark CLI - Professional SaaS Boilerplate").version("0.1.0-beta.4");
|
|
3614
|
-
program.command("dev").description("Start development server with registry watcher").option("-p, --port <port>", "Port to run the dev server on", "3000").option("--no-registry", "Disable registry watcher").action(devCommand);
|
|
3866
|
+
program.command("dev").description("Start development server with registry watcher").option("-p, --port <port>", "Port to run the dev server on", process.env.PORT || "3000").option("--no-registry", "Disable registry watcher").action(devCommand);
|
|
3615
3867
|
program.command("build").description("Build for production").option("--no-registry", "Skip registry generation before build").action(buildCommand);
|
|
3616
3868
|
program.command("generate").description("Generate all registries").option("-w, --watch", "Watch for changes").action(generateCommand);
|
|
3617
3869
|
var registry = program.command("registry").description("Registry management commands");
|
|
@@ -3623,8 +3875,13 @@ program.command("init").description("Initialize NextSpark project").option("-f,
|
|
|
3623
3875
|
program.command("add:plugin <package>").description("Add a plugin to your project").option("-v, --version <version>", "Specific version to install").option("-f, --force", "Overwrite if already exists").option("--skip-postinstall", "Skip postinstall hooks").option("--no-deps", "Skip installing dependencies").option("--dry-run", "Show what would be done without making changes").action(addPluginCommand);
|
|
3624
3876
|
program.command("add:theme <package>").description("Add a theme to your project").option("-v, --version <version>", "Specific version to install").option("-f, --force", "Overwrite if already exists").option("--skip-postinstall", "Skip postinstall hooks").option("--no-deps", "Skip installing dependencies").option("--dry-run", "Show what would be done without making changes").action(addThemeCommand);
|
|
3625
3877
|
program.command("doctor").description("Run health check on NextSpark project").action(doctorCommand);
|
|
3878
|
+
var db = program.command("db").description("Database management commands");
|
|
3879
|
+
db.command("migrate").description("Run database migrations").action(dbMigrateCommand);
|
|
3880
|
+
db.command("seed").description("Seed database with sample data").action(dbSeedCommand);
|
|
3881
|
+
program.command("db:migrate").description("Run database migrations (alias)").action(dbMigrateCommand);
|
|
3882
|
+
program.command("db:seed").description("Seed database with sample data (alias)").action(dbSeedCommand);
|
|
3626
3883
|
program.showHelpAfterError();
|
|
3627
3884
|
program.configureOutput({
|
|
3628
|
-
writeErr: (str) => process.stderr.write(
|
|
3885
|
+
writeErr: (str) => process.stderr.write(chalk16.red(str))
|
|
3629
3886
|
});
|
|
3630
3887
|
program.parse();
|