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