@betterstart/cli 0.1.50 → 0.1.52

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
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-6JCWMKSY.js";
5
5
 
6
6
  // src/cli.ts
7
- import { Command as Command9 } from "commander";
7
+ import { Command as Command10 } from "commander";
8
8
 
9
9
  // src/commands/generate.ts
10
10
  import path30 from "path";
@@ -2539,13 +2539,18 @@ ${selectItems}
2539
2539
  return ` <div className="space-y-4">
2540
2540
  <FormLabel className="text-sm font-medium leading-none">${label}${requiredStar}</FormLabel>${hintJSX}
2541
2541
  {${name}FieldArray.fields.map((item, index) => (
2542
- <div key={item.id} className="flex items-end gap-2 rounded-lg border p-4">
2543
- <div className="flex-1 space-y-4">
2542
+ <div key={item.id} className="relative rounded-lg border p-4">
2543
+ <button
2544
+ type="button"
2545
+ onClick={() => ${name}FieldArray.remove(index)}
2546
+ className="absolute right-2 top-2 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-destructive/10 hover:text-destructive"
2547
+ >
2548
+ <Trash2 className="h-4 w-4" />
2549
+ <span className="sr-only">Remove</span>
2550
+ </button>
2551
+ <div className="space-y-4 pr-8">
2544
2552
  ${nestedFieldsJSX}
2545
2553
  </div>
2546
- <Button type="button" variant="ghost" size="sm" onClick={() => ${name}FieldArray.remove(index)}>
2547
- Remove
2548
- </Button>
2549
2554
  </div>
2550
2555
  ))}
2551
2556
  <Button
@@ -2575,10 +2580,10 @@ function generateMultiStepForm(schema, cwd, cmsDir, options) {
2575
2580
  const zodFields = buildZodFields(allFields);
2576
2581
  const defaults = buildDefaultValues(allFields);
2577
2582
  const listFields = getListFields(allFields);
2578
- const hasListFields = listFields.length > 0;
2583
+ const hasListFields2 = listFields.length > 0;
2579
2584
  const { setup: watchSetup } = buildWatchDecls(allFields);
2580
- const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2581
- const fieldArraySetup = hasListFields ? `
2585
+ const rhfImport = hasListFields2 ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2586
+ const fieldArraySetup = hasListFields2 ? `
2582
2587
  ${buildFieldArrayDecls(listFields)}
2583
2588
  ` : "";
2584
2589
  const stepsConst = buildStepsConstant(steps, schema);
@@ -2661,7 +2666,7 @@ export function ${p7.pascal}Form() {
2661
2666
  return `'use client'
2662
2667
 
2663
2668
  import { zodResolver } from '@hookform/resolvers/zod'
2664
- import { Check, ChevronLeft, ChevronRight } from 'lucide-react'
2669
+ import { Check, ChevronLeft, ChevronRight${hasListFields ? ", Trash2" : ""} } from 'lucide-react'
2665
2670
  import { parseAsInteger, parseAsArrayOf, useQueryState } from 'nuqs'
2666
2671
  import { useState } from 'react'
2667
2672
  ${p7.rhfImport}
@@ -2868,14 +2873,14 @@ function generateSingleStepForm(schema, cwd, cmsDir, options) {
2868
2873
  const zodFields = buildZodFields(fields);
2869
2874
  const defaults = buildDefaultValues(fields);
2870
2875
  const listFields = getListFields(fields);
2871
- const hasListFields = listFields.length > 0;
2876
+ const hasListFields2 = listFields.length > 0;
2872
2877
  const { setup: watchSetup } = buildWatchDecls(fields);
2873
2878
  const rawFields = schema.fields || [];
2874
2879
  const fieldJSX = renderFieldsJSX(rawFields);
2875
2880
  const submitText = schema.submitButtonText || "Submit";
2876
2881
  const successMessage = escapeJsx(schema.successMessage || "Form submitted successfully!");
2877
- const rhfImport = hasListFields ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2878
- const fieldArraySetup = hasListFields ? `
2882
+ const rhfImport = hasListFields2 ? `import { useFieldArray, useForm } from 'react-hook-form'` : `import { useForm } from 'react-hook-form'`;
2883
+ const fieldArraySetup = hasListFields2 ? `
2879
2884
  ${buildFieldArrayDecls(listFields)}
2880
2885
  ` : "";
2881
2886
  const hasRadio = fields.some((f) => f.type === "radio");
@@ -2902,9 +2907,11 @@ export function ${pascal}Form() {
2902
2907
  )
2903
2908
  }
