@betterstart/cli 0.1.26 → 0.1.27

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 CHANGED
@@ -7640,9 +7640,6 @@ function detectPackageManager(cwd) {
7640
7640
  }
7641
7641
  return "npm";
7642
7642
  }
7643
- function installCommand(pm) {
7644
- return pm === "yarn" ? "yarn" : `${pm} install`;
7645
- }
7646
7643
  function runCommand(pm, script) {
7647
7644
  switch (pm) {
7648
7645
  case "pnpm":
@@ -11678,7 +11675,6 @@ var CORE_DEPS = [
11678
11675
  "input-otp",
11679
11676
  "react-resizable-panels",
11680
11677
  "recharts",
11681
- "shadcn",
11682
11678
  "tw-animate-css",
11683
11679
  "usehooks-ts",
11684
11680
  "vaul"
@@ -12021,6 +12017,7 @@ import { authClient } from '@cms/auth/client'
12021
12017
  import { Button } from '@cms/components/ui/button'
12022
12018
  import { Input } from '@cms/components/ui/input'
12023
12019
  import { Label } from '@cms/components/ui/label'
12020
+ import { LoaderCircle } from 'lucide-react'
12024
12021
  import { useRouter } from 'next/navigation'
12025
12022
  import * as React from 'react'
12026
12023
 
@@ -12093,6 +12090,7 @@ export function LoginForm() {
12093
12090
  </div>
12094
12091
 
12095
12092
  <Button type="submit" className="w-full" size="lg" disabled={isLoading}>
12093
+ {isLoading && <LoaderCircle className="animate-spin" />}
12096
12094
  {isLoading ? 'Signing in...' : 'Sign In'}
12097
12095
  </Button>
12098
12096
  </form>
@@ -13513,9 +13511,32 @@ const auth = betterAuth({
13513
13511
  const EMAIL = process.env.SEED_EMAIL!
13514
13512
  const PASSWORD = process.env.SEED_PASSWORD!
13515
13513
  const NAME = process.env.SEED_NAME || 'Admin'
13514
+ const OVERWRITE = process.env.SEED_OVERWRITE === 'true'
13516
13515
 
13517
13516
  async function main() {
13518
- console.log('\\n Creating admin user...')
13517
+ // Check if user already exists
13518
+ const existing = await db
13519
+ .select({ id: schema.user.id, name: schema.user.name })
13520
+ .from(schema.user)
13521
+ .where(eq(schema.user.email, EMAIL))
13522
+ .then((rows: { id: string; name: string }[]) => rows[0])
13523
+
13524
+ if (existing && !OVERWRITE) {
13525
+ // Exit code 2 signals "user exists" to the CLI
13526
+ console.log(\`EXISTING_USER:\${existing.name}\`)
13527
+ process.exit(2)
13528
+ }
13529
+
13530
+ if (existing && OVERWRITE) {
13531
+ console.log('\\n Replacing existing admin user...')
13532
+ // Remove existing account + session rows first (foreign key refs)
13533
+ await db.delete(schema.session).where(eq(schema.session.userId, existing.id))
13534
+ await db.delete(schema.account).where(eq(schema.account.userId, existing.id))
13535
+ await db.delete(schema.user).where(eq(schema.user.id, existing.id))
13536
+ } else {
13537
+ console.log('\\n Creating admin user...')
13538
+ }
13539
+
13519
13540
  console.log(\` Email: \${EMAIL}\\n\`)
13520
13541
 
13521
13542
  const result = await auth.api.signUpEmail({
@@ -13532,7 +13553,7 @@ async function main() {
13532
13553
  .set({ role: 'admin' })
13533
13554
  .where(eq(schema.user.id, result.user.id))
13534
13555
 
13535
- console.log(\` Admin user created: \${EMAIL}\`)
13556
+ console.log(\` Admin user \${existing ? 'replaced' : 'created'}: \${EMAIL}\`)
13536
13557
  console.log(' Role: admin\\n')
13537
13558
  process.exit(0)
13538
13559
  }
@@ -13590,22 +13611,52 @@ var seedCommand = new Command2("seed").description("Create the initial admin use
13590
13611
  fs31.mkdirSync(scriptsDir, { recursive: true });
13591
13612
  }
13592
13613
  fs31.writeFileSync(seedPath, buildSeedScript(), "utf-8");
13593
- const spinner4 = clack.spinner();
13594
- spinner4.start("Creating admin user...");
13595
- try {
13596
- const { execFileSync: execFileSync5 } = await import("child_process");
13597
- const tsxBin = path36.join(cwd, "node_modules", ".bin", "tsx");
13598
- execFileSync5(tsxBin, [seedPath], {
13614
+ const { execFile } = await import("child_process");
13615
+ const tsxBin = path36.join(cwd, "node_modules", ".bin", "tsx");
13616
+ const runSeed2 = (overwrite) => new Promise((resolve, reject) => {
13617
+ execFile(tsxBin, [seedPath], {
13599
13618
  cwd,
13600
- stdio: "pipe",
13601
13619
  env: {
13602
13620
  ...process.env,
13603
13621
  SEED_EMAIL: email,
13604
13622
  SEED_PASSWORD: password3,
13605
- SEED_NAME: name || "Admin"
13623
+ SEED_NAME: name || "Admin",
13624
+ ...overwrite ? { SEED_OVERWRITE: "true" } : {}
13625
+ }
13626
+ }, (err, stdout, stderr) => {
13627
+ if (err && "code" in err && err.code === 2) {
13628
+ resolve({ code: 2, stdout });
13629
+ } else if (err) {
13630
+ reject(new Error(stderr || err.message));
13631
+ } else {
13632
+ resolve({ code: 0, stdout });
13606
13633
  }
13607
13634
  });
13608
- spinner4.stop("Admin user created");
13635
+ });
13636
+ const spinner4 = clack.spinner();
13637
+ spinner4.start("Creating admin user...");
13638
+ try {
13639
+ const result = await runSeed2(false);
13640
+ if (result.code === 2) {
13641
+ const existingName = result.stdout.split("\n").find((l) => l.startsWith("EXISTING_USER:"))?.replace("EXISTING_USER:", "")?.trim() || "unknown";
13642
+ spinner4.stop(`Account already exists for ${email}`);
13643
+ const overwrite = await clack.confirm({
13644
+ message: `An admin account (${existingName}) already exists with this email. Replace it?`
13645
+ });
13646
+ if (clack.isCancel(overwrite) || !overwrite) {
13647
+ clack.cancel("Seed cancelled.");
13648
+ try {
13649
+ fs31.unlinkSync(seedPath);
13650
+ } catch {
13651
+ }
13652
+ process.exit(0);
13653
+ }
13654
+ spinner4.start("Replacing admin user...");
13655
+ await runSeed2(true);
13656
+ spinner4.stop("Admin user replaced");
13657
+ } else {
13658
+ spinner4.stop("Admin user created");
13659
+ }
13609
13660
  } catch (err) {
13610
13661
  spinner4.stop("Failed to create admin user");
13611
13662
  const errMsg = err instanceof Error ? err.message : String(err);
@@ -14481,44 +14532,6 @@ function findNextNonEmptyLine(lines, startIndex) {
14481
14532
  }
14482
14533
  return null;
14483
14534
  }
14484
- function cleanPackageJsonDeps(pkgPath, allDeps, allDevDeps) {
14485
- if (!fs34.existsSync(pkgPath)) return { removed: [], removedDev: [] };
14486
- const content = fs34.readFileSync(pkgPath, "utf-8");
14487
- let pkg;
14488
- try {
14489
- pkg = JSON.parse(content);
14490
- } catch {
14491
- return { removed: [], removedDev: [] };
14492
- }
14493
- const deps = pkg.dependencies ?? {};
14494
- const devDeps = pkg.devDependencies ?? {};
14495
- const depNames = new Set(allDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@")));
14496
- const devDepNames = new Set(
14497
- allDevDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@"))
14498
- );
14499
- const removed = [];
14500
- for (const name of Object.keys(deps)) {
14501
- if (depNames.has(name)) {
14502
- delete deps[name];
14503
- removed.push(name);
14504
- }
14505
- }
14506
- const removedDev = [];
14507
- for (const name of Object.keys(devDeps)) {
14508
- if (devDepNames.has(name)) {
14509
- delete devDeps[name];
14510
- removedDev.push(name);
14511
- }
14512
- }
14513
- if (removed.length === 0 && removedDev.length === 0) {
14514
- return { removed: [], removedDev: [] };
14515
- }
14516
- pkg.dependencies = deps;
14517
- pkg.devDependencies = devDeps;
14518
- fs34.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
14519
- `, "utf-8");
14520
- return { removed, removedDev };
14521
- }
14522
14535
 
14523
14536
  // src/commands/uninstall.ts
14524
14537
  function findMainCss2(cwd) {
@@ -14637,32 +14650,6 @@ function buildUninstallPlan(cwd) {
14637
14650
  });
14638
14651
  }
14639
14652
  }
14640
- const pkgPath = path40.join(cwd, "package.json");
14641
- if (fs35.existsSync(pkgPath)) {
14642
- const allCoreDeps = [...CORE_DEPS, ...EMAIL_DEPS];
14643
- const allDevDeps = [...DEV_DEPS, ...BIOME_DEV_DEPS];
14644
- const coreNames = new Set(
14645
- allCoreDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@"))
14646
- );
14647
- const devNames = new Set(
14648
- allDevDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@"))
14649
- );
14650
- const pkgContent = JSON.parse(fs35.readFileSync(pkgPath, "utf-8"));
14651
- const deps = Object.keys(pkgContent.dependencies ?? {}).filter((n) => coreNames.has(n));
14652
- const devDeps = Object.keys(pkgContent.devDependencies ?? {}).filter((n) => devNames.has(n));
14653
- if (deps.length > 0 || devDeps.length > 0) {
14654
- const items = [];
14655
- if (deps.length > 0) items.push(`${deps.length} dependencies`);
14656
- if (devDeps.length > 0) items.push(`${devDeps.length} devDependencies`);
14657
- steps.push({
14658
- label: "package.json dependencies",
14659
- items,
14660
- execute() {
14661
- cleanPackageJsonDeps(pkgPath, allCoreDeps, allDevDeps);
14662
- }
14663
- });
14664
- }
14665
- }
14666
14653
  return steps;
14667
14654
  }
14668
14655
  var uninstallCommand = new Command6("uninstall").description("Remove all CMS files and undo modifications made by betterstart init").option("-f, --force", "Skip all confirmation prompts", false).option("--cwd <path>", "Project root path").action(async (options) => {
@@ -14674,30 +14661,26 @@ var uninstallCommand = new Command6("uninstall").description("Remove all CMS fil
14674
14661
  p5.outro("Done");
14675
14662
  return;
14676
14663
  }
14677
- p5.log.warn(
14678
- `Found ${steps.length} ${steps.length === 1 ? "area" : "areas"} to clean up:`
14679
- );
14680
- let completedCount = 0;
14664
+ p5.log.warn("The following will be removed/modified:\n");
14681
14665
  for (const step of steps) {
14682
- p5.log.message("");
14683
- p5.log.step(pc3.bold(step.label));
14666
+ p5.log.message(` ${pc3.bold(step.label)}`);
14684
14667
  for (const item of step.items) {
14685
- p5.log.message(` ${pc3.dim("\u2022")} ${item}`);
14668
+ p5.log.message(` ${pc3.red("\xD7")} ${pc3.dim(item)}`);
14686
14669
  }
14687
- if (!options.force) {
14688
- const confirmed = await p5.confirm({
14689
- message: `Remove ${step.label}?`,
14690
- initialValue: true
14691
- });
14692
- if (p5.isCancel(confirmed)) {
14693
- p5.cancel("Uninstall cancelled.");
14694
- process.exit(0);
14695
- }
14696
- if (!confirmed) {
14697
- p5.log.info(pc3.dim(`Skipped: ${step.label}`));
14698
- continue;
14699
- }
14670
+ p5.log.message("");
14671
+ }
14672
+ if (!options.force) {
14673
+ const confirmed = await p5.confirm({
14674
+ message: `Proceed with uninstall? (${steps.length} ${steps.length === 1 ? "area" : "areas"})`,
14675
+ initialValue: false
14676
+ });
14677
+ if (p5.isCancel(confirmed) || !confirmed) {
14678
+ p5.cancel("Uninstall cancelled.");
14679
+ process.exit(0);
14700
14680
  }
14681
+ }
14682
+ let completedCount = 0;
14683
+ for (const step of steps) {
14701
14684
  step.execute();
14702
14685
  completedCount++;
14703
14686
  p5.log.success(`Removed: ${step.label}`);
@@ -14706,13 +14689,8 @@ var uninstallCommand = new Command6("uninstall").description("Remove all CMS fil
14706
14689
  if (completedCount === 0) {
14707
14690
  p5.log.info("No changes were made.");
14708
14691
  } else {
14709
- const pm = detectPackageManager(cwd);
14710
14692
  p5.note(
14711
- [
14712
- `Run ${pc3.cyan(installCommand(pm))} to clean up node_modules.`,
14713
- "",
14714
- pc3.dim("Database tables were NOT dropped \u2014 drop them manually if needed.")
14715
- ].join("\n"),
14693
+ pc3.dim("Database tables were NOT dropped \u2014 drop them manually if needed."),
14716
14694
  "Next steps"
14717
14695
  );
14718
14696
  }