2904
2909
  ` : "";
2910
+ const lucideImport = hasListFields2 ? `
2911
+ import { Trash2 } from 'lucide-react'` : "";
2905
2912
  const content = `'use client'
2906
2913
 
2907
- import { zodResolver } from '@hookform/resolvers/zod'
2914
+ import { zodResolver } from '@hookform/resolvers/zod'${lucideImport}
2908
2915
  import { useState } from 'react'
2909
2916
  ${rhfImport}
2910
2917
  import { z } from 'zod/v3'${queryClientImport}
@@ -15521,18 +15528,183 @@ var uninstallCommand = new Command6("uninstall").description("Remove all CMS fil
15521
15528
  p6.outro("Uninstall complete");
15522
15529
  });
15523
15530
 
15524
- // src/commands/update-deps.ts
15531
+ // src/commands/update-component.ts
15532
+ import fs45 from "fs";
15525
15533
  import path49 from "path";
15526
15534
  import * as clack2 from "@clack/prompts";
15527
15535
  import { Command as Command7 } from "commander";
15528
- var updateDepsCommand = new Command7("update-deps").description("Install or update all CMS dependencies").option("--cwd <path>", "Project root path").action(async (options) => {
15536
+ import fsExtra from "fs-extra";
15537
+ var TEMPLATE_REGISTRY = {
15538
+ // CSS
15539
+ "cms-globals": { relPath: "cms-globals.css", content: cmsGlobalsCssTemplate },
15540
+ // Layout
15541
+ "cms-providers": { relPath: "components/layout/cms-providers.tsx", content: cmsProvidersTemplate },
15542
+ "cms-nav-link": { relPath: "components/layout/cms-nav-link.tsx", content: cmsNavLinkTemplate },
15543
+ "cms-sidebar": { relPath: "components/layout/cms-sidebar.tsx", content: cmsSidebarTemplate },
15544
+ "cms-header": { relPath: "components/layout/cms-header.tsx", content: cmsHeaderTemplate },
15545
+ "cms-search": { relPath: "components/layout/cms-search.tsx", content: cmsSearchTemplate },
15546
+ // Shared
15547
+ "page-header": { relPath: "components/shared/page-header.tsx", content: pageHeaderTemplate },
15548
+ "delete-dialog": { relPath: "components/shared/delete-dialog.tsx", content: deleteDialogTemplate },
15549
+ "status-badge": { relPath: "components/shared/status-badge.tsx", content: statusBadgeTemplate },
15550
+ // Data table
15551
+ "data-table": { relPath: "components/data-table/data-table.tsx", content: dataTableTemplate },
15552
+ "data-table-pagination": { relPath: "components/data-table/data-table-pagination.tsx", content: dataTablePaginationTemplate },
15553
+ "data-table-toolbar": { relPath: "components/data-table/data-table-toolbar.tsx", content: dataTableToolbarTemplate },
15554
+ // Hooks
15555
+ "use-upload": { relPath: "hooks/use-upload.ts", content: useUploadHookTemplate },
15556
+ "use-editor-image-upload": { relPath: "hooks/use-editor-image-upload.ts", content: useEditorImageUploadHookTemplate },
15557
+ "use-local-storage": { relPath: "hooks/use-local-storage.ts", content: useLocalStorageHookTemplate },
15558
+ "use-cms-theme": { relPath: "hooks/use-cms-theme.tsx", content: useCmsThemeTemplate },
15559
+ "use-users": { relPath: "hooks/use-users.ts", content: useUsersHookTemplate },
15560
+ "use-mobile": { relPath: "hooks/use-mobile.ts", content: useMobileHookTemplate },
15561
+ // Types
15562
+ "types-index": { relPath: "types/index.ts", content: typesIndexTemplate },
15563
+ "auth-types": { relPath: "types/auth.ts", content: authTypesTemplate },
15564
+ "table-meta": { relPath: "types/table-meta.ts", content: tableMetaTypesTemplate },
15565
+ // Utils
15566
+ cn: { relPath: "utils/cn.ts", content: cnUtilTemplate },
15567
+ seo: { relPath: "utils/seo.ts", content: seoUtilTemplate },
15568
+ validation: { relPath: "utils/validation.ts", content: validationUtilTemplate },
15569
+ webhook: { relPath: "utils/webhook.ts", content: webhookUtilTemplate },
15570
+ mailchimp: { relPath: "utils/mailchimp.ts", content: mailchimpUtilTemplate },
15571
+ // Lib
15572
+ r2: { relPath: "lib/r2.ts", content: r2ClientTemplate },
15573
+ "form-settings-action": { relPath: "lib/actions/form-settings.ts", content: formSettingsActionTemplate },
15574
+ "upload-action": { relPath: "lib/actions/upload.ts", content: uploadActionTemplate },
15575
+ "users-action": { relPath: "lib/actions/users.ts", content: usersActionTemplate },
15576
+ // Markdown
15577
+ "markdown-render": { relPath: "lib/markdown/render.ts", content: markdownRenderTemplate },
15578
+ "markdown-format": { relPath: "lib/markdown/format.ts", content: markdownFormatTemplate },
15579
+ "markdown-cached": { relPath: "lib/markdown/cached.ts", content: markdownCachedTemplate }
15580
+ };
15581
+ function findCliRoot2() {
15582
+ let dir = new URL(".", import.meta.url).pathname;
15583
+ for (let i = 0; i < 5; i++) {
15584
+ const pkgPath = path49.join(dir, "package.json");
15585
+ if (fs45.existsSync(pkgPath)) {
15586
+ try {
15587
+ const pkg = JSON.parse(fs45.readFileSync(pkgPath, "utf-8"));
15588
+ if (pkg.name === "@betterstart/cli") {
15589
+ return dir;
15590
+ }
15591
+ } catch {
15592
+ }
15593
+ }
15594
+ dir = path49.dirname(dir);
15595
+ }
15596
+ return path49.resolve(new URL(".", import.meta.url).pathname, "..", "..");
15597
+ }
15598
+ function getStaticUiComponents() {
15599
+ const cliRoot = findCliRoot2();
15600
+ const uiDir = path49.join(cliRoot, "templates", "ui");
15601
+ if (!fs45.existsSync(uiDir)) return [];
15602
+ return fs45.readdirSync(uiDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => f.replace(/\.(tsx|ts)$/, ""));
15603
+ }
15604
+ function getAllComponentNames() {
15605
+ const staticUi = getStaticUiComponents();
15606
+ const templateKeys = Object.keys(TEMPLATE_REGISTRY);
15607
+ return [.../* @__PURE__ */ new Set([...staticUi, ...templateKeys, "tiptap"])].sort();
15608
+ }
15609
+ var updateComponentCommand = new Command7("update-component").description("Update individual CMS components from the latest CLI templates").argument("[components...]", "Component names to update (e.g., media-upload-field button)").option("--list", "List all available components").option("--all", "Update all components").option("--cwd <path>", "Project root path").action(async (components, options) => {
15529
15610
  const cwd = options.cwd ? path49.resolve(options.cwd) : process.cwd();
15530
- clack2.intro("BetterStart Update Dependencies");
15611
+ if (options.list) {
15612
+ const all = getAllComponentNames();
15613
+ clack2.intro("Available components");
15614
+ const uiComponents = getStaticUiComponents();
15615
+ const templateKeys = Object.keys(TEMPLATE_REGISTRY).sort();
15616
+ console.log();
15617
+ console.log(` UI Components (${uiComponents.length})`);
15618
+ console.log(` ${"\u2500".repeat(50)}`);
15619
+ console.log(` ${"Name".padEnd(28)} ${"Path"}`);
15620
+ console.log(` ${"\u2500".repeat(50)}`);
15621
+ for (const name of uiComponents) {
15622
+ console.log(` ${name.padEnd(28)} components/ui/${name}.tsx`);
15623
+ }
15624
+ console.log();
15625
+ console.log(` Template Components (${templateKeys.length})`);
15626
+ console.log(` ${"\u2500".repeat(56)}`);
15627
+ console.log(` ${"Name".padEnd(28)} ${"Path"}`);
15628
+ console.log(` ${"\u2500".repeat(56)}`);
15629
+ for (const name of templateKeys) {
15630
+ console.log(` ${name.padEnd(28)} ${TEMPLATE_REGISTRY[name].relPath}`);
15631
+ }
15632
+ console.log();
15633
+ console.log(` Special`);
15634
+ console.log(` ${"\u2500".repeat(56)}`);
15635
+ console.log(` ${"tiptap".padEnd(28)} components/ui/tiptap/ (all files)`);
15636
+ console.log();
15637
+ clack2.outro(`${all.length} components available`);
15638
+ return;
15639
+ }
15640
+ if (!options.all && components.length === 0) {
15641
+ clack2.log.error("Provide component names or use --all. Run with --list to see available components.");
15642
+ process.exit(1);
15643
+ }
15644
+ const config = await resolveConfig(cwd);
15645
+ const cms = path49.resolve(cwd, config.paths.cms);
15646
+ if (!fs45.existsSync(cms)) {
15647
+ clack2.cancel(`CMS directory not found at ${config.paths.cms}. Run 'betterstart init' first.`);
15648
+ process.exit(1);
15649
+ }
15650
+ clack2.intro("BetterStart Update Components");
15651
+ const toUpdate = options.all ? getAllComponentNames() : components;
15652
+ const cliRoot = findCliRoot2();
15653
+ const uiDir = path49.join(cliRoot, "templates", "ui");
15654
+ let updated = 0;
15655
+ let skipped = 0;
15656
+ for (const name of toUpdate) {
15657
+ if (TEMPLATE_REGISTRY[name]) {
15658
+ const entry = TEMPLATE_REGISTRY[name];
15659
+ const destPath = path49.join(cms, entry.relPath);
15660
+ fsExtra.ensureDirSync(path49.dirname(destPath));
15661
+ fs45.writeFileSync(destPath, entry.content(), "utf-8");
15662
+ clack2.log.success(`Updated ${entry.relPath}`);
15663
+ updated++;
15664
+ continue;
15665
+ }
15666
+ const uiFile = fs45.readdirSync(uiDir).find(
15667
+ (f) => f.replace(/\.(tsx|ts)$/, "") === name
15668
+ );
15669
+ if (uiFile) {
15670
+ const destPath = path49.join(cms, "components", "ui", uiFile);
15671
+ fsExtra.ensureDirSync(path49.dirname(destPath));
15672
+ fs45.copyFileSync(path49.join(uiDir, uiFile), destPath);
15673
+ clack2.log.success(`Updated components/ui/${uiFile}`);
15674
+ updated++;
15675
+ continue;
15676
+ }
15677
+ if (name === "tiptap") {
15678
+ const srcDir = path49.join(cliRoot, "templates", "tiptap");
15679
+ const destDir = path49.join(cms, "components", "ui", "tiptap");
15680
+ if (fs45.existsSync(srcDir)) {
15681
+ fsExtra.copySync(srcDir, destDir, { overwrite: true });
15682
+ clack2.log.success("Updated components/ui/tiptap/ (all files)");
15683
+ updated++;
15684
+ } else {
15685
+ clack2.log.warning("tiptap templates not found");
15686
+ skipped++;
15687
+ }
15688
+ continue;
15689
+ }
15690
+ clack2.log.warning(`Unknown component: ${name}`);
15691
+ skipped++;
15692
+ }
15693
+ clack2.outro(`Updated ${updated} component${updated !== 1 ? "s" : ""}${skipped > 0 ? `, ${skipped} skipped` : ""}`);
15694
+ });
15695
+
15696
+ // src/commands/update-deps.ts
15697
+ import path50 from "path";
15698
+ import * as clack3 from "@clack/prompts";
15699
+ import { Command as Command8 } from "commander";
15700
+ var updateDepsCommand = new Command8("update-deps").description("Install or update all CMS dependencies").option("--cwd <path>", "Project root path").action(async (options) => {
15701
+ const cwd = options.cwd ? path50.resolve(options.cwd) : process.cwd();
15702
+ clack3.intro("BetterStart Update Dependencies");
15531
15703
  const pm = detectPackageManager(cwd);
15532
- clack2.log.info(`Package manager: ${pm}`);
15704
+ clack3.log.info(`Package manager: ${pm}`);
15533
15705
  const config = await resolveConfig(cwd);
15534
15706
  const includeEmail = config.features?.email ?? true;
15535
- const s = clack2.spinner();
15707
+ const s = clack3.spinner();
15536
15708
  s.start("Installing dependencies...");
15537
15709
  const result = await installDependenciesAsync({
15538
15710
  cwd,
@@ -15544,34 +15716,34 @@ var updateDepsCommand = new Command7("update-deps").description("Install or upda
15544
15716
  s.stop(`Installed ${result.coreDeps.length} deps + ${result.devDeps.length} dev deps`);
15545
15717
  } else {
15546
15718
  s.stop("Dependency install failed");
15547
- clack2.log.error(result.error ?? "Unknown error");
15719
+ clack3.log.error(result.error ?? "Unknown error");
15548
15720
  process.exit(1);
15549
15721
  }
15550
- clack2.outro("Dependencies updated");
15722
+ clack3.outro("Dependencies updated");
15551
15723
  });
15552
15724
 
15553
15725
  // src/commands/update-styles.ts
15554
- import fs45 from "fs";
15555
- import path50 from "path";
15556
- import * as clack3 from "@clack/prompts";
15557
- import { Command as Command8 } from "commander";
15558
- var updateStylesCommand = new Command8("update-styles").description("Replace cms-globals.css with the latest version from the CLI").option("--cwd <path>", "Project root path").action(async (options) => {
15559
- const cwd = options.cwd ? path50.resolve(options.cwd) : process.cwd();
15560
- clack3.intro("BetterStart Update Styles");
15726
+ import fs46 from "fs";
15727
+ import path51 from "path";
15728
+ import * as clack4 from "@clack/prompts";
15729
+ import { Command as Command9 } from "commander";
15730
+ var updateStylesCommand = new Command9("update-styles").description("Replace cms-globals.css with the latest version from the CLI").option("--cwd <path>", "Project root path").action(async (options) => {
15731
+ const cwd = options.cwd ? path51.resolve(options.cwd) : process.cwd();
15732
+ clack4.intro("BetterStart Update Styles");
15561
15733
  const config = await resolveConfig(cwd);
15562
15734
  const cmsDir = config.paths?.cms ?? "./cms";
15563
- const targetPath = path50.join(cwd, cmsDir, "cms-globals.css");
15564
- if (!fs45.existsSync(targetPath)) {
15565
- clack3.cancel(`cms-globals.css not found at ${path50.relative(cwd, targetPath)}`);
15735
+ const targetPath = path51.join(cwd, cmsDir, "cms-globals.css");
15736
+ if (!fs46.existsSync(targetPath)) {
15737
+ clack4.cancel(`cms-globals.css not found at ${path51.relative(cwd, targetPath)}`);
15566
15738
  process.exit(1);
15567
15739
  }
15568
- fs45.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15569
- clack3.log.success(`Updated ${path50.relative(cwd, targetPath)}`);
15570
- clack3.outro("Styles updated");
15740
+ fs46.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
15741
+ clack4.log.success(`Updated ${path51.relative(cwd, targetPath)}`);
15742
+ clack4.outro("Styles updated");
15571
15743
  });
15572
15744
 
15573
15745
  // src/cli.ts
15574
- var program = new Command9();
15746
+ var program = new Command10();
15575
15747
  program.name("betterstart").description("Scaffold a full-featured CMS into any Next.js 16 application").version("0.1.0");
15576
15748
  program.addCommand(initCommand);
15577
15749
  program.addCommand(generateCommand);
@@ -15579,6 +15751,7 @@ program.addCommand(removeCommand);
15579
15751
  program.addCommand(seedCommand);
15580
15752
  program.addCommand(setupR2Command);
15581
15753
  program.addCommand(uninstallCommand);
15754
+ program.addCommand(updateComponentCommand);
15582
15755
  program.addCommand(updateDepsCommand);
15583
15756
  program.addCommand(updateStylesCommand);
15584
15757
  program.parse();