@betterstart/cli 0.1.58 → 0.1.60
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 +11 -6
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/generate.ts","../src/config/resolver.ts","../src/core/schema-reader.ts","../src/core/field-helpers/walking.ts","../src/core/field-helpers/flattening.ts","../src/core/field-helpers/form-fields.ts","../src/generators/email-template.ts","../src/utils/string.ts","../src/generators/form-admin/orchestrator.ts","../src/generators/form-admin/admin-columns.ts","../src/generators/form-admin/admin-page.ts","../src/generators/form-admin/admin-page-content.ts","../src/generators/form-admin/admin-settings-page.ts","../src/generators/form-admin/admin-table.ts","../src/generators/form-admin/admin-view-page.ts","../src/generators/form-navigation.ts","../src/generators/form-pipeline/form-actions.ts","../src/generators/form-pipeline/form-component-multistep.ts","../src/generators/form-pipeline/form-component-shared.ts","../src/core/type-mappers/drizzle.ts","../src/core/type-mappers/zod.ts","../src/core/type-mappers/typescript.ts","../src/generators/form-pipeline/form-component-single.ts","../src/generators/form-pipeline/form-component.ts","../src/generators/form-pipeline/form-database.ts","../src/generators/form-pipeline/form-hook.ts","../src/generators/form-pipeline/pipeline.ts","../src/generators/actions/entity-actions.ts","../src/generators/actions/action-helpers.ts","../src/generators/actions/single-actions.ts","../src/generators/cache.ts","../src/generators/columns/generate-columns.ts","../src/generators/columns/column-defs.ts","../src/generators/columns/column-actions.ts","../src/generators/columns/custom-cell.ts","../src/generators/create-page.ts","../src/generators/database.ts","../src/generators/edit-page.ts","../src/generators/form/form-entity.ts","../src/generators/form/zod-schema.ts","../src/generators/form/field-jsx-nested.ts","../src/generators/form/field-jsx.ts","../src/generators/form/form-shared.ts","../src/generators/form/form-single.ts","../src/generators/hook.ts","../src/generators/navigation.ts","../src/generators/page.ts","../src/generators/page-content.ts","../src/generators/single-page.ts","../src/generators/table.ts","../src/generators/index.ts","../src/generators/post-generate.ts","../src/utils/package-manager.ts","../src/commands/init.ts","../src/init/prompts/database.ts","../src/init/prompts/features.ts","../src/init/prompts/project.ts","../src/init/scaffolders/api-routes.ts","../src/utils/fs.ts","../src/init/templates/api/auth-route.ts","../src/init/templates/api/upload-route.ts","../src/init/scaffolders/auth.ts","../src/init/templates/lib/auth/auth.ts","../src/init/templates/lib/auth/auth-client.ts","../src/init/templates/lib/auth/middleware.ts","../src/init/scaffolders/base.ts","../src/init/scaffolders/biome.ts","../src/init/scaffolders/components.ts","../src/utils/detect.ts","../src/init/templates/components/cms-globals.ts","../src/init/templates/components/data-table/data-table.ts","../src/init/templates/components/data-table/data-table-pagination.ts","../src/init/templates/components/data-table/data-table-toolbar.ts","../src/init/templates/components/layout/cms-header.ts","../src/init/templates/components/layout/cms-nav-link.ts","../src/init/templates/components/layout/cms-providers.ts","../src/init/templates/components/layout/cms-search.ts","../src/init/templates/components/layout/cms-sidebar.ts","../src/init/templates/components/shared/delete-dialog.ts","../src/init/templates/components/shared/page-header.ts","../src/init/templates/components/shared/status-badge.ts","../src/init/templates/data/cms.ts","../src/init/templates/data/navigation.ts","../src/init/templates/hooks/use-cms-theme.ts","../src/init/templates/hooks/use-editor-image-upload.ts","../src/init/templates/hooks/use-local-storage.ts","../src/init/templates/hooks/use-mobile.ts","../src/init/templates/hooks/use-upload.ts","../src/init/templates/hooks/use-users.ts","../src/init/templates/lib/actions/form-settings.ts","../src/init/templates/lib/actions/upload.ts","../src/init/templates/lib/actions/users.ts","../src/init/templates/lib/markdown/cached.ts","../src/init/templates/lib/markdown/format.ts","../src/init/templates/lib/markdown/render.ts","../src/init/templates/lib/r2.ts","../src/init/templates/types/auth.ts","../src/init/templates/types/index.ts","../src/init/templates/types/table-meta.ts","../src/init/templates/utils/cn.ts","../src/init/templates/utils/seo.ts","../src/init/templates/utils/validation.ts","../src/init/templates/utils/webhook.ts","../src/init/templates/utils/mailchimp.ts","../src/init/scaffolders/database.ts","../src/init/templates/db/client.ts","../src/init/templates/db/schema.ts","../src/init/scaffolders/dependencies.ts","../src/init/scaffolders/env.ts","../src/utils/env.ts","../src/init/scaffolders/layout.ts","../src/init/templates/pages/authenticated-layout.ts","../src/init/templates/pages/cms-layout.ts","../src/init/templates/pages/dashboard-page.ts","../src/init/templates/pages/login-page.ts","../src/init/templates/pages/users/create-user-dialog.ts","../src/init/templates/pages/users/edit-role-dialog.ts","../src/init/templates/pages/users/users-columns.ts","../src/init/templates/pages/users/users-page.ts","../src/init/templates/pages/users/users-table.ts","../src/init/scaffolders/preset.ts","../src/init/templates/presets/blog-categories.ts","../src/init/templates/presets/blog-posts.ts","../src/init/templates/presets/default-settings.ts","../src/init/templates/presets/full-contact.ts","../src/init/templates/presets/full-navigation.ts","../src/init/scaffolders/tailwind.ts","../src/init/scaffolders/tsconfig.ts","../src/commands/seed.ts","../src/commands/remove.ts","../src/commands/setup-r2.ts","../src/commands/uninstall.ts","../src/commands/uninstall-cleaners.ts","../src/commands/update-component.ts","../src/commands/update-deps.ts","../src/commands/update-styles.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { generateCommand } from './commands/generate.js'\nimport { initCommand } from './commands/init.js'\nimport { removeCommand } from './commands/remove.js'\nimport { seedCommand } from './commands/seed.js'\nimport { setupR2Command } from './commands/setup-r2.js'\nimport { uninstallCommand } from './commands/uninstall.js'\nimport { updateComponentCommand } from './commands/update-component.js'\nimport { updateDepsCommand } from './commands/update-deps.js'\nimport { updateStylesCommand } from './commands/update-styles.js'\n\nconst program = new Command()\n\nprogram\n .name('betterstart')\n .description('Scaffold a full-featured CMS into any Next.js 16 application')\n .version('0.1.0')\n\nprogram.addCommand(initCommand)\nprogram.addCommand(generateCommand)\nprogram.addCommand(removeCommand)\nprogram.addCommand(seedCommand)\nprogram.addCommand(setupR2Command)\nprogram.addCommand(uninstallCommand)\nprogram.addCommand(updateComponentCommand)\nprogram.addCommand(updateDepsCommand)\nprogram.addCommand(updateStylesCommand)\n\nprogram.parse()\n","/**\n * generate command — read schema, detect type, run pipeline\n */\n\nimport path from 'node:path'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\nimport type { LoadedSchema } from '../core/schema-reader.js'\nimport { loadSchema, SchemaNotFoundError, validateLoadedSchema } from '../core/schema-reader.js'\nimport { runFormPipeline } from '../generators/form-pipeline/index.js'\nimport { runEntityPipeline, runSinglePipeline } from '../generators/index.js'\nimport { runPostGenerate } from '../generators/post-generate.js'\n\nexport const generateCommand = new Command('generate')\n .alias('g')\n .description('Generate entity or form from a JSON schema')\n .argument('<schema>', 'Schema name (e.g. posts, categories, contact)')\n .option('-f, --force', 'Overwrite existing generated files', false)\n .option('--skip-migration', 'Skip running db:push after generation', false)\n .option('--cwd <path>', 'Project root path')\n .action(\n async (\n schemaName: string,\n options: { force: boolean; skipMigration: boolean; cwd?: string }\n ) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n console.log('\\n BetterStart Generator\\n')\n\n // Load config\n let config: BetterstartConfig\n try {\n config = await resolveConfig(cwd)\n } catch (err) {\n console.error(` Error loading config: ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n }\n\n const schemasDir = path.join(cwd, config.paths?.schemas ?? './cms/schemas')\n console.log(` Project root: ${cwd}`)\n console.log(` Loading schema: ${schemaName}.json\\n`)\n\n // Load schema\n let loaded: LoadedSchema\n try {\n loaded = loadSchema(schemasDir, schemaName)\n } catch (err) {\n if (err instanceof SchemaNotFoundError) {\n console.error(` ${err.message}`)\n console.error(\n `\\n Create a schema file at: ${path.join(schemasDir, `${schemaName}.json`)}`\n )\n } else {\n console.error(\n ` Error loading schema: ${err instanceof Error ? err.message : String(err)}`\n )\n }\n process.exit(1)\n }\n\n // Validate schema\n const validationErrors = validateLoadedSchema(loaded)\n if (validationErrors.length > 0) {\n console.error(' Schema validation failed:\\n')\n for (const error of validationErrors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n console.log(` Schema validated (type: ${loaded.type})\\n`)\n\n // Route to correct pipeline\n if (loaded.type === 'form') {\n console.log(' Generating form files...\\n')\n\n const result = runFormPipeline(loaded.schema, cwd, config, {\n force: options.force,\n skipMigration: options.skipMigration\n })\n\n if (!result.success) {\n console.error('\\n Form generation completed with errors:\\n')\n for (const error of result.errors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n\n console.log('\\n Form generation complete!\\n')\n console.log(` ${result.files.length} files generated:`)\n for (const file of result.files) {\n console.log(` - ${file}`)\n }\n\n runPostGenerate(cwd, schemaName, {\n skipMigration: options.skipMigration\n })\n console.log('')\n return\n }\n\n // Single pipeline\n if (loaded.type === 'single') {\n console.log(' Generating single schema files...\\n')\n\n const result = runSinglePipeline(loaded.schema, cwd, config, {\n force: options.force,\n skipMigration: options.skipMigration\n })\n\n if (!result.success) {\n console.error('\\n Single generation completed with errors:\\n')\n for (const error of result.errors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n\n console.log('\\n Single generation complete!\\n')\n console.log(` ${result.files.length} files generated:`)\n for (const file of result.files) {\n console.log(` - ${file}`)\n }\n\n runPostGenerate(cwd, schemaName, {\n skipMigration: options.skipMigration\n })\n console.log('')\n return\n }\n\n // Entity pipeline\n console.log(' Generating files...\\n')\n\n const result = runEntityPipeline(loaded.schema, cwd, config, {\n force: options.force,\n skipMigration: options.skipMigration\n })\n\n if (!result.success) {\n console.error('\\n Generation completed with errors:\\n')\n for (const error of result.errors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n\n // Summary\n console.log('\\n Generation complete!\\n')\n console.log(` ${result.files.length} files generated:`)\n for (const file of result.files) {\n console.log(` - ${file}`)\n }\n\n // Post-generation: db:push + lint:fix\n runPostGenerate(cwd, schemaName, {\n skipMigration: options.skipMigration\n })\n console.log('')\n }\n )\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { BetterstartConfig } from './types.js'\n\nconst CONFIG_FILE_NAME = 'cms.config.ts'\n\nexport function getDefaultConfig(srcDir: boolean): BetterstartConfig {\n const appBase = srcDir ? './src/app' : './app'\n return {\n srcDir,\n paths: {\n cms: './cms',\n schemas: './cms/schemas',\n pages: `${appBase}/(cms)/cms/(authenticated)`,\n login: `${appBase}/(cms)/cms/login`,\n api: `${appBase}/(cms)/api/cms`\n },\n database: {\n provider: 'neon',\n migrationsDir: './cms/db/migrations'\n },\n features: {\n email: true\n },\n linter: 'biome',\n generated: {\n entities: [],\n singles: [],\n forms: []\n }\n }\n}\n\nexport function findConfigFile(cwd: string): string | undefined {\n const filePath = path.join(cwd, CONFIG_FILE_NAME)\n if (fs.existsSync(filePath)) {\n return filePath\n }\n return undefined\n}\n\nexport async function loadConfigFile(configPath: string): Promise<BetterstartConfig> {\n const { createJiti } = await import('jiti')\n\n const alias: Record<string, string> = {}\n try {\n alias['@betterstart/cli'] = fileURLToPath(import.meta.resolve('@betterstart/cli'))\n } catch {\n // Not critical — config may not import from us\n }\n\n const jiti = createJiti(import.meta.url, { alias })\n const mod = await jiti.import(configPath)\n return ((mod as Record<string, unknown>).default || mod) as BetterstartConfig\n}\n\nexport async function resolveConfig(cwd?: string): Promise<BetterstartConfig> {\n const workingDir = cwd ?? process.cwd()\n const configPath = findConfigFile(workingDir)\n\n if (!configPath) {\n const hasSrc = fs.existsSync(path.join(workingDir, 'src'))\n return getDefaultConfig(hasSrc)\n }\n\n return loadConfigFile(configPath)\n}\n","/**\n * Schema reader: load + validate JSON schemas from cms/schemas/\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { FormSchema, Schema } from '../types.js'\nimport { flattenFields } from './field-helpers/index.js'\n\n// ============================================================================\n// Schema Types\n// ============================================================================\n\nexport type SchemaType = 'entity' | 'single' | 'form'\n\nexport interface LoadedEntitySchema {\n type: 'entity'\n schema: Schema\n filePath: string\n}\n\nexport interface LoadedSingleSchema {\n type: 'single'\n schema: Schema\n filePath: string\n}\n\nexport interface LoadedFormSchema {\n type: 'form'\n schema: FormSchema\n filePath: string\n}\n\nexport type LoadedSchema = LoadedEntitySchema | LoadedSingleSchema | LoadedFormSchema\n\n// ============================================================================\n// Schema Loading\n// ============================================================================\n\n/**\n * Load a schema by name from the schemas directory\n * Detects entity vs form schemas automatically\n */\nexport function loadSchema(schemasDir: string, name: string): LoadedSchema {\n // Check for form schema first (in forms/ subdirectory)\n const formPath = path.join(schemasDir, 'forms', `${name}.json`)\n if (fs.existsSync(formPath)) {\n const content = fs.readFileSync(formPath, 'utf-8')\n const parsed = parseJson(content, formPath)\n return { type: 'form', schema: parsed as FormSchema, filePath: formPath }\n }\n\n // Check for entity schema\n const entityPath = path.join(schemasDir, `${name}.json`)\n if (!fs.existsSync(entityPath)) {\n throw new SchemaNotFoundError(name, schemasDir)\n }\n\n const content = fs.readFileSync(entityPath, 'utf-8')\n const parsed = parseJson(content, entityPath)\n\n const obj = parsed as Record<string, unknown>\n\n // Auto-detect form type from schema content\n if ('submitButtonText' in obj || 'steps' in obj) {\n return { type: 'form', schema: parsed as FormSchema, filePath: entityPath }\n }\n\n // Detect single schema via explicit type field\n if (obj.type === 'single') {\n return { type: 'single', schema: parsed as Schema, filePath: entityPath }\n }\n\n return { type: 'entity', schema: parsed as Schema, filePath: entityPath }\n}\n\n/**\n * List all available entity schemas in the schemas directory\n */\nexport function listEntitySchemas(schemasDir: string): string[] {\n if (!fs.existsSync(schemasDir)) return []\n return fs\n .readdirSync(schemasDir)\n .filter((f) => f.endsWith('.json') && f !== 'schema.json')\n .map((f) => f.replace('.json', ''))\n}\n\n/**\n * List all available form schemas\n */\nexport function listFormSchemas(schemasDir: string): string[] {\n const formsDir = path.join(schemasDir, 'forms')\n if (!fs.existsSync(formsDir)) return []\n return fs\n .readdirSync(formsDir)\n .filter((f) => f.endsWith('.json'))\n .map((f) => f.replace('.json', ''))\n}\n\n// ============================================================================\n// Schema Validation\n// ============================================================================\n\n/**\n * Validate an entity schema structure\n * Returns an array of error messages (empty = valid)\n */\nexport function validateEntitySchema(schema: Schema): string[] {\n const errors: string[] = []\n\n if (!schema.name || typeof schema.name !== 'string') {\n errors.push('Schema must have a valid \"name\" field')\n }\n if (!schema.label || typeof schema.label !== 'string') {\n errors.push('Schema must have a valid \"label\" field')\n }\n if (!schema.description || typeof schema.description !== 'string') {\n errors.push('Schema must have a valid \"description\" field')\n }\n if (!schema.icon || typeof schema.icon !== 'string') {\n errors.push('Schema must have a valid \"icon\" field')\n }\n if (!Array.isArray(schema.fields) || schema.fields.length === 0) {\n errors.push('Schema must have at least one field')\n }\n if (!Array.isArray(schema.columns) || schema.columns.length === 0) {\n errors.push('Schema must have at least one column')\n }\n\n // Validate fields\n for (const field of schema.fields || []) {\n if (field.type === 'separator') continue\n if (!field.name || !field.type) {\n errors.push(`Field is missing required properties: ${JSON.stringify(field)}`)\n }\n }\n\n // Validate columns reference real fields\n const flatFields = flattenFields(schema.fields || [])\n const fieldNames = new Set(flatFields.map((f) => f.name))\n // Auto fields are always available\n for (const auto of [\n 'id',\n 'createdAt',\n 'updatedAt',\n 'published',\n 'submittedAt',\n 'ipAddress',\n 'userAgent'\n ]) {\n fieldNames.add(auto)\n }\n\n for (const column of schema.columns || []) {\n if (!column.accessorKey || !column.header || !column.type) {\n errors.push(`Column is missing required properties: ${JSON.stringify(column)}`)\n } else if (!fieldNames.has(column.accessorKey)) {\n errors.push(\n `Column accessorKey \"${column.accessorKey}\" does not match any field. Available: ${Array.from(fieldNames).join(', ')}`\n )\n }\n }\n\n return errors\n}\n\n/**\n * Validate a single schema structure\n * Like entity validation but skips columns requirement (no list view)\n */\nexport function validateSingleSchema(schema: Schema): string[] {\n const errors: string[] = []\n\n if (!schema.name || typeof schema.name !== 'string') {\n errors.push('Schema must have a valid \"name\" field')\n }\n if (!schema.label || typeof schema.label !== 'string') {\n errors.push('Schema must have a valid \"label\" field')\n }\n if (!schema.description || typeof schema.description !== 'string') {\n errors.push('Schema must have a valid \"description\" field')\n }\n if (!schema.icon || typeof schema.icon !== 'string') {\n errors.push('Schema must have a valid \"icon\" field')\n }\n if (!Array.isArray(schema.fields) || schema.fields.length === 0) {\n errors.push('Schema must have at least one field')\n }\n\n // Validate fields\n for (const field of schema.fields || []) {\n if (field.type === 'separator') continue\n if (!field.name || !field.type) {\n errors.push(`Field is missing required properties: ${JSON.stringify(field)}`)\n }\n }\n\n // No columns validation — single schemas have no list view\n\n return errors\n}\n\n/**\n * Validate a form schema structure\n */\nexport function validateFormSchema(schema: FormSchema): string[] {\n const errors: string[] = []\n\n if (!schema.name || typeof schema.name !== 'string') {\n errors.push('Form schema must have a valid \"name\" field')\n }\n if (!schema.label || typeof schema.label !== 'string') {\n errors.push('Form schema must have a valid \"label\" field')\n }\n if (!schema.description || typeof schema.description !== 'string') {\n errors.push('Form schema must have a valid \"description\" field')\n }\n if (!schema.icon || typeof schema.icon !== 'string') {\n errors.push('Form schema must have a valid \"icon\" field')\n }\n\n const hasFields = Array.isArray(schema.fields) && schema.fields.length > 0\n const hasSteps = Array.isArray(schema.steps) && schema.steps.length > 0\n\n if (!hasFields && !hasSteps) {\n errors.push('Form schema must have either \"fields\" or \"steps\"')\n }\n if (hasFields && hasSteps) {\n errors.push('Form schema cannot have both \"fields\" and \"steps\"')\n }\n\n if (hasSteps) {\n for (const step of schema.steps!) {\n if (!step.name || !step.label) {\n errors.push(`Form step is missing name or label: ${JSON.stringify(step)}`)\n }\n if (!Array.isArray(step.fields) || step.fields.length === 0) {\n errors.push(`Form step \"${step.name}\" must have at least one field`)\n }\n }\n }\n\n return errors\n}\n\n/**\n * Validate a loaded schema (auto-detects type)\n */\nexport function validateLoadedSchema(loaded: LoadedSchema): string[] {\n if (loaded.type === 'entity') {\n return validateEntitySchema(loaded.schema)\n }\n if (loaded.type === 'single') {\n return validateSingleSchema(loaded.schema)\n }\n return validateFormSchema(loaded.schema)\n}\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nexport class SchemaNotFoundError extends Error {\n constructor(name: string, schemasDir: string) {\n super(\n `Schema \"${name}\" not found. Looked in:\\n - ${path.join(schemasDir, `${name}.json`)}\\n - ${path.join(schemasDir, 'forms', `${name}.json`)}`\n )\n this.name = 'SchemaNotFoundError'\n }\n}\n\n// ============================================================================\n// Internal Helpers\n// ============================================================================\n\nfunction parseJson(content: string, filePath: string): unknown {\n try {\n return JSON.parse(content)\n } catch {\n throw new Error(`Failed to parse JSON schema: ${filePath}`)\n }\n}\n","/**\n * Field tree walking and type checking utilities\n */\n\nimport type { SchemaField } from '../../types.js'\n\n// ============================================================================\n// Field Tree Walking\n// ============================================================================\n\nexport interface WalkFieldsOptions {\n includeLists?: boolean\n includeGroups?: boolean\n includeTabs?: boolean\n}\n\nconst DEFAULT_WALK_OPTIONS: WalkFieldsOptions = {\n includeLists: true,\n includeGroups: true,\n includeTabs: true\n}\n\n/**\n * Walk through all fields in a schema, including nested ones\n */\nexport function walkFields(\n fields: SchemaField[],\n callback: (field: SchemaField, depth: number, parent?: SchemaField) => void,\n options: WalkFieldsOptions = DEFAULT_WALK_OPTIONS\n): void {\n function walk(fieldsToWalk: SchemaField[], depth: number, parent?: SchemaField): void {\n for (const field of fieldsToWalk) {\n callback(field, depth, parent)\n\n if (options.includeGroups && field.type === 'group' && field.fields) {\n walk(field.fields, depth + 1, field)\n }\n if (options.includeLists && field.type === 'list' && field.fields) {\n walk(field.fields, depth + 1, field)\n }\n if (options.includeTabs && field.type === 'tabs' && field.tabs) {\n for (const tab of field.tabs) {\n if (tab.fields) {\n walk(tab.fields, depth + 1, field)\n }\n }\n }\n }\n }\n\n walk(fields, 0)\n}\n\n// ============================================================================\n// Field Type Checking\n// ============================================================================\n\n/**\n * Check if any field in the tree matches a specific type\n */\nexport function hasFieldType(\n fields: SchemaField[],\n type: string,\n options?: WalkFieldsOptions\n): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (field.type === type) found = true\n },\n options\n )\n return found\n}\n\n/**\n * Check if any field in the tree matches any of the given types\n */\nexport function hasAnyFieldType(\n fields: SchemaField[],\n types: string[],\n options?: WalkFieldsOptions\n): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (types.includes(field.type)) found = true\n },\n options\n )\n return found\n}\n\n/**\n * Check if any field uses icons (either icon type or hasIcon property)\n */\nexport function hasIconUsage(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (field.type === 'icon' || field.hasIcon) found = true\n },\n options\n )\n return found\n}\n\nexport function hasRelationshipField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, 'relationship', options)\n}\n\nexport function hasMarkdownField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, 'markdown', options)\n}\n\nexport function hasTextareaField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, 'text', options)\n}\n\n/**\n * Collect all fields of a specific type\n */\nexport function collectFieldsByType(\n fields: SchemaField[],\n type: string,\n options?: WalkFieldsOptions\n): SchemaField[] {\n const result: SchemaField[] = []\n walkFields(\n fields,\n (field) => {\n if (field.type === type) result.push(field)\n },\n options\n )\n return result\n}\n","/**\n * Field flattening and collection utilities\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { collectFieldsByType } from './walking.js'\n\n// ============================================================================\n// Field Flattening\n// ============================================================================\n\nconst AUTO_ID_FIELD: SchemaField = {\n name: 'id',\n type: 'serial',\n primaryKey: true\n}\n\n/**\n * Ensure fields have an ID field - automatically injects one if not present\n */\nexport function ensureIdField(fields: SchemaField[]): SchemaField[] {\n const hasId = fields.some((f) => f.primaryKey || f.name === 'id')\n return hasId ? fields : [AUTO_ID_FIELD, ...fields]\n}\n\n/**\n * Flatten group and tabs fields into individual fields for database operations\n * Automatically ensures an ID field exists\n */\nexport function flattenFields(fields: SchemaField[]): SchemaField[] {\n return flattenFieldsWithoutIdCheck(ensureIdField(fields))\n}\n\nfunction flattenFieldsWithoutIdCheck(fields: SchemaField[]): SchemaField[] {\n const flattened: SchemaField[] = []\n\n for (const field of fields) {\n if (field.type === 'group' && field.fields) {\n flattened.push(...flattenFieldsWithoutIdCheck(field.fields))\n } else if (field.type === 'tabs' && field.tabs) {\n for (const tab of field.tabs) {\n if (tab.fields) {\n flattened.push(...flattenFieldsWithoutIdCheck(tab.fields))\n }\n }\n } else {\n flattened.push(field)\n }\n }\n\n return flattened\n}\n\n// ============================================================================\n// Field Collection\n// ============================================================================\n\n/**\n * Get all many-to-many relationship fields\n */\nexport function getManyToManyFields(fields: SchemaField[]): SchemaField[] {\n const flat = flattenFields(fields)\n return flat.filter((f) => f.type === 'relationship' && f.multiple === true && f.relationship)\n}\n\n/**\n * Get all single relationship fields (excluding many-to-many)\n */\nexport function getNestedRelationshipFields(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'relationship' && f.relationship && !f.multiple) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) collect(f.fields)\n if (f.type === 'list' && f.fields) collect(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collect(tab.fields)\n }\n }\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Collect relationship fields from top-level and groups only (not lists)\n */\nexport function collectRelationshipFieldsTopLevel(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'relationship' && f.relationship) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) {\n collect(f.fields)\n }\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Collect ALL relationship fields including those in lists\n */\nexport function collectAllRelationshipFields(fields: SchemaField[]): SchemaField[] {\n return collectFieldsByType(fields, 'relationship')\n}\n\n/**\n * Get list fields that have nested fields (not just items)\n */\nexport function getListFieldsWithNestedFields(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'list' && f.fields && f.fields.length > 0) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) {\n collect(f.fields)\n }\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Get nested list fields (list fields inside list fields)\n */\nexport function getNestedListFields(\n fields: SchemaField[]\n): { parent: SchemaField; nested: SchemaField }[] {\n const result: { parent: SchemaField; nested: SchemaField }[] = []\n\n const listFields = getListFieldsWithNestedFields(fields)\n for (const parent of listFields) {\n if (parent.fields) {\n for (const nested of parent.fields) {\n if (nested.type === 'list' && nested.fields && nested.fields.length > 0) {\n result.push({ parent, nested })\n }\n }\n }\n }\n\n return result\n}\n","/**\n * Form schema field helpers (for FormSchema type)\n */\n\nimport type { FormField, FormSchema, FormStep } from '../../types.js'\n\n/**\n * Get all fields from a form schema (including from steps), flattening groups\n */\nexport function getAllFormFields(schema: FormSchema): FormField[] {\n const allFields: FormField[] = []\n\n const sources = schema.steps ? schema.steps.flatMap((step) => step.fields) : schema.fields || []\n\n for (const field of sources) {\n if (field.type === 'group' && field.fields) {\n for (const nestedField of field.fields) {\n allFields.push({\n ...nestedField,\n condition: nestedField.condition || field.condition\n })\n }\n } else {\n allFields.push(field)\n }\n }\n\n return allFields\n}\n\n/**\n * Check if a form schema is multi-step\n */\nexport function isMultiStepForm(schema: FormSchema): boolean {\n return Array.isArray(schema.steps) && schema.steps.length > 0\n}\n\n/**\n * Get all concrete fields from a form schema, flattening groups and skipping dynamicFields.\n * Works with both flat schemas (schema.fields) and multi-step schemas (schema.steps).\n */\nexport function getAllFormSchemaFields(schema: FormSchema): FormField[] {\n const flatten = (fields: FormField[]): FormField[] => {\n return fields.flatMap((field) => {\n if (field.type === 'dynamicFields') return []\n if (field.type === 'group' && field.fields) return flatten(field.fields)\n return field.type === 'group' ? [] : [field]\n })\n }\n if (schema.fields) return flatten(schema.fields)\n if (schema.steps) return schema.steps.flatMap((step) => flatten(step.fields))\n return []\n}\n\n/**\n * Get flat array of field names for a form step (for RHF trigger validation).\n * Groups are flattened to child names, list fields use parent name,\n * hidden and dynamicFields are excluded, showWhen fields are included.\n */\nexport function getStepFieldNames(step: FormStep): string[] {\n const names: string[] = []\n const collect = (fields: FormField[]): void => {\n for (const field of fields) {\n if (field.hidden) continue\n if (field.type === 'dynamicFields') continue\n if (field.type === 'group' && field.fields) {\n collect(field.fields)\n } else if (field.name) {\n names.push(field.name)\n }\n }\n }\n collect(step.fields)\n return names\n}\n\n/**\n * Check if a form schema contains dynamicFields\n */\nexport function hasDynamicFields(schema: FormSchema): boolean {\n const check = (fields: FormField[]): boolean => {\n for (const f of fields) {\n if (f.type === 'dynamicFields') return true\n if (f.type === 'group' && f.fields && check(f.fields)) return true\n }\n return false\n }\n if (schema.fields && check(schema.fields)) return true\n if (schema.steps) {\n for (const step of schema.steps) {\n if (check(step.fields)) return true\n }\n }\n return false\n}\n","/**\n * Email template generator: creates React Email template for form submission notifications\n * Output: cms/lib/emails/<name>-submission.tsx\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { getAllFormSchemaFields, hasDynamicFields } from '../core/field-helpers/index.js'\nimport type { FormField, FormSchema, GeneratorOptions } from '../types.js'\nimport { toPascalCase, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Type Mapping\n// ============================================================================\n\nfunction getTypeForField(field: FormField): string {\n switch (field.type) {\n case 'number':\n return 'number | null'\n case 'checkbox':\n return 'boolean | null'\n case 'list':\n case 'multiselect':\n if (field.fields && field.fields.length > 0) return 'Record<string, unknown>[] | null'\n return 'string[] | null'\n default:\n return 'string | null'\n }\n}\n\n// ============================================================================\n// Field Value Rendering\n// ============================================================================\n\nfunction generateFieldValue(field: FormField): string {\n const name = field.name || ''\n\n switch (field.type) {\n case 'checkbox':\n return `{${name} ? 'Yes' : 'No'}`\n case 'upload':\n case 'file':\n return `{${name} ? (\n <Link href={${name}} style={link}>Download File</Link>\n ) : 'No file uploaded'}`\n case 'email':\n return `{${name} ? (\n <Link href={\\`mailto:\\${${name}}\\`} style={link}>{${name}}</Link>\n ) : 'N/A'}`\n case 'url':\n return `{${name} ? (\n <Link href={${name}} style={link}>{${name}}</Link>\n ) : 'N/A'}`\n case 'list':\n case 'multiselect':\n if (field.fields && field.fields.length > 0) {\n return `{${name} && Array.isArray(${name}) && ${name}.length > 0 ? (\n ${name}.map((item, idx) => (\n <Text key={idx} style={listItem}>\n {Object.entries(item).map(([k, v]) => \\`\\${k}: \\${v}\\`).join(', ')}\n </Text>\n ))\n ) : 'N/A'}`\n }\n return `{${name} && Array.isArray(${name}) && ${name}.length > 0 ? ${name}.join(', ') : 'N/A'}`\n case 'date':\n return `{${name} ? new Date(${name}).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }) : 'N/A'}`\n default:\n return `{${name} ?? 'N/A'}`\n }\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface EmailTemplateResult {\n files: string[]\n}\n\nexport function generateEmailTemplate(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions = {}\n): EmailTemplateResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const fields = getAllFormSchemaFields(schema).filter((f) => f.name)\n const includeDynamic = hasDynamicFields(schema)\n\n const kebab = toKebabCase(formName)\n const filePath = path.join(cwd, cmsDir, 'lib', 'emails', `${kebab}-submission.tsx`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const needsLink = fields.some(\n (f) => f.type === 'upload' || f.type === 'file' || f.type === 'email' || f.type === 'url'\n )\n const needsListItem = fields.some(\n (f) => (f.type === 'list' || f.type === 'multiselect') && f.fields && f.fields.length > 0\n )\n\n // Props interface\n const propsFields = fields.map((f) => ` ${f.name}: ${getTypeForField(f)}`).join('\\n')\n const customFieldsProp = includeDynamic ? '\\n customFields?: Record<string, unknown> | null' : ''\n\n // Field sections in email body\n const fieldSections = fields\n .map(\n (f) => ` <Row style={fieldRow}>\n <Text style={label}>${f.label}</Text>\n <Text style={value}>${generateFieldValue(f)}</Text>\n </Row>`\n )\n .join('\\n\\n')\n\n // Dynamic fields section\n const customFieldsSection = includeDynamic\n ? `\n\n {customFields && Object.keys(customFields).length > 0 && (\n <>\n <Row style={dividerRow}>\n <Text style={sectionTitle}>Additional Information</Text>\n </Row>\n {Object.entries(customFields).map(([fieldKey, fieldValue]) => (\n <Row key={fieldKey} style={fieldRow}>\n <Text style={label}>{fieldKey.replace(/([A-Z])/g, ' $1').trim()}</Text>\n <Text style={value}>{fieldValue !== null && fieldValue !== undefined ? String(fieldValue) : 'N/A'}</Text>\n </Row>\n ))}\n </>\n )}`\n : ''\n\n // Props destructuring\n const propsDestructured = [\n ...fields.map((f) => f.name),\n ...(includeDynamic ? ['customFields'] : []),\n 'submittedAt'\n ].join(',\\n ')\n\n // Optional style blocks\n const linkStyle = needsLink\n ? `\nconst link = {\n color: colors.primary,\n fontWeight: '500' as const,\n textDecoration: 'none',\n}\n`\n : ''\n\n const listItemStyle = needsListItem\n ? `\nconst listItem = {\n backgroundColor: colors.borderLight,\n borderRadius: '6px',\n color: colors.text,\n fontSize: '14px',\n lineHeight: '20px',\n marginBottom: '6px',\n padding: '8px 12px',\n}\n`\n : ''\n\n const dynamicStyles = includeDynamic\n ? `\nconst dividerRow = {\n borderTop: \\`2px solid \\${colors.border}\\`,\n marginTop: '8px',\n paddingTop: '24px',\n}\n\nconst sectionTitle = {\n color: colors.text,\n fontSize: '14px',\n fontWeight: '600' as const,\n margin: '0 0 8px',\n}\n`\n : ''\n\n const content = `import { Body, Container, Head, Heading, Html${needsLink ? ', Link' : ''}, Preview, Row, Section, Text } from '@react-email/components'\n\ninterface ${pascal}SubmissionEmailProps {\n${propsFields}${customFieldsProp}\n submittedAt: string\n}\n\nexport function ${pascal}SubmissionEmail({\n ${propsDestructured}\n}: ${pascal}SubmissionEmailProps) {\n return (\n <Html>\n <Head />\n <Preview>New ${schema.label} Submission</Preview>\n <Body style={main}>\n <Container style={container}>\n <Section style={header}>\n <Text style={logoText}>BetterStart</Text>\n </Section>\n\n <Section style={titleSection}>\n <Heading style={h1}>New ${schema.label} Submission</Heading>\n <Text style={subtitle}>\n You received a new submission on {new Date(submittedAt).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}\n </Text>\n </Section>\n\n <Section style={card}>\n${fieldSections}${customFieldsSection}\n </Section>\n\n <Section style={footer}>\n <Text style={footerText}>\n Submitted at {new Date(submittedAt).toLocaleString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true, timeZoneName: 'short' })}\n </Text>\n <Text style={footerBrand}>BetterStart</Text>\n </Section>\n </Container>\n </Body>\n </Html>\n )\n}\n\nconst colors = {\n primary: '#7c3aed',\n background: '#f8fafc',\n cardBg: '#ffffff',\n text: '#1e293b',\n textMuted: '#64748b',\n textLight: '#94a3b8',\n border: '#e2e8f0',\n borderLight: '#f1f5f9',\n}\n\nconst main = {\n backgroundColor: colors.background,\n fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n padding: '40px 20px',\n}\n\nconst container = {\n margin: '0 auto',\n maxWidth: '600px',\n}\n\nconst header = {\n backgroundColor: colors.primary,\n borderRadius: '12px 12px 0 0',\n padding: '24px 32px',\n textAlign: 'center' as const,\n}\n\nconst logoText = {\n color: '#ffffff',\n fontSize: '24px',\n fontWeight: '700' as const,\n letterSpacing: '-0.02em',\n margin: '0',\n}\n\nconst titleSection = {\n backgroundColor: colors.cardBg,\n padding: '32px 32px 24px',\n textAlign: 'center' as const,\n}\n\nconst h1 = {\n color: colors.text,\n fontSize: '24px',\n fontWeight: '700' as const,\n lineHeight: '32px',\n margin: '0 0 8px',\n}\n\nconst subtitle = {\n color: colors.textMuted,\n fontSize: '14px',\n lineHeight: '20px',\n margin: '0',\n}\n\nconst card = {\n backgroundColor: colors.cardBg,\n padding: '0 32px 32px',\n}\n\nconst fieldRow = {\n borderBottom: \\`1px solid \\${colors.borderLight}\\`,\n padding: '16px 0',\n}\n\nconst label = {\n color: colors.textMuted,\n fontSize: '12px',\n fontWeight: '600' as const,\n letterSpacing: '0.025em',\n lineHeight: '16px',\n margin: '0 0 6px',\n textTransform: 'uppercase' as const,\n}\n\nconst value = {\n color: colors.text,\n fontSize: '16px',\n lineHeight: '24px',\n margin: '0',\n wordBreak: 'break-word' as const,\n}\n${linkStyle}${listItemStyle}${dynamicStyles}const footer = {\n backgroundColor: colors.cardBg,\n borderRadius: '0 0 12px 12px',\n borderTop: \\`1px solid \\${colors.border}\\`,\n padding: '24px 32px',\n textAlign: 'center' as const,\n}\n\nconst footerText = {\n color: colors.textLight,\n fontSize: '12px',\n lineHeight: '16px',\n margin: '0 0 8px',\n}\n\nconst footerBrand = {\n color: colors.textMuted,\n fontSize: '14px',\n fontWeight: '600' as const,\n margin: '0',\n}\n`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Shared string helpers used across all generators.\n */\n\nexport function toPascalCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nexport function toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nexport function singularize(str: string): string {\n if (str.endsWith('ies')) return `${str.slice(0, -3)}y`\n if (str.endsWith('ves')) return `${str.slice(0, -3)}f`\n if (\n str.endsWith('sses') ||\n str.endsWith('xes') ||\n str.endsWith('ches') ||\n str.endsWith('shes') ||\n str.endsWith('zes')\n )\n return str.slice(0, -2)\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\n\nexport function pluralize(str: string): string {\n if (str.endsWith('s') && !str.endsWith('ss')) return str\n if (str.endsWith('y') && !['ay', 'ey', 'iy', 'oy', 'uy'].some((v) => str.endsWith(v)))\n return `${str.slice(0, -1)}ies`\n if (str.endsWith('s') || str.endsWith('x') || str.endsWith('ch') || str.endsWith('sh'))\n return `${str}es`\n return `${str}s`\n}\n\nexport function toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\nexport function toScreamingSnake(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toUpperCase()\n}\n\nexport function quotePropertyName(name: string): string {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`\n}\n\nexport function singularizeLabel(label: string): string {\n const words = label.split(' ')\n const lastWord = words[words.length - 1]\n words[words.length - 1] = singularize(lastWord.toLowerCase())\n words[words.length - 1] =\n words[words.length - 1].charAt(0).toUpperCase() + words[words.length - 1].slice(1)\n return words.join(' ')\n}\n","/**\n * Form admin pages generator: creates admin UI for viewing/managing form submissions\n *\n * Generates under (authenticated)/forms/<name>/:\n * page.tsx, columns.tsx, <name>-submissions-table.tsx,\n * <name>-submissions-page-content.tsx, [id]/view/page.tsx\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { getAllFormSchemaFields, hasDynamicFields } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase, toKebabCase } from '../../utils/string.js'\nimport { generateColumns } from './admin-columns.js'\nimport { generatePage } from './admin-page.js'\nimport { generatePageContent } from './admin-page-content.js'\nimport { generateSettingsPage } from './admin-settings-page.js'\nimport { generateTable } from './admin-table.js'\nimport { generateViewPage } from './admin-view-page.js'\n\n// ============================================================================\n// Result Type\n// ============================================================================\n\nexport interface FormAdminPagesResult {\n files: string[]\n}\n\n// ============================================================================\n// Generator\n// ============================================================================\n\nexport function generateFormAdminPages(\n schema: FormSchema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions\n): FormAdminPagesResult {\n const formName = schema.name\n const kebab = toKebabCase(formName)\n const pascal = toPascalCase(formName)\n const camel = toCamelCase(formName)\n const fields = getAllFormSchemaFields(schema)\n\n const adminDir = path.join(cwd, pagesDir, 'forms', kebab)\n if (!fs.existsSync(adminDir)) fs.mkdirSync(adminDir, { recursive: true })\n\n const files: string[] = []\n const rel = (p: string) => path.relative(cwd, p)\n\n // 1. page.tsx\n const pagePath = path.join(adminDir, 'page.tsx')\n if (!fs.existsSync(pagePath) || options.force) {\n fs.writeFileSync(pagePath, generatePage(pascal, kebab), 'utf-8')\n }\n files.push(rel(pagePath))\n\n // 2. columns.tsx\n const columnsPath = path.join(adminDir, 'columns.tsx')\n if (!fs.existsSync(columnsPath) || options.force) {\n fs.writeFileSync(\n columnsPath,\n generateColumns(fields, pascal, kebab, camel, schema.columns),\n 'utf-8'\n )\n }\n files.push(rel(columnsPath))\n\n // 3. submissions-table.tsx\n const tablePath = path.join(adminDir, `${kebab}-submissions-table.tsx`)\n if (!fs.existsSync(tablePath) || options.force) {\n fs.writeFileSync(tablePath, generateTable(pascal, kebab, schema.label), 'utf-8')\n }\n files.push(rel(tablePath))\n\n // 4. submissions-page-content.tsx\n const contentPath = path.join(adminDir, `${kebab}-submissions-page-content.tsx`)\n if (!fs.existsSync(contentPath) || options.force) {\n fs.writeFileSync(contentPath, generatePageContent(pascal, kebab, camel, schema.label), 'utf-8')\n }\n files.push(rel(contentPath))\n\n // 5. [id]/view/page.tsx\n const viewDir = path.join(adminDir, '[id]', 'view')\n if (!fs.existsSync(viewDir)) fs.mkdirSync(viewDir, { recursive: true })\n const viewPath = path.join(viewDir, 'page.tsx')\n if (!fs.existsSync(viewPath) || options.force) {\n fs.writeFileSync(\n viewPath,\n generateViewPage(pascal, kebab, fields, schema.label, hasDynamicFields(schema)),\n 'utf-8'\n )\n }\n files.push(rel(viewPath))\n\n // 6. settings/page.tsx\n const settingsDir = path.join(adminDir, 'settings')\n if (!fs.existsSync(settingsDir)) fs.mkdirSync(settingsDir, { recursive: true })\n const settingsPath = path.join(settingsDir, 'page.tsx')\n if (!fs.existsSync(settingsPath) || options.force) {\n fs.writeFileSync(settingsPath, generateSettingsPage(pascal, kebab, schema.label), 'utf-8')\n }\n files.push(rel(settingsPath))\n\n return { files }\n}\n","import type { FormColumn, FormField } from '../../types.js'\n\n// ============================================================================\n// Column Definition Helper\n// ============================================================================\n\nfunction generateColumnDef(col: FormColumn): string {\n const sortableHeader = col.sortable\n ? `header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n >\n ${col.header}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n )`\n : `header: '${col.header}'`\n\n let cellDef: string\n switch (col.type) {\n case 'email':\n cellDef = `cell: ({ row }) => {\n const email = row.getValue('${col.accessorKey}') as string\n return email ? <a href={\\`mailto:\\${email}\\`} className=\"text-primary hover:underline\">{email}</a> : '-'\n }`\n break\n case 'date':\n cellDef = `cell: ({ row }) => {\n const date = row.getValue('${col.accessorKey}') as string\n return date ? new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) : '-'\n }`\n break\n case 'badge':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${col.accessorKey}') as string\n return <Badge variant=\"outline\">{value || 'N/A'}</Badge>\n }`\n break\n case 'number':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${col.accessorKey}') as number\n return <div className=\"text-right\">{value !== null && value !== undefined ? value : '-'}</div>\n }`\n break\n default:\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${col.accessorKey}') as string\n return <div>{value || '-'}</div>\n }`\n }\n\n return ` {\n accessorKey: '${col.accessorKey}',\n ${sortableHeader},\n ${cellDef}\n }`\n}\n\n// ============================================================================\n// Columns Generator\n// ============================================================================\n\nexport function generateColumns(\n fields: FormField[],\n pascal: string,\n kebab: string,\n camel: string,\n customColumns?: FormColumn[]\n): string {\n const hasBadge = customColumns?.some((c) => c.type === 'badge') ?? false\n\n const columnDefs = customColumns\n ? customColumns.map((col) => generateColumnDef(col)).join(',\\n')\n : fields\n .filter((f) => f.name)\n .map((f) => {\n const accessor = f.name!\n return ` {\n accessorKey: '${accessor}',\n header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n >\n ${f.label}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n ),\n cell: ({ row }) => {\n const value = row.getValue('${accessor}')\n return <div>${f.type === 'textarea' ? \"{value ? String(value).substring(0, 100) + (String(value).length > 100 ? '...' : '') : '-'}\" : \"{String(value ?? '-')}\"}</div>\n }\n }`\n })\n .join(',\\n')\n\n return `'use client'\n\nimport type { ${pascal}SubmissionData } from '@cms/actions/${kebab}-form'\nimport { delete${pascal}Submission } from '@cms/actions/${kebab}-form'\n${hasBadge ? \"import { Badge } from '@cms/components/ui/badge'\" : ''}\nimport { Button } from '@cms/components/ui/button'\nimport { Checkbox } from '@cms/components/ui/checkbox'\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ArrowUpDown, Eye, Trash } from 'lucide-react'\nimport Link from 'next/link'\nimport { useState, useTransition } from 'react'\nimport { toast } from 'sonner'\n\nfunction DeleteAction({ id }: { id: number }) {\n const [open, setOpen] = useState(false)\n const [isPending, startTransition] = useTransition()\n const queryClient = useQueryClient()\n\n const handleDelete = () => {\n startTransition(async () => {\n try {\n const result = await delete${pascal}Submission(id)\n if (result.success) {\n toast.success('Submission deleted successfully')\n queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete submission')\n }\n } catch {\n toast.error('An error occurred')\n }\n })\n }\n\n return (\n <AlertDialog open={open} onOpenChange={setOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" size=\"icon\" className=\"size-8\">\n <Trash className=\"size-3\" />\n <span className=\"sr-only\">Delete</span>\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This will permanently delete this submission.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e: React.MouseEvent) => { e.preventDefault(); handleDelete() }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n\nexport const columns: ColumnDef<${pascal}SubmissionData>[] = [\n {\n id: 'select',\n header: ({ table }) => (\n <Checkbox\n checked={table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && 'indeterminate')}\n onCheckedChange={(value: boolean) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value: boolean) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n enableSorting: false,\n enableHiding: false\n },\n${columnDefs},\n {\n id: 'actions',\n header: () => <div className=\"text-right\">Actions</div>,\n cell: ({ row }) => {\n const submission = row.original\n return (\n <div className=\"flex justify-end items-center gap-2\">\n <Button variant=\"outline\" size=\"icon\" className=\"size-8\" asChild>\n <Link href={\\`/cms/forms/${kebab}/\\${submission.id}/view\\`}>\n <Eye className=\"size-3\" />\n <span className=\"sr-only\">View</span>\n </Link>\n </Button>\n <DeleteAction id={submission.id} />\n </div>\n )\n }\n }\n]\n`\n}\n","export function generatePage(pascal: string, kebab: string): string {\n return `import { Suspense } from 'react'\nimport { ${pascal}SubmissionsPageContent } from './${kebab}-submissions-page-content'\nimport { columns } from './columns'\n\nexport default function Page() {\n return (\n <Suspense fallback={<div className=\"p-6\">Loading...</div>}>\n <${pascal}SubmissionsPageContent columns={columns} />\n </Suspense>\n )\n}\n`\n}\n","export function generatePageContent(pascal: string, kebab: string, camel: string, label: string): string {\n return `'use client'\n\nimport type { ${pascal}SubmissionData } from '@cms/actions/${kebab}-form'\nimport { deleteBulk${pascal}Submissions } from '@cms/actions/${kebab}-form'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ChevronLeft, Search, Settings, Trash2 } from 'lucide-react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { parseAsString, useQueryState } from 'nuqs'\nimport { startTransition, useCallback, useState, useTransition } from 'react'\nimport { toast } from 'sonner'\nimport { ${pascal}SubmissionsTable } from './${kebab}-submissions-table'\n\ninterface ${pascal}SubmissionsPageContentProps<TValue> {\n columns: ColumnDef<${pascal}SubmissionData, TValue>[]\n}\n\nexport function ${pascal}SubmissionsPageContent<TValue>({\n columns,\n}: ${pascal}SubmissionsPageContentProps<TValue>) {\n const router = useRouter()\n const queryClient = useQueryClient()\n const [search, setSearch] = useQueryState('q', parseAsString.withDefault(''))\n const [selectedIds, setSelectedIds] = useState<number[]>([])\n const [deleteOpen, setDeleteOpen] = useState(false)\n const [isPending, startDeleteTransition] = useTransition()\n\n const searchAction = useCallback(\n async (formData: FormData) => {\n const value = formData.get('search') as string\n startTransition(() => {\n setSearch(value || null)\n })\n },\n [setSearch]\n )\n\n const handleBulkDelete = () => {\n startDeleteTransition(async () => {\n try {\n const result = await deleteBulk${pascal}Submissions(selectedIds)\n if (result.success) {\n toast.success(\\`\\${selectedIds.length} submission\\${selectedIds.length > 1 ? 's' : ''} deleted\\`)\n queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n setSelectedIds([])\n setDeleteOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete submissions')\n }\n } catch {\n toast.error('An error occurred')\n }\n })\n }\n\n return (\n <>\n <PageHeader title=\"${label}\" back={<Button variant=\"ghost\" size=\"icon\" onClick={() => router.back()}><ChevronLeft /></Button>} search={<form action={searchAction} className=\"flex items-center gap-2 relative\">\n <Search className=\"text-muted-foreground/70 pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\" />\n <Input\n key={search}\n name=\"search\"\n placeholder=\"Search submissions...\"\n defaultValue={search}\n className=\"w-64 pl-9 bg-white rounded-full\"\n />\n </form>} actions={<div className=\"flex items-center gap-2\">\n {selectedIds.length > 0 && (\n <AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" size=\"default\">\n <Trash2 className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Delete {selectedIds.length}\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This will permanently delete {selectedIds.length}{' '}\n {selectedIds.length === 1 ? 'submission' : 'submissions'}.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e: React.MouseEvent) => { e.preventDefault(); handleBulkDelete() }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/forms/${kebab}/settings\">\n <Settings className=\"size-3.5\" />\n Settings\n </Link>\n </Button>\n </div>} />\n <main className=\"space-y-4 p-6\">\n <${pascal}SubmissionsTable\n columns={columns}\n selectedIds={selectedIds}\n setSelectedIds={setSelectedIds}\n search={search}\n />\n </main>\n </>\n )\n}\n`\n}\n","export function generateSettingsPage(pascal: string, kebab: string, label: string): string {\n return `'use client'\n\nimport {\n getFormSettings,\n testFormWebhook,\n upsertFormSettings,\n} from '@cms/actions/form-settings'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport { Label } from '@cms/components/ui/label'\nimport { Switch } from '@cms/components/ui/switch'\nimport { Textarea } from '@cms/components/ui/textarea'\nimport { ChevronLeft, Loader2 } from 'lucide-react'\nimport { useRouter } from 'next/navigation'\nimport { useEffect, useState, useTransition } from 'react'\nimport { toast } from 'sonner'\n\nexport default function ${pascal}SettingsPage() {\n const router = useRouter()\n const [notificationEmails, setNotificationEmails] = useState('')\n const [webhookUrl, setWebhookUrl] = useState('')\n const [webhookEnabled, setWebhookEnabled] = useState(false)\n const [isSaving, startSaveTransition] = useTransition()\n const [isTesting, startTestTransition] = useTransition()\n const [loaded, setLoaded] = useState(false)\n\n useEffect(() => {\n getFormSettings('${kebab}').then((settings) => {\n if (settings) {\n setNotificationEmails(settings.notificationEmails ?? '')\n setWebhookUrl(settings.webhookUrl ?? '')\n setWebhookEnabled(settings.webhookEnabled)\n }\n setLoaded(true)\n })\n }, [])\n\n const handleSave = () => {\n startSaveTransition(async () => {\n const result = await upsertFormSettings('${kebab}', {\n notificationEmails: notificationEmails || null,\n webhookUrl: webhookUrl || null,\n webhookEnabled,\n })\n if (result.success) {\n toast.success('Settings saved successfully')\n } else {\n toast.error(result.error || 'Failed to save settings')\n }\n })\n }\n\n const handleTestWebhook = () => {\n startTestTransition(async () => {\n const result = await testFormWebhook('${kebab}')\n if (result.success) {\n toast.success('Test webhook sent successfully')\n } else {\n toast.error(result.error || 'Failed to send test webhook')\n }\n })\n }\n\n if (!loaded) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n </div>\n )\n }\n\n return (\n <>\n <PageHeader title=\"${label} Settings\" back={<Button variant=\"ghost\" size=\"icon\" onClick={() => router.back()}><ChevronLeft /></Button>} />\n <div className=\"space-y-6 rounded-lg border p-6 mx-6 mt-6\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"notificationEmails\">Notification Emails</Label>\n <Textarea\n id=\"notificationEmails\"\n placeholder=\"email@example.com, another@example.com\"\n value={notificationEmails}\n onChange={(e) => setNotificationEmails(e.target.value)}\n rows={3}\n />\n <p className=\"text-xs text-muted-foreground\">\n Comma-separated list of email addresses to notify on new submissions.\n </p>\n </div>\n\n <div className=\"space-y-4 border-t pt-6\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"webhookUrl\">Webhook URL</Label>\n <Input\n id=\"webhookUrl\"\n type=\"url\"\n placeholder=\"https://hooks.example.com/endpoint\"\n value={webhookUrl}\n onChange={(e) => setWebhookUrl(e.target.value)}\n />\n <p className=\"text-xs text-muted-foreground\">\n Receive a POST request with form data on each submission.\n </p>\n </div>\n\n <div className=\"flex items-center space-x-2\">\n <Switch\n id=\"webhookEnabled\"\n checked={webhookEnabled}\n onCheckedChange={setWebhookEnabled}\n />\n <Label htmlFor=\"webhookEnabled\">Enable Webhook</Label>\n </div>\n\n {webhookUrl && webhookEnabled && (\n <Button\n variant=\"outline\"\n onClick={handleTestWebhook}\n disabled={isTesting}\n >\n {isTesting ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Sending...\n </>\n ) : (\n 'Test Webhook'\n )}\n </Button>\n )}\n </div>\n\n <div className=\"border-t pt-6\">\n <Button onClick={handleSave} disabled={isSaving}>\n {isSaving ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Saving...\n </>\n ) : (\n 'Save Settings'\n )}\n </Button>\n </div>\n </div>\n </>\n )\n}\n`\n}\n","export function generateTable(pascal: string, kebab: string, label: string): string {\n return `'use client'\n\nimport type { ${pascal}SubmissionData } from '@cms/actions/${kebab}-form'\nimport { use${pascal}Submissions } from '@cms/hooks/use-${kebab}-form'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@cms/components/ui/table'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport { useCallback, useMemo, useState } from 'react'\n\nconst PAGE_SIZE_OPTIONS = [\n { value: '10', label: '10' },\n { value: '20', label: '20' },\n { value: '50', label: '50' },\n { value: '100', label: '100' },\n { value: 'all', label: 'All' },\n]\n\ninterface ${pascal}SubmissionsTableProps<TValue> {\n columns: ColumnDef<${pascal}SubmissionData, TValue>[]\n selectedIds: number[]\n setSelectedIds: (ids: number[]) => void\n search?: string\n}\n\nexport function ${pascal}SubmissionsTable<TValue>({\n columns,\n selectedIds,\n setSelectedIds,\n search,\n}: ${pascal}SubmissionsTableProps<TValue>) {\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0))\n const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(10))\n\n const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize\n\n const handlePageSizeChange = useCallback(\n (value: string) => {\n if (value === 'all') {\n setPageSize(-1)\n } else {\n setPageSize(Number.parseInt(value, 10))\n }\n setPageIndex(0)\n },\n [setPageSize, setPageIndex]\n )\n\n const { data, error, isPending } = use${pascal}Submissions(search)\n\n const rowSelection = useMemo(() => {\n const selection: Record<string, boolean> = {}\n const submissions = data?.submissions ?? []\n submissions.forEach((sub, idx) => {\n if (selectedIds.includes(sub.id)) {\n selection[idx.toString()] = true\n }\n })\n return selection\n }, [selectedIds, data?.submissions])\n\n const handleRowSelectionChange = useCallback(\n (updater: Record<string, boolean> | ((old: Record<string, boolean>) => Record<string, boolean>)) => {\n const submissions = data?.submissions ?? []\n const newSelection = typeof updater === 'function' ? updater(rowSelection) : updater\n const newIds = Object.keys(newSelection)\n .filter((key) => newSelection[key])\n .map((key) => submissions[Number.parseInt(key, 10)]?.id)\n .filter(Boolean) as number[]\n setSelectedIds(newIds)\n },\n [data?.submissions, rowSelection, setSelectedIds]\n )\n\n const table = useReactTable({\n data: data?.submissions ?? [],\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n onRowSelectionChange: handleRowSelectionChange,\n state: {\n sorting,\n columnFilters,\n columnVisibility,\n rowSelection,\n pagination: { pageIndex, pageSize: effectivePageSize },\n },\n })\n\n return (\n <div className=\"space-y-4\">\n <div className=\"rounded-lg border overflow-hidden\">\n <Table>\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead key={header.id}>\n {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center text-muted-foreground\">\n Loading ${label} submissions...\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center text-destructive\">\n Error: {error.message}\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No submissions found.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-2\">\n <p className=\"text-sm text-muted-foreground\">Rows per page</p>\n <Select\n value={pageSize === -1 ? 'all' : pageSize.toString()}\n onValueChange={handlePageSizeChange}\n >\n <SelectTrigger className=\"h-8 w-[70px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent side=\"top\">\n {PAGE_SIZE_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center space-x-2\">\n <div className=\"flex w-[100px] items-center justify-center text-sm font-medium\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setPageIndex(Math.max(0, pageIndex - 1))} disabled={!table.getCanPreviousPage()}>\n Previous\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setPageIndex(pageIndex + 1)} disabled={!table.getCanNextPage()}>\n Next\n </Button>\n </div>\n </div>\n </div>\n )\n}\n`\n}\n","import type { FormField } from '../../types.js'\n\nexport function generateViewPage(\n pascal: string,\n kebab: string,\n fields: FormField[],\n label: string,\n includeDynamic: boolean\n): string {\n const fieldItems = fields\n .filter((f) => f.name)\n .map((f) => {\n const name = f.name!\n const lbl = f.label\n\n if (f.type === 'email') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">\n {submission.${name} ? (\n <a href={\\`mailto:\\${submission.${name}}\\`} className=\"text-primary hover:underline\">{submission.${name}}</a>\n ) : '-'}\n </p>\n </div>`\n }\n if (f.type === 'textarea') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm whitespace-pre-wrap\">{submission.${name} || '-'}</p>\n </div>`\n }\n if (f.type === 'checkbox') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">{submission.${name} ? 'Yes' : 'No'}</p>\n </div>`\n }\n if (f.type === 'date') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">{submission.${name} ? new Date(submission.${name}).toLocaleDateString() : '-'}</p>\n </div>`\n }\n if (f.type === 'url') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">\n {submission.${name} ? (\n <a href={submission.${name}} target=\"_blank\" rel=\"noopener noreferrer\" className=\"text-primary hover:underline break-all\">{submission.${name}}</a>\n ) : '-'}\n </p>\n </div>`\n }\n if (f.type === 'list' || f.type === 'multiselect') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <div className=\"text-sm\">\n {Array.isArray(submission.${name}) && submission.${name}.length > 0 ? (\n <ul className=\"list-disc list-inside space-y-1\">\n {submission.${name}.map((item: Record<string, unknown>, idx: number) => (\n <li key={idx}>{typeof item === 'string' ? item : Object.entries(item).map(([k, v]) => \\`\\${k}: \\${v}\\`).join(', ')}</li>\n ))}\n </ul>\n ) : '-'}\n </div>\n </div>`\n }\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">{submission.${name} ?? '-'}</p>\n </div>`\n })\n .join('\\n')\n\n const customFieldsSection = includeDynamic\n ? `\n {submission.customFields && Object.keys(submission.customFields).length > 0 && (\n <div className=\"space-y-3 border-t pt-4\">\n <p className=\"text-sm font-semibold text-muted-foreground\">Custom Fields</p>\n {Object.entries(submission.customFields).map(([key, value]) => (\n <div key={key} className=\"space-y-1\">\n <p className=\"text-sm font-medium capitalize\">{key.replace(/([A-Z])/g, ' $1').trim()}</p>\n <p className=\"text-sm\">{value !== null && value !== undefined ? String(value) : '-'}</p>\n </div>\n ))}\n </div>\n )}`\n : ''\n\n return `import { get${pascal}Submission } from '@cms/actions/${kebab}-form'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { ChevronLeft } from 'lucide-react'\nimport Link from 'next/link'\nimport { notFound } from 'next/navigation'\n\ninterface PageProps {\n params: Promise<{ id: string }>\n}\n\nexport default async function Page({ params }: PageProps) {\n const { id } = await params\n const submission = await get${pascal}Submission(Number.parseInt(id, 10))\n\n if (!submission) {\n notFound()\n }\n\n return (\n <>\n <PageHeader title=\"${label} Submission\" back={<Button variant=\"ghost\" size=\"icon\" asChild><Link href=\"/cms/forms/${kebab}\"><ChevronLeft /></Link></Button>} />\n <div className=\"rounded-lg border p-6 mx-6 mt-6 space-y-4\">\n${fieldItems}${customFieldsSection}\n <div className=\"space-y-1 border-t pt-4\">\n <p className=\"text-sm font-medium text-muted-foreground\">Submitted At</p>\n <p className=\"text-sm\">\n {new Date(submission.submittedAt).toLocaleString('en-US', {\n month: 'long', day: 'numeric', year: 'numeric',\n hour: 'numeric', minute: '2-digit'\n })}\n </p>\n </div>\n </div>\n </>\n )\n}\n`\n}\n","/**\n * Form navigation generator: adds form submissions entry to cms/data/navigation.ts\n * Each form gets a flat nav item with group: 'Forms'\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { FormSchema, GeneratorOptions } from '../types.js'\nimport { toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface NavItem {\n label: string\n href: string\n icon?: string\n group?: string\n}\n\n// ============================================================================\n// Parser (mirrors entity navigation generator)\n// ============================================================================\n\nfunction parseNavigationFile(content: string): { items: NavItem[]; iconImports: string[] } {\n const iconImportMatch = content.match(/import\\s*\\{([^}]+)\\}\\s*from\\s*['\"]lucide-react['\"]/)\n const iconImports: string[] = iconImportMatch\n ? iconImportMatch[1]\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s && s !== 'LucideIcon')\n : []\n\n const arrayBlock = extractTopLevelArray(content)\n if (!arrayBlock) return { items: [], iconImports }\n\n return { items: parseItemsBlock(arrayBlock), iconImports }\n}\n\nfunction extractTopLevelArray(content: string): string | null {\n const marker = content.indexOf('cmsNavigation')\n if (marker === -1) return null\n\n const eqSign = content.indexOf('=', marker)\n if (eqSign === -1) return null\n const openBracket = content.indexOf('[', eqSign)\n if (openBracket === -1) return null\n\n let depth = 0\n for (let i = openBracket; i < content.length; i++) {\n if (content[i] === '[') depth++\n if (content[i] === ']') depth--\n if (depth === 0) {\n return content.slice(openBracket + 1, i)\n }\n }\n return null\n}\n\nfunction parseItemsBlock(block: string): NavItem[] {\n const items: NavItem[] = []\n let depth = 0\n let current = ''\n let inObj = false\n\n for (const char of block) {\n if (char === '{') {\n if (depth === 0) inObj = true\n depth++\n current += char\n } else if (char === '}') {\n depth--\n current += char\n if (depth === 0 && inObj) {\n const item = parseSingleItem(current)\n if (item) items.push(item)\n current = ''\n inObj = false\n }\n } else if (inObj) {\n current += char\n }\n }\n\n return items\n}\n\nfunction parseSingleItem(str: string): NavItem | null {\n const labelMatch = str.match(/label:\\s*['\"]([^'\"]+)['\"]/)\n const hrefMatch = str.match(/href:\\s*['\"]([^'\"]+)['\"]/)\n const iconMatch = str.match(/icon:\\s*(\\w+)/)\n const groupMatch = str.match(/group:\\s*['\"]([^'\"]+)['\"]/)\n\n if (!labelMatch || !hrefMatch) return null\n\n const item: NavItem = { label: labelMatch[1], href: hrefMatch[1] }\n if (iconMatch) item.icon = iconMatch[1]\n if (groupMatch) item.group = groupMatch[1]\n\n return item\n}\n\n// ============================================================================\n// Code Generator (mirrors entity navigation generator)\n// ============================================================================\n\nfunction generateNavigationCode(items: NavItem[], iconImports: string[]): string {\n const lines: string[] = []\n\n lines.push(\"import type { LucideIcon } from 'lucide-react'\")\n lines.push(`import { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push('')\n lines.push('export interface CmsNavigationItem {')\n lines.push(' label: string')\n lines.push(' href: string')\n lines.push(' icon?: LucideIcon')\n lines.push(' group?: string')\n lines.push('}')\n lines.push('')\n lines.push('export const cmsNavigation: CmsNavigationItem[] = [')\n\n for (let i = 0; i < items.length; i++) {\n appendItem(lines, items[i], i === items.length - 1)\n }\n\n lines.push(']')\n lines.push('')\n\n return lines.join('\\n')\n}\n\nfunction appendItem(lines: string[], item: NavItem, isLast: boolean): void {\n lines.push(' {')\n lines.push(` label: '${item.label}',`)\n\n const hasMore = item.icon != null || item.group != null\n lines.push(` href: '${item.href}'${hasMore ? ',' : ''}`)\n\n if (item.icon && item.group) {\n lines.push(` icon: ${item.icon},`)\n lines.push(` group: '${item.group}'`)\n } else if (item.icon) {\n lines.push(` icon: ${item.icon}`)\n } else if (item.group) {\n lines.push(` group: '${item.group}'`)\n }\n\n lines.push(` }${isLast ? '' : ','}`)\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface FormNavigationResult {\n files: string[]\n}\n\n/**\n * Update cms/data/navigation.ts to add form under \"Forms\" group\n */\nexport function updateFormNavigation(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions = {}\n): FormNavigationResult {\n const navFilePath = path.join(cwd, cmsDir, 'data', 'navigation.ts')\n\n let items: NavItem[] = []\n let iconImports: string[] = []\n\n if (fs.existsSync(navFilePath)) {\n const content = fs.readFileSync(navFilePath, 'utf-8')\n const parsed = parseNavigationFile(content)\n items = parsed.items\n iconImports = parsed.iconImports\n }\n\n // Create form nav item with group: 'Forms'\n const kebab = toKebabCase(schema.name)\n const formHref = `/cms/forms/${kebab}`\n const existingIndex = items.findIndex((item) => item.href === formHref)\n\n const newItem: NavItem = {\n label: schema.label,\n href: formHref,\n icon: 'Inbox',\n group: 'Forms'\n }\n\n if (existingIndex >= 0) {\n if (options.force) {\n items[existingIndex] = newItem\n } else {\n return { files: [] }\n }\n } else {\n items.push(newItem)\n }\n\n // Reorganize: Dashboard first, then ungrouped alphabetical, then grouped alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => {\n if (!a.group && b.group) return -1\n if (a.group && !b.group) return 1\n if (a.group && b.group && a.group !== b.group) return a.group.localeCompare(b.group)\n return a.label.localeCompare(b.label)\n })\n\n items = [...(dashboard ? [dashboard] : []), ...others]\n\n // Ensure required icon is imported\n if (!iconImports.includes('Inbox')) {\n iconImports.push('Inbox')\n }\n iconImports.sort()\n\n // Write\n const dir = path.dirname(navFilePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n fs.writeFileSync(navFilePath, generateNavigationCode(items, iconImports), 'utf-8')\n\n return { files: [path.join(cmsDir, 'data', 'navigation.ts')] }\n}\n","/**\n * Form pipeline step 2: Server actions for form submissions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields } from '../../core/field-helpers/index.js'\nimport type { FormField, FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase, toKebabCase } from '../../utils/string.js'\n\ninterface StepResult {\n files: string[]\n}\n\n/**\n * Generate Mailchimp audience subscription code for a form\n * Auto-detects the email field unless explicitly specified in schema\n */\nfunction generateMailchimpCode(schema: FormSchema, fields: FormField[]): string {\n if (!schema.mailchimp) return ''\n\n let emailFieldName: string\n if (typeof schema.mailchimp === 'object' && schema.mailchimp.emailField) {\n emailFieldName = schema.mailchimp.emailField\n } else {\n const emailField = fields.find((f) => f.type === 'email')\n if (!emailField || !emailField.name) {\n console.warn(\n `Warning: Form \"${schema.name}\" has mailchimp enabled but no email field found. Skipping.`\n )\n return ''\n }\n emailFieldName = emailField.name\n }\n\n return `\\n // Add to Mailchimp audience (fire-and-forget, non-blocking)\n addToMailchimpAudience(data.${emailFieldName})`\n}\n\nexport function generateFormActions(\n schema: FormSchema,\n cwd: string,\n actionsDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const tableName = `${toCamelCase(formName)}Submissions`\n const pascal = toPascalCase(formName)\n const fields = getAllFormSchemaFields(schema)\n\n // Build TypeScript interface for submission data\n const dataFields = fields\n .map((f) => {\n let tsType = 'string'\n if (f.type === 'number') tsType = 'number'\n else if (f.type === 'checkbox') tsType = 'boolean'\n else if (f.type === 'multiselect') tsType = 'string[]'\n else if (f.type === 'list') {\n tsType = f.fields && f.fields.length > 0 ? 'Record<string, unknown>[]' : 'string[]'\n }\n const isReq = f.required && !f.condition\n const opt = isReq ? '' : '?'\n const nullable = isReq ? '' : ' | null'\n return ` ${f.name}${opt}: ${tsType}${nullable}`\n })\n .join('\\n')\n\n // Server-side validation for required fields\n const validation = fields\n .filter((f) => f.required && !f.condition)\n .map(\n (f) =>\n `if (!data.${f.name}) {\\n return { success: false, error: '${f.label} is required' }\\n }`\n )\n .join('\\n ')\n\n const kebab = toKebabCase(formName)\n const filePath = path.join(cwd, actionsDir, `${kebab}-form.ts`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const mailchimpImport = schema.mailchimp\n ? `\\nimport { addToMailchimpAudience } from '@cms/utils/mailchimp'`\n : ''\n const mailchimpCall = generateMailchimpCode(schema, fields)\n\n const content = `'use server'\n\nimport { desc, eq, or } from 'drizzle-orm'\nimport db from '@cms/db'\nimport { ${tableName} } from '@cms/db/schema'\nimport { getFormSettings } from '@cms/actions/form-settings'\nimport { sendWebhook } from '@cms/utils/webhook'${mailchimpImport}\n\nexport interface ${pascal}SubmissionData {\n id: number\n${dataFields}\n ipAddress: string | null\n userAgent: string | null\n submittedAt: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface ${pascal}SubmissionsResponse {\n submissions: ${pascal}SubmissionData[]\n total: number\n}\n\nexport interface Create${pascal}SubmissionInput {\n${dataFields}\n ipAddress?: string\n userAgent?: string\n}\n\nexport interface Create${pascal}SubmissionResult {\n success: boolean\n error?: string\n submission?: ${pascal}SubmissionData\n}\n\nexport interface Delete${pascal}SubmissionResult {\n success: boolean\n error?: string\n count?: number\n}\n\nexport async function get${pascal}Submissions(): Promise<${pascal}SubmissionsResponse> {\n try {\n const submissions = await db.select().from(${tableName}).orderBy(desc(${tableName}.submittedAt))\n return {\n submissions: submissions as ${pascal}SubmissionData[],\n total: submissions.length\n }\n } catch (error) {\n console.error('Error fetching ${formName} submissions:', error)\n throw new Error('Failed to fetch ${formName} submissions')\n }\n}\n\nexport async function get${pascal}Submission(id: number): Promise<${pascal}SubmissionData | null> {\n try {\n const [submission] = await db\n .select()\n .from(${tableName})\n .where(eq(${tableName}.id, id))\n .limit(1)\n return (submission as ${pascal}SubmissionData) ?? null\n } catch (error) {\n console.error(\\`Error fetching ${formName} submission \\${id}:\\`, error)\n throw new Error('Failed to fetch ${formName} submission')\n }\n}\n\nexport async function create${pascal}Submission(\n data: Create${pascal}SubmissionInput\n): Promise<Create${pascal}SubmissionResult> {\n try {\n ${validation}\n\n const [submission] = await db\n .insert(${tableName})\n .values({\n ...data,\n submittedAt: new Date().toISOString()\n })\n .returning()\n\n // Resolve notification emails from form settings or env var\n const settings = await getFormSettings('${formName}')\n const notificationEmails = settings?.notificationEmails\n ? settings.notificationEmails.split(',').map((e: string) => e.trim()).filter(Boolean)\n : process.env.NOTIFICATION_EMAIL\n ? [process.env.NOTIFICATION_EMAIL]\n : []\n\n if (notificationEmails.length > 0) {\n // TODO: Send notification email using your email provider (e.g. Resend)\n console.log(\\`[${formName}] New submission — notify: \\${notificationEmails.join(', ')}\\`)\n }\n\n // Send webhook if enabled\n if (settings?.webhookEnabled && settings?.webhookUrl) {\n sendWebhook(settings.webhookUrl, {\n form_name: '${formName}',\n submission_id: submission.id,\n ...data,\n submitted_at: (submission as ${pascal}SubmissionData).submittedAt,\n })\n }${mailchimpCall}\n\n return {\n success: true,\n submission: submission as ${pascal}SubmissionData\n }\n } catch (error) {\n console.error('Error creating ${formName} submission:', error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create ${formName} submission'\n }\n }\n}\n\nexport async function delete${pascal}Submission(id: number): Promise<Delete${pascal}SubmissionResult> {\n try {\n await db.delete(${tableName}).where(eq(${tableName}.id, id))\n return { success: true }\n } catch (error) {\n console.error(\\`Error deleting ${formName} submission \\${id}:\\`, error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete ${formName} submission'\n }\n }\n}\n\nexport async function deleteBulk${pascal}Submissions(ids: number[]): Promise<Delete${pascal}SubmissionResult> {\n try {\n if (ids.length === 0) return { success: true, count: 0 }\n await db.delete(${tableName}).where(\n or(...ids.map(id => eq(${tableName}.id, id)))\n )\n return { success: true, count: ids.length }\n } catch (error) {\n console.error(\\`Error bulk deleting ${formName} submissions:\\`, error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to bulk delete ${formName} submissions'\n }\n }\n}\n\nexport async function export${pascal}SubmissionsCSV(): Promise<string> {\n const { submissions } = await get${pascal}Submissions()\n if (submissions.length === 0) return ''\n const headers = Object.keys(submissions[0]).join(',')\n const rows = submissions.map((sub) =>\n Object.values(sub)\n .map((val: unknown) => {\n if (val === null || val === undefined) return ''\n const str = String(val)\n if (str.includes(',') || str.includes('\"') || str.includes('\\\\n')) {\n return \\`\"\\${str.replace(/\"/g, '\"\"')}\"\\`\n }\n return str\n })\n .join(',')\n )\n return [headers, ...rows].join('\\\\n')\n}\n\nexport async function export${pascal}SubmissionsJSON(): Promise<string> {\n const { submissions } = await get${pascal}Submissions()\n return JSON.stringify(submissions, null, 2)\n}\n`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Multi-step wizard form component generator\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields, getStepFieldNames } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toKebabCase } from '../../utils/string.js'\nimport {\n type StepResult,\n resolveUiImport,\n escapeJsx,\n renderFieldsJSX,\n buildZodFields,\n buildDefaultValues,\n buildFieldArrayDecls,\n buildWatchDecls,\n getListFields,\n} from './form-component-shared.js'\n\nexport function generateMultiStepForm(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const kebab = toKebabCase(formName)\n const steps = schema.steps!\n\n const filePath = path.join(cwd, cmsDir, 'components', 'forms', `${kebab}-form.tsx`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n // All fields flattened (for Zod schema + defaults)\n const allFields = getAllFormSchemaFields(schema)\n const zodFields = buildZodFields(allFields)\n const defaults = buildDefaultValues(allFields)\n\n // List fields and watch declarations are global\n const listFields = getListFields(allFields)\n const hasListFields = listFields.length > 0\n const { setup: watchSetup } = buildWatchDecls(allFields)\n\n const rhfImport = hasListFields\n ? `import { useFieldArray, useForm } from 'react-hook-form'`\n : `import { useForm } from 'react-hook-form'`\n const fieldArraySetup = hasListFields ? `\\n${buildFieldArrayDecls(listFields)}\\n` : ''\n\n // Build STEPS constant\n const stepsConst = buildStepsConstant(steps, schema)\n\n // Build per-step content blocks\n const stepContentBlocks = steps\n .map((step, index) => {\n const fieldsJSX = renderFieldsJSX(step.fields)\n return ` {currentStep === ${index} && (\\n <>\\n${fieldsJSX}\\n </>\\n )}`\n })\n .join('\\n')\n\n const submitText = schema.submitButtonText || 'Submit'\n const successMessage = escapeJsx(schema.successMessage || 'Form submitted successfully!')\n\n // Resolve UI imports\n const hasRadio = allFields.some((f) => f.type === 'radio')\n const hasFileUpload = allFields.some((f) => f.type === 'file' || f.type === 'upload')\n const buttonImport = resolveUiImport(cwd, 'button')\n const formImport = resolveUiImport(cwd, 'form')\n const inputImport = resolveUiImport(cwd, 'input')\n const textareaImport = resolveUiImport(cwd, 'textarea')\n const selectImport = resolveUiImport(cwd, 'select')\n const radioGroupImport = resolveUiImport(cwd, 'radio-group')\n const mediaUploadImport = resolveUiImport(cwd, 'media-upload-field')\n\n const content = buildComponentSource({\n pascal,\n kebab,\n rhfImport,\n hasRadio,\n hasFileUpload,\n hasListFields,\n buttonImport,\n formImport,\n inputImport,\n textareaImport,\n selectImport,\n radioGroupImport,\n mediaUploadImport,\n zodFields,\n defaults,\n stepsConst,\n fieldArraySetup,\n watchSetup,\n stepContentBlocks,\n submitText,\n successMessage,\n })\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n\nfunction buildStepsConstant(\n steps: NonNullable<FormSchema['steps']>,\n schema: FormSchema\n): string {\n const entries = steps.map((step) => {\n const fieldNames = getStepFieldNames(step)\n const fieldsStr = fieldNames.map((n) => `'${n}'`).join(', ')\n const desc = step.description ? `, description: '${escapeQuotes(step.description)}'` : ''\n return ` { name: '${step.name}', label: '${escapeQuotes(step.label)}'${desc}, fields: [${fieldsStr}] }`\n })\n return `const STEPS = [\\n${entries.join(',\\n')}\\n]`\n}\n\nfunction escapeQuotes(str: string): string {\n return str.replace(/'/g, \"\\\\'\")\n}\n\ninterface ComponentParts {\n pascal: string\n kebab: string\n rhfImport: string\n hasRadio: boolean\n hasFileUpload: boolean\n hasListFields: boolean\n buttonImport: string\n formImport: string\n inputImport: string\n textareaImport: string\n selectImport: string\n radioGroupImport: string\n mediaUploadImport: string\n zodFields: string\n defaults: string\n stepsConst: string\n fieldArraySetup: string\n watchSetup: string\n stepContentBlocks: string\n submitText: string\n successMessage: string\n}\n\nfunction buildComponentSource(p: ComponentParts): string {\n const queryClientImport = p.hasFileUpload\n ? `\\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'`\n : ''\n const queryClientSetup = p.hasFileUpload\n ? `\\nconst queryClient = new QueryClient()\\n`\n : ''\n const formComponentDecl = p.hasFileUpload ? `function ${p.pascal}FormInner` : `export function ${p.pascal}Form`\n const exportWrapper = p.hasFileUpload\n ? `\\nexport function ${p.pascal}Form() {\n return (\n <QueryClientProvider client={queryClient}>\n <${p.pascal}FormInner />\n </QueryClientProvider>\n )\n}\\n`\n : ''\n\n return `'use client'\n\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { ChevronLeft, ChevronRight${p.hasListFields ? ', Trash2' : ''} } from 'lucide-react'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport { useState } from 'react'\n${p.rhfImport}\nimport { z } from 'zod/v3'${queryClientImport}\nimport { create${p.pascal}Submission } from '@cms/actions/${p.kebab}-form'\nimport { Button } from '${p.buttonImport}'\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '${p.formImport}'\nimport { Input } from '${p.inputImport}'${p.hasFileUpload ? `\\nimport { MediaUploadField } from '${p.mediaUploadImport}'` : ''}\n${p.hasRadio ? `import { RadioGroup, RadioGroupItem } from '${p.radioGroupImport}'\\n` : ''}\nimport { Textarea } from '${p.textareaImport}'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '${p.selectImport}'\n\nconst formSchema = z.object({\n${p.zodFields}\n})\n\ntype FormValues = z.infer<typeof formSchema>\n${queryClientSetup}\n${p.stepsConst}\n\n${formComponentDecl}() {\n const [currentStep, setCurrentStep] = useQueryState('step', parseAsInteger.withDefault(0))\n const [submitted, setSubmitted] = useState(false)\n const [submitting, setSubmitting] = useState(false)\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema),\n mode: 'onSubmit',\n defaultValues: {\n${p.defaults}\n },\n })\n\n${p.fieldArraySetup}${p.watchSetup}\n async function handleNext() {\n const stepFields = STEPS[currentStep].fields as (keyof FormValues)[]\n const values = form.getValues()\n form.clearErrors(stepFields)\n let isValid = true\n for (const fieldName of stepFields) {\n const fieldSchema = formSchema.shape[fieldName]\n if (!fieldSchema) continue\n const result = fieldSchema.safeParse(values[fieldName])\n if (!result.success) {\n form.setError(fieldName, { type: 'validate', message: result.error.issues[0].message })\n isValid = false\n }\n }\n if (isValid) {\n setCurrentStep(currentStep + 1)\n }\n }\n\n function handleBack() {\n setCurrentStep(currentStep - 1)\n }\n\n async function onSubmit(values: FormValues) {\n setSubmitting(true)\n try {\n const result = await create${p.pascal}Submission(values)\n if (result.success) {\n setSubmitted(true)\n } else {\n form.setError('root', { message: result.error || 'Something went wrong' })\n }\n } catch {\n form.setError('root', { message: 'Something went wrong. Please try again.' })\n } finally {\n setSubmitting(false)\n }\n }\n\n if (submitted) {\n return (\n <div className=\"rounded-lg border p-6 text-center\">\n <h3 className=\"text-lg font-semibold\">Thank you!</h3>\n <p className=\"mt-2 text-muted-foreground\">${p.successMessage}</p>\n </div>\n )\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n {/* Step header */}\n <div>\n <h3 className=\"text-lg font-semibold\">{STEPS[currentStep].label}</h3>\n {'description' in STEPS[currentStep] && STEPS[currentStep].description && (\n <p className=\"text-sm text-muted-foreground mt-1\">{STEPS[currentStep].description}</p>\n )}\n </div>\n\n {/* Step content */}\n <div key={currentStep} className=\"animate-in fade-in duration-300 space-y-6\">\n${p.stepContentBlocks}\n </div>\n\n {form.formState.errors.root && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.root.message}</p>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleBack}\n disabled={currentStep === 0}\n >\n <ChevronLeft className=\"mr-2 h-4 w-4\" />\n Back\n </Button>\n {currentStep < STEPS.length - 1 ? (\n <Button type=\"button\" onClick={handleNext}>\n Next\n <ChevronRight className=\"ml-2 h-4 w-4\" />\n </Button>\n ) : (\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? 'Submitting...' : '${p.submitText}'}\n </Button>\n )}\n </div>\n </form>\n </Form>\n )\n}\n${exportWrapper}`\n}\n","/**\n * Shared helpers for form component generation\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { formFieldToZodType } from '../../core/type-mappers/index.js'\nimport type { FormField } from '../../types.js'\nimport { singularize } from '../../utils/string.js'\n\nexport interface StepResult {\n files: string[]\n}\n\n/**\n * Check if a shadcn UI component exists in the user's project.\n * Returns `@/components/ui/<name>` if found, otherwise `@cms/components/ui/<name>`.\n */\nexport function resolveUiImport(cwd: string, componentName: string): string {\n const locations = ['components/ui', 'src/components/ui']\n for (const loc of locations) {\n if (\n fs.existsSync(path.join(cwd, loc, `${componentName}.tsx`)) ||\n fs.existsSync(path.join(cwd, loc, `${componentName}.ts`))\n ) {\n return `@/components/ui/${componentName}`\n }\n }\n return `@cms/components/ui/${componentName}`\n}\n\n/** Escape text for safe use in JSX content */\nexport function escapeJsx(str: string): string {\n return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')\n}\n\n/** Flatten form fields, resolving groups and skipping dynamic fields */\nexport function flattenFormFields(fields: FormField[]): FormField[] {\n return fields.flatMap((field) => {\n if (field.type === 'dynamicFields') return []\n if (field.type === 'group' && field.fields) return flattenFormFields(field.fields)\n return field.type === 'group' ? [] : [field]\n })\n}\n\n/** Build Zod schema field entries from form fields */\nexport function buildZodFields(fields: FormField[]): string {\n return fields\n .filter((f) => f.name)\n .map((f) => ` ${f.name}: ${formFieldToZodType(f)}`)\n .join(',\\n')\n}\n\n/** Build default value entries from form fields */\nexport function buildDefaultValues(fields: FormField[]): string {\n return fields\n .filter((f) => f.name)\n .map((f) => {\n if (f.type === 'checkbox') return ` ${f.name}: false`\n if (f.type === 'number') return ` ${f.name}: undefined`\n if (f.type === 'multiselect' || f.type === 'list') return ` ${f.name}: []`\n if (f.type === 'radio' && f.defaultValue !== undefined) return ` ${f.name}: '${f.defaultValue}'`\n if (f.type === 'select' || f.type === 'radio') return ` ${f.name}: undefined`\n if (f.defaultValue !== undefined) return ` ${f.name}: '${f.defaultValue}'`\n return ` ${f.name}: ''`\n })\n .join(',\\n')\n}\n\n/** Build useFieldArray declarations for list fields */\nexport function buildFieldArrayDecls(listFields: FormField[]): string {\n return listFields\n .map(\n (f) =>\n ` const ${f.name}FieldArray = useFieldArray({ control: form.control, name: '${f.name}' })`\n )\n .join('\\n')\n}\n\n/** Build watch variable declarations for showWhen fields */\nexport function buildWatchDecls(fields: FormField[]): { setup: string; hasWatch: boolean } {\n const watchFields = new Set<string>()\n for (const f of fields) {\n if (f.showWhen) {\n watchFields.add(f.showWhen.field)\n }\n }\n if (watchFields.size === 0) return { setup: '', hasWatch: false }\n const decls = Array.from(watchFields)\n .map((wf) => ` const ${wf}Value = form.watch('${wf}')`)\n .join('\\n')\n return { setup: `\\n${decls}\\n`, hasWatch: true }\n}\n\n/** Get list fields that need useFieldArray */\nexport function getListFields(fields: FormField[]): FormField[] {\n return fields.filter(\n (f) => f.name && f.type === 'list' && f.fields && f.fields.length > 0\n )\n}\n\n/**\n * Render an array of form fields to JSX, preserving group layout.\n * Group fields render as a responsive grid wrapper; other fields render normally.\n */\nexport function renderFieldsJSX(fields: FormField[]): string {\n return fields\n .filter((f) => !f.hidden)\n .map((f) => {\n if (f.type === 'dynamicFields') return ''\n if (f.type === 'group' && f.fields) {\n const cols = f.columns || 2\n const innerJSX = renderFieldsJSX(f.fields)\n const groupJSX = ` <div className=\"grid grid-cols-1 md:grid-cols-${cols} gap-4\">\\n${innerJSX}\\n </div>`\n return f.showWhen ? wrapShowWhen(f, groupJSX) : groupJSX\n }\n if (!f.name) return ''\n return wrapShowWhen(f, generateFieldJSX(f))\n })\n .filter(Boolean)\n .join('\\n\\n')\n}\n\n/** Wrap field JSX with showWhen conditional if applicable */\nexport function wrapShowWhen(field: FormField, jsx: string): string {\n if (!field.showWhen) return jsx\n const watchVar = `${field.showWhen.field}Value`\n const { value } = field.showWhen\n if (Array.isArray(value)) {\n const vals = value.map((v) => `'${v}'`).join(', ')\n return ` {[${vals}].includes(${watchVar} as string) && (\\n${jsx}\\n )}`\n }\n return ` {${watchVar} === '${value}' && (\\n${jsx}\\n )}`\n}\n\n/** Generate JSX for a single form field */\nexport function generateFieldJSX(field: FormField): string {\n const name = field.name || ''\n const label = escapeJsx(field.label)\n const placeholder = field.placeholder || ''\n const hint = field.hint || ''\n\n const hintJSX = hint ? `\\n <FormDescription>${escapeJsx(hint)}</FormDescription>` : ''\n const hintPlainJSX = hint ? `\\n <p className=\"text-sm text-muted-foreground\">${escapeJsx(hint)}</p>` : ''\n const requiredStar = field.required ? ' <span className=\"text-destructive\">*</span>' : ''\n\n switch (field.type) {\n case 'textarea':\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <Textarea placeholder=\"${placeholder}\" {...field} />\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n\n case 'radio':\n if (field.options && field.options.length > 0) {\n const radioItems = field.options\n .map(\n (opt) =>\n ` <FormLabel htmlFor=\"${name}-${opt.value}\" className=\"flex items-center space-x-2 text-sm font-medium leading-none\">\n <RadioGroupItem value=\"${opt.value}\" id=\"${name}-${opt.value}\" />\n <span>${escapeJsx(opt.label)}</span>\n </FormLabel>`\n )\n .join('\\n')\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem className=\"space-y-3\">\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <RadioGroup onValueChange={field.onChange} defaultValue={field.value} className=\"flex items-center space-x-2\">\n${radioItems}\n </RadioGroup>\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n }\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n\n case 'select':\n if (field.options && field.options.length > 0) {\n const optionItems = field.options\n .map(\n (opt) =>\n ` <SelectItem value=\"${opt.value}\">${escapeJsx(opt.label)}</SelectItem>`\n )\n .join('\\n')\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <Select onValueChange={field.onChange} defaultValue={field.value}>\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder=\"${placeholder || 'Select...'}\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n${optionItems}\n </SelectContent>\n </Select>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n }\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n\n case 'checkbox':\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-start space-x-3 space-y-0\">\n <FormControl>\n <input\n type=\"checkbox\"\n checked={field.value}\n onChange={field.onChange}\n className=\"mt-1\"\n />\n </FormControl>\n <div className=\"space-y-1 leading-none\">\n <FormLabel>${label}${requiredStar}</FormLabel>${hintJSX}\n <FormMessage />\n </div>\n </FormItem>\n )}\n />`\n\n case 'email':\n return generateTextFieldJSX(name, label, placeholder || 'email@example.com', hintJSX, requiredStar, 'email')\n\n case 'number':\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'number')\n\n case 'date':\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'date')\n\n case 'url':\n return generateTextFieldJSX(name, label, placeholder || 'https://', hintJSX, requiredStar, 'url')\n\n case 'phone':\n return generateTextFieldJSX(name, label, placeholder || '+1 (555) 000-0000', hintJSX, requiredStar, 'tel')\n\n case 'file':\n case 'upload':\n return generateFileUploadFieldJSX(field, name, label, hintJSX, requiredStar)\n\n case 'list':\n return generateListFieldJSX(field, name, label, hintPlainJSX, requiredStar)\n\n default:\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n }\n}\n\nexport function generateTextFieldJSX(\n name: string,\n label: string,\n placeholder: string,\n hintJSX: string,\n requiredStar: string,\n inputType: string\n): string {\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <Input type=\"${inputType}\" placeholder=\"${placeholder}\" {...field} />\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n}\n\nfunction generateFileUploadFieldJSX(\n field: FormField,\n name: string,\n label: string,\n hintJSX: string,\n requiredStar: string\n): string {\n const accept = field.accept || '*/*'\n const maxSize = field.maxFileSize || 10\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <MediaUploadField\n value={field.value}\n onChange={field.onChange}\n onBlur={field.onBlur}\n accept=\"${accept}\"\n maxSizeInMB={${maxSize}}\n label=\"\"\n />\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n}\n\nfunction generateListFieldJSX(\n field: FormField,\n name: string,\n label: string,\n hintJSX: string,\n requiredStar: string\n): string {\n if (!field.fields || field.fields.length === 0) {\n return generateTextFieldJSX(name, label, field.placeholder || '', hintJSX, requiredStar, 'text')\n }\n\n const singularLabel = singularize(label)\n\n const nestedFieldsJSX = field.fields\n .map((nf) => {\n const nfLabel = escapeJsx(nf.label || nf.name || '')\n const nfPlaceholder = nf.placeholder || ''\n\n if (nf.type === 'select' && nf.options && nf.options.length > 0) {\n const selectItems = nf.options\n .map(\n (opt) =>\n ` <SelectItem value=\"${opt.value}\">${escapeJsx(opt.label)}</SelectItem>`\n )\n .join('\\n')\n return ` <FormField\n control={form.control}\n name={\\`${name}.\\${index}.${nf.name}\\`}\n render={({ field: formField }) => (\n <FormItem className=\"flex-1\">\n <FormLabel>${nfLabel}</FormLabel>\n <Select onValueChange={formField.onChange} defaultValue={formField.value}>\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder=\"${nf.placeholder || 'Select...'}\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n${selectItems}\n </SelectContent>\n </Select>\n <FormMessage />\n </FormItem>\n )}\n />`\n }\n\n return ` <FormField\n control={form.control}\n name={\\`${name}.\\${index}.${nf.name}\\`}\n render={({ field: formField }) => (\n <FormItem className=\"flex-1\">\n <FormLabel>${nfLabel}</FormLabel>\n <FormControl>\n <Input type=\"text\" placeholder=\"${nfPlaceholder}\" {...formField} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />`\n })\n .join('\\n')\n\n const defaultObj = field.fields\n .map((nf) => {\n if (nf.type === 'select' || nf.type === 'radio') return `${nf.name}: undefined`\n if (nf.type === 'checkbox') return `${nf.name}: false`\n if (nf.type === 'number') return `${nf.name}: undefined`\n return `${nf.name}: ''`\n })\n .join(', ')\n\n return ` <div className=\"space-y-4\">\n <FormLabel className=\"text-sm font-medium leading-none\">${label}${requiredStar}</FormLabel>${hintJSX}\n {${name}FieldArray.fields.map((item, index) => (\n <div key={item.id} className=\"relative rounded-lg border p-4\">\n <button\n type=\"button\"\n onClick={() => ${name}FieldArray.remove(index)}\n 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\"\n >\n <Trash2 className=\"h-4 w-4\" />\n <span className=\"sr-only\">Remove</span>\n </button>\n <div className=\"space-y-4 pr-8\">\n${nestedFieldsJSX}\n </div>\n </div>\n ))}\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => ${name}FieldArray.append({ ${defaultObj} })}\n >\n Add ${singularLabel}\n </Button>\n </div>`\n}\n","/**\n * Drizzle ORM type mappings for schema fields and form fields\n */\n\nimport type { FormField, SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nexport const DRIZZLE_DEFAULTS = {\n VARCHAR_LENGTH: 255,\n DECIMAL_PRECISION: 10,\n DECIMAL_SCALE: 2\n} as const\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\n/**\n * Check if a field name suggests it's a URL field\n */\nfunction isUrlField(fieldName: string): boolean {\n const urlKeywords = ['url', 'link', 'href', 'website', 'avatar', 'logo', 'thumbnail']\n const lowerName = fieldName.toLowerCase()\n return urlKeywords.some((keyword) => lowerName.includes(keyword))\n}\n\n// ============================================================================\n// Schema Field → Drizzle Type (for database generator)\n// ============================================================================\n\n/**\n * Map a schema field type to Drizzle ORM column type\n * @param field - The schema field\n * @param requiredImports - Set to track which Drizzle imports are needed\n * @returns The Drizzle column type expression\n */\nexport function toDrizzleType(field: SchemaField, requiredImports: Set<string>): string {\n switch (field.type) {\n case 'serial':\n requiredImports.add('serial')\n return 'serial()'\n case 'string':\n case 'varchar':\n if (isUrlField(field.name) && !field.length) {\n requiredImports.add('text')\n return 'text()'\n }\n requiredImports.add('varchar')\n return field.length\n ? `varchar({ length: ${field.length} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'image':\n case 'video':\n case 'media':\n requiredImports.add('text')\n return 'text()'\n case 'text':\n case 'markdown':\n case 'richtext':\n requiredImports.add('text')\n return 'text()'\n case 'number':\n requiredImports.add('integer')\n return 'integer()'\n case 'decimal':\n requiredImports.add('decimal')\n if (field.precision && field.scale) {\n return `decimal({ precision: ${field.precision}, scale: ${field.scale} })`\n }\n return `decimal({ precision: ${DRIZZLE_DEFAULTS.DECIMAL_PRECISION}, scale: ${DRIZZLE_DEFAULTS.DECIMAL_SCALE} })`\n case 'boolean':\n requiredImports.add('boolean')\n return 'boolean()'\n case 'timestamp':\n requiredImports.add('timestamp')\n return \"timestamp({ precision: 3, mode: 'string' })\"\n case 'date':\n requiredImports.add('date')\n return \"date({ mode: 'string' })\"\n case 'time':\n case 'select':\n case 'icon':\n requiredImports.add('varchar')\n return field.length\n ? `varchar({ length: ${field.length} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'curriculum':\n requiredImports.add('jsonb')\n return `jsonb().$type<{ mode: 'sequential'; items: Array<{ title?: string; description?: string }> } | { mode: 'weekly'; weeks: Array<{ weekNumber: number; weekTitle?: string; weekDescription?: string; durationHours?: number; items: Array<{ title?: string; description?: string }> }> }>()`\n case 'list':\n requiredImports.add('jsonb')\n if (field.fields && field.fields.length > 0) {\n const nestedType = buildNestedListType(field.fields)\n return `jsonb().$type<Array<{ ${nestedType} }>>()`\n }\n return 'jsonb().$type<string[]>()'\n case 'relationship':\n requiredImports.add('integer')\n return 'integer()'\n default:\n requiredImports.add('text')\n return 'text()'\n }\n}\n\n/**\n * Build nested type string for list fields with nested fields\n */\nfunction buildNestedListType(fields: SchemaField[]): string {\n return fields\n .flatMap((f) => {\n let type: string\n if (f.type === 'list' && f.fields && f.fields.length > 0) {\n const innerType = f.fields\n .map((nf) => {\n let nfType: string\n if (nf.type === 'boolean') {\n nfType = 'boolean'\n } else if (nf.type === 'number' || nf.type === 'decimal') {\n nfType = 'number'\n } else {\n nfType = 'string'\n }\n return `${quotePropertyName(nf.name)}?: ${nfType}`\n })\n .join('; ')\n type = `Array<{ ${innerType} }>`\n } else if (f.type === 'list') {\n type = 'string[]'\n } else if (f.type === 'number' || f.type === 'decimal') {\n type = 'number'\n } else if (f.type === 'boolean') {\n type = 'boolean'\n } else {\n type = 'string'\n }\n const result = [`${quotePropertyName(f.name)}?: ${type}`]\n if (f.hasIcon) {\n result.push(`${quotePropertyName(`${f.name}Icon`)}?: string`)\n }\n return result\n })\n .join('; ')\n}\n\n// ============================================================================\n// Form Field → Drizzle Type (for form-pipeline)\n// ============================================================================\n\n/**\n * Map a form field type to Drizzle ORM column type\n * @param field - The form field\n * @param requiredImports - Set to track which Drizzle imports are needed\n * @returns The Drizzle column type expression\n */\nexport function formFieldToDrizzleType(field: FormField, requiredImports: Set<string>): string {\n switch (field.type) {\n case 'text':\n requiredImports.add('varchar')\n return field.maxLength\n ? `varchar({ length: ${field.maxLength} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'textarea':\n requiredImports.add('text')\n return 'text()'\n case 'email':\n requiredImports.add('varchar')\n return `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'phone':\n requiredImports.add('varchar')\n return 'varchar({ length: 50 })'\n case 'number':\n requiredImports.add('integer')\n return 'integer()'\n case 'url':\n requiredImports.add('varchar')\n return 'varchar({ length: 500 })'\n case 'date':\n requiredImports.add('date')\n return \"date({ mode: 'string' })\"\n case 'select':\n case 'radio':\n case 'timezone':\n requiredImports.add('varchar')\n return `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'checkbox':\n requiredImports.add('boolean')\n return 'boolean()'\n case 'multiselect':\n requiredImports.add('jsonb')\n return 'jsonb().$type<string[]>()'\n case 'list':\n requiredImports.add('jsonb')\n if (field.fields && field.fields.length > 0) {\n return 'jsonb().$type<Record<string, unknown>[]>()'\n }\n return 'jsonb().$type<string[]>()'\n case 'file':\n case 'upload':\n requiredImports.add('text')\n return 'text()'\n default:\n requiredImports.add('text')\n return 'text()'\n }\n}\n","/**\n * Zod validation type mappings for schema fields and form fields\n */\n\nimport type { FormField, SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\n\n// ============================================================================\n// Schema Field → Zod Type (for form validation)\n// ============================================================================\n\n/**\n * Map a schema field type to Zod validation schema\n * @param field - The schema field\n * @returns The Zod schema expression as a string\n */\nexport function toZodType(field: SchemaField): string {\n const label = field.label || field.name\n\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return field.required\n ? `z.number({ message: '${label} is required' })`\n : 'z.number().optional()'\n case 'boolean':\n return 'z.boolean()'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext': {\n if (field.name.toLowerCase().includes('email')) {\n const base = field.required\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().email('Please enter a valid email address').optional()`\n return field.length ? `${base}.max(${field.length})` : base\n }\n const base = field.required ? `z.string().min(1, '${label} is required')` : 'z.string()'\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'date':\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n return `z.string().min(1, '${label} is required')`\n case 'timestamp':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'image':\n case 'video':\n case 'media': {\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n const mediaType =\n field.type === 'image' ? 'an image' : field.type === 'video' ? 'a video' : 'media'\n const base = `z.string().min(1, 'Please upload ${mediaType} for ${label}').url('Please provide a valid ${field.type} URL')`\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'list':\n return buildZodListType(field, label)\n case 'select': {\n if (field.options && field.options.length > 0) {\n const values = field.options.map((opt) => `'${opt.value}'`).join(', ')\n const valuesArray = `[${values}] as const`\n return field.required\n ? `z.string().min(1, '${label} is required').refine((val) => (${valuesArray} as readonly string[]).includes(val), { message: 'Invalid ${label}' })`\n : `z.string().refine((val) => !val || (${valuesArray} as readonly string[]).includes(val), { message: 'Invalid ${label}' }).optional()`\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'icon':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'relationship': {\n if (field.multiple) {\n return field.required\n ? `z.array(z.number()).min(1, '${label} is required')`\n : 'z.array(z.number()).optional()'\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'curriculum':\n return `z.object({\n mode: z.enum(['sequential', 'weekly']),\n items: z.array(z.object({\n title: z.string().max(255).optional(),\n description: z.string().max(500).optional()\n })).max(50),\n weeks: z.array(z.object({\n weekNumber: z.number().int().positive(),\n weekTitle: z.string().max(100).optional(),\n weekDescription: z.string().max(1000).optional(),\n durationHours: z.number().positive().optional(),\n items: z.array(z.object({\n title: z.string().max(255).optional(),\n description: z.string().max(500).optional()\n })).max(20)\n })).max(20)\n }).optional()`\n default:\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n\n/**\n * Build Zod type for list fields\n */\nfunction buildZodListType(field: SchemaField, label: string): string {\n if (field.fields && field.fields.length > 0) {\n const nestedFields = field.fields\n .flatMap((nestedField) => {\n const defs: string[] = []\n const nestedZodType = toZodType(nestedField)\n const alreadyOptional = nestedZodType.includes('.optional()')\n let nestedDef = ` ${quotePropertyName(nestedField.name)}: ${nestedZodType}`\n if (!nestedField.required && !alreadyOptional) {\n nestedDef += '.optional()'\n }\n defs.push(nestedDef)\n if (nestedField.hasIcon) {\n defs.push(` ${quotePropertyName(`${nestedField.name}Icon`)}: z.string().optional()`)\n }\n return defs\n })\n .join(',\\n')\n const objectSchema = `z.object({\\n${nestedFields}\\n })`\n const arraySchema = field.maxItems\n ? `z.array(${objectSchema}).max(${field.maxItems}, '${label} cannot exceed ${field.maxItems} items')`\n : `z.array(${objectSchema})`\n return field.required\n ? `${arraySchema}.min(1, '${label} must have at least one item')`\n : `${arraySchema}.optional()`\n }\n if (field.items?.type === 'string' || field.items?.type === 'varchar') {\n const itemSchema = field.items.length ? `z.string().max(${field.items.length})` : 'z.string()'\n const arraySchema = field.maxItems\n ? `z.array(${itemSchema}).max(${field.maxItems}, '${label} cannot exceed ${field.maxItems} items')`\n : `z.array(${itemSchema})`\n return field.required\n ? `${arraySchema}.min(1, '${label} must have at least one item')`\n : `${arraySchema}.optional()`\n }\n return field.required\n ? `z.array(z.string()).min(1, '${label} must have at least one item')`\n : 'z.array(z.string()).optional()'\n}\n\n// ============================================================================\n// Form Field → Zod Type (for form-pipeline)\n// ============================================================================\n\nexport interface FormFieldZodOptions {\n treatAsOptional?: boolean\n}\n\n/**\n * Map a form field type to Zod validation schema\n * @param field - The form field\n * @param options - Options for generating the zod type\n * @returns The Zod schema expression as a string\n */\nexport function formFieldToZodType(field: FormField, options: FormFieldZodOptions = {}): string {\n const label = field.label\n const isRequired = field.required && !options.treatAsOptional\n\n switch (field.type) {\n case 'text': {\n let zodType = isRequired ? `z.string().min(1, '${label} is required')` : 'z.string()'\n if (field.minLength) {\n zodType += `.min(${field.minLength}, '${label} must be at least ${field.minLength} characters')`\n }\n if (field.maxLength) {\n zodType += `.max(${field.maxLength}, '${label} must be at most ${field.maxLength} characters')`\n }\n if (field.pattern) {\n zodType += `.regex(new RegExp('${field.pattern}'), 'Invalid ${label} format')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'textarea': {\n let zodType = isRequired ? `z.string().min(1, '${label} is required')` : 'z.string()'\n if (field.minLength) {\n zodType += `.min(${field.minLength}, '${label} must be at least ${field.minLength} characters')`\n }\n if (field.maxLength) {\n zodType += `.max(${field.maxLength}, '${label} must be at most ${field.maxLength} characters')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'email':\n return isRequired\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || z.string().email().safeParse(val).success, { message: 'Please enter a valid email address' })`\n case 'phone': {\n const pattern =\n field.pattern || '^[+]?[(]?[0-9]{1,4}[)]?[-\\\\s\\\\.]?[(]?[0-9]{1,4}[)]?[-\\\\s\\\\.]?[0-9]{1,9}$'\n return isRequired\n ? `z.string().min(1, '${label} is required').regex(new RegExp('${pattern}'), 'Please enter a valid phone number')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || new RegExp('${pattern}').test(val), { message: 'Please enter a valid phone number' })`\n }\n case 'number': {\n let zodType = isRequired ? `z.number({ message: '${label} is required' })` : 'z.number()'\n if (field.min !== undefined) {\n zodType += `.min(${field.min}, '${label} must be at least ${field.min}')`\n }\n if (field.max !== undefined) {\n zodType += `.max(${field.max}, '${label} must be at most ${field.max}')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'url':\n return isRequired\n ? `z.string().min(1, '${label} is required').url('Please enter a valid URL')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || z.string().url().safeParse(val).success, { message: 'Please enter a valid URL' })`\n case 'date':\n return isRequired\n ? `z.string().min(1, '${label} is required')`\n : 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n case 'select':\n case 'radio':\n if (field.options && field.options.length > 0) {\n const values = field.options.map((opt) => `'${opt.value}'`).join(', ')\n return isRequired\n ? `z.enum([${values}], { message: '${label} is required' })`\n : `z.enum([${values}]).optional()`\n }\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'checkbox':\n return isRequired\n ? `z.boolean().refine(val => val === true, { message: '${label} is required' })`\n : 'z.boolean().optional()'\n case 'multiselect':\n return isRequired\n ? `z.array(z.string()).min(1, '${label} is required')`\n : 'z.array(z.string()).optional()'\n case 'timezone':\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nestedFields = field.fields\n .map((f) => `${f.name}: ${formFieldToZodType(f, options)}`)\n .join(', ')\n return isRequired\n ? `z.array(z.object({ ${nestedFields} })).min(1, '${label} is required')`\n : `z.array(z.object({ ${nestedFields} })).optional()`\n }\n return isRequired\n ? `z.array(z.string()).min(1, '${label} is required')`\n : 'z.array(z.string()).optional()'\n case 'file':\n case 'upload':\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n default:\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n","/**\n * TypeScript, form field, and SQL type mappings for schema fields\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, quotePropertyName } from '../../utils/string.js'\nimport { DRIZZLE_DEFAULTS } from './drizzle.js'\n\n// ============================================================================\n// Schema Field → TypeScript Type (for actions generator)\n// ============================================================================\n\n/**\n * Map a schema field type to TypeScript type\n * @param field - The schema field\n * @param mode - 'input' for form input types, 'output' for database output types\n * @returns The TypeScript type as a string\n */\nexport function toTypeScriptType(field: SchemaField, mode: 'input' | 'output' = 'output'): string {\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return 'number'\n case 'boolean':\n return 'boolean'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext':\n case 'date':\n case 'time':\n case 'timestamp':\n case 'image':\n case 'video':\n case 'media':\n case 'icon':\n case 'select':\n return 'string'\n case 'relationship':\n if (mode === 'input') {\n return field.multiple ? 'number[]' : 'string'\n }\n if (field.relationship) {\n const relationshipSingular = singularize(field.relationship)\n const relationshipPascal = toPascalCase(relationshipSingular)\n return field.multiple ? `${relationshipPascal}Data[]` : `${relationshipPascal}Data | null`\n }\n return 'string'\n case 'group':\n if (field.fields && field.fields.length > 0) {\n const groupType = field.fields\n .map((f) => {\n const type = toTypeScriptType(f, mode)\n return `${quotePropertyName(f.name)}?: ${type}`\n })\n .join('; ')\n return `{ ${groupType} }`\n }\n return 'Record<string, unknown>'\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nestedType = field.fields\n .flatMap((f) => {\n const type = toTypeScriptType(f, 'input')\n const fields = [`${quotePropertyName(f.name)}?: ${type}`]\n if (f.hasIcon) {\n fields.push(`${quotePropertyName(`${f.name}Icon`)}?: string`)\n }\n return fields\n })\n .join('; ')\n return `Array<{ ${nestedType} }>`\n }\n return 'string[]'\n case 'curriculum':\n return '{ mode: \"sequential\" | \"weekly\"; items: Array<{ title?: string; description?: string }>; weeks: Array<{ weekNumber: number; weekTitle?: string; weekDescription?: string; durationHours?: number; items: Array<{ title?: string; description?: string }> }> }'\n default:\n return 'string'\n }\n}\n\n// ============================================================================\n// Schema Field → Form Field Type (for form generator)\n// ============================================================================\n\n/**\n * Map a schema field type to HTML form input type\n * @param field - The schema field\n * @returns The form input type (checkbox, textarea, number, date, etc.)\n */\nexport function toFormFieldType(field: SchemaField): string {\n switch (field.type) {\n case 'boolean':\n return 'checkbox'\n case 'text':\n return 'textarea'\n case 'markdown':\n return 'markdown'\n case 'richtext':\n return 'richtext'\n case 'number':\n case 'decimal':\n return 'number'\n case 'date':\n return 'date'\n case 'time':\n return 'time'\n case 'timestamp':\n return 'datetime-local'\n default:\n return 'text'\n }\n}\n\n// ============================================================================\n// Schema Field → SQL Type (for raw SQL migrations)\n// ============================================================================\n\n/**\n * Map a schema field type to SQL column type\n * @param field - The schema field\n * @returns The SQL column type\n */\nexport function toSQLType(field: SchemaField): string {\n switch (field.type) {\n case 'serial':\n return 'SERIAL'\n case 'string':\n case 'varchar':\n return field.length\n ? `VARCHAR(${field.length})`\n : `VARCHAR(${DRIZZLE_DEFAULTS.VARCHAR_LENGTH})`\n case 'text':\n case 'markdown':\n case 'richtext':\n case 'image':\n case 'video':\n case 'media':\n return 'TEXT'\n case 'number':\n return 'INTEGER'\n case 'decimal':\n return `DECIMAL(${field.precision || DRIZZLE_DEFAULTS.DECIMAL_PRECISION}, ${field.scale || DRIZZLE_DEFAULTS.DECIMAL_SCALE})`\n case 'boolean':\n return 'BOOLEAN'\n case 'timestamp':\n return 'TIMESTAMP(3)'\n case 'date':\n return 'DATE'\n case 'time':\n case 'select':\n case 'icon':\n return `VARCHAR(${DRIZZLE_DEFAULTS.VARCHAR_LENGTH})`\n case 'list':\n case 'curriculum':\n return 'JSONB'\n case 'relationship':\n return 'INTEGER'\n default:\n return 'TEXT'\n }\n}\n","/**\n * Single-step (flat) form component generator\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toKebabCase } from '../../utils/string.js'\nimport {\n type StepResult,\n resolveUiImport,\n escapeJsx,\n renderFieldsJSX,\n buildZodFields,\n buildDefaultValues,\n buildFieldArrayDecls,\n buildWatchDecls,\n getListFields,\n} from './form-component-shared.js'\n\nexport function generateSingleStepForm(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const fields = getAllFormSchemaFields(schema)\n\n const kebab = toKebabCase(formName)\n const filePath = path.join(cwd, cmsDir, 'components', 'forms', `${kebab}-form.tsx`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const zodFields = buildZodFields(fields)\n const defaults = buildDefaultValues(fields)\n const listFields = getListFields(fields)\n const hasListFields = listFields.length > 0\n const { setup: watchSetup } = buildWatchDecls(fields)\n\n const rawFields = schema.fields || []\n const fieldJSX = renderFieldsJSX(rawFields)\n\n const submitText = schema.submitButtonText || 'Submit'\n const successMessage = escapeJsx(schema.successMessage || 'Form submitted successfully!')\n\n const rhfImport = hasListFields\n ? `import { useFieldArray, useForm } from 'react-hook-form'`\n : `import { useForm } from 'react-hook-form'`\n\n const fieldArraySetup = hasListFields ? `\\n${buildFieldArrayDecls(listFields)}\\n` : ''\n\n const hasRadio = fields.some((f) => f.type === 'radio')\n const hasFileUpload = fields.some((f) => f.type === 'file' || f.type === 'upload')\n const buttonImport = resolveUiImport(cwd, 'button')\n const formImport = resolveUiImport(cwd, 'form')\n const inputImport = resolveUiImport(cwd, 'input')\n const textareaImport = resolveUiImport(cwd, 'textarea')\n const selectImport = resolveUiImport(cwd, 'select')\n const radioGroupImport = resolveUiImport(cwd, 'radio-group')\n const mediaUploadImport = resolveUiImport(cwd, 'media-upload-field')\n\n const queryClientImport = hasFileUpload\n ? `\\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'`\n : ''\n const queryClientSetup = hasFileUpload\n ? `\\nconst queryClient = new QueryClient()\\n`\n : ''\n\n const formComponentDecl = hasFileUpload ? `function ${pascal}FormInner` : `export function ${pascal}Form`\n const exportWrapper = hasFileUpload\n ? `\\nexport function ${pascal}Form() {\n return (\n <QueryClientProvider client={queryClient}>\n <${pascal}FormInner />\n </QueryClientProvider>\n )\n}\\n`\n : ''\n\n const lucideImport = hasListFields ? `\\nimport { Trash2 } from 'lucide-react'` : ''\n\n const content = `'use client'\n\nimport { zodResolver } from '@hookform/resolvers/zod'${lucideImport}\nimport { useState } from 'react'\n${rhfImport}\nimport { z } from 'zod/v3'${queryClientImport}\nimport { create${pascal}Submission } from '@cms/actions/${kebab}-form'\nimport { Button } from '${buttonImport}'\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '${formImport}'\nimport { Input } from '${inputImport}'${hasFileUpload ? `\\nimport { MediaUploadField } from '${mediaUploadImport}'` : ''}${hasRadio ? `\\nimport { RadioGroup, RadioGroupItem } from '${radioGroupImport}'` : ''}\nimport { Textarea } from '${textareaImport}'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '${selectImport}'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\ntype FormValues = z.infer<typeof formSchema>\n${queryClientSetup}\n${formComponentDecl}() {\n const [submitted, setSubmitted] = useState(false)\n const [submitting, setSubmitting] = useState(false)\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n${defaults}\n },\n })\n${fieldArraySetup}${watchSetup}\n async function onSubmit(values: FormValues) {\n setSubmitting(true)\n try {\n const result = await create${pascal}Submission(values)\n if (result.success) {\n setSubmitted(true)\n } else {\n form.setError('root', { message: result.error || 'Something went wrong' })\n }\n } catch {\n form.setError('root', { message: 'Something went wrong. Please try again.' })\n } finally {\n setSubmitting(false)\n }\n }\n\n if (submitted) {\n return (\n <div className=\"rounded-lg border p-6 text-center\">\n <h3 className=\"text-lg font-semibold\">Thank you!</h3>\n <p className=\"mt-2 text-muted-foreground\">${successMessage}</p>\n </div>\n )\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n${fieldJSX}\n\n {form.formState.errors.root && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.root.message}</p>\n )}\n\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? 'Submitting...' : '${submitText}'}\n </Button>\n </form>\n </Form>\n )\n}\n${exportWrapper}`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Form pipeline step 4: Public form component generation\n * Routes to single-step or multi-step generator based on schema structure.\n */\n\nimport { isMultiStepForm } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport type { StepResult } from './form-component-shared.js'\nimport { generateMultiStepForm } from './form-component-multistep.js'\nimport { generateSingleStepForm } from './form-component-single.js'\n\nexport function generateFormComponent(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions\n): StepResult {\n if (isMultiStepForm(schema) && schema.steps!.length > 1) {\n return generateMultiStepForm(schema, cwd, cmsDir, options)\n }\n return generateSingleStepForm(schema, cwd, cmsDir, options)\n}\n","/**\n * Form pipeline step 1: Database schema generation for form submissions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields, hasDynamicFields } from '../../core/field-helpers/index.js'\nimport { formFieldToDrizzleType } from '../../core/type-mappers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase } from '../../utils/string.js'\n\nfunction findTableEnd(content: string, startIndex: number): number {\n let depth = 0\n let inString = false\n let stringChar = ''\n\n for (let i = startIndex; i < content.length; i++) {\n const char = content[i]\n const prev = i > 0 ? content[i - 1] : ''\n\n if ((char === '\"' || char === \"'\" || char === '`') && prev !== '\\\\') {\n if (!inString) {\n inString = true\n stringChar = char\n } else if (char === stringChar) {\n inString = false\n }\n continue\n }\n if (inString) continue\n\n if (char === '(' || char === '{' || char === '[') depth++\n if (char === ')' || char === '}' || char === ']') depth--\n\n if (depth === 0 && char === ')') {\n // Skip optional semicolon and trailing whitespace\n let end = i + 1\n while (end < content.length && (content[end] === ';' || content[end] === ' ' || content[end] === '\\t')) {\n end++\n }\n if (end < content.length && content[end] === '\\n') {\n end++\n }\n return end\n }\n }\n\n return content.length\n}\n\ninterface StepResult {\n files: string[]\n}\n\nexport function generateFormDatabase(\n schema: FormSchema,\n cwd: string,\n dbSchemaPath: string,\n options: GeneratorOptions\n): StepResult {\n const tableName = `${toCamelCase(schema.name)}Submissions`\n const fields = getAllFormSchemaFields(schema)\n const includeDynamic = hasDynamicFields(schema)\n\n const requiredImports = new Set<string>(['serial', 'timestamp', 'text'])\n if (includeDynamic) requiredImports.add('jsonb')\n\n // Generate field definitions\n const fieldDefs = fields\n .map((field) => {\n const drizzleType = formFieldToDrizzleType(field, requiredImports)\n return ` ${field.name}: ${drizzleType},`\n })\n .join('\\n')\n\n const customFieldsCol = includeDynamic\n ? '\\n customFields: jsonb().$type<Record<string, unknown>>(),'\n : ''\n\n const tableSchema = `\nexport const ${tableName} = pgTable('${toPascalCase(schema.name)}Submissions', {\n id: serial().primaryKey().notNull(),\n${fieldDefs}${customFieldsCol}\n ipAddress: text(),\n userAgent: text(),\n submittedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull(),\n createdAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull(),\n updatedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull()\n})\n`\n\n const filePath = path.join(cwd, dbSchemaPath)\n let content = fs.readFileSync(filePath, 'utf-8')\n\n // Merge imports\n const pgCoreMatch = content.match(/import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/)\n if (pgCoreMatch) {\n const existing = new Set(\n pgCoreMatch[1]\n .split(',')\n .map((i) => i.trim())\n .filter(Boolean)\n )\n const merged = Array.from(new Set([...existing, ...requiredImports])).sort()\n content = content.replace(\n /import\\s+\\{[^}]+\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/,\n `import {\\n ${merged.join(',\\n ')}\\n} from 'drizzle-orm/pg-core'`\n )\n }\n\n // Ensure sql import\n if (!content.includes('import { sql }')) {\n content = content.replace(\n /import\\s+\\{[^}]+\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/,\n (match) => `import { sql } from 'drizzle-orm'\\n${match}`\n )\n }\n\n // Remove all existing table definitions if --force (handles prior duplicates)\n if (content.includes(`export const ${tableName}`)) {\n if (!options.force) {\n return { files: [dbSchemaPath] }\n }\n const marker = `export const ${tableName} =`\n let start = content.indexOf(marker)\n while (start !== -1) {\n const end = findTableEnd(content, start)\n const actualStart = start > 0 && content[start - 1] === '\\n' ? start - 1 : start\n content = content.slice(0, actualStart) + content.slice(end)\n start = content.indexOf(marker)\n }\n }\n\n content += `\\n${tableSchema}`\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [dbSchemaPath] }\n}\n","/**\n * Form pipeline step 3: React Query hook for form submissions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase, toKebabCase } from '../../utils/string.js'\n\ninterface StepResult {\n files: string[]\n}\n\nexport function generateFormHook(\n schema: FormSchema,\n cwd: string,\n hooksDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const camel = toCamelCase(formName)\n const kebab = toKebabCase(formName)\n\n const filePath = path.join(cwd, hooksDir, `use-${kebab}-form.ts`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const successMsg = (schema.successMessage || 'Form submitted successfully').replace(/'/g, \"\\\\'\")\n\n const content = `import {\n create${pascal}Submission,\n delete${pascal}Submission,\n export${pascal}SubmissionsCSV,\n export${pascal}SubmissionsJSON,\n get${pascal}Submission,\n get${pascal}Submissions,\n} from '@cms/actions/${kebab}-form'\nimport type { Create${pascal}SubmissionInput } from '@cms/actions/${kebab}-form'\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\nimport { toast } from 'sonner'\n\nexport function use${pascal}Submissions(search?: string) {\n return useQuery({\n queryKey: ['${camel}-submissions', search ?? ''],\n queryFn: () => get${pascal}Submissions()\n })\n}\n\nexport function use${pascal}Submission(id: number | null) {\n return useQuery({\n queryKey: ['${camel}-submission', id],\n queryFn: () => get${pascal}Submission(id!),\n enabled: !!id\n })\n}\n\nexport function useCreate${pascal}Submission() {\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (data: Create${pascal}SubmissionInput) => create${pascal}Submission(data),\n onSuccess: async (result) => {\n if (result.success) {\n toast.success('${successMsg}')\n await queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n } else {\n toast.error(result.error || 'Failed to submit form')\n }\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to submit form')\n }\n })\n}\n\nexport function useDelete${pascal}Submission() {\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (id: number) => delete${pascal}Submission(id),\n onSuccess: async () => {\n toast.success('Submission deleted successfully')\n await queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to delete submission')\n }\n })\n}\n\nexport function useExport${pascal}SubmissionsCSV() {\n return useMutation({\n mutationFn: export${pascal}SubmissionsCSV,\n onSuccess: (csvContent) => {\n const blob = new Blob([csvContent], { type: 'text/csv' })\n const url = window.URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = '${formName}-submissions-' + new Date().toISOString().split('T')[0] + '.csv'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n window.URL.revokeObjectURL(url)\n toast.success('CSV exported successfully')\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to export CSV')\n }\n })\n}\n\nexport function useExport${pascal}SubmissionsJSON() {\n return useMutation({\n mutationFn: export${pascal}SubmissionsJSON,\n onSuccess: (jsonContent) => {\n const blob = new Blob([jsonContent], { type: 'application/json' })\n const url = window.URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = '${formName}-submissions-' + new Date().toISOString().split('T')[0] + '.json'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n window.URL.revokeObjectURL(url)\n toast.success('JSON exported successfully')\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to export JSON')\n }\n })\n}\n`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Form pipeline orchestrator — runs all form generation steps in sequence\n */\n\nimport type { BetterstartConfig } from '../../config/types.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { generateEmailTemplate } from '../email-template.js'\nimport { generateFormAdminPages } from '../form-admin/index.js'\nimport { updateFormNavigation } from '../form-navigation.js'\nimport { generateFormActions } from './form-actions.js'\nimport { generateFormComponent } from './form-component.js'\nimport { generateFormDatabase } from './form-database.js'\nimport { generateFormHook } from './form-hook.js'\n\nexport interface FormPipelineResult {\n success: boolean\n files: string[]\n errors: string[]\n}\n\n/**\n * Resolve output paths from config for form generation\n */\nfunction resolveFormPaths(config: BetterstartConfig) {\n const cms = config.paths?.cms ?? './cms'\n const pages = config.paths?.pages ?? './src/app/(cms)/cms/(authenticated)'\n return {\n cmsDir: cms,\n pagesDir: pages,\n dbSchemaPath: `${cms}/db/schema.ts`,\n actionsDir: `${cms}/lib/actions`,\n hooksDir: `${cms}/hooks`\n }\n}\n\n/**\n * Run the form generation pipeline\n */\nexport function runFormPipeline(\n schema: FormSchema,\n cwd: string,\n config: BetterstartConfig,\n options: GeneratorOptions = {}\n): FormPipelineResult {\n const paths = resolveFormPaths(config)\n const files: string[] = []\n const errors: string[] = []\n\n const steps: { name: string; run: () => string[] }[] = [\n {\n name: 'Database schema (submissions)',\n run: () => generateFormDatabase(schema, cwd, paths.dbSchemaPath, options).files\n },\n {\n name: 'Server actions',\n run: () => generateFormActions(schema, cwd, paths.actionsDir, options).files\n },\n {\n name: 'React Query hook',\n run: () => generateFormHook(schema, cwd, paths.hooksDir, options).files\n },\n {\n name: 'Public form component',\n run: () => generateFormComponent(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Admin pages',\n run: () => generateFormAdminPages(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Navigation',\n run: () => updateFormNavigation(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Email template',\n run: () => generateEmailTemplate(schema, cwd, paths.cmsDir, options).files\n }\n ]\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const stepNum = i + 1\n try {\n const result = step.run()\n files.push(...result)\n if (!options.silent) console.log(` ${stepNum}. ${step.name} ✓`)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${step.name}: ${msg}`)\n if (!options.silent) console.error(` ${stepNum}. ${step.name} ✗ — ${msg}`)\n }\n }\n\n return { success: errors.length === 0, files, errors }\n}\n","/**\n * Generator 2: Server actions — cms/lib/actions/<n>.ts\n * Generates 'use server' CRUD actions for an entity schema\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, getManyToManyFields } from '../../core/field-helpers/index.js'\nimport type { Schema, SchemaField } from '../../types.js'\nimport { toPascalCase, toCamelCase, singularize, pluralize, quotePropertyName } from '../../utils/string.js'\nimport type { ActionsGeneratorResult } from './action-helpers.js'\nimport {\n generateFieldMapping,\n getFieldType,\n buildRelationshipSelect,\n buildResultMapping,\n buildSingleRowMapping,\n buildExplicitSelect,\n findListFieldsWithRelationships,\n generatePopulateListRelsFunction\n} from './action-helpers.js'\n\n/**\n * Generate server actions file for an entity\n */\nexport function generateActions(\n schema: Schema,\n cwd: string,\n actionsDir: string,\n options: { force?: boolean; schemasDir?: string } = {}\n): ActionsGeneratorResult {\n const absActionsDir = path.join(cwd, actionsDir)\n const filePath = path.join(absActionsDir, `${schema.name}.ts`)\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n const tableVar = toCamelCase(schema.name)\n const camelPlural = toCamelCase(plural)\n const camelSingular = toCamelCase(singular)\n\n const dbFields = flattenFields(schema.fields)\n const m2mFields = getManyToManyFields(schema.fields)\n const hasM2M = m2mFields.length > 0\n\n const relationshipFields = dbFields.filter(\n (f) => f.type === 'relationship' && f.relationship && !f.multiple\n )\n const hasRelationships = relationshipFields.length > 0\n\n const regularDbFields = dbFields.filter(\n (f) => !(f.type === 'relationship' && f.multiple === true)\n )\n\n // Find list fields that contain relationship sub-fields\n const listFieldsWithRels = findListFieldsWithRelationships(dbFields)\n const hasListRels = listFieldsWithRels.length > 0\n\n // Collect relationship query info for list fields\n const allListRelQueries: Array<{\n fieldPath: string\n relField: SchemaField\n relTable: string\n listFieldName: string\n }> = []\n\n for (const { field: listField, path: fieldPath } of listFieldsWithRels) {\n const rels = (listField.fields || []).filter((f) => f.type === 'relationship' && f.relationship)\n for (const relField of rels) {\n allListRelQueries.push({\n fieldPath: fieldPath.join('_'),\n relField,\n relTable: toCamelCase(relField.relationship!),\n listFieldName: listField.name\n })\n }\n }\n\n // Generate populate helper function for list-relationship fields\n const populateListRelsFn = hasListRels\n ? generatePopulateListRelsFunction(allListRelQueries, Singular)\n : ''\n\n const htmlOutputFields = regularDbFields.filter(\n (f) => (f.type === 'richtext' || f.type === 'markdown') && f.output === 'html'\n )\n const hasHtmlOutput = htmlOutputFields.length > 0\n\n const hasSlug = regularDbFields.some((f) => f.name === 'slug')\n const hasDraft = schema.actions?.draft === true\n const hasPublished = regularDbFields.some((f) => f.name === 'published')\n const hasSearch = (schema.search?.fields || []).length > 0\n const searchFields = schema.search?.fields || []\n const hasFilters = (schema.filters || []).length > 0\n\n // Build allDbFields (with auto-added fields)\n const allDbFields = [...regularDbFields]\n if (hasDraft && !hasPublished) {\n allDbFields.push({ name: 'published', type: 'boolean' as const, required: true })\n }\n if (!regularDbFields.some((f) => f.name === 'createdAt')) {\n allDbFields.push({ name: 'createdAt', type: 'timestamp' as const, required: true })\n }\n if (!regularDbFields.some((f) => f.name === 'updatedAt')) {\n allDbFields.push({ name: 'updatedAt', type: 'timestamp' as const, required: true })\n }\n if (!regularDbFields.some((f) => f.name === 'sortOrder')) {\n allDbFields.push({ name: 'sortOrder', type: 'number' as const, required: true })\n }\n\n // List-specific fields (exclude heavy content columns when output: 'html')\n const listExcludeFields = new Set(htmlOutputFields.map(f => f.name))\n const listDbFields = hasHtmlOutput\n ? allDbFields.filter(f => !listExcludeFields.has(f.name))\n : allDbFields\n\n // Create fields (exclude auto-generated)\n const createFields = regularDbFields.filter(\n (f) =>\n !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt' && f.name !== 'sortOrder'\n )\n\n // Filterable fields for the Filters interface\n const filterableFields = allDbFields.filter(\n (f) =>\n !f.primaryKey &&\n f.name !== 'createdAt' &&\n f.name !== 'updatedAt' &&\n f.name !== 'sortOrder' &&\n ['string', 'varchar', 'text', 'boolean', 'number', 'decimal'].includes(f.type)\n )\n\n // --- Build imports ---\n const drizzleImports = ['asc', 'desc', 'eq', 'gt', 'inArray', 'lt']\n if (hasSearch || filterableFields.length > 1) drizzleImports.push('and')\n if (hasSearch) drizzleImports.push('ilike', 'or')\n if (hasRelationships) drizzleImports.push('sql')\n if (hasFilters) drizzleImports.push('isNotNull')\n const sortedDrizzleImports = [...new Set(drizzleImports)].sort()\n\n const dbImports = new Set([tableVar])\n for (const f of relationshipFields) dbImports.add(toCamelCase(f.relationship!))\n for (const f of m2mFields) {\n const junctionVar = toCamelCase(`${singular}${toPascalCase(f.relationship || '')}`)\n dbImports.add(junctionVar)\n dbImports.add(toCamelCase(f.relationship || ''))\n }\n for (const q of allListRelQueries) {\n dbImports.add(q.relTable)\n }\n const sortedDbImports = [...dbImports].sort()\n\n // --- Build interfaces ---\n const dataFields = allDbFields\n .map(\n (f) =>\n ` ${quotePropertyName(f.name)}: ${getFieldType(f, 'output')}${f.required ? '' : ' | null'}`\n )\n .join('\\n')\n const m2mFieldTypes = m2mFields.map((f) => ` ${quotePropertyName(f.name)}: number[]`).join('\\n')\n const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join('\\n')\n\n const dataInterface = `export interface ${Singular}Data {\\n${dataFields}${htmlFieldTypes ? `\\n${htmlFieldTypes}` : ''}${m2mFieldTypes ? `\\n${m2mFieldTypes}` : ''}\\n}`\n\n // Display data interface (for getBySlug): excludes raw content, includes contentHtml\n const displayDbFields = allDbFields.filter(f => !htmlOutputFields.some(h => h.name === f.name))\n const displayDataFields = displayDbFields\n .map(f => ` ${quotePropertyName(f.name)}: ${getFieldType(f, 'output')}${f.required ? '' : ' | null'}`)\n .join('\\n')\n const displayDataInterface = hasHtmlOutput\n ? `\\nexport interface ${Singular}DisplayData {\\n${displayDataFields}${htmlFieldTypes ? `\\n${htmlFieldTypes}` : ''}${m2mFieldTypes ? `\\n${m2mFieldTypes}` : ''}\\n}`\n : ''\n\n const responseInterface = `export interface ${Plural}Response {\\n ${camelPlural}: ${Singular}Data[]\\n total: number\\n}`\n\n const filtersInterfaceFields = filterableFields\n .map((f) => ` ${quotePropertyName(f.name)}?: ${getFieldType(f)}`)\n .join('\\n')\n const filtersInterface = `export interface Get${Plural}Filters {\\n search?: string\\n${filtersInterfaceFields}\\n limit?: number\\n}`\n\n const createInterfaceFields = createFields\n .map(\n (f) => ` ${quotePropertyName(f.name)}${f.required ? '' : '?'}: ${getFieldType(f, 'input')}`\n )\n .join('\\n')\n const createInterface = `export interface Create${Singular}Input {\\n${createInterfaceFields}${hasDraft ? `\\n published?: boolean` : ''}\\n}`\n\n const updateInterfaceFields = createFields\n .map((f) => ` ${quotePropertyName(f.name)}?: ${getFieldType(f, 'input')}`)\n .join('\\n')\n const updateInterface = `export interface Update${Singular}Input {\\n id: number\\n${updateInterfaceFields}${hasDraft ? `\\n published?: boolean` : ''}\\n}`\n\n // --- Build select clause ---\n const selectClause = hasRelationships\n ? buildRelationshipSelect(allDbFields, relationshipFields, tableVar)\n : `db.select().from(${tableVar})`\n\n // List select: excludes heavy content/html columns for performance\n const listSelectClause = hasHtmlOutput\n ? (hasRelationships\n ? buildRelationshipSelect(listDbFields, relationshipFields, tableVar)\n : buildExplicitSelect(listDbFields, tableVar))\n : selectClause\n\n // Display select (for getBySlug): excludes raw content, includes contentHtml\n const displaySelectClause = hasHtmlOutput && hasSlug\n ? (hasRelationships\n ? buildRelationshipSelect(displayDbFields, relationshipFields, tableVar, htmlOutputFields)\n : buildExplicitSelect(displayDbFields, tableVar, htmlOutputFields))\n : selectClause\n\n // --- Build query with filters ---\n const filterConditions = filterableFields\n .map((f) =>\n f.type === 'boolean'\n ? ` if (filters?.${f.name} !== undefined) {\\n conditions.push(eq(${tableVar}.${f.name}, filters.${f.name}))\\n }`\n : ` if (filters?.${f.name}) {\\n conditions.push(eq(${tableVar}.${f.name}, filters.${f.name}))\\n }`\n )\n .join('\\n')\n\n const searchBlock = hasSearch\n ? ` const search = filters?.search\\n if (search && typeof search === 'string' && search.trim()) {\\n const searchTerm = \\`%\\${search.trim().toLowerCase()}%\\`\\n conditions.push(\\n or(\\n${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(',\\n')}\\n )\\n )\\n }\\n`\n : ''\n\n // --- Build result mapping for relationships ---\n const resultMapping = hasRelationships\n ? buildResultMapping(\n allDbFields,\n relationshipFields,\n Plural,\n camelPlural,\n Singular,\n hasListRels\n )\n : hasListRels\n ? `\\n\\n const populated${Plural} = await Promise.all(\\n results.map(record => populate${Singular}ListRelationships(record as ${Singular}Data))\\n )\\n\\n return {\\n ${camelPlural}: populated${Plural},\\n total: populated${Plural}.length\\n }`\n : `\\n return {\\n ${camelPlural}: results as ${Singular}Data[],\\n total: results.length\\n }`\n\n // List-specific result mapping (uses listDbFields for relationship cases)\n const listResultMapping = hasHtmlOutput && hasRelationships\n ? buildResultMapping(listDbFields, relationshipFields, Plural, camelPlural, Singular, hasListRels)\n : resultMapping\n\n // --- Build field metadata for update ---\n const fieldMeta = createFields\n .map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`)\n .join(',\\n ')\n\n // --- Build create field mappings ---\n const createMappings = createFields\n .map((f) => ` ${f.name}: ${generateFieldMapping(f)}`)\n .join(',\\n')\n\n const htmlCreateBlock = hasHtmlOutput\n ? `\\n const { renderMarkdownSync } = await import('@cms/lib/markdown/render')\\n` +\n htmlOutputFields.map((f) => ` const ${f.name}Html = renderMarkdownSync(input.${f.name} || '')`).join('\\n') +\n '\\n'\n : ''\n\n const htmlCreateMappings = htmlOutputFields\n .map((f) => ` ${f.name}Html`)\n .join(',\\n')\n\n // --- Generate distinct filter functions ---\n const distinctFns = hasFilters\n ? (schema.filters || [])\n .map(\n (filter) =>\n `\\nexport async function getDistinct${Plural}${toPascalCase(filter.field)}(): Promise<string[]> {\\n try {\\n const results = await db\\n .selectDistinct({ value: ${tableVar}.${filter.field} })\\n .from(${tableVar})\\n .where(isNotNull(${tableVar}.${filter.field}))\\n .orderBy(asc(${tableVar}.${filter.field}))\\n return results.map((r) => String(r.value)).filter(Boolean)\\n } catch (error) {\\n console.error('Error fetching distinct ${plural} ${filter.field}:', error)\\n return []\\n }\\n}`\n )\n .join('\\n')\n : ''\n\n // --- Build M2M helper functions ---\n const m2mHelpers = hasM2M\n ? m2mFields\n .map((f) => {\n const rel = f.relationship || ''\n const RelPascal = toPascalCase(rel)\n const relSingular = singularize(rel)\n const junctionVar = toCamelCase(`${singular}${RelPascal}`)\n const entityIdCol = `${singular}Id`\n const relIdCol = `${relSingular}Id`\n return `\nexport async function get${RelPascal}For${Singular}(${singular}Id: number): Promise<number[]> {\n try {\n const results = await db.select({ ${relIdCol}: ${junctionVar}.${relIdCol} }).from(${junctionVar}).where(eq(${junctionVar}.${entityIdCol}, ${singular}Id))\n return results.map(r => r.${relIdCol})\n } catch (error) {\n console.error('Error fetching ${rel} for ${singular}:', error)\n return []\n }\n}\n\nexport async function set${RelPascal}For${Singular}(${singular}Id: number, ${rel}Ids: number[]): Promise<{ success: boolean; error?: string }> {\n try {\n await db.delete(${junctionVar}).where(eq(${junctionVar}.${entityIdCol}, ${singular}Id))\n if (${rel}Ids.length > 0) {\n await db.insert(${junctionVar}).values(${rel}Ids.map(${relSingular}Id => ({ ${entityIdCol}: ${singular}Id, ${relIdCol}: ${relSingular}Id })))\n }\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error setting ${rel} for ${singular}:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to set ${rel}' }\n }\n}`\n })\n .join('\\n')\n : ''\n\n // --- Slugify helper ---\n const slugifyHelper = schema.autoSlugify?.enabled\n ? `\\nfunction slugify(text: string): string {\\n return text.toLowerCase().trim().replace(/[^\\\\w\\\\s-]/g, '').replace(/\\\\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, '')\\n}\\n`\n : ''\n\n // --- Auto-slug blocks ---\n const autoSlugCreate = schema.autoSlugify?.enabled\n ? `\\n if ((!input.${schema.autoSlugify.targetField} || input.${schema.autoSlugify.targetField} === '') && input.${schema.autoSlugify.sourceField}) {\\n input.${schema.autoSlugify.targetField} = slugify(input.${schema.autoSlugify.sourceField})\\n }\\n`\n : ''\n const autoSlugUpdate = schema.autoSlugify?.enabled\n ? `\\n if (updateData.${schema.autoSlugify!.sourceField}) {\\n if (updateData.${schema.autoSlugify!.targetField} === '' || updateData.${schema.autoSlugify!.targetField} === undefined) {\\n updateData.${schema.autoSlugify!.targetField} = slugify(updateData.${schema.autoSlugify!.sourceField})\\n }\\n }\\n`\n : ''\n\n const cacheTag = `${plural}:all`\n\n // --- Build single row return (for getById) ---\n const singleRowReturn = (() => {\n if (hasRelationships && hasListRels) {\n return `const row = result[0]\\n return await populate${Singular}ListRelationships(${buildSingleRowMapping(allDbFields, relationshipFields, `${Singular}Data`)})`\n }\n if (hasRelationships) {\n return `const row = result[0]\\n return ${buildSingleRowMapping(allDbFields, relationshipFields, `${Singular}Data`)}`\n }\n if (hasListRels) {\n return `return await populate${Singular}ListRelationships(result[0] as ${Singular}Data)`\n }\n return `return result[0] as ${Singular}Data`\n })()\n\n // --- Build single row return (for getBySlug — display/frontend) ---\n const displaySingleRowReturn = hasHtmlOutput\n ? (() => {\n const displayType = `${Singular}DisplayData`\n if (hasRelationships && hasListRels) {\n return `const row = result[0]\\n return await populate${Singular}ListRelationships(${buildSingleRowMapping(displayDbFields, relationshipFields, `${Singular}Data`, htmlOutputFields)}) as unknown as ${displayType}`\n }\n if (hasRelationships) {\n return `const row = result[0]\\n return ${buildSingleRowMapping(displayDbFields, relationshipFields, displayType, htmlOutputFields)}`\n }\n if (hasListRels) {\n return `return await populate${Singular}ListRelationships(result[0] as unknown as ${Singular}Data) as unknown as ${displayType}`\n }\n return `return result[0] as ${displayType}`\n })()\n : singleRowReturn\n\n // --- Assemble the file ---\n const content = `'use server'\n\nimport db from '@cms/db'\nimport { ${sortedDbImports.join(', ')} } from '@cms/db/schema'\nimport { ${sortedDrizzleImports.join(', ')} } from 'drizzle-orm'\nimport { updateTag } from 'next/cache'\n\nconst CACHE_TAG = '${cacheTag}'\n\n${dataInterface}${displayDataInterface}\n\n${responseInterface}\n\n${filtersInterface}\n\n${createInterface}\n\nexport interface Create${Singular}Result {\n success: boolean\n error?: string\n ${camelSingular}?: ${Singular}Data\n}\n\n${updateInterface}\n\nexport interface Update${Singular}Result {\n success: boolean\n error?: string\n ${camelSingular}?: ${Singular}Data\n}\n\nexport interface Delete${Singular}Result {\n success: boolean\n error?: string\n}\n${slugifyHelper}${populateListRelsFn}\nexport async function get${Plural}(filters?: Get${Plural}Filters): Promise<${Plural}Response> {\n try {\n const conditions = []\n${searchBlock}${filterConditions}\n\n const query = ${listSelectClause}\n\n const orderedQuery = conditions.length > 0\n ? query.where(and(...conditions)).orderBy(asc(${tableVar}.sortOrder))\n : query.orderBy(asc(${tableVar}.sortOrder))\n\n const results = filters?.limit && filters.limit > 0\n ? await orderedQuery.limit(filters.limit)\n : await orderedQuery${listResultMapping}\n } catch (error) {\n console.error('Error fetching ${plural}:', error)\n return { ${camelPlural}: [], total: 0 }\n }\n}\n${distinctFns}\n\nexport async function get${Singular}ById(id: number): Promise<${Singular}Data | null> {\n try {\n const result = await ${selectClause}.where(eq(${tableVar}.id, id)).limit(1)\n if (result.length === 0) return null\n ${singleRowReturn}\n } catch (error) {\n console.error('Error fetching ${singular}:', error)\n return null\n }\n}${\n hasSlug\n ? `\n\nexport async function get${Singular}BySlug(slug: string): Promise<${hasHtmlOutput ? `${Singular}DisplayData` : `${Singular}Data`} | null> {\n try {\n const result = await ${displaySelectClause}.where(eq(${tableVar}.slug, slug)).limit(1)\n if (result.length === 0) return null\n ${displaySingleRowReturn}\n } catch (error) {\n console.error('Error fetching ${singular} by slug:', error)\n return null\n }\n}`\n : ''\n }\n\nexport async function create${Singular}(input: Create${Singular}Input): Promise<Create${Singular}Result> {\n try {${autoSlugCreate}\n const maxSortOrderResult = await db\n .select({ maxOrder: ${tableVar}.sortOrder })\n .from(${tableVar})\n .orderBy(desc(${tableVar}.sortOrder))\n .limit(1)\n const nextSortOrder = (maxSortOrderResult[0]?.maxOrder ?? 0) + 1\n${htmlCreateBlock}\n const result = await db.insert(${tableVar}).values({\n${createMappings},${hasHtmlOutput ? `\\n${htmlCreateMappings},` : ''}${hasDraft ? `\\n published: input.published ?? false,` : ''}\n sortOrder: nextSortOrder,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n }).returning()\n\n updateTag(CACHE_TAG)\n\n return {\n success: true,\n ${camelSingular}: result[0] as ${Singular}Data\n }\n } catch (error) {\n console.error('Error creating ${singular}:', error)\n throw new Error(error instanceof Error ? error.message : 'Failed to create ${singular}')\n }\n}\n\nexport async function update${Singular}(input: Update${Singular}Input): Promise<Update${Singular}Result> {\n try {\n const { id, ...updateData } = input\n${autoSlugUpdate}\n const fieldMeta = [\n ${fieldMeta}\n ]\n\n const processedData: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(updateData)) {\n if (key === 'published') { processedData[key] = value; continue }\n const field = fieldMeta.find(f => f.name === key)\n if (!field) continue\n if (field.type === 'list') {\n processedData[key] = value || []\n } else if (!field.required && ['date', 'timestamp', 'time', 'string', 'varchar', 'text', 'select'].includes(field.type)) {\n processedData[key] = value && value !== '' ? value : null\n } else {\n processedData[key] = value\n }\n }\n${hasHtmlOutput ? `\n const { renderMarkdownSync } = await import('@cms/lib/markdown/render')\\n` + htmlOutputFields.map((f) => ` if (processedData.${f.name} !== undefined) {\n processedData.${f.name}Html = renderMarkdownSync(String(processedData.${f.name} || ''))\n }`).join('\\n') + '\\n' : ''}\n const result = await db.update(${tableVar})\n .set({ ...processedData, updatedAt: new Date().toISOString() })\n .where(eq(${tableVar}.id, id))\n .returning()\n\n if (result.length === 0) throw new Error('${Singular} not found')\n\n updateTag(CACHE_TAG)\n\n return {\n success: true,\n ${camelSingular}: result[0] as ${Singular}Data\n }\n } catch (error) {\n console.error('Error updating ${singular}:', error)\n throw new Error(error instanceof Error ? error.message : 'Failed to update ${singular}')\n }\n}\n\nexport async function delete${Singular}(id: number): Promise<Delete${Singular}Result> {\n try {\n await db.delete(${tableVar}).where(eq(${tableVar}.id, id))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error deleting ${singular}:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to delete ${singular}' }\n }\n}\n\nexport async function deleteBulk${Plural}(ids: number[]): Promise<Delete${Singular}Result> {\n try {\n if (ids.length === 0) return { success: false, error: 'No items selected for deletion' }\n await db.delete(${tableVar}).where(inArray(${tableVar}.id, ids))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error deleting ${plural}:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to delete ${plural}' }\n }\n}\n\nexport async function update${Singular}SortOrder(\n id: number,\n direction: 'up' | 'down'\n): Promise<{ success: boolean; error?: string }> {\n try {\n const current = await db.select({ id: ${tableVar}.id, sortOrder: ${tableVar}.sortOrder }).from(${tableVar}).where(eq(${tableVar}.id, id)).limit(1)\n if (current.length === 0) return { success: false, error: '${Singular} not found' }\n\n const currentSortOrder = current[0].sortOrder\n const adjacent = await db\n .select({ id: ${tableVar}.id, sortOrder: ${tableVar}.sortOrder })\n .from(${tableVar})\n .where(direction === 'up' ? lt(${tableVar}.sortOrder, currentSortOrder) : gt(${tableVar}.sortOrder, currentSortOrder))\n .orderBy(direction === 'up' ? desc(${tableVar}.sortOrder) : asc(${tableVar}.sortOrder))\n .limit(1)\n\n if (adjacent.length === 0) return { success: true }\n\n await db.update(${tableVar}).set({ sortOrder: adjacent[0].sortOrder }).where(eq(${tableVar}.id, id))\n await db.update(${tableVar}).set({ sortOrder: currentSortOrder }).where(eq(${tableVar}.id, adjacent[0].id))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error updating sort order:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to update sort order' }\n }\n}\n\nexport async function bulkUpdate${Plural}SortOrder(\n updates: Array<{ id: number; sortOrder: number }>\n): Promise<{ success: boolean; error?: string }> {\n try {\n if (updates.length === 0) return { success: true }\n await Promise.all(updates.map((u) => db.update(${tableVar}).set({ sortOrder: u.sortOrder }).where(eq(${tableVar}.id, u.id))))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error bulk updating sort order:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to bulk update sort order' }\n }\n}${m2mHelpers}\n`\n\n // Write\n if (!fs.existsSync(absActionsDir)) {\n fs.mkdirSync(absActionsDir, { recursive: true })\n }\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [path.join(actionsDir, `${schema.name}.ts`)] }\n}\n","/**\n * Shared helpers for entity and single action generators\n */\n\nimport { toTypeScriptType } from '../../core/type-mappers/index.js'\nimport type { SchemaField } from '../../types.js'\nimport { toCamelCase } from '../../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface ActionsGeneratorResult {\n files: string[]\n}\n\n// ============================================================================\n// Field Mapping Helpers\n// ============================================================================\n\nexport function generateFieldMapping(field: SchemaField, source = 'input'): string {\n if (field.type === 'list') return `${source}.${field.name} || []`\n if (\n (field.type === 'date' || field.type === 'timestamp' || field.type === 'time') &&\n !field.required\n ) {\n return `${source}.${field.name} && ${source}.${field.name} !== '' ? ${source}.${field.name} : null`\n }\n if (!field.required && ['string', 'varchar', 'text', 'select'].includes(field.type)) {\n return `${source}.${field.name} && ${source}.${field.name} !== '' ? ${source}.${field.name} : null`\n }\n return `${source}.${field.name}`\n}\n\nexport function getFieldType(field: SchemaField, mode: 'input' | 'output' = 'output'): string {\n return toTypeScriptType(field, mode)\n}\n\n// ============================================================================\n// Helper builders for relationship queries\n// ============================================================================\n\nexport function buildRelationshipSelect(\n allDbFields: SchemaField[],\n relationshipFields: SchemaField[],\n tableVar: string,\n htmlFields: SchemaField[] = []\n): string {\n const fieldSelects = allDbFields\n .filter((f) => f.type !== 'relationship')\n .map((f) => ` ${f.name}: ${tableVar}.${f.name}`)\n const htmlSelects = htmlFields.map((f) => ` ${f.name}Html: ${tableVar}.${f.name}Html`)\n const regularSelects = [...fieldSelects, ...htmlSelects].join(',\\n')\n\n const relSelects = relationshipFields\n .map((f) => {\n const relTable = toCamelCase(f.relationship!)\n return ` ${f.name}: { id: ${relTable}.id, name: ${relTable}.name, title: ${relTable}.title, slug: ${relTable}.slug, label: ${relTable}.label }`\n })\n .join(',\\n')\n\n const joins = relationshipFields\n .map((f) => {\n const relTable = toCamelCase(f.relationship!)\n return `.leftJoin(${relTable}, sql\\`CAST(NULLIF(\\${${tableVar}.${f.name}}, '') AS INTEGER) = \\${${relTable}.id}\\`)`\n })\n .join('')\n\n return `db.select({\\n${regularSelects},\\n${relSelects}\\n }).from(${tableVar})${joins}`\n}\n\nexport function buildResultMapping(\n allDbFields: SchemaField[],\n _relationshipFields: SchemaField[],\n Plural: string,\n camelPlural: string,\n Singular: string,\n hasListRels = false\n): string {\n const rowMappings = allDbFields\n .map((f) => {\n if (f.type === 'relationship' && !f.multiple) {\n return ` ${f.name}: row.${f.name}?.id ? { id: row.${f.name}.id, name: row.${f.name}.name ?? undefined, title: row.${f.name}.title ?? undefined, slug: row.${f.name}.slug ?? undefined, label: row.${f.name}.label ?? undefined } : null`\n }\n return ` ${f.name}: row.${f.name}`\n })\n .join(',\\n')\n\n const mapBlock = `\n\n const mapped${Plural} = results.map((row) => ({\n${rowMappings}\n }))`\n\n if (hasListRels) {\n return `${mapBlock}\n\n const populated${Plural} = await Promise.all(\n mapped${Plural}.map(record => populate${Singular}ListRelationships(record as ${Singular}Data))\n )\n\n return {\n ${camelPlural}: populated${Plural},\n total: populated${Plural}.length\n }`\n }\n\n return `${mapBlock}\n\n return {\n ${camelPlural}: mapped${Plural} as ${Singular}Data[],\n total: mapped${Plural}.length\n }`\n}\n\nexport function buildSingleRowMapping(\n allDbFields: SchemaField[],\n _relationshipFields: SchemaField[],\n typeName: string,\n htmlFields: SchemaField[] = []\n): string {\n const fieldMappings = allDbFields\n .map((f) => {\n if (f.type === 'relationship' && !f.multiple) {\n return ` ${f.name}: row.${f.name}?.id ? { id: row.${f.name}.id, name: row.${f.name}.name ?? undefined, title: row.${f.name}.title ?? undefined, slug: row.${f.name}.slug ?? undefined, label: row.${f.name}.label ?? undefined } : null`\n }\n return ` ${f.name}: row.${f.name}`\n })\n const htmlMappings = htmlFields.map((f) => ` ${f.name}Html: row.${f.name}Html`)\n const mappings = [...fieldMappings, ...htmlMappings].join(',\\n')\n\n return `{\\n${mappings}\\n } as ${typeName}`\n}\n\nexport function buildExplicitSelect(fields: SchemaField[], tableVar: string, htmlFields: SchemaField[] = []): string {\n const fieldSelects = fields.map((f) => ` ${f.name}: ${tableVar}.${f.name}`)\n const htmlSelects = htmlFields.map((f) => ` ${f.name}Html: ${tableVar}.${f.name}Html`)\n const selects = [...fieldSelects, ...htmlSelects].join(',\\n')\n return `db.select({\\n${selects}\\n }).from(${tableVar})`\n}\n\n// ============================================================================\n// List-relationship helpers\n// ============================================================================\n\nexport function findListFieldsWithRelationships(\n fields: SchemaField[]\n): Array<{ field: SchemaField; path: string[] }> {\n const result: Array<{ field: SchemaField; path: string[] }> = []\n for (const field of fields) {\n if (field.type === 'list' && field.fields) {\n const hasRels = field.fields.some((f) => f.type === 'relationship' && f.relationship)\n if (hasRels) {\n result.push({ field, path: [field.name] })\n }\n }\n }\n return result\n}\n\nexport function generatePopulateListRelsFunction(\n queries: Array<{\n fieldPath: string\n relField: SchemaField\n relTable: string\n listFieldName: string\n }>,\n Singular: string\n): string {\n const blocks = queries.map((q) => {\n const v = `${q.fieldPath}_${q.relField.name}`\n return ` // ${q.listFieldName} -> ${q.relField.name}\n const ${v}Ids = record.${q.listFieldName} && Array.isArray(record.${q.listFieldName})\n ? (record.${q.listFieldName} as Record<string, unknown>[])\n .map((item) => item.${q.relField.name})\n .filter((id) => id != null && id !== '')\n .map((id) => Number.parseInt(String(id), 10))\n .filter((id) => !Number.isNaN(id))\n : []\n\n const ${v}Results = ${v}Ids.length > 0\n ? await db.select().from(${q.relTable}).where(inArray(${q.relTable}.id, ${v}Ids))\n : []\n\n const ${v}Map = new Map(${v}Results.map((r) => [r.id, r]))\n\n if (record.${q.listFieldName} && Array.isArray(record.${q.listFieldName})) {\n record.${q.listFieldName} = (record.${q.listFieldName} as Record<string, unknown>[]).map((item) => {\n const relId = item.${q.relField.name} ? Number.parseInt(String(item.${q.relField.name}), 10) : null\n return {\n ...item,\n ${q.relField.name}: relId && !Number.isNaN(relId) ? ${v}Map.get(relId) || null : null\n }\n })\n }`\n })\n\n return `\n/**\n * Populate relationship fields inside list (JSONB) fields\n */\nasync function populate${Singular}ListRelationships(record: ${Singular}Data): Promise<${Singular}Data> {\n${blocks.join('\\n\\n')}\n\n return record\n}\n`\n}\n","/**\n * Generator 2b: Server actions for single (singleton) schemas\n * Only getXxx() and upsertXxx() — no list, delete, sort, or bulk ops.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../../core/field-helpers/index.js'\nimport type { Schema } from '../../types.js'\nimport { toPascalCase, toCamelCase, singularize, quotePropertyName } from '../../utils/string.js'\nimport type { ActionsGeneratorResult } from './action-helpers.js'\nimport { generateFieldMapping, getFieldType } from './action-helpers.js'\n\n/**\n * Generate server actions file for a single (singleton) schema.\n * Only getXxx() and upsertXxx() — no list, delete, sort, or bulk ops.\n */\nexport function generateSingleActions(\n schema: Schema,\n cwd: string,\n actionsDir: string,\n options: { force?: boolean } = {}\n): ActionsGeneratorResult {\n const absActionsDir = path.join(cwd, actionsDir)\n const filePath = path.join(absActionsDir, `${schema.name}.ts`)\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const tableVar = toCamelCase(schema.name)\n const camelSingular = toCamelCase(singular)\n\n const dbFields = flattenFields(schema.fields).filter(\n (f) => !(f.type === 'relationship' && f.multiple === true)\n )\n\n const singleHtmlOutputFields = dbFields.filter(\n (f) => (f.type === 'richtext' || f.type === 'markdown') && f.output === 'html'\n )\n const singleHasHtmlOutput = singleHtmlOutputFields.length > 0\n\n // Build allDbFields (with auto-added timestamp fields, NO sortOrder)\n const allDbFields = [...dbFields]\n if (!dbFields.some((f) => f.name === 'createdAt')) {\n allDbFields.push({ name: 'createdAt', type: 'timestamp' as const, required: true })\n }\n if (!dbFields.some((f) => f.name === 'updatedAt')) {\n allDbFields.push({ name: 'updatedAt', type: 'timestamp' as const, required: true })\n }\n\n // Upsert fields (exclude auto-generated)\n const upsertFields = dbFields.filter(\n (f) => !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt'\n )\n\n // Data interface\n const dataFields = allDbFields\n .map(\n (f) =>\n ` ${quotePropertyName(f.name)}: ${getFieldType(f, 'output')}${f.required ? '' : ' | null'}`\n )\n .join('\\n')\n const singleHtmlFieldTypes = singleHtmlOutputFields.map((f) => ` ${f.name}Html: string`).join('\\n')\n const dataInterface = `export interface ${Singular}Data {\\n${dataFields}${singleHtmlFieldTypes ? `\\n${singleHtmlFieldTypes}` : ''}\\n}`\n\n // Upsert input interface\n const upsertInterfaceFields = upsertFields\n .map(\n (f) => ` ${quotePropertyName(f.name)}${f.required ? '' : '?'}: ${getFieldType(f, 'input')}`\n )\n .join('\\n')\n const upsertInterface = `export interface Upsert${Singular}Input {\\n${upsertInterfaceFields}\\n}`\n\n // Upsert field mappings\n const upsertMappings = upsertFields\n .map((f) => ` ${f.name}: ${generateFieldMapping(f)}`)\n .join(',\\n')\n\n // Field metadata for update processing\n const fieldMeta = upsertFields\n .map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`)\n .join(',\\n ')\n\n const cacheTag = `${schema.name}:all`\n\n const singleHtmlUpsertMappings = singleHtmlOutputFields\n .map((f) => ` ${f.name}Html`)\n .join(',\\n')\n\n const content = `'use server'\n\nimport db from '@cms/db'\nimport { ${tableVar} } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\nimport { updateTag } from 'next/cache'\n\nconst CACHE_TAG = '${cacheTag}'\n\n${dataInterface}\n\n${upsertInterface}\n\nexport interface Upsert${Singular}Result {\n success: boolean\n error?: string\n ${camelSingular}?: ${Singular}Data\n}\n\nexport async function get${Singular}(): Promise<${Singular}Data | null> {\n try {\n const result = await db.select().from(${tableVar}).where(eq(${tableVar}.id, 1)).limit(1)\n if (result.length === 0) return null\n return result[0] as ${Singular}Data\n } catch (error) {\n console.error('Error fetching ${singular}:', error)\n return null\n }\n}\n\nexport async function upsert${Singular}(input: Upsert${Singular}Input): Promise<Upsert${Singular}Result> {\n try {\n const fieldMeta = [\n ${fieldMeta}\n ]\n\n const processedData: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) {\n const field = fieldMeta.find(f => f.name === key)\n if (!field) continue\n if (field.type === 'list') {\n processedData[key] = value || []\n } else if (!field.required && ['date', 'timestamp', 'time', 'string', 'varchar', 'text', 'select'].includes(field.type)) {\n processedData[key] = value && value !== '' ? value : null\n } else {\n processedData[key] = value\n }\n }\n${singleHasHtmlOutput ? `\n const { renderMarkdownSync } = await import('@cms/lib/markdown/render')\\n` + singleHtmlOutputFields.map((f) => ` if (processedData.${f.name} !== undefined) {\n processedData.${f.name}Html = renderMarkdownSync(String(processedData.${f.name} || ''))\n }`).join('\\n') + '\\n' + singleHtmlOutputFields.map((f) => ` const ${f.name}Html = renderMarkdownSync(input.${f.name} || '')`).join('\\n') + '\\n' : ''}\n const now = new Date().toISOString()\n\n const result = await db\n .insert(${tableVar})\n .values({\n id: 1,\n${upsertMappings},${singleHasHtmlOutput ? '\\n' + singleHtmlOutputFields.map((f) => ` ${f.name}Html`).join(',\\n') + ',' : ''}\n createdAt: now,\n updatedAt: now\n })\n .onConflictDoUpdate({\n target: ${tableVar}.id,\n set: { ...processedData, updatedAt: now }\n })\n .returning()\n\n updateTag(CACHE_TAG)\n\n return {\n success: true,\n ${camelSingular}: result[0] as ${Singular}Data\n }\n } catch (error) {\n console.error('Error upserting ${singular}:', error)\n throw new Error(error instanceof Error ? error.message : 'Failed to save ${singular}')\n }\n}\n`\n\n if (!fs.existsSync(absActionsDir)) {\n fs.mkdirSync(absActionsDir, { recursive: true })\n }\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [path.join(actionsDir, `${schema.name}.ts`)] }\n}\n","/**\n * Generator 12: Cache module — cms/lib/cache/\n * Generates tags, cached queries, and revalidation helpers for all schemas\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize, pluralize, toScreamingSnake } from '../utils/string.js'\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\ninterface NestedLookupConfig {\n name: string\n pascalName: string\n camelName: string\n screamingSnake: string\n slugField: string\n}\n\ninterface CacheConfig {\n name: string\n singularName: string\n pluralName: string\n pascalSingular: string\n pascalPlural: string\n screamingSnake: string\n hasSlug: boolean\n isSingle: boolean\n nestedLookups: NestedLookupConfig[]\n}\n\n// ============================================================================\n// Schema Loading\n// ============================================================================\n\nfunction loadAllSchemas(cwd: string, schemasDir: string): Schema[] {\n const dir = path.join(cwd, schemasDir)\n if (!fs.existsSync(dir)) return []\n\n const files = fs.readdirSync(dir).filter((f) => f.endsWith('.json'))\n const seen = new Map<string, Schema>()\n\n for (const file of files) {\n if (file === 'schema.json') continue // skip metaschema\n const content = fs.readFileSync(path.join(dir, file), 'utf-8')\n const schema = JSON.parse(content) as Schema\n if (!schema.name) continue // skip non-entity JSON files\n seen.set(schema.name, schema)\n }\n\n return Array.from(seen.values())\n}\n\nfunction buildCacheConfig(schema: Schema): CacheConfig {\n const singularName = singularize(schema.name)\n const pluralName = pluralize(schema.name)\n const dbFields = flattenFields(schema.fields)\n const hasSlug = dbFields.some((f) => f.name === 'slug')\n\n const nestedLookups: NestedLookupConfig[] = (schema.nestedSlugLookups || []).map((lookup) => ({\n name: lookup.name,\n pascalName: toPascalCase(lookup.name),\n camelName: toCamelCase(lookup.name),\n screamingSnake: toScreamingSnake(lookup.name),\n slugField: lookup.slugField || 'slug'\n }))\n\n return {\n name: schema.name,\n singularName,\n pluralName,\n pascalSingular: toPascalCase(singularName),\n pascalPlural: toPascalCase(pluralName),\n screamingSnake: toScreamingSnake(pluralName),\n hasSlug,\n isSingle: schema.type === 'single',\n nestedLookups\n }\n}\n\n// ============================================================================\n// File Generators\n// ============================================================================\n\nfunction generateTags(configs: CacheConfig[]): string {\n const entries: string[] = []\n\n for (const c of configs) {\n entries.push(` ${c.screamingSnake}_ALL: '${c.pluralName}:all'`)\n\n if (c.isSingle) continue // single schemas only need the ALL tag\n\n if (c.hasSlug) {\n entries.push(\n ` ${c.screamingSnake}_BY_SLUG: (slug: string) => \\`${c.pluralName}:slug:\\${slug}\\``\n )\n }\n\n for (const n of c.nestedLookups) {\n entries.push(\n ` ${c.screamingSnake}_${n.screamingSnake}_BY_SLUG: (${c.singularName}Slug: string, ${n.camelName}Slug: string) => \\`${c.pluralName}:\\${${c.singularName}Slug}:${n.name}:\\${${n.camelName}Slug}\\``\n )\n }\n }\n\n entries.sort()\n\n return `/**\n * Cache tag constants for Next.js 'use cache' invalidation\n * AUTO-GENERATED — do not edit directly\n */\n\nexport const CACHE_TAGS = {\n${entries.join(',\\n')}\n} as const\n`\n}\n\nfunction generateCachedQueries(configs: CacheConfig[]): string {\n const actionImports: string[] = []\n const typeImports: string[] = []\n const fns: string[] = []\n\n for (const c of configs) {\n if (c.isSingle) {\n // Single schema: getCachedXxx() with no filters\n actionImports.push(`get${c.pascalSingular}`)\n\n fns.push(`\nexport const getCached${c.pascalSingular} = async () => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${c.pascalSingular}()\n}`)\n continue\n }\n\n // Entity schema: getCachedXxxPlural(filters) + slug lookups\n actionImports.push(`get${c.pascalPlural}`)\n typeImports.push(`Get${c.pascalPlural}Filters`)\n\n if (c.hasSlug) actionImports.push(`get${c.pascalSingular}BySlug`)\n for (const n of c.nestedLookups) actionImports.push(`get${n.pascalName}BySlug`)\n\n fns.push(`\nexport const getCached${c.pascalPlural} = async (filters?: Get${c.pascalPlural}Filters) => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${c.pascalPlural}(filters)\n}`)\n\n if (c.hasSlug) {\n fns.push(`\nexport const getCached${c.pascalSingular}BySlug = async (slug: string) => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_BY_SLUG(slug))\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${c.pascalSingular}BySlug(slug)\n}`)\n }\n\n for (const n of c.nestedLookups) {\n fns.push(`\nexport const getCached${n.pascalName}BySlug = async (${c.singularName}Slug: string, ${n.camelName}Slug: string) => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_${n.screamingSnake}_BY_SLUG(${c.singularName}Slug, ${n.camelName}Slug))\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${n.pascalName}BySlug(${c.singularName}Slug, ${n.camelName}Slug)\n}`)\n }\n }\n\n actionImports.sort()\n typeImports.sort()\n\n const typeImportStr =\n typeImports.length > 0\n ? `${typeImports\n .map((t) => {\n const schemaName = t\n .replace(/^Get/, '')\n .replace(/Filters$/, '')\n .toLowerCase()\n return `import type { ${t} } from '@cms/actions/${schemaName}'`\n })\n .join('\\n')}\\n`\n : ''\n\n // Group action imports by schema\n const actionsBySchema = new Map<string, string[]>()\n for (const c of configs) {\n if (c.isSingle) {\n actionsBySchema.set(c.name, [`get${c.pascalSingular}`])\n continue\n }\n const names: string[] = [`get${c.pascalPlural}`]\n if (c.hasSlug) names.push(`get${c.pascalSingular}BySlug`)\n for (const n of c.nestedLookups) names.push(`get${n.pascalName}BySlug`)\n actionsBySchema.set(c.name, names)\n }\n\n const actionImportLines = Array.from(actionsBySchema.entries())\n .map(([name, fns]) => `import { ${fns.join(', ')} } from '@cms/actions/${name}'`)\n .join('\\n')\n\n return `'use cache'\n\n/**\n * Cached query functions for Next.js 'use cache'\n * AUTO-GENERATED — do not edit directly\n */\n\nimport { cacheLife, cacheTag } from 'next/cache'\n${typeImportStr}${actionImportLines}\nimport { CACHE_TAGS } from './tags'\n${fns.join('\\n')}\n`\n}\n\nfunction generateRevalidate(configs: CacheConfig[]): string {\n const fns: string[] = []\n\n for (const c of configs) {\n if (c.isSingle) {\n fns.push(`\nexport const revalidate${c.pascalSingular} = async () => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n continue\n }\n\n fns.push(`\nexport const revalidate${c.pascalPlural} = async () => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n\n if (c.hasSlug) {\n fns.push(`\nexport const revalidate${c.pascalSingular}BySlug = async (slug: string) => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_BY_SLUG(slug), REVALIDATION_STRATEGY)\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n }\n\n for (const n of c.nestedLookups) {\n fns.push(`\nexport const revalidate${n.pascalName}BySlug = async (${c.singularName}Slug: string, ${n.camelName}Slug: string) => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_${n.screamingSnake}_BY_SLUG(${c.singularName}Slug, ${n.camelName}Slug), REVALIDATION_STRATEGY)\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n }\n }\n\n return `'use server'\n\n/**\n * Revalidation helpers for Next.js cache invalidation\n * AUTO-GENERATED — do not edit directly\n */\n\nimport { revalidateTag } from 'next/cache'\nimport { CACHE_TAGS } from './tags'\n\nconst REVALIDATION_STRATEGY = 'max' as const\n${fns.join('\\n')}\n`\n}\n\nfunction generateIndex(): string {\n return `/**\n * Cache module exports\n * AUTO-GENERATED — do not edit directly\n */\n\nexport * from './tags'\nexport * from './cached-queries'\nexport * from './cached-queries-custom'\nexport * from './revalidate'\n`\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface CacheGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate all cache files based on all schemas in cms/schemas/\n */\nexport function generateCache(\n _schema: Schema,\n cwd: string,\n cmsDir: string,\n _options: GeneratorOptions = {}\n): CacheGeneratorResult {\n const cacheDir = path.join(cwd, cmsDir, 'lib', 'cache')\n const schemasDir = path.join(cmsDir, 'schemas')\n\n // Load all schemas and build configs\n const schemas = loadAllSchemas(cwd, schemasDir)\n const configs = schemas.map(buildCacheConfig).sort((a, b) => a.name.localeCompare(b.name))\n\n if (!fs.existsSync(cacheDir)) {\n fs.mkdirSync(cacheDir, { recursive: true })\n }\n\n const files: string[] = []\n\n // tags.ts\n fs.writeFileSync(path.join(cacheDir, 'tags.ts'), generateTags(configs), 'utf-8')\n files.push(path.join(cmsDir, 'lib', 'cache', 'tags.ts'))\n\n // cached-queries.ts\n fs.writeFileSync(\n path.join(cacheDir, 'cached-queries.ts'),\n generateCachedQueries(configs),\n 'utf-8'\n )\n files.push(path.join(cmsDir, 'lib', 'cache', 'cached-queries.ts'))\n\n // revalidate.ts\n fs.writeFileSync(path.join(cacheDir, 'revalidate.ts'), generateRevalidate(configs), 'utf-8')\n files.push(path.join(cmsDir, 'lib', 'cache', 'revalidate.ts'))\n\n // cached-queries-custom.ts (user-maintained, scaffold only if missing)\n const customQueriesPath = path.join(cacheDir, 'cached-queries-custom.ts')\n if (!fs.existsSync(customQueriesPath)) {\n fs.writeFileSync(\n customQueriesPath,\n `/**\\n * Custom cached query functions (not auto-generated)\\n * Add your custom cached queries here.\\n */\\n\\nexport {}\\n`,\n 'utf-8'\n )\n files.push(path.join(cmsDir, 'lib', 'cache', 'cached-queries-custom.ts'))\n }\n\n // index.ts\n fs.writeFileSync(path.join(cacheDir, 'index.ts'), generateIndex(), 'utf-8')\n files.push(path.join(cmsDir, 'lib', 'cache', 'index.ts'))\n\n return { files }\n}\n","/**\n * Generator 4: Column definitions — (authenticated)/<n>/columns.tsx\n * Generates TanStack Table column definitions for entity list views\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport {\n generateColumnDef,\n generateFirstColumnDef,\n generateTitleFallback,\n isSortableColumn\n} from './column-defs.js'\nimport {\n generateDeleteActionTemplate,\n generateReorderButtonsTemplate,\n generateTruncateHelper\n} from './column-actions.js'\nimport { createCustomCellComponent } from './custom-cell.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface ColumnsGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate column definitions for entity list view\n */\nexport function generateColumns(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): ColumnsGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const columnsFilePath = path.join(entityDir, 'columns.tsx')\n\n if (fs.existsSync(columnsFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n\n const flatFields = flattenFields(schema.fields || [])\n const titleFallback = generateTitleFallback(flatFields)\n\n // --- Determine needed imports ---\n let needsArrowUpDown = false\n let needsBadge = false\n let needsButton = true // Always for actions column\n let needsAvatar = false\n let needsTruncate = false\n let needsReactQueryClient = false\n let needsToast = false\n let needsAlertDialog = false\n let needsTrash = false\n\n for (const column of schema.columns) {\n if (isSortableColumn(column)) {\n needsArrowUpDown = true\n needsButton = true\n }\n if (column.type === 'badge' || column.type === 'boolean') needsBadge = true\n if (column.type === 'image' || column.type === 'avatar') needsAvatar = true\n if (column.type === 'link') needsTruncate = true\n }\n\n const hasEdit = schema.actions?.edit ?? false\n const hasDelete = schema.actions?.delete ?? false\n if (hasDelete) {\n needsTrash = true\n needsAlertDialog = true\n needsReactQueryClient = true\n needsToast = true\n }\n\n // --- Build lucide icons ---\n const lucideIcons: string[] = []\n if (needsArrowUpDown) lucideIcons.push('ArrowUpDown')\n lucideIcons.push('ChevronDown', 'ChevronUp', 'Edit')\n if (needsTrash) lucideIcons.push('Trash')\n\n // --- Build UI component imports (individual per-component) ---\n const uiImports: string[] = []\n if (needsButton) uiImports.push(\"import { Button } from '@cms/components/ui/button'\")\n if (needsBadge) uiImports.push(\"import { Badge } from '@cms/components/ui/badge'\")\n uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (needsAvatar) {\n uiImports.push(\n \"import { Avatar, AvatarImage, AvatarFallback } from '@cms/components/ui/avatar'\"\n )\n }\n if (needsAlertDialog) {\n uiImports.push(`import {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger\n} from '@cms/components/ui/alert-dialog'`)\n }\n\n // --- Custom component imports ---\n const customImports: string[] = []\n for (const column of schema.columns) {\n if (column.type === 'custom' && column.component) {\n customImports.push(`import { ${column.component} } from './cells/${column.component}'`)\n createCustomCellComponent(schema, column.component, cwd, pagesDir, options)\n }\n }\n\n // --- Action imports ---\n const actionImports: string[] = []\n if (hasDelete) actionImports.push(`delete${Singular}`)\n\n // --- Generate columns ---\n const firstColumn = schema.columns[0]\n const restColumns = schema.columns.slice(1)\n\n const firstColDef = generateFirstColumnDef(firstColumn, flatFields, schema.name)\n const restColDefs = restColumns.map((col) => generateColumnDef(col, flatFields)).join(',\\n')\n\n // --- Delete handler ---\n const deleteHandler = hasDelete\n ? generateDeleteActionTemplate({ Singular, singular, plural })\n : ''\n\n // --- Reorder handler ---\n const reorderHandler = generateReorderButtonsTemplate()\n\n // --- Reorder column ---\n const reorderColumn = ` {\n id: 'reorder',\n header: () => <span className=\"sr-only\">Reorder</span>,\n cell: ({ row, table }) => {\n const reorderMode = table.options.meta?.reorderMode\n const onMoveRow = table.options.meta?.onMoveRow\n\n if (!reorderMode) return null\n\n const allRows = table.getRowModel().rows\n const currentIndex = allRows.findIndex(r => r.id === row.id)\n const isFirst = currentIndex === 0\n const isLast = currentIndex === allRows.length - 1\n\n return (\n <ReorderButtons\n id={row.original.id as number}\n isFirst={isFirst}\n isLast={isLast}\n onMoveRow={onMoveRow}\n />\n )\n },\n enableSorting: false,\n enableHiding: false,\n size: 80\n }`\n\n // --- Edit button ---\n let editButton = ''\n if (hasEdit) {\n editButton = ` <Button variant=\"outline\" className=\"size-8\" asChild>\n <Link href={\\`/cms/${schema.name}/\\${row.original.id}/edit\\`}>\n <Edit className=\"size-3\" strokeWidth={2} />\n <span className=\"sr-only\">Edit ${singular} {${titleFallback}}</span>\n </Link>\n </Button>`\n }\n\n // --- Actions column ---\n const actionsColumn = ` {\n id: 'actions',\n header: () => <div className=\"text-right\">Actions</div>,\n cell: ({ row }) => (\n <div className=\"flex justify-end items-center gap-2\">\n${editButton}\n${hasDelete ? ' <DeleteAction id={row.original.id as number} />' : ''}\n </div>\n )\n }`\n\n // --- Truncate helper ---\n const truncateHelper = needsTruncate\n ? generateTruncateHelper()\n : ''\n\n // --- Assemble file ---\n const content = `'use client'\n\nimport type { ColumnDef } from '@tanstack/react-table'\n${needsReactQueryClient ? \"import { useQueryClient } from '@tanstack/react-query'\" : ''}\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'\nimport Link from 'next/link'\nimport * as React from 'react'\n${needsToast ? \"import { toast } from 'sonner'\" : ''}\n${uiImports.join('\\n')}\n${actionImports.length > 0 ? `import { ${actionImports.join(', ')} } from '@cms/actions/${schema.name}'` : ''}\nimport type { ${Singular}Data } from '@cms/actions/${schema.name}'\n${customImports.join('\\n')}\n${truncateHelper}${deleteHandler}${reorderHandler}\nexport const columns: ColumnDef<${Singular}Data>[] = [\n${reorderColumn},\n${firstColDef}${restColDefs ? `,\\n${restColDefs}` : ''},\n${actionsColumn}\n]\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(columnsFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'columns.tsx')]\n }\n}\n","/**\n * Column definition generators for TanStack Table columns\n */\n\nimport type { SchemaColumn, SchemaField } from '../../types.js'\n\n// ============================================================================\n// Column Helpers\n// ============================================================================\n\nexport function isSortableColumn(column: SchemaColumn): boolean {\n if (typeof column.sortable === 'boolean') return column.sortable\n const nonSortableTypes = ['image', 'avatar', 'link', 'custom']\n return !nonSortableTypes.includes(column.type)\n}\n\nexport function generateTitleFallback(fields: SchemaField[]): string {\n const fieldNames = new Set(fields.map((f) => f.name))\n const fallbacks: string[] = []\n if (fieldNames.has('title')) fallbacks.push('row.original.title')\n if (fieldNames.has('name')) fallbacks.push('row.original.name')\n fallbacks.push('row.original.id')\n fallbacks.push(\"''\")\n return fallbacks.join(' || ')\n}\n\n// ============================================================================\n// Cell Renderers\n// ============================================================================\n\nexport function generateColumnDef(column: SchemaColumn, fields: SchemaField[]): string {\n const sortable = isSortableColumn(column)\n const headerDef = sortable\n ? `header: ({ column }) => {\n const sortDirection = column.getIsSorted()\n const sortLabel = sortDirection === 'asc'\n ? 'sorted ascending'\n : sortDirection === 'desc'\n ? 'sorted descending'\n : 'not sorted'\n\n return (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n aria-label={\\`Sort by ${column.header}, \\${sortLabel}\\`}\n aria-sort={sortDirection === 'asc' ? 'ascending' : sortDirection === 'desc' ? 'descending' : 'none'}\n >\n ${column.header}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n )\n }`\n : `header: '${column.header}'`\n\n const titleFallback = generateTitleFallback(fields)\n let cellDef = ''\n\n switch (column.type) {\n case 'image':\n cellDef = `cell: ({ row }) => {\n const imageUrl = row.getValue('${column.accessorKey}') ?? ''\n const title = ${titleFallback}\n return (\n <Avatar className=\"size-10 border\">\n <AvatarImage\n src={imageUrl}\n alt={title ? \\`${column.header} image for \\${title}\\` : '${column.header} image'}\n />\n <AvatarFallback>\n {String(title || imageUrl).substring(0, 2).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n )\n }`\n break\n case 'badge':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}')\n return (\n <Badge variant=\"outline\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </Badge>\n )\n }`\n break\n case 'date':\n cellDef = `cell: ({ row }) => {\n const date = new Date(row.getValue('${column.accessorKey}'))\n return (\n <div className=\"text-sm\">\n {date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric'\n })}\n </div>\n )\n }`\n break\n case 'email':\n cellDef = `cell: ({ row }) => {\n const email = row.getValue('${column.accessorKey}') as string\n return <div className=\"text-sm font-medium\">{email}</div>\n }`\n break\n case 'number':\n if (column.format === 'currency') {\n cellDef = `cell: ({ row }) => {\n const amount = row.getValue('${column.accessorKey}') as number\n return (\n <div className=\"text-sm font-medium\">\n {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount)}\n </div>\n )\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}') as number\n return <div className=\"text-sm\">{value}</div>\n }`\n }\n break\n case 'boolean':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}') as boolean\n return (\n <Badge variant={value ? 'outline' : 'secondary'}>\n {value ? 'Yes' : 'No'}\n </Badge>\n )\n }`\n break\n case 'link':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}') as string\n if (!value) return <div className=\"text-muted-foreground\">\\u2014</div>\n return (\n <a\n href={value}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-blue-600 hover:text-blue-800 hover:underline dark:text-blue-400 dark:hover:text-blue-300\"\n title={value}\n >\n {truncateStr(value, 50)}\n </a>\n )\n }`\n break\n case 'custom':\n if (column.component) {\n cellDef = `cell: ({ row }) => {\n return <${column.component} data={row.original} />\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}')\n return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>\n }`\n }\n break\n default:\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}')\n return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>\n }`\n break\n }\n\n return ` {\n accessorKey: '${column.accessorKey}',\n ${headerDef},\n ${cellDef}\n }`\n}\n\nexport function generateFirstColumnDef(\n column: SchemaColumn,\n fields: SchemaField[],\n schemaName: string\n): string {\n const sortable = isSortableColumn(column)\n const headerDef = sortable\n ? `header: ({ table, column }) => {\n const sortDirection = column.getIsSorted()\n const sortLabel = sortDirection === 'asc'\n ? 'sorted ascending'\n : sortDirection === 'desc'\n ? 'sorted descending'\n : 'not sorted'\n\n return (\n <div className=\"flex items-center gap-4\">\n <Checkbox\n checked={table.getIsAllPageRowsSelected()}\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n aria-label={\\`Sort by ${column.header}, \\${sortLabel}\\`}\n aria-sort={sortDirection === 'asc' ? 'ascending' : sortDirection === 'desc' ? 'descending' : 'none'}\n >\n ${column.header}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n </div>\n )\n }`\n : `header: ({ table }) => (\n <div className=\"flex items-center gap-4\">\n <Checkbox\n checked={table.getIsAllPageRowsSelected()}\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n <span>${column.header}</span>\n </div>\n )`\n\n const titleFallback = generateTitleFallback(fields)\n const linkBase = `/cms/${schemaName}`\n let cellDef = ''\n\n switch (column.type) {\n case 'image':\n cellDef = `cell: ({ row }) => {\n const imageUrl = row.original.${column.accessorKey} as string\n const title = ${titleFallback}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <Avatar className=\"size-10 border\">\n <AvatarImage\n src={imageUrl}\n alt={title ? \\`${column.header} image for \\${title}\\` : '${column.header} image'}\n />\n <AvatarFallback>\n {String(title || imageUrl).substring(0, 2).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'badge':\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <Badge variant=\"outline\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </Badge>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'date':\n cellDef = `cell: ({ row }) => {\n const date = new Date(row.original.${column.accessorKey})\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full\"\n >\n <div className=\"text-sm\">\n {date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric'\n })}\n </div>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'email':\n cellDef = `cell: ({ row }) => {\n const email = row.original.${column.accessorKey} as string\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full w-full max-w-[300px] py-3\"\n >\n <span className=\"text-sm font-medium truncate\">{email}</span>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'number':\n if (column.format === 'currency') {\n cellDef = `cell: ({ row }) => {\n const amount = row.original.${column.accessorKey} as number\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full\"\n >\n <div className=\"text-sm font-medium\">\n {new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD'\n }).format(amount)}\n </div>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey} as number\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full\"\n >\n <div className=\"text-sm\">{value}</div>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n }\n break\n case 'boolean':\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey} as boolean\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <Badge variant={value ? 'outline' : 'secondary'}>\n {value ? 'Yes' : 'No'}\n </Badge>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'custom':\n if (column.component) {\n cellDef = `cell: ({ row }) => {\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <${column.component} data={row.original} />\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full w-full max-w-[300px] py-3\"\n >\n <span className=\"truncate\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </span>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n }\n break\n case 'link':\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey} as string\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity max-w-[250px]\">\n {value ? (\n <a\n href={value}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-blue-600 hover:text-blue-800 hover:underline dark:text-blue-400 dark:hover:text-blue-300 truncate block\"\n title={value}\n onClick={(e) => e.stopPropagation()}\n >\n {truncateStr(value, 50)}\n </a>\n ) : (\n <span className=\"text-muted-foreground\">\\u2014</span>\n )}\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n default:\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full w-full max-w-[300px] py-3\"\n >\n <span className=\"truncate\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </span>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n }\n\n return ` {\n id: 'select',\n accessorKey: '${column.accessorKey}',\n ${headerDef},\n ${cellDef},\n enableSorting: ${sortable ? 'true' : 'false'},\n enableHiding: false\n }`\n}\n","/**\n * Template strings for inline column action components:\n * DeleteAction, ReorderButtons, and truncateStr helper\n */\n\n// ============================================================================\n// Delete Action Component Template\n// ============================================================================\n\nexport function generateDeleteActionTemplate(params: {\n Singular: string\n singular: string\n plural: string\n}): string {\n const { Singular, singular, plural } = params\n\n return `\nfunction DeleteAction({ id }: { id: number }) {\n const [open, setOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n const handleDelete = () => {\n startTransition(async () => {\n try {\n const result = await delete${Singular}(id)\n\n if (result.success) {\n toast.success('${Singular} deleted successfully')\n queryClient.refetchQueries({ queryKey: ['${plural}'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete ${singular}')\n }\n } catch (error) {\n toast.error('An error occurred')\n console.error(error)\n }\n })\n }\n\n return (\n <AlertDialog open={open} onOpenChange={setOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" className=\"size-8\" aria-label={\\`Delete ${singular} \\${id}\\`}>\n <Trash className=\"size-3\" strokeWidth={2} />\n <span className=\"sr-only\">Delete ${singular}</span>\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete this ${singular}.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n handleDelete()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n`\n}\n\n// ============================================================================\n// Reorder Buttons Component Template\n// ============================================================================\n\nexport function generateReorderButtonsTemplate(): string {\n return `\nfunction ReorderButtons({\n id,\n isFirst,\n isLast,\n onMoveRow\n}: {\n id: number\n isFirst: boolean\n isLast: boolean\n onMoveRow?: (id: number, direction: 'up' | 'down') => void\n}) {\n if (!onMoveRow) return null\n\n return (\n <div className=\"flex items-center gap-0.5\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => onMoveRow(id, 'up')}\n disabled={isFirst}\n aria-label=\"Move up\"\n className=\"size-7\"\n >\n <ChevronUp className=\"size-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => onMoveRow(id, 'down')}\n disabled={isLast}\n aria-label=\"Move down\"\n className=\"size-7\"\n >\n <ChevronDown className=\"size-4\" />\n </Button>\n </div>\n )\n}\n`\n}\n\n// ============================================================================\n// Truncate Helper Template\n// ============================================================================\n\nexport function generateTruncateHelper(): string {\n return `\nfunction truncateStr(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str\n return str.slice(0, maxLength) + '...'\n}\n`\n}\n","/**\n * Custom cell component generator — creates stub cell components for custom column types\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../../types.js'\nimport { toPascalCase, singularize } from '../../utils/string.js'\n\nexport function createCustomCellComponent(\n schema: Schema,\n componentName: string,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions\n): void {\n const cellsDir = path.join(cwd, pagesDir, schema.name, 'cells')\n const componentFilePath = path.join(cellsDir, `${componentName}.tsx`)\n\n if (fs.existsSync(componentFilePath) && !options.force) return\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n\n const content = `import type { ${Singular}Data } from '@cms/actions/${schema.name}'\n\ninterface ${componentName}Props {\n data: ${Singular}Data\n}\n\nexport function ${componentName}({ data }: ${componentName}Props) {\n return (\n <div>\n {JSON.stringify(data)}\n </div>\n )\n}\n`\n\n if (!fs.existsSync(cellsDir)) {\n fs.mkdirSync(cellsDir, { recursive: true })\n }\n fs.writeFileSync(componentFilePath, content, 'utf-8')\n}\n","/**\n * Generator 9: Create page — (authenticated)/<n>/new/page.tsx\n * Generates server page component for creating a new entity\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize, singularizeLabel, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface CreatePageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate create page component for adding a new entity\n */\nexport function generateCreatePage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): CreatePageGeneratorResult {\n const newDir = path.join(cwd, pagesDir, schema.name, 'new')\n const pageFilePath = path.join(newDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const singLabel = singularizeLabel(schema.label)\n const kebabName = toKebabCase(schema.name)\n\n const content = `import { ChevronLeft } from 'lucide-react'\nimport Link from 'next/link'\nimport { connection } from 'next/server'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { ${Singular}Form } from '../${kebabName}-form'\n\nexport default async function Create${Singular}Page() {\n await connection()\n\n return (\n <>\n <PageHeader title=\"Create ${singLabel}\" back={<Button variant=\"ghost\" size=\"icon\" asChild><Link href=\"/cms/${schema.name}\"><ChevronLeft /></Link></Button>} />\n <main className=\"container mx-auto max-w-5xl p-6 pb-20\">\n <${Singular}Form key={Date.now()} />\n </main>\n </>\n )\n}\n`\n\n if (!fs.existsSync(newDir)) {\n fs.mkdirSync(newDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'new', 'page.tsx')]\n }\n}\n","/**\n * Generator 1: Database schema — append table to cms/db/schema.ts\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, getManyToManyFields } from '../core/field-helpers/index.js'\nimport { toDrizzleType } from '../core/type-mappers/index.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize } from '../utils/string.js'\n\n// ============================================================================\n// Field Modifiers\n// ============================================================================\n\nfunction getFieldModifiers(field: SchemaField, needsSql: { value: boolean }): string {\n const modifiers: string[] = []\n\n if (field.primaryKey) {\n modifiers.push('.primaryKey()')\n }\n\n const isDateField = field.type === 'date' || field.type === 'timestamp'\n const hasValidDefault =\n field.default !== undefined && field.default !== null && !(isDateField && field.default === '')\n\n if (hasValidDefault) {\n if (typeof field.default === 'string') {\n modifiers.push(`.default('${field.default}')`)\n } else {\n modifiers.push(`.default(${field.default})`)\n }\n }\n\n if (field.name === 'createdAt' || field.name === 'updatedAt') {\n modifiers.push('.default(sql`CURRENT_TIMESTAMP`)')\n needsSql.value = true\n }\n\n if (field.required || field.primaryKey) {\n modifiers.push('.notNull()')\n }\n\n return modifiers.join('')\n}\n\n// ============================================================================\n// Table Generation\n// ============================================================================\n\nfunction generateTableDefinition(\n schema: Schema,\n requiredImports: Set<string>,\n needsSql: { value: boolean }\n): string {\n const tableName = toPascalCase(schema.name)\n const variableName = toCamelCase(schema.name)\n\n requiredImports.add('pgTable')\n\n // Flatten fields, exclude M2M relationships (handled via junction tables)\n const dbFields = flattenFields(schema.fields).filter(\n (f) => !(f.type === 'relationship' && f.multiple === true)\n )\n\n const hasDraftMode = schema.actions?.draft === true\n const hasPublishedField = dbFields.some((f) => f.name === 'published')\n\n const fieldDefs = dbFields\n .map((field) => {\n const drizzleType = toDrizzleType(field, requiredImports)\n const modifiers = getFieldModifiers(field, needsSql)\n const line = ` ${field.name}: ${drizzleType}${modifiers}`\n\n if ((field.type === 'richtext' || field.type === 'markdown') && field.output === 'html') {\n const snakeName = field.name.replace(/([A-Z])/g, '_$1').toLowerCase()\n requiredImports.add('text')\n return `${line},\\n ${field.name}Html: text('${snakeName}_html')`\n }\n\n return line\n })\n .join(',\\n')\n\n // Auto-add published field for draft mode\n let publishedField = ''\n if (hasDraftMode && !hasPublishedField) {\n requiredImports.add('boolean')\n publishedField = `,\\n published: boolean().notNull().default(false)`\n }\n\n // Auto-add timestamps\n const hasCreatedAt = dbFields.some((f) => f.name === 'createdAt')\n const hasUpdatedAt = dbFields.some((f) => f.name === 'updatedAt')\n let timestampFields = ''\n if (!hasCreatedAt || !hasUpdatedAt) {\n requiredImports.add('timestamp')\n needsSql.value = true\n }\n if (!hasCreatedAt) {\n timestampFields += `,\\n createdAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull()`\n }\n if (!hasUpdatedAt) {\n timestampFields += `,\\n updatedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull()`\n }\n\n // Auto-add sortOrder for drag-and-drop reordering (skip for single schemas)\n const isSingle = schema.type === 'single'\n const hasSortOrder = dbFields.some((f) => f.name === 'sortOrder')\n let sortOrderField = ''\n if (!isSingle && !hasSortOrder) {\n requiredImports.add('integer')\n sortOrderField = `,\\n sortOrder: integer().notNull().default(0)`\n }\n\n return `\\nexport const ${variableName} = pgTable(\\n '${tableName}',\\n {\\n${fieldDefs}${publishedField}${timestampFields}${sortOrderField}\\n }\\n)\\n`\n}\n\nfunction generateJunctionTable(\n schemaName: string,\n field: SchemaField,\n requiredImports: Set<string>\n): string {\n const singularSchema = singularize(schemaName)\n const singularRelation = singularize(field.relationship || '')\n const junctionName = `${singularSchema}${toPascalCase(field.relationship || '')}`\n const junctionPascal = toPascalCase(junctionName)\n const schemaIdCol = `${singularSchema}Id`\n const relationIdCol = `${singularRelation}Id`\n const schemaTableRef = toCamelCase(schemaName)\n const relationTableRef = toCamelCase(field.relationship || '')\n\n requiredImports.add('pgTable')\n requiredImports.add('integer')\n requiredImports.add('primaryKey')\n\n return `\\nexport const ${toCamelCase(junctionName)} = pgTable(\\n '${junctionPascal}',\\n {\\n ${schemaIdCol}: integer().notNull().references(() => ${schemaTableRef}.id, { onDelete: 'cascade' }),\\n ${relationIdCol}: integer().notNull().references(() => ${relationTableRef}.id, { onDelete: 'cascade' })\\n },\\n (table) => [primaryKey({ columns: [table.${schemaIdCol}, table.${relationIdCol}] })]\\n)\\n`\n}\n\n// ============================================================================\n// Import Merging\n// ============================================================================\n\nfunction mergeImports(content: string, requiredImports: Set<string>, needsSql: boolean): string {\n const pgCoreMatch = content.match(/import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/)\n\n // Use regex to detect sql import — handles single/double quotes, extra whitespace, semicolons\n const drizzleOrmMatch = content.match(/import\\s*\\{([^}]*)\\}\\s*from\\s*['\"]drizzle-orm['\"]/)\n const existingDrizzleOrmImports = new Set<string>()\n if (drizzleOrmMatch) {\n drizzleOrmMatch[1]\n .split(',')\n .map((i) => i.trim())\n .filter(Boolean)\n .forEach((i) => {\n existingDrizzleOrmImports.add(i)\n })\n }\n const hasSqlImport = existingDrizzleOrmImports.has('sql')\n\n // Collect existing pg-core imports\n const existing = new Set<string>()\n if (pgCoreMatch) {\n pgCoreMatch[1]\n .split(',')\n .map((i) => i.trim())\n .filter(Boolean)\n .forEach((i) => {\n existing.add(i)\n })\n }\n\n const merged = new Set([...existing, ...requiredImports])\n const sorted = Array.from(merged).sort()\n const newImport = `import {\\n ${sorted.join(',\\n ')}\\n} from 'drizzle-orm/pg-core'`\n\n let updated = content\n\n if (pgCoreMatch) {\n updated = updated.replace(/import\\s+\\{[^}]+\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/, newImport)\n } else if (drizzleOrmMatch) {\n updated = updated.replace(\n /import\\s*\\{[^}]*\\}\\s*from\\s*['\"]drizzle-orm['\"]/,\n (match) => `${match}\\n${newImport}`\n )\n } else {\n updated = `${newImport}\\n${updated}`\n }\n\n if (needsSql && !hasSqlImport) {\n if (drizzleOrmMatch) {\n // Add sql to existing drizzle-orm import\n existingDrizzleOrmImports.add('sql')\n const sortedOrm = Array.from(existingDrizzleOrmImports).sort()\n updated = updated.replace(\n /import\\s*\\{[^}]*\\}\\s*from\\s*['\"]drizzle-orm['\"]/,\n `import { ${sortedOrm.join(', ')} } from 'drizzle-orm'`\n )\n } else {\n updated = `import { sql } from 'drizzle-orm'\\n${updated}`\n }\n }\n\n return updated\n}\n\n// ============================================================================\n// Table End Finder (for --force replacement)\n// ============================================================================\n\nfunction findTableEnd(content: string, startIndex: number): number {\n let depth = 0\n let inString = false\n let stringChar = ''\n\n for (let i = startIndex; i < content.length; i++) {\n const char = content[i]\n const prev = i > 0 ? content[i - 1] : ''\n\n if ((char === '\"' || char === \"'\" || char === '`') && prev !== '\\\\') {\n if (!inString) {\n inString = true\n stringChar = char\n } else if (char === stringChar) {\n inString = false\n }\n continue\n }\n if (inString) continue\n\n if (char === '(' || char === '{' || char === '[') depth++\n if (char === ')' || char === '}' || char === ']') depth--\n\n if (depth === 0 && char === ')') {\n return i + 1\n }\n }\n\n return content.length\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface DatabaseGeneratorResult {\n files: string[]\n tableName: string\n junctionTables: string[]\n}\n\n/**\n * Generate database schema for an entity — appends to cms/db/schema.ts\n */\nexport function generateDatabase(\n schema: Schema,\n cwd: string,\n schemaDir: string,\n options: GeneratorOptions = {}\n): DatabaseGeneratorResult {\n const schemaFilePath = path.join(cwd, schemaDir)\n const files: string[] = []\n\n // Read existing schema.ts\n let content = ''\n if (fs.existsSync(schemaFilePath)) {\n content = fs.readFileSync(schemaFilePath, 'utf-8')\n }\n\n const variableName = toCamelCase(schema.name)\n\n // Check for existing table\n if (content.includes(`export const ${variableName} =`) && !options.force) {\n return {\n files: [],\n tableName: variableName,\n junctionTables: []\n }\n }\n\n const requiredImports = new Set<string>()\n const needsSql = { value: false }\n\n // Generate main table\n const tableDef = generateTableDefinition(schema, requiredImports, needsSql)\n\n // Generate junction tables for M2M\n const m2mFields = getManyToManyFields(schema.fields)\n const junctionDefs = m2mFields.map((f) => generateJunctionTable(schema.name, f, requiredImports))\n const junctionNames = m2mFields.map((f) => {\n const s = singularize(schema.name)\n return toCamelCase(`${s}${toPascalCase(f.relationship || '')}`)\n })\n\n let updated = content\n\n if (options.force && content.includes(`export const ${variableName} =`)) {\n // Replace existing table definition\n const start = content.indexOf(`export const ${variableName} =`)\n const end = findTableEnd(content, start)\n updated = content.slice(0, start) + tableDef.trim() + content.slice(end)\n } else {\n // Append new table\n updated = `${updated.trimEnd()}\\n${tableDef}`\n }\n\n // Handle junction tables\n for (let i = 0; i < m2mFields.length; i++) {\n const jName = junctionNames[i]\n if (options.force && updated.includes(`export const ${jName} =`)) {\n const start = updated.indexOf(`export const ${jName} =`)\n const end = findTableEnd(updated, start)\n updated = updated.slice(0, start) + junctionDefs[i].trim() + updated.slice(end)\n } else if (!updated.includes(`export const ${jName} =`)) {\n updated = `${updated.trimEnd()}\\n${junctionDefs[i]}`\n }\n }\n\n // Merge imports\n updated = mergeImports(updated, requiredImports, needsSql.value)\n\n // Write\n const dir = path.dirname(schemaFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(schemaFilePath, updated, 'utf-8')\n files.push(schemaDir)\n\n return {\n files,\n tableName: variableName,\n junctionTables: junctionNames\n }\n}\n","/**\n * Generator 10: Edit page — (authenticated)/<n>/[id]/edit/page.tsx\n * Generates server page component for editing an existing entity\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface EditPageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate edit page component for updating an existing entity\n */\nexport function generateEditPage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): EditPageGeneratorResult {\n const editDir = path.join(cwd, pagesDir, schema.name, '[id]', 'edit')\n const pageFilePath = path.join(editDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const camelSingular = toCamelCase(singular)\n const kebabName = toKebabCase(schema.name)\n\n const content = `import { ChevronLeft } from 'lucide-react'\nimport Link from 'next/link'\nimport { notFound } from 'next/navigation'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { get${Singular}ById } from '@cms/actions/${schema.name}'\nimport { ${Singular}Form } from '../../${kebabName}-form'\n\ninterface PageProps {\n params: Promise<{\n id: string\n }>\n}\n\nexport default async function Edit${Singular}Page({ params }: PageProps) {\n const { id } = await params\n const ${camelSingular} = await get${Singular}ById(Number.parseInt(id, 10))\n\n if (!${camelSingular}) {\n notFound()\n }\n\n return (\n <>\n <PageHeader title=\"Edit ${Singular}\" back={<Button variant=\"ghost\" size=\"icon\" asChild><Link href=\"/cms/${schema.name}\"><ChevronLeft /></Link></Button>} />\n <main className=\"container mx-auto max-w-5xl p-6 pb-20\">\n <${Singular}Form key={${camelSingular}.id} initialData={${camelSingular}} />\n </main>\n </>\n )\n}\n`\n\n if (!fs.existsSync(editDir)) {\n fs.mkdirSync(editDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, '[id]', 'edit', 'page.tsx')]\n }\n}\n","/**\n * Entity form generator — create/edit form with Zod validation, React Hook Form, and mutations\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, hasFieldType, hasIconUsage } from '../../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport { generateFieldJSX } from './field-jsx.js'\nimport {\n type FormGeneratorResult,\n collectRelationshipFields,\n buildZodFields,\n buildDefaultValues,\n buildUiImports\n} from './form-shared.js'\n\nexport function generateForm(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): FormGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const formFilePath = path.join(entityDir, `${schema.name}-form.tsx`)\n\n if (fs.existsSync(formFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n\n // Analyze fields\n const allFormFields = schema.fields.filter(\n (f) => !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt'\n )\n const flatFields = flattenFields(allFormFields)\n const hasDraft = schema.actions?.draft === true\n\n // Collect tab field names\n const tabFieldNames = new Set<string>()\n for (const f of schema.fields) {\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) for (const tf of tab.fields) tabFieldNames.add(tf.name)\n }\n }\n }\n\n // Check what components are needed\n const hasBoolean = hasFieldType(schema.fields, 'boolean')\n const hasImage = hasFieldType(schema.fields, 'image')\n const hasVideo = hasFieldType(schema.fields, 'video')\n const hasMedia = hasFieldType(schema.fields, 'media')\n const hasIcon = hasFieldType(schema.fields, 'icon')\n const hasIconPostfix = hasIconUsage(schema.fields)\n const hasDate = hasFieldType(schema.fields, 'date')\n const hasSelect = hasFieldType(schema.fields, 'select')\n const hasMarkdown = hasFieldType(schema.fields, 'markdown')\n const hasRichtext = hasFieldType(schema.fields, 'richtext')\n const hasTextarea = hasFieldType(schema.fields, 'text')\n const hasSeparator = hasFieldType(schema.fields, 'separator')\n const hasRelationship = hasFieldType(schema.fields, 'relationship')\n const hasTabsField = schema.fields.some((f) => f.type === 'tabs')\n const tabsField = schema.fields.find((f) => f.type === 'tabs')\n const firstTabName = tabsField?.tabs?.[0]?.name || ''\n\n const mainRelFields = collectRelationshipFields(schema.fields, tabFieldNames)\n\n // Collect list fields with nested fields (need useFieldArray hooks)\n const listFieldsWithNested: SchemaField[] = []\n function collectListFields(fields: SchemaField[]): void {\n for (const f of fields) {\n if (f.type === 'list' && f.fields && f.fields.length > 0 && !f.hidden) {\n listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFields(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collectListFields(tab.fields)\n }\n }\n }\n }\n collectListFields(allFormFields)\n const hasList = hasFieldType(schema.fields, 'list')\n const hasNestedList = listFieldsWithNested.length > 0\n // Simple list uses DynamicListField; nested list uses useFieldArray + Accordion\n const hasSimpleList =\n hasList && flatFields.some((f) => f.type === 'list' && (!f.fields || f.fields.length === 0))\n\n // Build Zod schema\n const zodFields = buildZodFields(flatFields)\n\n // Build default values\n const defaultValues = buildDefaultValues(flatFields)\n\n // Build form fields JSX\n const formFieldsJSX = allFormFields\n .filter((f) => !(hasDraft && f.name === 'published'))\n .map((f) => {\n if (f.type === 'tabs' && f.tabs) {\n const tabsList = f.tabs\n .map((t) => ` <TabsTrigger value=\"${t.name}\">${t.label}</TabsTrigger>`)\n .join('\\n')\n const tabsContent = f.tabs\n .map((t) => {\n const tabFields = (t.fields || [])\n .map((tf) => generateFieldJSX(tf, ' '))\n .join('\\n')\n return ` <TabsContent value=\"${t.name}\" className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${tabFields}\n </TabsContent>`\n })\n .join('\\n')\n return ` <Tabs value={activeTab} onValueChange={setActiveTab} className=\"w-full\">\n <TabsList>\n${tabsList}\n </TabsList>\n${tabsContent}\n </Tabs>`\n }\n if (tabFieldNames.has(f.name)) return ''\n return generateFieldJSX(f)\n })\n .filter(Boolean)\n .join('\\n')\n\n // --- Build imports ---\n const uiImports = buildUiImports({\n hasBoolean,\n hasTextarea,\n hasImage,\n hasVideo,\n hasMedia,\n hasIcon,\n hasIconPostfix,\n hasDate,\n hasMarkdown,\n hasRichtext,\n hasSeparator,\n hasSelect,\n hasTabsField,\n hasRelationship,\n hasSimpleList,\n hasNestedList\n })\n\n // Lucide icons\n const lucideIcons: string[] = []\n if (hasRelationship) lucideIcons.push('Check', 'ChevronsUpDown')\n if (hasNestedList) {\n if (!lucideIcons.includes('Plus')) lucideIcons.push('Plus')\n if (!lucideIcons.includes('X')) lucideIcons.push('X')\n }\n\n // Relationship hooks\n const relHookImports = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return `import { use${relPlural} } from '@cms/hooks/use-${f.relationship}'`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // Relationship state\n const relState = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return ` const [${f.name}Open, set${toPascalCase(f.name)}Open] = React.useState(false)\n const { data: ${f.relationship}Data } = use${relPlural}()`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // List field array hooks\n const fieldArrayHooks = listFieldsWithNested\n .map((field) => {\n const pascalFieldName = toPascalCase(field.name)\n return ` const [${field.name}Expanded, set${pascalFieldName}Expanded] = React.useState<string | undefined>(undefined)\n const ${field.name}FieldArray = useFieldArray({\n control: form.control,\n name: '${field.name}'\n })`\n })\n .join('\\n')\n\n const needsReact = mainRelFields.length > 0 || hasNestedList\n\n // --- Assemble file ---\n const content = `'use client'\n${needsReact ? \"\\nimport * as React from 'react'\" : ''}\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'${lucideIcons.length > 0 ? `\\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'` : ''}\nimport { useRouter } from 'next/navigation'\nimport {${hasNestedList ? ' useFieldArray,' : ''} useForm } from 'react-hook-form'\nimport { toast } from 'sonner'\nimport { z } from 'zod/v3'${hasTabsField ? \"\\nimport { useQueryState } from 'nuqs'\" : ''}${hasRelationship ? \"\\nimport { cn } from '@cms/utils/cn'\" : ''}\n${relHookImports ? `${relHookImports}\\n` : ''}${uiImports.join('\\n')}\nimport type {\n Create${Singular}Input,\n ${Singular}Data,\n Update${Singular}Input\n} from '@cms/actions/${schema.name}'\nimport { create${Singular}, update${Singular} } from '@cms/actions/${schema.name}'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\nexport type FormValues = z.infer<typeof formSchema>\n\ninterface ${Singular}FormProps {\n initialData?: ${Singular}Data\n}\n\nexport function ${Singular}Form({ initialData }: ${Singular}FormProps) {\n const router = useRouter()\n const queryClient = useQueryClient()${hasTabsField ? `\\n const [activeTab, setActiveTab] = useQueryState('tab', { defaultValue: '${firstTabName}' })` : ''}${relState ? `\\n${relState}` : ''}\n\n const createMutation = useMutation({\n mutationFn: (data: Create${Singular}Input) => create${Singular}(data),\n onSuccess: async () => {\n toast.success('${Singular} created successfully')\n await queryClient.invalidateQueries({ queryKey: ['${plural}'] })\n router.push('/cms/${schema.name}')\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to create ${singular}')\n }\n })\n\n const updateMutation = useMutation({\n mutationFn: (data: Update${Singular}Input) => update${Singular}(data),\n onSuccess: () => {\n toast.success('${Singular} updated successfully')\n queryClient.invalidateQueries({ queryKey: ['${plural}'] })\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to update ${singular}')\n }\n })\n\n const isPending = createMutation.isPending || updateMutation.isPending\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n${defaultValues}\n }\n })\n${fieldArrayHooks ? `\\n${fieldArrayHooks}\\n` : ''}\n function onSubmit(values: FormValues${hasDraft ? ', publishedValue: boolean = false' : ''}) {\n const cleanedValues = Object.fromEntries(\n Object.entries(values).map(([key, value]) => [key, value === undefined ? '' : value])\n ) as FormValues\n\n if (initialData) {\n updateMutation.mutate({\n id: initialData.id as number,\n ...cleanedValues${hasDraft ? ',\\n published: publishedValue' : ''}\n })\n } else {\n const { id: _id, ...createValues } = cleanedValues\n createMutation.mutate({\n ...createValues${hasDraft ? ',\\n published: publishedValue' : ''}\n } as Create${Singular}Input)\n }\n }\n\n return (\n <Form {...form}>\n <form id=\"${schema.name}-form\" onSubmit={form.handleSubmit((values) => onSubmit(values${hasDraft ? ', false' : ''}), (errors) => {\n console.error('Form validation errors:', errors)\n const firstError = Object.values(errors)[0]\n if (firstError?.message) {\n toast.error(String(firstError.message))\n } else {\n toast.error('Please fix the form errors before submitting')\n }\n })} className=\"space-y-6\">\n <div className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${formFieldsJSX}\n </div>\n\n <div className=\"flex items-center fixed bottom-0 md:left-[calc(var(--sidebar-width))] w-screen md:w-[calc(100svw-var(--sidebar-width)-4px)] right-0 bg-secondary border-t\">\n <div className=\"flex mx-auto py-4 w-full max-w-5xl items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push('/cms/${schema.name}')}\n disabled={isPending}\n size=\"lg\"\n >\n Cancel\n </Button>\n${\n hasDraft\n ? ` <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => form.handleSubmit((values) => onSubmit(values, false))()}\n disabled={isPending}\n size=\"lg\"\n >\n {isPending ? 'Saving...' : 'Save as Draft'}\n </Button>\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={() => form.handleSubmit((values) => onSubmit(values, true))()}\n disabled={isPending}\n size=\"lg\"\n >\n {isPending ? 'Publishing...' : initialData ? 'Update & Publish' : 'Publish'}\n </Button>`\n : ` <Button type=\"submit\" disabled={isPending} size=\"lg\">\n {isPending ? 'Saving...' : initialData ? 'Update' : 'Create'}\n </Button>`\n}\n </div>\n </div>\n </form>\n </Form>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(formFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]\n }\n}\n","/**\n * Zod schema generation helpers for entity/single forms\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\n\nexport function getFormFieldType(field: SchemaField): string {\n switch (field.type) {\n case 'boolean':\n return 'checkbox'\n case 'text':\n return 'textarea'\n case 'markdown':\n return 'markdown'\n case 'richtext':\n return 'richtext'\n case 'number':\n case 'decimal':\n return 'number'\n case 'date':\n return 'date'\n case 'time':\n return 'time'\n case 'timestamp':\n return 'datetime-local'\n default:\n return 'text'\n }\n}\n\nexport function getZodType(field: SchemaField): string {\n const label = field.label || field.name\n\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return field.required\n ? `z.number({ message: '${label} is required' })`\n : 'z.number().optional()'\n case 'boolean':\n return 'z.boolean()'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext': {\n if (field.name.toLowerCase().includes('email')) {\n const base = field.required\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().email('Please enter a valid email address').optional()`\n return field.length ? `${base}.max(${field.length})` : base\n }\n const base = field.required ? `z.string().min(1, '${label} is required')` : 'z.string()'\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'date':\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n return `z.string().min(1, '${label} is required')`\n case 'timestamp':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'image':\n case 'video':\n case 'media': {\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n const base = `z.string().min(1, 'Please upload ${label.toLowerCase()}').url('Please provide a valid URL')`\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nested = field.fields\n .flatMap((nf) => {\n const defs: string[] = []\n const zodType = getZodType(nf)\n const alreadyOptional = zodType.includes('.optional()')\n let def = ` ${quotePropertyName(nf.name)}: ${zodType}`\n if (!nf.required && !alreadyOptional) def += '.optional()'\n defs.push(def)\n if (nf.hasIcon)\n defs.push(` ${quotePropertyName(`${nf.name}Icon`)}: z.string().optional()`)\n return defs\n })\n .join(',\\n')\n const obj = `z.object({\\n${nested}\\n })`\n const arr = field.maxItems ? `z.array(${obj}).max(${field.maxItems})` : `z.array(${obj})`\n return field.required\n ? `${arr}.min(1, '${label} must have at least one item')`\n : `${arr}.optional()`\n }\n return field.required\n ? `z.array(z.string()).min(1, '${label} must have at least one item')`\n : 'z.array(z.string()).optional()'\n case 'select': {\n if (field.options && field.options.length > 0) {\n const values = field.options.map((o) => `'${o.value}'`).join(', ')\n const arr = `[${values}] as const`\n return field.required\n ? `z.string().min(1, '${label} is required').refine((val) => (${arr} as readonly string[]).includes(val), { message: 'Invalid ${label}' })`\n : `z.string().refine((val) => !val || (${arr} as readonly string[]).includes(val), { message: 'Invalid ${label}' }).optional()`\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'icon':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'relationship':\n if (field.multiple) {\n return field.required\n ? `z.array(z.number()).min(1, '${label} is required')`\n : 'z.array(z.number()).optional()'\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'group':\n if (field.fields && field.fields.length > 0) {\n const nested = field.fields\n .map((nf) => {\n const zodType = getZodType(nf)\n const alreadyOptional = zodType.includes('.optional()')\n let def = ` ${quotePropertyName(nf.name)}: ${zodType}`\n if (!nf.required && !alreadyOptional) def += '.optional()'\n return def\n })\n .join(',\\n')\n return field.required\n ? `z.object({\\n${nested}\\n })`\n : `z.object({\\n${nested}\\n }).optional()`\n }\n return 'z.record(z.unknown()).optional()'\n default:\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n","/**\n * List/nested-list JSX generation for form fields\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { toPascalCase, singularize } from '../../utils/string.js'\n\nexport function renderListField(field: SchemaField, indent: string, label: string): string {\n const listHintJSX = field.hint\n ? `${indent} <p className=\"text-[0.8rem] text-muted-foreground\">${field.hint}</p>`\n : ''\n\n // Simple string list — use DynamicListField\n if (!field.fields || field.fields.length === 0) {\n return `${indent}<DynamicListField\n${indent} name=\"${field.name}\"\n${indent} label=\"${label}\"\n${indent} disabled={isPending}${field.maxItems ? `\\n${indent} maxItems={${field.maxItems}}` : ''}\n${indent} placeholder=\"Enter value\"\n${indent}/>`\n }\n\n // Nested fields list — useFieldArray + Accordion\n const singularLabel = singularize(label)\n const pascalFieldName = toPascalCase(field.name)\n\n // Find title field for accordion header\n const stringTypes = ['string', 'varchar', 'text']\n const titleField =\n field.fields.find((f) => f.name === 'title' && stringTypes.includes(f.type)) ||\n field.fields.find((f) => f.name === 'name' && stringTypes.includes(f.type)) ||\n field.fields.find((f) => stringTypes.includes(f.type))\n const accordionTitle = titleField\n ? `{form.watch(\\`${field.name}.\\${index}.${titleField.name}\\`) || '${singularLabel} ' + (index + 1)}`\n : `${singularLabel} {index + 1}`\n\n // Generate nested field JSX\n const nestedFieldsJSX = field.fields\n .map((nf) => {\n const nestedLabel = nf.label || nf.name\n const nestedHint = nf.hint\n ? `\\n${indent} <FormDescription>${nf.hint}</FormDescription>`\n : ''\n if (nf.type === 'boolean') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-row items-start space-x-3 space-y-0\">\n${indent} <FormControl>\n${indent} <Checkbox checked={formField.value} onCheckedChange={formField.onChange} disabled={isPending} />\n${indent} </FormControl>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n if (nf.type === 'image') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <ImageUploadField value={formField.value} onChange={formField.onChange} onBlur={formField.onBlur} disabled={isPending} maxSizeInMB={10} label=\"\" />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n if (nf.type === 'video') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <VideoUploadField value={formField.value} onChange={formField.onChange} onBlur={formField.onBlur} disabled={isPending} maxSizeInMB={100} label=\"\" />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n if (nf.type === 'media') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <MediaUploadField value={formField.value} onChange={formField.onChange} onBlur={formField.onBlur} disabled={isPending} maxSizeInMB={100} label=\"\" />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n // Default: text input for nested fields\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <Input placeholder=\"Enter ${nestedLabel.toLowerCase()}\" disabled={isPending} {...formField} />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n })\n .join('\\n')\n\n return `${indent}<FormItem>\n${indent} {${field.name}FieldArray.fields.length === 0 && (\n${indent} <div className=\"text-sm text-muted-foreground rounded-lg border border-dashed p-6 text-center\">\n${indent} <p>No ${label.toLowerCase()} added yet.</p>\n${indent} <Button\n${indent} type=\"button\"\n${indent} variant=\"outline\"\n${indent} size=\"sm\"\n${indent} className=\"mt-2\"\n${indent} onClick={() => {\n${indent} ${field.name}FieldArray.append({${field.fields.map((nf) => `${nf.name}: ${nf.type === 'boolean' ? 'false' : \"''\"}`).join(', ')}})\n${indent} set${pascalFieldName}Expanded(\\`item-\\${${field.name}FieldArray.fields.length + 1}\\`)\n${indent} }}\n${indent} disabled={isPending}\n${indent} >\n${indent} <Plus className=\"size-3\" />\n${indent} Add ${singularLabel}\n${indent} </Button>\n${indent} </div>\n${indent} )}\n${indent} {${field.name}FieldArray.fields.length > 0 && (\n${indent} <div className=\"space-y-5\">\n${indent} <div className=\"flex items-center justify-between\">\n${indent} <Label className=\"text-base\">${label}</Label>\n${indent} <Button\n${indent} type=\"button\"\n${indent} variant=\"outline\"\n${indent} size=\"sm\"\n${indent} onClick={() => {\n${indent} ${field.name}FieldArray.append({${field.fields.map((nf) => `${nf.name}: ${nf.type === 'boolean' ? 'false' : \"''\"}`).join(', ')}})\n${indent} set${pascalFieldName}Expanded(\\`item-\\${${field.name}FieldArray.fields.length + 1}\\`)\n${indent} }}\n${indent} disabled={isPending${field.maxItems ? ` || ${field.name}FieldArray.fields.length >= ${field.maxItems}` : ''}}\n${indent} >\n${indent} <Plus className=\"size-3\" />\n${indent} Add ${singularLabel}\n${indent} </Button>\n${indent} </div>\n${listHintJSX ? `${listHintJSX}\\n` : ''}${indent} <Accordion\n${indent} type=\"single\"\n${indent} collapsible\n${indent} className=\"w-full gap-1 flex flex-col\"\n${indent} value={${field.name}Expanded}\n${indent} onValueChange={set${pascalFieldName}Expanded}\n${indent} >\n${indent} {${field.name}FieldArray.fields.map((item, index) => (\n${indent} <AccordionItem\n${indent} key={item.id}\n${indent} value={\\`item-\\${index + 1}\\`}\n${indent} className=\"p-0 border-none\"\n${indent} >\n${indent} <div className=\"space-y-5 rounded-lg border p-4 bg-secondary/50 [&_h3]:m-0 w-full\">\n${indent} <AccordionTrigger className=\"flex items-center p-0 justify-between w-full\">\n${indent} <h4 className=\"text-sm font-medium w-full\">\n${indent} ${accordionTitle}\n${indent} </h4>\n${indent} <Button\n${indent} asChild\n${indent} variant=\"ghost\"\n${indent} size=\"sm\"\n${indent} disabled={isPending}\n${indent} >\n${indent} <span\n${indent} role=\"button\"\n${indent} tabIndex={0}\n${indent} onClick={(e) => { e.stopPropagation(); ${field.name}FieldArray.remove(index); }}\n${indent} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); ${field.name}FieldArray.remove(index); } }}\n${indent} className=\"cursor-pointer\"\n${indent} >\n${indent} <X className=\"size-3\" />\n${indent} </span>\n${indent} </Button>\n${indent} </AccordionTrigger>\n${indent} <AccordionContent className=\"flex flex-col gap-4 px-1\">\n${indent} <Separator className=\"mt-2\" />\n${indent} <div className=\"space-y-5\">\n${nestedFieldsJSX}\n${indent} </div>\n${indent} </AccordionContent>\n${indent} </div>\n${indent} </AccordionItem>\n${indent} ))}\n${indent} </Accordion>\n${indent} </div>\n${indent} )}\n${indent}</FormItem>`\n}\n","/**\n * Form field JSX generation — dispatcher + per-type renderers\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport { getFormFieldType } from './zod-schema.js'\nimport { renderListField } from './field-jsx-nested.js'\n\nfunction generateIconPostfix(field: SchemaField, indent: string): string {\n const label = field.label || field.name\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}Icon\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label} Icon</FormLabel>\n${indent} <FormControl>\n${indent} <IconPicker\n${indent} value={formField.value}\n${indent} onValueChange={formField.onChange}\n${indent} triggerPlaceholder=\"Select icon\"\n${indent} />\n${indent} </FormControl>\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nexport function generateFieldJSX(field: SchemaField, indent = ' '): string {\n if (field.hidden) return ''\n\n const mainJSX = generateFieldJSXCore(field, indent)\n if (!mainJSX) return ''\n\n if (field.hasIcon) {\n return `${mainJSX}\\n${generateIconPostfix(field, indent)}`\n }\n\n return mainJSX\n}\n\nfunction generateFieldJSXCore(field: SchemaField, indent = ' '): string {\n const fieldType = getFormFieldType(field)\n const label = field.label || field.name\n const hintJSX = field.hint\n ? `${indent} <FormDescription>${field.hint}</FormDescription>`\n : ''\n\n if (field.type === 'group' && field.fields) return renderGroupField(field, indent, label)\n if (field.type === 'separator') return renderSeparatorField(field, indent)\n if (field.type === 'boolean') return renderBooleanField(field, indent, label, hintJSX)\n if (field.type === 'image') return renderImageField(field, indent, label, hintJSX)\n if (field.type === 'video') return renderVideoField(field, indent, label, hintJSX)\n if (field.type === 'media') return renderMediaField(field, indent, label, hintJSX)\n if (field.type === 'icon') return renderIconField(field, indent, label, hintJSX)\n if (field.type === 'date') return renderDateField(field, indent, label, hintJSX)\n if (field.type === 'select') return renderSelectField(field, indent, label, hintJSX)\n if (field.type === 'richtext') return renderRichtextField(field, indent, label, hintJSX)\n if (field.type === 'markdown') return renderMarkdownField(field, indent, label, hintJSX)\n if (field.type === 'text') return renderTextareaField(field, indent, label, hintJSX)\n if (field.type === 'relationship' && field.relationship)\n return renderRelationshipField(field, indent, label, hintJSX)\n if (field.type === 'list') return renderListField(field, indent, label)\n\n return renderDefaultField(field, indent, label, fieldType, hintJSX)\n}\n\nfunction renderGroupField(field: SchemaField, indent: string, label: string): string {\n const columns = field.columns || 1\n const gridClass = columns > 1 ? `grid-cols-${columns}` : 'grid-cols-1'\n const groupFields = field.fields!.map((nf) => generateFieldJSX(nf, `${indent} `)).join('\\n')\n const heading =\n label && label !== field.name\n ? `${indent}<h3 className=\"text-lg font-medium\">${label}</h3>\\n`\n : ''\n return `${indent}<div className=\"space-y-5\">\n${heading}${indent} <div className=\"grid ${gridClass} gap-4\">\n${groupFields}\n${indent} </div>\n${indent}</div>`\n}\n\nfunction renderSeparatorField(field: SchemaField, indent: string): string {\n if (field.label) {\n return `${indent}<div className=\"relative my-4\">\n${indent} <div className=\"absolute inset-0 flex items-center\">\n${indent} <Separator className=\"w-full\" />\n${indent} </div>\n${indent} <div className=\"relative flex justify-center text-xs uppercase\">\n${indent} <span className=\"bg-background px-2 text-muted-foreground\">${field.label}</span>\n${indent} </div>\n${indent}</div>`\n }\n return `${indent}<Separator className=\"my-4\" />`\n}\n\nfunction renderBooleanField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-row items-start space-x-3 space-y-0\">\n${indent} <FormControl>\n${indent} <Checkbox\n${indent} checked={formField.value}\n${indent} onCheckedChange={formField.onChange}\n${indent} disabled={isPending}\n${indent} />\n${indent} </FormControl>\n${indent} <div className=\"space-y-1 leading-none\">\n${indent} <FormLabel>${label}</FormLabel>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} </div>\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderImageField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <ImageUploadField\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} onBlur={formField.onBlur}\n${indent} disabled={isPending}\n${indent} maxSizeInMB={10}\n${indent} label=\"\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderVideoField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <VideoUploadField\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} onBlur={formField.onBlur}\n${indent} disabled={isPending}\n${indent} maxSizeInMB={100}\n${indent} label=\"\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderMediaField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <MediaUploadField\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} onBlur={formField.onBlur}\n${indent} disabled={isPending}\n${indent} maxSizeInMB={100}\n${indent} label=\"\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderIconField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <IconPicker\n${indent} value={formField.value}\n${indent} onValueChange={formField.onChange}\n${indent} triggerPlaceholder=\"Select ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderDateField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <DatePicker\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} disabled={isPending}\n${indent} placeholder=\"Select ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderSelectField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n const options = field.options || []\n const optionsJSX = options\n .map(\n (o) =>\n `${indent} <SelectItem key=\"${o.value}\" value=\"${o.value}\">${o.label}</SelectItem>`\n )\n .join('\\n')\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <Select\n${indent} value={formField.value}\n${indent} onValueChange={formField.onChange}\n${indent} disabled={isPending}\n${indent} >\n${indent} <SelectTrigger>\n${indent} <SelectValue placeholder=\"Select ${label.toLowerCase()}\" />\n${indent} </SelectTrigger>\n${indent} <SelectContent>\n${optionsJSX}\n${indent} </SelectContent>\n${indent} </Select>\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderRichtextField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <RichTextEditor\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} className=\"min-h-[300px]\"\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderMarkdownField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <MarkdownEditor\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} componentSnippets={{}}\n${indent} className=\"min-h-[300px]\"\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderTextareaField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <Textarea\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} className=\"min-h-[100px]\"\n${indent} disabled={isPending}\n${indent} {...formField}\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderRelationshipField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n const relName = field.relationship!\n const relSingular = singularize(relName)\n const relPascal = toPascalCase(relSingular)\n const displayField = `(('name' in item && item.name) || ('title' in item && item.title) || ('label' in item && item.label) || \\`${relPascal} \\${item.id ?? 'Unknown'}\\`) as string`\n const dataArray = `${relName}Data?.${relName}`\n\n if (field.multiple) {\n return renderMultiRelationshipField(field, indent, label, hintJSX, displayField, dataArray, relSingular)\n }\n\n return renderSingleRelationshipField(field, indent, label, hintJSX, displayField, dataArray, relSingular)\n}\n\nfunction renderMultiRelationshipField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string,\n displayField: string,\n dataArray: string,\n relSingular: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-col\">\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <Popover open={${field.name}Open} onOpenChange={set${toPascalCase(field.name)}Open}>\n${indent} <PopoverTrigger asChild>\n${indent} <FormControl>\n${indent} <Button\n${indent} variant=\"outline\"\n${indent} role=\"combobox\"\n${indent} className={cn(\"w-full justify-between\", (!formField.value || formField.value.length === 0) && \"text-muted-foreground\")}\n${indent} disabled={isPending}\n${indent} >\n${indent} {(formField.value?.length ?? 0) > 0\n${indent} ? \\`\\${formField.value!.length} selected\\`\n${indent} : \"Select ${label.toLowerCase()}\"}\n${indent} <ChevronsUpDown className=\"ml-2 size-4 shrink-0 opacity-50\" />\n${indent} </Button>\n${indent} </FormControl>\n${indent} </PopoverTrigger>\n${indent} <PopoverContent className=\"w-full p-0\" align=\"start\">\n${indent} <Command>\n${indent} <CommandInput placeholder=\"Search ${label.toLowerCase()}...\" />\n${indent} <CommandList>\n${indent} <CommandEmpty>No ${relSingular} found.</CommandEmpty>\n${indent} <CommandGroup>\n${indent} {${dataArray}?.filter((item) => item.id !== null).map((item) => {\n${indent} const displayName = ${displayField}\n${indent} const isSelected = formField.value?.includes(item.id as number) || false\n${indent} return (\n${indent} <CommandItem\n${indent} key={item.id}\n${indent} value={displayName}\n${indent} onSelect={() => {\n${indent} const current = formField.value || []\n${indent} formField.onChange(isSelected\n${indent} ? current.filter((id: number) => id !== item.id)\n${indent} : [...current, item.id as number])\n${indent} }}\n${indent} >\n${indent} <Check className={cn(\"mr-2 size-4\", isSelected ? \"opacity-100\" : \"opacity-0\")} />\n${indent} {displayName}\n${indent} </CommandItem>\n${indent} )\n${indent} })}\n${indent} </CommandGroup>\n${indent} </CommandList>\n${indent} </Command>\n${indent} </PopoverContent>\n${indent} </Popover>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderSingleRelationshipField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string,\n displayField: string,\n dataArray: string,\n relSingular: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-col\">\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <Popover open={${field.name}Open} onOpenChange={set${toPascalCase(field.name)}Open}>\n${indent} <PopoverTrigger asChild>\n${indent} <FormControl>\n${indent} <Button\n${indent} variant=\"outline\"\n${indent} role=\"combobox\"\n${indent} className={cn(\"w-full justify-between\", !formField.value && \"text-muted-foreground\")}\n${indent} disabled={isPending}\n${indent} >\n${indent} {formField.value\n${indent} ? (() => {\n${indent} const item = ${dataArray}?.find((item) => item.id !== null && String(item.id) === formField.value)\n${indent} return item ? (${displayField}) : \"Select ${label.toLowerCase()}\"\n${indent} })()\n${indent} : \"Select ${label.toLowerCase()}\"}\n${indent} <ChevronsUpDown className=\"ml-2 size-4 shrink-0 opacity-50\" />\n${indent} </Button>\n${indent} </FormControl>\n${indent} </PopoverTrigger>\n${indent} <PopoverContent className=\"w-full p-0\" align=\"start\">\n${indent} <Command>\n${indent} <CommandInput placeholder=\"Search ${label.toLowerCase()}...\" />\n${indent} <CommandList>\n${indent} <CommandEmpty>No ${relSingular} found.</CommandEmpty>\n${indent} <CommandGroup>\n${indent} {${dataArray}?.filter((item) => item.id !== null).map((item) => {\n${indent} const displayName = ${displayField}\n${indent} return (\n${indent} <CommandItem\n${indent} key={item.id}\n${indent} value={displayName}\n${indent} onSelect={() => {\n${indent} formField.onChange(String(item.id))\n${indent} set${toPascalCase(field.name)}Open(false)\n${indent} }}\n${indent} >\n${indent} <Check className={cn(\"mr-2 size-4\", formField.value === String(item.id) ? \"opacity-100\" : \"opacity-0\")} />\n${indent} {displayName}\n${indent} </CommandItem>\n${indent} )\n${indent} })}\n${indent} </CommandGroup>\n${indent} </CommandList>\n${indent} </Command>\n${indent} </PopoverContent>\n${indent} </Popover>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderDefaultField(\n field: SchemaField,\n indent: string,\n label: string,\n fieldType: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <Input\n${indent} type=\"${fieldType}\"\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} {...formField}\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n","/**\n * Shared logic for entity and single form generators\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\nimport { getZodType } from './zod-schema.js'\n\nexport interface FormGeneratorResult {\n files: string[]\n}\n\nexport function collectRelationshipFields(\n fields: SchemaField[],\n _tabFieldNames: Set<string>\n): SchemaField[] {\n const result: SchemaField[] = []\n const seen = new Set<string>()\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'relationship' && f.relationship && !seen.has(f.name)) {\n seen.add(f.name)\n result.push(f)\n }\n if (f.type === 'group' && f.fields) collect(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collect(tab.fields)\n }\n }\n }\n }\n collect(fields)\n return result\n}\n\nexport function generateDefaultValue(f: SchemaField): string {\n if (f.type === 'list') return ` ${f.name}: initialData?.${f.name} ?? []`\n if (f.type === 'boolean') return ` ${f.name}: initialData?.${f.name} ?? false`\n if (f.type === 'number' || f.type === 'decimal' || f.type === 'serial') {\n const def = f.required ? '0' : 'undefined'\n return ` ${f.name}: initialData?.${f.name} ?? ${def}`\n }\n if (f.type === 'relationship') {\n if (f.multiple) return ` ${f.name}: initialData?.${f.name} ?? []`\n return ` ${f.name}: initialData?.${f.name}\n ? (typeof initialData.${f.name} === 'object' ? String(initialData.${f.name}.id) : String(initialData.${f.name}))\n : ''`\n }\n if (f.type === 'date' || f.type === 'timestamp') {\n return ` ${f.name}: initialData?.${f.name} ?? undefined`\n }\n if (f.default !== undefined && f.default !== null) {\n const def = typeof f.default === 'string' ? `'${f.default}'` : f.default\n return ` ${f.name}: initialData?.${f.name} ?? ${def}`\n }\n return ` ${f.name}: initialData?.${f.name} ?? ''`\n}\n\nexport function buildZodFields(flatFields: SchemaField[]): string {\n return flatFields\n .filter((f) => f.type !== 'tabs')\n .flatMap((f) => {\n const defs: string[] = []\n const zodType = getZodType(f)\n const alreadyOptional = zodType.includes('.optional()')\n let def = ` ${quotePropertyName(f.name)}: ${zodType}`\n if (!f.required && !alreadyOptional) def += '.optional()'\n defs.push(def)\n if (f.hasIcon) defs.push(` ${quotePropertyName(`${f.name}Icon`)}: z.string().optional()`)\n return defs\n })\n .join(',\\n')\n}\n\nexport function buildDefaultValues(flatFields: SchemaField[]): string {\n return flatFields\n .filter((f) => f.type !== 'tabs')\n .flatMap((f) => {\n const defs = [generateDefaultValue(f)]\n if (f.hasIcon) defs.push(` ${f.name}Icon: initialData?.${f.name}Icon ?? ''`)\n return defs\n })\n .join(',\\n')\n}\n\nexport function buildUiImports(ctx: {\n hasBoolean: boolean\n hasTextarea: boolean\n hasImage: boolean\n hasVideo: boolean\n hasMedia: boolean\n hasIcon: boolean\n hasIconPostfix: boolean\n hasDate: boolean\n hasMarkdown: boolean\n hasRichtext: boolean\n hasSeparator: boolean\n hasSelect: boolean\n hasTabsField: boolean\n hasRelationship: boolean\n hasSimpleList: boolean\n hasNestedList: boolean\n}): string[] {\n const uiImports: string[] = [\n \"import { Button } from '@cms/components/ui/button'\",\n \"import { Input } from '@cms/components/ui/input'\",\n `import {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage\n} from '@cms/components/ui/form'`\n ]\n\n if (ctx.hasBoolean) uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (ctx.hasTextarea) uiImports.push(\"import { Textarea } from '@cms/components/ui/textarea'\")\n if (ctx.hasImage)\n uiImports.push(\"import { ImageUploadField } from '@cms/components/ui/image-upload-field'\")\n if (ctx.hasVideo)\n uiImports.push(\"import { VideoUploadField } from '@cms/components/ui/video-upload-field'\")\n if (ctx.hasMedia)\n uiImports.push(\"import { MediaUploadField } from '@cms/components/ui/media-upload-field'\")\n if (ctx.hasIcon || ctx.hasIconPostfix)\n uiImports.push(\"import { IconPicker } from '@cms/components/ui/icon-picker'\")\n if (ctx.hasDate) uiImports.push(\"import { DatePicker } from '@cms/components/ui/date-picker'\")\n if (ctx.hasMarkdown)\n uiImports.push(\"import { MarkdownEditor } from '@cms/components/ui/markdown-editor'\")\n if (ctx.hasRichtext)\n uiImports.push(\"import { RichTextEditor } from '@cms/components/ui/rich-text-editor'\")\n if (ctx.hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n if (ctx.hasSelect) {\n uiImports.push(`import {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'`)\n }\n if (ctx.hasTabsField) {\n uiImports.push(`import {\n Tabs,\n TabsList,\n TabsTrigger,\n TabsContent\n} from '@cms/components/ui/tabs'`)\n }\n if (ctx.hasRelationship) {\n uiImports.push(`import {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from '@cms/components/ui/command'`)\n uiImports.push(`import {\n Popover,\n PopoverContent,\n PopoverTrigger\n} from '@cms/components/ui/popover'`)\n }\n\n if (ctx.hasSimpleList)\n uiImports.push(\"import { DynamicListField } from '@cms/components/ui/dynamic-list-field'\")\n if (ctx.hasNestedList) {\n uiImports.push(`import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger\n} from '@cms/components/ui/accordion'`)\n if (!ctx.hasSeparator)\n uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n uiImports.push(\"import { Label } from '@cms/components/ui/label'\")\n }\n\n return uiImports\n}\n","/**\n * Single (singleton) form generator — upsert mutation, no router, \"Save\" button\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, hasFieldType, hasIconUsage } from '../../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport { generateFieldJSX } from './field-jsx.js'\nimport {\n type FormGeneratorResult,\n collectRelationshipFields,\n buildZodFields,\n buildDefaultValues,\n buildUiImports\n} from './form-shared.js'\n\nexport function generateSingleForm(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): FormGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const formFilePath = path.join(entityDir, `${schema.name}-form.tsx`)\n\n if (fs.existsSync(formFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n\n // Analyze fields\n const allFormFields = schema.fields.filter(\n (f) => !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt'\n )\n const flatFields = flattenFields(allFormFields)\n\n // Collect tab field names\n const tabFieldNames = new Set<string>()\n for (const f of schema.fields) {\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) for (const tf of tab.fields) tabFieldNames.add(tf.name)\n }\n }\n }\n\n // Check what components are needed\n const hasBoolean = hasFieldType(schema.fields, 'boolean')\n const hasImage = hasFieldType(schema.fields, 'image')\n const hasVideo = hasFieldType(schema.fields, 'video')\n const hasMedia = hasFieldType(schema.fields, 'media')\n const hasIcon = hasFieldType(schema.fields, 'icon')\n const hasIconPostfix = hasIconUsage(schema.fields)\n const hasDate = hasFieldType(schema.fields, 'date')\n const hasSelect = hasFieldType(schema.fields, 'select')\n const hasMarkdown = hasFieldType(schema.fields, 'markdown')\n const hasRichtext = hasFieldType(schema.fields, 'richtext')\n const hasTextarea = hasFieldType(schema.fields, 'text')\n const hasSeparator = hasFieldType(schema.fields, 'separator')\n const hasRelationship = hasFieldType(schema.fields, 'relationship')\n const hasTabsField = schema.fields.some((f) => f.type === 'tabs')\n const tabsField = schema.fields.find((f) => f.type === 'tabs')\n const firstTabName = tabsField?.tabs?.[0]?.name || ''\n\n const mainRelFields = collectRelationshipFields(schema.fields, tabFieldNames)\n\n // Collect list fields with nested fields\n const listFieldsWithNested: SchemaField[] = []\n function collectListFieldsSingle(fields: SchemaField[]): void {\n for (const f of fields) {\n if (f.type === 'list' && f.fields && f.fields.length > 0 && !f.hidden) {\n listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFieldsSingle(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collectListFieldsSingle(tab.fields)\n }\n }\n }\n }\n collectListFieldsSingle(allFormFields)\n const hasList = hasFieldType(schema.fields, 'list')\n const hasNestedList = listFieldsWithNested.length > 0\n const hasSimpleList =\n hasList && flatFields.some((f) => f.type === 'list' && (!f.fields || f.fields.length === 0))\n\n // Build Zod schema\n const zodFields = buildZodFields(flatFields)\n\n // Build default values\n const defaultValues = buildDefaultValues(flatFields)\n\n // Build form fields JSX\n const formFieldsJSX = allFormFields\n .map((f) => {\n if (f.type === 'tabs' && f.tabs) {\n const tabsList = f.tabs\n .map((t) => ` <TabsTrigger value=\"${t.name}\">${t.label}</TabsTrigger>`)\n .join('\\n')\n const tabsContent = f.tabs\n .map((t) => {\n const tabFields = (t.fields || [])\n .map((tf) => generateFieldJSX(tf, ' '))\n .join('\\n')\n return ` <TabsContent value=\"${t.name}\" className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${tabFields}\n </TabsContent>`\n })\n .join('\\n')\n return ` <Tabs value={activeTab} onValueChange={setActiveTab} className=\"w-full\">\n <TabsList>\n${tabsList}\n </TabsList>\n${tabsContent}\n </Tabs>`\n }\n if (tabFieldNames.has(f.name)) return ''\n return generateFieldJSX(f)\n })\n .filter(Boolean)\n .join('\\n')\n\n // --- Build imports ---\n const uiImports = buildUiImports({\n hasBoolean,\n hasTextarea,\n hasImage,\n hasVideo,\n hasMedia,\n hasIcon,\n hasIconPostfix,\n hasDate,\n hasMarkdown,\n hasRichtext,\n hasSeparator,\n hasSelect,\n hasTabsField,\n hasRelationship,\n hasSimpleList,\n hasNestedList\n })\n\n // Lucide icons\n const lucideIcons: string[] = []\n if (hasRelationship) lucideIcons.push('Check', 'ChevronsUpDown')\n if (hasNestedList) {\n if (!lucideIcons.includes('Plus')) lucideIcons.push('Plus')\n if (!lucideIcons.includes('X')) lucideIcons.push('X')\n }\n\n // Relationship hooks\n const relHookImports = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return `import { use${relPlural} } from '@cms/hooks/use-${f.relationship}'`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // Relationship state\n const relState = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return ` const [${f.name}Open, set${toPascalCase(f.name)}Open] = React.useState(false)\n const { data: ${f.relationship}Data } = use${relPlural}()`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // List field array hooks\n const fieldArrayHooks = listFieldsWithNested\n .map((field) => {\n const pascalFieldName = toPascalCase(field.name)\n return ` const [${field.name}Expanded, set${pascalFieldName}Expanded] = React.useState<string | undefined>(undefined)\n const ${field.name}FieldArray = useFieldArray({\n control: form.control,\n name: '${field.name}'\n })`\n })\n .join('\\n')\n\n const needsReact = mainRelFields.length > 0 || hasNestedList\n\n // --- Assemble file ---\n const content = `'use client'\n${needsReact ? \"\\nimport * as React from 'react'\" : ''}\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'${lucideIcons.length > 0 ? `\\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'` : ''}\nimport {${hasNestedList ? ' useFieldArray,' : ''} useForm } from 'react-hook-form'\nimport { toast } from 'sonner'\nimport { z } from 'zod/v3'${hasTabsField ? \"\\nimport { useQueryState } from 'nuqs'\" : ''}${hasRelationship ? \"\\nimport { cn } from '@cms/utils/cn'\" : ''}\n${relHookImports ? `${relHookImports}\\n` : ''}${uiImports.join('\\n')}\nimport type {\n ${Singular}Data,\n Upsert${Singular}Input\n} from '@cms/actions/${schema.name}'\nimport { upsert${Singular} } from '@cms/actions/${schema.name}'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\nexport type FormValues = z.infer<typeof formSchema>\n\ninterface ${Singular}FormProps {\n initialData?: ${Singular}Data | null\n}\n\nexport function ${Singular}Form({ initialData }: ${Singular}FormProps) {\n const queryClient = useQueryClient()${hasTabsField ? `\\n const [activeTab, setActiveTab] = useQueryState('tab', { defaultValue: '${firstTabName}' })` : ''}${relState ? `\\n${relState}` : ''}\n\n const upsertMutation = useMutation({\n mutationFn: (data: Upsert${Singular}Input) => upsert${Singular}(data),\n onSuccess: () => {\n toast.success('${schema.label} saved successfully')\n queryClient.invalidateQueries({ queryKey: ['${schema.name}'] })\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to save ${schema.label.toLowerCase()}')\n }\n })\n\n const isPending = upsertMutation.isPending\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n${defaultValues}\n }\n })\n${fieldArrayHooks ? `\\n${fieldArrayHooks}\\n` : ''}\n function onSubmit(values: FormValues) {\n const cleanedValues = Object.fromEntries(\n Object.entries(values).map(([key, value]) => [key, value === undefined ? '' : value])\n ) as FormValues\n\n upsertMutation.mutate(cleanedValues as Upsert${Singular}Input)\n }\n\n return (\n <Form {...form}>\n <form id=\"${schema.name}-form\" onSubmit={form.handleSubmit(onSubmit, (errors) => {\n console.error('Form validation errors:', errors)\n const firstError = Object.values(errors)[0]\n if (firstError?.message) {\n toast.error(String(firstError.message))\n } else {\n toast.error('Please fix the form errors before submitting')\n }\n })} className=\"space-y-6\">\n <div className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${formFieldsJSX}\n </div>\n\n <div className=\"flex items-center fixed bottom-0 md:left-[calc(var(--sidebar-width))] w-screen md:w-[calc(100svw-var(--sidebar-width)-4px)] right-0 bg-secondary border-t\">\n <div className=\"flex mx-auto py-4 w-full max-w-5xl items-center justify-end gap-2\">\n <Button type=\"submit\" disabled={isPending} size=\"lg\">\n {isPending ? 'Saving...' : 'Save'}\n </Button>\n </div>\n </div>\n </form>\n </Form>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(formFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]\n }\n}\n","/**\n * Generator 3: React Query hook — cms/hooks/use-<n>.ts\n * Generates client-side data fetching hooks wrapping server actions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize, pluralize } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface HookGeneratorResult {\n files: string[]\n hookName: string\n}\n\n/**\n * Generate React Query hook for an entity — writes to cms/hooks/use-<n>.ts\n */\nexport function generateHook(\n schema: Schema,\n cwd: string,\n hooksDir: string,\n options: GeneratorOptions = {}\n): HookGeneratorResult {\n const hookFileName = `use-${schema.name}.ts`\n const hookFilePath = path.join(cwd, hooksDir, hookFileName)\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n\n // Check if schema has a slug field\n const dbFields = flattenFields(schema.fields)\n const hasSlugField = dbFields.some((f) => f.name === 'slug')\n const hasHtmlOutput = dbFields.some(\n (f) => (f.type === 'richtext' || f.type === 'markdown') && f.output === 'html'\n )\n\n // Check for existing file\n if (fs.existsSync(hookFilePath) && !options.force) {\n return { files: [], hookName: `use${Plural}` }\n }\n\n // Check if schema has filters\n const hasFilters = schema.filters && schema.filters.length > 0\n\n // --- Build imports from actions ---\n const actionImports: string[] = [`get${Plural}`, `get${Singular}ById`]\n if (hasSlugField) actionImports.push(`get${Singular}BySlug`)\n if (hasFilters) {\n for (const filter of schema.filters!) {\n actionImports.push(`getDistinct${Plural}${toPascalCase(filter.field)}`)\n }\n }\n const typeImports = [\n `type ${Singular}Data`,\n ...(hasHtmlOutput && hasSlugField ? [`type ${Singular}DisplayData`] : []),\n `type ${Plural}Response`,\n `type Get${Plural}Filters`\n ]\n\n // --- Build filter parameters ---\n const filterParams = hasFilters\n ? schema.filters!.map((f) => `${f.field}?: string`).join(', ')\n : ''\n const allParams = filterParams ? `search?: string, ${filterParams}` : 'search?: string'\n\n // --- Build query key with all filter params ---\n const queryKeyParts = hasFilters\n ? [\"search ?? ''\", ...schema.filters!.map((f) => `${f.field} ?? ''`)].join(', ')\n : \"search ?? ''\"\n\n // --- Build filters object in queryFn ---\n const filtersBody = hasFilters\n ? `const filters: Get${Plural}Filters = {}\n if (search) filters.search = search\n${schema.filters!.map((f) => ` if (${f.field}) filters.${f.field} = ${f.field}`).join('\\n')}\n return get${Plural}(Object.keys(filters).length > 0 ? filters : undefined)`\n : `const filters: Get${Plural}Filters | undefined = search ? { search } : undefined\n return get${Plural}(filters)`\n\n // --- Singular hook ---\n const singularHook = `\nexport function use${Singular}(id: number | null | undefined): UseQueryResult<${Singular}Data | null, Error> {\n return useQuery({\n queryKey: ['${singular}', id],\n queryFn: () => (id ? get${Singular}ById(id) : Promise.resolve(null)),\n enabled: !!id,\n staleTime: 0\n })\n}`\n\n // --- Slug hook ---\n const slugReturnType = hasHtmlOutput ? `${Singular}DisplayData` : `${Singular}Data`\n const slugHook = hasSlugField\n ? `\n\nexport function use${Singular}BySlug(slug: string | null | undefined): UseQueryResult<${slugReturnType} | null, Error> {\n return useQuery({\n queryKey: ['${singular}', 'slug', slug],\n queryFn: () => (slug ? get${Singular}BySlug(slug) : Promise.resolve(null)),\n enabled: !!slug,\n staleTime: 0\n })\n}`\n : ''\n\n // --- Distinct filter hooks ---\n const distinctHooks = hasFilters\n ? schema\n .filters!.map(\n (filter) => `\n\nexport function use${Plural}Distinct${toPascalCase(filter.field)}(): UseQueryResult<string[], Error> {\n return useQuery({\n queryKey: ['${plural}', 'distinct', '${filter.field}'],\n queryFn: () => getDistinct${Plural}${toPascalCase(filter.field)}()\n })\n}`\n )\n .join('')\n : ''\n\n // --- Assemble file ---\n const content = `import {\n ${[...actionImports, ...typeImports].join(',\\n ')}\n} from '@cms/actions/${schema.name}'\nimport { type UseQueryResult, useQuery } from '@tanstack/react-query'\n\nexport function use${Plural}(\n ${allParams ? `${allParams},` : ''}\n options?: { enabled?: boolean }\n): UseQueryResult<${Plural}Response, Error> {\n return useQuery({\n queryKey: ['${plural}', ${queryKeyParts}],\n queryFn: () => {\n ${filtersBody}\n },\n enabled: options?.enabled ?? true,\n refetchOnMount: 'always'\n })\n}\n${singularHook}${slugHook}${distinctHooks}\n`\n\n // Write file\n const dir = path.dirname(hookFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(hookFilePath, content, 'utf-8')\n\n return {\n files: [path.join(hooksDir, hookFileName)],\n hookName: `use${Plural}`\n }\n}\n\n/**\n * Generate React Query hook for a single (singleton) schema.\n * Only useXxx() query — no list, slug, or filter hooks.\n */\nexport function generateSingleHook(\n schema: Schema,\n cwd: string,\n hooksDir: string,\n options: GeneratorOptions = {}\n): HookGeneratorResult {\n const hookFileName = `use-${schema.name}.ts`\n const hookFilePath = path.join(cwd, hooksDir, hookFileName)\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n\n if (fs.existsSync(hookFilePath) && !options.force) {\n return { files: [], hookName: `use${Singular}` }\n }\n\n const content = `import {\n get${Singular},\n type ${Singular}Data\n} from '@cms/actions/${schema.name}'\nimport { type UseQueryResult, useQuery } from '@tanstack/react-query'\n\nexport function use${Singular}(): UseQueryResult<${Singular}Data | null, Error> {\n return useQuery({\n queryKey: ['${schema.name}'],\n queryFn: () => get${Singular}(),\n staleTime: 0\n })\n}\n`\n\n const dir = path.dirname(hookFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(hookFilePath, content, 'utf-8')\n\n return {\n files: [path.join(hooksDir, hookFileName)],\n hookName: `use${Singular}`\n }\n}\n","/**\n * Generator 11: Navigation — append to cms/data/navigation.ts\n * Parses existing navigation file and inserts new entity entry.\n * Uses flat `group` property for sidebar grouping (no nested children).\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface NavItem {\n label: string\n href: string\n icon?: string\n group?: string\n}\n\n// ============================================================================\n// Parser\n// ============================================================================\n\n/**\n * Parse existing navigation.ts and extract nav items + icon imports\n */\nfunction parseNavigationFile(content: string): { items: NavItem[]; iconImports: string[] } {\n const iconImportMatch = content.match(/import\\s*\\{([^}]+)\\}\\s*from\\s*['\"]lucide-react['\"]/)\n const iconImports: string[] = iconImportMatch\n ? iconImportMatch[1]\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s && s !== 'LucideIcon')\n : []\n\n const arrayBlock = extractTopLevelArray(content)\n if (!arrayBlock) return { items: [], iconImports }\n\n const items = parseItemsBlock(arrayBlock)\n return { items, iconImports }\n}\n\n/**\n * Find the cmsNavigation array and extract its content using bracket counting\n */\nfunction extractTopLevelArray(content: string): string | null {\n const marker = content.indexOf('cmsNavigation')\n if (marker === -1) return null\n\n const eqSign = content.indexOf('=', marker)\n if (eqSign === -1) return null\n const openBracket = content.indexOf('[', eqSign)\n if (openBracket === -1) return null\n\n let depth = 0\n for (let i = openBracket; i < content.length; i++) {\n if (content[i] === '[') depth++\n if (content[i] === ']') depth--\n if (depth === 0) {\n return content.slice(openBracket + 1, i)\n }\n }\n return null\n}\n\nfunction parseItemsBlock(block: string): NavItem[] {\n const items: NavItem[] = []\n let depth = 0\n let current = ''\n let inObj = false\n\n for (const char of block) {\n if (char === '{') {\n if (depth === 0) inObj = true\n depth++\n current += char\n } else if (char === '}') {\n depth--\n current += char\n if (depth === 0 && inObj) {\n const item = parseSingleItem(current)\n if (item) items.push(item)\n current = ''\n inObj = false\n }\n } else if (inObj) {\n current += char\n }\n }\n\n return items\n}\n\nfunction parseSingleItem(str: string): NavItem | null {\n const labelMatch = str.match(/label:\\s*['\"]([^'\"]+)['\"]/)\n const hrefMatch = str.match(/href:\\s*['\"]([^'\"]+)['\"]/)\n const iconMatch = str.match(/icon:\\s*(\\w+)/)\n const groupMatch = str.match(/group:\\s*['\"]([^'\"]+)['\"]/)\n\n if (!labelMatch || !hrefMatch) return null\n\n const item: NavItem = {\n label: labelMatch[1],\n href: hrefMatch[1]\n }\n if (iconMatch) item.icon = iconMatch[1]\n if (groupMatch) item.group = groupMatch[1]\n\n return item\n}\n\n// ============================================================================\n// Code Generator\n// ============================================================================\n\nfunction generateNavigationCode(items: NavItem[], iconImports: string[]): string {\n const lines: string[] = []\n\n lines.push(\"import type { LucideIcon } from 'lucide-react'\")\n lines.push(`import { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push('')\n lines.push('export interface CmsNavigationItem {')\n lines.push(' label: string')\n lines.push(' href: string')\n lines.push(' icon?: LucideIcon')\n lines.push(' group?: string')\n lines.push('}')\n lines.push('')\n lines.push('export const cmsNavigation: CmsNavigationItem[] = [')\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n const isLast = i === items.length - 1\n appendItem(lines, item, isLast)\n }\n\n lines.push(']')\n lines.push('')\n\n return lines.join('\\n')\n}\n\nfunction appendItem(lines: string[], item: NavItem, isLast: boolean): void {\n lines.push(' {')\n lines.push(` label: '${item.label}',`)\n\n const hasMore = item.icon != null || item.group != null\n lines.push(` href: '${item.href}'${hasMore ? ',' : ''}`)\n\n if (item.icon && item.group) {\n lines.push(` icon: ${item.icon},`)\n lines.push(` group: '${item.group}'`)\n } else if (item.icon) {\n lines.push(` icon: ${item.icon}`)\n } else if (item.group) {\n lines.push(` group: '${item.group}'`)\n }\n\n lines.push(` }${isLast ? '' : ','}`)\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface NavigationGeneratorResult {\n files: string[]\n}\n\n/**\n * Update cms/data/navigation.ts to include new entity nav item\n */\nexport function updateNavigation(\n schema: Schema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions = {}\n): NavigationGeneratorResult {\n const navFilePath = path.join(cwd, cmsDir, 'data', 'navigation.ts')\n\n // Settings lives in the sidebar footer, not in navigation\n if (schema.name === 'settings') {\n return { files: [] }\n }\n\n // Parse existing navigation\n let items: NavItem[] = []\n let iconImports: string[] = []\n\n if (fs.existsSync(navFilePath)) {\n const content = fs.readFileSync(navFilePath, 'utf-8')\n const parsed = parseNavigationFile(content)\n items = parsed.items\n iconImports = parsed.iconImports\n }\n\n const entityHref = `/cms/${schema.name}`\n\n const newItem: NavItem = {\n label: schema.label,\n href: entityHref,\n icon: schema.icon\n }\n\n // If schema has a navGroup, set the group property\n if (schema.navGroup) {\n newItem.group = schema.navGroup.label\n }\n\n // Check if item already exists\n const existingIndex = items.findIndex((item) => item.href === entityHref)\n\n if (existingIndex >= 0) {\n if (options.force) {\n items[existingIndex] = newItem\n } else {\n return { files: [] }\n }\n } else {\n items.push(newItem)\n }\n\n // Reorganize: Dashboard first, then ungrouped alphabetical, then grouped alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => {\n // Ungrouped items first, then by group name, then by label\n if (!a.group && b.group) return -1\n if (a.group && !b.group) return 1\n if (a.group && b.group && a.group !== b.group) return a.group.localeCompare(b.group)\n return a.label.localeCompare(b.label)\n })\n\n items = [...(dashboard ? [dashboard] : []), ...others]\n\n // Add icon import if needed\n if (schema.icon && !iconImports.includes(schema.icon)) {\n iconImports.push(schema.icon)\n }\n iconImports.sort()\n\n // Write updated file\n const dir = path.dirname(navFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n\n const code = generateNavigationCode(items, iconImports)\n fs.writeFileSync(navFilePath, code, 'utf-8')\n\n return {\n files: [path.join(cmsDir, 'data', 'navigation.ts')]\n }\n}\n","/**\n * Generator 7: Page (server) — (authenticated)/<n>/page.tsx\n * Generates the server page component that renders columns + page content\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, pluralize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface PageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate server page component for entity list view\n */\nexport function generatePage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): PageGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const pageFilePath = path.join(entityDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const plural = pluralize(schema.name)\n const Plural = toPascalCase(plural)\n const kebabPlural = toKebabCase(plural)\n\n const content = `import * as React from 'react'\nimport { columns } from './columns'\nimport { ${Plural}PageContent } from './${kebabPlural}-page-content'\n\nexport default function ${Plural}Page() {\n return (\n <React.Suspense\n fallback={\n <div className=\"flex items-center justify-center h-48\">\n <div className=\"text-muted-foreground\">Loading ${schema.label}...</div>\n </div>\n }\n >\n <div className=\"flex flex-col\">\n <${Plural}PageContent columns={columns} />\n </div>\n </React.Suspense>\n )\n}\n`\n\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'page.tsx')]\n }\n}\n","/**\n * Generator 6: Page content — (authenticated)/<n>/<n>-page-content.tsx\n * Generates client component with search, filters, bulk delete, and table\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize, pluralize, singularizeLabel, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface PageContentGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate page content component for entity list view\n */\nexport function generatePageContent(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): PageContentGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n const fileName = `${toKebabCase(plural)}-page-content.tsx`\n const filePath = path.join(entityDir, fileName)\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [] }\n }\n\n const hasCreate = schema.actions?.create ?? false\n const hasDelete = schema.actions?.delete ?? false\n const hasFilters = schema.filters && schema.filters.length > 0\n\n // --- Lucide icons ---\n const lucideIcons: string[] = ['ChevronLeft', 'Search', 'CornerDownLeft']\n if (hasCreate) lucideIcons.push('Plus')\n if (hasDelete) lucideIcons.push('Trash2')\n if (hasFilters) lucideIcons.push('Check', 'ChevronsUpDown')\n\n // --- Build imports ---\n let imports = `'use client'\n\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'\n${hasCreate ? \"import Link from 'next/link'\\n\" : ''}import { useRouter } from 'next/navigation'\nimport { parseAsString${hasDelete ? ', parseAsArrayOf, parseAsInteger' : ''}, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport { useFormStatus } from 'react-dom'\n${hasDelete ? \"import { toast } from 'sonner'\\n\" : ''}import { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\n`\n\n if (hasDelete) {\n imports += `import {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger\n} from '@cms/components/ui/alert-dialog'\n`\n }\n\n if (hasFilters) {\n imports += `import {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from '@cms/components/ui/command'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger\n} from '@cms/components/ui/popover'\nimport { cn } from '@cms/utils/cn'\n`\n // Filter hooks\n const filterHooks = schema\n .filters!.map((f) => `use${Plural}Distinct${toPascalCase(f.field)}`)\n .join(', ')\n imports += `import { ${filterHooks} } from '@cms/hooks/use-${schema.name}'\\n`\n }\n\n imports += `import type { ${Singular}Data } from '@cms/actions/${schema.name}'\n${hasDelete ? `import { deleteBulk${Plural} } from '@cms/actions/${schema.name}'\\n` : ''}import { ${Plural}Table } from './${toKebabCase(plural)}-table'\n`\n\n // --- SearchButton component ---\n const searchButton = `function SearchButton() {\n const { pending } = useFormStatus()\n return (\n <Button type=\"submit\" variant=\"outline\" size=\"default\" disabled={pending}>\n {pending ? 'Searching...' : 'Search'}\n </Button>\n )\n}\n\n`\n\n // --- Filter state ---\n const filterLogic = hasFilters\n ? schema\n .filters!.map(\n (f) =>\n ` const [${f.field}, set${toPascalCase(f.field)}] = useQueryState('${f.field}', parseAsString.withDefault(''))\n const { data: ${f.field}Options } = use${Plural}Distinct${toPascalCase(f.field)}()\n const [${f.field}ComboboxOpen, set${toPascalCase(f.field)}ComboboxOpen] = React.useState(false)`\n )\n .join('\\n')\n : ''\n\n // --- Search logic ---\n const searchLogic = ` const [search, setSearch] = useQueryState('q', parseAsString.withDefault(''))\n\n const searchAction = React.useCallback(async (formData: FormData) => {\n const value = formData.get('search') as string\n React.startTransition(() => {\n setSearch(value || null)\n })\n }, [setSearch])\n${filterLogic ? `\\n${filterLogic}` : ''}`\n\n // --- Delete logic ---\n const deleteLogic = hasDelete\n ? `\n const [selectedIds, setSelectedIds] = useQueryState(\n 'selected',\n parseAsArrayOf(parseAsInteger).withDefault([])\n )\n const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n\n const handleBulkDelete = () => {\n startTransition(async () => {\n try {\n const result = await deleteBulk${Plural}(selectedIds)\n\n if (result.success) {\n toast.success(\n \\`\\${selectedIds.length} ${singular}\\${selectedIds.length > 1 ? 's' : ''} deleted successfully\\`\n )\n queryClient.refetchQueries({ queryKey: ['${plural}'] })\n setSelectedIds([])\n setDeleteDialogOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete ${plural}')\n }\n } catch (error) {\n toast.error('An error occurred')\n console.error(error)\n }\n })\n }\n`\n : ''\n\n // --- Filter dropdowns ---\n const _filterDropdowns = hasFilters\n ? schema\n .filters!.map(\n (\n f\n ) => ` <Popover open={${f.field}ComboboxOpen} onOpenChange={set${toPascalCase(f.field)}ComboboxOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={${f.field}ComboboxOpen}\n className=\"w-[200px] justify-between\"\n >\n {${f.field} || '${f.label}'}\n <ChevronsUpDown className=\"ml-2 size-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup>\n <CommandItem\n key=\"all\"\n value=\"\"\n onSelect={() => {\n React.startTransition(() => {\n set${toPascalCase(f.field)}('')\n })\n set${toPascalCase(f.field)}ComboboxOpen(false)\n }}\n >\n <Check\n className={cn(\n 'mr-2 size-4',\n ${f.field} === '' ? 'opacity-100' : 'opacity-0'\n )}\n />\n All ${f.label}\n </CommandItem>\n {${f.field}Options?.map((option) => (\n <CommandItem\n key={option}\n value={option}\n onSelect={() => {\n React.startTransition(() => {\n set${toPascalCase(f.field)}(option)\n })\n set${toPascalCase(f.field)}ComboboxOpen(false)\n }}\n >\n <Check\n className={cn(\n 'mr-2 size-4',\n ${f.field} === option ? 'opacity-100' : 'opacity-0'\n )}\n />\n {option}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>`\n )\n .join('\\n')\n : ''\n\n // --- Search input ---\n const searchInput = `<form action={searchAction} className=\"flex items-center gap-2 relative\">\n <Search className=\"text-muted-foreground/70 pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\" />\n <Input\n key={search}\n name=\"search\"\n placeholder=\"Search ${schema.label.toLowerCase()}...\"\n defaultValue={search}\n className=\"w-64 pl-9 bg-white rounded-lg\"\n />\n <CornerDownLeft className=\"text-muted-foreground/70 pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2\" />\n </form>`\n\n // --- Delete button ---\n const deleteButton = hasDelete\n ? ` {selectedIds.length > 0 && (\n <AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" size=\"default\">\n <Trash2 className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Delete {selectedIds.length}{' '}\n {selectedIds.length === 1 ? '${singular}' : '${plural}'}\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete {selectedIds.length}{' '}\n {selectedIds.length === 1 ? '${singular}' : '${plural}'}.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n handleBulkDelete()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}`\n : ''\n\n // --- Create button ---\n const createButton = hasCreate\n ? ` <Button asChild>\n <Link href=\"/cms/${schema.name}/new\">\n <Plus className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Create ${singularizeLabel(schema.label)}\n </Link>\n </Button>`\n : ''\n\n // --- Table props ---\n const filterPropsStr = hasFilters\n ? schema.filters!.map((f) => `${f.field}={${f.field}}`).join(' ')\n : ''\n const allTableProps = filterPropsStr ? `search={search} ${filterPropsStr}` : 'search={search}'\n const tableProps = hasDelete\n ? `columns={columns} selectedIds={selectedIds} setSelectedIds={setSelectedIds} ${allTableProps}`\n : `columns={columns} selectedIds={[]} setSelectedIds={() => {}} ${allTableProps}`\n\n // --- Assemble file ---\n const content = `${imports}\n${searchButton}interface ${Plural}PageContentProps<TValue> {\n columns: ColumnDef<${Singular}Data, TValue>[]\n}\n\nexport function ${Plural}PageContent<TValue>({\n columns\n}: ${Plural}PageContentProps<TValue>) {\n const router = useRouter()\n const queryClient = useQueryClient()\n${searchLogic}${deleteLogic}\n return (\n <>\n <PageHeader title=\"${schema.label}\" back={<Button variant=\"ghost\" size=\"icon\" onClick={() => router.back()}><ChevronLeft /></Button>} search={${searchInput}} actions={<div className=\"flex items-center gap-2\">${deleteButton} ${createButton}</div>} />\n <main className=\"space-y-6 p-6\">\n <${Plural}Table ${tableProps} />\n </main>\n </>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, fileName)]\n }\n}\n","/**\n * Generator: Single page — (authenticated)/<n>/page.tsx\n * Server component that fetches the singleton record and renders the form.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface SinglePageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate server page for a single (singleton) schema.\n * Calls getXxx() and renders XxxForm with initialData (null on first visit).\n */\nexport function generateSinglePage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): SinglePageGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const pageFilePath = path.join(entityDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const PageName = toPascalCase(schema.name)\n\n const content = `import { get${Singular} } from '@cms/actions/${schema.name}'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { ${Singular}Form } from './${schema.name}-form'\n\nexport default async function ${PageName}Page() {\n const data = await get${Singular}()\n\n return (\n <>\n <PageHeader title=\"${schema.label}\" />\n <main className=\"container mx-auto max-w-5xl p-6 pb-20\">\n <${Singular}Form initialData={data} />\n </main>\n </>\n )\n}\n`\n\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'page.tsx')]\n }\n}\n","/**\n * Generator 5: Table component — (authenticated)/<n>/<n>-table.tsx\n * Generates data table with pagination, sorting, reorder, and row selection\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize, pluralize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface TableGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate table component for entity list view\n */\nexport function generateTable(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): TableGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n const camelPlural = toCamelCase(plural)\n const camelSingular = toCamelCase(singular)\n const tableFileName = `${toKebabCase(plural)}-table.tsx`\n const tableFilePath = path.join(entityDir, tableFileName)\n\n if (fs.existsSync(tableFilePath) && !options.force) {\n return { files: [] }\n }\n\n // Check if schema has filters\n const hasFilters = schema.filters && schema.filters.length > 0\n const filterProps = hasFilters\n ? schema.filters!.map((f) => `${f.field}?: string`).join('\\n ')\n : ''\n const allFilterProps = filterProps ? `\\n ${filterProps}` : ''\n const filterParams = hasFilters ? schema.filters!.map((f) => f.field).join(', ') : ''\n const allParams = filterParams ? `search, ${filterParams}` : 'search'\n\n const content = `'use client'\n\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow\n} from '@cms/components/ui/table'\nimport { use${Plural} } from '@cms/hooks/use-${schema.name}'\nimport { bulkUpdate${Plural}SortOrder } from '@cms/actions/${schema.name}'\nimport type { ${Singular}Data } from '@cms/actions/${schema.name}'\nimport '@cms/types/table-meta'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ArrowUpDown, Save } from 'lucide-react'\nimport { toast } from 'sonner'\n\nconst PAGE_SIZE_OPTIONS = [\n { value: '10', label: '10' },\n { value: '20', label: '20' },\n { value: '50', label: '50' },\n { value: '100', label: '100' },\n { value: 'all', label: 'All' }\n]\n\ninterface ${Plural}TableProps<TValue> {\n columns: ColumnDef<${Singular}Data, TValue>[]\n selectedIds: number[]\n setSelectedIds: (ids: number[]) => void\n search?: string${allFilterProps}\n}\n\nexport function ${Plural}Table<TValue>({ columns, selectedIds, setSelectedIds, ${allParams} }: ${Plural}TableProps<TValue>) {\n const { data, error, isPending } = use${Plural}(${allParams})\n const queryClient = useQueryClient()\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0))\n const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(20))\n\n // Reorder mode state\n const [reorderMode, setReorderMode] = React.useState(false)\n const [localData, setLocalData] = React.useState<${Singular}Data[]>([])\n const [hasChanges, setHasChanges] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n\n // Sync local data when server data changes\n React.useEffect(() => {\n if (data?.${camelPlural}) {\n setLocalData([...data.${camelPlural}])\n setHasChanges(false)\n }\n }, [data?.${camelPlural}])\n\n // Handle local row move (client-side only)\n const handleMoveRow = React.useCallback((id: number, direction: 'up' | 'down') => {\n setLocalData((prev) => {\n const index = prev.findIndex((item) => item.id === id)\n if (index === -1) return prev\n\n const newIndex = direction === 'up' ? index - 1 : index + 1\n if (newIndex < 0 || newIndex >= prev.length) return prev\n\n const newData = [...prev]\n const [removed] = newData.splice(index, 1)\n newData.splice(newIndex, 0, removed)\n\n return newData\n })\n setHasChanges(true)\n }, [])\n\n // Save all sort order changes to the database\n const handleSave = React.useCallback(async () => {\n if (!hasChanges) return\n\n setIsSaving(true)\n try {\n const updates = localData.map((item, index) => ({\n id: item.id as number,\n sortOrder: index\n }))\n\n const result = await bulkUpdate${Plural}SortOrder(updates)\n\n if (result.success) {\n toast.success('Sort order saved successfully')\n queryClient.refetchQueries({ queryKey: ['${plural}'] })\n setHasChanges(false)\n setReorderMode(false)\n } else {\n toast.error(result.error || 'Failed to save sort order')\n }\n } catch (error) {\n toast.error('An error occurred while saving')\n console.error(error)\n } finally {\n setIsSaving(false)\n }\n }, [hasChanges, localData, queryClient])\n\n // Cancel reorder mode and reset changes\n const handleCancelReorder = React.useCallback(() => {\n if (data?.${camelPlural}) {\n setLocalData([...data.${camelPlural}])\n }\n setHasChanges(false)\n setReorderMode(false)\n }, [data?.${camelPlural}])\n\n // Use local data when in reorder mode, otherwise use server data\n const tableData = reorderMode ? localData : (data?.${camelPlural} ?? [])\n\n // Convert selectedIds array to rowSelection object format\n const rowSelection = React.useMemo(() => {\n const selection: Record<string, boolean> = {}\n const ${camelPlural} = data?.${camelPlural} ?? []\n ${camelPlural}.forEach((${camelSingular}, index) => {\n if (selectedIds.includes(${camelSingular}.id as number)) {\n selection[index.toString()] = true\n }\n })\n return selection\n }, [selectedIds, data?.${camelPlural}])\n\n // Handle row selection changes\n const handleRowSelectionChange = React.useCallback(\n (updater: Record<string, boolean> | ((old: Record<string, boolean>) => Record<string, boolean>)) => {\n const ${camelPlural} = data?.${camelPlural} ?? []\n const newSelection = typeof updater === 'function' ? updater(rowSelection) : updater\n\n const newSelectedIds = Object.keys(newSelection)\n .filter((key) => newSelection[key])\n .map((key) => ${camelPlural}[Number.parseInt(key)]?.id as number)\n .filter(Boolean)\n\n setSelectedIds(newSelectedIds)\n },\n [data?.${camelPlural}, rowSelection, setSelectedIds]\n )\n\n // Determine effective page size (handle 'all' case)\n const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize\n\n const handlePageSizeChange = React.useCallback((value: string) => {\n React.startTransition(() => {\n if (value === 'all') {\n setPageSize(-1)\n } else {\n setPageSize(Number(value))\n }\n setPageIndex(0)\n })\n }, [setPageSize, setPageIndex])\n\n const handlePaginationChange = React.useCallback(\n (updater: { pageIndex: number; pageSize: number } | ((old: { pageIndex: number; pageSize: number }) => { pageIndex: number; pageSize: number })) => {\n const currentPagination = { pageIndex, pageSize: effectivePageSize }\n const newPagination = typeof updater === 'function' ? updater(currentPagination) : updater\n React.startTransition(() => {\n setPageIndex(newPagination.pageIndex)\n })\n },\n [pageIndex, effectivePageSize, setPageIndex]\n )\n\n const table = useReactTable({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n onRowSelectionChange: handleRowSelectionChange,\n onPaginationChange: handlePaginationChange,\n meta: {\n reorderMode,\n onMoveRow: handleMoveRow\n },\n state: {\n sorting,\n columnFilters,\n columnVisibility,\n rowSelection,\n pagination: {\n pageIndex,\n pageSize: effectivePageSize\n }\n }\n })\n\n return (\n <div className=\"space-y-6\">\n {/* Reorder controls */}\n <div className=\"flex items-center gap-2\">\n <Button\n variant={reorderMode ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setReorderMode(!reorderMode)}\n disabled={isSaving}\n >\n <ArrowUpDown className=\"size-4 mr-1\" />\n Sort Order\n </Button>\n {reorderMode && (\n <>\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={handleSave}\n disabled={!hasChanges || isSaving}\n >\n <Save className=\"size-4 mr-1\" />\n {isSaving ? 'Saving...' : 'Save'}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCancelReorder}\n disabled={isSaving}\n >\n Cancel\n </Button>\n {hasChanges && (\n <span className=\"text-sm text-muted-foreground\">\n Unsaved changes\n </span>\n )}\n </>\n )}\n </div>\n\n <div className=\"bg-card border overflow-hidden rounded-lg\">\n <Table>\n <TableHeader className=\"bg-secondary\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => {\n return (\n <TableHead key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-muted-foreground\">Loading ${schema.label}...</div>\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-destructive\">Error loading ${schema.label}: {error.message}</div>\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No ${schema.label} found.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Rows per page</span>\n <Select\n value={pageSize === -1 ? 'all' : String(pageSize)}\n onValueChange={handlePageSizeChange}\n >\n <SelectTrigger className=\"w-[100px] h-8\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PAGE_SIZE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center space-x-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n >\n Previous\n </Button>\n <div className=\"text-sm text-muted-foreground\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount() || 1}\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n >\n Next\n </Button>\n </div>\n </div>\n </div>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(tableFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, tableFileName)]\n }\n}\n","/**\n * Pipeline orchestrator — runs all 12 entity generation steps in sequence\n */\n\nimport type { BetterstartConfig } from '../config/types.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { generateActions, generateSingleActions } from './actions/index.js'\nimport { generateCache } from './cache.js'\nimport { generateColumns } from './columns/index.js'\nimport { generateCreatePage } from './create-page.js'\nimport { generateDatabase } from './database.js'\nimport { generateEditPage } from './edit-page.js'\nimport { generateForm, generateSingleForm } from './form/index.js'\nimport { generateHook, generateSingleHook } from './hook.js'\nimport { updateNavigation } from './navigation.js'\nimport { generatePage } from './page.js'\nimport { generatePageContent } from './page-content.js'\nimport { generateSinglePage } from './single-page.js'\nimport { generateTable } from './table.js'\n\nexport interface PipelineResult {\n success: boolean\n files: string[]\n errors: string[]\n}\n\n/**\n * Resolve output directories from config paths\n */\nfunction resolvePaths(config: BetterstartConfig) {\n const cms = config.paths?.cms ?? './cms'\n const pages = config.paths?.pages ?? './src/app/(cms)/cms/(authenticated)'\n const schemas = config.paths?.schemas ?? './cms/schemas'\n\n return {\n cmsDir: cms,\n pagesDir: pages,\n schemasDir: schemas,\n dbSchemaDir: `${cms}/db/schema.ts`,\n actionsDir: `${cms}/lib/actions`,\n hooksDir: `${cms}/hooks`\n }\n}\n\n/**\n * Run the full 12-step entity generation pipeline\n */\nexport function runEntityPipeline(\n schema: Schema,\n cwd: string,\n config: BetterstartConfig,\n options: GeneratorOptions = {}\n): PipelineResult {\n const paths = resolvePaths(config)\n const files: string[] = []\n const errors: string[] = []\n\n const steps: { name: string; run: () => string[] }[] = [\n {\n name: 'Database schema',\n run: () => generateDatabase(schema, cwd, paths.dbSchemaDir, options).files\n },\n {\n name: 'Server actions',\n run: () =>\n generateActions(schema, cwd, paths.actionsDir, {\n force: options.force,\n schemasDir: paths.schemasDir\n }).files\n },\n {\n name: 'React Query hook',\n run: () => generateHook(schema, cwd, paths.hooksDir, options).files\n },\n {\n name: 'Column definitions',\n run: () => generateColumns(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Table component',\n run: () => generateTable(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Page content',\n run: () => generatePageContent(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Page (server)',\n run: () => generatePage(schema, cwd, paths.pagesDir, options).files\n }\n ]\n\n // Steps 8-10 are conditional on schema.actions\n if (schema.actions?.create || schema.actions?.edit) {\n steps.push({\n name: 'Form',\n run: () => generateForm(schema, cwd, paths.pagesDir, options).files\n })\n }\n\n if (schema.actions?.create) {\n steps.push({\n name: 'Create page',\n run: () => generateCreatePage(schema, cwd, paths.pagesDir, options).files\n })\n }\n\n if (schema.actions?.edit) {\n steps.push({\n name: 'Edit page',\n run: () => generateEditPage(schema, cwd, paths.pagesDir, options).files\n })\n }\n\n // Steps 11-12 always run\n steps.push(\n {\n name: 'Navigation',\n run: () => updateNavigation(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Cache module',\n run: () => generateCache(schema, cwd, paths.cmsDir, options).files\n }\n )\n\n // Execute each step\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const stepNum = i + 1\n try {\n const result = step.run()\n files.push(...result)\n if (!options.silent) console.log(` ${stepNum}. ${step.name} ✓`)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${step.name}: ${msg}`)\n if (!options.silent) console.error(` ${stepNum}. ${step.name} ✗ — ${msg}`)\n }\n }\n\n return {\n success: errors.length === 0,\n files,\n errors\n }\n}\n\n/**\n * Run the 7-step single (singleton) generation pipeline\n */\nexport function runSinglePipeline(\n schema: Schema,\n cwd: string,\n config: BetterstartConfig,\n options: GeneratorOptions = {}\n): PipelineResult {\n const paths = resolvePaths(config)\n const files: string[] = []\n const errors: string[] = []\n\n const steps: { name: string; run: () => string[] }[] = [\n {\n name: 'Database schema',\n run: () => generateDatabase(schema, cwd, paths.dbSchemaDir, options).files\n },\n {\n name: 'Server actions',\n run: () =>\n generateSingleActions(schema, cwd, paths.actionsDir, { force: options.force }).files\n },\n {\n name: 'React Query hook',\n run: () => generateSingleHook(schema, cwd, paths.hooksDir, options).files\n },\n {\n name: 'Form',\n run: () => generateSingleForm(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Single page',\n run: () => generateSinglePage(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Navigation',\n run: () => updateNavigation(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Cache module',\n run: () => generateCache(schema, cwd, paths.cmsDir, options).files\n }\n ]\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const stepNum = i + 1\n try {\n const result = step.run()\n files.push(...result)\n if (!options.silent) console.log(` ${stepNum}. ${step.name} ✓`)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${step.name}: ${msg}`)\n if (!options.silent) console.error(` ${stepNum}. ${step.name} ✗ — ${msg}`)\n }\n }\n\n return {\n success: errors.length === 0,\n files,\n errors\n }\n}\n\n// Re-export individual generators for direct use\nexport { generateActions, generateSingleActions } from './actions/index.js'\nexport { generateCache } from './cache.js'\nexport { generateColumns } from './columns/index.js'\nexport { generateCreatePage } from './create-page.js'\nexport { generateDatabase } from './database.js'\nexport { generateEditPage } from './edit-page.js'\nexport { generateForm, generateSingleForm } from './form/index.js'\nexport { generateHook, generateSingleHook } from './hook.js'\nexport { updateNavigation } from './navigation.js'\nexport { generatePage } from './page.js'\nexport { generatePageContent } from './page-content.js'\nexport { generateSinglePage } from './single-page.js'\nexport { generateTable } from './table.js'\n","/**\n * Post-generation tasks: auto db:push + lint:fix\n */\n\nimport { execFileSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { PackageManager } from '../utils/package-manager.js'\nimport { detectPackageManager } from '../utils/package-manager.js'\n\n/**\n * Load .env.local and set variables on process.env (if not already set)\n */\nfunction loadEnvFile(cwd: string): void {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return\n\n const content = fs.readFileSync(envPath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx === -1) continue\n\n const key = trimmed.slice(0, eqIdx).trim()\n let value = trimmed.slice(eqIdx + 1).trim()\n\n // Strip surrounding quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1)\n }\n\n // Strip inline comments\n const commentIdx = value.indexOf(' #')\n if (commentIdx !== -1) {\n value = value.slice(0, commentIdx).trim()\n }\n\n if (!process.env[key]) {\n process.env[key] = value\n }\n }\n}\n\nfunction runPmScript(pm: PackageManager, script: string, cwd: string): boolean {\n const args = pm === 'bun' ? ['run', script] : [script]\n try {\n execFileSync(pm, args, { cwd, stdio: 'pipe' })\n return true\n } catch {\n return false\n }\n}\n\nfunction hasPkgScript(cwd: string, script: string): boolean {\n const pkgPath = path.join(cwd, 'package.json')\n if (!fs.existsSync(pkgPath)) return false\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as Record<string, unknown>\n const scripts = pkg.scripts as Record<string, unknown> | undefined\n return !!scripts?.[script]\n } catch {\n return false\n }\n}\n\nexport interface PostGenerateOptions {\n skipMigration?: boolean\n}\n\nexport interface PostGenerateResult {\n dbPush: 'success' | 'skipped' | 'no-db-url' | 'failed'\n lintFix: 'success' | 'skipped' | 'failed'\n}\n\n/**\n * Run post-generation tasks: db:push and lint:fix\n */\nexport function runPostGenerate(\n cwd: string,\n schemaName: string,\n options: PostGenerateOptions = {}\n): PostGenerateResult {\n const pm = detectPackageManager(cwd)\n const result: PostGenerateResult = {\n dbPush: 'skipped',\n lintFix: 'skipped'\n }\n\n // 1. Database push\n if (!options.skipMigration) {\n loadEnvFile(cwd)\n\n const dbUrl = process.env.BETTERSTART_DATABASE_URL || process.env.DATABASE_URL\n\n if (!dbUrl) {\n result.dbPush = 'no-db-url'\n console.log('\\n Database: skipped (no DATABASE_URL configured)')\n console.log(' To sync later: run db:push after setting BETTERSTART_DATABASE_URL')\n } else if (hasPkgScript(cwd, 'db:push')) {\n console.log('\\n Running db:push...')\n const ok = runPmScript(pm, 'db:push', cwd)\n result.dbPush = ok ? 'success' : 'failed'\n console.log(ok ? ' Database schema synced' : ' Database push failed (run db:push manually)')\n } else {\n // Try running drizzle-kit push directly using project-local binary\n console.log('\\n Running drizzle-kit push...')\n const drizzleBin = path.join(cwd, 'node_modules', '.bin', 'drizzle-kit')\n try {\n execFileSync(drizzleBin, ['push', '--force'], { cwd, stdio: 'inherit' })\n result.dbPush = 'success'\n console.log(' Database schema synced')\n } catch {\n result.dbPush = 'failed'\n console.log(' Database push failed (run drizzle-kit push manually)')\n }\n }\n } else {\n console.log('\\n Database: skipped (--skip-migration)')\n }\n\n // 2. Lint fix\n if (hasPkgScript(cwd, 'lint:fix')) {\n console.log(' Running lint:fix...')\n const ok = runPmScript(pm, 'lint:fix', cwd)\n result.lintFix = ok ? 'success' : 'failed'\n console.log(ok ? ' Code formatted' : ' Lint fix had issues (run lint:fix manually)')\n } else {\n // Try biome directly using project-local binary\n const biomeBin = path.join(cwd, 'node_modules', '.bin', 'biome')\n try {\n execFileSync(biomeBin, ['check', '--write', '.'], { cwd, stdio: 'pipe' })\n result.lintFix = 'success'\n console.log(' Code formatted with Biome')\n } catch {\n result.lintFix = 'skipped'\n }\n }\n\n // Next steps\n console.log('\\n Next steps:')\n console.log(' 1. Review the generated files')\n if (options.skipMigration || result.dbPush !== 'success') {\n console.log(' 2. Run database migration: db:push')\n console.log(` 3. Start the dev server and visit /cms/${schemaName}`)\n } else {\n console.log(` 2. Start the dev server and visit /cms/${schemaName}`)\n }\n\n return result\n}\n","import { execFileSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'\n\nconst LOCKFILE_MAP: Record<string, PackageManager> = {\n 'pnpm-lock.yaml': 'pnpm',\n 'package-lock.json': 'npm',\n 'yarn.lock': 'yarn',\n 'bun.lockb': 'bun',\n 'bun.lock': 'bun'\n}\n\nexport function detectPackageManager(cwd: string): PackageManager {\n // Walk up the directory tree to find lockfiles (handles monorepos)\n let dir = path.resolve(cwd)\n const root = path.parse(dir).root\n while (dir !== root) {\n for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) {\n if (fs.existsSync(path.join(dir, lockfile))) {\n return pm\n }\n }\n // Check packageManager field in package.json at this level\n const pkgPath = path.join(dir, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as Record<string, unknown>\n if (typeof pkg.packageManager === 'string') {\n const name = pkg.packageManager.split('@')[0]\n if (name === 'pnpm' || name === 'npm' || name === 'yarn' || name === 'bun') {\n return name\n }\n }\n } catch {\n // ignore parse errors\n }\n }\n dir = path.dirname(dir)\n }\n\n return 'npm'\n}\n\nexport function installCommand(pm: PackageManager): string {\n return pm === 'yarn' ? 'yarn' : `${pm} install`\n}\n\nexport function addCommand(pm: PackageManager, deps: string[], dev = false): string {\n const devFlag = dev ? (pm === 'yarn' ? '--dev' : '-D') : ''\n\n switch (pm) {\n case 'pnpm':\n return `pnpm add ${devFlag} ${deps.join(' ')}`.trim()\n case 'yarn':\n return `yarn add ${devFlag} ${deps.join(' ')}`.trim()\n case 'bun':\n return `bun add ${devFlag} ${deps.join(' ')}`.trim()\n default:\n return `npm install ${devFlag} ${deps.join(' ')}`.trim()\n }\n}\n\nexport function runCommand(pm: PackageManager, script: string): string {\n switch (pm) {\n case 'pnpm':\n return `pnpm ${script}`\n case 'yarn':\n return `yarn ${script}`\n case 'bun':\n return `bun run ${script}`\n default:\n return `npm run ${script}`\n }\n}\n\nexport function execPm(pm: PackageManager, args: string[], cwd: string): void {\n execFileSync(pm, args, { cwd, stdio: 'inherit' })\n}\n\n/**\n * Returns the binary + leading args to run `create-next-app` via the given package manager.\n * Using the native PM avoids nested-npx issues (e.g. running inside `npx @betterstart/cli`).\n */\nexport function createNextAppCommand(pm: PackageManager): { bin: string; prefix: string[] } {\n switch (pm) {\n case 'pnpm':\n return { bin: 'pnpm', prefix: ['create', 'next-app@latest'] }\n case 'yarn':\n return { bin: 'yarn', prefix: ['create', 'next-app@latest'] }\n case 'bun':\n return { bin: 'bunx', prefix: ['create-next-app@latest'] }\n default:\n return { bin: 'npx', prefix: ['create-next-app@latest'] }\n }\n}\n","import { execFileSync, spawn } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport * as p from '@clack/prompts'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { getDefaultConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\nimport { promptDatabase } from '../init/prompts/database.js'\nimport { promptFeatures } from '../init/prompts/features.js'\nimport { promptProject } from '../init/prompts/project.js'\nimport { scaffoldApiRoutes } from '../init/scaffolders/api-routes.js'\nimport { scaffoldAuth } from '../init/scaffolders/auth.js'\nimport { regenerateCmsDoc, scaffoldBase } from '../init/scaffolders/base.js'\nimport { scaffoldBiome } from '../init/scaffolders/biome.js'\nimport { scaffoldComponents } from '../init/scaffolders/components.js'\nimport { scaffoldDatabase } from '../init/scaffolders/database.js'\nimport { installDependenciesAsync } from '../init/scaffolders/dependencies.js'\nimport { detectDevPort, scaffoldEnv } from '../init/scaffolders/env.js'\nimport { scaffoldLayout } from '../init/scaffolders/layout.js'\nimport { scaffoldPreset } from '../init/scaffolders/preset.js'\nimport { scaffoldTailwind } from '../init/scaffolders/tailwind.js'\nimport { scaffoldTsconfig } from '../init/scaffolders/tsconfig.js'\nimport { detectProject } from '../utils/detect.js'\nimport { createNextAppCommand, detectPackageManager, runCommand } from '../utils/package-manager.js'\nimport { buildSeedScript } from './seed.js'\n\nexport const initCommand = new Command('init')\n .description('Scaffold CMS into a new or existing Next.js project')\n .argument('[name]', 'Project name (creates new directory if fresh project)')\n .option('--preset <preset>', 'Starter preset: blank, blog, or full', 'blog')\n .option('-y, --yes', 'Skip all prompts (accept defaults)')\n .option(\n '--database-url <url>',\n 'PostgreSQL database connection string (postgres:// or postgresql://)'\n )\n .option('--force', 'Overwrite all existing CMS files (nuclear option)')\n .action(\n async (\n name: string | undefined,\n options: { preset: string; yes?: boolean; databaseUrl?: string; force?: boolean }\n ) => {\n p.intro(pc.bgCyan(pc.black(' BetterStart CMS ')))\n\n let cwd = process.cwd()\n let project = detectProject(cwd)\n let pm = detectPackageManager(cwd)\n let isFreshProject = false\n\n // Determine srcDir\n let srcDir: boolean\n if (project.isExisting) {\n p.log.info(`Next.js project detected ${pc.dim('·')} ${pc.cyan(pm)}`)\n srcDir = project.hasSrcDir\n\n if (!project.hasTypeScript) {\n p.log.error('TypeScript is required. Please add a tsconfig.json first.')\n process.exit(1)\n }\n\n if (options.force) {\n // Nuclear option: wipe all CMS-owned directories and root-level files\n const nukeDirs = ['cms', 'app/(cms)']\n const nukeFiles = ['cms.config.ts', 'CMS.md', 'drizzle.config.ts']\n let nuked = 0\n for (const dir of nukeDirs) {\n const fullPath = path.resolve(cwd, dir)\n if (fs.existsSync(fullPath)) {\n fs.rmSync(fullPath, { recursive: true, force: true })\n nuked++\n }\n }\n for (const file of nukeFiles) {\n const fullPath = path.resolve(cwd, file)\n if (fs.existsSync(fullPath)) {\n fs.unlinkSync(fullPath)\n nuked++\n }\n }\n if (nuked > 0) {\n p.log.warn(`${pc.yellow('Force mode:')} removed ${nuked} existing CMS paths`)\n }\n // Re-detect project after wipe\n project = detectProject(cwd)\n } else if (project.conflicts.length > 0) {\n const conflictLines = project.conflicts.map((c) => `${pc.yellow('▲')} ${c}`)\n conflictLines.push(\n '',\n pc.dim('Existing files will not be overwritten.'),\n pc.dim(`Use ${pc.bold('--force')} to remove existing CMS files before scaffolding.`)\n )\n p.note(conflictLines.join('\\n'), pc.yellow('Conflicts'))\n if (!options.yes) {\n const proceed = await p.confirm({\n message: 'Continue anyway?',\n initialValue: true\n })\n if (p.isCancel(proceed) || !proceed) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n }\n }\n } else {\n p.log.info('No Next.js project found — fresh project mode')\n const projectPrompt = await promptProject(name)\n srcDir = projectPrompt.useSrcDir\n\n // Ask for preferred package manager\n if (!options.yes) {\n const pmChoice = await p.select({\n message: 'Which package manager do you want to use?',\n options: [\n { value: 'pnpm' as const, label: 'pnpm', hint: 'recommended' },\n { value: 'npm' as const, label: 'npm' },\n { value: 'yarn' as const, label: 'yarn' },\n { value: 'bun' as const, label: 'bun' }\n ]\n })\n if (p.isCancel(pmChoice)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n pm = pmChoice\n }\n\n // Run create-next-app using the selected package manager's native command\n // to avoid nested-npx issues (e.g. when running via `npx @betterstart/cli`)\n const displayName =\n projectPrompt.projectName === '.' ? path.basename(cwd) : projectPrompt.projectName\n\n const { bin, prefix } = createNextAppCommand(pm)\n const cnaArgs = [\n ...prefix,\n projectPrompt.projectName,\n '--yes',\n '--typescript',\n '--tailwind',\n '--app',\n '--turbopack',\n '--biome',\n '--react-compiler',\n `--use-${pm}`\n ]\n if (srcDir) cnaArgs.push('--src-dir')\n else cnaArgs.push('--no-src-dir')\n\n p.log.step(`Creating Next.js app: ${pc.cyan(displayName)}`)\n\n try {\n execFileSync(bin, cnaArgs, {\n cwd,\n stdio: 'inherit',\n timeout: 120_000\n })\n } catch (err) {\n p.log.error(err instanceof Error ? err.message : 'create-next-app failed')\n p.log.info(\n `You can create the project manually:\\n ${pc.cyan(`npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`)}\\n Then run ${pc.cyan('betterstart init')} inside it.`\n )\n process.exit(1)\n }\n\n // Move into the new project directory\n cwd = path.resolve(cwd, projectPrompt.projectName)\n\n // Verify the project was actually created\n const hasPackageJson = fs.existsSync(path.join(cwd, 'package.json'))\n const hasNextConfig = ['next.config.ts', 'next.config.js', 'next.config.mjs'].some((f) =>\n fs.existsSync(path.join(cwd, f))\n )\n\n if (!hasPackageJson || !hasNextConfig) {\n p.log.error(\n 'create-next-app completed but the project was not created. This can happen with nested npx calls.'\n )\n const manualCmd = `npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`\n p.log.info(\n `Create the project manually:\\n ${pc.cyan(manualCmd)}\\n Then run ${pc.cyan('betterstart init')} inside it.`\n )\n process.exit(1)\n }\n\n p.log.success(`Created ${displayName} Next.js project`)\n project = detectProject(cwd)\n isFreshProject = true\n }\n\n // Feature prompts\n const features = options.yes\n ? { includeEmail: true, preset: options.preset as 'blank' | 'blog' | 'full' }\n : await promptFeatures(options.preset)\n\n // Database URL — check existing .env.local first, then prompt if needed\n let databaseUrl: string | undefined\n const existingDbUrl = readExistingDbUrl(cwd)\n\n if (options.yes) {\n // Non-interactive mode: --database-url flag > existing env > placeholder\n if (options.databaseUrl) {\n if (!isValidDbUrl(options.databaseUrl)) {\n p.log.error(\n `Invalid database URL. Must start with ${pc.cyan('postgres://')} or ${pc.cyan('postgresql://')}`\n )\n process.exit(1)\n }\n databaseUrl = options.databaseUrl\n } else if (existingDbUrl) {\n databaseUrl = existingDbUrl\n }\n // else: no flag, no existing → use placeholder (databaseUrl stays undefined)\n } else if (existingDbUrl) {\n // Interactive mode but a valid URL already exists — skip the prompt\n const masked = maskDbUrl(existingDbUrl)\n p.log.info(`Using existing database URL from .env.local ${pc.dim(`(${masked})`)}`)\n databaseUrl = existingDbUrl\n } else {\n const dbResult = await promptDatabase()\n databaseUrl = dbResult.url\n }\n\n // Build config\n const config: BetterstartConfig = {\n ...getDefaultConfig(srcDir),\n features: { email: features.includeEmail }\n }\n\n // Run scaffolders — group fast steps under one spinner, then show results in a note box\n interface ScaffoldResult {\n label: string\n result: string\n }\n const results: ScaffoldResult[] = []\n const s = p.spinner()\n\n s.start('Directory structure')\n\n const baseFiles = scaffoldBase({ cwd, config })\n results.push({ label: 'Directory structure', result: `${baseFiles.length} files` })\n\n s.message('TypeScript aliases')\n const tsResult = scaffoldTsconfig(cwd)\n results.push({\n label: 'TypeScript aliases',\n result: tsResult.added.length > 0 ? `${tsResult.added.length} paths` : 'already set'\n })\n\n s.message('Tailwind CSS')\n const twResult = scaffoldTailwind(cwd, srcDir)\n results.push({\n label: 'Tailwind CSS',\n result: twResult.appended ? 'updated' : twResult.file ? 'already set' : 'no CSS file'\n })\n\n s.message('Environment variables')\n const envResult = scaffoldEnv(cwd, { includeEmail: features.includeEmail, databaseUrl })\n const envCount = envResult.added.length + envResult.updated.length\n results.push({\n label: 'Environment variables',\n result: envCount > 0 ? `${envCount} vars` : 'already set'\n })\n\n s.message('Database')\n const dbFiles = scaffoldDatabase({ cwd, config })\n results.push({ label: 'Database', result: `${dbFiles.length} files` })\n\n s.message('Authentication')\n const authFiles = scaffoldAuth({ cwd, config })\n results.push({ label: 'Authentication', result: `${authFiles.length} files` })\n\n s.message('Components')\n const compFiles = scaffoldComponents({ cwd, config })\n results.push({ label: 'Components', result: `${compFiles.length} files` })\n\n s.message('Pages & layouts')\n const layoutFiles = scaffoldLayout({ cwd, config })\n results.push({ label: 'Pages & layouts', result: `${layoutFiles.length} files` })\n\n s.message('API routes')\n const apiFiles = scaffoldApiRoutes({ cwd, config })\n results.push({ label: 'API routes', result: `${apiFiles.length} routes` })\n\n s.message('Linter')\n let linterResult: string\n if (project.linter.type === 'none') {\n const biomeResult = scaffoldBiome(cwd, project.linter)\n linterResult = biomeResult.installed ? 'biome (new)' : 'none'\n } else {\n linterResult = project.linter.type\n }\n results.push({ label: 'Linter', result: linterResult })\n\n // Build the note content before stopping the spinner\n const maxLabel = Math.max(...results.map((r) => r.label.length))\n const noteLines = results.map((r) => {\n const padded = r.label.padEnd(maxLabel + 3)\n return `${pc.green('✓')} ${padded}${pc.dim(r.result)}`\n })\n\n // Stop spinner quietly and erase the empty stop line, then show results card\n s.stop('')\n process.stdout.write('\\x1B[2A\\x1B[J')\n p.note(noteLines.join('\\n'), 'Scaffolded CMS')\n\n // If drizzle.config.ts already existed (wasn't created), offer to update it\n const drizzleConfigPath = path.join(cwd, 'drizzle.config.ts')\n if (!dbFiles.includes('drizzle.config.ts') && fs.existsSync(drizzleConfigPath)) {\n if (options.force) {\n const { drizzleConfigTemplate } = await import('../init/templates/db/drizzle-config.js')\n fs.writeFileSync(drizzleConfigPath, drizzleConfigTemplate(), 'utf-8')\n p.log.success('Updated drizzle.config.ts')\n } else if (!options.yes) {\n const overwrite = await p.confirm({\n message: 'drizzle.config.ts already exists. Overwrite with latest version?',\n initialValue: true\n })\n if (!p.isCancel(overwrite) && overwrite) {\n const { drizzleConfigTemplate } = await import('../init/templates/db/drizzle-config.js')\n fs.writeFileSync(drizzleConfigPath, drizzleConfigTemplate(), 'utf-8')\n p.log.success('Updated drizzle.config.ts')\n }\n }\n }\n\n // Install dependencies (async so spinner can animate)\n s.start('Installing dependencies (this may take a minute)')\n const depsResult = await installDependenciesAsync({\n cwd,\n pm,\n includeEmail: features.includeEmail,\n includeBiome: project.linter.type === 'none'\n })\n let depsInstalled = false\n if (depsResult.success) {\n s.stop('')\n depsInstalled = true\n } else {\n s.stop('Failed to install dependencies')\n p.log.warning(depsResult.error ?? 'Unknown error')\n p.log.info(\n `You can install them manually:\\n ${pc.cyan(`${pm} add ${depsResult.coreDeps.join(' ')}`)}\\n ${pc.cyan(`${pm} add -D ${depsResult.devDeps.join(' ')}`)}`\n )\n }\n\n // Apply preset schemas + run entity generation + regenerate CMS.md\n if (depsInstalled) {\n process.stdout.write('\\x1B[2A\\x1B[J')\n }\n s.start(`Applying ${features.preset} preset`)\n const presetResult = scaffoldPreset({ cwd, config, preset: features.preset })\n // Regenerate CMS.md with full documentation\n {\n const entityNames: string[] = []\n const formNames: string[] = []\n const schemasDir = path.join(cwd, config.paths.schemas)\n const formsDir = path.join(schemasDir, 'forms')\n if (fs.existsSync(schemasDir)) {\n for (const f of fs.readdirSync(schemasDir)) {\n if (f.endsWith('.json')) entityNames.push(f.replace('.json', ''))\n }\n }\n if (fs.existsSync(formsDir)) {\n for (const f of fs.readdirSync(formsDir)) {\n if (f.endsWith('.json')) formNames.push(f.replace('.json', ''))\n }\n }\n regenerateCmsDoc(cwd, config, {\n preset: features.preset,\n schemas: entityNames,\n forms: formNames\n })\n }\n s.stop('')\n process.stdout.write('\\x1B[2A\\x1B[J')\n\n // Build combined note for deps + preset\n const installLines: string[] = []\n if (depsInstalled) {\n installLines.push(\n `${pc.green('✓')} Dependencies ${pc.dim(`${depsResult.coreDeps.length} deps + ${depsResult.devDeps.length} dev deps`)}`\n )\n }\n if (presetResult.errors.length > 0) {\n installLines.push(\n `${pc.yellow('▲')} Preset ${pc.dim(`${features.preset} — ${presetResult.errors.length} warning(s)`)}`\n )\n for (const err of presetResult.errors) {\n installLines.push(` ${pc.dim(err)}`)\n }\n } else {\n installLines.push(\n `${pc.green('✓')} Preset ${pc.dim(`${features.preset} — ${presetResult.schemas.length} schemas, ${presetResult.generatedFiles.length} files`)}`\n )\n }\n p.note(installLines.join('\\n'), 'Installed')\n\n // Push database schema if env var is configured (after preset so entity tables are included)\n let dbPushed = false\n if (depsResult.success && hasDbUrl(cwd)) {\n s.start('Pushing database schema (drizzle-kit push)')\n const pushResult = await runDrizzlePush(cwd)\n if (pushResult.success) {\n s.stop(`${pc.green('✓')} Database schema pushed`)\n dbPushed = true\n } else {\n s.stop('Database push failed')\n p.log.warning(pushResult.error ?? 'Unknown error')\n p.log.info(`You can run it manually: ${pc.cyan('npx drizzle-kit push')}`)\n }\n }\n\n // Auto-seed admin user (only when db push succeeded and interactive mode)\n let seedEmail: string | undefined\n let seedPassword: string | undefined\n let seedSuccess = false\n\n if (dbPushed && !options.yes) {\n p.note(pc.dim('Create your first admin user to access the CMS.'), 'Admin account')\n\n const credentials = await p.group(\n {\n email: () =>\n p.text({\n message: 'Admin email',\n placeholder: 'admin@example.com',\n validate: (v) => {\n if (!v || !v.includes('@')) return 'Please enter a valid email'\n }\n }),\n password: () =>\n p.password({\n message: 'Admin password',\n validate: (v) => {\n if (!v || v.length < 8) return 'Password must be at least 8 characters'\n }\n })\n },\n {\n onCancel: () => {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n }\n )\n\n seedEmail = credentials.email\n seedPassword = credentials.password\n\n s.start('Creating admin user')\n let seedResult = await runSeed(\n cwd,\n config.paths?.cms ?? './cms',\n credentials.email,\n credentials.password\n )\n\n if (seedResult.existingUser) {\n s.stop(`${pc.yellow('▲')} Admin user already exists (${seedResult.existingUser})`)\n const replace = await p.confirm({\n message: 'Replace existing admin user?',\n initialValue: false\n })\n if (!p.isCancel(replace) && replace) {\n s.start('Replacing admin user')\n seedResult = await runSeed(\n cwd,\n config.paths?.cms ?? './cms',\n credentials.email,\n credentials.password,\n true\n )\n } else {\n seedSuccess = true\n }\n }\n\n if (seedResult.success) {\n s.stop(`${pc.green('✓')} Admin user created`)\n seedSuccess = true\n } else if (!seedSuccess && seedResult.error) {\n s.stop(`${pc.red('✗')} Failed to create admin user`)\n p.note(\n `${pc.red(seedResult.error)}\\n\\nRun manually: ${pc.cyan('npx betterstart seed')}`,\n pc.red('Seed failed')\n )\n }\n }\n\n // Git init + commit for fresh projects\n if (isFreshProject) {\n s.start('Creating initial git commit')\n try {\n execFileSync('git', ['init'], { cwd, stdio: 'pipe' })\n execFileSync('git', ['add', '.'], { cwd, stdio: 'pipe' })\n execFileSync('git', ['commit', '-m', 'Initial commit from BetterStart'], {\n cwd,\n stdio: 'pipe'\n })\n s.stop('Created initial git commit')\n } catch {\n s.stop('Git commit skipped')\n }\n }\n\n const totalFiles =\n baseFiles.length +\n dbFiles.length +\n authFiles.length +\n compFiles.length +\n layoutFiles.length +\n apiFiles.length\n\n // Summary\n const summaryLines: string[] = [\n `Preset: ${pc.cyan(features.preset)}`,\n `Files created: ${pc.cyan(String(totalFiles))}`,\n `Env vars: ${envResult.added.length} added, ${envResult.skipped.length} skipped`\n ]\n\n if (seedSuccess && seedEmail && seedPassword) {\n summaryLines.push(\n '',\n `Admin: ${pc.cyan(seedEmail)}`,\n `Password: ${pc.cyan(seedPassword)}`,\n `CMS: ${pc.cyan(`http://localhost:${detectDevPort(cwd)}/cms/login`)}`\n )\n }\n\n // Next steps\n const nextSteps: string[] = []\n let step = 1\n const envStepLabel = databaseUrl\n ? `Fill in remaining values in ${pc.cyan('.env.local')}`\n : `Fill in values in ${pc.cyan('.env.local')}`\n nextSteps.push(` ${step++}. ${envStepLabel}`)\n if (!dbPushed) {\n nextSteps.push(` ${step++}. Run ${pc.cyan('npx drizzle-kit push')} to sync the database`)\n }\n if (!seedSuccess) {\n nextSteps.push(\n ` ${step++}. Run ${pc.cyan('npx betterstart seed')} to create an admin user`\n )\n }\n nextSteps.push(` ${step++}. Run ${pc.cyan('pnpm run dev')} to start the development server`)\n nextSteps.push(\n ` ${step++}. Run ${pc.cyan('npx betterstart generate <schema>')} to create content types`\n )\n\n summaryLines.push('', 'Next steps:', ...nextSteps)\n\n p.note(summaryLines.join('\\n'), 'CMS scaffolded successfully')\n\n // Offer to start the dev server (interactive mode only)\n if (!options.yes) {\n const devCmd = runCommand(pm, 'dev')\n const startDev = await p.confirm({\n message: 'Start the development server?',\n initialValue: true\n })\n\n if (!p.isCancel(startDev) && startDev) {\n p.outro(`Starting ${pc.cyan(devCmd)}...`)\n const [bin, ...args] = devCmd.split(' ')\n spawn(bin, args, { cwd, stdio: 'inherit' })\n return\n }\n }\n\n p.outro('Done!')\n }\n )\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Validate a database connection URL */\nfunction isValidDbUrl(url: string): boolean {\n return url.startsWith('postgres://') || url.startsWith('postgresql://')\n}\n\n/** Read BETTERSTART_DATABASE_URL from .env.local, returning the value if it's a real URL. */\nfunction readExistingDbUrl(cwd: string): string | undefined {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return undefined\n const content = fs.readFileSync(envPath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed.startsWith('#') || !trimmed.includes('=')) continue\n const [key, ...rest] = trimmed.split('=')\n if (key?.trim() === 'BETTERSTART_DATABASE_URL') {\n const val = rest\n .join('=')\n .replace(/^['\"]|['\"]$/g, '')\n .trim()\n if (\n val.length > 0 &&\n !val.startsWith('your_') &&\n val !== 'postgresql://...' &&\n isValidDbUrl(val)\n ) {\n return val\n }\n }\n }\n return undefined\n}\n\n/** Mask a database URL for display: show host only. */\nfunction maskDbUrl(url: string): string {\n try {\n const parsed = new URL(url)\n return `${parsed.protocol}//${parsed.host}/***`\n } catch {\n return 'postgres://***'\n }\n}\n\n/** Check if BETTERSTART_DATABASE_URL is set in .env.local */\nfunction hasDbUrl(cwd: string): boolean {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return false\n const content = fs.readFileSync(envPath, 'utf-8')\n // Check the var exists and has a non-placeholder value\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed.startsWith('#') || !trimmed.includes('=')) continue\n const [key, ...rest] = trimmed.split('=')\n if (key?.trim() === 'BETTERSTART_DATABASE_URL') {\n const val = rest.join('=').trim()\n const unquoted = val.replace(/^['\"]|['\"]$/g, '')\n return unquoted.length > 0 && !unquoted.startsWith('your_') && unquoted !== 'postgresql://...'\n }\n }\n return false\n}\n\ninterface SeedResult {\n success: boolean\n error: string | null\n existingUser?: string\n}\n\n/** Write seed script, run it with tsx, clean up. Returns success/error. */\nfunction runSeed(\n cwd: string,\n cmsDir: string,\n email: string,\n password: string,\n overwrite = false\n): Promise<SeedResult> {\n const scriptsDir = path.join(cwd, cmsDir, 'scripts')\n const seedPath = path.join(scriptsDir, 'seed.ts')\n\n if (!fs.existsSync(scriptsDir)) {\n fs.mkdirSync(scriptsDir, { recursive: true })\n }\n fs.writeFileSync(seedPath, buildSeedScript(), 'utf-8')\n\n const cleanup = () => {\n try {\n fs.unlinkSync(seedPath)\n if (fs.existsSync(scriptsDir) && fs.readdirSync(scriptsDir).length === 0) {\n fs.rmdirSync(scriptsDir)\n }\n } catch {\n // Not critical\n }\n }\n\n return new Promise((resolve) => {\n const tsxBin = path.join(cwd, 'node_modules', '.bin', 'tsx')\n const child = spawn(tsxBin, [seedPath], {\n cwd,\n stdio: 'pipe',\n env: {\n ...process.env,\n SEED_EMAIL: email,\n SEED_PASSWORD: password,\n SEED_NAME: 'Admin',\n ...(overwrite ? { SEED_OVERWRITE: 'true' } : {})\n }\n })\n let stdout = ''\n let stderr = ''\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString()\n })\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n const timeout = setTimeout(() => {\n child.kill()\n cleanup()\n resolve({ success: false, error: 'Seed timed out after 30 seconds' })\n }, 30_000)\n child.on('close', (code) => {\n clearTimeout(timeout)\n cleanup()\n if (code === 0) {\n resolve({ success: true, error: null })\n } else if (code === 2) {\n // Exit code 2 = user already exists\n const name = stdout.match(/EXISTING_USER:(.+)/)?.[1]?.trim()\n resolve({ success: false, error: null, existingUser: name ?? email })\n } else {\n resolve({ success: false, error: parseSeedError(stdout, stderr) })\n }\n })\n child.on('error', (err) => {\n clearTimeout(timeout)\n cleanup()\n resolve({ success: false, error: parseSeedError('', err.message) })\n })\n })\n}\n\n/** Extract a human-readable error from seed script output */\nfunction parseSeedError(stdout: string, stderr: string): string {\n // Check for common patterns in stderr/stdout\n const combined = `${stdout}\\n${stderr}`\n\n // \"Seed failed: <message>\" from the catch handler\n const seedFailed = combined.match(/Seed failed:\\s*(.+)/)?.[1]?.trim()\n if (seedFailed) return seedFailed\n\n // \"Failed to create user\" from auth API failure\n if (combined.includes('Failed to create user')) return 'Auth API failed to create user'\n\n // Connection errors\n if (combined.includes('ECONNREFUSED') || combined.includes('connection refused'))\n return 'Could not connect to database'\n if (combined.includes('BETTERSTART_DATABASE_URL')) return 'Database URL is missing or invalid'\n if (combined.includes('password authentication failed'))\n return 'Database authentication failed — check your connection string'\n if (combined.includes('does not exist') && combined.includes('relation'))\n return 'Database tables not found — run npx drizzle-kit push first'\n if (combined.includes('MODULE_NOT_FOUND') || combined.includes('Cannot find module'))\n return 'Missing dependencies — run your package manager install first'\n\n // Fall back to first meaningful line of stderr\n const firstLine = stderr\n .split('\\n')\n .map((l) => l.trim())\n .find((l) => l.length > 0 && !l.startsWith('at ') && !l.startsWith('node:'))\n if (firstLine) return firstLine\n\n return 'Unknown error — run npx betterstart seed for details'\n}\n\n/** Run drizzle-kit push to sync the database schema */\nfunction runDrizzlePush(cwd: string): Promise<{ success: boolean; error: string | null }> {\n return new Promise((resolve) => {\n const drizzleBin = path.join(cwd, 'node_modules', '.bin', 'drizzle-kit')\n const child = spawn(drizzleBin, ['push', '--force'], {\n cwd,\n stdio: 'pipe',\n env: { ...process.env }\n })\n let stderr = ''\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n child.on('close', (code) => {\n if (code === 0) resolve({ success: true, error: null })\n else resolve({ success: false, error: stderr || `drizzle-kit push exited with code ${code}` })\n })\n child.on('error', (err) => {\n resolve({ success: false, error: err.message })\n })\n })\n}\n","import { execFileSync } from 'node:child_process'\n\nimport * as p from '@clack/prompts'\nimport pc from 'picocolors'\n\nexport interface DatabasePromptResult {\n url: string\n}\n\nconst VERCEL_NEON_URL = 'https://vercel.com/dashboard/integrations/checkout/neon'\n\n/**\n * Prompt the user to configure their database connection.\n *\n * Three paths:\n * 1. Vercel (Neon) — opens the integration page, then asks for the URL\n * 2. Supabase — \"coming soon\", loops back\n * 3. Manual — asks for the URL directly\n */\nexport async function promptDatabase(): Promise<DatabasePromptResult> {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const choice = await p.select({\n message: 'How would you like to connect your database?',\n options: [\n {\n value: 'vercel-neon' as const,\n label: 'Vercel (Neon)',\n hint: 'opens browser to create a free Postgres database'\n },\n {\n value: 'supabase' as const,\n label: 'Supabase',\n hint: 'coming soon'\n },\n {\n value: 'manual' as const,\n label: 'Enter connection string manually'\n }\n ]\n })\n\n if (p.isCancel(choice)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n if (choice === 'supabase') {\n p.log.warning('Supabase support is coming soon. Please choose another option.')\n continue\n }\n\n if (choice === 'vercel-neon') {\n openBrowser(VERCEL_NEON_URL)\n p.log.info(\n `Opening Vercel… Create a Neon Postgres database, then copy the ${pc.cyan('DATABASE_URL')} from the dashboard.`\n )\n }\n\n // Shared URL text prompt for both vercel-neon and manual\n const url = await promptConnectionString()\n return { url }\n }\n}\n\n/** Text prompt for the connection string with quote-stripping validation. */\nasync function promptConnectionString(): Promise<string> {\n const input = await p.text({\n message: 'Paste your database connection string',\n placeholder: 'postgres://user:pass@host/db',\n validate(val) {\n if (!val.trim()) {\n return 'A connection string is required to continue'\n }\n const stripped = val.replace(/^['\"]|['\"]$/g, '')\n if (!stripped.startsWith('postgres://') && !stripped.startsWith('postgresql://')) {\n return 'Must start with postgres:// or postgresql://'\n }\n }\n })\n\n if (p.isCancel(input)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n return (input as string).replace(/^['\"]|['\"]$/g, '').trim()\n}\n\n/** Best-effort browser open. Fails silently in headless / CI environments. */\nfunction openBrowser(url: string): void {\n try {\n const platform = process.platform\n if (platform === 'darwin') {\n execFileSync('open', [url], { stdio: 'ignore' })\n } else if (platform === 'win32') {\n execFileSync('cmd', ['/c', 'start', url], { stdio: 'ignore' })\n } else {\n execFileSync('xdg-open', [url], { stdio: 'ignore' })\n }\n } catch {\n // Silently ignore — user can open the URL manually\n }\n}\n","import * as p from '@clack/prompts'\n\nexport type Preset = 'blank' | 'blog' | 'full'\n\nexport interface FeaturesPromptResult {\n includeEmail: true\n preset: Preset\n}\n\n/**\n * Prompt for preset selection.\n */\nexport async function promptFeatures(presetOverride?: string): Promise<FeaturesPromptResult> {\n let preset: Preset\n if (presetOverride && isValidPreset(presetOverride)) {\n preset = presetOverride\n } else {\n const selected = await p.select({\n message: 'Select a preset:',\n options: [\n { value: 'blog' as const, label: 'Blog', hint: 'Posts + Categories (recommended)' },\n { value: 'blank' as const, label: 'Blank', hint: 'CMS shell only, no content types' },\n { value: 'full' as const, label: 'Full', hint: 'Blog + Navigation + Contact form' }\n ],\n initialValue: 'blog' as const\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n preset = selected\n }\n\n return { includeEmail: true, preset }\n}\n\nfunction isValidPreset(value: string): value is Preset {\n return value === 'blank' || value === 'blog' || value === 'full'\n}\n","import * as p from '@clack/prompts'\n\nexport interface ProjectPromptResult {\n projectName: string\n useSrcDir: boolean\n}\n\n/**\n * Prompt for project name and src/ directory (fresh project only).\n */\nexport async function promptProject(defaultName?: string): Promise<ProjectPromptResult> {\n const projectName = await p.text({\n message: 'What is your project name?',\n placeholder: defaultName ?? 'my-app',\n defaultValue: defaultName ?? 'my-app',\n validate: (value) => {\n if (!value.trim()) return 'Project name is required'\n if (value.trim() === '.') return undefined\n if (!/^[a-z0-9_-]+$/i.test(value.trim())) {\n return 'Project name can only contain letters, numbers, hyphens, and underscores'\n }\n return undefined\n }\n })\n\n if (p.isCancel(projectName)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n const useSrcDir = await p.confirm({\n message: 'Use src/ directory?',\n initialValue: false\n })\n\n if (p.isCancel(useSrcDir)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n return { projectName: projectName.trim(), useSrcDir }\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { ensureDir, safeWriteFile } from '../../utils/fs.js'\n\nimport { authRouteTemplate } from '../templates/api/auth-route.js'\nimport { uploadRouteTemplate } from '../templates/api/upload-route.js'\n\nexport interface ApiRoutesScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create CMS API routes under /api/cms/.\n */\nexport function scaffoldApiRoutes({ cwd, config }: ApiRoutesScaffoldOptions): string[] {\n const created: string[] = []\n const apiDir = path.resolve(cwd, config.paths.api)\n\n function write(relPath: string, content: string): void {\n const fullPath = path.join(apiDir, relPath)\n ensureDir(path.dirname(fullPath))\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.api, relPath))\n }\n }\n\n // Better Auth catch-all: /api/cms/auth/[...all]/route.ts\n write(path.join('auth', '[...all]', 'route.ts'), authRouteTemplate())\n\n // Upload: /api/cms/upload/route.ts\n write(path.join('upload', 'route.ts'), uploadRouteTemplate())\n\n return created\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport fse from 'fs-extra'\n\n/**\n * Ensure a directory exists, creating it recursively if needed.\n */\nexport function ensureDir(dirPath: string): void {\n fse.ensureDirSync(dirPath)\n}\n\n/**\n * Write a file, creating parent directories as needed.\n * Will NOT overwrite an existing file unless `force` is true.\n * Returns true if the file was written, false if skipped.\n */\nexport function safeWriteFile(filePath: string, content: string, force = false): boolean {\n if (!force && fs.existsSync(filePath)) {\n return false\n }\n ensureDir(path.dirname(filePath))\n fs.writeFileSync(filePath, content, 'utf-8')\n return true\n}\n\n/**\n * Copy a single file, creating parent directories as needed.\n * Will NOT overwrite an existing file unless `force` is true.\n */\nexport function safeCopyFile(src: string, dest: string, force = false): boolean {\n if (!force && fs.existsSync(dest)) {\n return false\n }\n ensureDir(path.dirname(dest))\n fs.copyFileSync(src, dest)\n return true\n}\n\n/**\n * Recursively copy a directory of templates.\n * Skips existing files unless `force` is true.\n * Returns lists of written and skipped file paths.\n */\nexport function copyTemplateDir(\n srcDir: string,\n destDir: string,\n force = false\n): { written: string[]; skipped: string[] } {\n const written: string[] = []\n const skipped: string[] = []\n\n function walk(currentSrc: string, currentDest: string): void {\n const entries = fs.readdirSync(currentSrc, { withFileTypes: true })\n for (const entry of entries) {\n const srcPath = path.join(currentSrc, entry.name)\n const destPath = path.join(currentDest, entry.name)\n\n if (entry.isDirectory()) {\n walk(srcPath, destPath)\n } else {\n if (safeCopyFile(srcPath, destPath, force)) {\n written.push(destPath)\n } else {\n skipped.push(destPath)\n }\n }\n }\n }\n\n walk(srcDir, destDir)\n return { written, skipped }\n}\n\n/**\n * Append content to a file if the marker text is not already present.\n * Creates the file if it doesn't exist.\n * Returns true if content was appended.\n */\nexport function appendToFile(filePath: string, content: string, marker: string): boolean {\n if (fs.existsSync(filePath)) {\n const existing = fs.readFileSync(filePath, 'utf-8')\n if (existing.includes(marker)) {\n return false\n }\n fs.writeFileSync(filePath, `${existing.trimEnd()}\\n${content}\\n`, 'utf-8')\n } else {\n ensureDir(path.dirname(filePath))\n fs.writeFileSync(filePath, `${content}\\n`, 'utf-8')\n }\n return true\n}\n","/**\n * Template: app/(cms)/api/cms/auth/[...all]/route.ts\n * Better Auth catch-all route handler\n */\nexport function authRouteTemplate(): string {\n return `import { auth, toNextJsHandler } from '@cms/auth'\n\nexport const { GET, POST } = toNextJsHandler(auth)\n`\n}\n","/**\n * Template: app/(cms)/api/cms/upload/route.ts\n * File upload route handler — uploads to Cloudflare R2\n */\nexport function uploadRouteTemplate(): string {\n return `import { PutObjectCommand } from '@aws-sdk/client-s3'\nimport { BUCKET_NAME, generateFilePath, getPublicUrl, getR2Client } from '@cms/lib/r2'\nimport type { UploadedFile } from '@cms/types'\nimport { validateFiles } from '@cms/utils/validation'\nimport { type NextRequest, NextResponse } from 'next/server'\n\nexport async function POST(request: NextRequest) {\n try {\n const formData = await request.formData()\n const prefix = formData.get('prefix')?.toString() || 'uploads'\n\n const maxSizeInBytes = Number(formData.get('maxSizeInBytes')) || 10 * 1024 * 1024\n const allowedTypesRaw = formData.get('allowedTypes')?.toString()\n const allowedTypes = allowedTypesRaw ? allowedTypesRaw.split(',').filter(Boolean) : []\n\n const files: File[] = []\n for (const [key, value] of formData.entries()) {\n if (value instanceof File && key.startsWith('file')) {\n files.push(value)\n }\n }\n\n if (files.length === 0) {\n return NextResponse.json({ success: false, error: 'No files provided' }, { status: 400 })\n }\n\n const validation = validateFiles(files, {\n maxSizeInBytes,\n allowedTypes,\n maxFiles: 10,\n })\n\n if (!validation.valid) {\n return NextResponse.json(\n {\n success: false,\n error: validation.errors.map((e) => \\`\\${e.filename}: \\${e.error}\\`).join('; '),\n },\n { status: 400 },\n )\n }\n\n const uploadedFiles: UploadedFile[] = []\n\n for (const file of files) {\n const key = generateFilePath(file.name, prefix)\n const arrayBuffer = await file.arrayBuffer()\n const buffer = Buffer.from(arrayBuffer)\n\n const command = new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: key,\n Body: buffer,\n ContentType: file.type,\n ContentLength: file.size,\n })\n\n await getR2Client().send(command)\n\n uploadedFiles.push({\n key,\n url: getPublicUrl(key),\n filename: file.name,\n size: file.size,\n contentType: file.type,\n })\n }\n\n return NextResponse.json({ success: true, files: uploadedFiles })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to upload files'\n return NextResponse.json({ success: false, error: message }, { status: 500 })\n }\n}\n`\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { safeWriteFile } from '../../utils/fs.js'\n\nimport { authTemplate } from '../templates/lib/auth/auth.js'\nimport { authClientTemplate } from '../templates/lib/auth/auth-client.js'\nimport { authMiddlewareTemplate } from '../templates/lib/auth/middleware.js'\n\nexport interface AuthScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create Better Auth config, client, and middleware in cms/lib/auth/.\n */\nexport function scaffoldAuth({ cwd, config }: AuthScaffoldOptions): string[] {\n const created: string[] = []\n const authDir = path.resolve(cwd, config.paths.cms, 'lib', 'auth')\n\n function write(filename: string, content: string): void {\n const fullPath = path.join(authDir, filename)\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.cms, 'lib', 'auth', filename))\n }\n }\n\n write('auth.ts', authTemplate())\n write('auth-client.ts', authClientTemplate())\n write('middleware.ts', authMiddlewareTemplate())\n\n return created\n}\n","/**\n * Template: cms/lib/auth/auth.ts\n * Better Auth server configuration\n */\nexport function authTemplate(): string {\n return `import db from '@cms/db'\nimport * as schema from '@cms/db/schema'\nimport { betterAuth } from 'better-auth'\nimport { drizzleAdapter } from 'better-auth/adapters/drizzle'\nimport { toNextJsHandler } from 'better-auth/next-js'\n\nexport { toNextJsHandler }\n\nexport const auth = betterAuth({\n secret: process.env.BETTERSTART_AUTH_SECRET,\n baseURL: process.env.BETTERSTART_AUTH_URL,\n basePath: process.env.BETTERSTART_AUTH_BASE_PATH || '/api/cms/auth',\n database: drizzleAdapter(db, {\n provider: 'pg',\n schema: {\n user: schema.user,\n session: schema.session,\n account: schema.account,\n verification: schema.verification,\n },\n }),\n emailAndPassword: {\n enabled: true,\n minPasswordLength: 8,\n },\n session: {\n expiresIn: 60 * 60 * 24 * 7, // 7 days\n updateAge: 60 * 60 * 24, // 1 day\n },\n user: {\n additionalFields: {\n role: {\n type: 'string',\n required: false,\n defaultValue: 'member',\n input: false,\n },\n },\n },\n})\n\nexport type Session = typeof auth.$Infer.Session\nexport type User = typeof auth.$Infer.Session.user\n`\n}\n","/**\n * Template: cms/lib/auth/auth-client.ts\n * Better Auth client for use in client components\n */\nexport function authClientTemplate(): string {\n return `'use client'\n\nimport { createAuthClient } from 'better-auth/react'\n\nexport const authClient = createAuthClient({\n baseURL:\n process.env.NEXT_PUBLIC_BETTERSTART_AUTH_URL ||\n (typeof window !== 'undefined' ? window.location.origin : ''),\n basePath: '/api/cms/auth',\n})\n\nexport const { signIn, signUp, signOut, useSession } = authClient\n`\n}\n","/**\n * Template: cms/lib/auth/middleware.ts\n * Server-side auth helpers: getSession, requireRole\n */\nexport function authMiddlewareTemplate(): string {\n return `import { headers } from 'next/headers'\nimport { redirect } from 'next/navigation'\nimport { auth, type User } from './auth'\n\nexport enum UserRole {\n ADMIN = 'admin',\n EDITOR = 'editor',\n MEMBER = 'member',\n}\n\nexport function isUserRole(value: unknown): value is UserRole {\n return typeof value === 'string' && Object.values(UserRole).includes(value as UserRole)\n}\n\n/**\n * Get the current session from Better Auth\n */\nexport async function getSession() {\n const session = await auth.api.getSession({\n headers: await headers(),\n })\n return session\n}\n\n/**\n * Require the user to have one of the specified roles.\n * Redirects to /cms/login if not authenticated or unauthorized.\n */\nexport async function requireRole(allowedRoles: UserRole[]): Promise<User> {\n const session = await getSession()\n\n if (!session?.user) {\n redirect('/cms/login')\n }\n\n const user = session.user\n const role = isUserRole(user.role) ? user.role : UserRole.MEMBER\n\n if (!allowedRoles.includes(role)) {\n redirect('/cms/login')\n }\n\n return user\n}\n`\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { ensureDir, safeWriteFile } from '../../utils/fs.js'\n\nexport interface BaseScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\nexport interface CmsDocOptions {\n preset?: string\n schemas?: string[]\n forms?: string[]\n}\n\n/**\n * Create the cms/ directory structure, cms.config.ts, and CMS.md.\n */\nexport function scaffoldBase({ cwd, config }: BaseScaffoldOptions): string[] {\n const created: string[] = []\n\n // Create cms/ subdirectories\n const cmsDirs = [\n config.paths.cms,\n config.paths.schemas,\n path.join(config.paths.cms, 'db'),\n path.join(config.paths.cms, 'db', 'migrations'),\n path.join(config.paths.cms, 'lib', 'auth'),\n path.join(config.paths.cms, 'lib', 'actions'),\n path.join(config.paths.cms, 'lib', 'cache'),\n path.join(config.paths.cms, 'lib', 'markdown'),\n path.join(config.paths.cms, 'lib', 'emails'),\n path.join(config.paths.cms, 'lib'),\n path.join(config.paths.cms, 'hooks'),\n path.join(config.paths.cms, 'components', 'ui'),\n path.join(config.paths.cms, 'components', 'form'),\n path.join(config.paths.cms, 'components', 'data-table'),\n path.join(config.paths.cms, 'components', 'layout'),\n path.join(config.paths.cms, 'components', 'shared'),\n path.join(config.paths.cms, 'types'),\n path.join(config.paths.cms, 'utils'),\n path.join(config.paths.cms, 'data')\n ]\n\n for (const dir of cmsDirs) {\n ensureDir(path.resolve(cwd, dir))\n }\n\n // Create app route directories\n const appDirs = [config.paths.pages, config.paths.login, config.paths.api]\n\n for (const dir of appDirs) {\n ensureDir(path.resolve(cwd, dir))\n }\n\n // Write cms.config.ts\n const configContent = generateConfigFile(config)\n if (safeWriteFile(path.resolve(cwd, 'cms.config.ts'), configContent)) {\n created.push('cms.config.ts')\n }\n\n // Write CMS.md (basic version — regenerated after preset with full info)\n const cmsDoc = generateCmsDoc(config, {})\n if (safeWriteFile(path.resolve(cwd, 'CMS.md'), cmsDoc)) {\n created.push('CMS.md')\n }\n\n return created\n}\n\n/**\n * Regenerate CMS.md with full documentation including preset and schema info.\n * Called after the preset step so generated schemas can be listed.\n */\nexport function regenerateCmsDoc(\n cwd: string,\n config: BetterstartConfig,\n options: CmsDocOptions\n): void {\n const content = generateCmsDoc(config, options)\n fs.writeFileSync(path.resolve(cwd, 'CMS.md'), content, 'utf-8')\n}\n\nfunction generateConfigFile(config: BetterstartConfig): string {\n return `import { defineConfig } from '@betterstart/cli'\n\nexport default defineConfig({\n srcDir: ${String(config.srcDir)},\n\n paths: {\n cms: '${config.paths.cms}',\n schemas: '${config.paths.schemas}',\n pages: '${config.paths.pages}',\n login: '${config.paths.login}',\n api: '${config.paths.api}',\n },\n\n database: {\n provider: '${config.database.provider}',\n migrationsDir: '${config.database.migrationsDir}',\n },\n\n features: {\n email: ${String(config.features.email)},\n },\n\n linter: '${config.linter}',\n\n generated: {\n entities: [],\n singles: [],\n forms: [],\n },\n})\n`\n}\n\nfunction generateCmsDoc(config: BetterstartConfig, options: CmsDocOptions): string {\n const sections: string[] = []\n\n // Header\n sections.push(`# CMS\n\n> Auto-generated by [BetterStart CLI](https://github.com/betterstart/cli).\n> Regenerated on each \\`betterstart init\\`.`)\n\n // Preset\n if (options.preset) {\n sections.push(`## Preset\n\nThis project was initialized with the **${options.preset}** preset.`)\n }\n\n // Directory structure\n sections.push(`## Directory Structure\n\n| Path | Description |\n|------|-------------|\n| \\`cms/\\` | All CMS source code (you own this) |\n| \\`cms/schemas/\\` | Entity JSON schemas |\n| \\`cms/schemas/forms/\\` | Form JSON schemas |\n| \\`cms/db/\\` | Database client, schema, drizzle config |\n| \\`cms/lib/actions/\\` | Server actions (CRUD) |\n| \\`cms/lib/auth/\\` | Better Auth configuration |\n| \\`cms/lib/cache/\\` | Cache tags, queries, revalidation |\n| \\`cms/lib/emails/\\` | React Email templates |\n| \\`cms/hooks/\\` | React Query hooks |\n| \\`cms/components/\\` | UI components (shadcn-style) |\n| \\`cms/utils/\\` | Utility functions |\n| \\`${config.paths.pages}/\\` | Admin pages (auth-gated) |\n| \\`${config.paths.login}/\\` | Login page |\n| \\`${config.paths.api}/\\` | CMS API routes |`)\n\n // Generated content\n if (\n (options.schemas && options.schemas.length > 0) ||\n (options.forms && options.forms.length > 0)\n ) {\n const lines: string[] = ['## Generated Content', '']\n if (options.schemas && options.schemas.length > 0) {\n lines.push('### Entities')\n for (const s of options.schemas) {\n lines.push(`- **${s}** — \\`cms/schemas/${s}.json\\` → admin at \\`/cms/${s}\\``)\n }\n }\n if (options.forms && options.forms.length > 0) {\n lines.push('')\n lines.push('### Forms')\n for (const f of options.forms) {\n lines.push(`- **${f}** — \\`cms/schemas/forms/${f}.json\\` → admin at \\`/cms/forms/${f}\\``)\n }\n }\n sections.push(lines.join('\\n'))\n }\n\n // Commands\n sections.push(`## Commands\n\n\\`\\`\\`bash\n# Generate entity CRUD from a schema\nnpx betterstart generate <schema-name>\n\n# Generate with force overwrite\nnpx betterstart generate <schema-name> --force\n\n# Remove all generated files for an entity/form\nnpx betterstart remove <schema-name>\n\n# Create initial admin user\nnpx betterstart seed\n\\`\\`\\``)\n\n // Schema format\n sections.push(`## Schema Format\n\n### Entity Schema (\\`cms/schemas/<name>.json\\`)\n\n\\`\\`\\`json\n{\n \"name\": \"posts\",\n \"label\": \"Posts\",\n \"icon\": \"FileText\",\n \"fields\": [\n { \"name\": \"title\", \"type\": \"string\", \"label\": \"Title\", \"required\": true },\n { \"name\": \"content\", \"type\": \"richtext\", \"label\": \"Content\" }\n ]\n}\n\\`\\`\\`\n\nField types: \\`string\\`, \\`text\\`, \\`richtext\\`, \\`number\\`, \\`boolean\\`, \\`date\\`, \\`image\\`, \\`select\\`, \\`relationship\\`.\n\n### Form Schema (\\`cms/schemas/forms/<name>.json\\`)\n\n\\`\\`\\`json\n{\n \"name\": \"contact\",\n \"label\": \"Contact Form\",\n \"submitButtonText\": \"Send Message\",\n \"fields\": [\n { \"name\": \"email\", \"type\": \"email\", \"label\": \"Email\", \"required\": true },\n { \"name\": \"message\", \"type\": \"textarea\", \"label\": \"Message\", \"required\": true }\n ]\n}\n\\`\\`\\`\n\nField types: \\`text\\`, \\`textarea\\`, \\`email\\`, \\`phone\\`, \\`number\\`, \\`url\\`, \\`date\\`, \\`select\\`, \\`radio\\`, \\`checkbox\\`, \\`multiselect\\`, \\`file\\`.`)\n\n // Path aliases\n sections.push(`## Path Aliases\n\n| Alias | Resolves to |\n|-------|-------------|\n| \\`@cms/*\\` | \\`${config.paths.cms}/*\\` |`)\n\n // Environment variables\n sections.push(`## Environment Variables\n\nRequired variables in \\`.env.local\\`:\n\n| Variable | Description |\n|----------|-------------|\n| \\`BETTERSTART_DATABASE_URL\\` | PostgreSQL connection string |\n| \\`BETTERSTART_AUTH_SECRET\\` | Auth secret (\\`openssl rand -base64 32\\`) |\n| \\`BETTERSTART_AUTH_URL\\` | App URL (e.g. \\`http://localhost:3000\\`) |\n| \\`BETTERSTART_R2_*\\` | Cloudflare R2 storage credentials |\n| \\`BETTERSTART_RESEND_API_KEY\\` | Resend API key (if email enabled) |\n| \\`NOTIFICATION_EMAIL\\` | Fallback notification email address |`)\n\n // Configuration\n sections.push(`## Configuration\n\nEdit \\`cms.config.ts\\` to customize paths, database provider, and features.`)\n\n return `${sections.join('\\n\\n')}\\n`\n}\n","/**\n * Biome scaffolder: creates biome.json if no existing linter is detected\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { LinterInfo } from '../../utils/detect.js'\n\nexport interface BiomeScaffoldResult {\n /** Whether Biome was set up */\n installed: boolean\n /** Reason it was skipped (if any) */\n skippedReason: string | null\n}\n\n/**\n * Create biome.json config if no linter exists.\n * Does NOT install the package — the dependency installer (task 5.05) handles that.\n */\nexport function scaffoldBiome(cwd: string, linter: LinterInfo): BiomeScaffoldResult {\n if (linter.type !== 'none') {\n return {\n installed: false,\n skippedReason: `${linter.type} already configured (${linter.configFile})`\n }\n }\n\n const configPath = path.join(cwd, 'biome.json')\n if (fs.existsSync(configPath)) {\n return { installed: false, skippedReason: 'biome.json already exists' }\n }\n\n const config = {\n $schema: 'https://biomejs.dev/schemas/1.9.4/schema.json',\n vcs: {\n enabled: true,\n clientKind: 'git',\n useIgnoreFile: true\n },\n organizeImports: {\n enabled: true\n },\n formatter: {\n enabled: true,\n indentStyle: 'space',\n indentWidth: 2,\n lineWidth: 100\n },\n linter: {\n enabled: true,\n rules: {\n recommended: true,\n correctness: {\n noUnusedImports: 'warn',\n noUnusedVariables: 'warn'\n },\n style: {\n noNonNullAssertion: 'off'\n }\n }\n },\n javascript: {\n formatter: {\n quoteStyle: 'single',\n trailingCommas: 'all',\n semicolons: 'asNeeded'\n }\n },\n files: {\n ignore: [\n 'node_modules',\n '.next',\n 'dist',\n 'build',\n '*.config.js',\n '*.config.mjs',\n '*.config.cjs'\n ]\n }\n }\n\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, 'utf-8')\n return { installed: true, skippedReason: null }\n}\n","import path from 'node:path'\nimport fs from 'fs-extra'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { detectProjectName } from '../../utils/detect.js'\nimport { safeWriteFile } from '../../utils/fs.js'\n// CSS\nimport { cmsGlobalsCssTemplate } from '../templates/components/cms-globals.js'\n// Data table components\nimport { dataTableTemplate } from '../templates/components/data-table/data-table.js'\nimport { dataTablePaginationTemplate } from '../templates/components/data-table/data-table-pagination.js'\nimport { dataTableToolbarTemplate } from '../templates/components/data-table/data-table-toolbar.js'\n// Layout components\nimport { cmsHeaderTemplate } from '../templates/components/layout/cms-header.js'\nimport { cmsNavLinkTemplate } from '../templates/components/layout/cms-nav-link.js'\nimport { cmsProvidersTemplate } from '../templates/components/layout/cms-providers.js'\nimport { cmsSearchTemplate } from '../templates/components/layout/cms-search.js'\nimport { cmsSidebarTemplate } from '../templates/components/layout/cms-sidebar.js'\n// Shared components\nimport { deleteDialogTemplate } from '../templates/components/shared/delete-dialog.js'\nimport { pageHeaderTemplate } from '../templates/components/shared/page-header.js'\nimport { statusBadgeTemplate } from '../templates/components/shared/status-badge.js'\n// Data\nimport { cmsDataTemplate } from '../templates/data/cms.js'\nimport { navigationDataTemplate } from '../templates/data/navigation.js'\nimport { useCmsThemeTemplate } from '../templates/hooks/use-cms-theme.js'\n// Hooks\nimport { useEditorImageUploadHookTemplate } from '../templates/hooks/use-editor-image-upload.js'\nimport { useLocalStorageHookTemplate } from '../templates/hooks/use-local-storage.js'\nimport { useMobileHookTemplate } from '../templates/hooks/use-mobile.js'\nimport { useUploadHookTemplate } from '../templates/hooks/use-upload.js'\nimport { useUsersHookTemplate } from '../templates/hooks/use-users.js'\nimport { formSettingsActionTemplate } from '../templates/lib/actions/form-settings.js'\nimport { uploadActionTemplate } from '../templates/lib/actions/upload.js'\nimport { usersActionTemplate } from '../templates/lib/actions/users.js'\nimport { markdownCachedTemplate } from '../templates/lib/markdown/cached.js'\nimport { markdownFormatTemplate } from '../templates/lib/markdown/format.js'\n// Markdown\nimport { markdownRenderTemplate } from '../templates/lib/markdown/render.js'\n// Lib\nimport { r2ClientTemplate } from '../templates/lib/r2.js'\n// Types\nimport { authTypesTemplate } from '../templates/types/auth.js'\nimport { typesIndexTemplate } from '../templates/types/index.js'\nimport { tableMetaTypesTemplate } from '../templates/types/table-meta.js'\n// Utils\nimport { cnUtilTemplate } from '../templates/utils/cn.js'\nimport { seoUtilTemplate } from '../templates/utils/seo.js'\nimport { validationUtilTemplate } from '../templates/utils/validation.js'\nimport { webhookUtilTemplate } from '../templates/utils/webhook.js'\nimport { mailchimpUtilTemplate } from '../templates/utils/mailchimp.js'\n\nexport interface ComponentScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Copy all CMS components, hooks, types, utils, data, and lib code into the project.\n */\nexport function scaffoldComponents({ cwd, config }: ComponentScaffoldOptions): string[] {\n const cms = path.resolve(cwd, config.paths.cms)\n const created: string[] = []\n\n function write(relPath: string, content: string): void {\n const fullPath = path.join(cms, relPath)\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.cms, relPath))\n }\n }\n\n // --- CSS ---\n write('cms-globals.css', cmsGlobalsCssTemplate())\n\n // --- Components: layout ---\n write('components/layout/cms-providers.tsx', cmsProvidersTemplate())\n write('components/layout/cms-nav-link.tsx', cmsNavLinkTemplate())\n write('components/layout/cms-sidebar.tsx', cmsSidebarTemplate())\n write('components/layout/cms-header.tsx', cmsHeaderTemplate())\n write('components/layout/cms-search.tsx', cmsSearchTemplate())\n // --- Components: shared ---\n write('components/shared/page-header.tsx', pageHeaderTemplate())\n write('components/shared/delete-dialog.tsx', deleteDialogTemplate())\n write('components/shared/status-badge.tsx', statusBadgeTemplate())\n\n // --- Components: data-table ---\n write('components/data-table/data-table.tsx', dataTableTemplate())\n write('components/data-table/data-table-pagination.tsx', dataTablePaginationTemplate())\n write('components/data-table/data-table-toolbar.tsx', dataTableToolbarTemplate())\n\n // --- Components: ui (raw file copy) ---\n const uiCreated = copyUiTemplates(cwd, config)\n created.push(...uiCreated)\n\n // --- Components: ui/tiptap (recursive copy) ---\n const tiptapCreated = copyTiptapTemplates(cwd, config)\n created.push(...tiptapCreated)\n\n // --- Types ---\n write('types/index.ts', typesIndexTemplate())\n write('types/auth.ts', authTypesTemplate())\n write('types/table-meta.ts', tableMetaTypesTemplate())\n\n // --- Utils ---\n write('utils/cn.ts', cnUtilTemplate())\n write('utils/seo.ts', seoUtilTemplate())\n write('utils/validation.ts', validationUtilTemplate())\n write('utils/webhook.ts', webhookUtilTemplate())\n write('utils/mailchimp.ts', mailchimpUtilTemplate())\n\n // --- Hooks ---\n write('hooks/use-upload.ts', useUploadHookTemplate())\n write('hooks/use-editor-image-upload.ts', useEditorImageUploadHookTemplate())\n write('hooks/use-local-storage.ts', useLocalStorageHookTemplate())\n write('hooks/use-cms-theme.tsx', useCmsThemeTemplate())\n write('hooks/use-users.ts', useUsersHookTemplate())\n write('hooks/use-mobile.ts', useMobileHookTemplate())\n\n // --- Data ---\n const projectName = detectProjectName(cwd)\n write('data/cms.ts', cmsDataTemplate(projectName))\n write('data/navigation.ts', navigationDataTemplate())\n\n // --- Lib ---\n write('lib/r2.ts', r2ClientTemplate())\n write('lib/actions/form-settings.ts', formSettingsActionTemplate())\n write('lib/actions/upload.ts', uploadActionTemplate())\n write('lib/actions/users.ts', usersActionTemplate())\n\n // --- Markdown ---\n write('lib/markdown/render.ts', markdownRenderTemplate())\n write('lib/markdown/format.ts', markdownFormatTemplate())\n write('lib/markdown/cached.ts', markdownCachedTemplate())\n\n // --- Schema metaschema ---\n const schemaCreated = copySchemaMetaschema(cwd, config)\n created.push(...schemaCreated)\n\n return created\n}\n\n/**\n * Copy raw .tsx UI component files from the CLI's templates/ui/ directory.\n */\nfunction copyUiTemplates(cwd: string, config: BetterstartConfig): string[] {\n const created: string[] = []\n const destDir = path.resolve(cwd, config.paths.cms, 'components', 'ui')\n\n // Resolve the templates/ui/ directory relative to the CLI package root.\n // When built, this file is at dist/cli.js, so we go up to the package root.\n const cliRoot = findCliRoot()\n const srcDir = path.join(cliRoot, 'templates', 'ui')\n\n if (!fs.existsSync(srcDir)) {\n return created\n }\n\n const files = fs\n .readdirSync(srcDir)\n .filter((f: string) => f.endsWith('.tsx') || f.endsWith('.ts'))\n\n for (const file of files) {\n const destPath = path.join(destDir, file)\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(path.join(srcDir, file), destPath)\n created.push(path.join(config.paths.cms, 'components', 'ui', file))\n }\n }\n\n return created\n}\n\n/**\n * Recursively copy the TipTap editor directory from templates/tiptap/ → cms/components/ui/tiptap/.\n */\nfunction copyTiptapTemplates(cwd: string, config: BetterstartConfig): string[] {\n const created: string[] = []\n const cliRoot = findCliRoot()\n const srcDir = path.join(cliRoot, 'templates', 'tiptap')\n const destDir = path.resolve(cwd, config.paths.cms, 'components', 'ui', 'tiptap')\n\n if (!fs.existsSync(srcDir)) {\n return created\n }\n\n copyDirRecursive(srcDir, destDir, config.paths.cms, created)\n return created\n}\n\nfunction copyDirRecursive(src: string, dest: string, cmsPrefix: string, created: string[]): void {\n fs.ensureDirSync(dest)\n const entries = fs.readdirSync(src, { withFileTypes: true })\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath, cmsPrefix, created)\n } else if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath)\n // Build relative path from cms root for reporting\n const relFromCms = path.relative(path.resolve(dest, '..', '..', '..', '..'), destPath)\n created.push(relFromCms)\n }\n }\n}\n\n/**\n * Copy schema.json metaschema into cms/schemas/ so users get IDE validation.\n */\nfunction copySchemaMetaschema(cwd: string, config: BetterstartConfig): string[] {\n const created: string[] = []\n const cliRoot = findCliRoot()\n const srcPath = path.join(cliRoot, 'templates', 'schema.json')\n const destPath = path.resolve(cwd, config.paths.schemas, 'schema.json')\n\n if (fs.existsSync(srcPath) && !fs.existsSync(destPath)) {\n fs.ensureDirSync(path.dirname(destPath))\n fs.copyFileSync(srcPath, destPath)\n created.push(path.join(config.paths.schemas, 'schema.json'))\n }\n\n return created\n}\n\n/**\n * Find the CLI package root by looking for package.json with our name.\n */\nfunction findCliRoot(): string {\n // __dirname equivalent for ESM: walk up from this file's location\n let dir = new URL('.', import.meta.url).pathname\n for (let i = 0; i < 5; i++) {\n const pkgPath = path.join(dir, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (pkg.name === '@betterstart/cli') {\n return dir\n }\n } catch {\n // continue\n }\n }\n dir = path.dirname(dir)\n }\n // Fallback: assume 2 levels up from dist/\n return path.resolve(new URL('.', import.meta.url).pathname, '..', '..')\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport type LinterType = 'eslint' | 'biome' | 'none'\n\nexport interface LinterInfo {\n /** Detected linter type */\n type: LinterType\n /** Config file found (if any) */\n configFile: string | null\n}\n\nexport interface ProjectInfo {\n /** Whether this is an existing Next.js project */\n isExisting: boolean\n /** Whether the project uses a src/ directory */\n hasSrcDir: boolean\n /** Whether TypeScript is configured */\n hasTypeScript: boolean\n /** Whether Tailwind CSS is configured */\n hasTailwind: boolean\n /** Detected linter info */\n linter: LinterInfo\n /** Conflicts found that would block init */\n conflicts: string[]\n}\n\nconst NEXT_CONFIG_FILES = ['next.config.ts', 'next.config.js', 'next.config.mjs']\n\nexport function detectProjectName(cwd: string): string {\n const pkgPath = path.join(cwd, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (typeof pkg.name === 'string' && pkg.name.length > 0) {\n return formatProjectName(pkg.name)\n }\n } catch {\n /* ignore */\n }\n }\n return formatProjectName(path.basename(cwd))\n}\n\nfunction formatProjectName(name: string): string {\n const base = name.includes('/') ? name.split('/').pop()! : name\n return base\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, (c) => c.toUpperCase())\n .trim()\n}\n\nexport function detectProject(cwd: string): ProjectInfo {\n const isExisting = NEXT_CONFIG_FILES.some((f) => fs.existsSync(path.join(cwd, f)))\n\n const hasSrcDir = fs.existsSync(path.join(cwd, 'src'))\n\n const hasTypeScript =\n fs.existsSync(path.join(cwd, 'tsconfig.json')) ||\n fs.existsSync(path.join(cwd, 'tsconfig.app.json'))\n\n const hasTailwind = detectTailwind(cwd)\n const linter = detectLinter(cwd)\n\n const conflicts: string[] = []\n if (isExisting) {\n if (fs.existsSync(path.join(cwd, 'cms'))) {\n conflicts.push('cms/ directory already exists')\n }\n if (fs.existsSync(path.join(cwd, 'cms.config.ts'))) {\n conflicts.push('cms.config.ts already exists')\n }\n\n const appBase = hasSrcDir ? 'src/app' : 'app'\n if (fs.existsSync(path.join(cwd, appBase, '(cms)'))) {\n conflicts.push(`${appBase}/(cms)/ route group already exists`)\n }\n\n if (hasTsconfigCmsAliases(cwd)) {\n conflicts.push('@cms/* path aliases already exist in tsconfig.json')\n }\n\n if (hasEnvBetterstartVars(cwd)) {\n conflicts.push('BETTERSTART_* variables already exist in .env.local')\n }\n }\n\n return { isExisting, hasSrcDir, hasTypeScript, hasTailwind, linter, conflicts }\n}\n\n// ============================================================================\n// Linter Detection\n// ============================================================================\n\nconst BIOME_CONFIG_FILES = ['biome.json', 'biome.jsonc']\n\nconst ESLINT_CONFIG_FILES = [\n 'eslint.config.js',\n 'eslint.config.mjs',\n 'eslint.config.cjs',\n 'eslint.config.ts',\n '.eslintrc.json',\n '.eslintrc.js',\n '.eslintrc.cjs',\n '.eslintrc.yml',\n '.eslintrc.yaml',\n '.eslintrc'\n]\n\nexport function detectLinter(cwd: string): LinterInfo {\n // Check for Biome first (preferred)\n for (const f of BIOME_CONFIG_FILES) {\n if (fs.existsSync(path.join(cwd, f))) {\n return { type: 'biome', configFile: f }\n }\n }\n\n // Check for ESLint config files\n for (const f of ESLINT_CONFIG_FILES) {\n if (fs.existsSync(path.join(cwd, f))) {\n return { type: 'eslint', configFile: f }\n }\n }\n\n // Check package.json for eslintConfig field\n const pkgPath = path.join(cwd, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (pkg.eslintConfig) {\n return { type: 'eslint', configFile: 'package.json (eslintConfig)' }\n }\n } catch {\n // ignore parse errors\n }\n }\n\n return { type: 'none', configFile: null }\n}\n\n// ============================================================================\n// Tailwind Detection\n// ============================================================================\n\nfunction detectTailwind(cwd: string): boolean {\n // Tailwind v4: check for CSS files with @import \"tailwindcss\" or @theme\n const cssFiles = ['globals.css', 'app.css', 'index.css'].flatMap((f) => [\n path.join(cwd, 'src', 'app', f),\n path.join(cwd, 'app', f),\n path.join(cwd, 'src', f),\n path.join(cwd, f)\n ])\n\n for (const cssFile of cssFiles) {\n if (fs.existsSync(cssFile)) {\n const content = fs.readFileSync(cssFile, 'utf-8')\n if (\n content.includes('@import \"tailwindcss\"') ||\n content.includes(\"@import 'tailwindcss'\") ||\n content.includes('@theme')\n ) {\n return true\n }\n }\n }\n\n // Also check postcss.config for tailwindcss plugin (v3 style)\n const postcssFiles = ['postcss.config.js', 'postcss.config.mjs', 'postcss.config.cjs']\n for (const f of postcssFiles) {\n if (fs.existsSync(path.join(cwd, f))) {\n const content = fs.readFileSync(path.join(cwd, f), 'utf-8')\n if (content.includes('tailwindcss') || content.includes('@tailwindcss')) {\n return true\n }\n }\n }\n\n return false\n}\n\nfunction hasTsconfigCmsAliases(cwd: string): boolean {\n const tsconfigPath = path.join(cwd, 'tsconfig.json')\n if (!fs.existsSync(tsconfigPath)) return false\n\n try {\n const content = fs.readFileSync(tsconfigPath, 'utf-8')\n return content.includes('@cms/')\n } catch {\n return false\n }\n}\n\nfunction hasEnvBetterstartVars(cwd: string): boolean {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return false\n\n try {\n const content = fs.readFileSync(envPath, 'utf-8')\n return content.includes('BETTERSTART_')\n } catch {\n return false\n }\n}\n","/**\n * Template: cms/cms-globals.css\n * CMS-scoped styles: tokens under .cms-root, @layer cms\n * Does NOT import Tailwind — the host app already does.\n */\nexport function cmsGlobalsCssTemplate(): string {\n return `@import \"tailwindcss\";\n@import \"tw-animate-css\";\n@import \"shadcn/tailwind.css\";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --font-sans: var(--font-sans);\n --font-mono: var(--font-geist-mono);\n --color-sidebar-ring: var(--sidebar-ring);\n --color-sidebar-border: var(--sidebar-border);\n --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);\n --color-sidebar-accent: var(--sidebar-accent);\n --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);\n --color-sidebar-primary: var(--sidebar-primary);\n --color-sidebar-foreground: var(--sidebar-foreground);\n --color-sidebar: var(--sidebar);\n --color-chart-5: var(--chart-5);\n --color-chart-4: var(--chart-4);\n --color-chart-3: var(--chart-3);\n --color-chart-2: var(--chart-2);\n --color-chart-1: var(--chart-1);\n --color-ring: var(--ring);\n --color-input: var(--input);\n --color-border: var(--border);\n --color-destructive: var(--destructive);\n --color-accent-foreground: var(--accent-foreground);\n --color-accent: var(--accent);\n --color-muted-foreground: var(--muted-foreground);\n --color-muted: var(--muted);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-secondary: var(--secondary);\n --color-primary-foreground: var(--primary-foreground);\n --color-primary: var(--primary);\n --color-popover-foreground: var(--popover-foreground);\n --color-popover: var(--popover);\n --color-card-foreground: var(--card-foreground);\n --color-card: var(--card);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n --radius-2xl: calc(var(--radius) + 8px);\n --radius-3xl: calc(var(--radius) + 12px);\n --radius-4xl: calc(var(--radius) + 16px);\n}\n\n:root {\n --background: oklch(1 0 0);\n --foreground: oklch(0.141 0.005 285.823);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.141 0.005 285.823);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.141 0.005 285.823);\n --primary: oklch(0.21 0.006 285.885);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.967 0.001 286.375);\n --secondary-foreground: oklch(0.21 0.006 285.885);\n --muted: oklch(0.967 0.001 286.375);\n --muted-foreground: oklch(0.552 0.016 285.938);\n --accent: oklch(0.967 0.001 286.375);\n --accent-foreground: oklch(0.21 0.006 285.885);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.92 0.004 286.32);\n --input: oklch(0.92 0.004 286.32);\n --ring: oklch(0.705 0.015 286.067);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n --radius: 0.625rem;\n --sidebar: oklch(0.985 0 0);\n --sidebar-foreground: oklch(0.141 0.005 285.823);\n --sidebar-primary: oklch(0.21 0.006 285.885);\n --sidebar-primary-foreground: oklch(0.985 0 0);\n --sidebar-accent: oklch(0.967 0.001 286.375);\n --sidebar-accent-foreground: oklch(0.21 0.006 285.885);\n --sidebar-border: oklch(0.92 0.004 286.32);\n --sidebar-ring: oklch(0.705 0.015 286.067);\n}\n\n.dark {\n --background: oklch(0.141 0.005 285.823);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.21 0.006 285.885);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.21 0.006 285.885);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.92 0.004 286.32);\n --primary-foreground: oklch(0.21 0.006 285.885);\n --secondary: oklch(0.274 0.006 286.033);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.274 0.006 286.033);\n --muted-foreground: oklch(0.705 0.015 286.067);\n --accent: oklch(0.274 0.006 286.033);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.552 0.016 285.938);\n --chart-1: oklch(0.488 0.243 264.376);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n --sidebar: oklch(0.21 0.006 285.885);\n --sidebar-foreground: oklch(0.985 0 0);\n --sidebar-primary: oklch(0.488 0.243 264.376);\n --sidebar-primary-foreground: oklch(0.985 0 0);\n --sidebar-accent: oklch(0.274 0.006 286.033);\n --sidebar-accent-foreground: oklch(0.985 0 0);\n --sidebar-border: oklch(1 0 0 / 10%);\n --sidebar-ring: oklch(0.552 0.016 285.938);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground;\n }\n}\n\n/* Editor styles */\n.cms-root .tiptap {\n outline: none;\n}\n\n.cms-root .tiptap p.is-editor-empty:first-child::before {\n color: var(--muted-foreground);\n content: attr(data-placeholder);\n float: left;\n height: 0;\n pointer-events: none;\n}\n\n/* Date picker overrides */\n.cms-root .rdp {\n --rdp-accent-color: var(--primary);\n}\n\n/* Toast overrides */\n.cms-root [data-sonner-toaster] {\n font-family: inherit;\n}\n`\n}\n","/**\n * Template: cms/components/data-table/data-table.tsx\n * Generic reusable data table built on TanStack Table\n */\nexport function dataTableTemplate(): string {\n return `'use client'\n\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@cms/components/ui/table'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport { DataTablePagination } from './data-table-pagination'\n\ninterface DataTableProps<TData, TValue> {\n columns: ColumnDef<TData, TValue>[]\n data: TData[]\n isPending?: boolean\n error?: Error | null\n emptyMessage?: string\n loadingMessage?: string\n selectedIds?: number[]\n onSelectedIdsChange?: (ids: number[]) => void\n meta?: Record<string, unknown>\n getId?: (row: TData) => number\n}\n\nexport function DataTable<TData, TValue>({\n columns,\n data,\n isPending = false,\n error = null,\n emptyMessage = 'No results found.',\n loadingMessage = 'Loading...',\n selectedIds,\n onSelectedIdsChange,\n meta,\n getId = (row) => (row as { id: number }).id,\n}: DataTableProps<TData, TValue>) {\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0))\n const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(20))\n\n const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize\n\n // Convert selectedIds to rowSelection object\n const rowSelection = React.useMemo(() => {\n if (!selectedIds) return {}\n const selection: Record<string, boolean> = {}\n data.forEach((row, index) => {\n if (selectedIds.includes(getId(row))) {\n selection[index.toString()] = true\n }\n })\n return selection\n }, [selectedIds, data, getId])\n\n const handleRowSelectionChange = React.useCallback(\n (\n updater:\n | Record<string, boolean>\n | ((old: Record<string, boolean>) => Record<string, boolean>),\n ) => {\n if (!onSelectedIdsChange) return\n const newSelection = typeof updater === 'function' ? updater(rowSelection) : updater\n const newIds = Object.keys(newSelection)\n .filter((key) => newSelection[key])\n .map((key) => getId(data[Number.parseInt(key, 10)]))\n .filter(Boolean)\n onSelectedIdsChange(newIds)\n },\n [data, rowSelection, onSelectedIdsChange, getId],\n )\n\n const handlePaginationChange = React.useCallback(\n (\n updater:\n | { pageIndex: number; pageSize: number }\n | ((old: { pageIndex: number; pageSize: number }) => {\n pageIndex: number\n pageSize: number\n }),\n ) => {\n const current = { pageIndex, pageSize: effectivePageSize }\n const next = typeof updater === 'function' ? updater(current) : updater\n React.startTransition(() => {\n setPageIndex(next.pageIndex)\n })\n },\n [pageIndex, effectivePageSize, setPageIndex],\n )\n\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n onRowSelectionChange: selectedIds ? handleRowSelectionChange : undefined,\n onPaginationChange: handlePaginationChange,\n meta,\n state: {\n sorting,\n columnFilters,\n columnVisibility,\n rowSelection,\n pagination: {\n pageIndex,\n pageSize: effectivePageSize,\n },\n },\n })\n\n return (\n <div className=\"space-y-6\">\n <div className=\"bg-card border overflow-hidden rounded-lg corner-squircle\">\n <Table>\n <TableHeader className=\"bg-secondary\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-muted-foreground\">{loadingMessage}</div>\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-destructive\">Error: {error.message}</div>\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n {emptyMessage}\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n <DataTablePagination table={table} pageSize={pageSize} setPageSize={setPageSize} />\n </div>\n )\n}\n\nexport type { DataTableProps }\n`\n}\n","/**\n * Template: cms/components/data-table/data-table-pagination.tsx\n * Pagination controls for data tables\n */\nexport function dataTablePaginationTemplate(): string {\n return `'use client'\n\nimport { Button } from '@cms/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\nimport type { Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nconst PAGE_SIZE_OPTIONS = [\n { value: '10', label: '10' },\n { value: '20', label: '20' },\n { value: '50', label: '50' },\n { value: '100', label: '100' },\n { value: 'all', label: 'All' },\n]\n\ninterface DataTablePaginationProps<TData> {\n table: Table<TData>\n pageSize: number\n setPageSize: (value: number | null) => void\n}\n\nexport function DataTablePagination<TData>({\n table,\n pageSize,\n setPageSize,\n}: DataTablePaginationProps<TData>) {\n const handlePageSizeChange = React.useCallback(\n (value: string) => {\n React.startTransition(() => {\n if (value === 'all') {\n setPageSize(-1)\n } else {\n setPageSize(Number(value))\n }\n table.setPageIndex(0)\n })\n },\n [setPageSize, table],\n )\n\n return (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Rows per page</span>\n <Select\n value={pageSize === -1 ? 'all' : String(pageSize)}\n onValueChange={handlePageSizeChange}\n >\n <SelectTrigger className=\"w-[100px] h-8\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PAGE_SIZE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center space-x-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n >\n Previous\n </Button>\n <div className=\"text-sm text-muted-foreground\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount() || 1}\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n >\n Next\n </Button>\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Template: cms/components/data-table/data-table-toolbar.tsx\n * Reusable toolbar with search, reorder controls, and action slots\n */\nexport function dataTableToolbarTemplate(): string {\n return `'use client'\n\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport { ArrowUpDown, Save, Search } from 'lucide-react'\nimport type * as React from 'react'\nimport { useFormStatus } from 'react-dom'\n\nfunction SearchButton() {\n const { pending } = useFormStatus()\n return (\n <Button type=\"submit\" variant=\"outline\" size=\"default\" disabled={pending}>\n {pending ? 'Searching...' : 'Search'}\n </Button>\n )\n}\n\ninterface DataTableToolbarProps {\n search: string\n onSearch: (formData: FormData) => void\n searchPlaceholder?: string\n children?: React.ReactNode\n}\n\nexport function DataTableToolbar({\n search,\n onSearch,\n searchPlaceholder = 'Search...',\n children,\n}: DataTableToolbarProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <form action={onSearch} className=\"flex items-center gap-2\">\n <div className=\"relative\">\n <Search className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\" />\n <Input\n key={search}\n name=\"search\"\n placeholder={searchPlaceholder}\n defaultValue={search}\n className=\"w-64 pl-9\"\n />\n </div>\n <SearchButton />\n </form>\n {children}\n </div>\n )\n}\n\ninterface ReorderControlsProps {\n reorderMode: boolean\n onToggle: () => void\n onSave: () => void\n onCancel: () => void\n hasChanges: boolean\n isSaving: boolean\n}\n\nexport function ReorderControls({\n reorderMode,\n onToggle,\n onSave,\n onCancel,\n hasChanges,\n isSaving,\n}: ReorderControlsProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant={reorderMode ? 'default' : 'outline'}\n size=\"sm\"\n onClick={onToggle}\n disabled={isSaving}\n >\n <ArrowUpDown className=\"size-4 mr-1\" />\n Sort Order\n </Button>\n {reorderMode && (\n <>\n <Button variant=\"default\" size=\"sm\" onClick={onSave} disabled={!hasChanges || isSaving}>\n <Save className=\"size-4 mr-1\" />\n {isSaving ? 'Saving...' : 'Save'}\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={onCancel} disabled={isSaving}>\n Cancel\n </Button>\n {hasChanges && <span className=\"text-sm text-muted-foreground\">Unsaved changes</span>}\n </>\n )}\n </div>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-header.tsx\n * CMS admin header with theme toggle\n */\nexport function cmsHeaderTemplate(): string {\n return `'use client'\n\nimport { Button } from '@cms/components/ui/button'\nimport { SidebarTrigger, useSidebar } from '@cms/components/ui/sidebar'\nimport { useTheme } from '@cms/hooks/use-cms-theme'\nimport { Moon, Sun } from 'lucide-react'\n\nexport function CmsHeader() {\n const { theme, setTheme } = useTheme()\n const { state } = useSidebar()\n\n return (\n <header className=\"flex h-14 shrink-0 items-center gap-2 border-b border-border w-full sticky top-0 z-50\">\n <div className=\"flex items-center px-5 gap-1 flex-1 w-full justify-between\">\n <div className=\"flex items-center gap-2 w-full\">\n {state === 'collapsed' && <SidebarTrigger />}\n </div>\n <div className=\"flex items-center gap-2 ml-auto\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}\n >\n <Sun className=\"size-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n <Moon className=\"absolute size-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n <span className=\"sr-only\">Toggle theme</span>\n </Button>\n </div>\n </div>\n </header>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-nav-link.tsx\n * Client component for sidebar nav links with active state detection\n */\nexport function cmsNavLinkTemplate(): string {\n return `'use client'\n\nimport { SidebarMenuButton } from '@cms/components/ui/sidebar'\nimport Link from 'next/link'\nimport { usePathname } from 'next/navigation'\n\nexport function CmsNavLink({\n href,\n children,\n}: {\n href: string\n children: React.ReactNode\n}) {\n const pathname = usePathname()\n const isActive =\n href === '/cms'\n ? pathname === '/cms'\n : pathname === href || pathname.startsWith(href + '/')\n\n return (\n <SidebarMenuButton asChild isActive={isActive}>\n <Link href={href}>{children}</Link>\n </SidebarMenuButton>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-providers.tsx\n * CMS-scoped providers: QueryClient, CmsThemeProvider, Toaster, NuqsAdapter\n */\nexport function cmsProvidersTemplate(): string {\n return `'use client'\n\nimport { Toaster } from '@cms/components/ui/sonner'\nimport { CmsThemeProvider } from '@cms/hooks/use-cms-theme'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { NuqsAdapter } from 'nuqs/adapters/next/app'\nimport { useState } from 'react'\n\nexport function CmsProviders({ children }: { children: React.ReactNode }) {\n const [queryClient] = useState(\n () =>\n new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n refetchOnReconnect: false,\n },\n },\n }),\n )\n\n return (\n <QueryClientProvider client={queryClient}>\n <CmsThemeProvider>\n <NuqsAdapter>\n {children}\n <Toaster position=\"top-right\" richColors />\n </NuqsAdapter>\n </CmsThemeProvider>\n </QueryClientProvider>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-search.tsx\n * CMS admin search on header\n */\nexport function cmsSearchTemplate(): string {\n return `import { Button } from '@cms/components/ui/button'\nimport { Command, Search } from 'lucide-react'\n\nexport const CmsSearch = () => {\n return (\n <div className=\"flex items-center gap-2 relative w-full max-w-[240px]\">\n <Button\n variant=\"outline\"\n className=\"w-full text-left items-center pr-1.5! py-0 rounded-lg bg-white\"\n size=\"lg\"\n >\n <Search className=\"shrink-0 size-3.5 -ml-0.5 text-muted-foreground/70\" />\n <span className=\"w-full font-normal text-sm text-muted-foreground/70 [text-box-trim:trim-both]\">\n Quick search...\n </span>\n <div className=\"flex items-center gap-1 py-0.5 border rounded-full corner-squircle px-2 border-border bg-background\">\n <Command className=\"size-3! text-muted-foreground\" />\n <span className=\"font-mono text-xs font-medium\">K</span>\n </div>\n </Button>\n </div>\n )\n}\n\nCmsSearch.displayName = 'CmsSearch'\n`\n}\n","/**\n * Template: cms/components/layout/cms-sidebar.tsx\n * CMS admin sidebar with grouped navigation\n */\nexport function cmsSidebarTemplate(): string {\n return `import { getSession } from '@cms/auth/middleware'\nimport { Avatar, AvatarFallback, AvatarImage } from '@cms/components/ui/avatar'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuItem,\n} from '@cms/components/ui/sidebar'\nimport { cms } from '@cms/data/cms'\nimport { type CmsNavigationItem, cmsNavigation } from '@cms/data/navigation'\nimport { Settings, Users } from 'lucide-react'\nimport Link from 'next/link'\nimport { Fragment } from 'react'\nimport { getSetting } from '@/cms/lib/actions/settings'\nimport { CmsNavLink } from './cms-nav-link'\nimport { CmsSearch } from './cms-search'\n\nfunction groupNavItems(items: CmsNavigationItem[]) {\n const groups: { label: string | null; items: CmsNavigationItem[] }[] = []\n const groupMap = new Map<string | null, CmsNavigationItem[]>()\n\n for (const item of items) {\n const key = item.group ?? null\n if (!groupMap.has(key)) {\n const arr: CmsNavigationItem[] = []\n groupMap.set(key, arr)\n groups.push({ label: key, items: arr })\n }\n groupMap.get(key)!.push(item)\n }\n\n return groups\n}\n\nexport async function CmsSidebar(props: React.ComponentProps<typeof Sidebar>) {\n const session = await getSession()\n const settings = await getSetting()\n const user = session?.user ?? null\n const groups = groupNavItems(cmsNavigation)\n\n return (\n <Sidebar collapsible=\"icon\" {...props}>\n <SidebarHeader className=\"border-b border-border h-14 items-center flex w-full\">\n <div className=\"flex items-center gap-2 w-full relative h-full\">\n <Link href=\"/cms\" className=\"flex items-center gap-2 w-full\">\n <Avatar className=\"size-8\">\n <AvatarImage src={'/favicon.ico'} />\n <AvatarFallback className=\"text-sm font-semibold text-foreground\">\n {settings?.siteName?.charAt(0) ?? cms.name?.charAt(0)}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex text-foreground items-center gap-1 w-full group-data-[collapsible=icon]:hidden\">\n <span className=\"text-sm font-medium line-clamp-1\">\n {settings?.siteName ?? cms.name}\n </span>\n </div>\n </Link>\n </div>\n </SidebarHeader>\n <SidebarContent>\n <SidebarGroup className=\"pb-1\">\n <CmsSearch />\n </SidebarGroup>\n\n {groups.map((group) => (\n <Fragment key={group.label ?? '_ungrouped'}>\n <SidebarGroup>\n {group.label && <SidebarGroupLabel>{group.label}</SidebarGroupLabel>}\n <SidebarMenu>\n {group.items.map((item) => (\n <SidebarMenuItem key={item.href}>\n <CmsNavLink href={item.href}>\n {item.icon && (\n <item.icon className=\"text-muted-foreground\" absoluteStrokeWidth />\n )}\n <span>{item.label}</span>\n </CmsNavLink>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroup>\n </Fragment>\n ))}\n\n <SidebarGroup className=\"mt-auto\">\n <SidebarMenu>\n <SidebarMenuItem>\n <CmsNavLink href=\"/cms/users\">\n <Users />\n <span>Users</span>\n </CmsNavLink>\n </SidebarMenuItem>\n <SidebarMenuItem>\n <CmsNavLink href=\"/cms/settings\">\n <Settings />\n <span>Settings</span>\n </CmsNavLink>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarGroup>\n </SidebarContent>\n <SidebarFooter>\n {user && (\n <div className=\"flex items-center gap-2 p-2 text-sm\">\n <div className=\"flex-1 truncate\">\n <p className=\"font-medium truncate\">{user.name}</p>\n <p className=\"text-muted-foreground truncate text-xs\">{user.email}</p>\n </div>\n </div>\n )}\n </SidebarFooter>\n </Sidebar>\n )\n}\n`\n}\n","/**\n * Template: cms/components/shared/delete-dialog.tsx\n * Reusable confirmation dialog for delete actions\n */\nexport function deleteDialogTemplate(): string {\n return `'use client'\n\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { Button } from '@cms/components/ui/button'\nimport { Trash2 } from 'lucide-react'\n\ninterface DeleteDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n isPending?: boolean\n title?: string\n description?: string\n trigger?: React.ReactNode\n}\n\nexport function DeleteDialog({\n open,\n onOpenChange,\n onConfirm,\n isPending = false,\n title = 'Are you sure?',\n description = 'This action cannot be undone. This will permanently delete this item.',\n trigger,\n}: DeleteDialogProps) {\n return (\n <AlertDialog open={open} onOpenChange={onOpenChange}>\n {trigger && <AlertDialogTrigger asChild>{trigger}</AlertDialogTrigger>}\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{title}</AlertDialogTitle>\n <AlertDialogDescription>{description}</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n onConfirm()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n\ninterface DeleteButtonProps {\n onClick: () => void\n label?: string\n count?: number\n}\n\nexport function DeleteButton({ onClick, label = 'item', count }: DeleteButtonProps) {\n return (\n <Button variant=\"destructive\" size=\"default\" onClick={onClick}>\n <Trash2 className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Delete {count !== undefined ? \\`\\${count} \\${count === 1 ? label : \\`\\${label}s\\`}\\` : label}\n </Button>\n )\n}\n`\n}\n","/**\n * Template: cms/components/shared/page-header.tsx\n * Simple page header with title and description\n */\nexport function pageHeaderTemplate(): string {\n return `interface PageHeaderProps {\n title: string\n children?: React.ReactNode\n search?: React.ReactNode\n actions?: React.ReactNode\n back?: React.ReactNode\n}\n\nexport function PageHeader({ title, children, search, actions, back }: PageHeaderProps) {\n return (\n <div className=\"grid grid-cols-3 items-center justify-between w-full h-14 px-4 border-b border-border\">\n <div className=\"flex items-center justify-start gap-2 w-full\">{back && back}</div>\n <div className=\"flex items-center justify-center gap-2\">\n <h2 className=\"text-sm font-medium tracking-tight\">{title}</h2>\n </div>\n <div className=\"flex items-center justify-end gap-2\">\n {children && children}\n {search && search}\n {actions && actions}\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Template: cms/components/shared/status-badge.tsx\n * Status badge component for displaying entity states in tables\n */\nexport function statusBadgeTemplate(): string {\n return `import { Badge, type BadgeProps } from '@cms/components/ui/badge'\nimport { cn } from '@cms/utils/cn'\n\ntype StatusVariant = 'default' | 'success' | 'warning' | 'error' | 'info'\n\nconst statusStyles: Record<StatusVariant, string> = {\n default: 'bg-secondary text-secondary-foreground',\n success: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950 dark:text-emerald-300',\n warning: 'bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-300',\n error: 'bg-red-100 text-red-800 dark:bg-red-950 dark:text-red-300',\n info: 'bg-blue-100 text-blue-800 dark:bg-blue-950 dark:text-blue-300',\n}\n\ninterface StatusBadgeProps extends Omit<BadgeProps, 'variant'> {\n status: StatusVariant\n}\n\nexport function StatusBadge({ status, className, ...props }: StatusBadgeProps) {\n return (\n <Badge\n variant=\"outline\"\n className={cn('border-none font-medium', statusStyles[status], className)}\n {...props}\n />\n )\n}\n\n/** Map boolean values to status badges */\nexport function BooleanBadge({\n value,\n trueLabel = 'Yes',\n falseLabel = 'No',\n}: {\n value: boolean\n trueLabel?: string\n falseLabel?: string\n}) {\n return (\n <StatusBadge status={value ? 'success' : 'default'}>\n {value ? trueLabel : falseLabel}\n </StatusBadge>\n )\n}\n`\n}\n","/**\n * Template: cms/data/cms.ts\n * CMS metadata (project name, etc.)\n */\nexport function cmsDataTemplate(projectName: string): string {\n return `export const cms = {\n name: '${projectName}',\n}\n`\n}\n","/**\n * Template: cms/data/navigation.ts\n * CMS sidebar navigation entries — codegen appends to this file\n */\nexport function navigationDataTemplate(): string {\n return `import type { LucideIcon } from 'lucide-react'\nimport { ChartSpline, FileText, House, ImagePlay, Tag } from 'lucide-react'\n\nexport interface CmsNavigationItem {\n label: string\n href: string\n icon?: LucideIcon\n group?: string\n}\n\nexport const cmsNavigation: CmsNavigationItem[] = [\n {\n label: 'Overview',\n href: '/cms',\n icon: House,\n },\n {\n label: 'Analytics',\n href: '/cms/analytics',\n icon: ChartSpline,\n },\n {\n label: 'Media',\n href: '/cms/media',\n icon: ImagePlay,\n },\n {\n label: 'Categories',\n href: '/cms/categories',\n icon: Tag,\n group: 'Blog',\n },\n {\n label: 'Posts',\n href: '/cms/posts',\n icon: FileText,\n group: 'Blog',\n },\n]\n`\n}\n","/**\n * Template: cms/hooks/use-cms-theme.tsx\n * Self-contained CMS theme provider that scopes to .cms-root\n * Replaces next-themes to avoid hydration mismatches on <html>\n */\nexport function useCmsThemeTemplate(): string {\n return `'use client'\n\nimport * as React from 'react'\n\ntype Theme = 'light' | 'dark' | 'system'\n\ninterface ThemeContext {\n theme: Theme\n setTheme: (theme: Theme) => void\n resolvedTheme: 'light' | 'dark'\n}\n\nconst CmsThemeContext = React.createContext<ThemeContext | undefined>(undefined)\n\nconst STORAGE_KEY = 'cms-theme'\n\nfunction getSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light'\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nexport function CmsThemeProvider({ children }: { children: React.ReactNode }) {\n const [theme, setThemeState] = React.useState<Theme>('system')\n const [resolved, setResolved] = React.useState<'light' | 'dark'>('light')\n\n // Read from localStorage on mount\n React.useEffect(() => {\n const stored = localStorage.getItem(STORAGE_KEY) as Theme | null\n if (stored && ['light', 'dark', 'system'].includes(stored)) {\n setThemeState(stored)\n }\n }, [])\n\n // Resolve theme and apply .dark class to .cms-root\n React.useEffect(() => {\n const actual = theme === 'system' ? getSystemTheme() : theme\n setResolved(actual)\n\n const root = document.querySelector('.cms-root')\n if (root) {\n root.classList.toggle('dark', actual === 'dark')\n }\n }, [theme])\n\n // Listen for system theme changes\n React.useEffect(() => {\n if (theme !== 'system') return\n const mq = window.matchMedia('(prefers-color-scheme: dark)')\n const handler = () => {\n const actual = getSystemTheme()\n setResolved(actual)\n const root = document.querySelector('.cms-root')\n if (root) {\n root.classList.toggle('dark', actual === 'dark')\n }\n }\n mq.addEventListener('change', handler)\n return () => mq.removeEventListener('change', handler)\n }, [theme])\n\n const setTheme = React.useCallback((t: Theme) => {\n setThemeState(t)\n localStorage.setItem(STORAGE_KEY, t)\n }, [])\n\n const value = React.useMemo(\n () => ({ theme, setTheme, resolvedTheme: resolved }),\n [theme, setTheme, resolved],\n )\n\n return <CmsThemeContext.Provider value={value}>{children}</CmsThemeContext.Provider>\n}\n\nexport function useTheme(): ThemeContext {\n const ctx = React.useContext(CmsThemeContext)\n if (!ctx) throw new Error('useTheme must be used within CmsThemeProvider')\n return ctx\n}\n`\n}\n","/**\n * Template: cms/hooks/use-editor-image-upload.ts\n * Image upload hook for markdown editor (drag-drop, paste, file picker)\n */\nexport function useEditorImageUploadHookTemplate(): string {\n return `'use client'\n\nimport * as React from 'react'\nimport { useUpload } from './use-upload'\n\nexport interface EditorImageUploadResult {\n url: string\n filename: string\n}\n\nexport interface UseEditorImageUploadOptions {\n onImagesUploaded: (images: EditorImageUploadResult[]) => void\n}\n\nexport function useEditorImageUpload({ onImagesUploaded }: UseEditorImageUploadOptions) {\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n const onImagesUploadedRef = React.useRef(onImagesUploaded)\n onImagesUploadedRef.current = onImagesUploaded\n\n const { upload, progress, mutation } = useUpload({\n accept: 'image/*',\n maxSizeInMB: 10,\n prefix: 'images',\n onSuccess: (result) => {\n if (result.success && result.files) {\n const images: EditorImageUploadResult[] = result.files.map((f) => ({\n url: f.url,\n filename: f.filename,\n }))\n onImagesUploadedRef.current(images)\n }\n },\n })\n\n const isUploading = mutation.isPending\n\n const uploadImages = React.useCallback(\n (files: File[]) => {\n const imageFiles = files.filter((f) => f.type.startsWith('image/'))\n if (imageFiles.length === 0) return\n upload(imageFiles, 'images')\n },\n [upload],\n )\n\n const handleDrop = React.useCallback(\n (e: React.DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n const files = Array.from(e.dataTransfer.files).filter((f) => f.type.startsWith('image/'))\n if (files.length > 0) {\n uploadImages(files)\n }\n },\n [uploadImages],\n )\n\n const openFilePicker = React.useCallback(() => {\n fileInputRef.current?.click()\n }, [])\n\n const handleFileInputChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || [])\n if (files.length > 0) {\n uploadImages(files)\n }\n e.target.value = ''\n },\n [uploadImages],\n )\n\n return {\n uploadImages,\n isUploading,\n progress,\n handleDrop,\n openFilePicker,\n fileInputRef,\n handleFileInputChange,\n }\n}\n`\n}\n","/**\n * Template: cms/hooks/use-local-storage.ts\n * Type-safe localStorage hook with cms- prefix\n */\nexport function useLocalStorageHookTemplate(): string {\n return `import * as React from 'react'\n\nconst CMS_STORAGE_PREFIX = 'cms-'\n\n/** Type-safe wrapper for localStorage operations with cms- prefix. */\nexport function useLocalStorage<T>(key: string) {\n const prefixedKey = CMS_STORAGE_PREFIX + key\n\n const setItem = React.useCallback(\n (value: T) => {\n try {\n localStorage.setItem(prefixedKey, JSON.stringify(value))\n } catch {\n // Silent failure for localStorage access errors\n }\n },\n [prefixedKey],\n )\n\n const getItem = React.useCallback((): T | null => {\n try {\n const stored = localStorage.getItem(prefixedKey)\n return stored ? JSON.parse(stored) : null\n } catch {\n return null\n }\n }, [prefixedKey])\n\n const removeItem = React.useCallback(() => {\n try {\n localStorage.removeItem(prefixedKey)\n } catch {\n // Silent failure for localStorage access errors\n }\n }, [prefixedKey])\n\n const hasItem = React.useCallback((): boolean => {\n try {\n return localStorage.getItem(prefixedKey) !== null\n } catch {\n return false\n }\n }, [prefixedKey])\n\n return { setItem, getItem, removeItem, hasItem }\n}\n`\n}\n","/**\n * Template: cms/hooks/use-mobile.ts\n * Hook to detect mobile viewport using matchMedia\n */\nexport function useMobileHookTemplate(): string {\n return `import * as React from 'react'\n\nconst MOBILE_BREAKPOINT = 768\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)\n\n React.useEffect(() => {\n const mql = window.matchMedia(\\`(max-width: \\${MOBILE_BREAKPOINT - 1}px)\\`)\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n }\n mql.addEventListener('change', onChange)\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n return !!isMobile\n}\n`\n}\n","/**\n * Template: cms/hooks/use-upload.ts\n * File upload hook with validation and progress tracking\n */\nexport function useUploadHookTemplate(): string {\n return `'use client'\n\nimport type { UploadFileResult, UploadProgress } from '@cms/types'\nimport { type FileValidationConfig, validateFiles } from '@cms/utils/validation'\nimport { type UseMutationResult, useMutation } from '@tanstack/react-query'\nimport * as React from 'react'\n\nexport interface UseUploadOptions {\n /** File validation configuration */\n validationConfig?: FileValidationConfig\n /** Accept string (e.g., \"image/*\") */\n accept?: string\n /** Maximum file size in MB */\n maxSizeInMB?: number\n /** Callback fired when upload progress changes */\n onProgress?: (progress: UploadProgress[]) => void\n /** Callback fired when upload succeeds */\n onSuccess?: (result: UploadFileResult) => void\n /** Callback fired when upload fails */\n onError?: (error: Error) => void\n /** Optional prefix for file paths in R2 */\n prefix?: string\n}\n\nexport interface UploadMutationVariables {\n files: File[]\n prefix?: string\n}\n\nexport interface UseUploadReturn {\n mutation: UseMutationResult<UploadFileResult, Error, UploadMutationVariables, unknown>\n progress: UploadProgress[]\n upload: (files: File[], prefix?: string) => void\n validate: (files: File[]) => { valid: boolean; errors: string[] }\n}\n\nfunction parseAcceptTypes(accept: string): string[] {\n return accept\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n}\n\nexport function useUpload(options: UseUploadOptions = {}): UseUploadReturn {\n const {\n validationConfig: providedConfig,\n accept,\n maxSizeInMB,\n onProgress,\n onSuccess,\n onError,\n prefix: defaultPrefix,\n } = options\n\n const validationConfig = React.useMemo<FileValidationConfig>(() => {\n const config: FileValidationConfig = { ...providedConfig }\n\n if (accept) {\n const parsedTypes = parseAcceptTypes(accept)\n if (config.allowedTypes && config.allowedTypes.length > 0) {\n config.allowedTypes = [...config.allowedTypes, ...parsedTypes].filter(\n (v, i, a) => a.indexOf(v) === i,\n )\n } else {\n config.allowedTypes = parsedTypes\n }\n }\n\n if (maxSizeInMB !== undefined) {\n config.maxSizeInBytes = maxSizeInMB * 1024 * 1024\n }\n\n return config\n }, [providedConfig, accept, maxSizeInMB])\n\n const [progress, setProgress] = React.useState<UploadProgress[]>([])\n const [_isPending, startTransition] = React.useTransition()\n\n const mutation = useMutation<UploadFileResult, Error, UploadMutationVariables>({\n mutationFn: async ({ files, prefix = defaultPrefix }) => {\n const initialProgress: UploadProgress[] = files.map((file) => ({\n filename: file.name,\n progress: 0,\n loaded: 0,\n total: file.size,\n }))\n setProgress(initialProgress)\n onProgress?.(initialProgress)\n\n const formData = new FormData()\n if (prefix) {\n formData.append('prefix', prefix)\n }\n\n files.forEach((file, index) => {\n formData.append(\\`file\\${index}\\`, file)\n })\n\n // Simulate progress since server doesn't support streaming\n const progressInterval = setInterval(() => {\n setProgress((prev) =>\n prev.map((p) => {\n const newProgress = Math.min(p.progress + 10, 90)\n return {\n ...p,\n progress: newProgress,\n loaded: Math.floor((p.total * newProgress) / 100),\n }\n }),\n )\n }, 200)\n\n try {\n if (validationConfig?.maxSizeInBytes) {\n formData.append('maxSizeInBytes', validationConfig.maxSizeInBytes.toString())\n }\n if (validationConfig?.allowedTypes?.length) {\n formData.append('allowedTypes', validationConfig.allowedTypes.join(','))\n }\n\n const response = await fetch('/api/cms/upload', {\n method: 'POST',\n body: formData,\n })\n\n const result = (await response.json()) as UploadFileResult\n\n if (result.success) {\n const completeProgress: UploadProgress[] = files.map((file) => ({\n filename: file.name,\n progress: 100,\n loaded: file.size,\n total: file.size,\n }))\n setProgress(completeProgress)\n onProgress?.(completeProgress)\n }\n\n return result\n } finally {\n clearInterval(progressInterval)\n }\n },\n onSuccess: (result) => {\n onSuccess?.(result)\n startTransition(() => {\n setTimeout(() => {\n setProgress([])\n }, 2000)\n })\n },\n onError: (error) => {\n onError?.(error)\n setProgress([])\n },\n })\n\n const upload = React.useCallback(\n (files: File[], prefix?: string) => {\n mutation.mutate({ files, prefix })\n },\n [mutation],\n )\n\n const validate = React.useCallback(\n (files: File[]) => {\n const result = validateFiles(files, validationConfig)\n return {\n valid: result.valid,\n errors: result.errors.map((e) => \\`\\${e.filename}: \\${e.error}\\`),\n }\n },\n [validationConfig],\n )\n\n return { mutation, progress, upload, validate }\n}\n`\n}\n","/**\n * Template: cms/hooks/use-users.ts\n * React Query hook for fetching users\n */\nexport function useUsersHookTemplate(): string {\n return `'use client'\n\nimport { getUsers } from '@cms/actions/users'\nimport type { UsersResponse } from '@cms/types/auth'\nimport { useQuery } from '@tanstack/react-query'\n\nexport function useUsers() {\n return useQuery<UsersResponse>({\n queryKey: ['users'],\n queryFn: () => getUsers(),\n staleTime: 0,\n })\n}\n`\n}\n","/**\n * Template: cms/lib/actions/form-settings.ts\n * Form settings actions — CRUD for per-form webhook/notification configuration\n */\nexport function formSettingsActionTemplate(): string {\n return `'use server'\n\nimport db from '@cms/db'\nimport { formSettings } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\n\nexport interface FormSettingsData {\n id: number\n formName: string\n webhookUrl: string | null\n webhookEnabled: boolean\n notificationEmails: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface UpsertFormSettingsInput {\n webhookUrl?: string | null\n webhookEnabled?: boolean\n notificationEmails?: string | null\n}\n\nexport interface FormSettingsResult {\n success: boolean\n error?: string\n settings?: FormSettingsData\n}\n\nexport async function getFormSettings(formName: string): Promise<FormSettingsData | null> {\n try {\n const [settings] = await db\n .select()\n .from(formSettings)\n .where(eq(formSettings.formName, formName))\n .limit(1)\n return (settings as FormSettingsData) ?? null\n } catch (error) {\n console.error(\\`Error fetching form settings for \\${formName}:\\`, error)\n return null\n }\n}\n\nexport async function upsertFormSettings(\n formName: string,\n data: UpsertFormSettingsInput,\n): Promise<FormSettingsResult> {\n try {\n const existing = await getFormSettings(formName)\n\n if (existing) {\n const [updated] = await db\n .update(formSettings)\n .set({\n ...data,\n updatedAt: new Date().toISOString(),\n })\n .where(eq(formSettings.formName, formName))\n .returning()\n return { success: true, settings: updated as FormSettingsData }\n }\n\n const [created] = await db\n .insert(formSettings)\n .values({\n formName,\n webhookUrl: data.webhookUrl ?? null,\n webhookEnabled: data.webhookEnabled ?? false,\n notificationEmails: data.notificationEmails ?? null,\n })\n .returning()\n return { success: true, settings: created as FormSettingsData }\n } catch (error) {\n console.error(\\`Error upserting form settings for \\${formName}:\\`, error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to save form settings',\n }\n }\n}\n\nexport async function getAllFormSettings(): Promise<FormSettingsData[]> {\n try {\n const settings = await db.select().from(formSettings)\n return settings as FormSettingsData[]\n } catch (error) {\n console.error('Error fetching all form settings:', error)\n return []\n }\n}\n\nexport async function testFormWebhook(\n formName: string,\n): Promise<{ success: boolean; error?: string }> {\n try {\n const settings = await getFormSettings(formName)\n if (!settings?.webhookUrl) {\n return { success: false, error: 'No webhook URL configured' }\n }\n\n const formData = new URLSearchParams()\n formData.append('form_name', formName)\n formData.append('test', 'true')\n formData.append('message', 'This is a test webhook from BetterStart')\n formData.append('timestamp', new Date().toISOString())\n\n const response = await fetch(settings.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: formData.toString(),\n })\n\n if (!response.ok) {\n return {\n success: false,\n error: \\`Webhook returned status \\${response.status}\\`,\n }\n }\n\n return { success: true }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to send test webhook',\n }\n }\n}\n`\n}\n","/**\n * Template: cms/lib/actions/upload.ts\n * File upload action using Cloudflare R2\n */\nexport function uploadActionTemplate(): string {\n return `'use server'\n\nimport { PutObjectCommand } from '@aws-sdk/client-s3'\nimport { BUCKET_NAME, generateFilePath, getPublicUrl, getR2Client } from '@cms/lib/r2'\n\ninterface UploadedFile {\n key: string\n url: string\n filename: string\n size: number\n contentType: string\n}\n\ninterface UploadResult {\n success: boolean\n files?: UploadedFile[]\n error?: string\n}\n\ninterface FileValidationConfig {\n maxFiles?: number\n maxSizeInBytes?: number\n allowedTypes?: string[]\n}\n\n/**\n * Upload multiple files to Cloudflare R2\n */\nexport async function uploadFiles(\n formData: FormData,\n config: FileValidationConfig = {},\n): Promise<UploadResult> {\n try {\n const files: File[] = []\n const prefix = formData.get('prefix')?.toString() || 'uploads'\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File && key.startsWith('file')) {\n files.push(value)\n }\n }\n\n if (files.length === 0) {\n return { success: false, error: 'No files provided' }\n }\n\n if (config.maxFiles && files.length > config.maxFiles) {\n return { success: false, error: \\`Too many files. Maximum is \\${config.maxFiles}\\` }\n }\n\n const uploadedFiles: UploadedFile[] = []\n\n for (const file of files) {\n if (config.maxSizeInBytes && file.size > config.maxSizeInBytes) {\n return { success: false, error: \\`File \\${file.name} exceeds size limit\\` }\n }\n if (config.allowedTypes && !config.allowedTypes.includes(file.type)) {\n return { success: false, error: \\`File type \\${file.type} is not allowed\\` }\n }\n\n const key = generateFilePath(file.name, prefix)\n const arrayBuffer = await file.arrayBuffer()\n const buffer = Buffer.from(arrayBuffer)\n\n const command = new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: key,\n Body: buffer,\n ContentType: file.type,\n ContentLength: file.size,\n })\n\n await getR2Client().send(command)\n\n uploadedFiles.push({\n key,\n url: getPublicUrl(key),\n filename: file.name,\n size: file.size,\n contentType: file.type,\n })\n }\n\n return { success: true, files: uploadedFiles }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to upload files'\n return { success: false, error: message }\n }\n}\n\n/**\n * Upload a single file to Cloudflare R2\n */\nexport async function uploadFile(\n formData: FormData,\n config: FileValidationConfig = {},\n): Promise<UploadResult> {\n return uploadFiles(formData, { ...config, maxFiles: 1 })\n}\n\n/**\n * Upload an image from a URL to Cloudflare R2\n */\nexport async function uploadImageFromUrl(\n imageUrl: string,\n prefix = 'images',\n): Promise<{ success: boolean; url?: string; error?: string }> {\n try {\n const url = new URL(imageUrl)\n if (!['http:', 'https:'].includes(url.protocol)) {\n return { success: false, error: 'Only HTTP and HTTPS URLs are allowed' }\n }\n\n const response = await fetch(imageUrl, {\n headers: { 'User-Agent': 'Mozilla/5.0 (compatible; ImageFetcher/1.0)' },\n signal: AbortSignal.timeout(30000),\n })\n\n if (!response.ok) {\n return { success: false, error: \\`Failed to fetch image: \\${response.status}\\` }\n }\n\n const contentType = response.headers.get('content-type') || 'image/jpeg'\n if (!contentType.startsWith('image/')) {\n return { success: false, error: \\`Invalid content type: \\${contentType}\\` }\n }\n\n const arrayBuffer = await response.arrayBuffer()\n const buffer = Buffer.from(arrayBuffer)\n\n if (buffer.length === 0) return { success: false, error: 'Image file is empty' }\n if (buffer.length > 10 * 1024 * 1024) {\n return { success: false, error: 'Image exceeds 10MB limit' }\n }\n\n const filename = url.pathname.split('/').pop()?.split('?')[0] || 'image.jpg'\n const key = generateFilePath(filename, prefix)\n\n const command = new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: key,\n Body: buffer,\n ContentType: contentType,\n ContentLength: buffer.length,\n })\n\n await getR2Client().send(command)\n return { success: true, url: getPublicUrl(key) }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to upload image from URL'\n return { success: false, error: message }\n }\n}\n`\n}\n","/**\n * Template: cms/lib/actions/users.ts\n * User management actions (list, create, update role)\n *\n * Fix #5: Uses Better Auth's built-in createUser API instead of SHA-256 hashing.\n */\nexport function usersActionTemplate(): string {\n return `'use server'\n\nimport { auth } from '@cms/auth'\nimport db from '@cms/db'\nimport { user } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\n\nexport interface UserData {\n id: string\n email: string\n name: string\n emailVerified: boolean\n createdAt: string\n updatedAt: string\n role: string\n}\n\nexport interface UsersResponse {\n users: UserData[]\n total: number\n}\n\nexport interface CreateUserInput {\n email: string\n name: string\n password: string\n}\n\nexport interface CreateUserResult {\n success: boolean\n error?: string\n user?: UserData\n}\n\nexport interface UpdateUserRoleResult {\n success: boolean\n error?: string\n}\n\nexport interface DeleteUserResult {\n success: boolean\n error?: string\n}\n\n/**\n * Create a new user via Better Auth's built-in API\n */\nexport async function createUser(input: CreateUserInput): Promise<CreateUserResult> {\n try {\n const result = await auth.api.signUpEmail({\n body: {\n email: input.email,\n password: input.password,\n name: input.name,\n },\n })\n\n if (!result?.user) {\n return { success: false, error: 'Failed to create user' }\n }\n\n return {\n success: true,\n user: {\n id: result.user.id,\n email: result.user.email,\n name: input.name,\n emailVerified: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n role: 'member',\n },\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create user',\n }\n }\n}\n\n/**\n * Get all users\n */\nexport async function getUsers(): Promise<UsersResponse> {\n try {\n const users = await db\n .select({\n id: user.id,\n email: user.email,\n name: user.name,\n emailVerified: user.emailVerified,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n role: user.role,\n })\n .from(user)\n .orderBy(user.createdAt)\n\n const userData: UserData[] = users.map((u) => ({\n id: u.id,\n email: u.email,\n name: u.name,\n emailVerified: u.emailVerified,\n createdAt: u.createdAt.toISOString(),\n updatedAt: u.updatedAt.toISOString(),\n role: u.role || 'member',\n }))\n\n return { users: userData, total: userData.length }\n } catch {\n return { users: [], total: 0 }\n }\n}\n\n/**\n * Update a user's role\n */\nexport async function updateUserRole(userId: string, role: string): Promise<UpdateUserRoleResult> {\n try {\n await db.update(user).set({ role, updatedAt: new Date() }).where(eq(user.id, userId))\n\n return { success: true }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update user role',\n }\n }\n}\n\n/**\n * Delete a user\n */\nexport async function deleteUser(userId: string): Promise<DeleteUserResult> {\n try {\n await db.delete(user).where(eq(user.id, userId))\n return { success: true }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete user',\n }\n }\n}\n`\n}\n","/**\n * Template: cms/lib/markdown/cached.ts\n * Cached markdown rendering via Next.js 'use cache'\n */\nexport function markdownCachedTemplate(): string {\n return `'use cache'\n\nimport { renderMarkdownSync } from './render'\n\nexport async function renderMarkdown(src: string): Promise<string> {\n return renderMarkdownSync(src)\n}\n`\n}\n","/**\n * Template: cms/lib/markdown/format.ts\n * Markdown formatting / normalization utility\n */\nexport function markdownFormatTemplate(): string {\n return `/**\n * Format markdown content for consistent styling and readability\n */\nexport function formatMarkdown(content: string): string {\n if (!content || !content.trim()) {\n return ''\n }\n\n let formatted = content\n\n // Normalize line endings\n formatted = formatted.replace(/\\\\r\\\\n/g, '\\\\n')\n\n // Trim trailing whitespace from each line\n formatted = formatted\n .split('\\\\n')\n .map((line) => line.trimEnd())\n .join('\\\\n')\n\n // Normalize multiple blank lines to maximum of 2 (one blank line)\n formatted = formatted.replace(/\\\\n{3,}/g, '\\\\n\\\\n')\n\n // Ensure blank line before headings (unless at start)\n formatted = formatted.replace(/([^\\\\n])\\\\n(#{1,6}\\\\s)/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line after headings\n formatted = formatted.replace(/(#{1,6}\\\\s.*)\\\\n([^\\\\n#])/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line before code blocks\n formatted = formatted.replace(/([^\\\\n])\\\\n(\\`\\`\\`)/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line after code blocks\n formatted = formatted.replace(/(\\`\\`\\`)\\\\n([^\\\\n])/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line before horizontal rules\n formatted = formatted.replace(/([^\\\\n])\\\\n(---+)/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line after horizontal rules\n formatted = formatted.replace(/(---+)\\\\n([^\\\\n])/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line before blockquotes (unless nested)\n formatted = formatted.replace(/([^\\\\n>])\\\\n(>\\\\s)/g, '$1\\\\n\\\\n$2')\n\n // Normalize list item spacing\n formatted = formatted.replace(/^(\\\\s*)([-*+])\\\\s+/gm, '$1$2 ')\n formatted = formatted.replace(/^(\\\\s*)(\\\\d+\\\\.)\\\\s+/gm, '$1$2 ')\n\n // Remove leading blank lines\n formatted = formatted.replace(/^\\\\n+/, '')\n\n // Ensure single trailing newline\n formatted = \\`\\${formatted.trimEnd()}\\\\n\\`\n\n return formatted\n}\n`\n}\n","/**\n * Template: cms/lib/markdown/render.ts\n * Shiki + KaTeX + heading anchors markdown renderer\n */\nexport function markdownRenderTemplate(): string {\n return `import { transformerNotationDiff, transformerNotationHighlight } from '@shikijs/transformers'\nimport { renderToString } from 'katex'\nimport MarkdownIt from 'markdown-it'\nimport { createHighlighterCoreSync } from 'shiki/core'\nimport { createJavaScriptRegexEngine } from 'shiki/engine/javascript'\nimport css from 'shiki/langs/css.mjs'\nimport go from 'shiki/langs/go.mjs'\nimport javascript from 'shiki/langs/javascript.mjs'\nimport json from 'shiki/langs/json.mjs'\nimport jsx from 'shiki/langs/jsx.mjs'\nimport markdown from 'shiki/langs/markdown.mjs'\nimport python from 'shiki/langs/python.mjs'\nimport rust from 'shiki/langs/rust.mjs'\nimport shellscript from 'shiki/langs/shellscript.mjs'\nimport sql from 'shiki/langs/sql.mjs'\nimport tsx from 'shiki/langs/tsx.mjs'\nimport typescript from 'shiki/langs/typescript.mjs'\nimport yaml from 'shiki/langs/yaml.mjs'\nimport githubDark from 'shiki/themes/github-dark.mjs'\nimport githubLight from 'shiki/themes/github-light.mjs'\n\n// --- Helpers ---\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\\\w\\\\s-]/g, '')\n .replace(/\\\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\nfunction trimMathBlock(content: string): string {\n return content.replace(/\\\\$\\\\$([\\\\s\\\\S]*?)\\\\$\\\\$/g, (_match, mathContent: string) => {\n const trimmed = mathContent.trim()\n if (!trimmed) return '$$\\\\n$$'\n const lines = trimmed.split('\\\\n').filter((line: string) => line.trim().length > 0)\n return \\`$$\\\\n\\${lines.join('\\\\n')}\\\\n$$\\`\n })\n}\n\n// --- Shiki Highlighter ---\n\nconst shiki = createHighlighterCoreSync({\n themes: [githubDark, githubLight],\n langs: [\n javascript,\n typescript,\n jsx,\n tsx,\n python,\n rust,\n go,\n json,\n yaml,\n css,\n sql,\n shellscript,\n markdown,\n ],\n engine: createJavaScriptRegexEngine(),\n})\n\nconst loadedLangs = shiki.getLoadedLanguages()\n\n// --- Heading Anchor Plugin ---\n\nfunction headingAnchorPlugin(md: MarkdownIt) {\n md.core.ruler.push('heading_anchors', (state) => {\n const tokens = state.tokens\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]\n if (token.type === 'heading_open') {\n const contentToken = tokens[i + 1]\n if (contentToken && contentToken.type === 'inline' && contentToken.content) {\n const slug = slugify(contentToken.content)\n const idIndex = token.attrIndex('id')\n if (idIndex < 0) {\n token.attrPush(['id', slug])\n } else if (token.attrs) {\n token.attrs[idIndex][1] = slug\n }\n }\n }\n }\n return true\n })\n}\n\n// --- Inline KaTeX math plugin (replaces markdown-it-dollarmath) ---\n\nfunction mathPlugin(md: MarkdownIt) {\n // Inline: $...$\n md.inline.ruler.after('escape', 'math_inline', (state, silent) => {\n if (state.src.charCodeAt(state.pos) !== 0x24) return false\n if (state.src.charCodeAt(state.pos + 1) === 0x24) return false\n const start = state.pos + 1\n let end = start\n while (end < state.posMax && state.src.charCodeAt(end) !== 0x24) {\n if (state.src.charCodeAt(end) === 0x5C) end++\n end++\n }\n if (end >= state.posMax) return false\n const content = state.src.slice(start, end).trim()\n if (!content) return false\n if (!silent) {\n const token = state.push('math_inline', 'math', 0)\n token.content = content\n token.markup = '$'\n }\n state.pos = end + 1\n return true\n })\n\n md.renderer.rules.math_inline = (tokens, idx) => {\n return renderToString(tokens[idx].content, { displayMode: false, throwOnError: false, strict: 'ignore' })\n }\n\n // Block: $$...$$\n md.block.ruler.after('blockquote', 'math_block', (state, startLine, endLine, silent) => {\n const startPos = state.bMarks[startLine] + state.tShift[startLine]\n if (state.src.charCodeAt(startPos) !== 0x24 || state.src.charCodeAt(startPos + 1) !== 0x24) return false\n if (silent) return true\n let nextLine = startLine\n let found = false\n while (nextLine < endLine) {\n nextLine++\n if (nextLine >= endLine) break\n const pos = state.bMarks[nextLine] + state.tShift[nextLine]\n const max = state.eMarks[nextLine]\n const line = state.src.slice(pos, max).trim()\n if (line === '$$') { found = true; break }\n }\n if (!found) return false\n const contentLines: string[] = []\n for (let i = startLine + 1; i < nextLine; i++) {\n contentLines.push(state.src.slice(state.bMarks[i] + state.tShift[i], state.eMarks[i]))\n }\n const token = state.push('math_block', 'math', 0)\n token.content = contentLines.join('\\\\n').trim()\n token.markup = '$$'\n token.map = [startLine, nextLine + 1]\n state.line = nextLine + 1\n return true\n })\n\n md.renderer.rules.math_block = (tokens, idx) => {\n return '<div class=\"math-display\">' + renderToString(tokens[idx].content, { displayMode: true, throwOnError: false, strict: 'ignore' }) + '</div>\\\\n'\n }\n}\n\n// --- Markdown-it Instance ---\n\nconst md = MarkdownIt({\n html: true,\n linkify: true,\n typographer: true,\n breaks: true,\n highlight: (code, lang) => {\n const language = loadedLangs.includes(lang) ? lang : 'bash'\n const highlighted = shiki.codeToHtml(code, {\n lang: language,\n themes: { light: 'github-light', dark: 'github-dark' },\n defaultColor: false,\n transformers: [transformerNotationHighlight(), transformerNotationDiff()],\n })\n const escapedCode = code.replace(/</g, '<').replace(/>/g, '>')\n return \\`<div class=\"code-block-wrapper not-prose\" data-lang=\"\\${language}\"><button class=\"copy-button\" data-code=\"\\${escapedCode.replace(/\"/g, '"')}\" aria-label=\"Copy code\">Copy</button>\\${highlighted}</div>\\`\n },\n})\n .use(headingAnchorPlugin)\n .use(mathPlugin)\n\nexport function renderMarkdownSync(src: string): string {\n const trimmedContent = trimMathBlock(src)\n return md.render(trimmedContent)\n}\n\nexport function renderMarkdownInline(src: string): string {\n return md.renderInline(src)\n}\n`\n}\n","/**\n * Template: cms/lib/r2.ts\n * Cloudflare R2 client (S3-compatible)\n */\nexport function r2ClientTemplate(): string {\n return `import { S3Client } from '@aws-sdk/client-s3'\n\nlet _r2Client: S3Client | null = null\n\n/**\n * Get or create the R2 client (lazy initialization, server-side only)\n */\nexport function getR2Client(): S3Client {\n if (typeof window !== 'undefined') {\n throw new Error('R2 client can only be used on the server side')\n }\n\n if (_r2Client) return _r2Client\n\n if (!process.env.BETTERSTART_R2_ACCESS_KEY_ID) {\n throw new Error('BETTERSTART_R2_ACCESS_KEY_ID is not set')\n }\n if (!process.env.BETTERSTART_R2_SECRET_ACCESS_KEY) {\n throw new Error('BETTERSTART_R2_SECRET_ACCESS_KEY is not set')\n }\n if (!process.env.BETTERSTART_R2_ACCOUNT_ID) {\n throw new Error('BETTERSTART_R2_ACCOUNT_ID is not set')\n }\n\n _r2Client = new S3Client({\n region: 'auto',\n endpoint: \\`https://\\${process.env.BETTERSTART_R2_ACCOUNT_ID}.r2.cloudflarestorage.com\\`,\n credentials: {\n accessKeyId: process.env.BETTERSTART_R2_ACCESS_KEY_ID,\n secretAccessKey: process.env.BETTERSTART_R2_SECRET_ACCESS_KEY,\n },\n })\n\n return _r2Client\n}\n\nexport const BUCKET_NAME = process.env.BETTERSTART_R2_BUCKET_NAME || ''\nexport const PUBLIC_URL = process.env.BETTERSTART_R2_PUBLIC_URL || ''\n\n/**\n * Generate a unique file path for uploads\n */\nexport function generateFilePath(filename: string, prefix = 'uploads'): string {\n const timestamp = Date.now()\n const randomStr = Math.random().toString(36).substring(2, 15)\n const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_')\n return \\`\\${prefix}/\\${timestamp}-\\${randomStr}-\\${sanitizedFilename}\\`\n}\n\n/**\n * Get the public URL for a file\n */\nexport function getPublicUrl(key: string): string {\n return \\`\\${PUBLIC_URL}/\\${key}\\`\n}\n`\n}\n","/**\n * Template: cms/types/auth.ts\n * Auth types: UserRole enum, session types, role utilities\n */\nexport function authTypesTemplate(): string {\n return `export interface AuthUser {\n id: string\n email: string\n name: string\n emailVerified: boolean\n image: string | null\n role: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface AuthSession {\n user: AuthUser\n isAuthenticated: boolean\n}\n\nexport enum UserRole {\n ADMIN = 'admin',\n EDITOR = 'editor',\n MEMBER = 'member',\n}\n\nexport interface UserWithRole extends AuthUser {\n role: UserRole\n}\n\n/** Type guard to check if a value is a valid UserRole */\nexport function isUserRole(value: unknown): value is UserRole {\n return typeof value === 'string' && Object.values(UserRole).includes(value as UserRole)\n}\n\n/** Check if user has one of the allowed roles */\nexport function hasRequiredRole(userRole: UserRole, allowedRoles: UserRole[]): boolean {\n return allowedRoles.includes(userRole)\n}\n\nexport interface AuthState {\n user: AuthUser | null\n loading: boolean\n error: Error | null\n}\n\nexport interface UserData {\n id: string\n email: string\n name: string\n emailVerified: boolean\n createdAt: string\n updatedAt: string\n role: string\n}\n\nexport interface UsersResponse {\n users: UserData[]\n total: number\n}\n\nexport interface CreateUserInput {\n email: string\n name: string\n password: string\n}\n\nexport interface CreateUserResult {\n success: boolean\n error?: string\n user?: UserData\n}\n\nexport interface UpdateUserRoleInput {\n userId: string\n role: UserRole\n}\n\nexport interface UpdateUserRoleResult {\n success: boolean\n error?: string\n}\n`\n}\n","/**\n * Template: cms/types/index.ts\n * Barrel export for all CMS types\n */\nexport function typesIndexTemplate(): string {\n return `export * from './auth'\n\n/** Markdown editor component types */\nexport interface MDXComponent {\n name: string\n snippet: string\n category: string\n}\n\nexport interface MarkdownEditorProps {\n value?: string\n onChange?: (value: string) => void\n placeholder?: string\n disabled?: boolean\n className?: string\n componentSnippets: Record<string, MDXComponent[]>\n}\n\n/** Upload types */\nexport interface UploadedFile {\n key: string\n url: string\n filename: string\n size: number\n contentType: string\n}\n\nexport interface UploadFileResult {\n success: boolean\n error?: string\n files?: UploadedFile[]\n}\n\nexport interface UploadProgress {\n filename: string\n progress: number\n loaded: number\n total: number\n}\n\n/** API response types */\nexport interface ApiResponse<T = unknown> {\n success: boolean\n data?: T\n error?: string\n message?: string\n}\n\n/** Database response types */\nexport interface PaginationParams {\n page: number\n limit: number\n sortBy?: string\n sortOrder?: 'asc' | 'desc'\n}\n\nexport interface PaginatedResponse<T> {\n data: T[]\n total: number\n page: number\n limit: number\n totalPages: number\n}\n\n/** TanStack Table meta augmentation */\ndeclare module '@tanstack/react-table' {\n // biome-ignore lint/correctness/noUnusedVariables: augmenting module\n interface TableMeta<TData extends import('@tanstack/react-table').RowData> {\n reorderMode?: boolean\n onMoveRow?: (id: number, direction: 'up' | 'down') => void\n currentUser?: {\n id: string\n email: string\n name: string\n image?: string | null\n role: string\n } | null\n }\n}\n`\n}\n","/**\n * Template: cms/types/table-meta.ts\n * TanStack Table meta augmentation\n */\nexport function tableMetaTypesTemplate(): string {\n return `import type { RowData } from '@tanstack/react-table'\n\ndeclare module '@tanstack/react-table' {\n // biome-ignore lint/correctness/noUnusedVariables: augmenting module\n interface TableMeta<TData extends RowData> {\n reorderMode?: boolean\n onMoveRow?: (id: number, direction: 'up' | 'down') => void\n currentUser?: {\n id: string\n email: string\n name: string\n image?: string | null\n role: string\n } | null\n }\n}\n`\n}\n","/**\n * Template: cms/utils/cn.ts\n * Tailwind class merge utility\n */\nexport function cnUtilTemplate(): string {\n return `import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n`\n}\n","/**\n * Template: cms/utils/seo.ts\n * SEO metadata utilities for generated pages\n */\nexport function seoUtilTemplate(): string {\n return `import type { Metadata } from 'next'\n\ninterface CreateMetadataOptions {\n title: string\n description: string\n path?: string\n ogImage?: string\n noIndex?: boolean\n}\n\n/**\n * Create consistent Next.js metadata for CMS-generated pages.\n * Use this in page.tsx files for entities that have public-facing pages.\n */\nexport function createMetadata({\n title,\n description,\n path,\n ogImage,\n noIndex = false,\n}: CreateMetadataOptions): Metadata {\n const metadata: Metadata = {\n title,\n description,\n openGraph: {\n title,\n description,\n type: 'website',\n ...(ogImage && { images: [{ url: ogImage }] }),\n },\n twitter: {\n card: ogImage ? 'summary_large_image' : 'summary',\n title,\n description,\n ...(ogImage && { images: [ogImage] }),\n },\n }\n\n if (path) {\n metadata.alternates = { canonical: path }\n }\n\n if (noIndex) {\n metadata.robots = { index: false, follow: false }\n }\n\n return metadata\n}\n\n/**\n * Generate JSON-LD structured data for a blog post / article.\n */\nexport function generateArticleSchema({\n title,\n description,\n url,\n imageUrl,\n datePublished,\n dateModified,\n authorName,\n}: {\n title: string\n description: string\n url: string\n imageUrl?: string\n datePublished: string\n dateModified?: string\n authorName?: string\n}) {\n return {\n '@context': 'https://schema.org',\n '@type': 'BlogPosting',\n headline: title,\n description,\n url,\n ...(imageUrl && { image: imageUrl }),\n datePublished,\n ...(dateModified && { dateModified }),\n ...(authorName && {\n author: { '@type': 'Person', name: authorName },\n }),\n }\n}\n\n/**\n * Serialize a JSON-LD schema object to a string for embedding in a script tag.\n */\nexport function schemaToJson(schema: Record<string, unknown>): string {\n return JSON.stringify(schema)\n}\n`\n}\n","/**\n * Template: cms/utils/validation.ts\n * File upload validation and common validation helpers\n */\nexport function validationUtilTemplate(): string {\n return `export interface FileValidationConfig {\n maxSizeInBytes?: number\n allowedTypes?: string[]\n maxFiles?: number\n}\n\nexport interface FileValidationError {\n filename: string\n error: string\n}\n\nexport interface FileValidationResult {\n valid: boolean\n errors: FileValidationError[]\n}\n\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\nconst DEFAULT_MAX_FILES = 10\n\nfunction isFileTypeAllowed(file: File, allowedTypes: string[]): boolean {\n for (const type of allowedTypes) {\n if (type.endsWith('/*')) {\n const prefix = type.slice(0, -1)\n if (file.type.startsWith(prefix)) return true\n } else if (type.startsWith('.')) {\n if (file.name.toLowerCase().endsWith(type.toLowerCase())) return true\n } else {\n if (file.type === type) return true\n }\n }\n return false\n}\n\n/**\n * Validate an array of files against size, type, and count constraints.\n */\nexport function validateFiles(\n files: File[],\n config: FileValidationConfig = {},\n): FileValidationResult {\n const { maxSizeInBytes = DEFAULT_MAX_SIZE, allowedTypes, maxFiles = DEFAULT_MAX_FILES } = config\n\n const errors: FileValidationError[] = []\n\n if (files.length > maxFiles) {\n errors.push({\n filename: '',\n error: \\`Too many files. Maximum is \\${maxFiles}.\\`,\n })\n }\n\n for (const file of files) {\n if (file.size > maxSizeInBytes) {\n const maxMB = Math.round(maxSizeInBytes / (1024 * 1024))\n errors.push({\n filename: file.name,\n error: \\`File exceeds maximum size of \\${maxMB}MB.\\`,\n })\n }\n\n if (allowedTypes && allowedTypes.length > 0 && !isFileTypeAllowed(file, allowedTypes)) {\n errors.push({\n filename: file.name,\n error: \\`File type \"\\${file.type || 'unknown'}\" is not allowed.\\`,\n })\n }\n }\n\n return { valid: errors.length === 0, errors }\n}\n\n/**\n * Format bytes to a human-readable string.\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B'\n const units = ['B', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(1024))\n return \\`\\${(bytes / 1024 ** i).toFixed(i === 0 ? 0 : 1)} \\${units[i]}\\`\n}\n\n/**\n * Check if a string is a valid URL.\n */\nexport function isValidUrl(str: string): boolean {\n try {\n new URL(str)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Slugify a string for use in URLs.\n */\nexport function slugify(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\\\w\\\\s-]/g, '')\n .replace(/[\\\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n}\n`\n}\n","/**\n * Template: cms/utils/webhook.ts\n * Fire-and-forget webhook sender for form submissions\n */\nexport function webhookUtilTemplate(): string {\n return `/**\n * Send payload to webhook URL (fire-and-forget, non-blocking)\n * @param webhookUrl - The webhook URL to send data to\n * @param payload - The form data to send as URL-encoded\n */\nexport function sendWebhook(\n webhookUrl: string | null | undefined,\n payload: Record<string, unknown>,\n): void {\n if (!webhookUrl) return // Fire-and-forget: runs in background, doesn't block\n ;(async () => {\n try {\n const formData = new URLSearchParams()\n for (const [key, value] of Object.entries(payload)) {\n if (value === null || value === undefined) continue\n const stringValue = typeof value === 'object' ? JSON.stringify(value) : String(value)\n formData.append(key, stringValue)\n }\n await fetch(webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: formData.toString(),\n })\n } catch (error) {\n console.error('Webhook failed:', error)\n }\n })()\n}\n`\n}\n","/**\n * Template: cms/utils/mailchimp.ts\n * Fire-and-forget Mailchimp audience subscription\n */\nexport function mailchimpUtilTemplate(): string {\n return `import mailchimp from '@mailchimp/mailchimp_marketing'\n\nif (process.env.BETTERSTART_MAILCHIMP_API_KEY && process.env.BETTERSTART_MAILCHIMP_SERVER_PREFIX) {\n mailchimp.setConfig({\n apiKey: process.env.BETTERSTART_MAILCHIMP_API_KEY,\n server: process.env.BETTERSTART_MAILCHIMP_SERVER_PREFIX\n })\n}\n\n/**\n * Add an email address to the Mailchimp audience (fire-and-forget, non-blocking)\n * Follows the same pattern as sendWebhook() in utils/webhook.ts\n */\nexport function addToMailchimpAudience(email: string): void {\n if (\n !process.env.BETTERSTART_MAILCHIMP_API_KEY ||\n !process.env.BETTERSTART_MAILCHIMP_SERVER_PREFIX ||\n !process.env.BETTERSTART_MAILCHIMP_AUDIENCE_ID\n )\n return\n\n ;(async () => {\n try {\n await mailchimp.lists.addListMember(process.env.BETTERSTART_MAILCHIMP_AUDIENCE_ID!, {\n email_address: email,\n status: 'subscribed' as const,\n merge_fields: {}\n })\n } catch (error: unknown) {\n // Silently ignore \"Member Exists\" (user re-submitting form)\n if (\n (error as { response?: { body?: { title?: string } } })?.response?.body?.title ===\n 'Member Exists'\n )\n return\n console.error('Failed to add to Mailchimp audience:', error)\n }\n })()\n}\n`\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { safeWriteFile } from '../../utils/fs.js'\n\nimport { dbClientTemplate } from '../templates/db/client.js'\nimport { drizzleConfigTemplate } from '../templates/db/drizzle-config.js'\nimport { dbSchemaTemplate } from '../templates/db/schema.js'\n\nexport interface DatabaseScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create database client, schema, and drizzle config in cms/db/.\n */\nexport function scaffoldDatabase({ cwd, config }: DatabaseScaffoldOptions): string[] {\n const created: string[] = []\n const dbDir = path.resolve(cwd, config.paths.cms, 'db')\n\n function write(filename: string, content: string): void {\n const fullPath = path.join(dbDir, filename)\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.cms, 'db', filename))\n }\n }\n\n write('client.ts', dbClientTemplate())\n write('schema.ts', dbSchemaTemplate())\n\n // Drizzle config goes at project root (where drizzle-kit expects it)\n const drizzleConfigPath = path.resolve(cwd, 'drizzle.config.ts')\n if (safeWriteFile(drizzleConfigPath, drizzleConfigTemplate())) {\n created.push('drizzle.config.ts')\n }\n\n return created\n}\n","/**\n * Template: cms/db/client.ts\n * Neon + Drizzle database client\n */\nexport function dbClientTemplate(): string {\n return `import { neon } from '@neondatabase/serverless'\nimport { drizzle } from 'drizzle-orm/neon-http'\nimport * as schema from './schema'\n\nconst sql = neon(process.env.BETTERSTART_DATABASE_URL!)\nconst db = drizzle({ client: sql, schema })\n\nexport default db\n`\n}\n","/**\n * Template: cms/db/schema.ts\n * Base schema with Better Auth tables only.\n * The generate command appends entity tables to this file.\n */\nexport function dbSchemaTemplate(): string {\n return `import { sql } from 'drizzle-orm'\nimport { boolean, pgTable, serial, text, timestamp, uniqueIndex, varchar } from 'drizzle-orm/pg-core'\n\n// ============================================================================\n// Better Auth tables\n// ============================================================================\n\nexport const user = pgTable('user', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n email: text('email').notNull().unique(),\n emailVerified: boolean('email_verified').notNull().default(false),\n image: text('image'),\n role: text('role').notNull().default('member'),\n createdAt: timestamp('created_at').notNull().defaultNow(),\n updatedAt: timestamp('updated_at').notNull().defaultNow(),\n})\n\nexport const session = pgTable('session', {\n id: text('id').primaryKey(),\n expiresAt: timestamp('expires_at').notNull(),\n token: text('token').notNull().unique(),\n createdAt: timestamp('created_at').notNull().defaultNow(),\n updatedAt: timestamp('updated_at').notNull().defaultNow(),\n ipAddress: text('ip_address'),\n userAgent: text('user_agent'),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n})\n\nexport const account = pgTable('account', {\n id: text('id').primaryKey(),\n accountId: text('account_id').notNull(),\n providerId: text('provider_id').notNull(),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n accessToken: text('access_token'),\n refreshToken: text('refresh_token'),\n idToken: text('id_token'),\n accessTokenExpiresAt: timestamp('access_token_expires_at'),\n refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),\n scope: text('scope'),\n password: text('password'),\n createdAt: timestamp('created_at').notNull().defaultNow(),\n updatedAt: timestamp('updated_at').notNull().defaultNow(),\n})\n\nexport const verification = pgTable('verification', {\n id: text('id').primaryKey(),\n identifier: text('identifier').notNull(),\n value: text('value').notNull(),\n expiresAt: timestamp('expires_at').notNull(),\n createdAt: timestamp('created_at').defaultNow(),\n updatedAt: timestamp('updated_at').defaultNow(),\n})\n\n// ============================================================================\n// Form Settings (shared table for all form configurations)\n// ============================================================================\n\nexport const formSettings = pgTable(\n 'FormSettings',\n {\n id: serial().primaryKey().notNull(),\n formName: varchar('formName', { length: 100 }).notNull(),\n webhookUrl: text('webhookUrl'),\n webhookEnabled: boolean('webhookEnabled').default(false).notNull(),\n notificationEmails: text('notificationEmails'),\n createdAt: timestamp('createdAt', { precision: 3, mode: 'string' })\n .default(sql\\`CURRENT_TIMESTAMP\\`)\n .notNull(),\n updatedAt: timestamp('updatedAt', { precision: 3, mode: 'string' })\n .default(sql\\`CURRENT_TIMESTAMP\\`)\n .notNull(),\n },\n (table) => [\n uniqueIndex('FormSettings_formName_key').using(\n 'btree',\n table.formName.asc().nullsLast().op('text_ops')\n ),\n ]\n)\n\n// ============================================================================\n// Generated entity tables (appended by \\`betterstart generate\\`)\n// ============================================================================\n`\n}\n","/**\n * Dependency installer: auto-install all required deps via detected package manager.\n * Splits into core (production) and dev dependencies.\n * Optionally includes email deps (resend + @react-email/components).\n * Uses async spawn so the clack spinner can animate during install.\n */\n\nimport { spawn } from 'node:child_process'\nimport type { PackageManager } from '../../utils/package-manager.js'\n\nexport interface InstallDepsOptions {\n cwd: string\n pm: PackageManager\n includeEmail: boolean\n includeBiome: boolean\n}\n\nexport interface InstallDepsResult {\n coreDeps: string[]\n devDeps: string[]\n success: boolean\n error: string | null\n}\n\n// ============================================================================\n// Dependency Lists\n// ============================================================================\n\n/** Core runtime deps — always installed */\nexport const CORE_DEPS = [\n // Database\n 'drizzle-orm',\n '@neondatabase/serverless',\n // Auth\n 'better-auth',\n // Data fetching + tables\n '@tanstack/react-query',\n '@tanstack/react-table',\n '@tanstack/react-virtual',\n // Forms + validation\n 'react-hook-form',\n '@hookform/resolvers',\n 'zod',\n // URL state + toast + theme\n 'nuqs',\n 'sonner',\n // Styling utilities\n 'geist',\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n // Icons\n 'lucide-react',\n // Storage (R2)\n '@aws-sdk/client-s3',\n // Radix UI primitives\n '@radix-ui/react-accordion',\n '@radix-ui/react-alert-dialog',\n '@radix-ui/react-aspect-ratio',\n '@radix-ui/react-avatar',\n '@radix-ui/react-checkbox',\n '@radix-ui/react-collapsible',\n '@radix-ui/react-context-menu',\n '@radix-ui/react-dialog',\n '@radix-ui/react-dropdown-menu',\n '@radix-ui/react-hover-card',\n '@radix-ui/react-label',\n '@radix-ui/react-menubar',\n '@radix-ui/react-navigation-menu',\n '@radix-ui/react-popover',\n '@radix-ui/react-progress',\n '@radix-ui/react-radio-group',\n '@radix-ui/react-scroll-area',\n '@radix-ui/react-select',\n '@radix-ui/react-separator',\n '@radix-ui/react-slider',\n '@radix-ui/react-slot',\n '@radix-ui/react-switch',\n '@radix-ui/react-tabs',\n '@radix-ui/react-toast',\n '@radix-ui/react-toggle',\n '@radix-ui/react-toggle-group',\n '@radix-ui/react-tooltip',\n // Rich text (TipTap)\n '@tiptap/core',\n '@tiptap/pm',\n '@tiptap/react',\n '@tiptap/starter-kit',\n '@tiptap/extension-highlight',\n '@tiptap/extension-horizontal-rule',\n '@tiptap/extension-image',\n '@tiptap/extension-list',\n '@tiptap/extension-placeholder',\n '@tiptap/extension-subscript',\n '@tiptap/extension-superscript',\n '@tiptap/extension-text-align',\n '@tiptap/extension-typography',\n '@tiptap/extensions',\n 'tiptap-markdown',\n '@floating-ui/react',\n 'react-hotkeys-hook',\n 'lodash.throttle',\n // CodeMirror markdown editor\n '@codemirror/lang-markdown',\n '@codemirror/view',\n '@uiw/codemirror-theme-github',\n '@uiw/react-codemirror',\n // Date\n 'date-fns',\n 'react-day-picker',\n // Markdown rendering\n 'shiki',\n '@shikijs/transformers',\n 'katex',\n 'markdown-it',\n // Drag-and-drop\n '@dnd-kit/core',\n '@dnd-kit/sortable',\n '@dnd-kit/utilities',\n // Other UI\n 'cmdk',\n 'embla-carousel-react',\n 'fuse.js',\n 'input-otp',\n 'react-resizable-panels',\n 'recharts',\n 'tw-animate-css',\n 'usehooks-ts',\n 'vaul'\n]\n\n/** Email deps — only when email feature is enabled */\nexport const EMAIL_DEPS = ['resend', '@react-email/components']\n\n/** Mailchimp deps — always installed (fire-and-forget, no-op without env vars) */\nexport const MAILCHIMP_DEPS = ['@mailchimp/mailchimp_marketing']\n\n/** Mailchimp type definitions */\nexport const MAILCHIMP_DEV_DEPS = ['@types/mailchimp__mailchimp_marketing']\n\n/** Dev deps — always installed */\nexport const DEV_DEPS = ['drizzle-kit', 'tsx', 'sass', '@types/katex', '@types/markdown-it@13']\n\n/** Biome dev dep — only when no existing linter */\nexport const BIOME_DEV_DEPS = ['@biomejs/biome']\n\n// ============================================================================\n// Installer\n// ============================================================================\n\nfunction buildAddArgs(pm: PackageManager, deps: string[], dev: boolean): string[] {\n const devFlag = dev ? (pm === 'yarn' ? '--dev' : '-D') : ''\n\n switch (pm) {\n case 'pnpm':\n return ['add', ...(devFlag ? [devFlag] : []), ...deps]\n case 'yarn':\n return ['add', ...(devFlag ? [devFlag] : []), ...deps]\n case 'bun':\n return ['add', ...(devFlag ? [devFlag] : []), ...deps]\n default:\n return ['install', ...(devFlag ? [devFlag] : []), ...deps]\n }\n}\n\nfunction spawnAsync(cmd: string, args: string[], cwd: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { cwd, stdio: 'pipe' })\n let stderr = ''\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n child.on('close', (code) => {\n if (code === 0) resolve()\n else reject(new Error(stderr || `${cmd} exited with code ${code}`))\n })\n child.on('error', reject)\n })\n}\n\nexport async function installDependenciesAsync({\n cwd,\n pm,\n includeEmail,\n includeBiome\n}: InstallDepsOptions): Promise<InstallDepsResult> {\n const coreDeps = [...CORE_DEPS, ...MAILCHIMP_DEPS]\n if (includeEmail) coreDeps.push(...EMAIL_DEPS)\n\n const devDeps = [...DEV_DEPS, ...MAILCHIMP_DEV_DEPS]\n if (includeBiome) devDeps.push(...BIOME_DEV_DEPS)\n\n try {\n // Install core deps\n await spawnAsync(pm, buildAddArgs(pm, coreDeps, false), cwd)\n\n // Install dev deps\n await spawnAsync(pm, buildAddArgs(pm, devDeps, true), cwd)\n\n return { coreDeps, devDeps, success: true, error: null }\n } catch (err) {\n return {\n coreDeps,\n devDeps,\n success: false,\n error: err instanceof Error ? err.message : 'Install failed'\n }\n }\n}\n","import crypto from 'node:crypto'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { EnvSection } from '../../utils/env.js'\nimport { appendEnvVars } from '../../utils/env.js'\n\nexport function detectDevPort(cwd: string): number {\n const pkgPath = join(cwd, 'package.json')\n if (!existsSync(pkgPath)) return 3000\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {\n scripts?: Record<string, string>\n }\n const devScript = pkg.scripts?.dev ?? ''\n const match = devScript.match(/--port\\s+(\\d+)|-p\\s+(\\d+)/)\n if (match) {\n const port = Number.parseInt(match[1] ?? match[2], 10)\n if (port > 0 && port <= 65535) return port\n }\n } catch {\n // ignore parse errors\n }\n return 3000\n}\n\nfunction getCoreEnvSections(\n databaseUrl: string | undefined,\n devPort: number\n): EnvSection[] {\n const authSecret = crypto.randomBytes(32).toString('base64')\n return [\n {\n header: 'Database (Neon)',\n vars: [{ key: 'BETTERSTART_DATABASE_URL', value: databaseUrl ?? 'postgresql://...' }]\n },\n {\n header: 'Authentication',\n vars: [\n { key: 'BETTERSTART_AUTH_SECRET', value: authSecret },\n { key: 'BETTERSTART_AUTH_URL', value: `http://localhost:${devPort}` },\n { key: 'BETTERSTART_AUTH_BASE_PATH', value: '/api/cms/auth' }\n ]\n },\n {\n header: 'Storage (Cloudflare R2)',\n vars: [\n { key: 'BETTERSTART_R2_ACCOUNT_ID', value: '' },\n { key: 'BETTERSTART_R2_ACCESS_KEY_ID', value: '' },\n { key: 'BETTERSTART_R2_SECRET_ACCESS_KEY', value: '' },\n { key: 'BETTERSTART_R2_BUCKET_NAME', value: '' },\n { key: 'BETTERSTART_R2_PUBLIC_URL', value: '' }\n ]\n }\n ]\n}\n\nfunction getEmailEnvSection(): EnvSection {\n return {\n header: 'Email (Resend)',\n vars: [\n { key: 'BETTERSTART_RESEND_API_KEY', value: '' },\n { key: 'BETTERSTART_EMAIL_FROM', value: 'noreply@yourdomain.com' }\n ]\n }\n}\n\nfunction getMailchimpEnvSection(): EnvSection {\n return {\n header: 'Mailchimp (optional — leave blank to disable)',\n vars: [\n { key: 'BETTERSTART_MAILCHIMP_API_KEY', value: '' },\n { key: 'BETTERSTART_MAILCHIMP_SERVER_PREFIX', value: '' },\n { key: 'BETTERSTART_MAILCHIMP_AUDIENCE_ID', value: '' }\n ]\n }\n}\n\n/**\n * Append BETTERSTART_* environment variables to .env.local.\n */\nexport function scaffoldEnv(\n cwd: string,\n options: { includeEmail: boolean; databaseUrl?: string }\n): { added: string[]; skipped: string[]; updated: string[] } {\n const devPort = detectDevPort(cwd)\n const sections = getCoreEnvSections(options.databaseUrl, devPort)\n if (options.includeEmail) {\n sections.push(getEmailEnvSection())\n }\n sections.push(getMailchimpEnvSection())\n // If the user provided a real database URL, overwrite any existing placeholder\n const overwrite = options.databaseUrl ? new Set(['BETTERSTART_DATABASE_URL']) : undefined\n return appendEnvVars(cwd, sections, overwrite)\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport interface EnvVar {\n key: string\n value: string\n comment?: string\n}\n\nexport interface EnvSection {\n header: string\n vars: EnvVar[]\n}\n\n/**\n * Safely append environment variables to .env.local.\n * Never overwrites existing values — only adds missing keys.\n * Keys listed in `overwrite` will be updated even if they already exist.\n */\nexport function appendEnvVars(\n cwd: string,\n sections: EnvSection[],\n overwrite?: Set<string>\n): { added: string[]; skipped: string[]; updated: string[] } {\n const envPath = path.join(cwd, '.env.local')\n let existing = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf-8') : ''\n\n const existingKeys = new Set(\n existing\n .split('\\n')\n .filter((line) => line.trim() && !line.trim().startsWith('#'))\n .map((line) => line.split('=')[0]?.trim())\n .filter(Boolean)\n )\n\n const added: string[] = []\n const skipped: string[] = []\n const updated: string[] = []\n const lines: string[] = []\n\n // In-place update for overwrite keys that already exist\n if (overwrite) {\n for (const section of sections) {\n for (const v of section.vars) {\n if (overwrite.has(v.key) && existingKeys.has(v.key)) {\n const pattern = new RegExp(`^${v.key}=.*$`, 'm')\n const replacement = v.comment\n ? `${v.key}=\"${v.value}\" # ${v.comment}`\n : `${v.key}=\"${v.value}\"`\n existing = existing.replace(pattern, replacement)\n updated.push(v.key)\n }\n }\n }\n }\n\n if (existing.trim()) {\n lines.push('')\n }\n\n for (const section of sections) {\n const sectionVars = section.vars.filter((v) => {\n if (existingKeys.has(v.key)) {\n if (!updated.includes(v.key)) skipped.push(v.key)\n return false\n }\n added.push(v.key)\n return true\n })\n\n if (sectionVars.length === 0) continue\n\n lines.push(`# ${section.header}`)\n for (const v of sectionVars) {\n const line = v.comment ? `${v.key}=\"${v.value}\" # ${v.comment}` : `${v.key}=\"${v.value}\"`\n lines.push(line)\n }\n lines.push('')\n }\n\n if (added.length > 0 || updated.length > 0) {\n const header = existing.trim()\n ? ''\n : '# ============================================\\n# BetterStart CMS\\n# ============================================\\n'\n const content = existing.trim()\n ? `${existing.trimEnd()}\\n${lines.join('\\n')}`\n : header + lines.join('\\n')\n fs.writeFileSync(envPath, content)\n }\n\n return { added, skipped, updated }\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { ensureDir, safeWriteFile } from '../../utils/fs.js'\nimport { authenticatedLayoutTemplate } from '../templates/pages/authenticated-layout.js'\n// Page templates\nimport { cmsLayoutTemplate } from '../templates/pages/cms-layout.js'\nimport { dashboardPageTemplate } from '../templates/pages/dashboard-page.js'\nimport { loginFormTemplate, loginPageTemplate } from '../templates/pages/login-page.js'\nimport { createUserDialogTemplate } from '../templates/pages/users/create-user-dialog.js'\nimport { editRoleDialogTemplate } from '../templates/pages/users/edit-role-dialog.js'\nimport { usersColumnsTemplate } from '../templates/pages/users/users-columns.js'\n// Users page templates\nimport { usersPageTemplate } from '../templates/pages/users/users-page.js'\nimport { usersTableTemplate } from '../templates/pages/users/users-table.js'\n\nexport interface LayoutScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create all CMS route structures: layouts, login, dashboard, users, settings.\n */\nexport function scaffoldLayout({ cwd, config }: LayoutScaffoldOptions): string[] {\n const created: string[] = []\n\n function write(relPath: string, content: string): void {\n const fullPath = path.resolve(cwd, relPath)\n ensureDir(path.dirname(fullPath))\n if (safeWriteFile(fullPath, content)) {\n created.push(relPath)\n }\n }\n\n // Derive base CMS layout dir from pages path\n // pages = \"./src/app/(cms)/cms/(authenticated)\" → cmsDir = \"./src/app/(cms)/cms\"\n const cmsDir = path.dirname(config.paths.pages)\n\n // --- Shared CMS layout ---\n write(path.join(cmsDir, 'layout.tsx'), cmsLayoutTemplate())\n\n // --- Authenticated layout ---\n write(path.join(config.paths.pages, 'layout.tsx'), authenticatedLayoutTemplate())\n\n // --- Login page ---\n write(path.join(config.paths.login, 'page.tsx'), loginPageTemplate())\n write(path.join(config.paths.login, 'login-form.tsx'), loginFormTemplate())\n\n // --- Dashboard ---\n write(path.join(config.paths.pages, 'page.tsx'), dashboardPageTemplate())\n\n // --- Users pages ---\n const usersDir = path.join(config.paths.pages, 'users')\n write(path.join(usersDir, 'page.tsx'), usersPageTemplate())\n write(path.join(usersDir, 'users-table.tsx'), usersTableTemplate())\n write(path.join(usersDir, 'columns.tsx'), usersColumnsTemplate())\n write(path.join(usersDir, 'create-user-dialog.tsx'), createUserDialogTemplate())\n write(path.join(usersDir, 'edit-role-dialog.tsx'), editRoleDialogTemplate())\n\n return created\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/layout.tsx\n * Auth-gated layout with sidebar + header\n * Requires admin or editor role to access\n */\nexport function authenticatedLayoutTemplate(): string {\n return `import { requireRole } from '@cms/auth/middleware'\nimport { CmsSidebar } from '@cms/components/layout/cms-sidebar'\nimport { SidebarInset, SidebarProvider } from '@cms/components/ui/sidebar'\nimport { UserRole } from '@cms/types/auth'\n\nexport default async function CmsAuthLayout({ children }: { children: React.ReactNode }) {\n await requireRole([UserRole.ADMIN, UserRole.EDITOR])\n\n return (\n <SidebarProvider>\n <CmsSidebar />\n <SidebarInset>\n <main>{children}</main>\n </SidebarInset>\n </SidebarProvider>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/layout.tsx\n * Shared CMS shell — css + providers (NO auth gate)\n * Login page lives under this layout but outside (authenticated)/\n */\nexport function cmsLayoutTemplate(): string {\n return `import '@cms/cms-globals.css'\nimport { CmsProviders } from '@cms/components/layout/cms-providers'\nimport { GeistMono } from 'geist/font/mono'\nimport { GeistSans } from 'geist/font/sans'\n\nexport default function CmsLayout({ children }: { children: React.ReactNode }) {\n return (\n <CmsProviders>\n <div\n className={\\`cms-root min-h-screen antialiased \\${GeistSans.variable} \\${GeistMono.variable}\\`}\n >\n {children}\n </div>\n </CmsProviders>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/page.tsx\n * Dashboard — simple welcome page with quick links\n */\nexport function dashboardPageTemplate(): string {\n return `import { PageHeader } from '@cms/components/shared/page-header'\nimport { Badge } from '@cms/components/ui/badge'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@cms/components/ui/card'\nimport { FileText, Settings, Users } from 'lucide-react'\nimport Link from 'next/link'\n\nconst quickLinks = [\n {\n title: 'Users',\n description: 'Manage admin users and roles',\n href: '/cms/users',\n icon: Users,\n },\n {\n title: 'Settings',\n description: 'Configure CMS settings',\n href: '/cms/settings',\n icon: Settings,\n },\n {\n title: 'Generate',\n description: 'Add a new resource from a schema',\n href: '#',\n icon: FileText,\n hint: 'npx betterstart generate <schema>',\n },\n]\n\nexport default function DashboardPage() {\n return (\n <div className=\"flex flex-col\">\n <PageHeader title=\"Dashboard\" />\n <div className=\"p-6 space-y-6\">\n <div className=\"grid gap-4 md:grid-cols-3\">\n {quickLinks.map((link) => (\n <Link key={link.title} href={link.href}>\n <Card className=\"hover:bg-accent/50 transition-colors h-full\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center gap-2\">\n <link.icon className=\"size-4 text-muted-foreground\" />\n <CardTitle className=\"text-sm font-medium\">{link.title}</CardTitle>\n </div>\n </CardHeader>\n <CardContent>\n <CardDescription>{link.description}</CardDescription>\n {link.hint && (\n <code className=\"mt-2 block rounded bg-muted px-1.5 py-0.5 font-mono text-xs text-muted-foreground\">\n {link.hint}\n </code>\n )}\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm font-medium\">Environment</CardTitle>\n <CardDescription>Current configuration status</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Environment</span>\n <Badge variant=\"outline\">\n {process.env.NODE_ENV === 'production' ? 'Production' : 'Development'}\n </Badge>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Database</span>\n <Badge variant=\"outline\">\n {process.env.BETTERSTART_DATABASE_URL ? 'Connected' : 'Not configured'}\n </Badge>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Storage (R2)</span>\n <Badge variant=\"outline\">\n {process.env.BETTERSTART_R2_BUCKET_NAME ? 'Configured' : 'Not configured'}\n </Badge>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Email (Resend)</span>\n <Badge variant=\"outline\">\n {process.env.BETTERSTART_RESEND_API_KEY ? 'Configured' : 'Not configured'}\n </Badge>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/login/page.tsx\n * CMS login page — outside (authenticated) route group\n */\nexport function loginPageTemplate(): string {\n return `import type { Metadata } from 'next'\nimport { LoginForm } from './login-form'\n\nexport const metadata: Metadata = {\n title: 'CMS Login',\n robots: { index: false, follow: false },\n}\n\nexport default function LoginPage() {\n return (\n <div className=\"flex min-h-screen items-center justify-center px-4\">\n <div className=\"w-full max-w-sm\">\n <div className=\"mb-8 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">CMS</h1>\n <p className=\"text-muted-foreground text-sm mt-1\">Sign in to access the admin panel</p>\n </div>\n <LoginForm />\n </div>\n </div>\n )\n}\n`\n}\n\n/**\n * Template: app/(cms)/cms/login/login-form.tsx\n * Client-side login form using Better Auth\n */\nexport function loginFormTemplate(): string {\n return `'use client'\n\nimport { authClient } from '@cms/auth/client'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport { Label } from '@cms/components/ui/label'\nimport { LoaderCircle } from 'lucide-react'\nimport { useRouter } from 'next/navigation'\nimport * as React from 'react'\n\nexport function LoginForm() {\n const router = useRouter()\n const [email, setEmail] = React.useState('')\n const [password, setPassword] = React.useState('')\n const [error, setError] = React.useState<string | null>(null)\n const [isLoading, setIsLoading] = React.useState(false)\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n setError(null)\n setIsLoading(true)\n\n try {\n const result = await authClient.signIn.email({\n email,\n password,\n })\n\n if (result.error) {\n setError(result.error.message || 'Invalid email or password')\n setIsLoading(false)\n return\n }\n\n router.push('/cms')\n router.refresh()\n } catch {\n setError('An error occurred. Please try again.')\n setIsLoading(false)\n }\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {error && (\n <div className=\"bg-destructive/10 text-destructive text-sm p-3 rounded-md\">{error}</div>\n )}\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isLoading}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <Input\n id=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n placeholder=\"Enter your password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isLoading}\n />\n </div>\n\n <Button type=\"submit\" className=\"w-full\" size=\"lg\" disabled={isLoading}>\n {isLoading && <LoaderCircle className=\"animate-spin\" />}\n {isLoading ? 'Signing in...' : 'Sign In'}\n </Button>\n </form>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/create-user-dialog.tsx\n * Dialog for creating new CMS users\n */\nexport function createUserDialogTemplate(): string {\n return `'use client'\n\nimport { createUser } from '@cms/actions/users'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@cms/components/ui/dialog'\nimport { Input } from '@cms/components/ui/input'\nimport { Label } from '@cms/components/ui/label'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Loader2, UserPlus } from 'lucide-react'\nimport * as React from 'react'\nimport { toast } from 'sonner'\n\nexport function CreateUserDialog() {\n const [open, setOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault()\n const formData = new FormData(e.currentTarget)\n const email = formData.get('email') as string\n const name = formData.get('name') as string\n const password = formData.get('password') as string\n\n startTransition(async () => {\n try {\n const result = await createUser({ email, name, password })\n if (result.success) {\n toast.success('User created successfully')\n queryClient.refetchQueries({ queryKey: ['users'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to create user')\n }\n } catch {\n toast.error('An unexpected error occurred')\n }\n })\n }\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button>\n <UserPlus className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Create User\n </Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-[425px]\">\n <DialogHeader>\n <DialogTitle>Create New User</DialogTitle>\n <DialogDescription>\n Add a new user to the CMS. They can sign in with these credentials.\n </DialogDescription>\n </DialogHeader>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"create-email\">Email</Label>\n <Input\n id=\"create-email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"user@example.com\"\n required\n disabled={isPending}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"create-name\">Name</Label>\n <Input\n id=\"create-name\"\n name=\"name\"\n type=\"text\"\n placeholder=\"Full name\"\n required\n disabled={isPending}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"create-password\">Password</Label>\n <Input\n id=\"create-password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"Min 8 characters\"\n minLength={8}\n required\n disabled={isPending}\n />\n </div>\n <div className=\"flex justify-end gap-2 pt-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={isPending}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={isPending}>\n {isPending && <Loader2 className=\"size-4 mr-1 animate-spin\" />}\n Create User\n </Button>\n </div>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/edit-role-dialog.tsx\n * Dialog for changing a user's role\n */\nexport function editRoleDialogTemplate(): string {\n return `'use client'\n\nimport { updateUserRole } from '@cms/actions/users'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@cms/components/ui/dialog'\nimport { Label } from '@cms/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\nimport { UserRole } from '@cms/types/auth'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Loader2 } from 'lucide-react'\nimport * as React from 'react'\nimport { toast } from 'sonner'\n\ninterface EditRoleDialogProps {\n userId: string\n currentRole: string\n userName: string\n children: React.ReactNode\n}\n\nexport function EditRoleDialog({ userId, currentRole, userName, children }: EditRoleDialogProps) {\n const [open, setOpen] = React.useState(false)\n const [role, setRole] = React.useState(currentRole)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n const handleSave = () => {\n startTransition(async () => {\n try {\n const result = await updateUserRole(userId, role as UserRole)\n if (result.success) {\n toast.success(\\`Role updated for \\${userName}\\`)\n queryClient.refetchQueries({ queryKey: ['users'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to update role')\n }\n } catch {\n toast.error('An unexpected error occurred')\n }\n })\n }\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>{children}</DialogTrigger>\n <DialogContent className=\"sm:max-w-[350px]\">\n <DialogHeader>\n <DialogTitle>Edit Role</DialogTitle>\n <DialogDescription>Change the role for {userName}</DialogDescription>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Role</Label>\n <Select value={role} onValueChange={setRole}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={UserRole.ADMIN}>Admin</SelectItem>\n <SelectItem value={UserRole.EDITOR}>Editor</SelectItem>\n <SelectItem value={UserRole.MEMBER}>Member</SelectItem>\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={() => setOpen(false)} disabled={isPending}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={isPending || role === currentRole}>\n {isPending && <Loader2 className=\"size-4 mr-1 animate-spin\" />}\n Save\n </Button>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/columns.tsx\n * Users table column definitions\n */\nexport function usersColumnsTemplate(): string {\n return `'use client'\n\nimport { deleteUser } from '@cms/actions/users'\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { Avatar, AvatarFallback } from '@cms/components/ui/avatar'\nimport { Badge } from '@cms/components/ui/badge'\nimport { Button } from '@cms/components/ui/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@cms/components/ui/dropdown-menu'\nimport type { UserData } from '@cms/types/auth'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ArrowUpDown, Edit, MoreHorizontal, Trash } from 'lucide-react'\nimport React from 'react'\nimport { toast } from 'sonner'\nimport { EditRoleDialog } from './edit-role-dialog'\n\nfunction getInitials(nameOrEmail: string): string {\n const parts = nameOrEmail.includes('@')\n ? nameOrEmail.split('@')[0].split(/[._-]/)\n : nameOrEmail.split(' ')\n return parts\n .filter(Boolean)\n .slice(0, 2)\n .map((p) => p[0].toUpperCase())\n .join('')\n}\n\nfunction DeleteUserAction({\n userId,\n userName,\n isCurrentUser,\n}: {\n userId: string\n userName: string\n isCurrentUser: boolean\n}) {\n const [open, setOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n if (isCurrentUser) return null\n\n const handleDelete = () => {\n startTransition(async () => {\n try {\n const result = await deleteUser(userId)\n\n if (result.success) {\n toast.success('User deleted successfully')\n queryClient.refetchQueries({ queryKey: ['users'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete user')\n }\n } catch (error) {\n toast.error('An error occurred')\n console.error(error)\n }\n })\n }\n\n return (\n <AlertDialog open={open} onOpenChange={setOpen}>\n <AlertDialogTrigger asChild>\n <DropdownMenuItem className=\"text-destructive\" onSelect={(e) => e.preventDefault()}>\n <Trash className=\"size-4 mr-2\" />\n Delete user\n </DropdownMenuItem>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete <strong>{userName}</strong>{' '}\n and all of their data.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n handleDelete()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n\nexport const columns: ColumnDef<UserData>[] = [\n {\n accessorKey: 'email',\n header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n >\n User\n <ArrowUpDown className=\"size-4\" />\n </Button>\n ),\n cell: ({ row }) => {\n const email = row.getValue('email') as string\n const name = row.original.name\n return (\n <div className=\"flex items-center gap-3\">\n <Avatar className=\"size-8\">\n <AvatarFallback>{getInitials(name || email)}</AvatarFallback>\n </Avatar>\n <div className=\"flex flex-col\">\n <div className=\"font-medium\">{name || 'N/A'}</div>\n <div className=\"text-muted-foreground text-sm\">{email}</div>\n </div>\n </div>\n )\n },\n },\n {\n accessorKey: 'emailVerified',\n header: 'Status',\n cell: ({ row }) => {\n const verified = row.getValue('emailVerified') as boolean\n return (\n <Badge variant={verified ? 'outline' : 'secondary'}>\n {verified ? 'Verified' : 'Unverified'}\n </Badge>\n )\n },\n },\n {\n accessorKey: 'role',\n header: 'Role',\n cell: ({ row, table }) => {\n const role = row.getValue('role') as string\n const currentUser = table.options.meta?.currentUser\n const isCurrentUser = currentUser?.email === row.original.email\n\n if (isCurrentUser) {\n return (\n <Badge variant=\"outline\" className=\"capitalize\">\n {role} (you)\n </Badge>\n )\n }\n\n return (\n <EditRoleDialog\n userId={row.original.id}\n currentRole={row.original.role}\n userName={row.original.name}\n >\n <Badge variant=\"outline\" className=\"capitalize cursor-pointer\">\n {role}\n <Edit className=\"size-3 ml-1\" strokeWidth={2} />\n </Badge>\n </EditRoleDialog>\n )\n },\n },\n {\n accessorKey: 'createdAt',\n header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50\"\n >\n Joined\n <ArrowUpDown className=\"size-4\" />\n </Button>\n ),\n cell: ({ row }) => {\n const date = new Date(row.getValue('createdAt'))\n return (\n <div className=\"text-sm\">\n {date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}\n </div>\n )\n },\n },\n {\n id: 'actions',\n cell: ({ row, table }) => {\n const currentUser = table.options.meta?.currentUser\n const isCurrentUser = currentUser?.email === row.original.email\n\n return (\n <div className=\"flex justify-end\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" className=\"size-8 p-0\">\n <span className=\"sr-only\">Open menu</span>\n <MoreHorizontal className=\"size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuLabel>Actions</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => navigator.clipboard.writeText(row.original.id)}>\n Copy user ID\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DeleteUserAction\n userId={row.original.id}\n userName={row.original.name}\n isCurrentUser={isCurrentUser}\n />\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )\n },\n },\n]\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/page.tsx\n * Users management page (server component)\n */\nexport function usersPageTemplate(): string {\n return `import { PageHeader } from '@cms/components/shared/page-header'\nimport { columns } from './columns'\nimport { CreateUserDialog } from './create-user-dialog'\nimport { UsersTable } from './users-table'\n\nexport default function UsersPage() {\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader title=\"Users\">\n <CreateUserDialog />\n </PageHeader>\n </div>\n <main className=\"p-6\">\n <UsersTable columns={columns} />\n </main>\n </div>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/users-table.tsx\n * Users data table (client component)\n */\nexport function usersTableTemplate(): string {\n return `'use client'\n\nimport { authClient } from '@cms/auth/client'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@cms/components/ui/table'\nimport { useUsers } from '@cms/hooks/use-users'\nimport type { UserData } from '@cms/types/auth'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport * as React from 'react'\n\ninterface UsersTableProps<TValue> {\n columns: ColumnDef<UserData, TValue>[]\n}\n\nexport function UsersTable<TValue>({ columns }: UsersTableProps<TValue>) {\n const { data: session } = authClient.useSession()\n const { data, error, isPending } = useUsers()\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n\n const table = useReactTable({\n data: data?.users ?? [],\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n meta: {\n currentUser: session?.user\n ? {\n id: session.user.id,\n email: session.user.email,\n name: session.user.name,\n image: session.user.image,\n role: (session.user as { role?: string }).role || 'member',\n }\n : null,\n },\n state: { sorting, columnFilters, columnVisibility },\n })\n\n return (\n <div className=\"space-y-4\">\n <div className=\"bg-card border overflow-hidden rounded-lg corner-squircle\">\n <Table>\n <TableHeader className=\"bg-secondary\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-muted-foreground\">Loading users...</div>\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-destructive\">Error: {error.message}</div>\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No users found.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n <div className=\"flex items-center justify-end space-x-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n >\n Previous\n </Button>\n <div className=\"text-sm text-muted-foreground\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount() || 1}\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n >\n Next\n </Button>\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Preset scaffolder: copy preset schemas into cms/schemas/ and run generate\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { runFormPipeline } from '../../generators/form-pipeline/index.js'\nimport { runEntityPipeline, runSinglePipeline } from '../../generators/index.js'\nimport type { FormSchema, Schema } from '../../types.js'\nimport type { Preset } from '../prompts/features.js'\nimport { blogCategoriesSchema } from '../templates/presets/blog-categories.js'\nimport { blogPostsSchema } from '../templates/presets/blog-posts.js'\nimport { defaultSettingsSchema } from '../templates/presets/default-settings.js'\nimport { fullContactSchema } from '../templates/presets/full-contact.js'\nimport { fullNavigationSchema } from '../templates/presets/full-navigation.js'\n\nexport interface PresetScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n preset: Preset\n}\n\nexport interface PresetScaffoldResult {\n schemas: string[]\n generatedFiles: string[]\n errors: string[]\n}\n\ninterface PresetSchema {\n filename: string\n content: string\n isForm: boolean\n isSingle: boolean\n}\n\nfunction getPresetSchemas(preset: Preset): PresetSchema[] {\n // Settings schema is always included (even for blank preset)\n const schemas: PresetSchema[] = [\n {\n filename: 'settings.json',\n content: defaultSettingsSchema(),\n isForm: false,\n isSingle: true\n }\n ]\n\n if (preset !== 'blank') {\n schemas.push(\n {\n filename: 'categories.json',\n content: blogCategoriesSchema(),\n isForm: false,\n isSingle: false\n },\n { filename: 'posts.json', content: blogPostsSchema(), isForm: false, isSingle: false }\n )\n }\n\n if (preset === 'full') {\n schemas.push(\n {\n filename: 'navigation.json',\n content: fullNavigationSchema(),\n isForm: false,\n isSingle: false\n },\n {\n filename: 'forms/contact.json',\n content: fullContactSchema(),\n isForm: true,\n isSingle: false\n }\n )\n }\n\n return schemas\n}\n\n/**\n * Apply preset: write schema files and run entity generation for each\n */\nexport function scaffoldPreset({\n cwd,\n config,\n preset\n}: PresetScaffoldOptions): PresetScaffoldResult {\n const result: PresetScaffoldResult = {\n schemas: [],\n generatedFiles: [],\n errors: []\n }\n\n const schemasDir = path.join(cwd, config.paths?.schemas ?? './cms/schemas')\n const presetSchemas = getPresetSchemas(preset)\n\n // 1. Write all schema files first\n for (const ps of presetSchemas) {\n const filePath = path.join(schemasDir, ps.filename)\n const dir = path.dirname(filePath)\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n\n fs.writeFileSync(filePath, ps.content, 'utf-8')\n result.schemas.push(ps.filename)\n }\n\n // 2. Run pipelines for each schema\n for (const ps of presetSchemas) {\n try {\n if (ps.isForm) {\n const schema = JSON.parse(ps.content) as FormSchema\n const pipelineResult = runFormPipeline(schema, cwd, config, { force: true, silent: true })\n result.generatedFiles.push(...pipelineResult.files)\n if (!pipelineResult.success) {\n result.errors.push(...pipelineResult.errors.map((e) => `${ps.filename}: ${e}`))\n }\n } else if (ps.isSingle) {\n const schema = JSON.parse(ps.content) as Schema\n const pipelineResult = runSinglePipeline(schema, cwd, config, {\n force: true,\n silent: true\n })\n result.generatedFiles.push(...pipelineResult.files)\n if (!pipelineResult.success) {\n result.errors.push(...pipelineResult.errors.map((e) => `${ps.filename}: ${e}`))\n }\n } else {\n const schema = JSON.parse(ps.content) as Schema\n const pipelineResult = runEntityPipeline(schema, cwd, config, {\n force: true,\n silent: true\n })\n result.generatedFiles.push(...pipelineResult.files)\n if (!pipelineResult.success) {\n result.errors.push(...pipelineResult.errors.map((e) => `${ps.filename}: ${e}`))\n }\n }\n } catch (err) {\n result.errors.push(`${ps.filename}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n return result\n}\n","/**\n * Blog preset: categories.json schema\n * Simple entity with name, slug, description, color\n */\nexport function blogCategoriesSchema(): string {\n return JSON.stringify(\n {\n name: 'categories',\n label: 'Categories',\n description: 'Organize posts with categories',\n icon: 'Tag',\n navGroup: { label: 'Blog', icon: 'BookOpen' },\n fields: [\n {\n name: 'name',\n type: 'string',\n label: 'Name',\n required: true,\n hint: 'Category name'\n },\n {\n name: 'slug',\n type: 'string',\n label: 'Slug',\n hint: 'URL-friendly identifier (auto-generated from name)',\n hidden: true\n },\n {\n name: 'description',\n type: 'text',\n label: 'Description',\n hint: 'Optional description of the category'\n },\n {\n name: 'color',\n type: 'string',\n label: 'Color',\n hint: 'Optional color code for UI display (e.g., #3B82F6)'\n }\n ],\n columns: [\n {\n accessorKey: 'name',\n header: 'Name',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'slug',\n header: 'Slug',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'description',\n header: 'Description',\n type: 'text',\n sortable: false\n },\n {\n accessorKey: 'createdAt',\n header: 'Created',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n create: true,\n edit: true,\n delete: true\n },\n search: {\n fields: ['name', 'description']\n },\n autoSlugify: {\n enabled: true,\n sourceField: 'name',\n targetField: 'slug'\n }\n },\n null,\n 2\n )\n}\n","/**\n * Blog preset: posts.json schema\n * Entity with M2M relationship to categories, richtext content, auto-slugify\n */\nexport function blogPostsSchema(): string {\n return JSON.stringify(\n {\n name: 'posts',\n label: 'Posts',\n description: 'Manage blog posts and articles',\n icon: 'FileText',\n navGroup: { label: 'Blog', icon: 'BookOpen' },\n fields: [\n {\n name: 'title',\n type: 'string',\n label: 'Title',\n required: true\n },\n {\n name: 'slug',\n type: 'string',\n label: 'Slug',\n hint: 'URL-friendly identifier (auto-generated from title)',\n hidden: true\n },\n {\n name: 'categories',\n type: 'relationship',\n relationship: 'categories',\n label: 'Categories',\n multiple: true,\n hint: 'Assign one or more categories'\n },\n {\n name: 'excerpt',\n type: 'text',\n label: 'Excerpt',\n hint: 'Short summary for listing pages'\n },\n {\n name: 'coverImage',\n type: 'image',\n label: 'Cover Image'\n },\n {\n name: 'content',\n type: 'richtext',\n label: 'Content',\n output: 'html'\n }\n ],\n columns: [\n {\n accessorKey: 'title',\n header: 'Title',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'published',\n header: 'Status',\n type: 'boolean',\n sortable: true\n },\n {\n accessorKey: 'updatedAt',\n header: 'Updated',\n type: 'date',\n sortable: true\n },\n {\n accessorKey: 'createdAt',\n header: 'Created',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n create: true,\n edit: true,\n delete: true,\n draft: true\n },\n search: {\n fields: ['title', 'excerpt']\n },\n autoSlugify: {\n enabled: true,\n sourceField: 'title',\n targetField: 'slug'\n }\n },\n null,\n 2\n )\n}\n","/**\n * Default settings schema (applied to ALL presets including blank)\n * Generates a singleton form at /cms/settings\n */\nexport function defaultSettingsSchema(): string {\n return JSON.stringify(\n {\n name: 'settings',\n type: 'single',\n label: 'Settings',\n description: 'General site settings',\n icon: 'Settings',\n fields: [\n { name: 'siteName', type: 'string', label: 'Site Name', default: 'BetterStart' },\n { name: 'tagline', type: 'string', label: 'Tagline' },\n { name: 'separator1', type: 'separator' },\n { name: 'logo', type: 'image', label: 'Logo' },\n { name: 'favicon', type: 'image', label: 'Favicon' }\n ]\n },\n null,\n 2\n )\n}\n","/**\n * Full preset: contact.json form schema\n * Public contact form with admin submission viewer\n */\nexport function fullContactSchema(): string {\n return JSON.stringify(\n {\n name: 'contact',\n label: 'Contact Form',\n description: 'Website contact form submissions',\n icon: 'Mail',\n submitButtonText: 'Send Message',\n successMessage: \"Thank you! We'll get back to you soon.\",\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Full Name',\n placeholder: 'Jane Doe',\n required: true,\n minLength: 2,\n maxLength: 100\n },\n {\n name: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'jane@example.com',\n required: true\n },\n {\n name: 'subject',\n type: 'select',\n label: 'Subject',\n required: true,\n options: [\n { label: 'General Inquiry', value: 'general' },\n { label: 'Support', value: 'support' },\n { label: 'Feedback', value: 'feedback' },\n { label: 'Other', value: 'other' }\n ]\n },\n {\n name: 'message',\n type: 'textarea',\n label: 'Message',\n placeholder: 'How can we help?',\n required: true,\n minLength: 10\n }\n ],\n columns: [\n {\n accessorKey: 'name',\n header: 'Name',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'email',\n header: 'Email',\n type: 'email',\n sortable: true\n },\n {\n accessorKey: 'subject',\n header: 'Subject',\n type: 'badge',\n sortable: true\n },\n {\n accessorKey: 'submittedAt',\n header: 'Submitted',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n export: true,\n delete: true\n }\n },\n null,\n 2\n )\n}\n","/**\n * Full preset: navigation.json schema\n * Entity for managing website navigation menus with nested items\n */\nexport function fullNavigationSchema(): string {\n return JSON.stringify(\n {\n name: 'navigation',\n label: 'Navigation',\n description: 'Manage website navigation menus',\n icon: 'Navigation',\n fields: [\n {\n name: 'name',\n type: 'string',\n label: 'Name',\n required: true,\n hint: 'Navigation name (e.g., Main, Footer)'\n },\n {\n name: 'slug',\n type: 'string',\n label: 'Slug',\n hint: 'URL-friendly identifier (auto-generated from name)',\n hidden: true\n },\n {\n name: 'navItems',\n type: 'list',\n label: 'Navigation Items',\n fields: [\n {\n name: 'title',\n type: 'string',\n label: 'Title'\n },\n {\n name: 'url',\n type: 'string',\n label: 'URL Path'\n }\n ]\n }\n ],\n columns: [\n {\n accessorKey: 'name',\n header: 'Name',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'createdAt',\n header: 'Created',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n create: true,\n edit: true,\n delete: true\n },\n autoSlugify: {\n enabled: true,\n sourceField: 'name',\n targetField: 'slug'\n }\n },\n null,\n 2\n )\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nconst SOURCE_LINES = ['@source \"../cms/**/*.{ts,tsx}\";', '@source \"./(cms)/**/*.{ts,tsx}\";']\nconst SOURCE_LINES_SRC = ['@source \"../../cms/**/*.{ts,tsx}\";', '@source \"./(cms)/**/*.{ts,tsx}\";']\n\n// Tailwind v4 @theme tokens that map CSS vars to utility classes.\n// These let Tailwind generate bg-primary, text-muted-foreground, border-border, etc.\nconst CMS_THEME_BLOCK = `\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-destructive-foreground: var(--destructive-foreground);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-input-border: var(--input-border);\n --color-ring: var(--ring);\n --color-chart-1: var(--chart-1);\n --color-chart-2: var(--chart-2);\n --color-chart-3: var(--chart-3);\n --color-chart-4: var(--chart-4);\n --color-chart-5: var(--chart-5);\n --color-sidebar: var(--sidebar);\n --color-sidebar-foreground: var(--sidebar-foreground);\n --color-sidebar-primary: var(--sidebar-primary);\n --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);\n --color-sidebar-accent: var(--sidebar-accent);\n --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);\n --color-sidebar-border: var(--sidebar-border);\n --color-sidebar-ring: var(--sidebar-ring);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n}`\n\n/**\n * Find the main CSS file that imports Tailwind.\n */\nfunction findMainCss(cwd: string): string | undefined {\n const candidates = [\n 'src/app/globals.css',\n 'app/globals.css',\n 'src/app/global.css',\n 'app/global.css',\n 'src/app/app.css',\n 'app/app.css',\n 'src/globals.css',\n 'globals.css'\n ]\n\n for (const candidate of candidates) {\n const filePath = path.join(cwd, candidate)\n if (fs.existsSync(filePath)) {\n return filePath\n }\n }\n return undefined\n}\n\n/**\n * Append @source directive and @theme tokens to the user's main CSS file\n * so Tailwind scans CMS component classes and generates utility classes.\n */\nexport function scaffoldTailwind(\n cwd: string,\n hasSrcDir: boolean\n): { file: string | null; appended: boolean } {\n const cssFile = findMainCss(cwd)\n if (!cssFile) {\n return { file: null, appended: false }\n }\n\n let content = fs.readFileSync(cssFile, 'utf-8')\n let changed = false\n\n // 1. Add @source directives if not present\n const sourceLines = hasSrcDir ? SOURCE_LINES_SRC : SOURCE_LINES\n const missingLines = sourceLines.filter((sl) => !content.includes(sl))\n if (missingLines.length > 0) {\n const lines = content.split('\\n')\n let insertIndex = 0\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim()\n if (\n trimmed.startsWith('@import') ||\n trimmed.startsWith('@source') ||\n trimmed.startsWith('@plugin')\n ) {\n insertIndex = i + 1\n }\n }\n lines.splice(insertIndex, 0, ...missingLines)\n content = lines.join('\\n')\n changed = true\n }\n\n // 2. Add @theme tokens if not already present\n if (!content.includes('--color-primary')) {\n // If there's an existing @theme inline block, merge into it.\n // Otherwise append the full block at the end.\n const themeMatch = content.match(/@theme\\s+inline\\s*\\{/)\n if (themeMatch && themeMatch.index !== undefined) {\n // Find the closing brace of the existing @theme block\n let braceDepth = 0\n let insertPos = -1\n for (let i = themeMatch.index; i < content.length; i++) {\n if (content[i] === '{') braceDepth++\n if (content[i] === '}') {\n braceDepth--\n if (braceDepth === 0) {\n insertPos = i\n break\n }\n }\n }\n if (insertPos !== -1) {\n // Extract the existing @theme block content to avoid duplicates\n const existingBlock = content.slice(themeMatch.index, insertPos)\n const varsOnly = CMS_THEME_BLOCK.split('\\n')\n .filter((l) => l.trim().startsWith('--'))\n .filter((l) => {\n const varName = l.trim().split(':')[0]!.trim()\n return !existingBlock.includes(varName)\n })\n .map((l) => ` ${l.trim()}`)\n .join('\\n')\n if (varsOnly) {\n content = `${content.slice(0, insertPos)}${varsOnly}\\n${content.slice(insertPos)}`\n changed = true\n }\n }\n } else {\n // No existing @theme block — append the full block\n content = `${content}\\n${CMS_THEME_BLOCK}\\n`\n changed = true\n }\n }\n\n if (changed) {\n fs.writeFileSync(cssFile, content, 'utf-8')\n }\n\n return { file: cssFile, appended: changed }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\n// Strip line and block comments from JSON, respecting quoted strings.\nfunction stripJsonComments(input: string): string {\n let result = ''\n let i = 0\n while (i < input.length) {\n // Inside a string — copy until closing quote\n if (input[i] === '\"') {\n let j = i + 1\n while (j < input.length) {\n if (input[j] === '\\\\') {\n j += 2\n continue\n }\n if (input[j] === '\"') {\n j++\n break\n }\n j++\n }\n result += input.slice(i, j)\n i = j\n // Line comment\n } else if (input[i] === '/' && input[i + 1] === '/') {\n const nl = input.indexOf('\\n', i)\n i = nl === -1 ? input.length : nl\n // Block comment\n } else if (input[i] === '/' && input[i + 1] === '*') {\n const end = input.indexOf('*/', i + 2)\n i = end === -1 ? input.length : end + 2\n } else {\n result += input[i]\n i++\n }\n }\n return result\n}\n\nconst CMS_PATH_ALIASES: Record<string, string[]> = {\n '@cms/*': ['./cms/*'],\n '@cms/db': ['./cms/db/client'],\n '@cms/db/schema': ['./cms/db/schema'],\n '@cms/actions/*': ['./cms/lib/actions/*'],\n '@cms/auth': ['./cms/lib/auth/auth'],\n '@cms/auth/client': ['./cms/lib/auth/auth-client'],\n '@cms/auth/middleware': ['./cms/lib/auth/middleware'],\n '@cms/hooks/*': ['./cms/hooks/*'],\n '@cms/components/*': ['./cms/components/*'],\n '@cms/types': ['./cms/types'],\n '@cms/types/*': ['./cms/types/*'],\n '@cms/utils/*': ['./cms/utils/*'],\n '@cms/data/*': ['./cms/data/*'],\n '@cms/cache/*': ['./cms/lib/cache/*']\n}\n\n/**\n * Append @cms/* path aliases to tsconfig.json.\n * Preserves existing content and only adds missing aliases.\n */\nexport function scaffoldTsconfig(cwd: string): { added: string[]; skipped: string[] } {\n const tsconfigPath = path.join(cwd, 'tsconfig.json')\n const added: string[] = []\n const skipped: string[] = []\n\n if (!fs.existsSync(tsconfigPath)) {\n skipped.push('tsconfig.json not found')\n return { added, skipped }\n }\n\n const raw = fs.readFileSync(tsconfigPath, 'utf-8')\n\n // Strip JSON comments while preserving string contents.\n // Walks character-by-character to avoid mangling strings that contain /* or //.\n const stripped = stripJsonComments(raw)\n // Remove trailing commas before } or ]\n .replace(/,\\s*([\\]}])/g, '$1')\n\n let tsconfig: Record<string, unknown>\n try {\n tsconfig = JSON.parse(stripped)\n } catch {\n skipped.push('Failed to parse tsconfig.json')\n return { added, skipped }\n }\n\n const compilerOptions = (tsconfig.compilerOptions ?? {}) as Record<string, unknown>\n const paths = (compilerOptions.paths ?? {}) as Record<string, string[]>\n\n for (const [alias, target] of Object.entries(CMS_PATH_ALIASES)) {\n if (alias in paths) {\n skipped.push(alias)\n } else {\n paths[alias] = target\n added.push(alias)\n }\n }\n\n compilerOptions.paths = paths\n tsconfig.compilerOptions = compilerOptions\n\n fs.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\\n`, 'utf-8')\n\n return { added, skipped }\n}\n","/**\n * seed command — create initial admin user via Better Auth\n *\n * Generates a seed script at cms/scripts/seed.ts and runs it with tsx.\n * The script uses Better Auth's server API to create the user, then\n * sets the role to 'admin' via a direct database update.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\n\nexport function buildSeedScript(): string {\n // Self-contained: inlines DB + auth setup so tsx doesn't need @cms/* aliases.\n // Only relative import is ../db/schema which uses npm packages only.\n return `/**\n * BetterStart CMS — Seed Script\n * Creates the initial admin user\n * AUTO-GENERATED — safe to delete after running\n */\n\nimport { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\n// Load .env.local (inline — avoids @next/env dependency)\nfor (const envFile of ['.env.local', '.env']) {\n try {\n const content = readFileSync(resolve(process.cwd(), envFile), 'utf-8')\n for (const line of content.split('\\\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx).trim()\n const val = trimmed.slice(eqIdx + 1).trim().replace(/^['\"]|['\"]$/g, '')\n if (!process.env[key]) process.env[key] = val\n }\n } catch {}\n}\n\nimport { neon } from '@neondatabase/serverless'\nimport { drizzle } from 'drizzle-orm/neon-http'\nimport { eq } from 'drizzle-orm'\nimport * as schema from '../db/schema'\nimport { betterAuth } from 'better-auth'\nimport { drizzleAdapter } from 'better-auth/adapters/drizzle'\n\n// Inline DB connection (mirrors cms/db/client.ts)\nconst sql = neon(process.env.BETTERSTART_DATABASE_URL!)\nconst db = drizzle({ client: sql, schema })\n\n// Inline auth setup (mirrors cms/lib/auth/auth.ts)\nconst auth = betterAuth({\n secret: process.env.BETTERSTART_AUTH_SECRET,\n baseURL: process.env.BETTERSTART_AUTH_URL,\n basePath: process.env.BETTERSTART_AUTH_BASE_PATH || '/api/cms/auth',\n database: drizzleAdapter(db, {\n provider: 'pg',\n schema: {\n user: schema.user,\n session: schema.session,\n account: schema.account,\n verification: schema.verification,\n },\n }),\n emailAndPassword: { enabled: true, minPasswordLength: 8 },\n user: {\n additionalFields: {\n role: { type: 'string', required: false, defaultValue: 'member', input: false },\n },\n },\n})\n\nconst EMAIL = process.env.SEED_EMAIL!\nconst PASSWORD = process.env.SEED_PASSWORD!\nconst NAME = process.env.SEED_NAME || 'Admin'\nconst OVERWRITE = process.env.SEED_OVERWRITE === 'true'\n\nasync function main() {\n // Check if user already exists\n const existing = await db\n .select({ id: schema.user.id, name: schema.user.name })\n .from(schema.user)\n .where(eq(schema.user.email, EMAIL))\n .then((rows: { id: string; name: string }[]) => rows[0])\n\n if (existing && !OVERWRITE) {\n // Exit code 2 signals \"user exists\" to the CLI\n console.log(\\`EXISTING_USER:\\${existing.name}\\`)\n process.exit(2)\n }\n\n if (existing && OVERWRITE) {\n console.log('\\\\n Replacing existing admin user...')\n // Remove existing account + session rows first (foreign key refs)\n await db.delete(schema.session).where(eq(schema.session.userId, existing.id))\n await db.delete(schema.account).where(eq(schema.account.userId, existing.id))\n await db.delete(schema.user).where(eq(schema.user.id, existing.id))\n } else {\n console.log('\\\\n Creating admin user...')\n }\n\n console.log(\\` Email: \\${EMAIL}\\\\n\\`)\n\n const result = await auth.api.signUpEmail({\n body: { email: EMAIL, password: PASSWORD, name: NAME },\n })\n\n if (!result?.user) {\n console.error(' Failed to create user.')\n process.exit(1)\n }\n\n await db\n .update(schema.user)\n .set({ role: 'admin' })\n .where(eq(schema.user.id, result.user.id))\n\n console.log(\\` Admin user \\${existing ? 'replaced' : 'created'}: \\${EMAIL}\\`)\n console.log(' Role: admin\\\\n')\n process.exit(0)\n}\n\nmain().catch((err) => {\n console.error(' Seed failed:', err.message || err)\n process.exit(1)\n})\n`\n}\n\nexport const seedCommand = new Command('seed')\n .description('Create the initial admin user')\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n clack.intro('BetterStart Seed')\n\n // Load config\n let config: BetterstartConfig\n try {\n config = await resolveConfig(cwd)\n } catch (err) {\n clack.cancel(`Error loading config: ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n }\n\n const cmsDir = config.paths?.cms ?? './cms'\n\n // Prompt for user details\n const email = await clack.text({\n message: 'Admin email',\n placeholder: 'admin@example.com',\n validate: (v) => {\n if (!v || !v.includes('@')) return 'Please enter a valid email'\n }\n })\n if (clack.isCancel(email)) {\n clack.cancel('Cancelled.')\n process.exit(0)\n }\n\n const password = await clack.password({\n message: 'Admin password',\n validate: (v) => {\n if (!v || v.length < 8) return 'Password must be at least 8 characters'\n }\n })\n if (clack.isCancel(password)) {\n clack.cancel('Cancelled.')\n process.exit(0)\n }\n\n const name = await clack.text({\n message: 'Admin name',\n placeholder: 'Admin',\n defaultValue: 'Admin'\n })\n if (clack.isCancel(name)) {\n clack.cancel('Cancelled.')\n process.exit(0)\n }\n\n // Write seed script\n const scriptsDir = path.join(cwd, cmsDir, 'scripts')\n const seedPath = path.join(scriptsDir, 'seed.ts')\n\n if (!fs.existsSync(scriptsDir)) {\n fs.mkdirSync(scriptsDir, { recursive: true })\n }\n fs.writeFileSync(seedPath, buildSeedScript(), 'utf-8')\n\n const { execFile } = await import('node:child_process')\n const tsxBin = path.join(cwd, 'node_modules', '.bin', 'tsx')\n\n const runSeed = (overwrite: boolean) =>\n new Promise<{ code: number; stdout: string }>((resolve, reject) => {\n execFile(\n tsxBin,\n [seedPath],\n {\n cwd,\n env: {\n ...process.env,\n SEED_EMAIL: email,\n SEED_PASSWORD: password,\n SEED_NAME: name || 'Admin',\n ...(overwrite ? { SEED_OVERWRITE: 'true' } : {})\n }\n },\n (err, stdout, stderr) => {\n if (err && 'code' in err && err.code === 2) {\n // Exit code 2 = user already exists\n resolve({ code: 2, stdout })\n } else if (err) {\n reject(new Error(stderr || err.message))\n } else {\n resolve({ code: 0, stdout })\n }\n }\n )\n })\n\n const spinner = clack.spinner()\n spinner.start('Creating admin user...')\n\n try {\n const result = await runSeed(false)\n\n if (result.code === 2) {\n // User already exists — ask to overwrite\n const existingName =\n result.stdout\n .split('\\n')\n .find((l) => l.startsWith('EXISTING_USER:'))\n ?.replace('EXISTING_USER:', '')\n ?.trim() || 'unknown'\n\n spinner.stop(`Account already exists for ${email}`)\n\n const overwrite = await clack.confirm({\n message: `An admin account (${existingName}) already exists with this email. Replace it?`\n })\n if (clack.isCancel(overwrite) || !overwrite) {\n clack.cancel('Seed cancelled.')\n // Clean up before exiting\n try {\n fs.unlinkSync(seedPath)\n } catch {}\n process.exit(0)\n }\n\n spinner.start('Replacing admin user...')\n await runSeed(true)\n spinner.stop('Admin user replaced')\n } else {\n spinner.stop('Admin user created')\n }\n } catch (err) {\n spinner.stop('Failed to create admin user')\n\n const errMsg = err instanceof Error ? err.message : String(err)\n clack.log.error(errMsg)\n clack.log.info('You can run the seed script manually:')\n clack.log.info(\n ` SEED_EMAIL=\"${email}\" SEED_PASSWORD=\"...\" npx tsx ${path.relative(cwd, seedPath)}`\n )\n clack.outro('')\n process.exit(1)\n }\n\n // Clean up seed script\n try {\n fs.unlinkSync(seedPath)\n // Remove scripts dir if empty\n if (fs.existsSync(scriptsDir) && fs.readdirSync(scriptsDir).length === 0) {\n fs.rmdirSync(scriptsDir)\n }\n } catch {\n // Not critical\n }\n\n clack.outro(`Admin user ready: ${email}`)\n })\n","/**\n * remove command — delete generated files, clean schema.ts + navigation.ts\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport readline from 'node:readline'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\nimport { toCamelCase, singularize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Schema.ts Cleaning\n// ============================================================================\n\nfunction findTableEnd(content: string, startIndex: number): number {\n let depth = 0\n let inString = false\n let stringChar = ''\n\n for (let i = startIndex; i < content.length; i++) {\n const char = content[i]\n const prev = i > 0 ? content[i - 1] : ''\n\n if ((char === '\"' || char === \"'\" || char === '`') && prev !== '\\\\') {\n if (!inString) {\n inString = true\n stringChar = char\n } else if (char === stringChar) {\n inString = false\n }\n continue\n }\n if (inString) continue\n\n if (char === '(' || char === '{' || char === '[') depth++\n if (char === ')' || char === '}' || char === ']') depth--\n\n if (depth === 0 && char === ')') {\n // Skip trailing newlines\n let end = i + 1\n while (end < content.length && content[end] === '\\n') end++\n return end\n }\n }\n return content.length\n}\n\nfunction removeTableFromSchema(schemaFilePath: string, name: string): boolean {\n if (!fs.existsSync(schemaFilePath)) return false\n\n let content = fs.readFileSync(schemaFilePath, 'utf-8')\n const variableName = toCamelCase(name)\n let changed = false\n\n // Remove main table\n if (content.includes(`export const ${variableName} =`)) {\n const start = content.indexOf(`export const ${variableName} =`)\n const end = findTableEnd(content, start)\n content = content.slice(0, start) + content.slice(end)\n changed = true\n }\n\n // Remove junction tables (e.g., postCategories for posts schema)\n const singular = singularize(name)\n const junctionPrefix = toCamelCase(singular)\n // Find all exports starting with the singular prefix that are pgTable calls\n const regex = new RegExp(`export const (${junctionPrefix}[A-Z]\\\\w*) = pgTable\\\\(`, 'g')\n let jMatch = regex.exec(content)\n while (jMatch) {\n const jVarName = jMatch[1]\n const jStart = content.indexOf(`export const ${jVarName} =`)\n if (jStart !== -1) {\n const jEnd = findTableEnd(content, jStart)\n content = content.slice(0, jStart) + content.slice(jEnd)\n changed = true\n // Reset regex since content changed\n regex.lastIndex = 0\n jMatch = regex.exec(content)\n } else {\n jMatch = regex.exec(content)\n }\n }\n\n if (changed) {\n // Clean up multiple blank lines\n content = content.replace(/\\n{3,}/g, '\\n\\n')\n fs.writeFileSync(schemaFilePath, content, 'utf-8')\n }\n\n return changed\n}\n\n// ============================================================================\n// Navigation.ts Cleaning\n// ============================================================================\n\nfunction removeFromNavigation(navFilePath: string, name: string): boolean {\n if (!fs.existsSync(navFilePath)) return false\n\n const content = fs.readFileSync(navFilePath, 'utf-8')\n const href = `/cms/${name}`\n\n if (!content.includes(`'${href}'`)) return false\n\n // Flat structure: find the { ... } block containing this href\n const lines = content.split('\\n')\n let startLine = -1\n let endLine = -1\n let depth = 0\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n\n if (startLine === -1 && line.includes(`'${href}'`)) {\n // Walk back to find the opening `{`\n for (let j = i; j >= 0; j--) {\n if (lines[j].trim().startsWith('{')) {\n startLine = j\n break\n }\n }\n }\n\n if (startLine !== -1 && i >= startLine) {\n for (const char of line) {\n if (char === '{') depth++\n if (char === '}') depth--\n }\n if (depth === 0 && line.includes('}')) {\n endLine = i\n break\n }\n }\n }\n\n if (startLine === -1 || endLine === -1) return false\n\n lines.splice(startLine, endLine - startLine + 1)\n\n // Clean up double commas or leading commas\n const updated = lines\n .join('\\n')\n .replace(/,\\s*,/g, ',')\n .replace(/\\[\\s*,/, '[')\n fs.writeFileSync(navFilePath, updated, 'utf-8')\n return true\n}\n\n// ============================================================================\n// Confirmation\n// ============================================================================\n\nasync function promptConfirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout\n })\n return new Promise((resolve) => {\n rl.question(`${message} (y/N) `, (answer) => {\n rl.close()\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes')\n })\n })\n}\n\n// ============================================================================\n// Command\n// ============================================================================\n\nexport const removeCommand = new Command('remove')\n .alias('rm')\n .description('Remove all generated files for an entity or form')\n .argument('<schema>', 'Schema name to remove (e.g. posts, categories, contact)')\n .option('-f, --force', 'Skip confirmation prompt', false)\n .option('--cwd <path>', 'Project root path')\n .action(async (schemaName: string, options: { force: boolean; cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n console.log('\\n BetterStart Remove\\n')\n\n // Load config\n let config: BetterstartConfig\n try {\n config = await resolveConfig(cwd)\n } catch (err) {\n console.error(` Error loading config: ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n }\n\n const cmsDir = config.paths?.cms ?? './cms'\n const pagesDir = config.paths?.pages ?? './src/app/(cms)/cms/(authenticated)'\n const kebabName = toKebabCase(schemaName)\n\n // Collect files/dirs to remove\n const targets: { path: string; label: string; isDir: boolean }[] = []\n\n // Pages directory\n const entityPagesDir = path.join(cwd, pagesDir, schemaName)\n if (fs.existsSync(entityPagesDir)) {\n targets.push({\n path: entityPagesDir,\n label: `${path.join(pagesDir, schemaName)}/`,\n isDir: true\n })\n }\n\n // Actions file\n const actionsFile = path.join(cwd, cmsDir, 'lib', 'actions', `${kebabName}.ts`)\n if (fs.existsSync(actionsFile)) {\n targets.push({\n path: actionsFile,\n label: path.join(cmsDir, 'lib', 'actions', `${kebabName}.ts`),\n isDir: false\n })\n }\n\n // Hook file\n const hookFile = path.join(cwd, cmsDir, 'hooks', `use-${kebabName}.ts`)\n if (fs.existsSync(hookFile)) {\n targets.push({\n path: hookFile,\n label: path.join(cmsDir, 'hooks', `use-${kebabName}.ts`),\n isDir: false\n })\n }\n\n // Check schema.ts for table entry\n const schemaFilePath = path.join(cwd, cmsDir, 'db', 'schema.ts')\n const hasTable =\n fs.existsSync(schemaFilePath) &&\n fs.readFileSync(schemaFilePath, 'utf-8').includes(`export const ${toCamelCase(schemaName)} =`)\n\n // Check navigation.ts for entry\n const navFilePath = path.join(cwd, cmsDir, 'data', 'navigation.ts')\n const hasNavEntry =\n fs.existsSync(navFilePath) &&\n fs.readFileSync(navFilePath, 'utf-8').includes(`'/cms/${schemaName}'`)\n\n if (targets.length === 0 && !hasTable && !hasNavEntry) {\n console.log(` No generated files found for: ${schemaName}`)\n return\n }\n\n // Show what will be removed\n console.log(' Files to remove:\\n')\n for (const t of targets) {\n console.log(` ${t.isDir ? '[dir]' : ' '} ${t.label}`)\n }\n if (hasTable) {\n console.log(` [edit] ${path.join(cmsDir, 'db', 'schema.ts')} (remove table)`)\n }\n if (hasNavEntry) {\n console.log(` [edit] ${path.join(cmsDir, 'data', 'navigation.ts')} (remove entry)`)\n }\n\n // Confirm\n if (!options.force) {\n console.log('')\n const confirmed = await promptConfirm(' Are you sure?')\n if (!confirmed) {\n console.log('\\n Cancelled.\\n')\n return\n }\n }\n\n console.log('')\n\n // Delete files/dirs\n for (const t of targets) {\n if (t.isDir) {\n fs.rmSync(t.path, { recursive: true, force: true })\n } else {\n fs.unlinkSync(t.path)\n }\n console.log(` Removed: ${t.label}`)\n }\n\n // Clean schema.ts\n if (hasTable) {\n removeTableFromSchema(schemaFilePath, schemaName)\n console.log(` Cleaned: ${path.join(cmsDir, 'db', 'schema.ts')}`)\n }\n\n // Clean navigation.ts\n if (hasNavEntry) {\n removeFromNavigation(navFilePath, schemaName)\n console.log(` Cleaned: ${path.join(cmsDir, 'data', 'navigation.ts')}`)\n }\n\n console.log('\\n Removal complete!')\n console.log('\\n Note: You may need to manually:')\n console.log(' - Run a migration to drop the database table')\n console.log(' - Remove the schema file from cms/schemas/')\n console.log(' - Regenerate the cache module (betterstart generate <any-schema>)')\n console.log('')\n })\n","/**\n * setup-r2 command — create a Cloudflare R2 bucket and configure env vars\n *\n * 1. Checks for wrangler CLI\n * 2. Ensures user is logged in to Cloudflare\n * 3. Creates an R2 bucket\n * 4. Enables the r2.dev public URL automatically via CF API\n * 5. Opens the dashboard for API token creation\n * 6. Prompts for credentials and writes them to .env.local\n */\n\nimport { execFileSync, spawnSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport * as p from '@clack/prompts'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\n\nimport { appendEnvVars } from '../utils/env.js'\n\nexport const setupR2Command = new Command('setup-r2')\n .description('Create a Cloudflare R2 bucket and configure storage env vars')\n .option('--cwd <path>', 'Project root path')\n .option('--bucket <name>', 'Bucket name (skips prompt)')\n .action(async (options: { cwd?: string; bucket?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n p.intro(pc.bgCyan(pc.black(' BetterStart — R2 Storage Setup ')))\n\n const s = p.spinner()\n\n // 1. Check for wrangler\n s.start('Looking for wrangler CLI')\n const wrangler = findWrangler(cwd)\n if (!wrangler) {\n s.stop(`${pc.red('✗')} Wrangler CLI not found`)\n p.log.error(\n `Install it first:\\n ${pc.cyan('npm install -g wrangler')}\\n ${pc.dim('or')} ${pc.cyan('npx wrangler --version')}`\n )\n process.exit(1)\n }\n s.stop(`Wrangler: ${pc.cyan(wrangler.bin === 'npx' ? 'npx wrangler' : 'wrangler')}`)\n\n // 2. Check auth / prompt login\n s.start('Checking Cloudflare authentication')\n const whoami = runWrangler(wrangler, ['whoami'], { cwd })\n const whoamiOut = whoami.stdout?.toString() ?? ''\n\n if (whoami.status !== 0 || whoamiOut.includes('Not authenticated')) {\n s.stop(`${pc.yellow('▲')} Not logged in to Cloudflare`)\n const login = await p.confirm({\n message: 'Open browser to log in to Cloudflare?',\n initialValue: true,\n })\n if (p.isCancel(login) || !login) {\n p.cancel('Setup cancelled. Run `wrangler login` manually first.')\n process.exit(0)\n }\n\n s.start('Waiting for Cloudflare login')\n const loginResult = runWrangler(wrangler, ['login'], { cwd, stdio: 'inherit', timeout: 120_000 })\n if (loginResult.status !== 0) {\n s.stop(`${pc.red('✗')} Login failed`)\n p.cancel('Could not authenticate with Cloudflare. Run `wrangler login` manually.')\n process.exit(1)\n }\n s.stop(`${pc.green('✓')} Logged in to Cloudflare`)\n } else {\n // Table format: \"│ Peiris@kasun.io's Account │ <id> │\"\n // Or \"associated with the email user@example.com\"\n const emailMatch = whoamiOut.match(/associated with the email\\s+(\\S+)/i)\n const tableMatch = whoamiOut.match(/│\\s*([^│]+?)\\s*│\\s*[a-f0-9]{32}\\s*│/)\n const accountLabel = emailMatch?.[1] ?? tableMatch?.[1]?.trim() ?? 'authenticated'\n s.stop(`Logged in as ${pc.cyan(accountLabel)}`)\n }\n\n // 3. Get account ID\n s.start('Fetching account ID')\n const accountId = extractAccountId(wrangler, cwd)\n if (!accountId) {\n s.stop(`${pc.red('✗')} Could not determine account ID`)\n p.log.info(\n `You can find it at: ${pc.cyan('https://dash.cloudflare.com/?to=/:account/r2')}`\n )\n process.exit(1)\n }\n s.stop(`Account ID: ${pc.dim(accountId)}`)\n\n // 4. Prompt for bucket name\n let bucketName = options.bucket\n if (!bucketName) {\n const result = await p.text({\n message: 'R2 bucket name',\n placeholder: 'betterstart-uploads',\n defaultValue: 'betterstart-uploads',\n validate: (v) => {\n if (!v || v.length < 3) return 'Bucket name must be at least 3 characters'\n if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(v))\n return 'Bucket name must be lowercase alphanumeric with hyphens, no leading/trailing hyphens'\n },\n })\n if (p.isCancel(result)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n bucketName = result\n }\n\n // 5. Create bucket\n s.start(`Creating R2 bucket: ${bucketName}`)\n\n const createResult = runWrangler(wrangler, ['r2', 'bucket', 'create', bucketName], {\n cwd,\n timeout: 30_000,\n })\n const createOut = (createResult.stdout?.toString() ?? '') + (createResult.stderr?.toString() ?? '')\n\n if (createResult.status !== 0) {\n if (createOut.includes('already exists') || createOut.includes('AlreadyExists')) {\n s.stop(`Bucket ${pc.cyan(bucketName)} already exists — using it`)\n } else {\n s.stop('Failed to create bucket')\n p.log.error(createOut.trim() || 'Unknown error from wrangler')\n process.exit(1)\n }\n } else {\n s.stop(`Created bucket: ${pc.cyan(bucketName)}`)\n }\n\n // 6. Enable r2.dev public URL automatically\n let publicUrl = ''\n const oauthToken = readWranglerToken()\n if (oauthToken) {\n s.start('Enabling public r2.dev URL')\n const domainResult = await enablePublicDomain(accountId, bucketName, oauthToken)\n if (domainResult.success && domainResult.domain) {\n publicUrl = `https://${domainResult.domain}`\n s.stop(`Public URL: ${pc.cyan(publicUrl)}`)\n } else {\n s.stop('Could not enable public URL automatically')\n p.log.warning(domainResult.error ?? 'Unknown error')\n p.log.info(\n `You can enable it manually in the dashboard:\\n ${pc.cyan(`https://dash.cloudflare.com/${accountId}/r2/default/buckets/${bucketName}/settings`)}`\n )\n }\n } else {\n p.log.warning('Could not read wrangler OAuth token — skipping public URL setup')\n p.log.info(\n `Enable it manually: ${pc.cyan(`https://dash.cloudflare.com/${accountId}/r2/default/buckets/${bucketName}/settings`)}`\n )\n }\n\n // 7. Prompt for S3-compatible API credentials\n p.note(\n [\n `Create an R2 API token with ${pc.bold('Object Read & Write')} permission.`,\n '',\n `Dashboard: ${pc.cyan(`https://dash.cloudflare.com/${accountId}/r2/api-tokens`)}`,\n '',\n pc.dim('The dashboard will give you an Access Key ID and Secret Access Key.'),\n ].join('\\n'),\n 'Create R2 API Token'\n )\n\n const openDashboard = await p.confirm({\n message: 'Open the R2 API tokens page in your browser?',\n initialValue: true,\n })\n if (!p.isCancel(openDashboard) && openDashboard) {\n const url = `https://dash.cloudflare.com/${accountId}/r2/api-tokens`\n try {\n execFileSync('open', [url], { stdio: 'pipe', timeout: 5_000 })\n } catch {\n p.log.warning(`Could not open browser. Visit: ${pc.cyan(url)}`)\n }\n }\n\n const credentials = await p.group(\n {\n accessKeyId: () =>\n p.text({\n message: 'R2 Access Key ID',\n placeholder: 'Paste from Cloudflare dashboard',\n validate: (v) => {\n if (!v || v.trim().length < 10) return 'Please paste a valid Access Key ID'\n },\n }),\n secretAccessKey: () =>\n p.password({\n message: 'R2 Secret Access Key',\n validate: (v) => {\n if (!v || v.trim().length < 10) return 'Please paste a valid Secret Access Key'\n },\n }),\n },\n {\n onCancel: () => {\n p.cancel('Setup cancelled.')\n process.exit(0)\n },\n }\n )\n\n // 8. Write env vars to .env.local\n s.start('Writing environment variables')\n const envResult = appendEnvVars(cwd, [\n {\n header: 'Storage (Cloudflare R2)',\n vars: [\n { key: 'BETTERSTART_R2_ACCOUNT_ID', value: accountId },\n { key: 'BETTERSTART_R2_ACCESS_KEY_ID', value: credentials.accessKeyId.trim() },\n { key: 'BETTERSTART_R2_SECRET_ACCESS_KEY', value: credentials.secretAccessKey.trim() },\n { key: 'BETTERSTART_R2_BUCKET_NAME', value: bucketName },\n ...(publicUrl ? [{ key: 'BETTERSTART_R2_PUBLIC_URL', value: publicUrl }] : []),\n ],\n },\n ], new Set([\n 'BETTERSTART_R2_ACCOUNT_ID',\n 'BETTERSTART_R2_ACCESS_KEY_ID',\n 'BETTERSTART_R2_SECRET_ACCESS_KEY',\n 'BETTERSTART_R2_BUCKET_NAME',\n 'BETTERSTART_R2_PUBLIC_URL',\n ]))\n\n const totalChanged = envResult.added.length + envResult.updated.length\n if (totalChanged > 0) {\n s.stop(`Updated .env.local ${pc.dim(`(${envResult.added.length} added, ${envResult.updated.length} updated)`)}`)\n } else {\n s.stop('All R2 env vars already set in .env.local')\n }\n\n // Summary\n const summaryLines = [\n `Bucket: ${pc.cyan(bucketName)}`,\n `Account: ${pc.dim(accountId)}`,\n `Access Key: ${pc.dim(credentials.accessKeyId.trim().slice(0, 8) + '...')}`,\n ]\n if (publicUrl) {\n summaryLines.push(`Public URL: ${pc.cyan(publicUrl)}`)\n }\n summaryLines.push(`Env file: ${pc.dim('.env.local')}`)\n\n p.note(summaryLines.join('\\n'), pc.green('R2 storage configured'))\n\n p.outro('Done! Your CMS can now upload files to R2.')\n })\n\ninterface WranglerRef {\n bin: string\n prefix: string[] // e.g. ['wrangler'] when using npx, [] when direct\n}\n\n/** Find wrangler binary — check local node_modules, global PATH, then npx */\nfunction findWrangler(cwd: string): WranglerRef | null {\n // Check local\n const localBin = path.join(cwd, 'node_modules', '.bin', 'wrangler')\n if (fs.existsSync(localBin)) return { bin: localBin, prefix: [] }\n\n // Check global via which\n const result = spawnSync('which', ['wrangler'], { stdio: 'pipe', timeout: 5_000 })\n if (result.status === 0) {\n const found = result.stdout?.toString().trim()\n if (found) return { bin: found, prefix: [] }\n }\n\n // Fall back to npx — just check it resolves (fast, no download)\n const npxResult = spawnSync('npx', ['wrangler', '--version'], {\n stdio: 'pipe',\n timeout: 15_000,\n })\n if (npxResult.status === 0) return { bin: 'npx', prefix: ['wrangler'] }\n\n return null\n}\n\n/** Run a wrangler command via the resolved ref */\nfunction runWrangler(\n ref: WranglerRef,\n args: string[],\n opts: { cwd: string; timeout?: number; stdio?: 'pipe' | 'inherit' }\n) {\n const fullArgs = [...ref.prefix, ...args]\n return spawnSync(ref.bin, fullArgs, {\n cwd: opts.cwd,\n stdio: opts.stdio ?? 'pipe',\n timeout: opts.timeout ?? 15_000,\n })\n}\n\n/** Extract account ID from wrangler whoami output */\nfunction extractAccountId(ref: WranglerRef, cwd: string): string | null {\n const result = runWrangler(ref, ['whoami'], { cwd })\n const output = result.stdout?.toString() ?? ''\n\n // wrangler whoami prints account ID in format: \"Account ID: <id>\"\n const idMatch = output.match(/Account ID[:\\s]+([a-f0-9]{32})/i)\n if (idMatch) return idMatch[1]\n\n // Table format: look for 32-char hex string\n const hexMatch = output.match(/\\b([a-f0-9]{32})\\b/)\n if (hexMatch) return hexMatch[1]\n\n return null\n}\n\n/** Read the OAuth token from wrangler's config file */\nfunction readWranglerToken(): string | null {\n // Wrangler stores config at platform-specific paths\n const candidates = [\n path.join(os.homedir(), 'Library', 'Preferences', '.wrangler', 'config', 'default.toml'), // macOS\n path.join(os.homedir(), '.config', '.wrangler', 'config', 'default.toml'), // Linux\n path.join(os.homedir(), '.wrangler', 'config', 'default.toml'), // fallback\n ]\n\n if (process.env.WRANGLER_CONFIG_PATH) {\n candidates.unshift(process.env.WRANGLER_CONFIG_PATH)\n }\n if (process.env.XDG_CONFIG_HOME) {\n candidates.unshift(\n path.join(process.env.XDG_CONFIG_HOME, '.wrangler', 'config', 'default.toml')\n )\n }\n\n for (const configPath of candidates) {\n if (!fs.existsSync(configPath)) continue\n try {\n const content = fs.readFileSync(configPath, 'utf-8')\n const match = content.match(/^oauth_token\\s*=\\s*\"([^\"]+)\"/m)\n if (match) return match[1]\n } catch {\n continue\n }\n }\n return null\n}\n\n/** Enable the r2.dev managed public domain on a bucket via Cloudflare API */\nasync function enablePublicDomain(\n accountId: string,\n bucketName: string,\n token: string\n): Promise<{ success: boolean; domain?: string; error?: string }> {\n try {\n const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/r2/buckets/${bucketName}/domains/managed`\n const res = await fetch(url, {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ enabled: true }),\n })\n const data = (await res.json()) as {\n success: boolean\n result?: { domain?: string; enabled?: boolean }\n errors?: Array<{ message: string }>\n }\n if (data.success && data.result?.domain) {\n return { success: true, domain: data.result.domain }\n }\n const errMsg = data.errors?.[0]?.message ?? 'API returned success=false'\n return { success: false, error: errMsg }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : 'fetch failed' }\n }\n}\n","/**\n * uninstall command — fully reverse everything `betterstart init` did.\n * Removes CMS directories, config files, path aliases, CSS modifications,\n * env vars, and dependencies from package.json.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as p from '@clack/prompts'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { cleanCss, cleanEnvFile, cleanTsconfig } from './uninstall-cleaners.js'\n\n// ============================================================================\n// CSS File Finder (shared logic with tailwind scaffolder)\n// ============================================================================\n\nfunction findMainCss(cwd: string): string | undefined {\n const candidates = [\n 'src/app/globals.css',\n 'app/globals.css',\n 'src/app/global.css',\n 'app/global.css',\n 'src/app/app.css',\n 'app/app.css',\n 'src/globals.css',\n 'globals.css'\n ]\n for (const candidate of candidates) {\n const filePath = path.join(cwd, candidate)\n if (fs.existsSync(filePath)) return filePath\n }\n return undefined\n}\n\n// ============================================================================\n// Biome Detection\n// ============================================================================\n\nfunction isCLICreatedBiome(biomePath: string): boolean {\n if (!fs.existsSync(biomePath)) return false\n try {\n const content = JSON.parse(fs.readFileSync(biomePath, 'utf-8'))\n // Check key structural markers that match our template\n return (\n content.$schema?.includes('biomejs.dev') &&\n content.formatter?.indentStyle === 'space' &&\n content.javascript?.formatter?.quoteStyle === 'single' &&\n Array.isArray(content.files?.ignore) &&\n content.files.ignore.includes('.next')\n )\n } catch {\n return false\n }\n}\n\n// ============================================================================\n// Uninstall Plan\n// ============================================================================\n\ninterface UninstallStep {\n label: string\n items: string[]\n count: number\n unit: string\n execute: () => void\n}\n\nfunction buildUninstallPlan(cwd: string): UninstallStep[] {\n const steps: UninstallStep[] = []\n const hasSrc = fs.existsSync(path.join(cwd, 'src'))\n const appBase = hasSrc ? 'src/app' : 'app'\n\n // Step 1: CMS directories\n const dirs: string[] = []\n const cmsDir = path.join(cwd, 'cms')\n const cmsRouteGroup = path.join(cwd, appBase, '(cms)')\n if (fs.existsSync(cmsDir)) dirs.push('cms/')\n if (fs.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`)\n\n if (dirs.length > 0) {\n steps.push({\n label: 'CMS directories',\n items: dirs,\n count: dirs.length,\n unit: dirs.length === 1 ? 'directory' : 'directories',\n execute() {\n if (fs.existsSync(cmsDir)) fs.rmSync(cmsDir, { recursive: true, force: true })\n if (fs.existsSync(cmsRouteGroup)) fs.rmSync(cmsRouteGroup, { recursive: true, force: true })\n }\n })\n }\n\n // Step 2: Config files\n const configFiles: string[] = []\n const configPaths: string[] = []\n const candidates = [\n ['cms.config.ts', path.join(cwd, 'cms.config.ts')],\n ['drizzle.config.ts', path.join(cwd, 'drizzle.config.ts')],\n ['CMS.md', path.join(cwd, 'CMS.md')]\n ] as const\n\n for (const [label, fullPath] of candidates) {\n if (fs.existsSync(fullPath)) {\n configFiles.push(label)\n configPaths.push(fullPath)\n }\n }\n\n const biomePath = path.join(cwd, 'biome.json')\n if (isCLICreatedBiome(biomePath)) {\n configFiles.push('biome.json (CLI-created)')\n configPaths.push(biomePath)\n }\n\n if (configFiles.length > 0) {\n steps.push({\n label: 'Config files',\n items: configFiles,\n count: configFiles.length,\n unit: configFiles.length === 1 ? 'file' : 'files',\n execute() {\n for (const p of configPaths) {\n if (fs.existsSync(p)) fs.unlinkSync(p)\n }\n }\n })\n }\n\n // Step 3: tsconfig.json @cms/* aliases\n const tsconfigPath = path.join(cwd, 'tsconfig.json')\n if (fs.existsSync(tsconfigPath)) {\n const content = fs.readFileSync(tsconfigPath, 'utf-8')\n const aliasMatches = content.match(/\"@cms\\//g)\n if (aliasMatches && aliasMatches.length > 0) {\n const aliasCount = aliasMatches.length\n steps.push({\n label: 'tsconfig.json path aliases',\n items: [`@cms/* aliases in tsconfig.json`],\n count: aliasCount,\n unit: aliasCount === 1 ? 'alias' : 'aliases',\n execute() {\n cleanTsconfig(tsconfigPath)\n }\n })\n }\n }\n\n // Step 4: CSS @source lines\n const cssFile = findMainCss(cwd)\n if (cssFile) {\n const cssContent = fs.readFileSync(cssFile, 'utf-8')\n const sourceLines = cssContent\n .split('\\n')\n .filter((l) => /^@source\\s+\"[^\"]*cms[^\"]*\";\\s*$/.test(l))\n if (sourceLines.length > 0) {\n const relCss = path.relative(cwd, cssFile)\n steps.push({\n label: `CSS @source lines (${relCss})`,\n items: [`@source lines in ${relCss}`],\n count: sourceLines.length,\n unit: sourceLines.length === 1 ? 'line' : 'lines',\n execute() {\n cleanCss(cssFile)\n }\n })\n }\n }\n\n // Step 5: .env.local BETTERSTART_* vars\n const envPath = path.join(cwd, '.env.local')\n if (fs.existsSync(envPath)) {\n const envContent = fs.readFileSync(envPath, 'utf-8')\n const bsVars = envContent\n .split('\\n')\n .filter((l) => l.trim().match(/^BETTERSTART_\\w+=/))\n .map((l) => l.split('=')[0]!)\n if (bsVars.length > 0) {\n steps.push({\n label: '.env.local variables',\n items: ['BETTERSTART_* vars in .env.local'],\n count: bsVars.length,\n unit: bsVars.length === 1 ? 'variable' : 'variables',\n execute() {\n cleanEnvFile(envPath)\n }\n })\n }\n }\n\n return steps\n}\n\n// ============================================================================\n// Command\n// ============================================================================\n\nexport const uninstallCommand = new Command('uninstall')\n .description('Remove all CMS files and undo modifications made by betterstart init')\n .option('-f, --force', 'Skip all confirmation prompts', false)\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { force: boolean; cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n p.intro(pc.bgRed(pc.white(' BetterStart Uninstall ')))\n\n // Build the plan\n const steps = buildUninstallPlan(cwd)\n\n if (steps.length === 0) {\n p.log.success(`${pc.green('✓')} Nothing to remove — project is already clean.`)\n p.outro('Done')\n return\n }\n\n // Show plan as a formatted note box\n const planLines = steps.map((step) => {\n const names = step.items.join(' ')\n const countLabel = pc.dim(`${step.count} ${step.unit}`)\n return `${pc.red('×')} ${names} ${countLabel}`\n })\n p.note(planLines.join('\\n'), 'Uninstall plan')\n\n // Single confirmation for everything\n if (!options.force) {\n const confirmed = await p.confirm({\n message: 'Proceed with uninstall?',\n initialValue: false\n })\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Uninstall cancelled.')\n process.exit(0)\n }\n }\n\n // Execute all steps with a single spinner\n const s = p.spinner()\n s.start(steps[0]!.label)\n for (const step of steps) {\n s.message(step.label)\n step.execute()\n }\n const parts = steps.map((step) => `${step.count} ${step.unit}`)\n s.stop(`Removed ${parts.join(', ')}`)\n\n p.note(pc.dim('Database tables were NOT dropped — drop them manually if needed.'), 'Next steps')\n\n p.outro('Uninstall complete')\n })\n","/**\n * Cleaner functions for `betterstart uninstall`.\n * Each function modifies a single file type and returns what was removed.\n */\n\nimport fs from 'node:fs'\n\n// ============================================================================\n// JSON Comment Stripper (shared with tsconfig scaffolder)\n// ============================================================================\n\nfunction stripJsonComments(input: string): string {\n let result = ''\n let i = 0\n while (i < input.length) {\n if (input[i] === '\"') {\n let j = i + 1\n while (j < input.length) {\n if (input[j] === '\\\\') {\n j += 2\n continue\n }\n if (input[j] === '\"') {\n j++\n break\n }\n j++\n }\n result += input.slice(i, j)\n i = j\n } else if (input[i] === '/' && input[i + 1] === '/') {\n const nl = input.indexOf('\\n', i)\n i = nl === -1 ? input.length : nl\n } else if (input[i] === '/' && input[i + 1] === '*') {\n const end = input.indexOf('*/', i + 2)\n i = end === -1 ? input.length : end + 2\n } else {\n result += input[i]\n i++\n }\n }\n return result\n}\n\n// ============================================================================\n// cleanTsconfig\n// ============================================================================\n\n/**\n * Remove all `@cms/*` path aliases from tsconfig.json.\n * Returns the list of removed alias keys.\n */\nexport function cleanTsconfig(tsconfigPath: string): string[] {\n if (!fs.existsSync(tsconfigPath)) return []\n\n const raw = fs.readFileSync(tsconfigPath, 'utf-8')\n const stripped = stripJsonComments(raw).replace(/,\\s*([\\]}])/g, '$1')\n\n let tsconfig: Record<string, unknown>\n try {\n tsconfig = JSON.parse(stripped)\n } catch {\n return []\n }\n\n const compilerOptions = (tsconfig.compilerOptions ?? {}) as Record<string, unknown>\n const paths = (compilerOptions.paths ?? {}) as Record<string, string[]>\n\n const removed: string[] = []\n for (const key of Object.keys(paths)) {\n if (key.startsWith('@cms/') || key === '@cms/*') {\n removed.push(key)\n delete paths[key]\n }\n }\n\n if (removed.length === 0) return []\n\n if (Object.keys(paths).length === 0) {\n compilerOptions.paths = undefined\n } else {\n compilerOptions.paths = paths\n }\n tsconfig.compilerOptions = compilerOptions\n\n fs.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\\n`, 'utf-8')\n return removed\n}\n\n// ============================================================================\n// cleanCss\n// ============================================================================\n\n/**\n * Remove @source lines containing \"cms\" from a CSS file.\n * Returns the removed lines.\n */\nexport function cleanCss(cssPath: string): string[] {\n if (!fs.existsSync(cssPath)) return []\n\n const content = fs.readFileSync(cssPath, 'utf-8')\n const lines = content.split('\\n')\n\n const sourcePattern = /^@source\\s+\"[^\"]*cms[^\"]*\";\\s*$/\n const removed: string[] = []\n const kept: string[] = []\n\n for (const line of lines) {\n if (sourcePattern.test(line)) {\n removed.push(line.trim())\n } else {\n kept.push(line)\n }\n }\n\n if (removed.length === 0) return []\n\n // Clean up resulting double blank lines\n const cleaned = kept.join('\\n').replace(/\\n{3,}/g, '\\n\\n')\n fs.writeFileSync(cssPath, cleaned, 'utf-8')\n return removed\n}\n\n// ============================================================================\n// cleanEnvFile\n// ============================================================================\n\n/**\n * Remove BETTERSTART_* vars and the BetterStart header block from .env.local.\n * Returns the removed variable names.\n */\nexport function cleanEnvFile(envPath: string): string[] {\n if (!fs.existsSync(envPath)) return []\n\n const content = fs.readFileSync(envPath, 'utf-8')\n const lines = content.split('\\n')\n const removed: string[] = []\n const kept: string[] = []\n\n // Track header block lines to remove\n const headerPattern = /^# =+$/\n const headerTextPattern = /^# BetterStart CMS$/\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n const trimmed = line.trim()\n\n // Remove BETTERSTART_* variable lines\n if (trimmed.match(/^BETTERSTART_\\w+=/)) {\n const key = trimmed.split('=')[0]!\n removed.push(key)\n continue\n }\n\n // Remove header block: # ====... / # BetterStart CMS / # ====...\n if (headerPattern.test(trimmed)) {\n const next = lines[i + 1]?.trim()\n const afterNext = lines[i + 2]?.trim()\n if (next && headerTextPattern.test(next) && afterNext && headerPattern.test(afterNext)) {\n i += 2 // skip all 3 header lines\n continue\n }\n }\n\n // Remove section comment headers that only precede BETTERSTART_ vars\n // e.g., \"# Database (Neon)\" followed by BETTERSTART_DATABASE_URL\n if (trimmed.startsWith('#') && !headerPattern.test(trimmed)) {\n const nextNonEmpty = findNextNonEmptyLine(lines, i + 1)\n if (nextNonEmpty?.match(/^BETTERSTART_\\w+=/)) {\n continue // skip this comment header\n }\n }\n\n kept.push(line)\n }\n\n if (removed.length === 0) return []\n\n // Clean up multiple blank lines\n const result = kept\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n\n if (result === '') {\n // File is now empty — delete it\n fs.unlinkSync(envPath)\n } else {\n fs.writeFileSync(envPath, `${result}\\n`, 'utf-8')\n }\n\n return removed\n}\n\nfunction findNextNonEmptyLine(lines: string[], startIndex: number): string | null {\n for (let i = startIndex; i < lines.length; i++) {\n const trimmed = lines[i]!.trim()\n if (trimmed !== '') return trimmed\n }\n return null\n}\n\n// ============================================================================\n// cleanPackageJsonDeps\n// ============================================================================\n\n/**\n * Remove CMS dependencies from package.json.\n * Returns the removed dep and devDep names.\n */\nexport function cleanPackageJsonDeps(\n pkgPath: string,\n allDeps: string[],\n allDevDeps: string[]\n): { removed: string[]; removedDev: string[] } {\n if (!fs.existsSync(pkgPath)) return { removed: [], removedDev: [] }\n\n const content = fs.readFileSync(pkgPath, 'utf-8')\n let pkg: Record<string, unknown>\n try {\n pkg = JSON.parse(content)\n } catch {\n return { removed: [], removedDev: [] }\n }\n\n const deps = (pkg.dependencies ?? {}) as Record<string, string>\n const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>\n\n // Build lookup set: handle version-pinned names like @types/markdown-it@13 → @types/markdown-it\n const depNames = new Set(\n allDeps.map((d) =>\n d\n .split('@')\n .slice(0, d.startsWith('@') ? 2 : 1)\n .join('@')\n )\n )\n const devDepNames = new Set(\n allDevDeps.map((d) =>\n d\n .split('@')\n .slice(0, d.startsWith('@') ? 2 : 1)\n .join('@')\n )\n )\n\n const removed: string[] = []\n for (const name of Object.keys(deps)) {\n if (depNames.has(name)) {\n delete deps[name]\n removed.push(name)\n }\n }\n\n const removedDev: string[] = []\n for (const name of Object.keys(devDeps)) {\n if (devDepNames.has(name)) {\n delete devDeps[name]\n removedDev.push(name)\n }\n }\n\n if (removed.length === 0 && removedDev.length === 0) {\n return { removed: [], removedDev: [] }\n }\n\n pkg.dependencies = deps\n pkg.devDependencies = devDeps\n fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`, 'utf-8')\n\n return { removed, removedDev }\n}\n","/**\n * update-component command — update individual CMS components from the latest CLI templates\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport fsExtra from 'fs-extra'\nimport { resolveConfig } from '../config/resolver.js'\nimport { cmsGlobalsCssTemplate } from '../init/templates/components/cms-globals.js'\nimport { dataTableTemplate } from '../init/templates/components/data-table/data-table.js'\nimport { dataTablePaginationTemplate } from '../init/templates/components/data-table/data-table-pagination.js'\nimport { dataTableToolbarTemplate } from '../init/templates/components/data-table/data-table-toolbar.js'\nimport { cmsHeaderTemplate } from '../init/templates/components/layout/cms-header.js'\nimport { cmsNavLinkTemplate } from '../init/templates/components/layout/cms-nav-link.js'\nimport { cmsProvidersTemplate } from '../init/templates/components/layout/cms-providers.js'\nimport { cmsSearchTemplate } from '../init/templates/components/layout/cms-search.js'\nimport { cmsSidebarTemplate } from '../init/templates/components/layout/cms-sidebar.js'\nimport { deleteDialogTemplate } from '../init/templates/components/shared/delete-dialog.js'\nimport { pageHeaderTemplate } from '../init/templates/components/shared/page-header.js'\nimport { statusBadgeTemplate } from '../init/templates/components/shared/status-badge.js'\nimport { useCmsThemeTemplate } from '../init/templates/hooks/use-cms-theme.js'\nimport { useEditorImageUploadHookTemplate } from '../init/templates/hooks/use-editor-image-upload.js'\nimport { useLocalStorageHookTemplate } from '../init/templates/hooks/use-local-storage.js'\nimport { useMobileHookTemplate } from '../init/templates/hooks/use-mobile.js'\nimport { useUploadHookTemplate } from '../init/templates/hooks/use-upload.js'\nimport { useUsersHookTemplate } from '../init/templates/hooks/use-users.js'\nimport { formSettingsActionTemplate } from '../init/templates/lib/actions/form-settings.js'\nimport { uploadActionTemplate } from '../init/templates/lib/actions/upload.js'\nimport { usersActionTemplate } from '../init/templates/lib/actions/users.js'\nimport { markdownCachedTemplate } from '../init/templates/lib/markdown/cached.js'\nimport { markdownFormatTemplate } from '../init/templates/lib/markdown/format.js'\nimport { markdownRenderTemplate } from '../init/templates/lib/markdown/render.js'\nimport { r2ClientTemplate } from '../init/templates/lib/r2.js'\nimport { authTypesTemplate } from '../init/templates/types/auth.js'\nimport { typesIndexTemplate } from '../init/templates/types/index.js'\nimport { tableMetaTypesTemplate } from '../init/templates/types/table-meta.js'\nimport { cnUtilTemplate } from '../init/templates/utils/cn.js'\nimport { mailchimpUtilTemplate } from '../init/templates/utils/mailchimp.js'\nimport { seoUtilTemplate } from '../init/templates/utils/seo.js'\nimport { validationUtilTemplate } from '../init/templates/utils/validation.js'\nimport { webhookUtilTemplate } from '../init/templates/utils/webhook.js'\n\ninterface TemplateEntry {\n relPath: string\n content: () => string\n}\n\n/**\n * Template-function components (layout, shared, hooks, utils, etc.)\n * Key = component name used on CLI, value = { relative path in cms/, content generator }\n */\nconst TEMPLATE_REGISTRY: Record<string, TemplateEntry> = {\n // CSS\n 'cms-globals': { relPath: 'cms-globals.css', content: cmsGlobalsCssTemplate },\n // Layout\n 'cms-providers': { relPath: 'components/layout/cms-providers.tsx', content: cmsProvidersTemplate },\n 'cms-nav-link': { relPath: 'components/layout/cms-nav-link.tsx', content: cmsNavLinkTemplate },\n 'cms-sidebar': { relPath: 'components/layout/cms-sidebar.tsx', content: cmsSidebarTemplate },\n 'cms-header': { relPath: 'components/layout/cms-header.tsx', content: cmsHeaderTemplate },\n 'cms-search': { relPath: 'components/layout/cms-search.tsx', content: cmsSearchTemplate },\n // Shared\n 'page-header': { relPath: 'components/shared/page-header.tsx', content: pageHeaderTemplate },\n 'delete-dialog': { relPath: 'components/shared/delete-dialog.tsx', content: deleteDialogTemplate },\n 'status-badge': { relPath: 'components/shared/status-badge.tsx', content: statusBadgeTemplate },\n // Data table\n 'data-table': { relPath: 'components/data-table/data-table.tsx', content: dataTableTemplate },\n 'data-table-pagination': { relPath: 'components/data-table/data-table-pagination.tsx', content: dataTablePaginationTemplate },\n 'data-table-toolbar': { relPath: 'components/data-table/data-table-toolbar.tsx', content: dataTableToolbarTemplate },\n // Hooks\n 'use-upload': { relPath: 'hooks/use-upload.ts', content: useUploadHookTemplate },\n 'use-editor-image-upload': { relPath: 'hooks/use-editor-image-upload.ts', content: useEditorImageUploadHookTemplate },\n 'use-local-storage': { relPath: 'hooks/use-local-storage.ts', content: useLocalStorageHookTemplate },\n 'use-cms-theme': { relPath: 'hooks/use-cms-theme.tsx', content: useCmsThemeTemplate },\n 'use-users': { relPath: 'hooks/use-users.ts', content: useUsersHookTemplate },\n 'use-mobile': { relPath: 'hooks/use-mobile.ts', content: useMobileHookTemplate },\n // Types\n 'types-index': { relPath: 'types/index.ts', content: typesIndexTemplate },\n 'auth-types': { relPath: 'types/auth.ts', content: authTypesTemplate },\n 'table-meta': { relPath: 'types/table-meta.ts', content: tableMetaTypesTemplate },\n // Utils\n cn: { relPath: 'utils/cn.ts', content: cnUtilTemplate },\n seo: { relPath: 'utils/seo.ts', content: seoUtilTemplate },\n validation: { relPath: 'utils/validation.ts', content: validationUtilTemplate },\n webhook: { relPath: 'utils/webhook.ts', content: webhookUtilTemplate },\n mailchimp: { relPath: 'utils/mailchimp.ts', content: mailchimpUtilTemplate },\n // Lib\n r2: { relPath: 'lib/r2.ts', content: r2ClientTemplate },\n 'form-settings-action': { relPath: 'lib/actions/form-settings.ts', content: formSettingsActionTemplate },\n 'upload-action': { relPath: 'lib/actions/upload.ts', content: uploadActionTemplate },\n 'users-action': { relPath: 'lib/actions/users.ts', content: usersActionTemplate },\n // Markdown\n 'markdown-render': { relPath: 'lib/markdown/render.ts', content: markdownRenderTemplate },\n 'markdown-format': { relPath: 'lib/markdown/format.ts', content: markdownFormatTemplate },\n 'markdown-cached': { relPath: 'lib/markdown/cached.ts', content: markdownCachedTemplate },\n}\n\n/**\n * Find the CLI package root by looking for package.json with our name.\n */\nfunction findCliRoot(): string {\n let dir = new URL('.', import.meta.url).pathname\n for (let i = 0; i < 5; i++) {\n const pkgPath = path.join(dir, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (pkg.name === '@betterstart/cli') {\n return dir\n }\n } catch {\n // continue\n }\n }\n dir = path.dirname(dir)\n }\n return path.resolve(new URL('.', import.meta.url).pathname, '..', '..')\n}\n\n/**\n * Get all available static UI component names from templates/ui/\n */\nfunction getStaticUiComponents(): string[] {\n const cliRoot = findCliRoot()\n const uiDir = path.join(cliRoot, 'templates', 'ui')\n if (!fs.existsSync(uiDir)) return []\n return fs\n .readdirSync(uiDir)\n .filter((f: string) => f.endsWith('.tsx') || f.endsWith('.ts'))\n .map((f: string) => f.replace(/\\.(tsx|ts)$/, ''))\n}\n\nfunction getAllComponentNames(): string[] {\n const staticUi = getStaticUiComponents()\n const templateKeys = Object.keys(TEMPLATE_REGISTRY)\n return [...new Set([...staticUi, ...templateKeys, 'tiptap'])].sort()\n}\n\nexport const updateComponentCommand = new Command('update-component')\n .description('Update individual CMS components from the latest CLI templates')\n .argument('[components...]', 'Component names to update (e.g., media-upload-field button)')\n .option('--list', 'List all available components')\n .option('--all', 'Update all components')\n .option('--cwd <path>', 'Project root path')\n .action(async (components: string[], options: { list?: boolean; all?: boolean; cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n if (options.list) {\n const all = getAllComponentNames()\n clack.intro('Available components')\n\n const uiComponents = getStaticUiComponents()\n const templateKeys = Object.keys(TEMPLATE_REGISTRY).sort()\n\n // UI components table\n console.log()\n console.log(` UI Components (${uiComponents.length})`)\n console.log(` ${'─'.repeat(50)}`)\n console.log(` ${'Name'.padEnd(28)} ${'Path'}`)\n console.log(` ${'─'.repeat(50)}`)\n for (const name of uiComponents) {\n console.log(` ${name.padEnd(28)} components/ui/${name}.tsx`)\n }\n\n // Template components table\n console.log()\n console.log(` Template Components (${templateKeys.length})`)\n console.log(` ${'─'.repeat(56)}`)\n console.log(` ${'Name'.padEnd(28)} ${'Path'}`)\n console.log(` ${'─'.repeat(56)}`)\n for (const name of templateKeys) {\n console.log(` ${name.padEnd(28)} ${TEMPLATE_REGISTRY[name].relPath}`)\n }\n\n // Special\n console.log()\n console.log(` Special`)\n console.log(` ${'─'.repeat(56)}`)\n console.log(` ${'tiptap'.padEnd(28)} components/ui/tiptap/ (all files)`)\n console.log()\n\n clack.outro(`${all.length} components available`)\n return\n }\n\n if (!options.all && components.length === 0) {\n clack.log.error('Provide component names or use --all. Run with --list to see available components.')\n process.exit(1)\n }\n\n const config = await resolveConfig(cwd)\n const cms = path.resolve(cwd, config.paths.cms)\n\n if (!fs.existsSync(cms)) {\n clack.cancel(`CMS directory not found at ${config.paths.cms}. Run 'betterstart init' first.`)\n process.exit(1)\n }\n\n clack.intro('BetterStart Update Components')\n\n const toUpdate = options.all ? getAllComponentNames() : components\n const cliRoot = findCliRoot()\n const uiDir = path.join(cliRoot, 'templates', 'ui')\n let updated = 0\n let skipped = 0\n\n for (const name of toUpdate) {\n // 1. Check template registry (template functions)\n if (TEMPLATE_REGISTRY[name]) {\n const entry = TEMPLATE_REGISTRY[name]\n const destPath = path.join(cms, entry.relPath)\n fsExtra.ensureDirSync(path.dirname(destPath))\n fs.writeFileSync(destPath, entry.content(), 'utf-8')\n clack.log.success(`Updated ${entry.relPath}`)\n updated++\n continue\n }\n\n // 2. Check static UI templates\n const uiFile = fs.readdirSync(uiDir).find(\n (f: string) => f.replace(/\\.(tsx|ts)$/, '') === name,\n )\n if (uiFile) {\n const destPath = path.join(cms, 'components', 'ui', uiFile)\n fsExtra.ensureDirSync(path.dirname(destPath))\n fs.copyFileSync(path.join(uiDir, uiFile), destPath)\n clack.log.success(`Updated components/ui/${uiFile}`)\n updated++\n continue\n }\n\n // 3. Special: tiptap directory\n if (name === 'tiptap') {\n const srcDir = path.join(cliRoot, 'templates', 'tiptap')\n const destDir = path.join(cms, 'components', 'ui', 'tiptap')\n if (fs.existsSync(srcDir)) {\n fsExtra.copySync(srcDir, destDir, { overwrite: true })\n clack.log.success('Updated components/ui/tiptap/ (all files)')\n updated++\n } else {\n clack.log.warning('tiptap templates not found')\n skipped++\n }\n continue\n }\n\n clack.log.warning(`Unknown component: ${name}`)\n skipped++\n }\n\n clack.outro(`Updated ${updated} component${updated !== 1 ? 's' : ''}${skipped > 0 ? `, ${skipped} skipped` : ''}`)\n })\n","/**\n * update-deps command — (re-)install all required CMS dependencies.\n * Safe to run repeatedly; the package manager will skip already-installed packages.\n */\n\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport { installDependenciesAsync } from '../init/scaffolders/dependencies.js'\nimport { detectPackageManager } from '../utils/package-manager.js'\n\nexport const updateDepsCommand = new Command('update-deps')\n .description('Install or update all CMS dependencies')\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n clack.intro('BetterStart Update Dependencies')\n\n const pm = detectPackageManager(cwd)\n clack.log.info(`Package manager: ${pm}`)\n\n const config = await resolveConfig(cwd)\n const includeEmail = config.features?.email ?? true\n\n const s = clack.spinner()\n s.start('Installing dependencies...')\n\n const result = await installDependenciesAsync({\n cwd,\n pm,\n includeEmail,\n includeBiome: false\n })\n\n if (result.success) {\n s.stop(`Installed ${result.coreDeps.length} deps + ${result.devDeps.length} dev deps`)\n } else {\n s.stop('Dependency install failed')\n clack.log.error(result.error ?? 'Unknown error')\n process.exit(1)\n }\n\n clack.outro('Dependencies updated')\n })\n","/**\n * update-styles command — replace cms-globals.css with the latest version\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport { cmsGlobalsCssTemplate } from '../init/templates/components/cms-globals.js'\n\nexport const updateStylesCommand = new Command('update-styles')\n .description('Replace cms-globals.css with the latest version from the CLI')\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n clack.intro('BetterStart Update Styles')\n\n const config = await resolveConfig(cwd)\n const cmsDir = config.paths?.cms ?? './cms'\n const targetPath = path.join(cwd, cmsDir, 'cms-globals.css')\n\n if (!fs.existsSync(targetPath)) {\n clack.cancel(`cms-globals.css not found at ${path.relative(cwd, targetPath)}`)\n process.exit(1)\n }\n\n fs.writeFileSync(targetPath, cmsGlobalsCssTemplate(), 'utf-8')\n\n clack.log.success(`Updated ${path.relative(cwd, targetPath)}`)\n clack.outro('Styles updated')\n })\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6LT;;;AC9LO,SAAS,8BAAsC;AACpD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0JT;;;ACzJO,SAAS,sBAA8B;AAC5C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkJT;;;ACrJO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQT;;;ACTO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwDT;;;ACzDO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqHT;;;ACtHO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6FT;;;AC9FO,SAAS,uBAA+B;AAC7C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkPT;;;ACnPO,SAAS,oBAA4B;AAC1C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBT;;;ACrBO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["Command","path","fs","path","path","fs","content","parsed","path","fs","path","p","path","fs","fs","path","path","fs","p","fs","path","path","fs","fs","path","path","fs","fs","path","fs","path","fs","path","path","fs","p","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fns","fs","path","generateColumnDef","fs","path","path","fs","generateColumns","path","fs","generateColumnDef","fs","path","path","fs","fs","path","findTableEnd","path","fs","fs","path","path","fs","fs","path","base","generateFieldJSX","buildZodFields","buildDefaultValues","path","fs","buildZodFields","buildDefaultValues","generateFieldJSX","fs","path","path","fs","buildZodFields","buildDefaultValues","generateFieldJSX","fs","path","path","fs","fs","path","parseNavigationFile","extractTopLevelArray","parseItemsBlock","parseSingleItem","generateNavigationCode","appendItem","fs","path","generatePage","path","fs","fs","path","generatePageContent","path","fs","fs","path","path","fs","fs","path","generateTable","path","fs","generateColumns","generateTable","generatePageContent","generatePage","execFileSync","fs","path","fs","path","path","fs","execFileSync","path","result","execFileSync","spawn","fs","path","p","Command","pc","execFileSync","p","p","path","fs","path","path","path","path","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","path","path","fs","path","path","path","fs","path","path","fs","fs","path","fs","path","fs","path","Command","Command","path","password","fs","runSeed","spinner","Command","pc","path","fs","execFileSync","drizzleConfigTemplate","spawn","password","fs","path","Command","findTableEnd","fs","Command","path","execFileSync","fs","path","p","Command","pc","Command","path","pc","execFileSync","fs","fs","path","p","Command","pc","fs","stripJsonComments","findMainCss","path","fs","p","Command","pc","fs","path","clack","Command","findCliRoot","path","fs","Command","path","clack","Command","Command","path","fs","path","clack","Command","Command","path","fs","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/generate.ts","../src/config/resolver.ts","../src/core/schema-reader.ts","../src/core/field-helpers/walking.ts","../src/core/field-helpers/flattening.ts","../src/core/field-helpers/form-fields.ts","../src/generators/email-template.ts","../src/utils/string.ts","../src/generators/form-admin/orchestrator.ts","../src/generators/form-admin/admin-columns.ts","../src/generators/form-admin/admin-page.ts","../src/generators/form-admin/admin-page-content.ts","../src/generators/form-admin/admin-settings-page.ts","../src/generators/form-admin/admin-table.ts","../src/generators/form-admin/admin-view-page.ts","../src/generators/form-navigation.ts","../src/generators/form-pipeline/form-actions.ts","../src/generators/form-pipeline/form-component-multistep.ts","../src/generators/form-pipeline/form-component-shared.ts","../src/core/type-mappers/drizzle.ts","../src/core/type-mappers/zod.ts","../src/core/type-mappers/typescript.ts","../src/generators/form-pipeline/form-component-single.ts","../src/generators/form-pipeline/form-component.ts","../src/generators/form-pipeline/form-database.ts","../src/generators/form-pipeline/form-hook.ts","../src/generators/form-pipeline/pipeline.ts","../src/generators/actions/entity-actions.ts","../src/generators/actions/action-helpers.ts","../src/generators/actions/single-actions.ts","../src/generators/cache.ts","../src/generators/columns/generate-columns.ts","../src/generators/columns/column-defs.ts","../src/generators/columns/column-actions.ts","../src/generators/columns/custom-cell.ts","../src/generators/create-page.ts","../src/generators/database.ts","../src/generators/edit-page.ts","../src/generators/form/form-entity.ts","../src/generators/form/zod-schema.ts","../src/generators/form/field-jsx-nested.ts","../src/generators/form/field-jsx.ts","../src/generators/form/form-shared.ts","../src/generators/form/form-single.ts","../src/generators/hook.ts","../src/generators/navigation.ts","../src/generators/page.ts","../src/generators/page-content.ts","../src/generators/single-page.ts","../src/generators/table.ts","../src/generators/index.ts","../src/generators/post-generate.ts","../src/utils/package-manager.ts","../src/commands/init.ts","../src/init/prompts/database.ts","../src/init/prompts/features.ts","../src/init/prompts/project.ts","../src/init/scaffolders/api-routes.ts","../src/utils/fs.ts","../src/init/templates/api/auth-route.ts","../src/init/templates/api/upload-route.ts","../src/init/scaffolders/auth.ts","../src/init/templates/lib/auth/auth.ts","../src/init/templates/lib/auth/auth-client.ts","../src/init/templates/lib/auth/middleware.ts","../src/init/scaffolders/base.ts","../src/init/scaffolders/biome.ts","../src/init/scaffolders/components.ts","../src/utils/detect.ts","../src/init/templates/components/cms-globals.ts","../src/init/templates/components/data-table/data-table.ts","../src/init/templates/components/data-table/data-table-pagination.ts","../src/init/templates/components/data-table/data-table-toolbar.ts","../src/init/templates/components/layout/cms-header.ts","../src/init/templates/components/layout/cms-nav-link.ts","../src/init/templates/components/layout/cms-providers.ts","../src/init/templates/components/layout/cms-search.ts","../src/init/templates/components/layout/cms-sidebar.ts","../src/init/templates/components/shared/delete-dialog.ts","../src/init/templates/components/shared/page-header.ts","../src/init/templates/components/shared/status-badge.ts","../src/init/templates/data/cms.ts","../src/init/templates/data/navigation.ts","../src/init/templates/hooks/use-cms-theme.ts","../src/init/templates/hooks/use-editor-image-upload.ts","../src/init/templates/hooks/use-local-storage.ts","../src/init/templates/hooks/use-mobile.ts","../src/init/templates/hooks/use-upload.ts","../src/init/templates/hooks/use-users.ts","../src/init/templates/lib/actions/form-settings.ts","../src/init/templates/lib/actions/upload.ts","../src/init/templates/lib/actions/users.ts","../src/init/templates/lib/markdown/cached.ts","../src/init/templates/lib/markdown/format.ts","../src/init/templates/lib/markdown/render.ts","../src/init/templates/lib/r2.ts","../src/init/templates/types/auth.ts","../src/init/templates/types/index.ts","../src/init/templates/types/table-meta.ts","../src/init/templates/utils/cn.ts","../src/init/templates/utils/seo.ts","../src/init/templates/utils/validation.ts","../src/init/templates/utils/webhook.ts","../src/init/templates/utils/mailchimp.ts","../src/init/scaffolders/database.ts","../src/init/templates/db/client.ts","../src/init/templates/db/schema.ts","../src/init/scaffolders/dependencies.ts","../src/init/scaffolders/env.ts","../src/utils/env.ts","../src/init/scaffolders/layout.ts","../src/init/templates/pages/authenticated-layout.ts","../src/init/templates/pages/cms-layout.ts","../src/init/templates/pages/dashboard-page.ts","../src/init/templates/pages/login-page.ts","../src/init/templates/pages/users/create-user-dialog.ts","../src/init/templates/pages/users/edit-role-dialog.ts","../src/init/templates/pages/users/users-columns.ts","../src/init/templates/pages/users/users-page.ts","../src/init/templates/pages/users/users-table.ts","../src/init/scaffolders/preset.ts","../src/init/templates/presets/blog-categories.ts","../src/init/templates/presets/blog-posts.ts","../src/init/templates/presets/default-settings.ts","../src/init/templates/presets/full-contact.ts","../src/init/templates/presets/full-navigation.ts","../src/init/scaffolders/tailwind.ts","../src/init/scaffolders/tsconfig.ts","../src/commands/seed.ts","../src/commands/remove.ts","../src/commands/setup-r2.ts","../src/commands/uninstall.ts","../src/commands/uninstall-cleaners.ts","../src/commands/update-component.ts","../src/commands/update-deps.ts","../src/commands/update-styles.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { generateCommand } from './commands/generate.js'\nimport { initCommand } from './commands/init.js'\nimport { removeCommand } from './commands/remove.js'\nimport { seedCommand } from './commands/seed.js'\nimport { setupR2Command } from './commands/setup-r2.js'\nimport { uninstallCommand } from './commands/uninstall.js'\nimport { updateComponentCommand } from './commands/update-component.js'\nimport { updateDepsCommand } from './commands/update-deps.js'\nimport { updateStylesCommand } from './commands/update-styles.js'\n\nconst program = new Command()\n\nprogram\n .name('betterstart')\n .description('Scaffold a full-featured CMS into any Next.js 16 application')\n .version('0.1.0')\n\nprogram.addCommand(initCommand)\nprogram.addCommand(generateCommand)\nprogram.addCommand(removeCommand)\nprogram.addCommand(seedCommand)\nprogram.addCommand(setupR2Command)\nprogram.addCommand(uninstallCommand)\nprogram.addCommand(updateComponentCommand)\nprogram.addCommand(updateDepsCommand)\nprogram.addCommand(updateStylesCommand)\n\nprogram.parse()\n","/**\n * generate command — read schema, detect type, run pipeline\n */\n\nimport path from 'node:path'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\nimport type { LoadedSchema } from '../core/schema-reader.js'\nimport { loadSchema, SchemaNotFoundError, validateLoadedSchema } from '../core/schema-reader.js'\nimport { runFormPipeline } from '../generators/form-pipeline/index.js'\nimport { runEntityPipeline, runSinglePipeline } from '../generators/index.js'\nimport { runPostGenerate } from '../generators/post-generate.js'\n\nexport const generateCommand = new Command('generate')\n .alias('g')\n .description('Generate entity or form from a JSON schema')\n .argument('<schema>', 'Schema name (e.g. posts, categories, contact)')\n .option('-f, --force', 'Overwrite existing generated files', false)\n .option('--skip-migration', 'Skip running db:push after generation', false)\n .option('--cwd <path>', 'Project root path')\n .action(\n async (\n schemaName: string,\n options: { force: boolean; skipMigration: boolean; cwd?: string }\n ) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n console.log('\\n BetterStart Generator\\n')\n\n // Load config\n let config: BetterstartConfig\n try {\n config = await resolveConfig(cwd)\n } catch (err) {\n console.error(` Error loading config: ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n }\n\n const schemasDir = path.join(cwd, config.paths?.schemas ?? './cms/schemas')\n console.log(` Project root: ${cwd}`)\n console.log(` Loading schema: ${schemaName}.json\\n`)\n\n // Load schema\n let loaded: LoadedSchema\n try {\n loaded = loadSchema(schemasDir, schemaName)\n } catch (err) {\n if (err instanceof SchemaNotFoundError) {\n console.error(` ${err.message}`)\n console.error(\n `\\n Create a schema file at: ${path.join(schemasDir, `${schemaName}.json`)}`\n )\n } else {\n console.error(\n ` Error loading schema: ${err instanceof Error ? err.message : String(err)}`\n )\n }\n process.exit(1)\n }\n\n // Validate schema\n const validationErrors = validateLoadedSchema(loaded)\n if (validationErrors.length > 0) {\n console.error(' Schema validation failed:\\n')\n for (const error of validationErrors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n console.log(` Schema validated (type: ${loaded.type})\\n`)\n\n // Route to correct pipeline\n if (loaded.type === 'form') {\n console.log(' Generating form files...\\n')\n\n const result = runFormPipeline(loaded.schema, cwd, config, {\n force: options.force,\n skipMigration: options.skipMigration\n })\n\n if (!result.success) {\n console.error('\\n Form generation completed with errors:\\n')\n for (const error of result.errors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n\n console.log('\\n Form generation complete!\\n')\n console.log(` ${result.files.length} files generated:`)\n for (const file of result.files) {\n console.log(` - ${file}`)\n }\n\n runPostGenerate(cwd, schemaName, {\n skipMigration: options.skipMigration\n })\n console.log('')\n return\n }\n\n // Single pipeline\n if (loaded.type === 'single') {\n console.log(' Generating single schema files...\\n')\n\n const result = runSinglePipeline(loaded.schema, cwd, config, {\n force: options.force,\n skipMigration: options.skipMigration\n })\n\n if (!result.success) {\n console.error('\\n Single generation completed with errors:\\n')\n for (const error of result.errors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n\n console.log('\\n Single generation complete!\\n')\n console.log(` ${result.files.length} files generated:`)\n for (const file of result.files) {\n console.log(` - ${file}`)\n }\n\n runPostGenerate(cwd, schemaName, {\n skipMigration: options.skipMigration\n })\n console.log('')\n return\n }\n\n // Entity pipeline\n console.log(' Generating files...\\n')\n\n const result = runEntityPipeline(loaded.schema, cwd, config, {\n force: options.force,\n skipMigration: options.skipMigration\n })\n\n if (!result.success) {\n console.error('\\n Generation completed with errors:\\n')\n for (const error of result.errors) {\n console.error(` - ${error}`)\n }\n process.exit(1)\n }\n\n // Summary\n console.log('\\n Generation complete!\\n')\n console.log(` ${result.files.length} files generated:`)\n for (const file of result.files) {\n console.log(` - ${file}`)\n }\n\n // Post-generation: db:push + lint:fix\n runPostGenerate(cwd, schemaName, {\n skipMigration: options.skipMigration\n })\n console.log('')\n }\n )\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { BetterstartConfig } from './types.js'\n\nconst CONFIG_FILE_NAME = 'cms.config.ts'\n\nexport function getDefaultConfig(srcDir: boolean): BetterstartConfig {\n const appBase = srcDir ? './src/app' : './app'\n return {\n srcDir,\n paths: {\n cms: './cms',\n schemas: './cms/schemas',\n pages: `${appBase}/(cms)/cms/(authenticated)`,\n login: `${appBase}/(cms)/cms/login`,\n api: `${appBase}/(cms)/api/cms`\n },\n database: {\n provider: 'neon',\n migrationsDir: './cms/db/migrations'\n },\n features: {\n email: true\n },\n linter: 'biome',\n generated: {\n entities: [],\n singles: [],\n forms: []\n }\n }\n}\n\nexport function findConfigFile(cwd: string): string | undefined {\n const filePath = path.join(cwd, CONFIG_FILE_NAME)\n if (fs.existsSync(filePath)) {\n return filePath\n }\n return undefined\n}\n\nexport async function loadConfigFile(configPath: string): Promise<BetterstartConfig> {\n const { createJiti } = await import('jiti')\n\n const alias: Record<string, string> = {}\n try {\n alias['@betterstart/cli'] = fileURLToPath(import.meta.resolve('@betterstart/cli'))\n } catch {\n // Not critical — config may not import from us\n }\n\n const jiti = createJiti(import.meta.url, { alias })\n const mod = await jiti.import(configPath)\n return ((mod as Record<string, unknown>).default || mod) as BetterstartConfig\n}\n\nexport async function resolveConfig(cwd?: string): Promise<BetterstartConfig> {\n const workingDir = cwd ?? process.cwd()\n const configPath = findConfigFile(workingDir)\n\n if (!configPath) {\n const hasSrc = fs.existsSync(path.join(workingDir, 'src'))\n return getDefaultConfig(hasSrc)\n }\n\n return loadConfigFile(configPath)\n}\n","/**\n * Schema reader: load + validate JSON schemas from cms/schemas/\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { FormSchema, Schema } from '../types.js'\nimport { flattenFields } from './field-helpers/index.js'\n\n// ============================================================================\n// Schema Types\n// ============================================================================\n\nexport type SchemaType = 'entity' | 'single' | 'form'\n\nexport interface LoadedEntitySchema {\n type: 'entity'\n schema: Schema\n filePath: string\n}\n\nexport interface LoadedSingleSchema {\n type: 'single'\n schema: Schema\n filePath: string\n}\n\nexport interface LoadedFormSchema {\n type: 'form'\n schema: FormSchema\n filePath: string\n}\n\nexport type LoadedSchema = LoadedEntitySchema | LoadedSingleSchema | LoadedFormSchema\n\n// ============================================================================\n// Schema Loading\n// ============================================================================\n\n/**\n * Load a schema by name from the schemas directory\n * Detects entity vs form schemas automatically\n */\nexport function loadSchema(schemasDir: string, name: string): LoadedSchema {\n // Check for form schema first (in forms/ subdirectory)\n const formPath = path.join(schemasDir, 'forms', `${name}.json`)\n if (fs.existsSync(formPath)) {\n const content = fs.readFileSync(formPath, 'utf-8')\n const parsed = parseJson(content, formPath)\n return { type: 'form', schema: parsed as FormSchema, filePath: formPath }\n }\n\n // Check for entity schema\n const entityPath = path.join(schemasDir, `${name}.json`)\n if (!fs.existsSync(entityPath)) {\n throw new SchemaNotFoundError(name, schemasDir)\n }\n\n const content = fs.readFileSync(entityPath, 'utf-8')\n const parsed = parseJson(content, entityPath)\n\n const obj = parsed as Record<string, unknown>\n\n // Auto-detect form type from schema content\n if ('submitButtonText' in obj || 'steps' in obj) {\n return { type: 'form', schema: parsed as FormSchema, filePath: entityPath }\n }\n\n // Detect single schema via explicit type field\n if (obj.type === 'single') {\n return { type: 'single', schema: parsed as Schema, filePath: entityPath }\n }\n\n return { type: 'entity', schema: parsed as Schema, filePath: entityPath }\n}\n\n/**\n * List all available entity schemas in the schemas directory\n */\nexport function listEntitySchemas(schemasDir: string): string[] {\n if (!fs.existsSync(schemasDir)) return []\n return fs\n .readdirSync(schemasDir)\n .filter((f) => f.endsWith('.json') && f !== 'schema.json')\n .map((f) => f.replace('.json', ''))\n}\n\n/**\n * List all available form schemas\n */\nexport function listFormSchemas(schemasDir: string): string[] {\n const formsDir = path.join(schemasDir, 'forms')\n if (!fs.existsSync(formsDir)) return []\n return fs\n .readdirSync(formsDir)\n .filter((f) => f.endsWith('.json'))\n .map((f) => f.replace('.json', ''))\n}\n\n// ============================================================================\n// Schema Validation\n// ============================================================================\n\n/**\n * Validate an entity schema structure\n * Returns an array of error messages (empty = valid)\n */\nexport function validateEntitySchema(schema: Schema): string[] {\n const errors: string[] = []\n\n if (!schema.name || typeof schema.name !== 'string') {\n errors.push('Schema must have a valid \"name\" field')\n }\n if (!schema.label || typeof schema.label !== 'string') {\n errors.push('Schema must have a valid \"label\" field')\n }\n if (!schema.description || typeof schema.description !== 'string') {\n errors.push('Schema must have a valid \"description\" field')\n }\n if (!schema.icon || typeof schema.icon !== 'string') {\n errors.push('Schema must have a valid \"icon\" field')\n }\n if (!Array.isArray(schema.fields) || schema.fields.length === 0) {\n errors.push('Schema must have at least one field')\n }\n if (!Array.isArray(schema.columns) || schema.columns.length === 0) {\n errors.push('Schema must have at least one column')\n }\n\n // Validate fields\n for (const field of schema.fields || []) {\n if (field.type === 'separator') continue\n if (!field.name || !field.type) {\n errors.push(`Field is missing required properties: ${JSON.stringify(field)}`)\n }\n }\n\n // Validate columns reference real fields\n const flatFields = flattenFields(schema.fields || [])\n const fieldNames = new Set(flatFields.map((f) => f.name))\n // Auto fields are always available\n for (const auto of [\n 'id',\n 'createdAt',\n 'updatedAt',\n 'published',\n 'submittedAt',\n 'ipAddress',\n 'userAgent'\n ]) {\n fieldNames.add(auto)\n }\n\n for (const column of schema.columns || []) {\n if (!column.accessorKey || !column.header || !column.type) {\n errors.push(`Column is missing required properties: ${JSON.stringify(column)}`)\n } else if (!fieldNames.has(column.accessorKey)) {\n errors.push(\n `Column accessorKey \"${column.accessorKey}\" does not match any field. Available: ${Array.from(fieldNames).join(', ')}`\n )\n }\n }\n\n return errors\n}\n\n/**\n * Validate a single schema structure\n * Like entity validation but skips columns requirement (no list view)\n */\nexport function validateSingleSchema(schema: Schema): string[] {\n const errors: string[] = []\n\n if (!schema.name || typeof schema.name !== 'string') {\n errors.push('Schema must have a valid \"name\" field')\n }\n if (!schema.label || typeof schema.label !== 'string') {\n errors.push('Schema must have a valid \"label\" field')\n }\n if (!schema.description || typeof schema.description !== 'string') {\n errors.push('Schema must have a valid \"description\" field')\n }\n if (!schema.icon || typeof schema.icon !== 'string') {\n errors.push('Schema must have a valid \"icon\" field')\n }\n if (!Array.isArray(schema.fields) || schema.fields.length === 0) {\n errors.push('Schema must have at least one field')\n }\n\n // Validate fields\n for (const field of schema.fields || []) {\n if (field.type === 'separator') continue\n if (!field.name || !field.type) {\n errors.push(`Field is missing required properties: ${JSON.stringify(field)}`)\n }\n }\n\n // No columns validation — single schemas have no list view\n\n return errors\n}\n\n/**\n * Validate a form schema structure\n */\nexport function validateFormSchema(schema: FormSchema): string[] {\n const errors: string[] = []\n\n if (!schema.name || typeof schema.name !== 'string') {\n errors.push('Form schema must have a valid \"name\" field')\n }\n if (!schema.label || typeof schema.label !== 'string') {\n errors.push('Form schema must have a valid \"label\" field')\n }\n if (!schema.description || typeof schema.description !== 'string') {\n errors.push('Form schema must have a valid \"description\" field')\n }\n if (!schema.icon || typeof schema.icon !== 'string') {\n errors.push('Form schema must have a valid \"icon\" field')\n }\n\n const hasFields = Array.isArray(schema.fields) && schema.fields.length > 0\n const hasSteps = Array.isArray(schema.steps) && schema.steps.length > 0\n\n if (!hasFields && !hasSteps) {\n errors.push('Form schema must have either \"fields\" or \"steps\"')\n }\n if (hasFields && hasSteps) {\n errors.push('Form schema cannot have both \"fields\" and \"steps\"')\n }\n\n if (hasSteps) {\n for (const step of schema.steps!) {\n if (!step.name || !step.label) {\n errors.push(`Form step is missing name or label: ${JSON.stringify(step)}`)\n }\n if (!Array.isArray(step.fields) || step.fields.length === 0) {\n errors.push(`Form step \"${step.name}\" must have at least one field`)\n }\n }\n }\n\n return errors\n}\n\n/**\n * Validate a loaded schema (auto-detects type)\n */\nexport function validateLoadedSchema(loaded: LoadedSchema): string[] {\n if (loaded.type === 'entity') {\n return validateEntitySchema(loaded.schema)\n }\n if (loaded.type === 'single') {\n return validateSingleSchema(loaded.schema)\n }\n return validateFormSchema(loaded.schema)\n}\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nexport class SchemaNotFoundError extends Error {\n constructor(name: string, schemasDir: string) {\n super(\n `Schema \"${name}\" not found. Looked in:\\n - ${path.join(schemasDir, `${name}.json`)}\\n - ${path.join(schemasDir, 'forms', `${name}.json`)}`\n )\n this.name = 'SchemaNotFoundError'\n }\n}\n\n// ============================================================================\n// Internal Helpers\n// ============================================================================\n\nfunction parseJson(content: string, filePath: string): unknown {\n try {\n return JSON.parse(content)\n } catch {\n throw new Error(`Failed to parse JSON schema: ${filePath}`)\n }\n}\n","/**\n * Field tree walking and type checking utilities\n */\n\nimport type { SchemaField } from '../../types.js'\n\n// ============================================================================\n// Field Tree Walking\n// ============================================================================\n\nexport interface WalkFieldsOptions {\n includeLists?: boolean\n includeGroups?: boolean\n includeTabs?: boolean\n}\n\nconst DEFAULT_WALK_OPTIONS: WalkFieldsOptions = {\n includeLists: true,\n includeGroups: true,\n includeTabs: true\n}\n\n/**\n * Walk through all fields in a schema, including nested ones\n */\nexport function walkFields(\n fields: SchemaField[],\n callback: (field: SchemaField, depth: number, parent?: SchemaField) => void,\n options: WalkFieldsOptions = DEFAULT_WALK_OPTIONS\n): void {\n function walk(fieldsToWalk: SchemaField[], depth: number, parent?: SchemaField): void {\n for (const field of fieldsToWalk) {\n callback(field, depth, parent)\n\n if (options.includeGroups && field.type === 'group' && field.fields) {\n walk(field.fields, depth + 1, field)\n }\n if (options.includeLists && field.type === 'list' && field.fields) {\n walk(field.fields, depth + 1, field)\n }\n if (options.includeTabs && field.type === 'tabs' && field.tabs) {\n for (const tab of field.tabs) {\n if (tab.fields) {\n walk(tab.fields, depth + 1, field)\n }\n }\n }\n }\n }\n\n walk(fields, 0)\n}\n\n// ============================================================================\n// Field Type Checking\n// ============================================================================\n\n/**\n * Check if any field in the tree matches a specific type\n */\nexport function hasFieldType(\n fields: SchemaField[],\n type: string,\n options?: WalkFieldsOptions\n): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (field.type === type) found = true\n },\n options\n )\n return found\n}\n\n/**\n * Check if any field in the tree matches any of the given types\n */\nexport function hasAnyFieldType(\n fields: SchemaField[],\n types: string[],\n options?: WalkFieldsOptions\n): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (types.includes(field.type)) found = true\n },\n options\n )\n return found\n}\n\n/**\n * Check if any field uses icons (either icon type or hasIcon property)\n */\nexport function hasIconUsage(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (field.type === 'icon' || field.hasIcon) found = true\n },\n options\n )\n return found\n}\n\nexport function hasRelationshipField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, 'relationship', options)\n}\n\nexport function hasMarkdownField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, 'markdown', options)\n}\n\nexport function hasTextareaField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, 'text', options)\n}\n\n/**\n * Collect all fields of a specific type\n */\nexport function collectFieldsByType(\n fields: SchemaField[],\n type: string,\n options?: WalkFieldsOptions\n): SchemaField[] {\n const result: SchemaField[] = []\n walkFields(\n fields,\n (field) => {\n if (field.type === type) result.push(field)\n },\n options\n )\n return result\n}\n","/**\n * Field flattening and collection utilities\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { collectFieldsByType } from './walking.js'\n\n// ============================================================================\n// Field Flattening\n// ============================================================================\n\nconst AUTO_ID_FIELD: SchemaField = {\n name: 'id',\n type: 'serial',\n primaryKey: true\n}\n\n/**\n * Ensure fields have an ID field - automatically injects one if not present\n */\nexport function ensureIdField(fields: SchemaField[]): SchemaField[] {\n const hasId = fields.some((f) => f.primaryKey || f.name === 'id')\n return hasId ? fields : [AUTO_ID_FIELD, ...fields]\n}\n\n/**\n * Flatten group and tabs fields into individual fields for database operations\n * Automatically ensures an ID field exists\n */\nexport function flattenFields(fields: SchemaField[]): SchemaField[] {\n return flattenFieldsWithoutIdCheck(ensureIdField(fields))\n}\n\nfunction flattenFieldsWithoutIdCheck(fields: SchemaField[]): SchemaField[] {\n const flattened: SchemaField[] = []\n\n for (const field of fields) {\n if (field.type === 'group' && field.fields) {\n flattened.push(...flattenFieldsWithoutIdCheck(field.fields))\n } else if (field.type === 'tabs' && field.tabs) {\n for (const tab of field.tabs) {\n if (tab.fields) {\n flattened.push(...flattenFieldsWithoutIdCheck(tab.fields))\n }\n }\n } else {\n flattened.push(field)\n }\n }\n\n return flattened\n}\n\n// ============================================================================\n// Field Collection\n// ============================================================================\n\n/**\n * Get all many-to-many relationship fields\n */\nexport function getManyToManyFields(fields: SchemaField[]): SchemaField[] {\n const flat = flattenFields(fields)\n return flat.filter((f) => f.type === 'relationship' && f.multiple === true && f.relationship)\n}\n\n/**\n * Get all single relationship fields (excluding many-to-many)\n */\nexport function getNestedRelationshipFields(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'relationship' && f.relationship && !f.multiple) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) collect(f.fields)\n if (f.type === 'list' && f.fields) collect(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collect(tab.fields)\n }\n }\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Collect relationship fields from top-level and groups only (not lists)\n */\nexport function collectRelationshipFieldsTopLevel(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'relationship' && f.relationship) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) {\n collect(f.fields)\n }\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Collect ALL relationship fields including those in lists\n */\nexport function collectAllRelationshipFields(fields: SchemaField[]): SchemaField[] {\n return collectFieldsByType(fields, 'relationship')\n}\n\n/**\n * Get list fields that have nested fields (not just items)\n */\nexport function getListFieldsWithNestedFields(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'list' && f.fields && f.fields.length > 0) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) {\n collect(f.fields)\n }\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Get nested list fields (list fields inside list fields)\n */\nexport function getNestedListFields(\n fields: SchemaField[]\n): { parent: SchemaField; nested: SchemaField }[] {\n const result: { parent: SchemaField; nested: SchemaField }[] = []\n\n const listFields = getListFieldsWithNestedFields(fields)\n for (const parent of listFields) {\n if (parent.fields) {\n for (const nested of parent.fields) {\n if (nested.type === 'list' && nested.fields && nested.fields.length > 0) {\n result.push({ parent, nested })\n }\n }\n }\n }\n\n return result\n}\n","/**\n * Form schema field helpers (for FormSchema type)\n */\n\nimport type { FormField, FormSchema, FormStep } from '../../types.js'\n\n/**\n * Get all fields from a form schema (including from steps), flattening groups\n */\nexport function getAllFormFields(schema: FormSchema): FormField[] {\n const allFields: FormField[] = []\n\n const sources = schema.steps ? schema.steps.flatMap((step) => step.fields) : schema.fields || []\n\n for (const field of sources) {\n if (field.type === 'group' && field.fields) {\n for (const nestedField of field.fields) {\n allFields.push({\n ...nestedField,\n condition: nestedField.condition || field.condition\n })\n }\n } else {\n allFields.push(field)\n }\n }\n\n return allFields\n}\n\n/**\n * Check if a form schema is multi-step\n */\nexport function isMultiStepForm(schema: FormSchema): boolean {\n return Array.isArray(schema.steps) && schema.steps.length > 0\n}\n\n/**\n * Get all concrete fields from a form schema, flattening groups and skipping dynamicFields.\n * Works with both flat schemas (schema.fields) and multi-step schemas (schema.steps).\n */\nexport function getAllFormSchemaFields(schema: FormSchema): FormField[] {\n const flatten = (fields: FormField[]): FormField[] => {\n return fields.flatMap((field) => {\n if (field.type === 'dynamicFields') return []\n if (field.type === 'group' && field.fields) return flatten(field.fields)\n return field.type === 'group' ? [] : [field]\n })\n }\n if (schema.fields) return flatten(schema.fields)\n if (schema.steps) return schema.steps.flatMap((step) => flatten(step.fields))\n return []\n}\n\n/**\n * Get flat array of field names for a form step (for RHF trigger validation).\n * Groups are flattened to child names, list fields use parent name,\n * hidden and dynamicFields are excluded, showWhen fields are included.\n */\nexport function getStepFieldNames(step: FormStep): string[] {\n const names: string[] = []\n const collect = (fields: FormField[]): void => {\n for (const field of fields) {\n if (field.hidden) continue\n if (field.type === 'dynamicFields') continue\n if (field.type === 'group' && field.fields) {\n collect(field.fields)\n } else if (field.name) {\n names.push(field.name)\n }\n }\n }\n collect(step.fields)\n return names\n}\n\n/**\n * Check if a form schema contains dynamicFields\n */\nexport function hasDynamicFields(schema: FormSchema): boolean {\n const check = (fields: FormField[]): boolean => {\n for (const f of fields) {\n if (f.type === 'dynamicFields') return true\n if (f.type === 'group' && f.fields && check(f.fields)) return true\n }\n return false\n }\n if (schema.fields && check(schema.fields)) return true\n if (schema.steps) {\n for (const step of schema.steps) {\n if (check(step.fields)) return true\n }\n }\n return false\n}\n","/**\n * Email template generator: creates React Email template for form submission notifications\n * Output: cms/lib/emails/<name>-submission.tsx\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { getAllFormSchemaFields, hasDynamicFields } from '../core/field-helpers/index.js'\nimport type { FormField, FormSchema, GeneratorOptions } from '../types.js'\nimport { toPascalCase, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Type Mapping\n// ============================================================================\n\nfunction getTypeForField(field: FormField): string {\n switch (field.type) {\n case 'number':\n return 'number | null'\n case 'checkbox':\n return 'boolean | null'\n case 'list':\n case 'multiselect':\n if (field.fields && field.fields.length > 0) return 'Record<string, unknown>[] | null'\n return 'string[] | null'\n default:\n return 'string | null'\n }\n}\n\n// ============================================================================\n// Field Value Rendering\n// ============================================================================\n\nfunction generateFieldValue(field: FormField): string {\n const name = field.name || ''\n\n switch (field.type) {\n case 'checkbox':\n return `{${name} ? 'Yes' : 'No'}`\n case 'upload':\n case 'file':\n return `{${name} ? (\n <Link href={${name}} style={link}>Download File</Link>\n ) : 'No file uploaded'}`\n case 'email':\n return `{${name} ? (\n <Link href={\\`mailto:\\${${name}}\\`} style={link}>{${name}}</Link>\n ) : 'N/A'}`\n case 'url':\n return `{${name} ? (\n <Link href={${name}} style={link}>{${name}}</Link>\n ) : 'N/A'}`\n case 'list':\n case 'multiselect':\n if (field.fields && field.fields.length > 0) {\n return `{${name} && Array.isArray(${name}) && ${name}.length > 0 ? (\n ${name}.map((item, idx) => (\n <Text key={idx} style={listItem}>\n {Object.entries(item).map(([k, v]) => \\`\\${k}: \\${v}\\`).join(', ')}\n </Text>\n ))\n ) : 'N/A'}`\n }\n return `{${name} && Array.isArray(${name}) && ${name}.length > 0 ? ${name}.join(', ') : 'N/A'}`\n case 'date':\n return `{${name} ? new Date(${name}).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }) : 'N/A'}`\n default:\n return `{${name} ?? 'N/A'}`\n }\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface EmailTemplateResult {\n files: string[]\n}\n\nexport function generateEmailTemplate(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions = {}\n): EmailTemplateResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const fields = getAllFormSchemaFields(schema).filter((f) => f.name)\n const includeDynamic = hasDynamicFields(schema)\n\n const kebab = toKebabCase(formName)\n const filePath = path.join(cwd, cmsDir, 'lib', 'emails', `${kebab}-submission.tsx`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const needsLink = fields.some(\n (f) => f.type === 'upload' || f.type === 'file' || f.type === 'email' || f.type === 'url'\n )\n const needsListItem = fields.some(\n (f) => (f.type === 'list' || f.type === 'multiselect') && f.fields && f.fields.length > 0\n )\n\n // Props interface\n const propsFields = fields.map((f) => ` ${f.name}: ${getTypeForField(f)}`).join('\\n')\n const customFieldsProp = includeDynamic ? '\\n customFields?: Record<string, unknown> | null' : ''\n\n // Field sections in email body\n const fieldSections = fields\n .map(\n (f) => ` <Row style={fieldRow}>\n <Text style={label}>${f.label}</Text>\n <Text style={value}>${generateFieldValue(f)}</Text>\n </Row>`\n )\n .join('\\n\\n')\n\n // Dynamic fields section\n const customFieldsSection = includeDynamic\n ? `\n\n {customFields && Object.keys(customFields).length > 0 && (\n <>\n <Row style={dividerRow}>\n <Text style={sectionTitle}>Additional Information</Text>\n </Row>\n {Object.entries(customFields).map(([fieldKey, fieldValue]) => (\n <Row key={fieldKey} style={fieldRow}>\n <Text style={label}>{fieldKey.replace(/([A-Z])/g, ' $1').trim()}</Text>\n <Text style={value}>{fieldValue !== null && fieldValue !== undefined ? String(fieldValue) : 'N/A'}</Text>\n </Row>\n ))}\n </>\n )}`\n : ''\n\n // Props destructuring\n const propsDestructured = [\n ...fields.map((f) => f.name),\n ...(includeDynamic ? ['customFields'] : []),\n 'submittedAt'\n ].join(',\\n ')\n\n // Optional style blocks\n const linkStyle = needsLink\n ? `\nconst link = {\n color: colors.primary,\n fontWeight: '500' as const,\n textDecoration: 'none',\n}\n`\n : ''\n\n const listItemStyle = needsListItem\n ? `\nconst listItem = {\n backgroundColor: colors.borderLight,\n borderRadius: '6px',\n color: colors.text,\n fontSize: '14px',\n lineHeight: '20px',\n marginBottom: '6px',\n padding: '8px 12px',\n}\n`\n : ''\n\n const dynamicStyles = includeDynamic\n ? `\nconst dividerRow = {\n borderTop: \\`2px solid \\${colors.border}\\`,\n marginTop: '8px',\n paddingTop: '24px',\n}\n\nconst sectionTitle = {\n color: colors.text,\n fontSize: '14px',\n fontWeight: '600' as const,\n margin: '0 0 8px',\n}\n`\n : ''\n\n const content = `import { Body, Container, Head, Heading, Html${needsLink ? ', Link' : ''}, Preview, Row, Section, Text } from '@react-email/components'\n\ninterface ${pascal}SubmissionEmailProps {\n${propsFields}${customFieldsProp}\n submittedAt: string\n}\n\nexport function ${pascal}SubmissionEmail({\n ${propsDestructured}\n}: ${pascal}SubmissionEmailProps) {\n return (\n <Html>\n <Head />\n <Preview>New ${schema.label} Submission</Preview>\n <Body style={main}>\n <Container style={container}>\n <Section style={header}>\n <Text style={logoText}>BetterStart</Text>\n </Section>\n\n <Section style={titleSection}>\n <Heading style={h1}>New ${schema.label} Submission</Heading>\n <Text style={subtitle}>\n You received a new submission on {new Date(submittedAt).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}\n </Text>\n </Section>\n\n <Section style={card}>\n${fieldSections}${customFieldsSection}\n </Section>\n\n <Section style={footer}>\n <Text style={footerText}>\n Submitted at {new Date(submittedAt).toLocaleString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true, timeZoneName: 'short' })}\n </Text>\n <Text style={footerBrand}>BetterStart</Text>\n </Section>\n </Container>\n </Body>\n </Html>\n )\n}\n\nconst colors = {\n primary: '#7c3aed',\n background: '#f8fafc',\n cardBg: '#ffffff',\n text: '#1e293b',\n textMuted: '#64748b',\n textLight: '#94a3b8',\n border: '#e2e8f0',\n borderLight: '#f1f5f9',\n}\n\nconst main = {\n backgroundColor: colors.background,\n fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n padding: '40px 20px',\n}\n\nconst container = {\n margin: '0 auto',\n maxWidth: '600px',\n}\n\nconst header = {\n backgroundColor: colors.primary,\n borderRadius: '12px 12px 0 0',\n padding: '24px 32px',\n textAlign: 'center' as const,\n}\n\nconst logoText = {\n color: '#ffffff',\n fontSize: '24px',\n fontWeight: '700' as const,\n letterSpacing: '-0.02em',\n margin: '0',\n}\n\nconst titleSection = {\n backgroundColor: colors.cardBg,\n padding: '32px 32px 24px',\n textAlign: 'center' as const,\n}\n\nconst h1 = {\n color: colors.text,\n fontSize: '24px',\n fontWeight: '700' as const,\n lineHeight: '32px',\n margin: '0 0 8px',\n}\n\nconst subtitle = {\n color: colors.textMuted,\n fontSize: '14px',\n lineHeight: '20px',\n margin: '0',\n}\n\nconst card = {\n backgroundColor: colors.cardBg,\n padding: '0 32px 32px',\n}\n\nconst fieldRow = {\n borderBottom: \\`1px solid \\${colors.borderLight}\\`,\n padding: '16px 0',\n}\n\nconst label = {\n color: colors.textMuted,\n fontSize: '12px',\n fontWeight: '600' as const,\n letterSpacing: '0.025em',\n lineHeight: '16px',\n margin: '0 0 6px',\n textTransform: 'uppercase' as const,\n}\n\nconst value = {\n color: colors.text,\n fontSize: '16px',\n lineHeight: '24px',\n margin: '0',\n wordBreak: 'break-word' as const,\n}\n${linkStyle}${listItemStyle}${dynamicStyles}const footer = {\n backgroundColor: colors.cardBg,\n borderRadius: '0 0 12px 12px',\n borderTop: \\`1px solid \\${colors.border}\\`,\n padding: '24px 32px',\n textAlign: 'center' as const,\n}\n\nconst footerText = {\n color: colors.textLight,\n fontSize: '12px',\n lineHeight: '16px',\n margin: '0 0 8px',\n}\n\nconst footerBrand = {\n color: colors.textMuted,\n fontSize: '14px',\n fontWeight: '600' as const,\n margin: '0',\n}\n`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Shared string helpers used across all generators.\n */\n\nexport function toPascalCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nexport function toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nexport function singularize(str: string): string {\n if (str.endsWith('ies')) return `${str.slice(0, -3)}y`\n if (str.endsWith('ves')) return `${str.slice(0, -3)}f`\n if (\n str.endsWith('sses') ||\n str.endsWith('xes') ||\n str.endsWith('ches') ||\n str.endsWith('shes') ||\n str.endsWith('zes')\n )\n return str.slice(0, -2)\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\n\nexport function pluralize(str: string): string {\n if (str.endsWith('s') && !str.endsWith('ss')) return str\n if (str.endsWith('y') && !['ay', 'ey', 'iy', 'oy', 'uy'].some((v) => str.endsWith(v)))\n return `${str.slice(0, -1)}ies`\n if (str.endsWith('s') || str.endsWith('x') || str.endsWith('ch') || str.endsWith('sh'))\n return `${str}es`\n return `${str}s`\n}\n\nexport function toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\nexport function toScreamingSnake(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toUpperCase()\n}\n\nexport function quotePropertyName(name: string): string {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`\n}\n\nexport function singularizeLabel(label: string): string {\n const words = label.split(' ')\n const lastWord = words[words.length - 1]\n words[words.length - 1] = singularize(lastWord.toLowerCase())\n words[words.length - 1] =\n words[words.length - 1].charAt(0).toUpperCase() + words[words.length - 1].slice(1)\n return words.join(' ')\n}\n","/**\n * Form admin pages generator: creates admin UI for viewing/managing form submissions\n *\n * Generates under (authenticated)/forms/<name>/:\n * page.tsx, columns.tsx, <name>-submissions-table.tsx,\n * <name>-submissions-page-content.tsx, [id]/view/page.tsx\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { getAllFormSchemaFields, hasDynamicFields } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase, toKebabCase } from '../../utils/string.js'\nimport { generateColumns } from './admin-columns.js'\nimport { generatePage } from './admin-page.js'\nimport { generatePageContent } from './admin-page-content.js'\nimport { generateSettingsPage } from './admin-settings-page.js'\nimport { generateTable } from './admin-table.js'\nimport { generateViewPage } from './admin-view-page.js'\n\n// ============================================================================\n// Result Type\n// ============================================================================\n\nexport interface FormAdminPagesResult {\n files: string[]\n}\n\n// ============================================================================\n// Generator\n// ============================================================================\n\nexport function generateFormAdminPages(\n schema: FormSchema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions\n): FormAdminPagesResult {\n const formName = schema.name\n const kebab = toKebabCase(formName)\n const pascal = toPascalCase(formName)\n const camel = toCamelCase(formName)\n const fields = getAllFormSchemaFields(schema)\n\n const adminDir = path.join(cwd, pagesDir, 'forms', kebab)\n if (!fs.existsSync(adminDir)) fs.mkdirSync(adminDir, { recursive: true })\n\n const files: string[] = []\n const rel = (p: string) => path.relative(cwd, p)\n\n // 1. page.tsx\n const pagePath = path.join(adminDir, 'page.tsx')\n if (!fs.existsSync(pagePath) || options.force) {\n fs.writeFileSync(pagePath, generatePage(pascal, kebab), 'utf-8')\n }\n files.push(rel(pagePath))\n\n // 2. columns.tsx\n const columnsPath = path.join(adminDir, 'columns.tsx')\n if (!fs.existsSync(columnsPath) || options.force) {\n fs.writeFileSync(\n columnsPath,\n generateColumns(fields, pascal, kebab, camel, schema.columns),\n 'utf-8'\n )\n }\n files.push(rel(columnsPath))\n\n // 3. submissions-table.tsx\n const tablePath = path.join(adminDir, `${kebab}-submissions-table.tsx`)\n if (!fs.existsSync(tablePath) || options.force) {\n fs.writeFileSync(tablePath, generateTable(pascal, kebab, schema.label), 'utf-8')\n }\n files.push(rel(tablePath))\n\n // 4. submissions-page-content.tsx\n const contentPath = path.join(adminDir, `${kebab}-submissions-page-content.tsx`)\n if (!fs.existsSync(contentPath) || options.force) {\n fs.writeFileSync(contentPath, generatePageContent(pascal, kebab, camel, schema.label), 'utf-8')\n }\n files.push(rel(contentPath))\n\n // 5. [id]/view/page.tsx\n const viewDir = path.join(adminDir, '[id]', 'view')\n if (!fs.existsSync(viewDir)) fs.mkdirSync(viewDir, { recursive: true })\n const viewPath = path.join(viewDir, 'page.tsx')\n if (!fs.existsSync(viewPath) || options.force) {\n fs.writeFileSync(\n viewPath,\n generateViewPage(pascal, kebab, fields, schema.label, hasDynamicFields(schema)),\n 'utf-8'\n )\n }\n files.push(rel(viewPath))\n\n // 6. settings/page.tsx\n const settingsDir = path.join(adminDir, 'settings')\n if (!fs.existsSync(settingsDir)) fs.mkdirSync(settingsDir, { recursive: true })\n const settingsPath = path.join(settingsDir, 'page.tsx')\n if (!fs.existsSync(settingsPath) || options.force) {\n fs.writeFileSync(settingsPath, generateSettingsPage(pascal, kebab, schema.label), 'utf-8')\n }\n files.push(rel(settingsPath))\n\n return { files }\n}\n","import type { FormColumn, FormField } from '../../types.js'\n\n// ============================================================================\n// Column Definition Helper\n// ============================================================================\n\nfunction generateColumnDef(col: FormColumn): string {\n const sortableHeader = col.sortable\n ? `header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n >\n ${col.header}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n )`\n : `header: '${col.header}'`\n\n let cellDef: string\n switch (col.type) {\n case 'email':\n cellDef = `cell: ({ row }) => {\n const email = row.getValue('${col.accessorKey}') as string\n return email ? <a href={\\`mailto:\\${email}\\`} className=\"text-primary hover:underline\">{email}</a> : '-'\n }`\n break\n case 'date':\n cellDef = `cell: ({ row }) => {\n const date = row.getValue('${col.accessorKey}') as string\n return date ? new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) : '-'\n }`\n break\n case 'badge':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${col.accessorKey}') as string\n return <Badge variant=\"outline\">{value || 'N/A'}</Badge>\n }`\n break\n case 'number':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${col.accessorKey}') as number\n return <div className=\"text-right\">{value !== null && value !== undefined ? value : '-'}</div>\n }`\n break\n default:\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${col.accessorKey}') as string\n return <div>{value || '-'}</div>\n }`\n }\n\n return ` {\n accessorKey: '${col.accessorKey}',\n ${sortableHeader},\n ${cellDef}\n }`\n}\n\n// ============================================================================\n// Columns Generator\n// ============================================================================\n\nexport function generateColumns(\n fields: FormField[],\n pascal: string,\n kebab: string,\n camel: string,\n customColumns?: FormColumn[]\n): string {\n const hasBadge = customColumns?.some((c) => c.type === 'badge') ?? false\n\n const columnDefs = customColumns\n ? customColumns.map((col) => generateColumnDef(col)).join(',\\n')\n : fields\n .filter((f) => f.name)\n .map((f) => {\n const accessor = f.name!\n return ` {\n accessorKey: '${accessor}',\n header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n >\n ${f.label}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n ),\n cell: ({ row }) => {\n const value = row.getValue('${accessor}')\n return <div>${f.type === 'textarea' ? \"{value ? String(value).substring(0, 100) + (String(value).length > 100 ? '...' : '') : '-'}\" : \"{String(value ?? '-')}\"}</div>\n }\n }`\n })\n .join(',\\n')\n\n return `'use client'\n\nimport type { ${pascal}SubmissionData } from '@cms/actions/${kebab}-form'\nimport { delete${pascal}Submission } from '@cms/actions/${kebab}-form'\n${hasBadge ? \"import { Badge } from '@cms/components/ui/badge'\" : ''}\nimport { Button } from '@cms/components/ui/button'\nimport { Checkbox } from '@cms/components/ui/checkbox'\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ArrowUpDown, Eye, Trash } from 'lucide-react'\nimport Link from 'next/link'\nimport { useState, useTransition } from 'react'\nimport { toast } from 'sonner'\n\nfunction DeleteAction({ id }: { id: number }) {\n const [open, setOpen] = useState(false)\n const [isPending, startTransition] = useTransition()\n const queryClient = useQueryClient()\n\n const handleDelete = () => {\n startTransition(async () => {\n try {\n const result = await delete${pascal}Submission(id)\n if (result.success) {\n toast.success('Submission deleted successfully')\n queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete submission')\n }\n } catch {\n toast.error('An error occurred')\n }\n })\n }\n\n return (\n <AlertDialog open={open} onOpenChange={setOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" size=\"icon\" className=\"size-8\">\n <Trash className=\"size-3\" />\n <span className=\"sr-only\">Delete</span>\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This will permanently delete this submission.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e: React.MouseEvent) => { e.preventDefault(); handleDelete() }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n\nexport const columns: ColumnDef<${pascal}SubmissionData>[] = [\n {\n id: 'select',\n header: ({ table }) => (\n <Checkbox\n checked={table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && 'indeterminate')}\n onCheckedChange={(value: boolean) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value: boolean) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n enableSorting: false,\n enableHiding: false\n },\n${columnDefs},\n {\n id: 'actions',\n header: () => <div className=\"text-right\">Actions</div>,\n cell: ({ row }) => {\n const submission = row.original\n return (\n <div className=\"flex justify-end items-center gap-2\">\n <Button variant=\"outline\" size=\"icon\" className=\"size-8\" asChild>\n <Link href={\\`/cms/forms/${kebab}/\\${submission.id}/view\\`}>\n <Eye className=\"size-3\" />\n <span className=\"sr-only\">View</span>\n </Link>\n </Button>\n <DeleteAction id={submission.id} />\n </div>\n )\n }\n }\n]\n`\n}\n","export function generatePage(pascal: string, kebab: string): string {\n return `import { Suspense } from 'react'\nimport { ${pascal}SubmissionsPageContent } from './${kebab}-submissions-page-content'\nimport { columns } from './columns'\n\nexport default function Page() {\n return (\n <Suspense fallback={<div className=\"p-6\">Loading...</div>}>\n <${pascal}SubmissionsPageContent columns={columns} />\n </Suspense>\n )\n}\n`\n}\n","export function generatePageContent(pascal: string, kebab: string, camel: string, label: string): string {\n return `'use client'\n\nimport type { ${pascal}SubmissionData } from '@cms/actions/${kebab}-form'\nimport { deleteBulk${pascal}Submissions } from '@cms/actions/${kebab}-form'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ChevronLeft, Search, Settings, Trash2 } from 'lucide-react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { parseAsString, useQueryState } from 'nuqs'\nimport { startTransition, useCallback, useState, useTransition } from 'react'\nimport { toast } from 'sonner'\nimport { ${pascal}SubmissionsTable } from './${kebab}-submissions-table'\n\ninterface ${pascal}SubmissionsPageContentProps<TValue> {\n columns: ColumnDef<${pascal}SubmissionData, TValue>[]\n}\n\nexport function ${pascal}SubmissionsPageContent<TValue>({\n columns,\n}: ${pascal}SubmissionsPageContentProps<TValue>) {\n const router = useRouter()\n const queryClient = useQueryClient()\n const [search, setSearch] = useQueryState('q', parseAsString.withDefault(''))\n const [selectedIds, setSelectedIds] = useState<number[]>([])\n const [deleteOpen, setDeleteOpen] = useState(false)\n const [isPending, startDeleteTransition] = useTransition()\n\n const searchAction = useCallback(\n async (formData: FormData) => {\n const value = formData.get('search') as string\n startTransition(() => {\n setSearch(value || null)\n })\n },\n [setSearch]\n )\n\n const handleBulkDelete = () => {\n startDeleteTransition(async () => {\n try {\n const result = await deleteBulk${pascal}Submissions(selectedIds)\n if (result.success) {\n toast.success(\\`\\${selectedIds.length} submission\\${selectedIds.length > 1 ? 's' : ''} deleted\\`)\n queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n setSelectedIds([])\n setDeleteOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete submissions')\n }\n } catch {\n toast.error('An error occurred')\n }\n })\n }\n\n return (\n <>\n <PageHeader title=\"${label}\" back={<Button variant=\"ghost\" size=\"icon\" onClick={() => router.back()}><ChevronLeft /></Button>} search={<form action={searchAction} className=\"flex items-center gap-2 relative\">\n <Search className=\"text-muted-foreground/70 pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\" />\n <Input\n key={search}\n name=\"search\"\n placeholder=\"Search submissions...\"\n defaultValue={search}\n className=\"w-64 pl-9 bg-white rounded-full\"\n />\n </form>} actions={<div className=\"flex items-center gap-2\">\n {selectedIds.length > 0 && (\n <AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" size=\"default\">\n <Trash2 className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Delete {selectedIds.length}\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This will permanently delete {selectedIds.length}{' '}\n {selectedIds.length === 1 ? 'submission' : 'submissions'}.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e: React.MouseEvent) => { e.preventDefault(); handleBulkDelete() }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/forms/${kebab}/settings\">\n <Settings className=\"size-3.5\" />\n Settings\n </Link>\n </Button>\n </div>} />\n <main className=\"space-y-4 p-6\">\n <${pascal}SubmissionsTable\n columns={columns}\n selectedIds={selectedIds}\n setSelectedIds={setSelectedIds}\n search={search}\n />\n </main>\n </>\n )\n}\n`\n}\n","export function generateSettingsPage(pascal: string, kebab: string, label: string): string {\n return `'use client'\n\nimport {\n getFormSettings,\n testFormWebhook,\n upsertFormSettings,\n} from '@cms/actions/form-settings'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport { Label } from '@cms/components/ui/label'\nimport { Switch } from '@cms/components/ui/switch'\nimport { Textarea } from '@cms/components/ui/textarea'\nimport { ChevronLeft, Loader2 } from 'lucide-react'\nimport { useRouter } from 'next/navigation'\nimport { useEffect, useState, useTransition } from 'react'\nimport { toast } from 'sonner'\n\nexport default function ${pascal}SettingsPage() {\n const router = useRouter()\n const [notificationEmails, setNotificationEmails] = useState('')\n const [webhookUrl, setWebhookUrl] = useState('')\n const [webhookEnabled, setWebhookEnabled] = useState(false)\n const [isSaving, startSaveTransition] = useTransition()\n const [isTesting, startTestTransition] = useTransition()\n const [loaded, setLoaded] = useState(false)\n\n useEffect(() => {\n getFormSettings('${kebab}').then((settings) => {\n if (settings) {\n setNotificationEmails(settings.notificationEmails ?? '')\n setWebhookUrl(settings.webhookUrl ?? '')\n setWebhookEnabled(settings.webhookEnabled)\n }\n setLoaded(true)\n })\n }, [])\n\n const handleSave = () => {\n startSaveTransition(async () => {\n const result = await upsertFormSettings('${kebab}', {\n notificationEmails: notificationEmails || null,\n webhookUrl: webhookUrl || null,\n webhookEnabled,\n })\n if (result.success) {\n toast.success('Settings saved successfully')\n } else {\n toast.error(result.error || 'Failed to save settings')\n }\n })\n }\n\n const handleTestWebhook = () => {\n startTestTransition(async () => {\n const result = await testFormWebhook('${kebab}')\n if (result.success) {\n toast.success('Test webhook sent successfully')\n } else {\n toast.error(result.error || 'Failed to send test webhook')\n }\n })\n }\n\n if (!loaded) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"size-6 animate-spin text-muted-foreground\" />\n </div>\n )\n }\n\n return (\n <>\n <PageHeader title=\"${label} Settings\" back={<Button variant=\"ghost\" size=\"icon\" onClick={() => router.back()}><ChevronLeft /></Button>} />\n <div className=\"space-y-6 rounded-lg border p-6 mx-6 mt-6\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"notificationEmails\">Notification Emails</Label>\n <Textarea\n id=\"notificationEmails\"\n placeholder=\"email@example.com, another@example.com\"\n value={notificationEmails}\n onChange={(e) => setNotificationEmails(e.target.value)}\n rows={3}\n />\n <p className=\"text-xs text-muted-foreground\">\n Comma-separated list of email addresses to notify on new submissions.\n </p>\n </div>\n\n <div className=\"space-y-4 border-t pt-6\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"webhookUrl\">Webhook URL</Label>\n <Input\n id=\"webhookUrl\"\n type=\"url\"\n placeholder=\"https://hooks.example.com/endpoint\"\n value={webhookUrl}\n onChange={(e) => setWebhookUrl(e.target.value)}\n />\n <p className=\"text-xs text-muted-foreground\">\n Receive a POST request with form data on each submission.\n </p>\n </div>\n\n <div className=\"flex items-center space-x-2\">\n <Switch\n id=\"webhookEnabled\"\n checked={webhookEnabled}\n onCheckedChange={setWebhookEnabled}\n />\n <Label htmlFor=\"webhookEnabled\">Enable Webhook</Label>\n </div>\n\n {webhookUrl && webhookEnabled && (\n <Button\n variant=\"outline\"\n onClick={handleTestWebhook}\n disabled={isTesting}\n >\n {isTesting ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Sending...\n </>\n ) : (\n 'Test Webhook'\n )}\n </Button>\n )}\n </div>\n\n <div className=\"border-t pt-6\">\n <Button onClick={handleSave} disabled={isSaving}>\n {isSaving ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Saving...\n </>\n ) : (\n 'Save Settings'\n )}\n </Button>\n </div>\n </div>\n </>\n )\n}\n`\n}\n","export function generateTable(pascal: string, kebab: string, label: string): string {\n return `'use client'\n\nimport type { ${pascal}SubmissionData } from '@cms/actions/${kebab}-form'\nimport { use${pascal}Submissions } from '@cms/hooks/use-${kebab}-form'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@cms/components/ui/table'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport { useCallback, useMemo, useState } from 'react'\n\nconst PAGE_SIZE_OPTIONS = [\n { value: '10', label: '10' },\n { value: '20', label: '20' },\n { value: '50', label: '50' },\n { value: '100', label: '100' },\n { value: 'all', label: 'All' },\n]\n\ninterface ${pascal}SubmissionsTableProps<TValue> {\n columns: ColumnDef<${pascal}SubmissionData, TValue>[]\n selectedIds: number[]\n setSelectedIds: (ids: number[]) => void\n search?: string\n}\n\nexport function ${pascal}SubmissionsTable<TValue>({\n columns,\n selectedIds,\n setSelectedIds,\n search,\n}: ${pascal}SubmissionsTableProps<TValue>) {\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0))\n const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(10))\n\n const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize\n\n const handlePageSizeChange = useCallback(\n (value: string) => {\n if (value === 'all') {\n setPageSize(-1)\n } else {\n setPageSize(Number.parseInt(value, 10))\n }\n setPageIndex(0)\n },\n [setPageSize, setPageIndex]\n )\n\n const { data, error, isPending } = use${pascal}Submissions(search)\n\n const rowSelection = useMemo(() => {\n const selection: Record<string, boolean> = {}\n const submissions = data?.submissions ?? []\n submissions.forEach((sub, idx) => {\n if (selectedIds.includes(sub.id)) {\n selection[idx.toString()] = true\n }\n })\n return selection\n }, [selectedIds, data?.submissions])\n\n const handleRowSelectionChange = useCallback(\n (updater: Record<string, boolean> | ((old: Record<string, boolean>) => Record<string, boolean>)) => {\n const submissions = data?.submissions ?? []\n const newSelection = typeof updater === 'function' ? updater(rowSelection) : updater\n const newIds = Object.keys(newSelection)\n .filter((key) => newSelection[key])\n .map((key) => submissions[Number.parseInt(key, 10)]?.id)\n .filter(Boolean) as number[]\n setSelectedIds(newIds)\n },\n [data?.submissions, rowSelection, setSelectedIds]\n )\n\n const table = useReactTable({\n data: data?.submissions ?? [],\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n onRowSelectionChange: handleRowSelectionChange,\n state: {\n sorting,\n columnFilters,\n columnVisibility,\n rowSelection,\n pagination: { pageIndex, pageSize: effectivePageSize },\n },\n })\n\n return (\n <div className=\"space-y-4\">\n <div className=\"rounded-lg border overflow-hidden\">\n <Table>\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead key={header.id}>\n {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center text-muted-foreground\">\n Loading ${label} submissions...\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center text-destructive\">\n Error: {error.message}\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No submissions found.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-2\">\n <p className=\"text-sm text-muted-foreground\">Rows per page</p>\n <Select\n value={pageSize === -1 ? 'all' : pageSize.toString()}\n onValueChange={handlePageSizeChange}\n >\n <SelectTrigger className=\"h-8 w-[70px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent side=\"top\">\n {PAGE_SIZE_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center space-x-2\">\n <div className=\"flex w-[100px] items-center justify-center text-sm font-medium\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setPageIndex(Math.max(0, pageIndex - 1))} disabled={!table.getCanPreviousPage()}>\n Previous\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setPageIndex(pageIndex + 1)} disabled={!table.getCanNextPage()}>\n Next\n </Button>\n </div>\n </div>\n </div>\n )\n}\n`\n}\n","import type { FormField } from '../../types.js'\n\nexport function generateViewPage(\n pascal: string,\n kebab: string,\n fields: FormField[],\n label: string,\n includeDynamic: boolean\n): string {\n const fieldItems = fields\n .filter((f) => f.name)\n .map((f) => {\n const name = f.name!\n const lbl = f.label\n\n if (f.type === 'email') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">\n {submission.${name} ? (\n <a href={\\`mailto:\\${submission.${name}}\\`} className=\"text-primary hover:underline\">{submission.${name}}</a>\n ) : '-'}\n </p>\n </div>`\n }\n if (f.type === 'textarea') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm whitespace-pre-wrap\">{submission.${name} || '-'}</p>\n </div>`\n }\n if (f.type === 'checkbox') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">{submission.${name} ? 'Yes' : 'No'}</p>\n </div>`\n }\n if (f.type === 'date') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">{submission.${name} ? new Date(submission.${name}).toLocaleDateString() : '-'}</p>\n </div>`\n }\n if (f.type === 'url') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">\n {submission.${name} ? (\n <a href={submission.${name}} target=\"_blank\" rel=\"noopener noreferrer\" className=\"text-primary hover:underline break-all\">{submission.${name}}</a>\n ) : '-'}\n </p>\n </div>`\n }\n if (f.type === 'list' || f.type === 'multiselect') {\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <div className=\"text-sm\">\n {Array.isArray(submission.${name}) && submission.${name}.length > 0 ? (\n <ul className=\"list-disc list-inside space-y-1\">\n {submission.${name}.map((item: Record<string, unknown>, idx: number) => (\n <li key={idx}>{typeof item === 'string' ? item : Object.entries(item).map(([k, v]) => \\`\\${k}: \\${v}\\`).join(', ')}</li>\n ))}\n </ul>\n ) : '-'}\n </div>\n </div>`\n }\n return ` <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-muted-foreground\">${lbl}</p>\n <p className=\"text-sm\">{submission.${name} ?? '-'}</p>\n </div>`\n })\n .join('\\n')\n\n const customFieldsSection = includeDynamic\n ? `\n {submission.customFields && Object.keys(submission.customFields).length > 0 && (\n <div className=\"space-y-3 border-t pt-4\">\n <p className=\"text-sm font-semibold text-muted-foreground\">Custom Fields</p>\n {Object.entries(submission.customFields).map(([key, value]) => (\n <div key={key} className=\"space-y-1\">\n <p className=\"text-sm font-medium capitalize\">{key.replace(/([A-Z])/g, ' $1').trim()}</p>\n <p className=\"text-sm\">{value !== null && value !== undefined ? String(value) : '-'}</p>\n </div>\n ))}\n </div>\n )}`\n : ''\n\n return `import { get${pascal}Submission } from '@cms/actions/${kebab}-form'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { ChevronLeft } from 'lucide-react'\nimport Link from 'next/link'\nimport { notFound } from 'next/navigation'\n\ninterface PageProps {\n params: Promise<{ id: string }>\n}\n\nexport default async function Page({ params }: PageProps) {\n const { id } = await params\n const submission = await get${pascal}Submission(Number.parseInt(id, 10))\n\n if (!submission) {\n notFound()\n }\n\n return (\n <>\n <PageHeader title=\"${label} Submission\" back={<Button variant=\"ghost\" size=\"icon\" asChild><Link href=\"/cms/forms/${kebab}\"><ChevronLeft /></Link></Button>} />\n <div className=\"rounded-lg border p-6 mx-6 mt-6 space-y-4\">\n${fieldItems}${customFieldsSection}\n <div className=\"space-y-1 border-t pt-4\">\n <p className=\"text-sm font-medium text-muted-foreground\">Submitted At</p>\n <p className=\"text-sm\">\n {new Date(submission.submittedAt).toLocaleString('en-US', {\n month: 'long', day: 'numeric', year: 'numeric',\n hour: 'numeric', minute: '2-digit'\n })}\n </p>\n </div>\n </div>\n </>\n )\n}\n`\n}\n","/**\n * Form navigation generator: adds form submissions entry to cms/data/navigation.ts\n * Each form gets a flat nav item with group: 'Forms'\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { FormSchema, GeneratorOptions } from '../types.js'\nimport { toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface NavItem {\n label: string\n href: string\n icon?: string\n group?: string\n}\n\n// ============================================================================\n// Parser (mirrors entity navigation generator)\n// ============================================================================\n\nfunction parseNavigationFile(content: string): { items: NavItem[]; iconImports: string[] } {\n const iconImportMatch = content.match(/import\\s*\\{([^}]+)\\}\\s*from\\s*['\"]lucide-react['\"]/)\n const iconImports: string[] = iconImportMatch\n ? iconImportMatch[1]\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s && s !== 'LucideIcon')\n : []\n\n const arrayBlock = extractTopLevelArray(content)\n if (!arrayBlock) return { items: [], iconImports }\n\n return { items: parseItemsBlock(arrayBlock), iconImports }\n}\n\nfunction extractTopLevelArray(content: string): string | null {\n const marker = content.indexOf('cmsNavigation')\n if (marker === -1) return null\n\n const eqSign = content.indexOf('=', marker)\n if (eqSign === -1) return null\n const openBracket = content.indexOf('[', eqSign)\n if (openBracket === -1) return null\n\n let depth = 0\n for (let i = openBracket; i < content.length; i++) {\n if (content[i] === '[') depth++\n if (content[i] === ']') depth--\n if (depth === 0) {\n return content.slice(openBracket + 1, i)\n }\n }\n return null\n}\n\nfunction parseItemsBlock(block: string): NavItem[] {\n const items: NavItem[] = []\n let depth = 0\n let current = ''\n let inObj = false\n\n for (const char of block) {\n if (char === '{') {\n if (depth === 0) inObj = true\n depth++\n current += char\n } else if (char === '}') {\n depth--\n current += char\n if (depth === 0 && inObj) {\n const item = parseSingleItem(current)\n if (item) items.push(item)\n current = ''\n inObj = false\n }\n } else if (inObj) {\n current += char\n }\n }\n\n return items\n}\n\nfunction parseSingleItem(str: string): NavItem | null {\n const labelMatch = str.match(/label:\\s*['\"]([^'\"]+)['\"]/)\n const hrefMatch = str.match(/href:\\s*['\"]([^'\"]+)['\"]/)\n const iconMatch = str.match(/icon:\\s*(\\w+)/)\n const groupMatch = str.match(/group:\\s*['\"]([^'\"]+)['\"]/)\n\n if (!labelMatch || !hrefMatch) return null\n\n const item: NavItem = { label: labelMatch[1], href: hrefMatch[1] }\n if (iconMatch) item.icon = iconMatch[1]\n if (groupMatch) item.group = groupMatch[1]\n\n return item\n}\n\n// ============================================================================\n// Code Generator (mirrors entity navigation generator)\n// ============================================================================\n\nfunction generateNavigationCode(items: NavItem[], iconImports: string[]): string {\n const lines: string[] = []\n\n lines.push(\"import type { LucideIcon } from 'lucide-react'\")\n lines.push(`import { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push('')\n lines.push('export interface CmsNavigationItem {')\n lines.push(' label: string')\n lines.push(' href: string')\n lines.push(' icon?: LucideIcon')\n lines.push(' group?: string')\n lines.push('}')\n lines.push('')\n lines.push('export const cmsNavigation: CmsNavigationItem[] = [')\n\n for (let i = 0; i < items.length; i++) {\n appendItem(lines, items[i], i === items.length - 1)\n }\n\n lines.push(']')\n lines.push('')\n\n return lines.join('\\n')\n}\n\nfunction appendItem(lines: string[], item: NavItem, isLast: boolean): void {\n lines.push(' {')\n lines.push(` label: '${item.label}',`)\n\n const hasMore = item.icon != null || item.group != null\n lines.push(` href: '${item.href}'${hasMore ? ',' : ''}`)\n\n if (item.icon && item.group) {\n lines.push(` icon: ${item.icon},`)\n lines.push(` group: '${item.group}'`)\n } else if (item.icon) {\n lines.push(` icon: ${item.icon}`)\n } else if (item.group) {\n lines.push(` group: '${item.group}'`)\n }\n\n lines.push(` }${isLast ? '' : ','}`)\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface FormNavigationResult {\n files: string[]\n}\n\n/**\n * Update cms/data/navigation.ts to add form under \"Forms\" group\n */\nexport function updateFormNavigation(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions = {}\n): FormNavigationResult {\n const navFilePath = path.join(cwd, cmsDir, 'data', 'navigation.ts')\n\n let items: NavItem[] = []\n let iconImports: string[] = []\n\n if (fs.existsSync(navFilePath)) {\n const content = fs.readFileSync(navFilePath, 'utf-8')\n const parsed = parseNavigationFile(content)\n items = parsed.items\n iconImports = parsed.iconImports\n }\n\n // Create form nav item with group: 'Forms'\n const kebab = toKebabCase(schema.name)\n const formHref = `/cms/forms/${kebab}`\n const existingIndex = items.findIndex((item) => item.href === formHref)\n\n const newItem: NavItem = {\n label: schema.label,\n href: formHref,\n icon: 'Inbox',\n group: 'Forms'\n }\n\n if (existingIndex >= 0) {\n if (options.force) {\n items[existingIndex] = newItem\n } else {\n return { files: [] }\n }\n } else {\n items.push(newItem)\n }\n\n // Reorganize: Dashboard first, then ungrouped alphabetical, then grouped alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => {\n if (!a.group && b.group) return -1\n if (a.group && !b.group) return 1\n if (a.group && b.group && a.group !== b.group) return a.group.localeCompare(b.group)\n return a.label.localeCompare(b.label)\n })\n\n items = [...(dashboard ? [dashboard] : []), ...others]\n\n // Ensure required icon is imported\n if (!iconImports.includes('Inbox')) {\n iconImports.push('Inbox')\n }\n iconImports.sort()\n\n // Write\n const dir = path.dirname(navFilePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n fs.writeFileSync(navFilePath, generateNavigationCode(items, iconImports), 'utf-8')\n\n return { files: [path.join(cmsDir, 'data', 'navigation.ts')] }\n}\n","/**\n * Form pipeline step 2: Server actions for form submissions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields } from '../../core/field-helpers/index.js'\nimport type { FormField, FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase, toKebabCase } from '../../utils/string.js'\n\ninterface StepResult {\n files: string[]\n}\n\n/**\n * Generate Mailchimp audience subscription code for a form\n * Auto-detects the email field unless explicitly specified in schema\n */\nfunction generateMailchimpCode(schema: FormSchema, fields: FormField[]): string {\n if (!schema.mailchimp) return ''\n\n let emailFieldName: string\n if (typeof schema.mailchimp === 'object' && schema.mailchimp.emailField) {\n emailFieldName = schema.mailchimp.emailField\n } else {\n const emailField = fields.find((f) => f.type === 'email')\n if (!emailField || !emailField.name) {\n console.warn(\n `Warning: Form \"${schema.name}\" has mailchimp enabled but no email field found. Skipping.`\n )\n return ''\n }\n emailFieldName = emailField.name\n }\n\n return `\\n // Add to Mailchimp audience (fire-and-forget, non-blocking)\n addToMailchimpAudience(data.${emailFieldName})`\n}\n\nexport function generateFormActions(\n schema: FormSchema,\n cwd: string,\n actionsDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const tableName = `${toCamelCase(formName)}Submissions`\n const pascal = toPascalCase(formName)\n const fields = getAllFormSchemaFields(schema)\n\n // Build TypeScript interface for submission data\n const dataFields = fields\n .map((f) => {\n let tsType = 'string'\n if (f.type === 'number') tsType = 'number'\n else if (f.type === 'checkbox') tsType = 'boolean'\n else if (f.type === 'multiselect') tsType = 'string[]'\n else if (f.type === 'list') {\n tsType = f.fields && f.fields.length > 0 ? 'Record<string, unknown>[]' : 'string[]'\n }\n const isReq = f.required && !f.condition\n const opt = isReq ? '' : '?'\n const nullable = isReq ? '' : ' | null'\n return ` ${f.name}${opt}: ${tsType}${nullable}`\n })\n .join('\\n')\n\n // Server-side validation for required fields\n const validation = fields\n .filter((f) => f.required && !f.condition)\n .map(\n (f) =>\n `if (!data.${f.name}) {\\n return { success: false, error: '${f.label} is required' }\\n }`\n )\n .join('\\n ')\n\n const kebab = toKebabCase(formName)\n const filePath = path.join(cwd, actionsDir, `${kebab}-form.ts`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const mailchimpImport = schema.mailchimp\n ? `\\nimport { addToMailchimpAudience } from '@cms/utils/mailchimp'`\n : ''\n const mailchimpCall = generateMailchimpCode(schema, fields)\n\n const content = `'use server'\n\nimport { desc, eq, or } from 'drizzle-orm'\nimport db from '@cms/db'\nimport { ${tableName} } from '@cms/db/schema'\nimport { getFormSettings } from '@cms/actions/form-settings'\nimport { sendWebhook } from '@cms/utils/webhook'${mailchimpImport}\n\nexport interface ${pascal}SubmissionData {\n id: number\n${dataFields}\n ipAddress: string | null\n userAgent: string | null\n submittedAt: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface ${pascal}SubmissionsResponse {\n submissions: ${pascal}SubmissionData[]\n total: number\n}\n\nexport interface Create${pascal}SubmissionInput {\n${dataFields}\n ipAddress?: string\n userAgent?: string\n}\n\nexport interface Create${pascal}SubmissionResult {\n success: boolean\n error?: string\n submission?: ${pascal}SubmissionData\n}\n\nexport interface Delete${pascal}SubmissionResult {\n success: boolean\n error?: string\n count?: number\n}\n\nexport async function get${pascal}Submissions(): Promise<${pascal}SubmissionsResponse> {\n try {\n const submissions = await db.select().from(${tableName}).orderBy(desc(${tableName}.submittedAt))\n return {\n submissions: submissions as ${pascal}SubmissionData[],\n total: submissions.length\n }\n } catch (error) {\n console.error('Error fetching ${formName} submissions:', error)\n throw new Error('Failed to fetch ${formName} submissions')\n }\n}\n\nexport async function get${pascal}Submission(id: number): Promise<${pascal}SubmissionData | null> {\n try {\n const [submission] = await db\n .select()\n .from(${tableName})\n .where(eq(${tableName}.id, id))\n .limit(1)\n return (submission as ${pascal}SubmissionData) ?? null\n } catch (error) {\n console.error(\\`Error fetching ${formName} submission \\${id}:\\`, error)\n throw new Error('Failed to fetch ${formName} submission')\n }\n}\n\nexport async function create${pascal}Submission(\n data: Create${pascal}SubmissionInput\n): Promise<Create${pascal}SubmissionResult> {\n try {\n ${validation}\n\n const [submission] = await db\n .insert(${tableName})\n .values({\n ...data,\n submittedAt: new Date().toISOString()\n })\n .returning()\n\n // Resolve notification emails from form settings or env var\n const settings = await getFormSettings('${formName}')\n const notificationEmails = settings?.notificationEmails\n ? settings.notificationEmails.split(',').map((e: string) => e.trim()).filter(Boolean)\n : process.env.NOTIFICATION_EMAIL\n ? [process.env.NOTIFICATION_EMAIL]\n : []\n\n if (notificationEmails.length > 0) {\n // TODO: Send notification email using your email provider (e.g. Resend)\n console.log(\\`[${formName}] New submission — notify: \\${notificationEmails.join(', ')}\\`)\n }\n\n // Send webhook if enabled\n if (settings?.webhookEnabled && settings?.webhookUrl) {\n sendWebhook(settings.webhookUrl, {\n form_name: '${formName}',\n submission_id: submission.id,\n ...data,\n submitted_at: (submission as ${pascal}SubmissionData).submittedAt,\n })\n }${mailchimpCall}\n\n return {\n success: true,\n submission: submission as ${pascal}SubmissionData\n }\n } catch (error) {\n console.error('Error creating ${formName} submission:', error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create ${formName} submission'\n }\n }\n}\n\nexport async function delete${pascal}Submission(id: number): Promise<Delete${pascal}SubmissionResult> {\n try {\n await db.delete(${tableName}).where(eq(${tableName}.id, id))\n return { success: true }\n } catch (error) {\n console.error(\\`Error deleting ${formName} submission \\${id}:\\`, error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete ${formName} submission'\n }\n }\n}\n\nexport async function deleteBulk${pascal}Submissions(ids: number[]): Promise<Delete${pascal}SubmissionResult> {\n try {\n if (ids.length === 0) return { success: true, count: 0 }\n await db.delete(${tableName}).where(\n or(...ids.map(id => eq(${tableName}.id, id)))\n )\n return { success: true, count: ids.length }\n } catch (error) {\n console.error(\\`Error bulk deleting ${formName} submissions:\\`, error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to bulk delete ${formName} submissions'\n }\n }\n}\n\nexport async function export${pascal}SubmissionsCSV(): Promise<string> {\n const { submissions } = await get${pascal}Submissions()\n if (submissions.length === 0) return ''\n const headers = Object.keys(submissions[0]).join(',')\n const rows = submissions.map((sub) =>\n Object.values(sub)\n .map((val: unknown) => {\n if (val === null || val === undefined) return ''\n const str = String(val)\n if (str.includes(',') || str.includes('\"') || str.includes('\\\\n')) {\n return \\`\"\\${str.replace(/\"/g, '\"\"')}\"\\`\n }\n return str\n })\n .join(',')\n )\n return [headers, ...rows].join('\\\\n')\n}\n\nexport async function export${pascal}SubmissionsJSON(): Promise<string> {\n const { submissions } = await get${pascal}Submissions()\n return JSON.stringify(submissions, null, 2)\n}\n`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Multi-step wizard form component generator\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields, getStepFieldNames } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toKebabCase } from '../../utils/string.js'\nimport {\n type StepResult,\n resolveUiImport,\n escapeJsx,\n renderFieldsJSX,\n buildZodFields,\n buildDefaultValues,\n buildFieldArrayDecls,\n buildWatchDecls,\n getListFields,\n} from './form-component-shared.js'\n\nexport function generateMultiStepForm(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const kebab = toKebabCase(formName)\n const steps = schema.steps!\n\n const filePath = path.join(cwd, cmsDir, 'components', 'forms', `${kebab}-form.tsx`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n // All fields flattened (for Zod schema + defaults)\n const allFields = getAllFormSchemaFields(schema)\n const zodFields = buildZodFields(allFields)\n const defaults = buildDefaultValues(allFields)\n\n // List fields and watch declarations are global\n const listFields = getListFields(allFields)\n const hasListFields = listFields.length > 0\n const { setup: watchSetup } = buildWatchDecls(allFields)\n\n const rhfImport = hasListFields\n ? `import { useFieldArray, useForm } from 'react-hook-form'`\n : `import { useForm } from 'react-hook-form'`\n const fieldArraySetup = hasListFields ? `\\n${buildFieldArrayDecls(listFields)}\\n` : ''\n\n // Build STEPS constant\n const stepsConst = buildStepsConstant(steps, schema)\n\n // Build per-step content blocks\n const stepContentBlocks = steps\n .map((step, index) => {\n const fieldsJSX = renderFieldsJSX(step.fields)\n return ` {currentStep === ${index} && (\\n <>\\n${fieldsJSX}\\n </>\\n )}`\n })\n .join('\\n')\n\n const submitText = schema.submitButtonText || 'Submit'\n const successMessage = escapeJsx(schema.successMessage || 'Form submitted successfully!')\n\n // Resolve UI imports\n const hasRadio = allFields.some((f) => f.type === 'radio')\n const hasFileUpload = allFields.some((f) => f.type === 'file' || f.type === 'upload')\n const buttonImport = resolveUiImport(cwd, 'button')\n const formImport = resolveUiImport(cwd, 'form')\n const inputImport = resolveUiImport(cwd, 'input')\n const textareaImport = resolveUiImport(cwd, 'textarea')\n const selectImport = resolveUiImport(cwd, 'select')\n const radioGroupImport = resolveUiImport(cwd, 'radio-group')\n const mediaUploadImport = resolveUiImport(cwd, 'media-upload-field')\n\n const content = buildComponentSource({\n pascal,\n kebab,\n rhfImport,\n hasRadio,\n hasFileUpload,\n hasListFields,\n buttonImport,\n formImport,\n inputImport,\n textareaImport,\n selectImport,\n radioGroupImport,\n mediaUploadImport,\n zodFields,\n defaults,\n stepsConst,\n fieldArraySetup,\n watchSetup,\n stepContentBlocks,\n submitText,\n successMessage,\n })\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n\nfunction buildStepsConstant(\n steps: NonNullable<FormSchema['steps']>,\n schema: FormSchema\n): string {\n const entries = steps.map((step) => {\n const fieldNames = getStepFieldNames(step)\n const fieldsStr = fieldNames.map((n) => `'${n}'`).join(', ')\n const desc = step.description ? `, description: '${escapeQuotes(step.description)}'` : ''\n return ` { name: '${step.name}', label: '${escapeQuotes(step.label)}'${desc}, fields: [${fieldsStr}] }`\n })\n return `const STEPS = [\\n${entries.join(',\\n')}\\n]`\n}\n\nfunction escapeQuotes(str: string): string {\n return str.replace(/'/g, \"\\\\'\")\n}\n\ninterface ComponentParts {\n pascal: string\n kebab: string\n rhfImport: string\n hasRadio: boolean\n hasFileUpload: boolean\n hasListFields: boolean\n buttonImport: string\n formImport: string\n inputImport: string\n textareaImport: string\n selectImport: string\n radioGroupImport: string\n mediaUploadImport: string\n zodFields: string\n defaults: string\n stepsConst: string\n fieldArraySetup: string\n watchSetup: string\n stepContentBlocks: string\n submitText: string\n successMessage: string\n}\n\nfunction buildComponentSource(p: ComponentParts): string {\n const queryClientImport = p.hasFileUpload\n ? `\\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'`\n : ''\n const queryClientSetup = p.hasFileUpload\n ? `\\nconst queryClient = new QueryClient()\\n`\n : ''\n const formComponentDecl = p.hasFileUpload ? `function ${p.pascal}FormInner` : `export function ${p.pascal}Form`\n const exportWrapper = p.hasFileUpload\n ? `\\nexport function ${p.pascal}Form() {\n return (\n <QueryClientProvider client={queryClient}>\n <${p.pascal}FormInner />\n </QueryClientProvider>\n )\n}\\n`\n : ''\n\n return `'use client'\n\nimport { ChevronLeft, ChevronRight${p.hasListFields ? ', Trash2' : ''} } from 'lucide-react'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport { useState } from 'react'\n${p.rhfImport}\nimport { z } from 'zod/v3'${queryClientImport}\nimport { create${p.pascal}Submission } from '@cms/actions/${p.kebab}-form'\nimport { Button } from '${p.buttonImport}'\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '${p.formImport}'\nimport { Input } from '${p.inputImport}'${p.hasFileUpload ? `\\nimport { MediaUploadField } from '${p.mediaUploadImport}'` : ''}\n${p.hasRadio ? `import { RadioGroup, RadioGroupItem } from '${p.radioGroupImport}'\\n` : ''}\nimport { Textarea } from '${p.textareaImport}'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '${p.selectImport}'\n\nconst formSchema = z.object({\n${p.zodFields}\n})\n\ntype FormValues = z.infer<typeof formSchema>\n${queryClientSetup}\n${p.stepsConst}\n\n${formComponentDecl}() {\n const [currentStep, setCurrentStep] = useQueryState('step', parseAsInteger.withDefault(0))\n const [submitted, setSubmitted] = useState(false)\n const [submitting, setSubmitting] = useState(false)\n\n const form = useForm<FormValues>({\n defaultValues: {\n${p.defaults}\n },\n })\n\n${p.fieldArraySetup}${p.watchSetup}\n async function handleNext() {\n const stepFields = STEPS[currentStep].fields as (keyof FormValues)[]\n const values = form.getValues()\n form.clearErrors(stepFields)\n let isValid = true\n for (const fieldName of stepFields) {\n const fieldSchema = formSchema.shape[fieldName]\n if (!fieldSchema) continue\n const result = fieldSchema.safeParse(values[fieldName])\n if (!result.success) {\n form.setError(fieldName, { type: 'validate', message: result.error.issues[0].message })\n isValid = false\n }\n }\n if (isValid) {\n setCurrentStep(currentStep + 1)\n }\n }\n\n function handleBack() {\n setCurrentStep(currentStep - 1)\n }\n\n async function onSubmit(values: FormValues) {\n const validation = formSchema.safeParse(values)\n if (!validation.success) {\n for (const issue of validation.error.issues) {\n const fieldName = issue.path[0] as keyof FormValues\n form.setError(fieldName, { type: 'validate', message: issue.message })\n }\n return\n }\n setSubmitting(true)\n try {\n const result = await create${p.pascal}Submission(validation.data)\n if (result.success) {\n setSubmitted(true)\n } else {\n form.setError('root', { message: result.error || 'Something went wrong' })\n }\n } catch {\n form.setError('root', { message: 'Something went wrong. Please try again.' })\n } finally {\n setSubmitting(false)\n }\n }\n\n if (submitted) {\n return (\n <div className=\"rounded-lg border p-6 text-center\">\n <h3 className=\"text-lg font-semibold\">Thank you!</h3>\n <p className=\"mt-2 text-muted-foreground\">${p.successMessage}</p>\n </div>\n )\n }\n\n return (\n <Form {...form}>\n <form onSubmit={(e) => e.preventDefault()} className=\"space-y-8\">\n {/* Step header */}\n <div>\n <h3 className=\"text-lg font-semibold\">{STEPS[currentStep].label}</h3>\n {'description' in STEPS[currentStep] && STEPS[currentStep].description && (\n <p className=\"text-sm text-muted-foreground mt-1\">{STEPS[currentStep].description}</p>\n )}\n </div>\n\n {/* Step content */}\n <div key={currentStep} className=\"animate-in fade-in duration-300 space-y-6\">\n${p.stepContentBlocks}\n </div>\n\n {form.formState.errors.root && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.root.message}</p>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleBack}\n disabled={currentStep === 0}\n >\n <ChevronLeft className=\"mr-2 h-4 w-4\" />\n Back\n </Button>\n {currentStep < STEPS.length - 1 ? (\n <Button type=\"button\" onClick={handleNext}>\n Next\n <ChevronRight className=\"ml-2 h-4 w-4\" />\n </Button>\n ) : (\n <Button type=\"button\" disabled={submitting} onClick={() => onSubmit(form.getValues())}>\n {submitting ? 'Submitting...' : '${p.submitText}'}\n </Button>\n )}\n </div>\n </form>\n </Form>\n )\n}\n${exportWrapper}`\n}\n","/**\n * Shared helpers for form component generation\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { formFieldToZodType } from '../../core/type-mappers/index.js'\nimport type { FormField } from '../../types.js'\nimport { singularize } from '../../utils/string.js'\n\nexport interface StepResult {\n files: string[]\n}\n\n/**\n * Check if a shadcn UI component exists in the user's project.\n * Returns `@/components/ui/<name>` if found, otherwise `@cms/components/ui/<name>`.\n */\nexport function resolveUiImport(cwd: string, componentName: string): string {\n const locations = ['components/ui', 'src/components/ui']\n for (const loc of locations) {\n if (\n fs.existsSync(path.join(cwd, loc, `${componentName}.tsx`)) ||\n fs.existsSync(path.join(cwd, loc, `${componentName}.ts`))\n ) {\n return `@/components/ui/${componentName}`\n }\n }\n return `@cms/components/ui/${componentName}`\n}\n\n/** Escape text for safe use in JSX content */\nexport function escapeJsx(str: string): string {\n return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')\n}\n\n/** Flatten form fields, resolving groups and skipping dynamic fields */\nexport function flattenFormFields(fields: FormField[]): FormField[] {\n return fields.flatMap((field) => {\n if (field.type === 'dynamicFields') return []\n if (field.type === 'group' && field.fields) return flattenFormFields(field.fields)\n return field.type === 'group' ? [] : [field]\n })\n}\n\n/** Build Zod schema field entries from form fields */\nexport function buildZodFields(fields: FormField[]): string {\n return fields\n .filter((f) => f.name)\n .map((f) => ` ${f.name}: ${formFieldToZodType(f)}`)\n .join(',\\n')\n}\n\n/** Build default value entries from form fields */\nexport function buildDefaultValues(fields: FormField[]): string {\n return fields\n .filter((f) => f.name)\n .map((f) => {\n if (f.type === 'checkbox') return ` ${f.name}: false`\n if (f.type === 'number') return ` ${f.name}: undefined`\n if (f.type === 'multiselect' || f.type === 'list') return ` ${f.name}: []`\n if (f.type === 'radio' && f.defaultValue !== undefined) return ` ${f.name}: '${f.defaultValue}'`\n if (f.type === 'select' || f.type === 'radio') return ` ${f.name}: undefined`\n if (f.defaultValue !== undefined) return ` ${f.name}: '${f.defaultValue}'`\n return ` ${f.name}: ''`\n })\n .join(',\\n')\n}\n\n/** Build useFieldArray declarations for list fields */\nexport function buildFieldArrayDecls(listFields: FormField[]): string {\n return listFields\n .map(\n (f) =>\n ` const ${f.name}FieldArray = useFieldArray({ control: form.control, name: '${f.name}' })`\n )\n .join('\\n')\n}\n\n/** Build watch variable declarations for showWhen fields */\nexport function buildWatchDecls(fields: FormField[]): { setup: string; hasWatch: boolean } {\n const watchFields = new Set<string>()\n for (const f of fields) {\n if (f.showWhen) {\n watchFields.add(f.showWhen.field)\n }\n }\n if (watchFields.size === 0) return { setup: '', hasWatch: false }\n const decls = Array.from(watchFields)\n .map((wf) => ` const ${wf}Value = form.watch('${wf}')`)\n .join('\\n')\n return { setup: `\\n${decls}\\n`, hasWatch: true }\n}\n\n/** Get list fields that need useFieldArray */\nexport function getListFields(fields: FormField[]): FormField[] {\n return fields.filter(\n (f) => f.name && f.type === 'list' && f.fields && f.fields.length > 0\n )\n}\n\n/**\n * Render an array of form fields to JSX, preserving group layout.\n * Group fields render as a responsive grid wrapper; other fields render normally.\n */\nexport function renderFieldsJSX(fields: FormField[]): string {\n return fields\n .filter((f) => !f.hidden)\n .map((f) => {\n if (f.type === 'dynamicFields') return ''\n if (f.type === 'group' && f.fields) {\n const cols = f.columns || 2\n const innerJSX = renderFieldsJSX(f.fields)\n const groupJSX = ` <div className=\"grid grid-cols-1 md:grid-cols-${cols} gap-4\">\\n${innerJSX}\\n </div>`\n return f.showWhen ? wrapShowWhen(f, groupJSX) : groupJSX\n }\n if (!f.name) return ''\n return wrapShowWhen(f, generateFieldJSX(f))\n })\n .filter(Boolean)\n .join('\\n\\n')\n}\n\n/** Wrap field JSX with showWhen conditional if applicable */\nexport function wrapShowWhen(field: FormField, jsx: string): string {\n if (!field.showWhen) return jsx\n const watchVar = `${field.showWhen.field}Value`\n const { value } = field.showWhen\n if (Array.isArray(value)) {\n const vals = value.map((v) => `'${v}'`).join(', ')\n return ` {[${vals}].includes(${watchVar} as string) && (\\n${jsx}\\n )}`\n }\n return ` {${watchVar} === '${value}' && (\\n${jsx}\\n )}`\n}\n\n/** Generate JSX for a single form field */\nexport function generateFieldJSX(field: FormField): string {\n const name = field.name || ''\n const label = escapeJsx(field.label)\n const placeholder = field.placeholder || ''\n const hint = field.hint || ''\n\n const hintJSX = hint ? `\\n <FormDescription>${escapeJsx(hint)}</FormDescription>` : ''\n const hintPlainJSX = hint ? `\\n <p className=\"text-sm text-muted-foreground\">${escapeJsx(hint)}</p>` : ''\n const requiredStar = field.required ? ' <span className=\"text-destructive\">*</span>' : ''\n\n switch (field.type) {\n case 'textarea':\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <Textarea placeholder=\"${placeholder}\" {...field} />\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n\n case 'radio':\n if (field.options && field.options.length > 0) {\n const radioItems = field.options\n .map(\n (opt) =>\n ` <FormLabel htmlFor=\"${name}-${opt.value}\" className=\"flex items-center space-x-2 text-sm font-medium leading-none\">\n <RadioGroupItem value=\"${opt.value}\" id=\"${name}-${opt.value}\" />\n <span>${escapeJsx(opt.label)}</span>\n </FormLabel>`\n )\n .join('\\n')\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem className=\"space-y-3\">\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <RadioGroup onValueChange={field.onChange} defaultValue={field.value} className=\"flex items-center space-x-2\">\n${radioItems}\n </RadioGroup>\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n }\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n\n case 'select':\n if (field.options && field.options.length > 0) {\n const optionItems = field.options\n .map(\n (opt) =>\n ` <SelectItem value=\"${opt.value}\">${escapeJsx(opt.label)}</SelectItem>`\n )\n .join('\\n')\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <Select onValueChange={field.onChange} defaultValue={field.value}>\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder=\"${placeholder || 'Select...'}\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n${optionItems}\n </SelectContent>\n </Select>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n }\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n\n case 'checkbox':\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-start space-x-3 space-y-0\">\n <FormControl>\n <input\n type=\"checkbox\"\n checked={field.value}\n onChange={field.onChange}\n className=\"mt-1\"\n />\n </FormControl>\n <div className=\"space-y-1 leading-none\">\n <FormLabel>${label}${requiredStar}</FormLabel>${hintJSX}\n <FormMessage />\n </div>\n </FormItem>\n )}\n />`\n\n case 'email':\n return generateTextFieldJSX(name, label, placeholder || 'email@example.com', hintJSX, requiredStar, 'email')\n\n case 'number':\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'number')\n\n case 'date':\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'date')\n\n case 'url':\n return generateTextFieldJSX(name, label, placeholder || 'https://', hintJSX, requiredStar, 'url')\n\n case 'phone':\n return generateTextFieldJSX(name, label, placeholder || '+1 (555) 000-0000', hintJSX, requiredStar, 'tel')\n\n case 'file':\n case 'upload':\n return generateFileUploadFieldJSX(field, name, label, hintJSX, requiredStar)\n\n case 'list':\n return generateListFieldJSX(field, name, label, hintPlainJSX, requiredStar)\n\n default:\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n }\n}\n\nexport function generateTextFieldJSX(\n name: string,\n label: string,\n placeholder: string,\n hintJSX: string,\n requiredStar: string,\n inputType: string\n): string {\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <Input type=\"${inputType}\" placeholder=\"${placeholder}\" {...field} />\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n}\n\nfunction generateFileUploadFieldJSX(\n field: FormField,\n name: string,\n label: string,\n hintJSX: string,\n requiredStar: string\n): string {\n const accept = field.accept || '*/*'\n const maxSize = field.maxFileSize || 10\n return ` <FormField\n control={form.control}\n name=\"${name}\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>${label}${requiredStar}</FormLabel>\n <FormControl>\n <MediaUploadField\n value={field.value}\n onChange={field.onChange}\n onBlur={field.onBlur}\n accept=\"${accept}\"\n maxSizeInMB={${maxSize}}\n label=\"\"\n />\n </FormControl>${hintJSX}\n <FormMessage />\n </FormItem>\n )}\n />`\n}\n\nfunction generateListFieldJSX(\n field: FormField,\n name: string,\n label: string,\n hintJSX: string,\n requiredStar: string\n): string {\n if (!field.fields || field.fields.length === 0) {\n return generateTextFieldJSX(name, label, field.placeholder || '', hintJSX, requiredStar, 'text')\n }\n\n const singularLabel = singularize(label)\n\n const nestedFieldsJSX = field.fields\n .map((nf) => {\n const nfLabel = escapeJsx(nf.label || nf.name || '')\n const nfPlaceholder = nf.placeholder || ''\n\n if (nf.type === 'select' && nf.options && nf.options.length > 0) {\n const selectItems = nf.options\n .map(\n (opt) =>\n ` <SelectItem value=\"${opt.value}\">${escapeJsx(opt.label)}</SelectItem>`\n )\n .join('\\n')\n return ` <FormField\n control={form.control}\n name={\\`${name}.\\${index}.${nf.name}\\`}\n render={({ field: formField }) => (\n <FormItem className=\"flex-1\">\n <FormLabel>${nfLabel}</FormLabel>\n <Select onValueChange={formField.onChange} defaultValue={formField.value}>\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder=\"${nf.placeholder || 'Select...'}\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n${selectItems}\n </SelectContent>\n </Select>\n <FormMessage />\n </FormItem>\n )}\n />`\n }\n\n return ` <FormField\n control={form.control}\n name={\\`${name}.\\${index}.${nf.name}\\`}\n render={({ field: formField }) => (\n <FormItem className=\"flex-1\">\n <FormLabel>${nfLabel}</FormLabel>\n <FormControl>\n <Input type=\"text\" placeholder=\"${nfPlaceholder}\" {...formField} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />`\n })\n .join('\\n')\n\n const defaultObj = field.fields\n .map((nf) => {\n if (nf.type === 'select' || nf.type === 'radio') return `${nf.name}: undefined`\n if (nf.type === 'checkbox') return `${nf.name}: false`\n if (nf.type === 'number') return `${nf.name}: undefined`\n return `${nf.name}: ''`\n })\n .join(', ')\n\n return ` <div className=\"space-y-4\">\n <FormLabel className=\"text-sm font-medium leading-none\">${label}${requiredStar}</FormLabel>${hintJSX}\n {${name}FieldArray.fields.map((item, index) => (\n <div key={item.id} className=\"relative rounded-lg border p-4\">\n <button\n type=\"button\"\n onClick={() => ${name}FieldArray.remove(index)}\n 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\"\n >\n <Trash2 className=\"h-4 w-4\" />\n <span className=\"sr-only\">Remove</span>\n </button>\n <div className=\"space-y-4 pr-8\">\n${nestedFieldsJSX}\n </div>\n </div>\n ))}\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => ${name}FieldArray.append({ ${defaultObj} })}\n >\n Add ${singularLabel}\n </Button>\n </div>`\n}\n","/**\n * Drizzle ORM type mappings for schema fields and form fields\n */\n\nimport type { FormField, SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nexport const DRIZZLE_DEFAULTS = {\n VARCHAR_LENGTH: 255,\n DECIMAL_PRECISION: 10,\n DECIMAL_SCALE: 2\n} as const\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\n/**\n * Check if a field name suggests it's a URL field\n */\nfunction isUrlField(fieldName: string): boolean {\n const urlKeywords = ['url', 'link', 'href', 'website', 'avatar', 'logo', 'thumbnail']\n const lowerName = fieldName.toLowerCase()\n return urlKeywords.some((keyword) => lowerName.includes(keyword))\n}\n\n// ============================================================================\n// Schema Field → Drizzle Type (for database generator)\n// ============================================================================\n\n/**\n * Map a schema field type to Drizzle ORM column type\n * @param field - The schema field\n * @param requiredImports - Set to track which Drizzle imports are needed\n * @returns The Drizzle column type expression\n */\nexport function toDrizzleType(field: SchemaField, requiredImports: Set<string>): string {\n switch (field.type) {\n case 'serial':\n requiredImports.add('serial')\n return 'serial()'\n case 'string':\n case 'varchar':\n if (isUrlField(field.name) && !field.length) {\n requiredImports.add('text')\n return 'text()'\n }\n requiredImports.add('varchar')\n return field.length\n ? `varchar({ length: ${field.length} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'image':\n case 'video':\n case 'media':\n requiredImports.add('text')\n return 'text()'\n case 'text':\n case 'markdown':\n case 'richtext':\n requiredImports.add('text')\n return 'text()'\n case 'number':\n requiredImports.add('integer')\n return 'integer()'\n case 'decimal':\n requiredImports.add('decimal')\n if (field.precision && field.scale) {\n return `decimal({ precision: ${field.precision}, scale: ${field.scale} })`\n }\n return `decimal({ precision: ${DRIZZLE_DEFAULTS.DECIMAL_PRECISION}, scale: ${DRIZZLE_DEFAULTS.DECIMAL_SCALE} })`\n case 'boolean':\n requiredImports.add('boolean')\n return 'boolean()'\n case 'timestamp':\n requiredImports.add('timestamp')\n return \"timestamp({ precision: 3, mode: 'string' })\"\n case 'date':\n requiredImports.add('date')\n return \"date({ mode: 'string' })\"\n case 'time':\n case 'select':\n case 'icon':\n requiredImports.add('varchar')\n return field.length\n ? `varchar({ length: ${field.length} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'curriculum':\n requiredImports.add('jsonb')\n return `jsonb().$type<{ mode: 'sequential'; items: Array<{ title?: string; description?: string }> } | { mode: 'weekly'; weeks: Array<{ weekNumber: number; weekTitle?: string; weekDescription?: string; durationHours?: number; items: Array<{ title?: string; description?: string }> }> }>()`\n case 'list':\n requiredImports.add('jsonb')\n if (field.fields && field.fields.length > 0) {\n const nestedType = buildNestedListType(field.fields)\n return `jsonb().$type<Array<{ ${nestedType} }>>()`\n }\n return 'jsonb().$type<string[]>()'\n case 'relationship':\n requiredImports.add('integer')\n return 'integer()'\n default:\n requiredImports.add('text')\n return 'text()'\n }\n}\n\n/**\n * Build nested type string for list fields with nested fields\n */\nfunction buildNestedListType(fields: SchemaField[]): string {\n return fields\n .flatMap((f) => {\n let type: string\n if (f.type === 'list' && f.fields && f.fields.length > 0) {\n const innerType = f.fields\n .map((nf) => {\n let nfType: string\n if (nf.type === 'boolean') {\n nfType = 'boolean'\n } else if (nf.type === 'number' || nf.type === 'decimal') {\n nfType = 'number'\n } else {\n nfType = 'string'\n }\n return `${quotePropertyName(nf.name)}?: ${nfType}`\n })\n .join('; ')\n type = `Array<{ ${innerType} }>`\n } else if (f.type === 'list') {\n type = 'string[]'\n } else if (f.type === 'number' || f.type === 'decimal') {\n type = 'number'\n } else if (f.type === 'boolean') {\n type = 'boolean'\n } else {\n type = 'string'\n }\n const result = [`${quotePropertyName(f.name)}?: ${type}`]\n if (f.hasIcon) {\n result.push(`${quotePropertyName(`${f.name}Icon`)}?: string`)\n }\n return result\n })\n .join('; ')\n}\n\n// ============================================================================\n// Form Field → Drizzle Type (for form-pipeline)\n// ============================================================================\n\n/**\n * Map a form field type to Drizzle ORM column type\n * @param field - The form field\n * @param requiredImports - Set to track which Drizzle imports are needed\n * @returns The Drizzle column type expression\n */\nexport function formFieldToDrizzleType(field: FormField, requiredImports: Set<string>): string {\n switch (field.type) {\n case 'text':\n requiredImports.add('varchar')\n return field.maxLength\n ? `varchar({ length: ${field.maxLength} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'textarea':\n requiredImports.add('text')\n return 'text()'\n case 'email':\n requiredImports.add('varchar')\n return `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'phone':\n requiredImports.add('varchar')\n return 'varchar({ length: 50 })'\n case 'number':\n requiredImports.add('integer')\n return 'integer()'\n case 'url':\n requiredImports.add('varchar')\n return 'varchar({ length: 500 })'\n case 'date':\n requiredImports.add('date')\n return \"date({ mode: 'string' })\"\n case 'select':\n case 'radio':\n case 'timezone':\n requiredImports.add('varchar')\n return `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'checkbox':\n requiredImports.add('boolean')\n return 'boolean()'\n case 'multiselect':\n requiredImports.add('jsonb')\n return 'jsonb().$type<string[]>()'\n case 'list':\n requiredImports.add('jsonb')\n if (field.fields && field.fields.length > 0) {\n return 'jsonb().$type<Record<string, unknown>[]>()'\n }\n return 'jsonb().$type<string[]>()'\n case 'file':\n case 'upload':\n requiredImports.add('text')\n return 'text()'\n default:\n requiredImports.add('text')\n return 'text()'\n }\n}\n","/**\n * Zod validation type mappings for schema fields and form fields\n */\n\nimport type { FormField, SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\n\n// ============================================================================\n// Schema Field → Zod Type (for form validation)\n// ============================================================================\n\n/**\n * Map a schema field type to Zod validation schema\n * @param field - The schema field\n * @returns The Zod schema expression as a string\n */\nexport function toZodType(field: SchemaField): string {\n const label = field.label || field.name\n\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return field.required\n ? `z.number({ message: '${label} is required' })`\n : 'z.number().optional()'\n case 'boolean':\n return 'z.boolean()'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext': {\n if (field.name.toLowerCase().includes('email')) {\n const base = field.required\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().email('Please enter a valid email address').optional()`\n return field.length ? `${base}.max(${field.length})` : base\n }\n const base = field.required ? `z.string().min(1, '${label} is required')` : 'z.string()'\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'date':\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n return `z.string().min(1, '${label} is required')`\n case 'timestamp':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'image':\n case 'video':\n case 'media': {\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n const mediaType =\n field.type === 'image' ? 'an image' : field.type === 'video' ? 'a video' : 'media'\n const base = `z.string().min(1, 'Please upload ${mediaType} for ${label}').url('Please provide a valid ${field.type} URL')`\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'list':\n return buildZodListType(field, label)\n case 'select': {\n if (field.options && field.options.length > 0) {\n const values = field.options.map((opt) => `'${opt.value}'`).join(', ')\n const valuesArray = `[${values}] as const`\n return field.required\n ? `z.string().min(1, '${label} is required').refine((val) => (${valuesArray} as readonly string[]).includes(val), { message: 'Invalid ${label}' })`\n : `z.string().refine((val) => !val || (${valuesArray} as readonly string[]).includes(val), { message: 'Invalid ${label}' }).optional()`\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'icon':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'relationship': {\n if (field.multiple) {\n return field.required\n ? `z.array(z.number()).min(1, '${label} is required')`\n : 'z.array(z.number()).optional()'\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'curriculum':\n return `z.object({\n mode: z.enum(['sequential', 'weekly']),\n items: z.array(z.object({\n title: z.string().max(255).optional(),\n description: z.string().max(500).optional()\n })).max(50),\n weeks: z.array(z.object({\n weekNumber: z.number().int().positive(),\n weekTitle: z.string().max(100).optional(),\n weekDescription: z.string().max(1000).optional(),\n durationHours: z.number().positive().optional(),\n items: z.array(z.object({\n title: z.string().max(255).optional(),\n description: z.string().max(500).optional()\n })).max(20)\n })).max(20)\n }).optional()`\n default:\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n\n/**\n * Build Zod type for list fields\n */\nfunction buildZodListType(field: SchemaField, label: string): string {\n if (field.fields && field.fields.length > 0) {\n const nestedFields = field.fields\n .flatMap((nestedField) => {\n const defs: string[] = []\n const nestedZodType = toZodType(nestedField)\n const alreadyOptional = nestedZodType.includes('.optional()')\n let nestedDef = ` ${quotePropertyName(nestedField.name)}: ${nestedZodType}`\n if (!nestedField.required && !alreadyOptional) {\n nestedDef += '.optional()'\n }\n defs.push(nestedDef)\n if (nestedField.hasIcon) {\n defs.push(` ${quotePropertyName(`${nestedField.name}Icon`)}: z.string().optional()`)\n }\n return defs\n })\n .join(',\\n')\n const objectSchema = `z.object({\\n${nestedFields}\\n })`\n const arraySchema = field.maxItems\n ? `z.array(${objectSchema}).max(${field.maxItems}, '${label} cannot exceed ${field.maxItems} items')`\n : `z.array(${objectSchema})`\n return field.required\n ? `${arraySchema}.min(1, '${label} must have at least one item')`\n : `${arraySchema}.optional()`\n }\n if (field.items?.type === 'string' || field.items?.type === 'varchar') {\n const itemSchema = field.items.length ? `z.string().max(${field.items.length})` : 'z.string()'\n const arraySchema = field.maxItems\n ? `z.array(${itemSchema}).max(${field.maxItems}, '${label} cannot exceed ${field.maxItems} items')`\n : `z.array(${itemSchema})`\n return field.required\n ? `${arraySchema}.min(1, '${label} must have at least one item')`\n : `${arraySchema}.optional()`\n }\n return field.required\n ? `z.array(z.string()).min(1, '${label} must have at least one item')`\n : 'z.array(z.string()).optional()'\n}\n\n// ============================================================================\n// Form Field → Zod Type (for form-pipeline)\n// ============================================================================\n\nexport interface FormFieldZodOptions {\n treatAsOptional?: boolean\n}\n\n/**\n * Map a form field type to Zod validation schema\n * @param field - The form field\n * @param options - Options for generating the zod type\n * @returns The Zod schema expression as a string\n */\nexport function formFieldToZodType(field: FormField, options: FormFieldZodOptions = {}): string {\n const label = field.label\n const isRequired = field.required && !options.treatAsOptional\n\n switch (field.type) {\n case 'text': {\n let zodType = isRequired ? `z.string().min(1, '${label} is required')` : 'z.string()'\n if (field.minLength) {\n zodType += `.min(${field.minLength}, '${label} must be at least ${field.minLength} characters')`\n }\n if (field.maxLength) {\n zodType += `.max(${field.maxLength}, '${label} must be at most ${field.maxLength} characters')`\n }\n if (field.pattern) {\n zodType += `.regex(new RegExp('${field.pattern}'), 'Invalid ${label} format')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'textarea': {\n let zodType = isRequired ? `z.string().min(1, '${label} is required')` : 'z.string()'\n if (field.minLength) {\n zodType += `.min(${field.minLength}, '${label} must be at least ${field.minLength} characters')`\n }\n if (field.maxLength) {\n zodType += `.max(${field.maxLength}, '${label} must be at most ${field.maxLength} characters')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'email':\n return isRequired\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || z.string().email().safeParse(val).success, { message: 'Please enter a valid email address' })`\n case 'phone': {\n const pattern =\n field.pattern || '^[+]?[(]?[0-9]{1,4}[)]?[-\\\\s\\\\.]?[(]?[0-9]{1,4}[)]?[-\\\\s\\\\.]?[0-9]{1,9}$'\n return isRequired\n ? `z.string().min(1, '${label} is required').regex(new RegExp('${pattern}'), 'Please enter a valid phone number')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || new RegExp('${pattern}').test(val), { message: 'Please enter a valid phone number' })`\n }\n case 'number': {\n let zodType = isRequired ? `z.number({ message: '${label} is required' })` : 'z.number()'\n if (field.min !== undefined) {\n zodType += `.min(${field.min}, '${label} must be at least ${field.min}')`\n }\n if (field.max !== undefined) {\n zodType += `.max(${field.max}, '${label} must be at most ${field.max}')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'url':\n return isRequired\n ? `z.string().min(1, '${label} is required').url('Please enter a valid URL')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || z.string().url().safeParse(val).success, { message: 'Please enter a valid URL' })`\n case 'date':\n return isRequired\n ? `z.string().min(1, '${label} is required')`\n : 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n case 'select':\n case 'radio':\n if (field.options && field.options.length > 0) {\n const values = field.options.map((opt) => `'${opt.value}'`).join(', ')\n return isRequired\n ? `z.enum([${values}], { message: '${label} is required' })`\n : `z.enum([${values}]).optional()`\n }\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'checkbox':\n return isRequired\n ? `z.boolean().refine(val => val === true, { message: '${label} is required' })`\n : 'z.boolean().optional()'\n case 'multiselect':\n return isRequired\n ? `z.array(z.string()).min(1, '${label} is required')`\n : 'z.array(z.string()).optional()'\n case 'timezone':\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nestedFields = field.fields\n .map((f) => `${f.name}: ${formFieldToZodType(f, options)}`)\n .join(', ')\n return isRequired\n ? `z.array(z.object({ ${nestedFields} })).min(1, '${label} is required')`\n : `z.array(z.object({ ${nestedFields} })).optional()`\n }\n return isRequired\n ? `z.array(z.string()).min(1, '${label} is required')`\n : 'z.array(z.string()).optional()'\n case 'file':\n case 'upload':\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n default:\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n","/**\n * TypeScript, form field, and SQL type mappings for schema fields\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, quotePropertyName } from '../../utils/string.js'\nimport { DRIZZLE_DEFAULTS } from './drizzle.js'\n\n// ============================================================================\n// Schema Field → TypeScript Type (for actions generator)\n// ============================================================================\n\n/**\n * Map a schema field type to TypeScript type\n * @param field - The schema field\n * @param mode - 'input' for form input types, 'output' for database output types\n * @returns The TypeScript type as a string\n */\nexport function toTypeScriptType(field: SchemaField, mode: 'input' | 'output' = 'output'): string {\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return 'number'\n case 'boolean':\n return 'boolean'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext':\n case 'date':\n case 'time':\n case 'timestamp':\n case 'image':\n case 'video':\n case 'media':\n case 'icon':\n case 'select':\n return 'string'\n case 'relationship':\n if (mode === 'input') {\n return field.multiple ? 'number[]' : 'string'\n }\n if (field.relationship) {\n const relationshipSingular = singularize(field.relationship)\n const relationshipPascal = toPascalCase(relationshipSingular)\n return field.multiple ? `${relationshipPascal}Data[]` : `${relationshipPascal}Data | null`\n }\n return 'string'\n case 'group':\n if (field.fields && field.fields.length > 0) {\n const groupType = field.fields\n .map((f) => {\n const type = toTypeScriptType(f, mode)\n return `${quotePropertyName(f.name)}?: ${type}`\n })\n .join('; ')\n return `{ ${groupType} }`\n }\n return 'Record<string, unknown>'\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nestedType = field.fields\n .flatMap((f) => {\n const type = toTypeScriptType(f, 'input')\n const fields = [`${quotePropertyName(f.name)}?: ${type}`]\n if (f.hasIcon) {\n fields.push(`${quotePropertyName(`${f.name}Icon`)}?: string`)\n }\n return fields\n })\n .join('; ')\n return `Array<{ ${nestedType} }>`\n }\n return 'string[]'\n case 'curriculum':\n return '{ mode: \"sequential\" | \"weekly\"; items: Array<{ title?: string; description?: string }>; weeks: Array<{ weekNumber: number; weekTitle?: string; weekDescription?: string; durationHours?: number; items: Array<{ title?: string; description?: string }> }> }'\n default:\n return 'string'\n }\n}\n\n// ============================================================================\n// Schema Field → Form Field Type (for form generator)\n// ============================================================================\n\n/**\n * Map a schema field type to HTML form input type\n * @param field - The schema field\n * @returns The form input type (checkbox, textarea, number, date, etc.)\n */\nexport function toFormFieldType(field: SchemaField): string {\n switch (field.type) {\n case 'boolean':\n return 'checkbox'\n case 'text':\n return 'textarea'\n case 'markdown':\n return 'markdown'\n case 'richtext':\n return 'richtext'\n case 'number':\n case 'decimal':\n return 'number'\n case 'date':\n return 'date'\n case 'time':\n return 'time'\n case 'timestamp':\n return 'datetime-local'\n default:\n return 'text'\n }\n}\n\n// ============================================================================\n// Schema Field → SQL Type (for raw SQL migrations)\n// ============================================================================\n\n/**\n * Map a schema field type to SQL column type\n * @param field - The schema field\n * @returns The SQL column type\n */\nexport function toSQLType(field: SchemaField): string {\n switch (field.type) {\n case 'serial':\n return 'SERIAL'\n case 'string':\n case 'varchar':\n return field.length\n ? `VARCHAR(${field.length})`\n : `VARCHAR(${DRIZZLE_DEFAULTS.VARCHAR_LENGTH})`\n case 'text':\n case 'markdown':\n case 'richtext':\n case 'image':\n case 'video':\n case 'media':\n return 'TEXT'\n case 'number':\n return 'INTEGER'\n case 'decimal':\n return `DECIMAL(${field.precision || DRIZZLE_DEFAULTS.DECIMAL_PRECISION}, ${field.scale || DRIZZLE_DEFAULTS.DECIMAL_SCALE})`\n case 'boolean':\n return 'BOOLEAN'\n case 'timestamp':\n return 'TIMESTAMP(3)'\n case 'date':\n return 'DATE'\n case 'time':\n case 'select':\n case 'icon':\n return `VARCHAR(${DRIZZLE_DEFAULTS.VARCHAR_LENGTH})`\n case 'list':\n case 'curriculum':\n return 'JSONB'\n case 'relationship':\n return 'INTEGER'\n default:\n return 'TEXT'\n }\n}\n","/**\n * Single-step (flat) form component generator\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toKebabCase } from '../../utils/string.js'\nimport {\n type StepResult,\n resolveUiImport,\n escapeJsx,\n renderFieldsJSX,\n buildZodFields,\n buildDefaultValues,\n buildFieldArrayDecls,\n buildWatchDecls,\n getListFields,\n} from './form-component-shared.js'\n\nexport function generateSingleStepForm(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const fields = getAllFormSchemaFields(schema)\n\n const kebab = toKebabCase(formName)\n const filePath = path.join(cwd, cmsDir, 'components', 'forms', `${kebab}-form.tsx`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const zodFields = buildZodFields(fields)\n const defaults = buildDefaultValues(fields)\n const listFields = getListFields(fields)\n const hasListFields = listFields.length > 0\n const { setup: watchSetup } = buildWatchDecls(fields)\n\n const rawFields = schema.fields || []\n const fieldJSX = renderFieldsJSX(rawFields)\n\n const submitText = schema.submitButtonText || 'Submit'\n const successMessage = escapeJsx(schema.successMessage || 'Form submitted successfully!')\n\n const rhfImport = hasListFields\n ? `import { useFieldArray, useForm } from 'react-hook-form'`\n : `import { useForm } from 'react-hook-form'`\n\n const fieldArraySetup = hasListFields ? `\\n${buildFieldArrayDecls(listFields)}\\n` : ''\n\n const hasRadio = fields.some((f) => f.type === 'radio')\n const hasFileUpload = fields.some((f) => f.type === 'file' || f.type === 'upload')\n const buttonImport = resolveUiImport(cwd, 'button')\n const formImport = resolveUiImport(cwd, 'form')\n const inputImport = resolveUiImport(cwd, 'input')\n const textareaImport = resolveUiImport(cwd, 'textarea')\n const selectImport = resolveUiImport(cwd, 'select')\n const radioGroupImport = resolveUiImport(cwd, 'radio-group')\n const mediaUploadImport = resolveUiImport(cwd, 'media-upload-field')\n\n const queryClientImport = hasFileUpload\n ? `\\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'`\n : ''\n const queryClientSetup = hasFileUpload\n ? `\\nconst queryClient = new QueryClient()\\n`\n : ''\n\n const formComponentDecl = hasFileUpload ? `function ${pascal}FormInner` : `export function ${pascal}Form`\n const exportWrapper = hasFileUpload\n ? `\\nexport function ${pascal}Form() {\n return (\n <QueryClientProvider client={queryClient}>\n <${pascal}FormInner />\n </QueryClientProvider>\n )\n}\\n`\n : ''\n\n const lucideImport = hasListFields ? `\\nimport { Trash2 } from 'lucide-react'` : ''\n\n const content = `'use client'\n\nimport { zodResolver } from '@hookform/resolvers/zod'${lucideImport}\nimport { useState } from 'react'\n${rhfImport}\nimport { z } from 'zod/v3'${queryClientImport}\nimport { create${pascal}Submission } from '@cms/actions/${kebab}-form'\nimport { Button } from '${buttonImport}'\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '${formImport}'\nimport { Input } from '${inputImport}'${hasFileUpload ? `\\nimport { MediaUploadField } from '${mediaUploadImport}'` : ''}${hasRadio ? `\\nimport { RadioGroup, RadioGroupItem } from '${radioGroupImport}'` : ''}\nimport { Textarea } from '${textareaImport}'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '${selectImport}'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\ntype FormValues = z.infer<typeof formSchema>\n${queryClientSetup}\n${formComponentDecl}() {\n const [submitted, setSubmitted] = useState(false)\n const [submitting, setSubmitting] = useState(false)\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n${defaults}\n },\n })\n${fieldArraySetup}${watchSetup}\n async function onSubmit(values: FormValues) {\n setSubmitting(true)\n try {\n const result = await create${pascal}Submission(values)\n if (result.success) {\n setSubmitted(true)\n } else {\n form.setError('root', { message: result.error || 'Something went wrong' })\n }\n } catch {\n form.setError('root', { message: 'Something went wrong. Please try again.' })\n } finally {\n setSubmitting(false)\n }\n }\n\n if (submitted) {\n return (\n <div className=\"rounded-lg border p-6 text-center\">\n <h3 className=\"text-lg font-semibold\">Thank you!</h3>\n <p className=\"mt-2 text-muted-foreground\">${successMessage}</p>\n </div>\n )\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n${fieldJSX}\n\n {form.formState.errors.root && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.root.message}</p>\n )}\n\n <Button type=\"submit\" disabled={submitting}>\n {submitting ? 'Submitting...' : '${submitText}'}\n </Button>\n </form>\n </Form>\n )\n}\n${exportWrapper}`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Form pipeline step 4: Public form component generation\n * Routes to single-step or multi-step generator based on schema structure.\n */\n\nimport { isMultiStepForm } from '../../core/field-helpers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport type { StepResult } from './form-component-shared.js'\nimport { generateMultiStepForm } from './form-component-multistep.js'\nimport { generateSingleStepForm } from './form-component-single.js'\n\nexport function generateFormComponent(\n schema: FormSchema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions\n): StepResult {\n if (isMultiStepForm(schema) && schema.steps!.length > 1) {\n return generateMultiStepForm(schema, cwd, cmsDir, options)\n }\n return generateSingleStepForm(schema, cwd, cmsDir, options)\n}\n","/**\n * Form pipeline step 1: Database schema generation for form submissions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { getAllFormSchemaFields, hasDynamicFields } from '../../core/field-helpers/index.js'\nimport { formFieldToDrizzleType } from '../../core/type-mappers/index.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase } from '../../utils/string.js'\n\nfunction findTableEnd(content: string, startIndex: number): number {\n let depth = 0\n let inString = false\n let stringChar = ''\n\n for (let i = startIndex; i < content.length; i++) {\n const char = content[i]\n const prev = i > 0 ? content[i - 1] : ''\n\n if ((char === '\"' || char === \"'\" || char === '`') && prev !== '\\\\') {\n if (!inString) {\n inString = true\n stringChar = char\n } else if (char === stringChar) {\n inString = false\n }\n continue\n }\n if (inString) continue\n\n if (char === '(' || char === '{' || char === '[') depth++\n if (char === ')' || char === '}' || char === ']') depth--\n\n if (depth === 0 && char === ')') {\n // Skip optional semicolon and trailing whitespace\n let end = i + 1\n while (end < content.length && (content[end] === ';' || content[end] === ' ' || content[end] === '\\t')) {\n end++\n }\n if (end < content.length && content[end] === '\\n') {\n end++\n }\n return end\n }\n }\n\n return content.length\n}\n\ninterface StepResult {\n files: string[]\n}\n\nexport function generateFormDatabase(\n schema: FormSchema,\n cwd: string,\n dbSchemaPath: string,\n options: GeneratorOptions\n): StepResult {\n const tableName = `${toCamelCase(schema.name)}Submissions`\n const fields = getAllFormSchemaFields(schema)\n const includeDynamic = hasDynamicFields(schema)\n\n const requiredImports = new Set<string>(['serial', 'timestamp', 'text'])\n if (includeDynamic) requiredImports.add('jsonb')\n\n // Generate field definitions\n const fieldDefs = fields\n .map((field) => {\n const drizzleType = formFieldToDrizzleType(field, requiredImports)\n return ` ${field.name}: ${drizzleType},`\n })\n .join('\\n')\n\n const customFieldsCol = includeDynamic\n ? '\\n customFields: jsonb().$type<Record<string, unknown>>(),'\n : ''\n\n const tableSchema = `\nexport const ${tableName} = pgTable('${toPascalCase(schema.name)}Submissions', {\n id: serial().primaryKey().notNull(),\n${fieldDefs}${customFieldsCol}\n ipAddress: text(),\n userAgent: text(),\n submittedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull(),\n createdAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull(),\n updatedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull()\n})\n`\n\n const filePath = path.join(cwd, dbSchemaPath)\n let content = fs.readFileSync(filePath, 'utf-8')\n\n // Merge imports\n const pgCoreMatch = content.match(/import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/)\n if (pgCoreMatch) {\n const existing = new Set(\n pgCoreMatch[1]\n .split(',')\n .map((i) => i.trim())\n .filter(Boolean)\n )\n const merged = Array.from(new Set([...existing, ...requiredImports])).sort()\n content = content.replace(\n /import\\s+\\{[^}]+\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/,\n `import {\\n ${merged.join(',\\n ')}\\n} from 'drizzle-orm/pg-core'`\n )\n }\n\n // Ensure sql import\n if (!content.includes('import { sql }')) {\n content = content.replace(\n /import\\s+\\{[^}]+\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/,\n (match) => `import { sql } from 'drizzle-orm'\\n${match}`\n )\n }\n\n // Remove all existing table definitions if --force (handles prior duplicates)\n if (content.includes(`export const ${tableName}`)) {\n if (!options.force) {\n return { files: [dbSchemaPath] }\n }\n const marker = `export const ${tableName} =`\n let start = content.indexOf(marker)\n while (start !== -1) {\n const end = findTableEnd(content, start)\n const actualStart = start > 0 && content[start - 1] === '\\n' ? start - 1 : start\n content = content.slice(0, actualStart) + content.slice(end)\n start = content.indexOf(marker)\n }\n }\n\n content += `\\n${tableSchema}`\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [dbSchemaPath] }\n}\n","/**\n * Form pipeline step 3: React Query hook for form submissions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { toPascalCase, toCamelCase, toKebabCase } from '../../utils/string.js'\n\ninterface StepResult {\n files: string[]\n}\n\nexport function generateFormHook(\n schema: FormSchema,\n cwd: string,\n hooksDir: string,\n options: GeneratorOptions\n): StepResult {\n const formName = schema.name\n const pascal = toPascalCase(formName)\n const camel = toCamelCase(formName)\n const kebab = toKebabCase(formName)\n\n const filePath = path.join(cwd, hooksDir, `use-${kebab}-form.ts`)\n const dir = path.dirname(filePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [path.relative(cwd, filePath)] }\n }\n\n const successMsg = (schema.successMessage || 'Form submitted successfully').replace(/'/g, \"\\\\'\")\n\n const content = `import {\n create${pascal}Submission,\n delete${pascal}Submission,\n export${pascal}SubmissionsCSV,\n export${pascal}SubmissionsJSON,\n get${pascal}Submission,\n get${pascal}Submissions,\n} from '@cms/actions/${kebab}-form'\nimport type { Create${pascal}SubmissionInput } from '@cms/actions/${kebab}-form'\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\nimport { toast } from 'sonner'\n\nexport function use${pascal}Submissions(search?: string) {\n return useQuery({\n queryKey: ['${camel}-submissions', search ?? ''],\n queryFn: () => get${pascal}Submissions()\n })\n}\n\nexport function use${pascal}Submission(id: number | null) {\n return useQuery({\n queryKey: ['${camel}-submission', id],\n queryFn: () => get${pascal}Submission(id!),\n enabled: !!id\n })\n}\n\nexport function useCreate${pascal}Submission() {\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (data: Create${pascal}SubmissionInput) => create${pascal}Submission(data),\n onSuccess: async (result) => {\n if (result.success) {\n toast.success('${successMsg}')\n await queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n } else {\n toast.error(result.error || 'Failed to submit form')\n }\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to submit form')\n }\n })\n}\n\nexport function useDelete${pascal}Submission() {\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (id: number) => delete${pascal}Submission(id),\n onSuccess: async () => {\n toast.success('Submission deleted successfully')\n await queryClient.refetchQueries({ queryKey: ['${camel}-submissions'] })\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to delete submission')\n }\n })\n}\n\nexport function useExport${pascal}SubmissionsCSV() {\n return useMutation({\n mutationFn: export${pascal}SubmissionsCSV,\n onSuccess: (csvContent) => {\n const blob = new Blob([csvContent], { type: 'text/csv' })\n const url = window.URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = '${formName}-submissions-' + new Date().toISOString().split('T')[0] + '.csv'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n window.URL.revokeObjectURL(url)\n toast.success('CSV exported successfully')\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to export CSV')\n }\n })\n}\n\nexport function useExport${pascal}SubmissionsJSON() {\n return useMutation({\n mutationFn: export${pascal}SubmissionsJSON,\n onSuccess: (jsonContent) => {\n const blob = new Blob([jsonContent], { type: 'application/json' })\n const url = window.URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = '${formName}-submissions-' + new Date().toISOString().split('T')[0] + '.json'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n window.URL.revokeObjectURL(url)\n toast.success('JSON exported successfully')\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to export JSON')\n }\n })\n}\n`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n","/**\n * Form pipeline orchestrator — runs all form generation steps in sequence\n */\n\nimport type { BetterstartConfig } from '../../config/types.js'\nimport type { FormSchema, GeneratorOptions } from '../../types.js'\nimport { generateEmailTemplate } from '../email-template.js'\nimport { generateFormAdminPages } from '../form-admin/index.js'\nimport { updateFormNavigation } from '../form-navigation.js'\nimport { generateFormActions } from './form-actions.js'\nimport { generateFormComponent } from './form-component.js'\nimport { generateFormDatabase } from './form-database.js'\nimport { generateFormHook } from './form-hook.js'\n\nexport interface FormPipelineResult {\n success: boolean\n files: string[]\n errors: string[]\n}\n\n/**\n * Resolve output paths from config for form generation\n */\nfunction resolveFormPaths(config: BetterstartConfig) {\n const cms = config.paths?.cms ?? './cms'\n const pages = config.paths?.pages ?? './src/app/(cms)/cms/(authenticated)'\n return {\n cmsDir: cms,\n pagesDir: pages,\n dbSchemaPath: `${cms}/db/schema.ts`,\n actionsDir: `${cms}/lib/actions`,\n hooksDir: `${cms}/hooks`\n }\n}\n\n/**\n * Run the form generation pipeline\n */\nexport function runFormPipeline(\n schema: FormSchema,\n cwd: string,\n config: BetterstartConfig,\n options: GeneratorOptions = {}\n): FormPipelineResult {\n const paths = resolveFormPaths(config)\n const files: string[] = []\n const errors: string[] = []\n\n const steps: { name: string; run: () => string[] }[] = [\n {\n name: 'Database schema (submissions)',\n run: () => generateFormDatabase(schema, cwd, paths.dbSchemaPath, options).files\n },\n {\n name: 'Server actions',\n run: () => generateFormActions(schema, cwd, paths.actionsDir, options).files\n },\n {\n name: 'React Query hook',\n run: () => generateFormHook(schema, cwd, paths.hooksDir, options).files\n },\n {\n name: 'Public form component',\n run: () => generateFormComponent(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Admin pages',\n run: () => generateFormAdminPages(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Navigation',\n run: () => updateFormNavigation(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Email template',\n run: () => generateEmailTemplate(schema, cwd, paths.cmsDir, options).files\n }\n ]\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const stepNum = i + 1\n try {\n const result = step.run()\n files.push(...result)\n if (!options.silent) console.log(` ${stepNum}. ${step.name} ✓`)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${step.name}: ${msg}`)\n if (!options.silent) console.error(` ${stepNum}. ${step.name} ✗ — ${msg}`)\n }\n }\n\n return { success: errors.length === 0, files, errors }\n}\n","/**\n * Generator 2: Server actions — cms/lib/actions/<n>.ts\n * Generates 'use server' CRUD actions for an entity schema\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, getManyToManyFields } from '../../core/field-helpers/index.js'\nimport type { Schema, SchemaField } from '../../types.js'\nimport { toPascalCase, toCamelCase, singularize, pluralize, quotePropertyName } from '../../utils/string.js'\nimport type { ActionsGeneratorResult } from './action-helpers.js'\nimport {\n generateFieldMapping,\n getFieldType,\n buildRelationshipSelect,\n buildResultMapping,\n buildSingleRowMapping,\n buildExplicitSelect,\n findListFieldsWithRelationships,\n generatePopulateListRelsFunction\n} from './action-helpers.js'\n\n/**\n * Generate server actions file for an entity\n */\nexport function generateActions(\n schema: Schema,\n cwd: string,\n actionsDir: string,\n options: { force?: boolean; schemasDir?: string } = {}\n): ActionsGeneratorResult {\n const absActionsDir = path.join(cwd, actionsDir)\n const filePath = path.join(absActionsDir, `${schema.name}.ts`)\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n const tableVar = toCamelCase(schema.name)\n const camelPlural = toCamelCase(plural)\n const camelSingular = toCamelCase(singular)\n\n const dbFields = flattenFields(schema.fields)\n const m2mFields = getManyToManyFields(schema.fields)\n const hasM2M = m2mFields.length > 0\n\n const relationshipFields = dbFields.filter(\n (f) => f.type === 'relationship' && f.relationship && !f.multiple\n )\n const hasRelationships = relationshipFields.length > 0\n\n const regularDbFields = dbFields.filter(\n (f) => !(f.type === 'relationship' && f.multiple === true)\n )\n\n // Find list fields that contain relationship sub-fields\n const listFieldsWithRels = findListFieldsWithRelationships(dbFields)\n const hasListRels = listFieldsWithRels.length > 0\n\n // Collect relationship query info for list fields\n const allListRelQueries: Array<{\n fieldPath: string\n relField: SchemaField\n relTable: string\n listFieldName: string\n }> = []\n\n for (const { field: listField, path: fieldPath } of listFieldsWithRels) {\n const rels = (listField.fields || []).filter((f) => f.type === 'relationship' && f.relationship)\n for (const relField of rels) {\n allListRelQueries.push({\n fieldPath: fieldPath.join('_'),\n relField,\n relTable: toCamelCase(relField.relationship!),\n listFieldName: listField.name\n })\n }\n }\n\n // Generate populate helper function for list-relationship fields\n const populateListRelsFn = hasListRels\n ? generatePopulateListRelsFunction(allListRelQueries, Singular)\n : ''\n\n const htmlOutputFields = regularDbFields.filter(\n (f) => (f.type === 'richtext' || f.type === 'markdown') && f.output === 'html'\n )\n const hasHtmlOutput = htmlOutputFields.length > 0\n\n const hasSlug = regularDbFields.some((f) => f.name === 'slug')\n const hasDraft = schema.actions?.draft === true\n const hasPublished = regularDbFields.some((f) => f.name === 'published')\n const hasSearch = (schema.search?.fields || []).length > 0\n const searchFields = schema.search?.fields || []\n const hasFilters = (schema.filters || []).length > 0\n\n // Build allDbFields (with auto-added fields)\n const allDbFields = [...regularDbFields]\n if (hasDraft && !hasPublished) {\n allDbFields.push({ name: 'published', type: 'boolean' as const, required: true })\n }\n if (!regularDbFields.some((f) => f.name === 'createdAt')) {\n allDbFields.push({ name: 'createdAt', type: 'timestamp' as const, required: true })\n }\n if (!regularDbFields.some((f) => f.name === 'updatedAt')) {\n allDbFields.push({ name: 'updatedAt', type: 'timestamp' as const, required: true })\n }\n if (!regularDbFields.some((f) => f.name === 'sortOrder')) {\n allDbFields.push({ name: 'sortOrder', type: 'number' as const, required: true })\n }\n\n // List-specific fields (exclude heavy content columns when output: 'html')\n const listExcludeFields = new Set(htmlOutputFields.map(f => f.name))\n const listDbFields = hasHtmlOutput\n ? allDbFields.filter(f => !listExcludeFields.has(f.name))\n : allDbFields\n\n // Create fields (exclude auto-generated)\n const createFields = regularDbFields.filter(\n (f) =>\n !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt' && f.name !== 'sortOrder'\n )\n\n // Filterable fields for the Filters interface\n const filterableFields = allDbFields.filter(\n (f) =>\n !f.primaryKey &&\n f.name !== 'createdAt' &&\n f.name !== 'updatedAt' &&\n f.name !== 'sortOrder' &&\n ['string', 'varchar', 'text', 'boolean', 'number', 'decimal'].includes(f.type)\n )\n\n // --- Build imports ---\n const drizzleImports = ['asc', 'desc', 'eq', 'gt', 'inArray', 'lt']\n if (hasSearch || filterableFields.length > 1) drizzleImports.push('and')\n if (hasSearch) drizzleImports.push('ilike', 'or')\n if (hasRelationships) drizzleImports.push('sql')\n if (hasFilters) drizzleImports.push('isNotNull')\n const sortedDrizzleImports = [...new Set(drizzleImports)].sort()\n\n const dbImports = new Set([tableVar])\n for (const f of relationshipFields) dbImports.add(toCamelCase(f.relationship!))\n for (const f of m2mFields) {\n const junctionVar = toCamelCase(`${singular}${toPascalCase(f.relationship || '')}`)\n dbImports.add(junctionVar)\n dbImports.add(toCamelCase(f.relationship || ''))\n }\n for (const q of allListRelQueries) {\n dbImports.add(q.relTable)\n }\n const sortedDbImports = [...dbImports].sort()\n\n // --- Build interfaces ---\n const dataFields = allDbFields\n .map(\n (f) =>\n ` ${quotePropertyName(f.name)}: ${getFieldType(f, 'output')}${f.required ? '' : ' | null'}`\n )\n .join('\\n')\n const m2mFieldTypes = m2mFields.map((f) => ` ${quotePropertyName(f.name)}: number[]`).join('\\n')\n const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join('\\n')\n\n const dataInterface = `export interface ${Singular}Data {\\n${dataFields}${htmlFieldTypes ? `\\n${htmlFieldTypes}` : ''}${m2mFieldTypes ? `\\n${m2mFieldTypes}` : ''}\\n}`\n\n // Display data interface (for getBySlug): excludes raw content, includes contentHtml\n const displayDbFields = allDbFields.filter(f => !htmlOutputFields.some(h => h.name === f.name))\n const displayDataFields = displayDbFields\n .map(f => ` ${quotePropertyName(f.name)}: ${getFieldType(f, 'output')}${f.required ? '' : ' | null'}`)\n .join('\\n')\n const displayDataInterface = hasHtmlOutput\n ? `\\nexport interface ${Singular}DisplayData {\\n${displayDataFields}${htmlFieldTypes ? `\\n${htmlFieldTypes}` : ''}${m2mFieldTypes ? `\\n${m2mFieldTypes}` : ''}\\n}`\n : ''\n\n const responseInterface = `export interface ${Plural}Response {\\n ${camelPlural}: ${Singular}Data[]\\n total: number\\n}`\n\n const filtersInterfaceFields = filterableFields\n .map((f) => ` ${quotePropertyName(f.name)}?: ${getFieldType(f)}`)\n .join('\\n')\n const filtersInterface = `export interface Get${Plural}Filters {\\n search?: string\\n${filtersInterfaceFields}\\n limit?: number\\n}`\n\n const createInterfaceFields = createFields\n .map(\n (f) => ` ${quotePropertyName(f.name)}${f.required ? '' : '?'}: ${getFieldType(f, 'input')}`\n )\n .join('\\n')\n const createInterface = `export interface Create${Singular}Input {\\n${createInterfaceFields}${hasDraft ? `\\n published?: boolean` : ''}\\n}`\n\n const updateInterfaceFields = createFields\n .map((f) => ` ${quotePropertyName(f.name)}?: ${getFieldType(f, 'input')}`)\n .join('\\n')\n const updateInterface = `export interface Update${Singular}Input {\\n id: number\\n${updateInterfaceFields}${hasDraft ? `\\n published?: boolean` : ''}\\n}`\n\n // --- Build select clause ---\n const selectClause = hasRelationships\n ? buildRelationshipSelect(allDbFields, relationshipFields, tableVar)\n : `db.select().from(${tableVar})`\n\n // List select: excludes heavy content/html columns for performance\n const listSelectClause = hasHtmlOutput\n ? (hasRelationships\n ? buildRelationshipSelect(listDbFields, relationshipFields, tableVar)\n : buildExplicitSelect(listDbFields, tableVar))\n : selectClause\n\n // Display select (for getBySlug): excludes raw content, includes contentHtml\n const displaySelectClause = hasHtmlOutput && hasSlug\n ? (hasRelationships\n ? buildRelationshipSelect(displayDbFields, relationshipFields, tableVar, htmlOutputFields)\n : buildExplicitSelect(displayDbFields, tableVar, htmlOutputFields))\n : selectClause\n\n // --- Build query with filters ---\n const filterConditions = filterableFields\n .map((f) =>\n f.type === 'boolean'\n ? ` if (filters?.${f.name} !== undefined) {\\n conditions.push(eq(${tableVar}.${f.name}, filters.${f.name}))\\n }`\n : ` if (filters?.${f.name}) {\\n conditions.push(eq(${tableVar}.${f.name}, filters.${f.name}))\\n }`\n )\n .join('\\n')\n\n const searchBlock = hasSearch\n ? ` const search = filters?.search\\n if (search && typeof search === 'string' && search.trim()) {\\n const searchTerm = \\`%\\${search.trim().toLowerCase()}%\\`\\n conditions.push(\\n or(\\n${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(',\\n')}\\n )\\n )\\n }\\n`\n : ''\n\n // --- Build result mapping for relationships ---\n const resultMapping = hasRelationships\n ? buildResultMapping(\n allDbFields,\n relationshipFields,\n Plural,\n camelPlural,\n Singular,\n hasListRels\n )\n : hasListRels\n ? `\\n\\n const populated${Plural} = await Promise.all(\\n results.map(record => populate${Singular}ListRelationships(record as ${Singular}Data))\\n )\\n\\n return {\\n ${camelPlural}: populated${Plural},\\n total: populated${Plural}.length\\n }`\n : `\\n return {\\n ${camelPlural}: results as ${Singular}Data[],\\n total: results.length\\n }`\n\n // List-specific result mapping (uses listDbFields for relationship cases)\n const listResultMapping = hasHtmlOutput && hasRelationships\n ? buildResultMapping(listDbFields, relationshipFields, Plural, camelPlural, Singular, hasListRels)\n : resultMapping\n\n // --- Build field metadata for update ---\n const fieldMeta = createFields\n .map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`)\n .join(',\\n ')\n\n // --- Build create field mappings ---\n const createMappings = createFields\n .map((f) => ` ${f.name}: ${generateFieldMapping(f)}`)\n .join(',\\n')\n\n const htmlCreateBlock = hasHtmlOutput\n ? `\\n const { renderMarkdownSync } = await import('@cms/lib/markdown/render')\\n` +\n htmlOutputFields.map((f) => ` const ${f.name}Html = renderMarkdownSync(input.${f.name} || '')`).join('\\n') +\n '\\n'\n : ''\n\n const htmlCreateMappings = htmlOutputFields\n .map((f) => ` ${f.name}Html`)\n .join(',\\n')\n\n // --- Generate distinct filter functions ---\n const distinctFns = hasFilters\n ? (schema.filters || [])\n .map(\n (filter) =>\n `\\nexport async function getDistinct${Plural}${toPascalCase(filter.field)}(): Promise<string[]> {\\n try {\\n const results = await db\\n .selectDistinct({ value: ${tableVar}.${filter.field} })\\n .from(${tableVar})\\n .where(isNotNull(${tableVar}.${filter.field}))\\n .orderBy(asc(${tableVar}.${filter.field}))\\n return results.map((r) => String(r.value)).filter(Boolean)\\n } catch (error) {\\n console.error('Error fetching distinct ${plural} ${filter.field}:', error)\\n return []\\n }\\n}`\n )\n .join('\\n')\n : ''\n\n // --- Build M2M helper functions ---\n const m2mHelpers = hasM2M\n ? m2mFields\n .map((f) => {\n const rel = f.relationship || ''\n const RelPascal = toPascalCase(rel)\n const relSingular = singularize(rel)\n const junctionVar = toCamelCase(`${singular}${RelPascal}`)\n const entityIdCol = `${singular}Id`\n const relIdCol = `${relSingular}Id`\n return `\nexport async function get${RelPascal}For${Singular}(${singular}Id: number): Promise<number[]> {\n try {\n const results = await db.select({ ${relIdCol}: ${junctionVar}.${relIdCol} }).from(${junctionVar}).where(eq(${junctionVar}.${entityIdCol}, ${singular}Id))\n return results.map(r => r.${relIdCol})\n } catch (error) {\n console.error('Error fetching ${rel} for ${singular}:', error)\n return []\n }\n}\n\nexport async function set${RelPascal}For${Singular}(${singular}Id: number, ${rel}Ids: number[]): Promise<{ success: boolean; error?: string }> {\n try {\n await db.delete(${junctionVar}).where(eq(${junctionVar}.${entityIdCol}, ${singular}Id))\n if (${rel}Ids.length > 0) {\n await db.insert(${junctionVar}).values(${rel}Ids.map(${relSingular}Id => ({ ${entityIdCol}: ${singular}Id, ${relIdCol}: ${relSingular}Id })))\n }\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error setting ${rel} for ${singular}:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to set ${rel}' }\n }\n}`\n })\n .join('\\n')\n : ''\n\n // --- Slugify helper ---\n const slugifyHelper = schema.autoSlugify?.enabled\n ? `\\nfunction slugify(text: string): string {\\n return text.toLowerCase().trim().replace(/[^\\\\w\\\\s-]/g, '').replace(/\\\\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, '')\\n}\\n`\n : ''\n\n // --- Auto-slug blocks ---\n const autoSlugCreate = schema.autoSlugify?.enabled\n ? `\\n if ((!input.${schema.autoSlugify.targetField} || input.${schema.autoSlugify.targetField} === '') && input.${schema.autoSlugify.sourceField}) {\\n input.${schema.autoSlugify.targetField} = slugify(input.${schema.autoSlugify.sourceField})\\n }\\n`\n : ''\n const autoSlugUpdate = schema.autoSlugify?.enabled\n ? `\\n if (updateData.${schema.autoSlugify!.sourceField}) {\\n if (updateData.${schema.autoSlugify!.targetField} === '' || updateData.${schema.autoSlugify!.targetField} === undefined) {\\n updateData.${schema.autoSlugify!.targetField} = slugify(updateData.${schema.autoSlugify!.sourceField})\\n }\\n }\\n`\n : ''\n\n const cacheTag = `${plural}:all`\n\n // --- Build single row return (for getById) ---\n const singleRowReturn = (() => {\n if (hasRelationships && hasListRels) {\n return `const row = result[0]\\n return await populate${Singular}ListRelationships(${buildSingleRowMapping(allDbFields, relationshipFields, `${Singular}Data`)})`\n }\n if (hasRelationships) {\n return `const row = result[0]\\n return ${buildSingleRowMapping(allDbFields, relationshipFields, `${Singular}Data`)}`\n }\n if (hasListRels) {\n return `return await populate${Singular}ListRelationships(result[0] as ${Singular}Data)`\n }\n return `return result[0] as ${Singular}Data`\n })()\n\n // --- Build single row return (for getBySlug — display/frontend) ---\n const displaySingleRowReturn = hasHtmlOutput\n ? (() => {\n const displayType = `${Singular}DisplayData`\n if (hasRelationships && hasListRels) {\n return `const row = result[0]\\n return await populate${Singular}ListRelationships(${buildSingleRowMapping(displayDbFields, relationshipFields, `${Singular}Data`, htmlOutputFields)}) as unknown as ${displayType}`\n }\n if (hasRelationships) {\n return `const row = result[0]\\n return ${buildSingleRowMapping(displayDbFields, relationshipFields, displayType, htmlOutputFields)}`\n }\n if (hasListRels) {\n return `return await populate${Singular}ListRelationships(result[0] as unknown as ${Singular}Data) as unknown as ${displayType}`\n }\n return `return result[0] as ${displayType}`\n })()\n : singleRowReturn\n\n // --- Assemble the file ---\n const content = `'use server'\n\nimport db from '@cms/db'\nimport { ${sortedDbImports.join(', ')} } from '@cms/db/schema'\nimport { ${sortedDrizzleImports.join(', ')} } from 'drizzle-orm'\nimport { updateTag } from 'next/cache'\n\nconst CACHE_TAG = '${cacheTag}'\n\n${dataInterface}${displayDataInterface}\n\n${responseInterface}\n\n${filtersInterface}\n\n${createInterface}\n\nexport interface Create${Singular}Result {\n success: boolean\n error?: string\n ${camelSingular}?: ${Singular}Data\n}\n\n${updateInterface}\n\nexport interface Update${Singular}Result {\n success: boolean\n error?: string\n ${camelSingular}?: ${Singular}Data\n}\n\nexport interface Delete${Singular}Result {\n success: boolean\n error?: string\n}\n${slugifyHelper}${populateListRelsFn}\nexport async function get${Plural}(filters?: Get${Plural}Filters): Promise<${Plural}Response> {\n try {\n const conditions = []\n${searchBlock}${filterConditions}\n\n const query = ${listSelectClause}\n\n const orderedQuery = conditions.length > 0\n ? query.where(and(...conditions)).orderBy(asc(${tableVar}.sortOrder))\n : query.orderBy(asc(${tableVar}.sortOrder))\n\n const results = filters?.limit && filters.limit > 0\n ? await orderedQuery.limit(filters.limit)\n : await orderedQuery${listResultMapping}\n } catch (error) {\n console.error('Error fetching ${plural}:', error)\n return { ${camelPlural}: [], total: 0 }\n }\n}\n${distinctFns}\n\nexport async function get${Singular}ById(id: number): Promise<${Singular}Data | null> {\n try {\n const result = await ${selectClause}.where(eq(${tableVar}.id, id)).limit(1)\n if (result.length === 0) return null\n ${singleRowReturn}\n } catch (error) {\n console.error('Error fetching ${singular}:', error)\n return null\n }\n}${\n hasSlug\n ? `\n\nexport async function get${Singular}BySlug(slug: string): Promise<${hasHtmlOutput ? `${Singular}DisplayData` : `${Singular}Data`} | null> {\n try {\n const result = await ${displaySelectClause}.where(eq(${tableVar}.slug, slug)).limit(1)\n if (result.length === 0) return null\n ${displaySingleRowReturn}\n } catch (error) {\n console.error('Error fetching ${singular} by slug:', error)\n return null\n }\n}`\n : ''\n }\n\nexport async function create${Singular}(input: Create${Singular}Input): Promise<Create${Singular}Result> {\n try {${autoSlugCreate}\n const maxSortOrderResult = await db\n .select({ maxOrder: ${tableVar}.sortOrder })\n .from(${tableVar})\n .orderBy(desc(${tableVar}.sortOrder))\n .limit(1)\n const nextSortOrder = (maxSortOrderResult[0]?.maxOrder ?? 0) + 1\n${htmlCreateBlock}\n const result = await db.insert(${tableVar}).values({\n${createMappings},${hasHtmlOutput ? `\\n${htmlCreateMappings},` : ''}${hasDraft ? `\\n published: input.published ?? false,` : ''}\n sortOrder: nextSortOrder,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n }).returning()\n\n updateTag(CACHE_TAG)\n\n return {\n success: true,\n ${camelSingular}: result[0] as ${Singular}Data\n }\n } catch (error) {\n console.error('Error creating ${singular}:', error)\n throw new Error(error instanceof Error ? error.message : 'Failed to create ${singular}')\n }\n}\n\nexport async function update${Singular}(input: Update${Singular}Input): Promise<Update${Singular}Result> {\n try {\n const { id, ...updateData } = input\n${autoSlugUpdate}\n const fieldMeta = [\n ${fieldMeta}\n ]\n\n const processedData: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(updateData)) {\n if (key === 'published') { processedData[key] = value; continue }\n const field = fieldMeta.find(f => f.name === key)\n if (!field) continue\n if (field.type === 'list') {\n processedData[key] = value || []\n } else if (!field.required && ['date', 'timestamp', 'time', 'string', 'varchar', 'text', 'select'].includes(field.type)) {\n processedData[key] = value && value !== '' ? value : null\n } else {\n processedData[key] = value\n }\n }\n${hasHtmlOutput ? `\n const { renderMarkdownSync } = await import('@cms/lib/markdown/render')\\n` + htmlOutputFields.map((f) => ` if (processedData.${f.name} !== undefined) {\n processedData.${f.name}Html = renderMarkdownSync(String(processedData.${f.name} || ''))\n }`).join('\\n') + '\\n' : ''}\n const result = await db.update(${tableVar})\n .set({ ...processedData, updatedAt: new Date().toISOString() })\n .where(eq(${tableVar}.id, id))\n .returning()\n\n if (result.length === 0) throw new Error('${Singular} not found')\n\n updateTag(CACHE_TAG)\n\n return {\n success: true,\n ${camelSingular}: result[0] as ${Singular}Data\n }\n } catch (error) {\n console.error('Error updating ${singular}:', error)\n throw new Error(error instanceof Error ? error.message : 'Failed to update ${singular}')\n }\n}\n\nexport async function delete${Singular}(id: number): Promise<Delete${Singular}Result> {\n try {\n await db.delete(${tableVar}).where(eq(${tableVar}.id, id))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error deleting ${singular}:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to delete ${singular}' }\n }\n}\n\nexport async function deleteBulk${Plural}(ids: number[]): Promise<Delete${Singular}Result> {\n try {\n if (ids.length === 0) return { success: false, error: 'No items selected for deletion' }\n await db.delete(${tableVar}).where(inArray(${tableVar}.id, ids))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error deleting ${plural}:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to delete ${plural}' }\n }\n}\n\nexport async function update${Singular}SortOrder(\n id: number,\n direction: 'up' | 'down'\n): Promise<{ success: boolean; error?: string }> {\n try {\n const current = await db.select({ id: ${tableVar}.id, sortOrder: ${tableVar}.sortOrder }).from(${tableVar}).where(eq(${tableVar}.id, id)).limit(1)\n if (current.length === 0) return { success: false, error: '${Singular} not found' }\n\n const currentSortOrder = current[0].sortOrder\n const adjacent = await db\n .select({ id: ${tableVar}.id, sortOrder: ${tableVar}.sortOrder })\n .from(${tableVar})\n .where(direction === 'up' ? lt(${tableVar}.sortOrder, currentSortOrder) : gt(${tableVar}.sortOrder, currentSortOrder))\n .orderBy(direction === 'up' ? desc(${tableVar}.sortOrder) : asc(${tableVar}.sortOrder))\n .limit(1)\n\n if (adjacent.length === 0) return { success: true }\n\n await db.update(${tableVar}).set({ sortOrder: adjacent[0].sortOrder }).where(eq(${tableVar}.id, id))\n await db.update(${tableVar}).set({ sortOrder: currentSortOrder }).where(eq(${tableVar}.id, adjacent[0].id))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error updating sort order:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to update sort order' }\n }\n}\n\nexport async function bulkUpdate${Plural}SortOrder(\n updates: Array<{ id: number; sortOrder: number }>\n): Promise<{ success: boolean; error?: string }> {\n try {\n if (updates.length === 0) return { success: true }\n await Promise.all(updates.map((u) => db.update(${tableVar}).set({ sortOrder: u.sortOrder }).where(eq(${tableVar}.id, u.id))))\n updateTag(CACHE_TAG)\n return { success: true }\n } catch (error) {\n console.error('Error bulk updating sort order:', error)\n return { success: false, error: error instanceof Error ? error.message : 'Failed to bulk update sort order' }\n }\n}${m2mHelpers}\n`\n\n // Write\n if (!fs.existsSync(absActionsDir)) {\n fs.mkdirSync(absActionsDir, { recursive: true })\n }\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [path.join(actionsDir, `${schema.name}.ts`)] }\n}\n","/**\n * Shared helpers for entity and single action generators\n */\n\nimport { toTypeScriptType } from '../../core/type-mappers/index.js'\nimport type { SchemaField } from '../../types.js'\nimport { toCamelCase } from '../../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface ActionsGeneratorResult {\n files: string[]\n}\n\n// ============================================================================\n// Field Mapping Helpers\n// ============================================================================\n\nexport function generateFieldMapping(field: SchemaField, source = 'input'): string {\n if (field.type === 'list') return `${source}.${field.name} || []`\n if (\n (field.type === 'date' || field.type === 'timestamp' || field.type === 'time') &&\n !field.required\n ) {\n return `${source}.${field.name} && ${source}.${field.name} !== '' ? ${source}.${field.name} : null`\n }\n if (!field.required && ['string', 'varchar', 'text', 'select'].includes(field.type)) {\n return `${source}.${field.name} && ${source}.${field.name} !== '' ? ${source}.${field.name} : null`\n }\n return `${source}.${field.name}`\n}\n\nexport function getFieldType(field: SchemaField, mode: 'input' | 'output' = 'output'): string {\n return toTypeScriptType(field, mode)\n}\n\n// ============================================================================\n// Helper builders for relationship queries\n// ============================================================================\n\nexport function buildRelationshipSelect(\n allDbFields: SchemaField[],\n relationshipFields: SchemaField[],\n tableVar: string,\n htmlFields: SchemaField[] = []\n): string {\n const fieldSelects = allDbFields\n .filter((f) => f.type !== 'relationship')\n .map((f) => ` ${f.name}: ${tableVar}.${f.name}`)\n const htmlSelects = htmlFields.map((f) => ` ${f.name}Html: ${tableVar}.${f.name}Html`)\n const regularSelects = [...fieldSelects, ...htmlSelects].join(',\\n')\n\n const relSelects = relationshipFields\n .map((f) => {\n const relTable = toCamelCase(f.relationship!)\n return ` ${f.name}: { id: ${relTable}.id, name: ${relTable}.name, title: ${relTable}.title, slug: ${relTable}.slug, label: ${relTable}.label }`\n })\n .join(',\\n')\n\n const joins = relationshipFields\n .map((f) => {\n const relTable = toCamelCase(f.relationship!)\n return `.leftJoin(${relTable}, sql\\`CAST(NULLIF(\\${${tableVar}.${f.name}}, '') AS INTEGER) = \\${${relTable}.id}\\`)`\n })\n .join('')\n\n return `db.select({\\n${regularSelects},\\n${relSelects}\\n }).from(${tableVar})${joins}`\n}\n\nexport function buildResultMapping(\n allDbFields: SchemaField[],\n _relationshipFields: SchemaField[],\n Plural: string,\n camelPlural: string,\n Singular: string,\n hasListRels = false\n): string {\n const rowMappings = allDbFields\n .map((f) => {\n if (f.type === 'relationship' && !f.multiple) {\n return ` ${f.name}: row.${f.name}?.id ? { id: row.${f.name}.id, name: row.${f.name}.name ?? undefined, title: row.${f.name}.title ?? undefined, slug: row.${f.name}.slug ?? undefined, label: row.${f.name}.label ?? undefined } : null`\n }\n return ` ${f.name}: row.${f.name}`\n })\n .join(',\\n')\n\n const mapBlock = `\n\n const mapped${Plural} = results.map((row) => ({\n${rowMappings}\n }))`\n\n if (hasListRels) {\n return `${mapBlock}\n\n const populated${Plural} = await Promise.all(\n mapped${Plural}.map(record => populate${Singular}ListRelationships(record as ${Singular}Data))\n )\n\n return {\n ${camelPlural}: populated${Plural},\n total: populated${Plural}.length\n }`\n }\n\n return `${mapBlock}\n\n return {\n ${camelPlural}: mapped${Plural} as ${Singular}Data[],\n total: mapped${Plural}.length\n }`\n}\n\nexport function buildSingleRowMapping(\n allDbFields: SchemaField[],\n _relationshipFields: SchemaField[],\n typeName: string,\n htmlFields: SchemaField[] = []\n): string {\n const fieldMappings = allDbFields\n .map((f) => {\n if (f.type === 'relationship' && !f.multiple) {\n return ` ${f.name}: row.${f.name}?.id ? { id: row.${f.name}.id, name: row.${f.name}.name ?? undefined, title: row.${f.name}.title ?? undefined, slug: row.${f.name}.slug ?? undefined, label: row.${f.name}.label ?? undefined } : null`\n }\n return ` ${f.name}: row.${f.name}`\n })\n const htmlMappings = htmlFields.map((f) => ` ${f.name}Html: row.${f.name}Html`)\n const mappings = [...fieldMappings, ...htmlMappings].join(',\\n')\n\n return `{\\n${mappings}\\n } as ${typeName}`\n}\n\nexport function buildExplicitSelect(fields: SchemaField[], tableVar: string, htmlFields: SchemaField[] = []): string {\n const fieldSelects = fields.map((f) => ` ${f.name}: ${tableVar}.${f.name}`)\n const htmlSelects = htmlFields.map((f) => ` ${f.name}Html: ${tableVar}.${f.name}Html`)\n const selects = [...fieldSelects, ...htmlSelects].join(',\\n')\n return `db.select({\\n${selects}\\n }).from(${tableVar})`\n}\n\n// ============================================================================\n// List-relationship helpers\n// ============================================================================\n\nexport function findListFieldsWithRelationships(\n fields: SchemaField[]\n): Array<{ field: SchemaField; path: string[] }> {\n const result: Array<{ field: SchemaField; path: string[] }> = []\n for (const field of fields) {\n if (field.type === 'list' && field.fields) {\n const hasRels = field.fields.some((f) => f.type === 'relationship' && f.relationship)\n if (hasRels) {\n result.push({ field, path: [field.name] })\n }\n }\n }\n return result\n}\n\nexport function generatePopulateListRelsFunction(\n queries: Array<{\n fieldPath: string\n relField: SchemaField\n relTable: string\n listFieldName: string\n }>,\n Singular: string\n): string {\n const blocks = queries.map((q) => {\n const v = `${q.fieldPath}_${q.relField.name}`\n return ` // ${q.listFieldName} -> ${q.relField.name}\n const ${v}Ids = record.${q.listFieldName} && Array.isArray(record.${q.listFieldName})\n ? (record.${q.listFieldName} as Record<string, unknown>[])\n .map((item) => item.${q.relField.name})\n .filter((id) => id != null && id !== '')\n .map((id) => Number.parseInt(String(id), 10))\n .filter((id) => !Number.isNaN(id))\n : []\n\n const ${v}Results = ${v}Ids.length > 0\n ? await db.select().from(${q.relTable}).where(inArray(${q.relTable}.id, ${v}Ids))\n : []\n\n const ${v}Map = new Map(${v}Results.map((r) => [r.id, r]))\n\n if (record.${q.listFieldName} && Array.isArray(record.${q.listFieldName})) {\n record.${q.listFieldName} = (record.${q.listFieldName} as Record<string, unknown>[]).map((item) => {\n const relId = item.${q.relField.name} ? Number.parseInt(String(item.${q.relField.name}), 10) : null\n return {\n ...item,\n ${q.relField.name}: relId && !Number.isNaN(relId) ? ${v}Map.get(relId) || null : null\n }\n })\n }`\n })\n\n return `\n/**\n * Populate relationship fields inside list (JSONB) fields\n */\nasync function populate${Singular}ListRelationships(record: ${Singular}Data): Promise<${Singular}Data> {\n${blocks.join('\\n\\n')}\n\n return record\n}\n`\n}\n","/**\n * Generator 2b: Server actions for single (singleton) schemas\n * Only getXxx() and upsertXxx() — no list, delete, sort, or bulk ops.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../../core/field-helpers/index.js'\nimport type { Schema } from '../../types.js'\nimport { toPascalCase, toCamelCase, singularize, quotePropertyName } from '../../utils/string.js'\nimport type { ActionsGeneratorResult } from './action-helpers.js'\nimport { generateFieldMapping, getFieldType } from './action-helpers.js'\n\n/**\n * Generate server actions file for a single (singleton) schema.\n * Only getXxx() and upsertXxx() — no list, delete, sort, or bulk ops.\n */\nexport function generateSingleActions(\n schema: Schema,\n cwd: string,\n actionsDir: string,\n options: { force?: boolean } = {}\n): ActionsGeneratorResult {\n const absActionsDir = path.join(cwd, actionsDir)\n const filePath = path.join(absActionsDir, `${schema.name}.ts`)\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const tableVar = toCamelCase(schema.name)\n const camelSingular = toCamelCase(singular)\n\n const dbFields = flattenFields(schema.fields).filter(\n (f) => !(f.type === 'relationship' && f.multiple === true)\n )\n\n const singleHtmlOutputFields = dbFields.filter(\n (f) => (f.type === 'richtext' || f.type === 'markdown') && f.output === 'html'\n )\n const singleHasHtmlOutput = singleHtmlOutputFields.length > 0\n\n // Build allDbFields (with auto-added timestamp fields, NO sortOrder)\n const allDbFields = [...dbFields]\n if (!dbFields.some((f) => f.name === 'createdAt')) {\n allDbFields.push({ name: 'createdAt', type: 'timestamp' as const, required: true })\n }\n if (!dbFields.some((f) => f.name === 'updatedAt')) {\n allDbFields.push({ name: 'updatedAt', type: 'timestamp' as const, required: true })\n }\n\n // Upsert fields (exclude auto-generated)\n const upsertFields = dbFields.filter(\n (f) => !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt'\n )\n\n // Data interface\n const dataFields = allDbFields\n .map(\n (f) =>\n ` ${quotePropertyName(f.name)}: ${getFieldType(f, 'output')}${f.required ? '' : ' | null'}`\n )\n .join('\\n')\n const singleHtmlFieldTypes = singleHtmlOutputFields.map((f) => ` ${f.name}Html: string`).join('\\n')\n const dataInterface = `export interface ${Singular}Data {\\n${dataFields}${singleHtmlFieldTypes ? `\\n${singleHtmlFieldTypes}` : ''}\\n}`\n\n // Upsert input interface\n const upsertInterfaceFields = upsertFields\n .map(\n (f) => ` ${quotePropertyName(f.name)}${f.required ? '' : '?'}: ${getFieldType(f, 'input')}`\n )\n .join('\\n')\n const upsertInterface = `export interface Upsert${Singular}Input {\\n${upsertInterfaceFields}\\n}`\n\n // Upsert field mappings\n const upsertMappings = upsertFields\n .map((f) => ` ${f.name}: ${generateFieldMapping(f)}`)\n .join(',\\n')\n\n // Field metadata for update processing\n const fieldMeta = upsertFields\n .map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`)\n .join(',\\n ')\n\n const cacheTag = `${schema.name}:all`\n\n const singleHtmlUpsertMappings = singleHtmlOutputFields\n .map((f) => ` ${f.name}Html`)\n .join(',\\n')\n\n const content = `'use server'\n\nimport db from '@cms/db'\nimport { ${tableVar} } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\nimport { updateTag } from 'next/cache'\n\nconst CACHE_TAG = '${cacheTag}'\n\n${dataInterface}\n\n${upsertInterface}\n\nexport interface Upsert${Singular}Result {\n success: boolean\n error?: string\n ${camelSingular}?: ${Singular}Data\n}\n\nexport async function get${Singular}(): Promise<${Singular}Data | null> {\n try {\n const result = await db.select().from(${tableVar}).where(eq(${tableVar}.id, 1)).limit(1)\n if (result.length === 0) return null\n return result[0] as ${Singular}Data\n } catch (error) {\n console.error('Error fetching ${singular}:', error)\n return null\n }\n}\n\nexport async function upsert${Singular}(input: Upsert${Singular}Input): Promise<Upsert${Singular}Result> {\n try {\n const fieldMeta = [\n ${fieldMeta}\n ]\n\n const processedData: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) {\n const field = fieldMeta.find(f => f.name === key)\n if (!field) continue\n if (field.type === 'list') {\n processedData[key] = value || []\n } else if (!field.required && ['date', 'timestamp', 'time', 'string', 'varchar', 'text', 'select'].includes(field.type)) {\n processedData[key] = value && value !== '' ? value : null\n } else {\n processedData[key] = value\n }\n }\n${singleHasHtmlOutput ? `\n const { renderMarkdownSync } = await import('@cms/lib/markdown/render')\\n` + singleHtmlOutputFields.map((f) => ` if (processedData.${f.name} !== undefined) {\n processedData.${f.name}Html = renderMarkdownSync(String(processedData.${f.name} || ''))\n }`).join('\\n') + '\\n' + singleHtmlOutputFields.map((f) => ` const ${f.name}Html = renderMarkdownSync(input.${f.name} || '')`).join('\\n') + '\\n' : ''}\n const now = new Date().toISOString()\n\n const result = await db\n .insert(${tableVar})\n .values({\n id: 1,\n${upsertMappings},${singleHasHtmlOutput ? '\\n' + singleHtmlOutputFields.map((f) => ` ${f.name}Html`).join(',\\n') + ',' : ''}\n createdAt: now,\n updatedAt: now\n })\n .onConflictDoUpdate({\n target: ${tableVar}.id,\n set: { ...processedData, updatedAt: now }\n })\n .returning()\n\n updateTag(CACHE_TAG)\n\n return {\n success: true,\n ${camelSingular}: result[0] as ${Singular}Data\n }\n } catch (error) {\n console.error('Error upserting ${singular}:', error)\n throw new Error(error instanceof Error ? error.message : 'Failed to save ${singular}')\n }\n}\n`\n\n if (!fs.existsSync(absActionsDir)) {\n fs.mkdirSync(absActionsDir, { recursive: true })\n }\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [path.join(actionsDir, `${schema.name}.ts`)] }\n}\n","/**\n * Generator 12: Cache module — cms/lib/cache/\n * Generates tags, cached queries, and revalidation helpers for all schemas\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize, pluralize, toScreamingSnake } from '../utils/string.js'\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\ninterface NestedLookupConfig {\n name: string\n pascalName: string\n camelName: string\n screamingSnake: string\n slugField: string\n}\n\ninterface CacheConfig {\n name: string\n singularName: string\n pluralName: string\n pascalSingular: string\n pascalPlural: string\n screamingSnake: string\n hasSlug: boolean\n isSingle: boolean\n nestedLookups: NestedLookupConfig[]\n}\n\n// ============================================================================\n// Schema Loading\n// ============================================================================\n\nfunction loadAllSchemas(cwd: string, schemasDir: string): Schema[] {\n const dir = path.join(cwd, schemasDir)\n if (!fs.existsSync(dir)) return []\n\n const files = fs.readdirSync(dir).filter((f) => f.endsWith('.json'))\n const seen = new Map<string, Schema>()\n\n for (const file of files) {\n if (file === 'schema.json') continue // skip metaschema\n const content = fs.readFileSync(path.join(dir, file), 'utf-8')\n const schema = JSON.parse(content) as Schema\n if (!schema.name) continue // skip non-entity JSON files\n seen.set(schema.name, schema)\n }\n\n return Array.from(seen.values())\n}\n\nfunction buildCacheConfig(schema: Schema): CacheConfig {\n const singularName = singularize(schema.name)\n const pluralName = pluralize(schema.name)\n const dbFields = flattenFields(schema.fields)\n const hasSlug = dbFields.some((f) => f.name === 'slug')\n\n const nestedLookups: NestedLookupConfig[] = (schema.nestedSlugLookups || []).map((lookup) => ({\n name: lookup.name,\n pascalName: toPascalCase(lookup.name),\n camelName: toCamelCase(lookup.name),\n screamingSnake: toScreamingSnake(lookup.name),\n slugField: lookup.slugField || 'slug'\n }))\n\n return {\n name: schema.name,\n singularName,\n pluralName,\n pascalSingular: toPascalCase(singularName),\n pascalPlural: toPascalCase(pluralName),\n screamingSnake: toScreamingSnake(pluralName),\n hasSlug,\n isSingle: schema.type === 'single',\n nestedLookups\n }\n}\n\n// ============================================================================\n// File Generators\n// ============================================================================\n\nfunction generateTags(configs: CacheConfig[]): string {\n const entries: string[] = []\n\n for (const c of configs) {\n entries.push(` ${c.screamingSnake}_ALL: '${c.pluralName}:all'`)\n\n if (c.isSingle) continue // single schemas only need the ALL tag\n\n if (c.hasSlug) {\n entries.push(\n ` ${c.screamingSnake}_BY_SLUG: (slug: string) => \\`${c.pluralName}:slug:\\${slug}\\``\n )\n }\n\n for (const n of c.nestedLookups) {\n entries.push(\n ` ${c.screamingSnake}_${n.screamingSnake}_BY_SLUG: (${c.singularName}Slug: string, ${n.camelName}Slug: string) => \\`${c.pluralName}:\\${${c.singularName}Slug}:${n.name}:\\${${n.camelName}Slug}\\``\n )\n }\n }\n\n entries.sort()\n\n return `/**\n * Cache tag constants for Next.js 'use cache' invalidation\n * AUTO-GENERATED — do not edit directly\n */\n\nexport const CACHE_TAGS = {\n${entries.join(',\\n')}\n} as const\n`\n}\n\nfunction generateCachedQueries(configs: CacheConfig[]): string {\n const actionImports: string[] = []\n const typeImports: string[] = []\n const fns: string[] = []\n\n for (const c of configs) {\n if (c.isSingle) {\n // Single schema: getCachedXxx() with no filters\n actionImports.push(`get${c.pascalSingular}`)\n\n fns.push(`\nexport const getCached${c.pascalSingular} = async () => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${c.pascalSingular}()\n}`)\n continue\n }\n\n // Entity schema: getCachedXxxPlural(filters) + slug lookups\n actionImports.push(`get${c.pascalPlural}`)\n typeImports.push(`Get${c.pascalPlural}Filters`)\n\n if (c.hasSlug) actionImports.push(`get${c.pascalSingular}BySlug`)\n for (const n of c.nestedLookups) actionImports.push(`get${n.pascalName}BySlug`)\n\n fns.push(`\nexport const getCached${c.pascalPlural} = async (filters?: Get${c.pascalPlural}Filters) => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${c.pascalPlural}(filters)\n}`)\n\n if (c.hasSlug) {\n fns.push(`\nexport const getCached${c.pascalSingular}BySlug = async (slug: string) => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_BY_SLUG(slug))\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${c.pascalSingular}BySlug(slug)\n}`)\n }\n\n for (const n of c.nestedLookups) {\n fns.push(`\nexport const getCached${n.pascalName}BySlug = async (${c.singularName}Slug: string, ${n.camelName}Slug: string) => {\n cacheLife('max')\n cacheTag(CACHE_TAGS.${c.screamingSnake}_${n.screamingSnake}_BY_SLUG(${c.singularName}Slug, ${n.camelName}Slug))\n cacheTag(CACHE_TAGS.${c.screamingSnake}_ALL)\n return get${n.pascalName}BySlug(${c.singularName}Slug, ${n.camelName}Slug)\n}`)\n }\n }\n\n actionImports.sort()\n typeImports.sort()\n\n const typeImportStr =\n typeImports.length > 0\n ? `${typeImports\n .map((t) => {\n const schemaName = t\n .replace(/^Get/, '')\n .replace(/Filters$/, '')\n .toLowerCase()\n return `import type { ${t} } from '@cms/actions/${schemaName}'`\n })\n .join('\\n')}\\n`\n : ''\n\n // Group action imports by schema\n const actionsBySchema = new Map<string, string[]>()\n for (const c of configs) {\n if (c.isSingle) {\n actionsBySchema.set(c.name, [`get${c.pascalSingular}`])\n continue\n }\n const names: string[] = [`get${c.pascalPlural}`]\n if (c.hasSlug) names.push(`get${c.pascalSingular}BySlug`)\n for (const n of c.nestedLookups) names.push(`get${n.pascalName}BySlug`)\n actionsBySchema.set(c.name, names)\n }\n\n const actionImportLines = Array.from(actionsBySchema.entries())\n .map(([name, fns]) => `import { ${fns.join(', ')} } from '@cms/actions/${name}'`)\n .join('\\n')\n\n return `'use cache'\n\n/**\n * Cached query functions for Next.js 'use cache'\n * AUTO-GENERATED — do not edit directly\n */\n\nimport { cacheLife, cacheTag } from 'next/cache'\n${typeImportStr}${actionImportLines}\nimport { CACHE_TAGS } from './tags'\n${fns.join('\\n')}\n`\n}\n\nfunction generateRevalidate(configs: CacheConfig[]): string {\n const fns: string[] = []\n\n for (const c of configs) {\n if (c.isSingle) {\n fns.push(`\nexport const revalidate${c.pascalSingular} = async () => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n continue\n }\n\n fns.push(`\nexport const revalidate${c.pascalPlural} = async () => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n\n if (c.hasSlug) {\n fns.push(`\nexport const revalidate${c.pascalSingular}BySlug = async (slug: string) => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_BY_SLUG(slug), REVALIDATION_STRATEGY)\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n }\n\n for (const n of c.nestedLookups) {\n fns.push(`\nexport const revalidate${n.pascalName}BySlug = async (${c.singularName}Slug: string, ${n.camelName}Slug: string) => {\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_${n.screamingSnake}_BY_SLUG(${c.singularName}Slug, ${n.camelName}Slug), REVALIDATION_STRATEGY)\n revalidateTag(CACHE_TAGS.${c.screamingSnake}_ALL, REVALIDATION_STRATEGY)\n}`)\n }\n }\n\n return `'use server'\n\n/**\n * Revalidation helpers for Next.js cache invalidation\n * AUTO-GENERATED — do not edit directly\n */\n\nimport { revalidateTag } from 'next/cache'\nimport { CACHE_TAGS } from './tags'\n\nconst REVALIDATION_STRATEGY = 'max' as const\n${fns.join('\\n')}\n`\n}\n\nfunction generateIndex(): string {\n return `/**\n * Cache module exports\n * AUTO-GENERATED — do not edit directly\n */\n\nexport * from './tags'\nexport * from './cached-queries'\nexport * from './cached-queries-custom'\nexport * from './revalidate'\n`\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface CacheGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate all cache files based on all schemas in cms/schemas/\n */\nexport function generateCache(\n _schema: Schema,\n cwd: string,\n cmsDir: string,\n _options: GeneratorOptions = {}\n): CacheGeneratorResult {\n const cacheDir = path.join(cwd, cmsDir, 'lib', 'cache')\n const schemasDir = path.join(cmsDir, 'schemas')\n\n // Load all schemas and build configs\n const schemas = loadAllSchemas(cwd, schemasDir)\n const configs = schemas.map(buildCacheConfig).sort((a, b) => a.name.localeCompare(b.name))\n\n if (!fs.existsSync(cacheDir)) {\n fs.mkdirSync(cacheDir, { recursive: true })\n }\n\n const files: string[] = []\n\n // tags.ts\n fs.writeFileSync(path.join(cacheDir, 'tags.ts'), generateTags(configs), 'utf-8')\n files.push(path.join(cmsDir, 'lib', 'cache', 'tags.ts'))\n\n // cached-queries.ts\n fs.writeFileSync(\n path.join(cacheDir, 'cached-queries.ts'),\n generateCachedQueries(configs),\n 'utf-8'\n )\n files.push(path.join(cmsDir, 'lib', 'cache', 'cached-queries.ts'))\n\n // revalidate.ts\n fs.writeFileSync(path.join(cacheDir, 'revalidate.ts'), generateRevalidate(configs), 'utf-8')\n files.push(path.join(cmsDir, 'lib', 'cache', 'revalidate.ts'))\n\n // cached-queries-custom.ts (user-maintained, scaffold only if missing)\n const customQueriesPath = path.join(cacheDir, 'cached-queries-custom.ts')\n if (!fs.existsSync(customQueriesPath)) {\n fs.writeFileSync(\n customQueriesPath,\n `/**\\n * Custom cached query functions (not auto-generated)\\n * Add your custom cached queries here.\\n */\\n\\nexport {}\\n`,\n 'utf-8'\n )\n files.push(path.join(cmsDir, 'lib', 'cache', 'cached-queries-custom.ts'))\n }\n\n // index.ts\n fs.writeFileSync(path.join(cacheDir, 'index.ts'), generateIndex(), 'utf-8')\n files.push(path.join(cmsDir, 'lib', 'cache', 'index.ts'))\n\n return { files }\n}\n","/**\n * Generator 4: Column definitions — (authenticated)/<n>/columns.tsx\n * Generates TanStack Table column definitions for entity list views\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport {\n generateColumnDef,\n generateFirstColumnDef,\n generateTitleFallback,\n isSortableColumn\n} from './column-defs.js'\nimport {\n generateDeleteActionTemplate,\n generateReorderButtonsTemplate,\n generateTruncateHelper\n} from './column-actions.js'\nimport { createCustomCellComponent } from './custom-cell.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface ColumnsGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate column definitions for entity list view\n */\nexport function generateColumns(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): ColumnsGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const columnsFilePath = path.join(entityDir, 'columns.tsx')\n\n if (fs.existsSync(columnsFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n\n const flatFields = flattenFields(schema.fields || [])\n const titleFallback = generateTitleFallback(flatFields)\n\n // --- Determine needed imports ---\n let needsArrowUpDown = false\n let needsBadge = false\n let needsButton = true // Always for actions column\n let needsAvatar = false\n let needsTruncate = false\n let needsReactQueryClient = false\n let needsToast = false\n let needsAlertDialog = false\n let needsTrash = false\n\n for (const column of schema.columns) {\n if (isSortableColumn(column)) {\n needsArrowUpDown = true\n needsButton = true\n }\n if (column.type === 'badge' || column.type === 'boolean') needsBadge = true\n if (column.type === 'image' || column.type === 'avatar') needsAvatar = true\n if (column.type === 'link') needsTruncate = true\n }\n\n const hasEdit = schema.actions?.edit ?? false\n const hasDelete = schema.actions?.delete ?? false\n if (hasDelete) {\n needsTrash = true\n needsAlertDialog = true\n needsReactQueryClient = true\n needsToast = true\n }\n\n // --- Build lucide icons ---\n const lucideIcons: string[] = []\n if (needsArrowUpDown) lucideIcons.push('ArrowUpDown')\n lucideIcons.push('ChevronDown', 'ChevronUp', 'Edit')\n if (needsTrash) lucideIcons.push('Trash')\n\n // --- Build UI component imports (individual per-component) ---\n const uiImports: string[] = []\n if (needsButton) uiImports.push(\"import { Button } from '@cms/components/ui/button'\")\n if (needsBadge) uiImports.push(\"import { Badge } from '@cms/components/ui/badge'\")\n uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (needsAvatar) {\n uiImports.push(\n \"import { Avatar, AvatarImage, AvatarFallback } from '@cms/components/ui/avatar'\"\n )\n }\n if (needsAlertDialog) {\n uiImports.push(`import {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger\n} from '@cms/components/ui/alert-dialog'`)\n }\n\n // --- Custom component imports ---\n const customImports: string[] = []\n for (const column of schema.columns) {\n if (column.type === 'custom' && column.component) {\n customImports.push(`import { ${column.component} } from './cells/${column.component}'`)\n createCustomCellComponent(schema, column.component, cwd, pagesDir, options)\n }\n }\n\n // --- Action imports ---\n const actionImports: string[] = []\n if (hasDelete) actionImports.push(`delete${Singular}`)\n\n // --- Generate columns ---\n const firstColumn = schema.columns[0]\n const restColumns = schema.columns.slice(1)\n\n const firstColDef = generateFirstColumnDef(firstColumn, flatFields, schema.name)\n const restColDefs = restColumns.map((col) => generateColumnDef(col, flatFields)).join(',\\n')\n\n // --- Delete handler ---\n const deleteHandler = hasDelete\n ? generateDeleteActionTemplate({ Singular, singular, plural })\n : ''\n\n // --- Reorder handler ---\n const reorderHandler = generateReorderButtonsTemplate()\n\n // --- Reorder column ---\n const reorderColumn = ` {\n id: 'reorder',\n header: () => <span className=\"sr-only\">Reorder</span>,\n cell: ({ row, table }) => {\n const reorderMode = table.options.meta?.reorderMode\n const onMoveRow = table.options.meta?.onMoveRow\n\n if (!reorderMode) return null\n\n const allRows = table.getRowModel().rows\n const currentIndex = allRows.findIndex(r => r.id === row.id)\n const isFirst = currentIndex === 0\n const isLast = currentIndex === allRows.length - 1\n\n return (\n <ReorderButtons\n id={row.original.id as number}\n isFirst={isFirst}\n isLast={isLast}\n onMoveRow={onMoveRow}\n />\n )\n },\n enableSorting: false,\n enableHiding: false,\n size: 80\n }`\n\n // --- Edit button ---\n let editButton = ''\n if (hasEdit) {\n editButton = ` <Button variant=\"outline\" className=\"size-8\" asChild>\n <Link href={\\`/cms/${schema.name}/\\${row.original.id}/edit\\`}>\n <Edit className=\"size-3\" strokeWidth={2} />\n <span className=\"sr-only\">Edit ${singular} {${titleFallback}}</span>\n </Link>\n </Button>`\n }\n\n // --- Actions column ---\n const actionsColumn = ` {\n id: 'actions',\n header: () => <div className=\"text-right\">Actions</div>,\n cell: ({ row }) => (\n <div className=\"flex justify-end items-center gap-2\">\n${editButton}\n${hasDelete ? ' <DeleteAction id={row.original.id as number} />' : ''}\n </div>\n )\n }`\n\n // --- Truncate helper ---\n const truncateHelper = needsTruncate\n ? generateTruncateHelper()\n : ''\n\n // --- Assemble file ---\n const content = `'use client'\n\nimport type { ColumnDef } from '@tanstack/react-table'\n${needsReactQueryClient ? \"import { useQueryClient } from '@tanstack/react-query'\" : ''}\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'\nimport Link from 'next/link'\nimport * as React from 'react'\n${needsToast ? \"import { toast } from 'sonner'\" : ''}\n${uiImports.join('\\n')}\n${actionImports.length > 0 ? `import { ${actionImports.join(', ')} } from '@cms/actions/${schema.name}'` : ''}\nimport type { ${Singular}Data } from '@cms/actions/${schema.name}'\n${customImports.join('\\n')}\n${truncateHelper}${deleteHandler}${reorderHandler}\nexport const columns: ColumnDef<${Singular}Data>[] = [\n${reorderColumn},\n${firstColDef}${restColDefs ? `,\\n${restColDefs}` : ''},\n${actionsColumn}\n]\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(columnsFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'columns.tsx')]\n }\n}\n","/**\n * Column definition generators for TanStack Table columns\n */\n\nimport type { SchemaColumn, SchemaField } from '../../types.js'\n\n// ============================================================================\n// Column Helpers\n// ============================================================================\n\nexport function isSortableColumn(column: SchemaColumn): boolean {\n if (typeof column.sortable === 'boolean') return column.sortable\n const nonSortableTypes = ['image', 'avatar', 'link', 'custom']\n return !nonSortableTypes.includes(column.type)\n}\n\nexport function generateTitleFallback(fields: SchemaField[]): string {\n const fieldNames = new Set(fields.map((f) => f.name))\n const fallbacks: string[] = []\n if (fieldNames.has('title')) fallbacks.push('row.original.title')\n if (fieldNames.has('name')) fallbacks.push('row.original.name')\n fallbacks.push('row.original.id')\n fallbacks.push(\"''\")\n return fallbacks.join(' || ')\n}\n\n// ============================================================================\n// Cell Renderers\n// ============================================================================\n\nexport function generateColumnDef(column: SchemaColumn, fields: SchemaField[]): string {\n const sortable = isSortableColumn(column)\n const headerDef = sortable\n ? `header: ({ column }) => {\n const sortDirection = column.getIsSorted()\n const sortLabel = sortDirection === 'asc'\n ? 'sorted ascending'\n : sortDirection === 'desc'\n ? 'sorted descending'\n : 'not sorted'\n\n return (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n aria-label={\\`Sort by ${column.header}, \\${sortLabel}\\`}\n aria-sort={sortDirection === 'asc' ? 'ascending' : sortDirection === 'desc' ? 'descending' : 'none'}\n >\n ${column.header}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n )\n }`\n : `header: '${column.header}'`\n\n const titleFallback = generateTitleFallback(fields)\n let cellDef = ''\n\n switch (column.type) {\n case 'image':\n cellDef = `cell: ({ row }) => {\n const imageUrl = row.getValue('${column.accessorKey}') ?? ''\n const title = ${titleFallback}\n return (\n <Avatar className=\"size-10 border\">\n <AvatarImage\n src={imageUrl}\n alt={title ? \\`${column.header} image for \\${title}\\` : '${column.header} image'}\n />\n <AvatarFallback>\n {String(title || imageUrl).substring(0, 2).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n )\n }`\n break\n case 'badge':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}')\n return (\n <Badge variant=\"outline\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </Badge>\n )\n }`\n break\n case 'date':\n cellDef = `cell: ({ row }) => {\n const date = new Date(row.getValue('${column.accessorKey}'))\n return (\n <div className=\"text-sm\">\n {date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric'\n })}\n </div>\n )\n }`\n break\n case 'email':\n cellDef = `cell: ({ row }) => {\n const email = row.getValue('${column.accessorKey}') as string\n return <div className=\"text-sm font-medium\">{email}</div>\n }`\n break\n case 'number':\n if (column.format === 'currency') {\n cellDef = `cell: ({ row }) => {\n const amount = row.getValue('${column.accessorKey}') as number\n return (\n <div className=\"text-sm font-medium\">\n {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount)}\n </div>\n )\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}') as number\n return <div className=\"text-sm\">{value}</div>\n }`\n }\n break\n case 'boolean':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}') as boolean\n return (\n <Badge variant={value ? 'outline' : 'secondary'}>\n {value ? 'Yes' : 'No'}\n </Badge>\n )\n }`\n break\n case 'link':\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}') as string\n if (!value) return <div className=\"text-muted-foreground\">\\u2014</div>\n return (\n <a\n href={value}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-blue-600 hover:text-blue-800 hover:underline dark:text-blue-400 dark:hover:text-blue-300\"\n title={value}\n >\n {truncateStr(value, 50)}\n </a>\n )\n }`\n break\n case 'custom':\n if (column.component) {\n cellDef = `cell: ({ row }) => {\n return <${column.component} data={row.original} />\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}')\n return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>\n }`\n }\n break\n default:\n cellDef = `cell: ({ row }) => {\n const value = row.getValue('${column.accessorKey}')\n return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>\n }`\n break\n }\n\n return ` {\n accessorKey: '${column.accessorKey}',\n ${headerDef},\n ${cellDef}\n }`\n}\n\nexport function generateFirstColumnDef(\n column: SchemaColumn,\n fields: SchemaField[],\n schemaName: string\n): string {\n const sortable = isSortableColumn(column)\n const headerDef = sortable\n ? `header: ({ table, column }) => {\n const sortDirection = column.getIsSorted()\n const sortLabel = sortDirection === 'asc'\n ? 'sorted ascending'\n : sortDirection === 'desc'\n ? 'sorted descending'\n : 'not sorted'\n\n return (\n <div className=\"flex items-center gap-4\">\n <Checkbox\n checked={table.getIsAllPageRowsSelected()}\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n aria-label={\\`Sort by ${column.header}, \\${sortLabel}\\`}\n aria-sort={sortDirection === 'asc' ? 'ascending' : sortDirection === 'desc' ? 'descending' : 'none'}\n >\n ${column.header}\n <ArrowUpDown className=\"size-4\" />\n </Button>\n </div>\n )\n }`\n : `header: ({ table }) => (\n <div className=\"flex items-center gap-4\">\n <Checkbox\n checked={table.getIsAllPageRowsSelected()}\n onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n <span>${column.header}</span>\n </div>\n )`\n\n const titleFallback = generateTitleFallback(fields)\n const linkBase = `/cms/${schemaName}`\n let cellDef = ''\n\n switch (column.type) {\n case 'image':\n cellDef = `cell: ({ row }) => {\n const imageUrl = row.original.${column.accessorKey} as string\n const title = ${titleFallback}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <Avatar className=\"size-10 border\">\n <AvatarImage\n src={imageUrl}\n alt={title ? \\`${column.header} image for \\${title}\\` : '${column.header} image'}\n />\n <AvatarFallback>\n {String(title || imageUrl).substring(0, 2).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'badge':\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <Badge variant=\"outline\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </Badge>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'date':\n cellDef = `cell: ({ row }) => {\n const date = new Date(row.original.${column.accessorKey})\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full\"\n >\n <div className=\"text-sm\">\n {date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric'\n })}\n </div>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'email':\n cellDef = `cell: ({ row }) => {\n const email = row.original.${column.accessorKey} as string\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full w-full max-w-[300px] py-3\"\n >\n <span className=\"text-sm font-medium truncate\">{email}</span>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'number':\n if (column.format === 'currency') {\n cellDef = `cell: ({ row }) => {\n const amount = row.original.${column.accessorKey} as number\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full\"\n >\n <div className=\"text-sm font-medium\">\n {new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD'\n }).format(amount)}\n </div>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey} as number\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full\"\n >\n <div className=\"text-sm\">{value}</div>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n }\n break\n case 'boolean':\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey} as boolean\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <Badge variant={value ? 'outline' : 'secondary'}>\n {value ? 'Yes' : 'No'}\n </Badge>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n case 'custom':\n if (column.component) {\n cellDef = `cell: ({ row }) => {\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\">\n <${column.component} data={row.original} />\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n } else {\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full w-full max-w-[300px] py-3\"\n >\n <span className=\"truncate\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </span>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n }\n break\n case 'link':\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey} as string\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link href={\\`${linkBase}/\\${row.original.id}/edit\\`} className=\"flex items-center gap-2 hover:opacity-80 transition-opacity max-w-[250px]\">\n {value ? (\n <a\n href={value}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-blue-600 hover:text-blue-800 hover:underline dark:text-blue-400 dark:hover:text-blue-300 truncate block\"\n title={value}\n onClick={(e) => e.stopPropagation()}\n >\n {truncateStr(value, 50)}\n </a>\n ) : (\n <span className=\"text-muted-foreground\">\\u2014</span>\n )}\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n default:\n cellDef = `cell: ({ row }) => {\n const value = row.original.${column.accessorKey}\n return (\n <div className=\"flex items-center gap-4 h-full group\">\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n <Link\n href={\\`${linkBase}/\\${row.original.id}/edit\\`}\n className=\"dark:hover:text-blue-500 hover:text-blue-600 transition-colors flex items-center gap-2 h-full w-full max-w-[300px] py-3\"\n >\n <span className=\"truncate\">\n {value === null || value === undefined ? 'Unavailable' : String(value)}\n </span>\n <Edit\n className=\"size-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0\"\n strokeWidth={2}\n />\n </Link>\n </div>\n )\n }`\n break\n }\n\n return ` {\n id: 'select',\n accessorKey: '${column.accessorKey}',\n ${headerDef},\n ${cellDef},\n enableSorting: ${sortable ? 'true' : 'false'},\n enableHiding: false\n }`\n}\n","/**\n * Template strings for inline column action components:\n * DeleteAction, ReorderButtons, and truncateStr helper\n */\n\n// ============================================================================\n// Delete Action Component Template\n// ============================================================================\n\nexport function generateDeleteActionTemplate(params: {\n Singular: string\n singular: string\n plural: string\n}): string {\n const { Singular, singular, plural } = params\n\n return `\nfunction DeleteAction({ id }: { id: number }) {\n const [open, setOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n const handleDelete = () => {\n startTransition(async () => {\n try {\n const result = await delete${Singular}(id)\n\n if (result.success) {\n toast.success('${Singular} deleted successfully')\n queryClient.refetchQueries({ queryKey: ['${plural}'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete ${singular}')\n }\n } catch (error) {\n toast.error('An error occurred')\n console.error(error)\n }\n })\n }\n\n return (\n <AlertDialog open={open} onOpenChange={setOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" className=\"size-8\" aria-label={\\`Delete ${singular} \\${id}\\`}>\n <Trash className=\"size-3\" strokeWidth={2} />\n <span className=\"sr-only\">Delete ${singular}</span>\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete this ${singular}.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n handleDelete()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n`\n}\n\n// ============================================================================\n// Reorder Buttons Component Template\n// ============================================================================\n\nexport function generateReorderButtonsTemplate(): string {\n return `\nfunction ReorderButtons({\n id,\n isFirst,\n isLast,\n onMoveRow\n}: {\n id: number\n isFirst: boolean\n isLast: boolean\n onMoveRow?: (id: number, direction: 'up' | 'down') => void\n}) {\n if (!onMoveRow) return null\n\n return (\n <div className=\"flex items-center gap-0.5\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => onMoveRow(id, 'up')}\n disabled={isFirst}\n aria-label=\"Move up\"\n className=\"size-7\"\n >\n <ChevronUp className=\"size-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => onMoveRow(id, 'down')}\n disabled={isLast}\n aria-label=\"Move down\"\n className=\"size-7\"\n >\n <ChevronDown className=\"size-4\" />\n </Button>\n </div>\n )\n}\n`\n}\n\n// ============================================================================\n// Truncate Helper Template\n// ============================================================================\n\nexport function generateTruncateHelper(): string {\n return `\nfunction truncateStr(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str\n return str.slice(0, maxLength) + '...'\n}\n`\n}\n","/**\n * Custom cell component generator — creates stub cell components for custom column types\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../../types.js'\nimport { toPascalCase, singularize } from '../../utils/string.js'\n\nexport function createCustomCellComponent(\n schema: Schema,\n componentName: string,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions\n): void {\n const cellsDir = path.join(cwd, pagesDir, schema.name, 'cells')\n const componentFilePath = path.join(cellsDir, `${componentName}.tsx`)\n\n if (fs.existsSync(componentFilePath) && !options.force) return\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n\n const content = `import type { ${Singular}Data } from '@cms/actions/${schema.name}'\n\ninterface ${componentName}Props {\n data: ${Singular}Data\n}\n\nexport function ${componentName}({ data }: ${componentName}Props) {\n return (\n <div>\n {JSON.stringify(data)}\n </div>\n )\n}\n`\n\n if (!fs.existsSync(cellsDir)) {\n fs.mkdirSync(cellsDir, { recursive: true })\n }\n fs.writeFileSync(componentFilePath, content, 'utf-8')\n}\n","/**\n * Generator 9: Create page — (authenticated)/<n>/new/page.tsx\n * Generates server page component for creating a new entity\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize, singularizeLabel, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface CreatePageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate create page component for adding a new entity\n */\nexport function generateCreatePage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): CreatePageGeneratorResult {\n const newDir = path.join(cwd, pagesDir, schema.name, 'new')\n const pageFilePath = path.join(newDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const singLabel = singularizeLabel(schema.label)\n const kebabName = toKebabCase(schema.name)\n\n const content = `import { ChevronLeft } from 'lucide-react'\nimport Link from 'next/link'\nimport { connection } from 'next/server'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { ${Singular}Form } from '../${kebabName}-form'\n\nexport default async function Create${Singular}Page() {\n await connection()\n\n return (\n <>\n <PageHeader title=\"Create ${singLabel}\" back={<Button variant=\"ghost\" size=\"icon\" asChild><Link href=\"/cms/${schema.name}\"><ChevronLeft /></Link></Button>} />\n <main className=\"container mx-auto max-w-5xl p-6 pb-20\">\n <${Singular}Form key={Date.now()} />\n </main>\n </>\n )\n}\n`\n\n if (!fs.existsSync(newDir)) {\n fs.mkdirSync(newDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'new', 'page.tsx')]\n }\n}\n","/**\n * Generator 1: Database schema — append table to cms/db/schema.ts\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, getManyToManyFields } from '../core/field-helpers/index.js'\nimport { toDrizzleType } from '../core/type-mappers/index.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize } from '../utils/string.js'\n\n// ============================================================================\n// Field Modifiers\n// ============================================================================\n\nfunction getFieldModifiers(field: SchemaField, needsSql: { value: boolean }): string {\n const modifiers: string[] = []\n\n if (field.primaryKey) {\n modifiers.push('.primaryKey()')\n }\n\n const isDateField = field.type === 'date' || field.type === 'timestamp'\n const hasValidDefault =\n field.default !== undefined && field.default !== null && !(isDateField && field.default === '')\n\n if (hasValidDefault) {\n if (typeof field.default === 'string') {\n modifiers.push(`.default('${field.default}')`)\n } else {\n modifiers.push(`.default(${field.default})`)\n }\n }\n\n if (field.name === 'createdAt' || field.name === 'updatedAt') {\n modifiers.push('.default(sql`CURRENT_TIMESTAMP`)')\n needsSql.value = true\n }\n\n if (field.required || field.primaryKey) {\n modifiers.push('.notNull()')\n }\n\n return modifiers.join('')\n}\n\n// ============================================================================\n// Table Generation\n// ============================================================================\n\nfunction generateTableDefinition(\n schema: Schema,\n requiredImports: Set<string>,\n needsSql: { value: boolean }\n): string {\n const tableName = toPascalCase(schema.name)\n const variableName = toCamelCase(schema.name)\n\n requiredImports.add('pgTable')\n\n // Flatten fields, exclude M2M relationships (handled via junction tables)\n const dbFields = flattenFields(schema.fields).filter(\n (f) => !(f.type === 'relationship' && f.multiple === true)\n )\n\n const hasDraftMode = schema.actions?.draft === true\n const hasPublishedField = dbFields.some((f) => f.name === 'published')\n\n const fieldDefs = dbFields\n .map((field) => {\n const drizzleType = toDrizzleType(field, requiredImports)\n const modifiers = getFieldModifiers(field, needsSql)\n const line = ` ${field.name}: ${drizzleType}${modifiers}`\n\n if ((field.type === 'richtext' || field.type === 'markdown') && field.output === 'html') {\n const snakeName = field.name.replace(/([A-Z])/g, '_$1').toLowerCase()\n requiredImports.add('text')\n return `${line},\\n ${field.name}Html: text('${snakeName}_html')`\n }\n\n return line\n })\n .join(',\\n')\n\n // Auto-add published field for draft mode\n let publishedField = ''\n if (hasDraftMode && !hasPublishedField) {\n requiredImports.add('boolean')\n publishedField = `,\\n published: boolean().notNull().default(false)`\n }\n\n // Auto-add timestamps\n const hasCreatedAt = dbFields.some((f) => f.name === 'createdAt')\n const hasUpdatedAt = dbFields.some((f) => f.name === 'updatedAt')\n let timestampFields = ''\n if (!hasCreatedAt || !hasUpdatedAt) {\n requiredImports.add('timestamp')\n needsSql.value = true\n }\n if (!hasCreatedAt) {\n timestampFields += `,\\n createdAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull()`\n }\n if (!hasUpdatedAt) {\n timestampFields += `,\\n updatedAt: timestamp({ precision: 3, mode: 'string' }).default(sql\\`CURRENT_TIMESTAMP\\`).notNull()`\n }\n\n // Auto-add sortOrder for drag-and-drop reordering (skip for single schemas)\n const isSingle = schema.type === 'single'\n const hasSortOrder = dbFields.some((f) => f.name === 'sortOrder')\n let sortOrderField = ''\n if (!isSingle && !hasSortOrder) {\n requiredImports.add('integer')\n sortOrderField = `,\\n sortOrder: integer().notNull().default(0)`\n }\n\n return `\\nexport const ${variableName} = pgTable(\\n '${tableName}',\\n {\\n${fieldDefs}${publishedField}${timestampFields}${sortOrderField}\\n }\\n)\\n`\n}\n\nfunction generateJunctionTable(\n schemaName: string,\n field: SchemaField,\n requiredImports: Set<string>\n): string {\n const singularSchema = singularize(schemaName)\n const singularRelation = singularize(field.relationship || '')\n const junctionName = `${singularSchema}${toPascalCase(field.relationship || '')}`\n const junctionPascal = toPascalCase(junctionName)\n const schemaIdCol = `${singularSchema}Id`\n const relationIdCol = `${singularRelation}Id`\n const schemaTableRef = toCamelCase(schemaName)\n const relationTableRef = toCamelCase(field.relationship || '')\n\n requiredImports.add('pgTable')\n requiredImports.add('integer')\n requiredImports.add('primaryKey')\n\n return `\\nexport const ${toCamelCase(junctionName)} = pgTable(\\n '${junctionPascal}',\\n {\\n ${schemaIdCol}: integer().notNull().references(() => ${schemaTableRef}.id, { onDelete: 'cascade' }),\\n ${relationIdCol}: integer().notNull().references(() => ${relationTableRef}.id, { onDelete: 'cascade' })\\n },\\n (table) => [primaryKey({ columns: [table.${schemaIdCol}, table.${relationIdCol}] })]\\n)\\n`\n}\n\n// ============================================================================\n// Import Merging\n// ============================================================================\n\nfunction mergeImports(content: string, requiredImports: Set<string>, needsSql: boolean): string {\n const pgCoreMatch = content.match(/import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/)\n\n // Use regex to detect sql import — handles single/double quotes, extra whitespace, semicolons\n const drizzleOrmMatch = content.match(/import\\s*\\{([^}]*)\\}\\s*from\\s*['\"]drizzle-orm['\"]/)\n const existingDrizzleOrmImports = new Set<string>()\n if (drizzleOrmMatch) {\n drizzleOrmMatch[1]\n .split(',')\n .map((i) => i.trim())\n .filter(Boolean)\n .forEach((i) => {\n existingDrizzleOrmImports.add(i)\n })\n }\n const hasSqlImport = existingDrizzleOrmImports.has('sql')\n\n // Collect existing pg-core imports\n const existing = new Set<string>()\n if (pgCoreMatch) {\n pgCoreMatch[1]\n .split(',')\n .map((i) => i.trim())\n .filter(Boolean)\n .forEach((i) => {\n existing.add(i)\n })\n }\n\n const merged = new Set([...existing, ...requiredImports])\n const sorted = Array.from(merged).sort()\n const newImport = `import {\\n ${sorted.join(',\\n ')}\\n} from 'drizzle-orm/pg-core'`\n\n let updated = content\n\n if (pgCoreMatch) {\n updated = updated.replace(/import\\s+\\{[^}]+\\}\\s+from\\s+['\"]drizzle-orm\\/pg-core['\"]/, newImport)\n } else if (drizzleOrmMatch) {\n updated = updated.replace(\n /import\\s*\\{[^}]*\\}\\s*from\\s*['\"]drizzle-orm['\"]/,\n (match) => `${match}\\n${newImport}`\n )\n } else {\n updated = `${newImport}\\n${updated}`\n }\n\n if (needsSql && !hasSqlImport) {\n if (drizzleOrmMatch) {\n // Add sql to existing drizzle-orm import\n existingDrizzleOrmImports.add('sql')\n const sortedOrm = Array.from(existingDrizzleOrmImports).sort()\n updated = updated.replace(\n /import\\s*\\{[^}]*\\}\\s*from\\s*['\"]drizzle-orm['\"]/,\n `import { ${sortedOrm.join(', ')} } from 'drizzle-orm'`\n )\n } else {\n updated = `import { sql } from 'drizzle-orm'\\n${updated}`\n }\n }\n\n return updated\n}\n\n// ============================================================================\n// Table End Finder (for --force replacement)\n// ============================================================================\n\nfunction findTableEnd(content: string, startIndex: number): number {\n let depth = 0\n let inString = false\n let stringChar = ''\n\n for (let i = startIndex; i < content.length; i++) {\n const char = content[i]\n const prev = i > 0 ? content[i - 1] : ''\n\n if ((char === '\"' || char === \"'\" || char === '`') && prev !== '\\\\') {\n if (!inString) {\n inString = true\n stringChar = char\n } else if (char === stringChar) {\n inString = false\n }\n continue\n }\n if (inString) continue\n\n if (char === '(' || char === '{' || char === '[') depth++\n if (char === ')' || char === '}' || char === ']') depth--\n\n if (depth === 0 && char === ')') {\n return i + 1\n }\n }\n\n return content.length\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface DatabaseGeneratorResult {\n files: string[]\n tableName: string\n junctionTables: string[]\n}\n\n/**\n * Generate database schema for an entity — appends to cms/db/schema.ts\n */\nexport function generateDatabase(\n schema: Schema,\n cwd: string,\n schemaDir: string,\n options: GeneratorOptions = {}\n): DatabaseGeneratorResult {\n const schemaFilePath = path.join(cwd, schemaDir)\n const files: string[] = []\n\n // Read existing schema.ts\n let content = ''\n if (fs.existsSync(schemaFilePath)) {\n content = fs.readFileSync(schemaFilePath, 'utf-8')\n }\n\n const variableName = toCamelCase(schema.name)\n\n // Check for existing table\n if (content.includes(`export const ${variableName} =`) && !options.force) {\n return {\n files: [],\n tableName: variableName,\n junctionTables: []\n }\n }\n\n const requiredImports = new Set<string>()\n const needsSql = { value: false }\n\n // Generate main table\n const tableDef = generateTableDefinition(schema, requiredImports, needsSql)\n\n // Generate junction tables for M2M\n const m2mFields = getManyToManyFields(schema.fields)\n const junctionDefs = m2mFields.map((f) => generateJunctionTable(schema.name, f, requiredImports))\n const junctionNames = m2mFields.map((f) => {\n const s = singularize(schema.name)\n return toCamelCase(`${s}${toPascalCase(f.relationship || '')}`)\n })\n\n let updated = content\n\n if (options.force && content.includes(`export const ${variableName} =`)) {\n // Replace existing table definition\n const start = content.indexOf(`export const ${variableName} =`)\n const end = findTableEnd(content, start)\n updated = content.slice(0, start) + tableDef.trim() + content.slice(end)\n } else {\n // Append new table\n updated = `${updated.trimEnd()}\\n${tableDef}`\n }\n\n // Handle junction tables\n for (let i = 0; i < m2mFields.length; i++) {\n const jName = junctionNames[i]\n if (options.force && updated.includes(`export const ${jName} =`)) {\n const start = updated.indexOf(`export const ${jName} =`)\n const end = findTableEnd(updated, start)\n updated = updated.slice(0, start) + junctionDefs[i].trim() + updated.slice(end)\n } else if (!updated.includes(`export const ${jName} =`)) {\n updated = `${updated.trimEnd()}\\n${junctionDefs[i]}`\n }\n }\n\n // Merge imports\n updated = mergeImports(updated, requiredImports, needsSql.value)\n\n // Write\n const dir = path.dirname(schemaFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(schemaFilePath, updated, 'utf-8')\n files.push(schemaDir)\n\n return {\n files,\n tableName: variableName,\n junctionTables: junctionNames\n }\n}\n","/**\n * Generator 10: Edit page — (authenticated)/<n>/[id]/edit/page.tsx\n * Generates server page component for editing an existing entity\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface EditPageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate edit page component for updating an existing entity\n */\nexport function generateEditPage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): EditPageGeneratorResult {\n const editDir = path.join(cwd, pagesDir, schema.name, '[id]', 'edit')\n const pageFilePath = path.join(editDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const camelSingular = toCamelCase(singular)\n const kebabName = toKebabCase(schema.name)\n\n const content = `import { ChevronLeft } from 'lucide-react'\nimport Link from 'next/link'\nimport { notFound } from 'next/navigation'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { get${Singular}ById } from '@cms/actions/${schema.name}'\nimport { ${Singular}Form } from '../../${kebabName}-form'\n\ninterface PageProps {\n params: Promise<{\n id: string\n }>\n}\n\nexport default async function Edit${Singular}Page({ params }: PageProps) {\n const { id } = await params\n const ${camelSingular} = await get${Singular}ById(Number.parseInt(id, 10))\n\n if (!${camelSingular}) {\n notFound()\n }\n\n return (\n <>\n <PageHeader title=\"Edit ${Singular}\" back={<Button variant=\"ghost\" size=\"icon\" asChild><Link href=\"/cms/${schema.name}\"><ChevronLeft /></Link></Button>} />\n <main className=\"container mx-auto max-w-5xl p-6 pb-20\">\n <${Singular}Form key={${camelSingular}.id} initialData={${camelSingular}} />\n </main>\n </>\n )\n}\n`\n\n if (!fs.existsSync(editDir)) {\n fs.mkdirSync(editDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, '[id]', 'edit', 'page.tsx')]\n }\n}\n","/**\n * Entity form generator — create/edit form with Zod validation, React Hook Form, and mutations\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, hasFieldType, hasIconUsage } from '../../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport { generateFieldJSX } from './field-jsx.js'\nimport {\n type FormGeneratorResult,\n collectRelationshipFields,\n buildZodFields,\n buildDefaultValues,\n buildUiImports\n} from './form-shared.js'\n\nexport function generateForm(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): FormGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const formFilePath = path.join(entityDir, `${schema.name}-form.tsx`)\n\n if (fs.existsSync(formFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n\n // Analyze fields\n const allFormFields = schema.fields.filter(\n (f) => !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt'\n )\n const flatFields = flattenFields(allFormFields)\n const hasDraft = schema.actions?.draft === true\n\n // Collect tab field names\n const tabFieldNames = new Set<string>()\n for (const f of schema.fields) {\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) for (const tf of tab.fields) tabFieldNames.add(tf.name)\n }\n }\n }\n\n // Check what components are needed\n const hasBoolean = hasFieldType(schema.fields, 'boolean')\n const hasImage = hasFieldType(schema.fields, 'image')\n const hasVideo = hasFieldType(schema.fields, 'video')\n const hasMedia = hasFieldType(schema.fields, 'media')\n const hasIcon = hasFieldType(schema.fields, 'icon')\n const hasIconPostfix = hasIconUsage(schema.fields)\n const hasDate = hasFieldType(schema.fields, 'date')\n const hasSelect = hasFieldType(schema.fields, 'select')\n const hasMarkdown = hasFieldType(schema.fields, 'markdown')\n const hasRichtext = hasFieldType(schema.fields, 'richtext')\n const hasTextarea = hasFieldType(schema.fields, 'text')\n const hasSeparator = hasFieldType(schema.fields, 'separator')\n const hasRelationship = hasFieldType(schema.fields, 'relationship')\n const hasTabsField = schema.fields.some((f) => f.type === 'tabs')\n const tabsField = schema.fields.find((f) => f.type === 'tabs')\n const firstTabName = tabsField?.tabs?.[0]?.name || ''\n\n const mainRelFields = collectRelationshipFields(schema.fields, tabFieldNames)\n\n // Collect list fields with nested fields (need useFieldArray hooks)\n const listFieldsWithNested: SchemaField[] = []\n function collectListFields(fields: SchemaField[]): void {\n for (const f of fields) {\n if (f.type === 'list' && f.fields && f.fields.length > 0 && !f.hidden) {\n listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFields(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collectListFields(tab.fields)\n }\n }\n }\n }\n collectListFields(allFormFields)\n const hasList = hasFieldType(schema.fields, 'list')\n const hasNestedList = listFieldsWithNested.length > 0\n // Simple list uses DynamicListField; nested list uses useFieldArray + Accordion\n const hasSimpleList =\n hasList && flatFields.some((f) => f.type === 'list' && (!f.fields || f.fields.length === 0))\n\n // Build Zod schema\n const zodFields = buildZodFields(flatFields)\n\n // Build default values\n const defaultValues = buildDefaultValues(flatFields)\n\n // Build form fields JSX\n const formFieldsJSX = allFormFields\n .filter((f) => !(hasDraft && f.name === 'published'))\n .map((f) => {\n if (f.type === 'tabs' && f.tabs) {\n const tabsList = f.tabs\n .map((t) => ` <TabsTrigger value=\"${t.name}\">${t.label}</TabsTrigger>`)\n .join('\\n')\n const tabsContent = f.tabs\n .map((t) => {\n const tabFields = (t.fields || [])\n .map((tf) => generateFieldJSX(tf, ' '))\n .join('\\n')\n return ` <TabsContent value=\"${t.name}\" className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${tabFields}\n </TabsContent>`\n })\n .join('\\n')\n return ` <Tabs value={activeTab} onValueChange={setActiveTab} className=\"w-full\">\n <TabsList>\n${tabsList}\n </TabsList>\n${tabsContent}\n </Tabs>`\n }\n if (tabFieldNames.has(f.name)) return ''\n return generateFieldJSX(f)\n })\n .filter(Boolean)\n .join('\\n')\n\n // --- Build imports ---\n const uiImports = buildUiImports({\n hasBoolean,\n hasTextarea,\n hasImage,\n hasVideo,\n hasMedia,\n hasIcon,\n hasIconPostfix,\n hasDate,\n hasMarkdown,\n hasRichtext,\n hasSeparator,\n hasSelect,\n hasTabsField,\n hasRelationship,\n hasSimpleList,\n hasNestedList\n })\n\n // Lucide icons\n const lucideIcons: string[] = []\n if (hasRelationship) lucideIcons.push('Check', 'ChevronsUpDown')\n if (hasNestedList) {\n if (!lucideIcons.includes('Plus')) lucideIcons.push('Plus')\n if (!lucideIcons.includes('X')) lucideIcons.push('X')\n }\n\n // Relationship hooks\n const relHookImports = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return `import { use${relPlural} } from '@cms/hooks/use-${f.relationship}'`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // Relationship state\n const relState = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return ` const [${f.name}Open, set${toPascalCase(f.name)}Open] = React.useState(false)\n const { data: ${f.relationship}Data } = use${relPlural}()`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // List field array hooks\n const fieldArrayHooks = listFieldsWithNested\n .map((field) => {\n const pascalFieldName = toPascalCase(field.name)\n return ` const [${field.name}Expanded, set${pascalFieldName}Expanded] = React.useState<string | undefined>(undefined)\n const ${field.name}FieldArray = useFieldArray({\n control: form.control,\n name: '${field.name}'\n })`\n })\n .join('\\n')\n\n const needsReact = mainRelFields.length > 0 || hasNestedList\n\n // --- Assemble file ---\n const content = `'use client'\n${needsReact ? \"\\nimport * as React from 'react'\" : ''}\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'${lucideIcons.length > 0 ? `\\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'` : ''}\nimport { useRouter } from 'next/navigation'\nimport {${hasNestedList ? ' useFieldArray,' : ''} useForm } from 'react-hook-form'\nimport { toast } from 'sonner'\nimport { z } from 'zod/v3'${hasTabsField ? \"\\nimport { useQueryState } from 'nuqs'\" : ''}${hasRelationship ? \"\\nimport { cn } from '@cms/utils/cn'\" : ''}\n${relHookImports ? `${relHookImports}\\n` : ''}${uiImports.join('\\n')}\nimport type {\n Create${Singular}Input,\n ${Singular}Data,\n Update${Singular}Input\n} from '@cms/actions/${schema.name}'\nimport { create${Singular}, update${Singular} } from '@cms/actions/${schema.name}'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\nexport type FormValues = z.infer<typeof formSchema>\n\ninterface ${Singular}FormProps {\n initialData?: ${Singular}Data\n}\n\nexport function ${Singular}Form({ initialData }: ${Singular}FormProps) {\n const router = useRouter()\n const queryClient = useQueryClient()${hasTabsField ? `\\n const [activeTab, setActiveTab] = useQueryState('tab', { defaultValue: '${firstTabName}' })` : ''}${relState ? `\\n${relState}` : ''}\n\n const createMutation = useMutation({\n mutationFn: (data: Create${Singular}Input) => create${Singular}(data),\n onSuccess: async () => {\n toast.success('${Singular} created successfully')\n await queryClient.invalidateQueries({ queryKey: ['${plural}'] })\n router.push('/cms/${schema.name}')\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to create ${singular}')\n }\n })\n\n const updateMutation = useMutation({\n mutationFn: (data: Update${Singular}Input) => update${Singular}(data),\n onSuccess: () => {\n toast.success('${Singular} updated successfully')\n queryClient.invalidateQueries({ queryKey: ['${plural}'] })\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to update ${singular}')\n }\n })\n\n const isPending = createMutation.isPending || updateMutation.isPending\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n${defaultValues}\n }\n })\n${fieldArrayHooks ? `\\n${fieldArrayHooks}\\n` : ''}\n function onSubmit(values: FormValues${hasDraft ? ', publishedValue: boolean = false' : ''}) {\n const cleanedValues = Object.fromEntries(\n Object.entries(values).map(([key, value]) => [key, value === undefined ? '' : value])\n ) as FormValues\n\n if (initialData) {\n updateMutation.mutate({\n id: initialData.id as number,\n ...cleanedValues${hasDraft ? ',\\n published: publishedValue' : ''}\n })\n } else {\n const { id: _id, ...createValues } = cleanedValues\n createMutation.mutate({\n ...createValues${hasDraft ? ',\\n published: publishedValue' : ''}\n } as Create${Singular}Input)\n }\n }\n\n return (\n <Form {...form}>\n <form id=\"${schema.name}-form\" onSubmit={form.handleSubmit((values) => onSubmit(values${hasDraft ? ', false' : ''}), (errors) => {\n console.error('Form validation errors:', errors)\n const firstError = Object.values(errors)[0]\n if (firstError?.message) {\n toast.error(String(firstError.message))\n } else {\n toast.error('Please fix the form errors before submitting')\n }\n })} className=\"space-y-6\">\n <div className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${formFieldsJSX}\n </div>\n\n <div className=\"flex items-center fixed bottom-0 md:left-[calc(var(--sidebar-width))] w-screen md:w-[calc(100svw-var(--sidebar-width)-4px)] right-0 bg-secondary border-t\">\n <div className=\"flex mx-auto py-4 w-full max-w-5xl items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push('/cms/${schema.name}')}\n disabled={isPending}\n size=\"lg\"\n >\n Cancel\n </Button>\n${\n hasDraft\n ? ` <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => form.handleSubmit((values) => onSubmit(values, false))()}\n disabled={isPending}\n size=\"lg\"\n >\n {isPending ? 'Saving...' : 'Save as Draft'}\n </Button>\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={() => form.handleSubmit((values) => onSubmit(values, true))()}\n disabled={isPending}\n size=\"lg\"\n >\n {isPending ? 'Publishing...' : initialData ? 'Update & Publish' : 'Publish'}\n </Button>`\n : ` <Button type=\"submit\" disabled={isPending} size=\"lg\">\n {isPending ? 'Saving...' : initialData ? 'Update' : 'Create'}\n </Button>`\n}\n </div>\n </div>\n </form>\n </Form>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(formFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]\n }\n}\n","/**\n * Zod schema generation helpers for entity/single forms\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\n\nexport function getFormFieldType(field: SchemaField): string {\n switch (field.type) {\n case 'boolean':\n return 'checkbox'\n case 'text':\n return 'textarea'\n case 'markdown':\n return 'markdown'\n case 'richtext':\n return 'richtext'\n case 'number':\n case 'decimal':\n return 'number'\n case 'date':\n return 'date'\n case 'time':\n return 'time'\n case 'timestamp':\n return 'datetime-local'\n default:\n return 'text'\n }\n}\n\nexport function getZodType(field: SchemaField): string {\n const label = field.label || field.name\n\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return field.required\n ? `z.number({ message: '${label} is required' })`\n : 'z.number().optional()'\n case 'boolean':\n return 'z.boolean()'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext': {\n if (field.name.toLowerCase().includes('email')) {\n const base = field.required\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().email('Please enter a valid email address').optional()`\n return field.length ? `${base}.max(${field.length})` : base\n }\n const base = field.required ? `z.string().min(1, '${label} is required')` : 'z.string()'\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'date':\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n return `z.string().min(1, '${label} is required')`\n case 'timestamp':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'image':\n case 'video':\n case 'media': {\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n const base = `z.string().min(1, 'Please upload ${label.toLowerCase()}').url('Please provide a valid URL')`\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nested = field.fields\n .flatMap((nf) => {\n const defs: string[] = []\n const zodType = getZodType(nf)\n const alreadyOptional = zodType.includes('.optional()')\n let def = ` ${quotePropertyName(nf.name)}: ${zodType}`\n if (!nf.required && !alreadyOptional) def += '.optional()'\n defs.push(def)\n if (nf.hasIcon)\n defs.push(` ${quotePropertyName(`${nf.name}Icon`)}: z.string().optional()`)\n return defs\n })\n .join(',\\n')\n const obj = `z.object({\\n${nested}\\n })`\n const arr = field.maxItems ? `z.array(${obj}).max(${field.maxItems})` : `z.array(${obj})`\n return field.required\n ? `${arr}.min(1, '${label} must have at least one item')`\n : `${arr}.optional()`\n }\n return field.required\n ? `z.array(z.string()).min(1, '${label} must have at least one item')`\n : 'z.array(z.string()).optional()'\n case 'select': {\n if (field.options && field.options.length > 0) {\n const values = field.options.map((o) => `'${o.value}'`).join(', ')\n const arr = `[${values}] as const`\n return field.required\n ? `z.string().min(1, '${label} is required').refine((val) => (${arr} as readonly string[]).includes(val), { message: 'Invalid ${label}' })`\n : `z.string().refine((val) => !val || (${arr} as readonly string[]).includes(val), { message: 'Invalid ${label}' }).optional()`\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'icon':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'relationship':\n if (field.multiple) {\n return field.required\n ? `z.array(z.number()).min(1, '${label} is required')`\n : 'z.array(z.number()).optional()'\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'group':\n if (field.fields && field.fields.length > 0) {\n const nested = field.fields\n .map((nf) => {\n const zodType = getZodType(nf)\n const alreadyOptional = zodType.includes('.optional()')\n let def = ` ${quotePropertyName(nf.name)}: ${zodType}`\n if (!nf.required && !alreadyOptional) def += '.optional()'\n return def\n })\n .join(',\\n')\n return field.required\n ? `z.object({\\n${nested}\\n })`\n : `z.object({\\n${nested}\\n }).optional()`\n }\n return 'z.record(z.unknown()).optional()'\n default:\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n","/**\n * List/nested-list JSX generation for form fields\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { toPascalCase, singularize } from '../../utils/string.js'\n\nexport function renderListField(field: SchemaField, indent: string, label: string): string {\n const listHintJSX = field.hint\n ? `${indent} <p className=\"text-[0.8rem] text-muted-foreground\">${field.hint}</p>`\n : ''\n\n // Simple string list — use DynamicListField\n if (!field.fields || field.fields.length === 0) {\n return `${indent}<DynamicListField\n${indent} name=\"${field.name}\"\n${indent} label=\"${label}\"\n${indent} disabled={isPending}${field.maxItems ? `\\n${indent} maxItems={${field.maxItems}}` : ''}\n${indent} placeholder=\"Enter value\"\n${indent}/>`\n }\n\n // Nested fields list — useFieldArray + Accordion\n const singularLabel = singularize(label)\n const pascalFieldName = toPascalCase(field.name)\n\n // Find title field for accordion header\n const stringTypes = ['string', 'varchar', 'text']\n const titleField =\n field.fields.find((f) => f.name === 'title' && stringTypes.includes(f.type)) ||\n field.fields.find((f) => f.name === 'name' && stringTypes.includes(f.type)) ||\n field.fields.find((f) => stringTypes.includes(f.type))\n const accordionTitle = titleField\n ? `{form.watch(\\`${field.name}.\\${index}.${titleField.name}\\`) || '${singularLabel} ' + (index + 1)}`\n : `${singularLabel} {index + 1}`\n\n // Generate nested field JSX\n const nestedFieldsJSX = field.fields\n .map((nf) => {\n const nestedLabel = nf.label || nf.name\n const nestedHint = nf.hint\n ? `\\n${indent} <FormDescription>${nf.hint}</FormDescription>`\n : ''\n if (nf.type === 'boolean') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-row items-start space-x-3 space-y-0\">\n${indent} <FormControl>\n${indent} <Checkbox checked={formField.value} onCheckedChange={formField.onChange} disabled={isPending} />\n${indent} </FormControl>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n if (nf.type === 'image') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <ImageUploadField value={formField.value} onChange={formField.onChange} onBlur={formField.onBlur} disabled={isPending} maxSizeInMB={10} label=\"\" />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n if (nf.type === 'video') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <VideoUploadField value={formField.value} onChange={formField.onChange} onBlur={formField.onBlur} disabled={isPending} maxSizeInMB={100} label=\"\" />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n if (nf.type === 'media') {\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <MediaUploadField value={formField.value} onChange={formField.onChange} onBlur={formField.onBlur} disabled={isPending} maxSizeInMB={100} label=\"\" />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n }\n // Default: text input for nested fields\n return `${indent} <FormField\n${indent} control={form.control}\n${indent} name={\\`${field.name}.\\${index}.${nf.name}\\`}\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${nestedLabel}</FormLabel>\n${indent} <FormControl>\n${indent} <Input placeholder=\"Enter ${nestedLabel.toLowerCase()}\" disabled={isPending} {...formField} />\n${indent} </FormControl>${nestedHint}\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent} />`\n })\n .join('\\n')\n\n return `${indent}<FormItem>\n${indent} {${field.name}FieldArray.fields.length === 0 && (\n${indent} <div className=\"text-sm text-muted-foreground rounded-lg border border-dashed p-6 text-center\">\n${indent} <p>No ${label.toLowerCase()} added yet.</p>\n${indent} <Button\n${indent} type=\"button\"\n${indent} variant=\"outline\"\n${indent} size=\"sm\"\n${indent} className=\"mt-2\"\n${indent} onClick={() => {\n${indent} ${field.name}FieldArray.append({${field.fields.map((nf) => `${nf.name}: ${nf.type === 'boolean' ? 'false' : \"''\"}`).join(', ')}})\n${indent} set${pascalFieldName}Expanded(\\`item-\\${${field.name}FieldArray.fields.length + 1}\\`)\n${indent} }}\n${indent} disabled={isPending}\n${indent} >\n${indent} <Plus className=\"size-3\" />\n${indent} Add ${singularLabel}\n${indent} </Button>\n${indent} </div>\n${indent} )}\n${indent} {${field.name}FieldArray.fields.length > 0 && (\n${indent} <div className=\"space-y-5\">\n${indent} <div className=\"flex items-center justify-between\">\n${indent} <Label className=\"text-base\">${label}</Label>\n${indent} <Button\n${indent} type=\"button\"\n${indent} variant=\"outline\"\n${indent} size=\"sm\"\n${indent} onClick={() => {\n${indent} ${field.name}FieldArray.append({${field.fields.map((nf) => `${nf.name}: ${nf.type === 'boolean' ? 'false' : \"''\"}`).join(', ')}})\n${indent} set${pascalFieldName}Expanded(\\`item-\\${${field.name}FieldArray.fields.length + 1}\\`)\n${indent} }}\n${indent} disabled={isPending${field.maxItems ? ` || ${field.name}FieldArray.fields.length >= ${field.maxItems}` : ''}}\n${indent} >\n${indent} <Plus className=\"size-3\" />\n${indent} Add ${singularLabel}\n${indent} </Button>\n${indent} </div>\n${listHintJSX ? `${listHintJSX}\\n` : ''}${indent} <Accordion\n${indent} type=\"single\"\n${indent} collapsible\n${indent} className=\"w-full gap-1 flex flex-col\"\n${indent} value={${field.name}Expanded}\n${indent} onValueChange={set${pascalFieldName}Expanded}\n${indent} >\n${indent} {${field.name}FieldArray.fields.map((item, index) => (\n${indent} <AccordionItem\n${indent} key={item.id}\n${indent} value={\\`item-\\${index + 1}\\`}\n${indent} className=\"p-0 border-none\"\n${indent} >\n${indent} <div className=\"space-y-5 rounded-lg border p-4 bg-secondary/50 [&_h3]:m-0 w-full\">\n${indent} <AccordionTrigger className=\"flex items-center p-0 justify-between w-full\">\n${indent} <h4 className=\"text-sm font-medium w-full\">\n${indent} ${accordionTitle}\n${indent} </h4>\n${indent} <Button\n${indent} asChild\n${indent} variant=\"ghost\"\n${indent} size=\"sm\"\n${indent} disabled={isPending}\n${indent} >\n${indent} <span\n${indent} role=\"button\"\n${indent} tabIndex={0}\n${indent} onClick={(e) => { e.stopPropagation(); ${field.name}FieldArray.remove(index); }}\n${indent} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); ${field.name}FieldArray.remove(index); } }}\n${indent} className=\"cursor-pointer\"\n${indent} >\n${indent} <X className=\"size-3\" />\n${indent} </span>\n${indent} </Button>\n${indent} </AccordionTrigger>\n${indent} <AccordionContent className=\"flex flex-col gap-4 px-1\">\n${indent} <Separator className=\"mt-2\" />\n${indent} <div className=\"space-y-5\">\n${nestedFieldsJSX}\n${indent} </div>\n${indent} </AccordionContent>\n${indent} </div>\n${indent} </AccordionItem>\n${indent} ))}\n${indent} </Accordion>\n${indent} </div>\n${indent} )}\n${indent}</FormItem>`\n}\n","/**\n * Form field JSX generation — dispatcher + per-type renderers\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport { getFormFieldType } from './zod-schema.js'\nimport { renderListField } from './field-jsx-nested.js'\n\nfunction generateIconPostfix(field: SchemaField, indent: string): string {\n const label = field.label || field.name\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}Icon\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label} Icon</FormLabel>\n${indent} <FormControl>\n${indent} <IconPicker\n${indent} value={formField.value}\n${indent} onValueChange={formField.onChange}\n${indent} triggerPlaceholder=\"Select icon\"\n${indent} />\n${indent} </FormControl>\n${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nexport function generateFieldJSX(field: SchemaField, indent = ' '): string {\n if (field.hidden) return ''\n\n const mainJSX = generateFieldJSXCore(field, indent)\n if (!mainJSX) return ''\n\n if (field.hasIcon) {\n return `${mainJSX}\\n${generateIconPostfix(field, indent)}`\n }\n\n return mainJSX\n}\n\nfunction generateFieldJSXCore(field: SchemaField, indent = ' '): string {\n const fieldType = getFormFieldType(field)\n const label = field.label || field.name\n const hintJSX = field.hint\n ? `${indent} <FormDescription>${field.hint}</FormDescription>`\n : ''\n\n if (field.type === 'group' && field.fields) return renderGroupField(field, indent, label)\n if (field.type === 'separator') return renderSeparatorField(field, indent)\n if (field.type === 'boolean') return renderBooleanField(field, indent, label, hintJSX)\n if (field.type === 'image') return renderImageField(field, indent, label, hintJSX)\n if (field.type === 'video') return renderVideoField(field, indent, label, hintJSX)\n if (field.type === 'media') return renderMediaField(field, indent, label, hintJSX)\n if (field.type === 'icon') return renderIconField(field, indent, label, hintJSX)\n if (field.type === 'date') return renderDateField(field, indent, label, hintJSX)\n if (field.type === 'select') return renderSelectField(field, indent, label, hintJSX)\n if (field.type === 'richtext') return renderRichtextField(field, indent, label, hintJSX)\n if (field.type === 'markdown') return renderMarkdownField(field, indent, label, hintJSX)\n if (field.type === 'text') return renderTextareaField(field, indent, label, hintJSX)\n if (field.type === 'relationship' && field.relationship)\n return renderRelationshipField(field, indent, label, hintJSX)\n if (field.type === 'list') return renderListField(field, indent, label)\n\n return renderDefaultField(field, indent, label, fieldType, hintJSX)\n}\n\nfunction renderGroupField(field: SchemaField, indent: string, label: string): string {\n const columns = field.columns || 1\n const gridClass = columns > 1 ? `grid-cols-${columns}` : 'grid-cols-1'\n const groupFields = field.fields!.map((nf) => generateFieldJSX(nf, `${indent} `)).join('\\n')\n const heading =\n label && label !== field.name\n ? `${indent}<h3 className=\"text-lg font-medium\">${label}</h3>\\n`\n : ''\n return `${indent}<div className=\"space-y-5\">\n${heading}${indent} <div className=\"grid ${gridClass} gap-4\">\n${groupFields}\n${indent} </div>\n${indent}</div>`\n}\n\nfunction renderSeparatorField(field: SchemaField, indent: string): string {\n if (field.label) {\n return `${indent}<div className=\"relative my-4\">\n${indent} <div className=\"absolute inset-0 flex items-center\">\n${indent} <Separator className=\"w-full\" />\n${indent} </div>\n${indent} <div className=\"relative flex justify-center text-xs uppercase\">\n${indent} <span className=\"bg-background px-2 text-muted-foreground\">${field.label}</span>\n${indent} </div>\n${indent}</div>`\n }\n return `${indent}<Separator className=\"my-4\" />`\n}\n\nfunction renderBooleanField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-row items-start space-x-3 space-y-0\">\n${indent} <FormControl>\n${indent} <Checkbox\n${indent} checked={formField.value}\n${indent} onCheckedChange={formField.onChange}\n${indent} disabled={isPending}\n${indent} />\n${indent} </FormControl>\n${indent} <div className=\"space-y-1 leading-none\">\n${indent} <FormLabel>${label}</FormLabel>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} </div>\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderImageField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <ImageUploadField\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} onBlur={formField.onBlur}\n${indent} disabled={isPending}\n${indent} maxSizeInMB={10}\n${indent} label=\"\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderVideoField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <VideoUploadField\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} onBlur={formField.onBlur}\n${indent} disabled={isPending}\n${indent} maxSizeInMB={100}\n${indent} label=\"\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderMediaField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <MediaUploadField\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} onBlur={formField.onBlur}\n${indent} disabled={isPending}\n${indent} maxSizeInMB={100}\n${indent} label=\"\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderIconField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <IconPicker\n${indent} value={formField.value}\n${indent} onValueChange={formField.onChange}\n${indent} triggerPlaceholder=\"Select ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderDateField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <DatePicker\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} disabled={isPending}\n${indent} placeholder=\"Select ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderSelectField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n const options = field.options || []\n const optionsJSX = options\n .map(\n (o) =>\n `${indent} <SelectItem key=\"${o.value}\" value=\"${o.value}\">${o.label}</SelectItem>`\n )\n .join('\\n')\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <Select\n${indent} value={formField.value}\n${indent} onValueChange={formField.onChange}\n${indent} disabled={isPending}\n${indent} >\n${indent} <SelectTrigger>\n${indent} <SelectValue placeholder=\"Select ${label.toLowerCase()}\" />\n${indent} </SelectTrigger>\n${indent} <SelectContent>\n${optionsJSX}\n${indent} </SelectContent>\n${indent} </Select>\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderRichtextField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <RichTextEditor\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} className=\"min-h-[300px]\"\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderMarkdownField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <MarkdownEditor\n${indent} value={formField.value}\n${indent} onChange={formField.onChange}\n${indent} componentSnippets={{}}\n${indent} className=\"min-h-[300px]\"\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderTextareaField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <Textarea\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} className=\"min-h-[100px]\"\n${indent} disabled={isPending}\n${indent} {...formField}\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderRelationshipField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string\n): string {\n const relName = field.relationship!\n const relSingular = singularize(relName)\n const relPascal = toPascalCase(relSingular)\n const displayField = `(('name' in item && item.name) || ('title' in item && item.title) || ('label' in item && item.label) || \\`${relPascal} \\${item.id ?? 'Unknown'}\\`) as string`\n const dataArray = `${relName}Data?.${relName}`\n\n if (field.multiple) {\n return renderMultiRelationshipField(field, indent, label, hintJSX, displayField, dataArray, relSingular)\n }\n\n return renderSingleRelationshipField(field, indent, label, hintJSX, displayField, dataArray, relSingular)\n}\n\nfunction renderMultiRelationshipField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string,\n displayField: string,\n dataArray: string,\n relSingular: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-col\">\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <Popover open={${field.name}Open} onOpenChange={set${toPascalCase(field.name)}Open}>\n${indent} <PopoverTrigger asChild>\n${indent} <FormControl>\n${indent} <Button\n${indent} variant=\"outline\"\n${indent} role=\"combobox\"\n${indent} className={cn(\"w-full justify-between\", (!formField.value || formField.value.length === 0) && \"text-muted-foreground\")}\n${indent} disabled={isPending}\n${indent} >\n${indent} {(formField.value?.length ?? 0) > 0\n${indent} ? \\`\\${formField.value!.length} selected\\`\n${indent} : \"Select ${label.toLowerCase()}\"}\n${indent} <ChevronsUpDown className=\"ml-2 size-4 shrink-0 opacity-50\" />\n${indent} </Button>\n${indent} </FormControl>\n${indent} </PopoverTrigger>\n${indent} <PopoverContent className=\"w-full p-0\" align=\"start\">\n${indent} <Command>\n${indent} <CommandInput placeholder=\"Search ${label.toLowerCase()}...\" />\n${indent} <CommandList>\n${indent} <CommandEmpty>No ${relSingular} found.</CommandEmpty>\n${indent} <CommandGroup>\n${indent} {${dataArray}?.filter((item) => item.id !== null).map((item) => {\n${indent} const displayName = ${displayField}\n${indent} const isSelected = formField.value?.includes(item.id as number) || false\n${indent} return (\n${indent} <CommandItem\n${indent} key={item.id}\n${indent} value={displayName}\n${indent} onSelect={() => {\n${indent} const current = formField.value || []\n${indent} formField.onChange(isSelected\n${indent} ? current.filter((id: number) => id !== item.id)\n${indent} : [...current, item.id as number])\n${indent} }}\n${indent} >\n${indent} <Check className={cn(\"mr-2 size-4\", isSelected ? \"opacity-100\" : \"opacity-0\")} />\n${indent} {displayName}\n${indent} </CommandItem>\n${indent} )\n${indent} })}\n${indent} </CommandGroup>\n${indent} </CommandList>\n${indent} </Command>\n${indent} </PopoverContent>\n${indent} </Popover>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderSingleRelationshipField(\n field: SchemaField,\n indent: string,\n label: string,\n hintJSX: string,\n displayField: string,\n dataArray: string,\n relSingular: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem className=\"flex flex-col\">\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <Popover open={${field.name}Open} onOpenChange={set${toPascalCase(field.name)}Open}>\n${indent} <PopoverTrigger asChild>\n${indent} <FormControl>\n${indent} <Button\n${indent} variant=\"outline\"\n${indent} role=\"combobox\"\n${indent} className={cn(\"w-full justify-between\", !formField.value && \"text-muted-foreground\")}\n${indent} disabled={isPending}\n${indent} >\n${indent} {formField.value\n${indent} ? (() => {\n${indent} const item = ${dataArray}?.find((item) => item.id !== null && String(item.id) === formField.value)\n${indent} return item ? (${displayField}) : \"Select ${label.toLowerCase()}\"\n${indent} })()\n${indent} : \"Select ${label.toLowerCase()}\"}\n${indent} <ChevronsUpDown className=\"ml-2 size-4 shrink-0 opacity-50\" />\n${indent} </Button>\n${indent} </FormControl>\n${indent} </PopoverTrigger>\n${indent} <PopoverContent className=\"w-full p-0\" align=\"start\">\n${indent} <Command>\n${indent} <CommandInput placeholder=\"Search ${label.toLowerCase()}...\" />\n${indent} <CommandList>\n${indent} <CommandEmpty>No ${relSingular} found.</CommandEmpty>\n${indent} <CommandGroup>\n${indent} {${dataArray}?.filter((item) => item.id !== null).map((item) => {\n${indent} const displayName = ${displayField}\n${indent} return (\n${indent} <CommandItem\n${indent} key={item.id}\n${indent} value={displayName}\n${indent} onSelect={() => {\n${indent} formField.onChange(String(item.id))\n${indent} set${toPascalCase(field.name)}Open(false)\n${indent} }}\n${indent} >\n${indent} <Check className={cn(\"mr-2 size-4\", formField.value === String(item.id) ? \"opacity-100\" : \"opacity-0\")} />\n${indent} {displayName}\n${indent} </CommandItem>\n${indent} )\n${indent} })}\n${indent} </CommandGroup>\n${indent} </CommandList>\n${indent} </Command>\n${indent} </PopoverContent>\n${indent} </Popover>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n\nfunction renderDefaultField(\n field: SchemaField,\n indent: string,\n label: string,\n fieldType: string,\n hintJSX: string\n): string {\n return `${indent}<FormField\n${indent} control={form.control}\n${indent} name=\"${field.name}\"\n${indent} render={({ field: formField }) => (\n${indent} <FormItem>\n${indent} <FormLabel>${label}</FormLabel>\n${indent} <FormControl>\n${indent} <Input\n${indent} type=\"${fieldType}\"\n${indent} placeholder=\"Enter ${label.toLowerCase()}\"\n${indent} {...formField}\n${indent} />\n${indent} </FormControl>\n${hintJSX ? `${hintJSX}\\n` : ''}${indent} <FormMessage />\n${indent} </FormItem>\n${indent} )}\n${indent}/>`\n}\n","/**\n * Shared logic for entity and single form generators\n */\n\nimport type { SchemaField } from '../../types.js'\nimport { quotePropertyName } from '../../utils/string.js'\nimport { getZodType } from './zod-schema.js'\n\nexport interface FormGeneratorResult {\n files: string[]\n}\n\nexport function collectRelationshipFields(\n fields: SchemaField[],\n _tabFieldNames: Set<string>\n): SchemaField[] {\n const result: SchemaField[] = []\n const seen = new Set<string>()\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'relationship' && f.relationship && !seen.has(f.name)) {\n seen.add(f.name)\n result.push(f)\n }\n if (f.type === 'group' && f.fields) collect(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collect(tab.fields)\n }\n }\n }\n }\n collect(fields)\n return result\n}\n\nexport function generateDefaultValue(f: SchemaField): string {\n if (f.type === 'list') return ` ${f.name}: initialData?.${f.name} ?? []`\n if (f.type === 'boolean') return ` ${f.name}: initialData?.${f.name} ?? false`\n if (f.type === 'number' || f.type === 'decimal' || f.type === 'serial') {\n const def = f.required ? '0' : 'undefined'\n return ` ${f.name}: initialData?.${f.name} ?? ${def}`\n }\n if (f.type === 'relationship') {\n if (f.multiple) return ` ${f.name}: initialData?.${f.name} ?? []`\n return ` ${f.name}: initialData?.${f.name}\n ? (typeof initialData.${f.name} === 'object' ? String(initialData.${f.name}.id) : String(initialData.${f.name}))\n : ''`\n }\n if (f.type === 'date' || f.type === 'timestamp') {\n return ` ${f.name}: initialData?.${f.name} ?? undefined`\n }\n if (f.default !== undefined && f.default !== null) {\n const def = typeof f.default === 'string' ? `'${f.default}'` : f.default\n return ` ${f.name}: initialData?.${f.name} ?? ${def}`\n }\n return ` ${f.name}: initialData?.${f.name} ?? ''`\n}\n\nexport function buildZodFields(flatFields: SchemaField[]): string {\n return flatFields\n .filter((f) => f.type !== 'tabs')\n .flatMap((f) => {\n const defs: string[] = []\n const zodType = getZodType(f)\n const alreadyOptional = zodType.includes('.optional()')\n let def = ` ${quotePropertyName(f.name)}: ${zodType}`\n if (!f.required && !alreadyOptional) def += '.optional()'\n defs.push(def)\n if (f.hasIcon) defs.push(` ${quotePropertyName(`${f.name}Icon`)}: z.string().optional()`)\n return defs\n })\n .join(',\\n')\n}\n\nexport function buildDefaultValues(flatFields: SchemaField[]): string {\n return flatFields\n .filter((f) => f.type !== 'tabs')\n .flatMap((f) => {\n const defs = [generateDefaultValue(f)]\n if (f.hasIcon) defs.push(` ${f.name}Icon: initialData?.${f.name}Icon ?? ''`)\n return defs\n })\n .join(',\\n')\n}\n\nexport function buildUiImports(ctx: {\n hasBoolean: boolean\n hasTextarea: boolean\n hasImage: boolean\n hasVideo: boolean\n hasMedia: boolean\n hasIcon: boolean\n hasIconPostfix: boolean\n hasDate: boolean\n hasMarkdown: boolean\n hasRichtext: boolean\n hasSeparator: boolean\n hasSelect: boolean\n hasTabsField: boolean\n hasRelationship: boolean\n hasSimpleList: boolean\n hasNestedList: boolean\n}): string[] {\n const uiImports: string[] = [\n \"import { Button } from '@cms/components/ui/button'\",\n \"import { Input } from '@cms/components/ui/input'\",\n `import {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage\n} from '@cms/components/ui/form'`\n ]\n\n if (ctx.hasBoolean) uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (ctx.hasTextarea) uiImports.push(\"import { Textarea } from '@cms/components/ui/textarea'\")\n if (ctx.hasImage)\n uiImports.push(\"import { ImageUploadField } from '@cms/components/ui/image-upload-field'\")\n if (ctx.hasVideo)\n uiImports.push(\"import { VideoUploadField } from '@cms/components/ui/video-upload-field'\")\n if (ctx.hasMedia)\n uiImports.push(\"import { MediaUploadField } from '@cms/components/ui/media-upload-field'\")\n if (ctx.hasIcon || ctx.hasIconPostfix)\n uiImports.push(\"import { IconPicker } from '@cms/components/ui/icon-picker'\")\n if (ctx.hasDate) uiImports.push(\"import { DatePicker } from '@cms/components/ui/date-picker'\")\n if (ctx.hasMarkdown)\n uiImports.push(\"import { MarkdownEditor } from '@cms/components/ui/markdown-editor'\")\n if (ctx.hasRichtext)\n uiImports.push(\"import { RichTextEditor } from '@cms/components/ui/rich-text-editor'\")\n if (ctx.hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n if (ctx.hasSelect) {\n uiImports.push(`import {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'`)\n }\n if (ctx.hasTabsField) {\n uiImports.push(`import {\n Tabs,\n TabsList,\n TabsTrigger,\n TabsContent\n} from '@cms/components/ui/tabs'`)\n }\n if (ctx.hasRelationship) {\n uiImports.push(`import {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from '@cms/components/ui/command'`)\n uiImports.push(`import {\n Popover,\n PopoverContent,\n PopoverTrigger\n} from '@cms/components/ui/popover'`)\n }\n\n if (ctx.hasSimpleList)\n uiImports.push(\"import { DynamicListField } from '@cms/components/ui/dynamic-list-field'\")\n if (ctx.hasNestedList) {\n uiImports.push(`import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger\n} from '@cms/components/ui/accordion'`)\n if (!ctx.hasSeparator)\n uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n uiImports.push(\"import { Label } from '@cms/components/ui/label'\")\n }\n\n return uiImports\n}\n","/**\n * Single (singleton) form generator — upsert mutation, no router, \"Save\" button\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields, hasFieldType, hasIconUsage } from '../../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../../types.js'\nimport { toPascalCase, singularize, pluralize } from '../../utils/string.js'\nimport { generateFieldJSX } from './field-jsx.js'\nimport {\n type FormGeneratorResult,\n collectRelationshipFields,\n buildZodFields,\n buildDefaultValues,\n buildUiImports\n} from './form-shared.js'\n\nexport function generateSingleForm(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): FormGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const formFilePath = path.join(entityDir, `${schema.name}-form.tsx`)\n\n if (fs.existsSync(formFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n\n // Analyze fields\n const allFormFields = schema.fields.filter(\n (f) => !f.primaryKey && f.name !== 'createdAt' && f.name !== 'updatedAt'\n )\n const flatFields = flattenFields(allFormFields)\n\n // Collect tab field names\n const tabFieldNames = new Set<string>()\n for (const f of schema.fields) {\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) for (const tf of tab.fields) tabFieldNames.add(tf.name)\n }\n }\n }\n\n // Check what components are needed\n const hasBoolean = hasFieldType(schema.fields, 'boolean')\n const hasImage = hasFieldType(schema.fields, 'image')\n const hasVideo = hasFieldType(schema.fields, 'video')\n const hasMedia = hasFieldType(schema.fields, 'media')\n const hasIcon = hasFieldType(schema.fields, 'icon')\n const hasIconPostfix = hasIconUsage(schema.fields)\n const hasDate = hasFieldType(schema.fields, 'date')\n const hasSelect = hasFieldType(schema.fields, 'select')\n const hasMarkdown = hasFieldType(schema.fields, 'markdown')\n const hasRichtext = hasFieldType(schema.fields, 'richtext')\n const hasTextarea = hasFieldType(schema.fields, 'text')\n const hasSeparator = hasFieldType(schema.fields, 'separator')\n const hasRelationship = hasFieldType(schema.fields, 'relationship')\n const hasTabsField = schema.fields.some((f) => f.type === 'tabs')\n const tabsField = schema.fields.find((f) => f.type === 'tabs')\n const firstTabName = tabsField?.tabs?.[0]?.name || ''\n\n const mainRelFields = collectRelationshipFields(schema.fields, tabFieldNames)\n\n // Collect list fields with nested fields\n const listFieldsWithNested: SchemaField[] = []\n function collectListFieldsSingle(fields: SchemaField[]): void {\n for (const f of fields) {\n if (f.type === 'list' && f.fields && f.fields.length > 0 && !f.hidden) {\n listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFieldsSingle(f.fields)\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields) collectListFieldsSingle(tab.fields)\n }\n }\n }\n }\n collectListFieldsSingle(allFormFields)\n const hasList = hasFieldType(schema.fields, 'list')\n const hasNestedList = listFieldsWithNested.length > 0\n const hasSimpleList =\n hasList && flatFields.some((f) => f.type === 'list' && (!f.fields || f.fields.length === 0))\n\n // Build Zod schema\n const zodFields = buildZodFields(flatFields)\n\n // Build default values\n const defaultValues = buildDefaultValues(flatFields)\n\n // Build form fields JSX\n const formFieldsJSX = allFormFields\n .map((f) => {\n if (f.type === 'tabs' && f.tabs) {\n const tabsList = f.tabs\n .map((t) => ` <TabsTrigger value=\"${t.name}\">${t.label}</TabsTrigger>`)\n .join('\\n')\n const tabsContent = f.tabs\n .map((t) => {\n const tabFields = (t.fields || [])\n .map((tf) => generateFieldJSX(tf, ' '))\n .join('\\n')\n return ` <TabsContent value=\"${t.name}\" className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${tabFields}\n </TabsContent>`\n })\n .join('\\n')\n return ` <Tabs value={activeTab} onValueChange={setActiveTab} className=\"w-full\">\n <TabsList>\n${tabsList}\n </TabsList>\n${tabsContent}\n </Tabs>`\n }\n if (tabFieldNames.has(f.name)) return ''\n return generateFieldJSX(f)\n })\n .filter(Boolean)\n .join('\\n')\n\n // --- Build imports ---\n const uiImports = buildUiImports({\n hasBoolean,\n hasTextarea,\n hasImage,\n hasVideo,\n hasMedia,\n hasIcon,\n hasIconPostfix,\n hasDate,\n hasMarkdown,\n hasRichtext,\n hasSeparator,\n hasSelect,\n hasTabsField,\n hasRelationship,\n hasSimpleList,\n hasNestedList\n })\n\n // Lucide icons\n const lucideIcons: string[] = []\n if (hasRelationship) lucideIcons.push('Check', 'ChevronsUpDown')\n if (hasNestedList) {\n if (!lucideIcons.includes('Plus')) lucideIcons.push('Plus')\n if (!lucideIcons.includes('X')) lucideIcons.push('X')\n }\n\n // Relationship hooks\n const relHookImports = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return `import { use${relPlural} } from '@cms/hooks/use-${f.relationship}'`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // Relationship state\n const relState = mainRelFields\n .map((f) => {\n const relPlural = toPascalCase(pluralize(f.relationship || ''))\n return ` const [${f.name}Open, set${toPascalCase(f.name)}Open] = React.useState(false)\n const { data: ${f.relationship}Data } = use${relPlural}()`\n })\n .filter((v, i, a) => a.indexOf(v) === i)\n .join('\\n')\n\n // List field array hooks\n const fieldArrayHooks = listFieldsWithNested\n .map((field) => {\n const pascalFieldName = toPascalCase(field.name)\n return ` const [${field.name}Expanded, set${pascalFieldName}Expanded] = React.useState<string | undefined>(undefined)\n const ${field.name}FieldArray = useFieldArray({\n control: form.control,\n name: '${field.name}'\n })`\n })\n .join('\\n')\n\n const needsReact = mainRelFields.length > 0 || hasNestedList\n\n // --- Assemble file ---\n const content = `'use client'\n${needsReact ? \"\\nimport * as React from 'react'\" : ''}\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useMutation, useQueryClient } from '@tanstack/react-query'${lucideIcons.length > 0 ? `\\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'` : ''}\nimport {${hasNestedList ? ' useFieldArray,' : ''} useForm } from 'react-hook-form'\nimport { toast } from 'sonner'\nimport { z } from 'zod/v3'${hasTabsField ? \"\\nimport { useQueryState } from 'nuqs'\" : ''}${hasRelationship ? \"\\nimport { cn } from '@cms/utils/cn'\" : ''}\n${relHookImports ? `${relHookImports}\\n` : ''}${uiImports.join('\\n')}\nimport type {\n ${Singular}Data,\n Upsert${Singular}Input\n} from '@cms/actions/${schema.name}'\nimport { upsert${Singular} } from '@cms/actions/${schema.name}'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\nexport type FormValues = z.infer<typeof formSchema>\n\ninterface ${Singular}FormProps {\n initialData?: ${Singular}Data | null\n}\n\nexport function ${Singular}Form({ initialData }: ${Singular}FormProps) {\n const queryClient = useQueryClient()${hasTabsField ? `\\n const [activeTab, setActiveTab] = useQueryState('tab', { defaultValue: '${firstTabName}' })` : ''}${relState ? `\\n${relState}` : ''}\n\n const upsertMutation = useMutation({\n mutationFn: (data: Upsert${Singular}Input) => upsert${Singular}(data),\n onSuccess: () => {\n toast.success('${schema.label} saved successfully')\n queryClient.invalidateQueries({ queryKey: ['${schema.name}'] })\n },\n onError: (error: Error) => {\n toast.error(error.message || 'Failed to save ${schema.label.toLowerCase()}')\n }\n })\n\n const isPending = upsertMutation.isPending\n\n const form = useForm<FormValues>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n${defaultValues}\n }\n })\n${fieldArrayHooks ? `\\n${fieldArrayHooks}\\n` : ''}\n function onSubmit(values: FormValues) {\n const cleanedValues = Object.fromEntries(\n Object.entries(values).map(([key, value]) => [key, value === undefined ? '' : value])\n ) as FormValues\n\n upsertMutation.mutate(cleanedValues as Upsert${Singular}Input)\n }\n\n return (\n <Form {...form}>\n <form id=\"${schema.name}-form\" onSubmit={form.handleSubmit(onSubmit, (errors) => {\n console.error('Form validation errors:', errors)\n const firstError = Object.values(errors)[0]\n if (firstError?.message) {\n toast.error(String(firstError.message))\n } else {\n toast.error('Please fix the form errors before submitting')\n }\n })} className=\"space-y-6\">\n <div className=\"space-y-6 p-6 rounded-2xl border bg-card\">\n${formFieldsJSX}\n </div>\n\n <div className=\"flex items-center fixed bottom-0 md:left-[calc(var(--sidebar-width))] w-screen md:w-[calc(100svw-var(--sidebar-width)-4px)] right-0 bg-secondary border-t\">\n <div className=\"flex mx-auto py-4 w-full max-w-5xl items-center justify-end gap-2\">\n <Button type=\"submit\" disabled={isPending} size=\"lg\">\n {isPending ? 'Saving...' : 'Save'}\n </Button>\n </div>\n </div>\n </form>\n </Form>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(formFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, `${schema.name}-form.tsx`)]\n }\n}\n","/**\n * Generator 3: React Query hook — cms/hooks/use-<n>.ts\n * Generates client-side data fetching hooks wrapping server actions\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { flattenFields } from '../core/field-helpers/index.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize, pluralize } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface HookGeneratorResult {\n files: string[]\n hookName: string\n}\n\n/**\n * Generate React Query hook for an entity — writes to cms/hooks/use-<n>.ts\n */\nexport function generateHook(\n schema: Schema,\n cwd: string,\n hooksDir: string,\n options: GeneratorOptions = {}\n): HookGeneratorResult {\n const hookFileName = `use-${schema.name}.ts`\n const hookFilePath = path.join(cwd, hooksDir, hookFileName)\n\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n\n // Check if schema has a slug field\n const dbFields = flattenFields(schema.fields)\n const hasSlugField = dbFields.some((f) => f.name === 'slug')\n const hasHtmlOutput = dbFields.some(\n (f) => (f.type === 'richtext' || f.type === 'markdown') && f.output === 'html'\n )\n\n // Check for existing file\n if (fs.existsSync(hookFilePath) && !options.force) {\n return { files: [], hookName: `use${Plural}` }\n }\n\n // Check if schema has filters\n const hasFilters = schema.filters && schema.filters.length > 0\n\n // --- Build imports from actions ---\n const actionImports: string[] = [`get${Plural}`, `get${Singular}ById`]\n if (hasSlugField) actionImports.push(`get${Singular}BySlug`)\n if (hasFilters) {\n for (const filter of schema.filters!) {\n actionImports.push(`getDistinct${Plural}${toPascalCase(filter.field)}`)\n }\n }\n const typeImports = [\n `type ${Singular}Data`,\n ...(hasHtmlOutput && hasSlugField ? [`type ${Singular}DisplayData`] : []),\n `type ${Plural}Response`,\n `type Get${Plural}Filters`\n ]\n\n // --- Build filter parameters ---\n const filterParams = hasFilters\n ? schema.filters!.map((f) => `${f.field}?: string`).join(', ')\n : ''\n const allParams = filterParams ? `search?: string, ${filterParams}` : 'search?: string'\n\n // --- Build query key with all filter params ---\n const queryKeyParts = hasFilters\n ? [\"search ?? ''\", ...schema.filters!.map((f) => `${f.field} ?? ''`)].join(', ')\n : \"search ?? ''\"\n\n // --- Build filters object in queryFn ---\n const filtersBody = hasFilters\n ? `const filters: Get${Plural}Filters = {}\n if (search) filters.search = search\n${schema.filters!.map((f) => ` if (${f.field}) filters.${f.field} = ${f.field}`).join('\\n')}\n return get${Plural}(Object.keys(filters).length > 0 ? filters : undefined)`\n : `const filters: Get${Plural}Filters | undefined = search ? { search } : undefined\n return get${Plural}(filters)`\n\n // --- Singular hook ---\n const singularHook = `\nexport function use${Singular}(id: number | null | undefined): UseQueryResult<${Singular}Data | null, Error> {\n return useQuery({\n queryKey: ['${singular}', id],\n queryFn: () => (id ? get${Singular}ById(id) : Promise.resolve(null)),\n enabled: !!id,\n staleTime: 0\n })\n}`\n\n // --- Slug hook ---\n const slugReturnType = hasHtmlOutput ? `${Singular}DisplayData` : `${Singular}Data`\n const slugHook = hasSlugField\n ? `\n\nexport function use${Singular}BySlug(slug: string | null | undefined): UseQueryResult<${slugReturnType} | null, Error> {\n return useQuery({\n queryKey: ['${singular}', 'slug', slug],\n queryFn: () => (slug ? get${Singular}BySlug(slug) : Promise.resolve(null)),\n enabled: !!slug,\n staleTime: 0\n })\n}`\n : ''\n\n // --- Distinct filter hooks ---\n const distinctHooks = hasFilters\n ? schema\n .filters!.map(\n (filter) => `\n\nexport function use${Plural}Distinct${toPascalCase(filter.field)}(): UseQueryResult<string[], Error> {\n return useQuery({\n queryKey: ['${plural}', 'distinct', '${filter.field}'],\n queryFn: () => getDistinct${Plural}${toPascalCase(filter.field)}()\n })\n}`\n )\n .join('')\n : ''\n\n // --- Assemble file ---\n const content = `import {\n ${[...actionImports, ...typeImports].join(',\\n ')}\n} from '@cms/actions/${schema.name}'\nimport { type UseQueryResult, useQuery } from '@tanstack/react-query'\n\nexport function use${Plural}(\n ${allParams ? `${allParams},` : ''}\n options?: { enabled?: boolean }\n): UseQueryResult<${Plural}Response, Error> {\n return useQuery({\n queryKey: ['${plural}', ${queryKeyParts}],\n queryFn: () => {\n ${filtersBody}\n },\n enabled: options?.enabled ?? true,\n refetchOnMount: 'always'\n })\n}\n${singularHook}${slugHook}${distinctHooks}\n`\n\n // Write file\n const dir = path.dirname(hookFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(hookFilePath, content, 'utf-8')\n\n return {\n files: [path.join(hooksDir, hookFileName)],\n hookName: `use${Plural}`\n }\n}\n\n/**\n * Generate React Query hook for a single (singleton) schema.\n * Only useXxx() query — no list, slug, or filter hooks.\n */\nexport function generateSingleHook(\n schema: Schema,\n cwd: string,\n hooksDir: string,\n options: GeneratorOptions = {}\n): HookGeneratorResult {\n const hookFileName = `use-${schema.name}.ts`\n const hookFilePath = path.join(cwd, hooksDir, hookFileName)\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n\n if (fs.existsSync(hookFilePath) && !options.force) {\n return { files: [], hookName: `use${Singular}` }\n }\n\n const content = `import {\n get${Singular},\n type ${Singular}Data\n} from '@cms/actions/${schema.name}'\nimport { type UseQueryResult, useQuery } from '@tanstack/react-query'\n\nexport function use${Singular}(): UseQueryResult<${Singular}Data | null, Error> {\n return useQuery({\n queryKey: ['${schema.name}'],\n queryFn: () => get${Singular}(),\n staleTime: 0\n })\n}\n`\n\n const dir = path.dirname(hookFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(hookFilePath, content, 'utf-8')\n\n return {\n files: [path.join(hooksDir, hookFileName)],\n hookName: `use${Singular}`\n }\n}\n","/**\n * Generator 11: Navigation — append to cms/data/navigation.ts\n * Parses existing navigation file and inserts new entity entry.\n * Uses flat `group` property for sidebar grouping (no nested children).\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface NavItem {\n label: string\n href: string\n icon?: string\n group?: string\n}\n\n// ============================================================================\n// Parser\n// ============================================================================\n\n/**\n * Parse existing navigation.ts and extract nav items + icon imports\n */\nfunction parseNavigationFile(content: string): { items: NavItem[]; iconImports: string[] } {\n const iconImportMatch = content.match(/import\\s*\\{([^}]+)\\}\\s*from\\s*['\"]lucide-react['\"]/)\n const iconImports: string[] = iconImportMatch\n ? iconImportMatch[1]\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s && s !== 'LucideIcon')\n : []\n\n const arrayBlock = extractTopLevelArray(content)\n if (!arrayBlock) return { items: [], iconImports }\n\n const items = parseItemsBlock(arrayBlock)\n return { items, iconImports }\n}\n\n/**\n * Find the cmsNavigation array and extract its content using bracket counting\n */\nfunction extractTopLevelArray(content: string): string | null {\n const marker = content.indexOf('cmsNavigation')\n if (marker === -1) return null\n\n const eqSign = content.indexOf('=', marker)\n if (eqSign === -1) return null\n const openBracket = content.indexOf('[', eqSign)\n if (openBracket === -1) return null\n\n let depth = 0\n for (let i = openBracket; i < content.length; i++) {\n if (content[i] === '[') depth++\n if (content[i] === ']') depth--\n if (depth === 0) {\n return content.slice(openBracket + 1, i)\n }\n }\n return null\n}\n\nfunction parseItemsBlock(block: string): NavItem[] {\n const items: NavItem[] = []\n let depth = 0\n let current = ''\n let inObj = false\n\n for (const char of block) {\n if (char === '{') {\n if (depth === 0) inObj = true\n depth++\n current += char\n } else if (char === '}') {\n depth--\n current += char\n if (depth === 0 && inObj) {\n const item = parseSingleItem(current)\n if (item) items.push(item)\n current = ''\n inObj = false\n }\n } else if (inObj) {\n current += char\n }\n }\n\n return items\n}\n\nfunction parseSingleItem(str: string): NavItem | null {\n const labelMatch = str.match(/label:\\s*['\"]([^'\"]+)['\"]/)\n const hrefMatch = str.match(/href:\\s*['\"]([^'\"]+)['\"]/)\n const iconMatch = str.match(/icon:\\s*(\\w+)/)\n const groupMatch = str.match(/group:\\s*['\"]([^'\"]+)['\"]/)\n\n if (!labelMatch || !hrefMatch) return null\n\n const item: NavItem = {\n label: labelMatch[1],\n href: hrefMatch[1]\n }\n if (iconMatch) item.icon = iconMatch[1]\n if (groupMatch) item.group = groupMatch[1]\n\n return item\n}\n\n// ============================================================================\n// Code Generator\n// ============================================================================\n\nfunction generateNavigationCode(items: NavItem[], iconImports: string[]): string {\n const lines: string[] = []\n\n lines.push(\"import type { LucideIcon } from 'lucide-react'\")\n lines.push(`import { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push('')\n lines.push('export interface CmsNavigationItem {')\n lines.push(' label: string')\n lines.push(' href: string')\n lines.push(' icon?: LucideIcon')\n lines.push(' group?: string')\n lines.push('}')\n lines.push('')\n lines.push('export const cmsNavigation: CmsNavigationItem[] = [')\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n const isLast = i === items.length - 1\n appendItem(lines, item, isLast)\n }\n\n lines.push(']')\n lines.push('')\n\n return lines.join('\\n')\n}\n\nfunction appendItem(lines: string[], item: NavItem, isLast: boolean): void {\n lines.push(' {')\n lines.push(` label: '${item.label}',`)\n\n const hasMore = item.icon != null || item.group != null\n lines.push(` href: '${item.href}'${hasMore ? ',' : ''}`)\n\n if (item.icon && item.group) {\n lines.push(` icon: ${item.icon},`)\n lines.push(` group: '${item.group}'`)\n } else if (item.icon) {\n lines.push(` icon: ${item.icon}`)\n } else if (item.group) {\n lines.push(` group: '${item.group}'`)\n }\n\n lines.push(` }${isLast ? '' : ','}`)\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface NavigationGeneratorResult {\n files: string[]\n}\n\n/**\n * Update cms/data/navigation.ts to include new entity nav item\n */\nexport function updateNavigation(\n schema: Schema,\n cwd: string,\n cmsDir: string,\n options: GeneratorOptions = {}\n): NavigationGeneratorResult {\n const navFilePath = path.join(cwd, cmsDir, 'data', 'navigation.ts')\n\n // Settings lives in the sidebar footer, not in navigation\n if (schema.name === 'settings') {\n return { files: [] }\n }\n\n // Parse existing navigation\n let items: NavItem[] = []\n let iconImports: string[] = []\n\n if (fs.existsSync(navFilePath)) {\n const content = fs.readFileSync(navFilePath, 'utf-8')\n const parsed = parseNavigationFile(content)\n items = parsed.items\n iconImports = parsed.iconImports\n }\n\n const entityHref = `/cms/${schema.name}`\n\n const newItem: NavItem = {\n label: schema.label,\n href: entityHref,\n icon: schema.icon\n }\n\n // If schema has a navGroup, set the group property\n if (schema.navGroup) {\n newItem.group = schema.navGroup.label\n }\n\n // Check if item already exists\n const existingIndex = items.findIndex((item) => item.href === entityHref)\n\n if (existingIndex >= 0) {\n if (options.force) {\n items[existingIndex] = newItem\n } else {\n return { files: [] }\n }\n } else {\n items.push(newItem)\n }\n\n // Reorganize: Dashboard first, then ungrouped alphabetical, then grouped alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => {\n // Ungrouped items first, then by group name, then by label\n if (!a.group && b.group) return -1\n if (a.group && !b.group) return 1\n if (a.group && b.group && a.group !== b.group) return a.group.localeCompare(b.group)\n return a.label.localeCompare(b.label)\n })\n\n items = [...(dashboard ? [dashboard] : []), ...others]\n\n // Add icon import if needed\n if (schema.icon && !iconImports.includes(schema.icon)) {\n iconImports.push(schema.icon)\n }\n iconImports.sort()\n\n // Write updated file\n const dir = path.dirname(navFilePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n\n const code = generateNavigationCode(items, iconImports)\n fs.writeFileSync(navFilePath, code, 'utf-8')\n\n return {\n files: [path.join(cmsDir, 'data', 'navigation.ts')]\n }\n}\n","/**\n * Generator 7: Page (server) — (authenticated)/<n>/page.tsx\n * Generates the server page component that renders columns + page content\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, pluralize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface PageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate server page component for entity list view\n */\nexport function generatePage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): PageGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const pageFilePath = path.join(entityDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const plural = pluralize(schema.name)\n const Plural = toPascalCase(plural)\n const kebabPlural = toKebabCase(plural)\n\n const content = `import * as React from 'react'\nimport { columns } from './columns'\nimport { ${Plural}PageContent } from './${kebabPlural}-page-content'\n\nexport default function ${Plural}Page() {\n return (\n <React.Suspense\n fallback={\n <div className=\"flex items-center justify-center h-48\">\n <div className=\"text-muted-foreground\">Loading ${schema.label}...</div>\n </div>\n }\n >\n <div className=\"flex flex-col\">\n <${Plural}PageContent columns={columns} />\n </div>\n </React.Suspense>\n )\n}\n`\n\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'page.tsx')]\n }\n}\n","/**\n * Generator 6: Page content — (authenticated)/<n>/<n>-page-content.tsx\n * Generates client component with search, filters, bulk delete, and table\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize, pluralize, singularizeLabel, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface PageContentGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate page content component for entity list view\n */\nexport function generatePageContent(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): PageContentGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n const fileName = `${toKebabCase(plural)}-page-content.tsx`\n const filePath = path.join(entityDir, fileName)\n\n if (fs.existsSync(filePath) && !options.force) {\n return { files: [] }\n }\n\n const hasCreate = schema.actions?.create ?? false\n const hasDelete = schema.actions?.delete ?? false\n const hasFilters = schema.filters && schema.filters.length > 0\n\n // --- Lucide icons ---\n const lucideIcons: string[] = ['ChevronLeft', 'Search', 'CornerDownLeft']\n if (hasCreate) lucideIcons.push('Plus')\n if (hasDelete) lucideIcons.push('Trash2')\n if (hasFilters) lucideIcons.push('Check', 'ChevronsUpDown')\n\n // --- Build imports ---\n let imports = `'use client'\n\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ${lucideIcons.join(', ')} } from 'lucide-react'\n${hasCreate ? \"import Link from 'next/link'\\n\" : ''}import { useRouter } from 'next/navigation'\nimport { parseAsString${hasDelete ? ', parseAsArrayOf, parseAsInteger' : ''}, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport { useFormStatus } from 'react-dom'\n${hasDelete ? \"import { toast } from 'sonner'\\n\" : ''}import { PageHeader } from '@cms/components/shared/page-header'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\n`\n\n if (hasDelete) {\n imports += `import {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger\n} from '@cms/components/ui/alert-dialog'\n`\n }\n\n if (hasFilters) {\n imports += `import {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from '@cms/components/ui/command'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger\n} from '@cms/components/ui/popover'\nimport { cn } from '@cms/utils/cn'\n`\n // Filter hooks\n const filterHooks = schema\n .filters!.map((f) => `use${Plural}Distinct${toPascalCase(f.field)}`)\n .join(', ')\n imports += `import { ${filterHooks} } from '@cms/hooks/use-${schema.name}'\\n`\n }\n\n imports += `import type { ${Singular}Data } from '@cms/actions/${schema.name}'\n${hasDelete ? `import { deleteBulk${Plural} } from '@cms/actions/${schema.name}'\\n` : ''}import { ${Plural}Table } from './${toKebabCase(plural)}-table'\n`\n\n // --- SearchButton component ---\n const searchButton = `function SearchButton() {\n const { pending } = useFormStatus()\n return (\n <Button type=\"submit\" variant=\"outline\" size=\"default\" disabled={pending}>\n {pending ? 'Searching...' : 'Search'}\n </Button>\n )\n}\n\n`\n\n // --- Filter state ---\n const filterLogic = hasFilters\n ? schema\n .filters!.map(\n (f) =>\n ` const [${f.field}, set${toPascalCase(f.field)}] = useQueryState('${f.field}', parseAsString.withDefault(''))\n const { data: ${f.field}Options } = use${Plural}Distinct${toPascalCase(f.field)}()\n const [${f.field}ComboboxOpen, set${toPascalCase(f.field)}ComboboxOpen] = React.useState(false)`\n )\n .join('\\n')\n : ''\n\n // --- Search logic ---\n const searchLogic = ` const [search, setSearch] = useQueryState('q', parseAsString.withDefault(''))\n\n const searchAction = React.useCallback(async (formData: FormData) => {\n const value = formData.get('search') as string\n React.startTransition(() => {\n setSearch(value || null)\n })\n }, [setSearch])\n${filterLogic ? `\\n${filterLogic}` : ''}`\n\n // --- Delete logic ---\n const deleteLogic = hasDelete\n ? `\n const [selectedIds, setSelectedIds] = useQueryState(\n 'selected',\n parseAsArrayOf(parseAsInteger).withDefault([])\n )\n const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n\n const handleBulkDelete = () => {\n startTransition(async () => {\n try {\n const result = await deleteBulk${Plural}(selectedIds)\n\n if (result.success) {\n toast.success(\n \\`\\${selectedIds.length} ${singular}\\${selectedIds.length > 1 ? 's' : ''} deleted successfully\\`\n )\n queryClient.refetchQueries({ queryKey: ['${plural}'] })\n setSelectedIds([])\n setDeleteDialogOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete ${plural}')\n }\n } catch (error) {\n toast.error('An error occurred')\n console.error(error)\n }\n })\n }\n`\n : ''\n\n // --- Filter dropdowns ---\n const _filterDropdowns = hasFilters\n ? schema\n .filters!.map(\n (\n f\n ) => ` <Popover open={${f.field}ComboboxOpen} onOpenChange={set${toPascalCase(f.field)}ComboboxOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={${f.field}ComboboxOpen}\n className=\"w-[200px] justify-between\"\n >\n {${f.field} || '${f.label}'}\n <ChevronsUpDown className=\"ml-2 size-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup>\n <CommandItem\n key=\"all\"\n value=\"\"\n onSelect={() => {\n React.startTransition(() => {\n set${toPascalCase(f.field)}('')\n })\n set${toPascalCase(f.field)}ComboboxOpen(false)\n }}\n >\n <Check\n className={cn(\n 'mr-2 size-4',\n ${f.field} === '' ? 'opacity-100' : 'opacity-0'\n )}\n />\n All ${f.label}\n </CommandItem>\n {${f.field}Options?.map((option) => (\n <CommandItem\n key={option}\n value={option}\n onSelect={() => {\n React.startTransition(() => {\n set${toPascalCase(f.field)}(option)\n })\n set${toPascalCase(f.field)}ComboboxOpen(false)\n }}\n >\n <Check\n className={cn(\n 'mr-2 size-4',\n ${f.field} === option ? 'opacity-100' : 'opacity-0'\n )}\n />\n {option}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>`\n )\n .join('\\n')\n : ''\n\n // --- Search input ---\n const searchInput = `<form action={searchAction} className=\"flex items-center gap-2 relative\">\n <Search className=\"text-muted-foreground/70 pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\" />\n <Input\n key={search}\n name=\"search\"\n placeholder=\"Search ${schema.label.toLowerCase()}...\"\n defaultValue={search}\n className=\"w-64 pl-9 bg-white rounded-lg\"\n />\n <CornerDownLeft className=\"text-muted-foreground/70 pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2\" />\n </form>`\n\n // --- Delete button ---\n const deleteButton = hasDelete\n ? ` {selectedIds.length > 0 && (\n <AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\" size=\"default\">\n <Trash2 className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Delete {selectedIds.length}{' '}\n {selectedIds.length === 1 ? '${singular}' : '${plural}'}\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete {selectedIds.length}{' '}\n {selectedIds.length === 1 ? '${singular}' : '${plural}'}.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n handleBulkDelete()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}`\n : ''\n\n // --- Create button ---\n const createButton = hasCreate\n ? ` <Button asChild>\n <Link href=\"/cms/${schema.name}/new\">\n <Plus className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Create ${singularizeLabel(schema.label)}\n </Link>\n </Button>`\n : ''\n\n // --- Table props ---\n const filterPropsStr = hasFilters\n ? schema.filters!.map((f) => `${f.field}={${f.field}}`).join(' ')\n : ''\n const allTableProps = filterPropsStr ? `search={search} ${filterPropsStr}` : 'search={search}'\n const tableProps = hasDelete\n ? `columns={columns} selectedIds={selectedIds} setSelectedIds={setSelectedIds} ${allTableProps}`\n : `columns={columns} selectedIds={[]} setSelectedIds={() => {}} ${allTableProps}`\n\n // --- Assemble file ---\n const content = `${imports}\n${searchButton}interface ${Plural}PageContentProps<TValue> {\n columns: ColumnDef<${Singular}Data, TValue>[]\n}\n\nexport function ${Plural}PageContent<TValue>({\n columns\n}: ${Plural}PageContentProps<TValue>) {\n const router = useRouter()\n const queryClient = useQueryClient()\n${searchLogic}${deleteLogic}\n return (\n <>\n <PageHeader title=\"${schema.label}\" back={<Button variant=\"ghost\" size=\"icon\" onClick={() => router.back()}><ChevronLeft /></Button>} search={${searchInput}} actions={<div className=\"flex items-center gap-2\">${deleteButton} ${createButton}</div>} />\n <main className=\"space-y-6 p-6\">\n <${Plural}Table ${tableProps} />\n </main>\n </>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, fileName)]\n }\n}\n","/**\n * Generator: Single page — (authenticated)/<n>/page.tsx\n * Server component that fetches the singleton record and renders the form.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, singularize } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface SinglePageGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate server page for a single (singleton) schema.\n * Calls getXxx() and renders XxxForm with initialData (null on first visit).\n */\nexport function generateSinglePage(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): SinglePageGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const pageFilePath = path.join(entityDir, 'page.tsx')\n\n if (fs.existsSync(pageFilePath) && !options.force) {\n return { files: [] }\n }\n\n const singular = singularize(schema.name)\n const Singular = toPascalCase(singular)\n const PageName = toPascalCase(schema.name)\n\n const content = `import { get${Singular} } from '@cms/actions/${schema.name}'\nimport { PageHeader } from '@cms/components/shared/page-header'\nimport { ${Singular}Form } from './${schema.name}-form'\n\nexport default async function ${PageName}Page() {\n const data = await get${Singular}()\n\n return (\n <>\n <PageHeader title=\"${schema.label}\" />\n <main className=\"container mx-auto max-w-5xl p-6 pb-20\">\n <${Singular}Form initialData={data} />\n </main>\n </>\n )\n}\n`\n\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(pageFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, 'page.tsx')]\n }\n}\n","/**\n * Generator 5: Table component — (authenticated)/<n>/<n>-table.tsx\n * Generates data table with pagination, sorting, reorder, and row selection\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { toPascalCase, toCamelCase, singularize, pluralize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface TableGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate table component for entity list view\n */\nexport function generateTable(\n schema: Schema,\n cwd: string,\n pagesDir: string,\n options: GeneratorOptions = {}\n): TableGeneratorResult {\n const entityDir = path.join(cwd, pagesDir, schema.name)\n const singular = singularize(schema.name)\n const plural = pluralize(schema.name)\n const Singular = toPascalCase(singular)\n const Plural = toPascalCase(plural)\n const camelPlural = toCamelCase(plural)\n const camelSingular = toCamelCase(singular)\n const tableFileName = `${toKebabCase(plural)}-table.tsx`\n const tableFilePath = path.join(entityDir, tableFileName)\n\n if (fs.existsSync(tableFilePath) && !options.force) {\n return { files: [] }\n }\n\n // Check if schema has filters\n const hasFilters = schema.filters && schema.filters.length > 0\n const filterProps = hasFilters\n ? schema.filters!.map((f) => `${f.field}?: string`).join('\\n ')\n : ''\n const allFilterProps = filterProps ? `\\n ${filterProps}` : ''\n const filterParams = hasFilters ? schema.filters!.map((f) => f.field).join(', ') : ''\n const allParams = filterParams ? `search, ${filterParams}` : 'search'\n\n const content = `'use client'\n\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow\n} from '@cms/components/ui/table'\nimport { use${Plural} } from '@cms/hooks/use-${schema.name}'\nimport { bulkUpdate${Plural}SortOrder } from '@cms/actions/${schema.name}'\nimport type { ${Singular}Data } from '@cms/actions/${schema.name}'\nimport '@cms/types/table-meta'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ArrowUpDown, Save } from 'lucide-react'\nimport { toast } from 'sonner'\n\nconst PAGE_SIZE_OPTIONS = [\n { value: '10', label: '10' },\n { value: '20', label: '20' },\n { value: '50', label: '50' },\n { value: '100', label: '100' },\n { value: 'all', label: 'All' }\n]\n\ninterface ${Plural}TableProps<TValue> {\n columns: ColumnDef<${Singular}Data, TValue>[]\n selectedIds: number[]\n setSelectedIds: (ids: number[]) => void\n search?: string${allFilterProps}\n}\n\nexport function ${Plural}Table<TValue>({ columns, selectedIds, setSelectedIds, ${allParams} }: ${Plural}TableProps<TValue>) {\n const { data, error, isPending } = use${Plural}(${allParams})\n const queryClient = useQueryClient()\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0))\n const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(20))\n\n // Reorder mode state\n const [reorderMode, setReorderMode] = React.useState(false)\n const [localData, setLocalData] = React.useState<${Singular}Data[]>([])\n const [hasChanges, setHasChanges] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n\n // Sync local data when server data changes\n React.useEffect(() => {\n if (data?.${camelPlural}) {\n setLocalData([...data.${camelPlural}])\n setHasChanges(false)\n }\n }, [data?.${camelPlural}])\n\n // Handle local row move (client-side only)\n const handleMoveRow = React.useCallback((id: number, direction: 'up' | 'down') => {\n setLocalData((prev) => {\n const index = prev.findIndex((item) => item.id === id)\n if (index === -1) return prev\n\n const newIndex = direction === 'up' ? index - 1 : index + 1\n if (newIndex < 0 || newIndex >= prev.length) return prev\n\n const newData = [...prev]\n const [removed] = newData.splice(index, 1)\n newData.splice(newIndex, 0, removed)\n\n return newData\n })\n setHasChanges(true)\n }, [])\n\n // Save all sort order changes to the database\n const handleSave = React.useCallback(async () => {\n if (!hasChanges) return\n\n setIsSaving(true)\n try {\n const updates = localData.map((item, index) => ({\n id: item.id as number,\n sortOrder: index\n }))\n\n const result = await bulkUpdate${Plural}SortOrder(updates)\n\n if (result.success) {\n toast.success('Sort order saved successfully')\n queryClient.refetchQueries({ queryKey: ['${plural}'] })\n setHasChanges(false)\n setReorderMode(false)\n } else {\n toast.error(result.error || 'Failed to save sort order')\n }\n } catch (error) {\n toast.error('An error occurred while saving')\n console.error(error)\n } finally {\n setIsSaving(false)\n }\n }, [hasChanges, localData, queryClient])\n\n // Cancel reorder mode and reset changes\n const handleCancelReorder = React.useCallback(() => {\n if (data?.${camelPlural}) {\n setLocalData([...data.${camelPlural}])\n }\n setHasChanges(false)\n setReorderMode(false)\n }, [data?.${camelPlural}])\n\n // Use local data when in reorder mode, otherwise use server data\n const tableData = reorderMode ? localData : (data?.${camelPlural} ?? [])\n\n // Convert selectedIds array to rowSelection object format\n const rowSelection = React.useMemo(() => {\n const selection: Record<string, boolean> = {}\n const ${camelPlural} = data?.${camelPlural} ?? []\n ${camelPlural}.forEach((${camelSingular}, index) => {\n if (selectedIds.includes(${camelSingular}.id as number)) {\n selection[index.toString()] = true\n }\n })\n return selection\n }, [selectedIds, data?.${camelPlural}])\n\n // Handle row selection changes\n const handleRowSelectionChange = React.useCallback(\n (updater: Record<string, boolean> | ((old: Record<string, boolean>) => Record<string, boolean>)) => {\n const ${camelPlural} = data?.${camelPlural} ?? []\n const newSelection = typeof updater === 'function' ? updater(rowSelection) : updater\n\n const newSelectedIds = Object.keys(newSelection)\n .filter((key) => newSelection[key])\n .map((key) => ${camelPlural}[Number.parseInt(key)]?.id as number)\n .filter(Boolean)\n\n setSelectedIds(newSelectedIds)\n },\n [data?.${camelPlural}, rowSelection, setSelectedIds]\n )\n\n // Determine effective page size (handle 'all' case)\n const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize\n\n const handlePageSizeChange = React.useCallback((value: string) => {\n React.startTransition(() => {\n if (value === 'all') {\n setPageSize(-1)\n } else {\n setPageSize(Number(value))\n }\n setPageIndex(0)\n })\n }, [setPageSize, setPageIndex])\n\n const handlePaginationChange = React.useCallback(\n (updater: { pageIndex: number; pageSize: number } | ((old: { pageIndex: number; pageSize: number }) => { pageIndex: number; pageSize: number })) => {\n const currentPagination = { pageIndex, pageSize: effectivePageSize }\n const newPagination = typeof updater === 'function' ? updater(currentPagination) : updater\n React.startTransition(() => {\n setPageIndex(newPagination.pageIndex)\n })\n },\n [pageIndex, effectivePageSize, setPageIndex]\n )\n\n const table = useReactTable({\n data: tableData,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n onRowSelectionChange: handleRowSelectionChange,\n onPaginationChange: handlePaginationChange,\n meta: {\n reorderMode,\n onMoveRow: handleMoveRow\n },\n state: {\n sorting,\n columnFilters,\n columnVisibility,\n rowSelection,\n pagination: {\n pageIndex,\n pageSize: effectivePageSize\n }\n }\n })\n\n return (\n <div className=\"space-y-6\">\n {/* Reorder controls */}\n <div className=\"flex items-center gap-2\">\n <Button\n variant={reorderMode ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setReorderMode(!reorderMode)}\n disabled={isSaving}\n >\n <ArrowUpDown className=\"size-4 mr-1\" />\n Sort Order\n </Button>\n {reorderMode && (\n <>\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={handleSave}\n disabled={!hasChanges || isSaving}\n >\n <Save className=\"size-4 mr-1\" />\n {isSaving ? 'Saving...' : 'Save'}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCancelReorder}\n disabled={isSaving}\n >\n Cancel\n </Button>\n {hasChanges && (\n <span className=\"text-sm text-muted-foreground\">\n Unsaved changes\n </span>\n )}\n </>\n )}\n </div>\n\n <div className=\"bg-card border overflow-hidden rounded-lg\">\n <Table>\n <TableHeader className=\"bg-secondary\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => {\n return (\n <TableHead key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n )\n })}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-muted-foreground\">Loading ${schema.label}...</div>\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-destructive\">Error loading ${schema.label}: {error.message}</div>\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No ${schema.label} found.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Rows per page</span>\n <Select\n value={pageSize === -1 ? 'all' : String(pageSize)}\n onValueChange={handlePageSizeChange}\n >\n <SelectTrigger className=\"w-[100px] h-8\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PAGE_SIZE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center space-x-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n >\n Previous\n </Button>\n <div className=\"text-sm text-muted-foreground\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount() || 1}\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n >\n Next\n </Button>\n </div>\n </div>\n </div>\n )\n}\n`\n\n // Write file\n if (!fs.existsSync(entityDir)) {\n fs.mkdirSync(entityDir, { recursive: true })\n }\n fs.writeFileSync(tableFilePath, content, 'utf-8')\n\n return {\n files: [path.join(pagesDir, schema.name, tableFileName)]\n }\n}\n","/**\n * Pipeline orchestrator — runs all 12 entity generation steps in sequence\n */\n\nimport type { BetterstartConfig } from '../config/types.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\nimport { generateActions, generateSingleActions } from './actions/index.js'\nimport { generateCache } from './cache.js'\nimport { generateColumns } from './columns/index.js'\nimport { generateCreatePage } from './create-page.js'\nimport { generateDatabase } from './database.js'\nimport { generateEditPage } from './edit-page.js'\nimport { generateForm, generateSingleForm } from './form/index.js'\nimport { generateHook, generateSingleHook } from './hook.js'\nimport { updateNavigation } from './navigation.js'\nimport { generatePage } from './page.js'\nimport { generatePageContent } from './page-content.js'\nimport { generateSinglePage } from './single-page.js'\nimport { generateTable } from './table.js'\n\nexport interface PipelineResult {\n success: boolean\n files: string[]\n errors: string[]\n}\n\n/**\n * Resolve output directories from config paths\n */\nfunction resolvePaths(config: BetterstartConfig) {\n const cms = config.paths?.cms ?? './cms'\n const pages = config.paths?.pages ?? './src/app/(cms)/cms/(authenticated)'\n const schemas = config.paths?.schemas ?? './cms/schemas'\n\n return {\n cmsDir: cms,\n pagesDir: pages,\n schemasDir: schemas,\n dbSchemaDir: `${cms}/db/schema.ts`,\n actionsDir: `${cms}/lib/actions`,\n hooksDir: `${cms}/hooks`\n }\n}\n\n/**\n * Run the full 12-step entity generation pipeline\n */\nexport function runEntityPipeline(\n schema: Schema,\n cwd: string,\n config: BetterstartConfig,\n options: GeneratorOptions = {}\n): PipelineResult {\n const paths = resolvePaths(config)\n const files: string[] = []\n const errors: string[] = []\n\n const steps: { name: string; run: () => string[] }[] = [\n {\n name: 'Database schema',\n run: () => generateDatabase(schema, cwd, paths.dbSchemaDir, options).files\n },\n {\n name: 'Server actions',\n run: () =>\n generateActions(schema, cwd, paths.actionsDir, {\n force: options.force,\n schemasDir: paths.schemasDir\n }).files\n },\n {\n name: 'React Query hook',\n run: () => generateHook(schema, cwd, paths.hooksDir, options).files\n },\n {\n name: 'Column definitions',\n run: () => generateColumns(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Table component',\n run: () => generateTable(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Page content',\n run: () => generatePageContent(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Page (server)',\n run: () => generatePage(schema, cwd, paths.pagesDir, options).files\n }\n ]\n\n // Steps 8-10 are conditional on schema.actions\n if (schema.actions?.create || schema.actions?.edit) {\n steps.push({\n name: 'Form',\n run: () => generateForm(schema, cwd, paths.pagesDir, options).files\n })\n }\n\n if (schema.actions?.create) {\n steps.push({\n name: 'Create page',\n run: () => generateCreatePage(schema, cwd, paths.pagesDir, options).files\n })\n }\n\n if (schema.actions?.edit) {\n steps.push({\n name: 'Edit page',\n run: () => generateEditPage(schema, cwd, paths.pagesDir, options).files\n })\n }\n\n // Steps 11-12 always run\n steps.push(\n {\n name: 'Navigation',\n run: () => updateNavigation(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Cache module',\n run: () => generateCache(schema, cwd, paths.cmsDir, options).files\n }\n )\n\n // Execute each step\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const stepNum = i + 1\n try {\n const result = step.run()\n files.push(...result)\n if (!options.silent) console.log(` ${stepNum}. ${step.name} ✓`)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${step.name}: ${msg}`)\n if (!options.silent) console.error(` ${stepNum}. ${step.name} ✗ — ${msg}`)\n }\n }\n\n return {\n success: errors.length === 0,\n files,\n errors\n }\n}\n\n/**\n * Run the 7-step single (singleton) generation pipeline\n */\nexport function runSinglePipeline(\n schema: Schema,\n cwd: string,\n config: BetterstartConfig,\n options: GeneratorOptions = {}\n): PipelineResult {\n const paths = resolvePaths(config)\n const files: string[] = []\n const errors: string[] = []\n\n const steps: { name: string; run: () => string[] }[] = [\n {\n name: 'Database schema',\n run: () => generateDatabase(schema, cwd, paths.dbSchemaDir, options).files\n },\n {\n name: 'Server actions',\n run: () =>\n generateSingleActions(schema, cwd, paths.actionsDir, { force: options.force }).files\n },\n {\n name: 'React Query hook',\n run: () => generateSingleHook(schema, cwd, paths.hooksDir, options).files\n },\n {\n name: 'Form',\n run: () => generateSingleForm(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Single page',\n run: () => generateSinglePage(schema, cwd, paths.pagesDir, options).files\n },\n {\n name: 'Navigation',\n run: () => updateNavigation(schema, cwd, paths.cmsDir, options).files\n },\n {\n name: 'Cache module',\n run: () => generateCache(schema, cwd, paths.cmsDir, options).files\n }\n ]\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const stepNum = i + 1\n try {\n const result = step.run()\n files.push(...result)\n if (!options.silent) console.log(` ${stepNum}. ${step.name} ✓`)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${step.name}: ${msg}`)\n if (!options.silent) console.error(` ${stepNum}. ${step.name} ✗ — ${msg}`)\n }\n }\n\n return {\n success: errors.length === 0,\n files,\n errors\n }\n}\n\n// Re-export individual generators for direct use\nexport { generateActions, generateSingleActions } from './actions/index.js'\nexport { generateCache } from './cache.js'\nexport { generateColumns } from './columns/index.js'\nexport { generateCreatePage } from './create-page.js'\nexport { generateDatabase } from './database.js'\nexport { generateEditPage } from './edit-page.js'\nexport { generateForm, generateSingleForm } from './form/index.js'\nexport { generateHook, generateSingleHook } from './hook.js'\nexport { updateNavigation } from './navigation.js'\nexport { generatePage } from './page.js'\nexport { generatePageContent } from './page-content.js'\nexport { generateSinglePage } from './single-page.js'\nexport { generateTable } from './table.js'\n","/**\n * Post-generation tasks: auto db:push + lint:fix\n */\n\nimport { execFileSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport type { PackageManager } from '../utils/package-manager.js'\nimport { detectPackageManager } from '../utils/package-manager.js'\n\n/**\n * Load .env.local and set variables on process.env (if not already set)\n */\nfunction loadEnvFile(cwd: string): void {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return\n\n const content = fs.readFileSync(envPath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx === -1) continue\n\n const key = trimmed.slice(0, eqIdx).trim()\n let value = trimmed.slice(eqIdx + 1).trim()\n\n // Strip surrounding quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1)\n }\n\n // Strip inline comments\n const commentIdx = value.indexOf(' #')\n if (commentIdx !== -1) {\n value = value.slice(0, commentIdx).trim()\n }\n\n if (!process.env[key]) {\n process.env[key] = value\n }\n }\n}\n\nfunction runPmScript(pm: PackageManager, script: string, cwd: string): boolean {\n const args = pm === 'bun' ? ['run', script] : [script]\n try {\n execFileSync(pm, args, { cwd, stdio: 'pipe' })\n return true\n } catch {\n return false\n }\n}\n\nfunction hasPkgScript(cwd: string, script: string): boolean {\n const pkgPath = path.join(cwd, 'package.json')\n if (!fs.existsSync(pkgPath)) return false\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as Record<string, unknown>\n const scripts = pkg.scripts as Record<string, unknown> | undefined\n return !!scripts?.[script]\n } catch {\n return false\n }\n}\n\nexport interface PostGenerateOptions {\n skipMigration?: boolean\n}\n\nexport interface PostGenerateResult {\n dbPush: 'success' | 'skipped' | 'no-db-url' | 'failed'\n lintFix: 'success' | 'skipped' | 'failed'\n}\n\n/**\n * Run post-generation tasks: db:push and lint:fix\n */\nexport function runPostGenerate(\n cwd: string,\n schemaName: string,\n options: PostGenerateOptions = {}\n): PostGenerateResult {\n const pm = detectPackageManager(cwd)\n const result: PostGenerateResult = {\n dbPush: 'skipped',\n lintFix: 'skipped'\n }\n\n // 1. Database push\n if (!options.skipMigration) {\n loadEnvFile(cwd)\n\n const dbUrl = process.env.BETTERSTART_DATABASE_URL || process.env.DATABASE_URL\n\n if (!dbUrl) {\n result.dbPush = 'no-db-url'\n console.log('\\n Database: skipped (no DATABASE_URL configured)')\n console.log(' To sync later: run db:push after setting BETTERSTART_DATABASE_URL')\n } else if (hasPkgScript(cwd, 'db:push')) {\n console.log('\\n Running db:push...')\n const ok = runPmScript(pm, 'db:push', cwd)\n result.dbPush = ok ? 'success' : 'failed'\n console.log(ok ? ' Database schema synced' : ' Database push failed (run db:push manually)')\n } else {\n // Try running drizzle-kit push directly using project-local binary\n console.log('\\n Running drizzle-kit push...')\n const drizzleBin = path.join(cwd, 'node_modules', '.bin', 'drizzle-kit')\n try {\n execFileSync(drizzleBin, ['push', '--force'], { cwd, stdio: 'inherit' })\n result.dbPush = 'success'\n console.log(' Database schema synced')\n } catch {\n result.dbPush = 'failed'\n console.log(' Database push failed (run drizzle-kit push manually)')\n }\n }\n } else {\n console.log('\\n Database: skipped (--skip-migration)')\n }\n\n // 2. Lint fix\n if (hasPkgScript(cwd, 'lint:fix')) {\n console.log(' Running lint:fix...')\n const ok = runPmScript(pm, 'lint:fix', cwd)\n result.lintFix = ok ? 'success' : 'failed'\n console.log(ok ? ' Code formatted' : ' Lint fix had issues (run lint:fix manually)')\n } else {\n // Try biome directly using project-local binary\n const biomeBin = path.join(cwd, 'node_modules', '.bin', 'biome')\n try {\n execFileSync(biomeBin, ['check', '--write', '.'], { cwd, stdio: 'pipe' })\n result.lintFix = 'success'\n console.log(' Code formatted with Biome')\n } catch {\n result.lintFix = 'skipped'\n }\n }\n\n // Next steps\n console.log('\\n Next steps:')\n console.log(' 1. Review the generated files')\n if (options.skipMigration || result.dbPush !== 'success') {\n console.log(' 2. Run database migration: db:push')\n console.log(` 3. Start the dev server and visit /cms/${schemaName}`)\n } else {\n console.log(` 2. Start the dev server and visit /cms/${schemaName}`)\n }\n\n return result\n}\n","import { execFileSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'\n\nconst LOCKFILE_MAP: Record<string, PackageManager> = {\n 'pnpm-lock.yaml': 'pnpm',\n 'package-lock.json': 'npm',\n 'yarn.lock': 'yarn',\n 'bun.lockb': 'bun',\n 'bun.lock': 'bun'\n}\n\nexport function detectPackageManager(cwd: string): PackageManager {\n // Walk up the directory tree to find lockfiles (handles monorepos)\n let dir = path.resolve(cwd)\n const root = path.parse(dir).root\n while (dir !== root) {\n for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) {\n if (fs.existsSync(path.join(dir, lockfile))) {\n return pm\n }\n }\n // Check packageManager field in package.json at this level\n const pkgPath = path.join(dir, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as Record<string, unknown>\n if (typeof pkg.packageManager === 'string') {\n const name = pkg.packageManager.split('@')[0]\n if (name === 'pnpm' || name === 'npm' || name === 'yarn' || name === 'bun') {\n return name\n }\n }\n } catch {\n // ignore parse errors\n }\n }\n dir = path.dirname(dir)\n }\n\n return 'npm'\n}\n\nexport function installCommand(pm: PackageManager): string {\n return pm === 'yarn' ? 'yarn' : `${pm} install`\n}\n\nexport function addCommand(pm: PackageManager, deps: string[], dev = false): string {\n const devFlag = dev ? (pm === 'yarn' ? '--dev' : '-D') : ''\n\n switch (pm) {\n case 'pnpm':\n return `pnpm add ${devFlag} ${deps.join(' ')}`.trim()\n case 'yarn':\n return `yarn add ${devFlag} ${deps.join(' ')}`.trim()\n case 'bun':\n return `bun add ${devFlag} ${deps.join(' ')}`.trim()\n default:\n return `npm install ${devFlag} ${deps.join(' ')}`.trim()\n }\n}\n\nexport function runCommand(pm: PackageManager, script: string): string {\n switch (pm) {\n case 'pnpm':\n return `pnpm ${script}`\n case 'yarn':\n return `yarn ${script}`\n case 'bun':\n return `bun run ${script}`\n default:\n return `npm run ${script}`\n }\n}\n\nexport function execPm(pm: PackageManager, args: string[], cwd: string): void {\n execFileSync(pm, args, { cwd, stdio: 'inherit' })\n}\n\n/**\n * Returns the binary + leading args to run `create-next-app` via the given package manager.\n * Using the native PM avoids nested-npx issues (e.g. running inside `npx @betterstart/cli`).\n */\nexport function createNextAppCommand(pm: PackageManager): { bin: string; prefix: string[] } {\n switch (pm) {\n case 'pnpm':\n return { bin: 'pnpm', prefix: ['create', 'next-app@latest'] }\n case 'yarn':\n return { bin: 'yarn', prefix: ['create', 'next-app@latest'] }\n case 'bun':\n return { bin: 'bunx', prefix: ['create-next-app@latest'] }\n default:\n return { bin: 'npx', prefix: ['create-next-app@latest'] }\n }\n}\n","import { execFileSync, spawn } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport * as p from '@clack/prompts'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { getDefaultConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\nimport { promptDatabase } from '../init/prompts/database.js'\nimport { promptFeatures } from '../init/prompts/features.js'\nimport { promptProject } from '../init/prompts/project.js'\nimport { scaffoldApiRoutes } from '../init/scaffolders/api-routes.js'\nimport { scaffoldAuth } from '../init/scaffolders/auth.js'\nimport { regenerateCmsDoc, scaffoldBase } from '../init/scaffolders/base.js'\nimport { scaffoldBiome } from '../init/scaffolders/biome.js'\nimport { scaffoldComponents } from '../init/scaffolders/components.js'\nimport { scaffoldDatabase } from '../init/scaffolders/database.js'\nimport { installDependenciesAsync } from '../init/scaffolders/dependencies.js'\nimport { detectDevPort, scaffoldEnv } from '../init/scaffolders/env.js'\nimport { scaffoldLayout } from '../init/scaffolders/layout.js'\nimport { scaffoldPreset } from '../init/scaffolders/preset.js'\nimport { scaffoldTailwind } from '../init/scaffolders/tailwind.js'\nimport { scaffoldTsconfig } from '../init/scaffolders/tsconfig.js'\nimport { detectProject } from '../utils/detect.js'\nimport { createNextAppCommand, detectPackageManager, runCommand } from '../utils/package-manager.js'\nimport { buildSeedScript } from './seed.js'\n\nexport const initCommand = new Command('init')\n .description('Scaffold CMS into a new or existing Next.js project')\n .argument('[name]', 'Project name (creates new directory if fresh project)')\n .option('--preset <preset>', 'Starter preset: blank, blog, or full', 'blog')\n .option('-y, --yes', 'Skip all prompts (accept defaults)')\n .option(\n '--database-url <url>',\n 'PostgreSQL database connection string (postgres:// or postgresql://)'\n )\n .option('--force', 'Overwrite all existing CMS files (nuclear option)')\n .action(\n async (\n name: string | undefined,\n options: { preset: string; yes?: boolean; databaseUrl?: string; force?: boolean }\n ) => {\n p.intro(pc.bgCyan(pc.black(' BetterStart CMS ')))\n\n let cwd = process.cwd()\n let project = detectProject(cwd)\n let pm = detectPackageManager(cwd)\n let isFreshProject = false\n\n // Determine srcDir\n let srcDir: boolean\n if (project.isExisting) {\n p.log.info(`Next.js project detected ${pc.dim('·')} ${pc.cyan(pm)}`)\n srcDir = project.hasSrcDir\n\n if (!project.hasTypeScript) {\n p.log.error('TypeScript is required. Please add a tsconfig.json first.')\n process.exit(1)\n }\n\n if (options.force) {\n // Nuclear option: wipe all CMS-owned directories and root-level files\n const nukeDirs = ['cms', 'app/(cms)']\n const nukeFiles = ['cms.config.ts', 'CMS.md', 'drizzle.config.ts']\n let nuked = 0\n for (const dir of nukeDirs) {\n const fullPath = path.resolve(cwd, dir)\n if (fs.existsSync(fullPath)) {\n fs.rmSync(fullPath, { recursive: true, force: true })\n nuked++\n }\n }\n for (const file of nukeFiles) {\n const fullPath = path.resolve(cwd, file)\n if (fs.existsSync(fullPath)) {\n fs.unlinkSync(fullPath)\n nuked++\n }\n }\n if (nuked > 0) {\n p.log.warn(`${pc.yellow('Force mode:')} removed ${nuked} existing CMS paths`)\n }\n // Re-detect project after wipe\n project = detectProject(cwd)\n } else if (project.conflicts.length > 0) {\n const conflictLines = project.conflicts.map((c) => `${pc.yellow('▲')} ${c}`)\n conflictLines.push(\n '',\n pc.dim('Existing files will not be overwritten.'),\n pc.dim(`Use ${pc.bold('--force')} to remove existing CMS files before scaffolding.`)\n )\n p.note(conflictLines.join('\\n'), pc.yellow('Conflicts'))\n if (!options.yes) {\n const proceed = await p.confirm({\n message: 'Continue anyway?',\n initialValue: true\n })\n if (p.isCancel(proceed) || !proceed) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n }\n }\n } else {\n p.log.info('No Next.js project found — fresh project mode')\n const projectPrompt = await promptProject(name)\n srcDir = projectPrompt.useSrcDir\n\n // Ask for preferred package manager\n if (!options.yes) {\n const pmChoice = await p.select({\n message: 'Which package manager do you want to use?',\n options: [\n { value: 'pnpm' as const, label: 'pnpm', hint: 'recommended' },\n { value: 'npm' as const, label: 'npm' },\n { value: 'yarn' as const, label: 'yarn' },\n { value: 'bun' as const, label: 'bun' }\n ]\n })\n if (p.isCancel(pmChoice)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n pm = pmChoice\n }\n\n // Run create-next-app using the selected package manager's native command\n // to avoid nested-npx issues (e.g. when running via `npx @betterstart/cli`)\n const displayName =\n projectPrompt.projectName === '.' ? path.basename(cwd) : projectPrompt.projectName\n\n const { bin, prefix } = createNextAppCommand(pm)\n const cnaArgs = [\n ...prefix,\n projectPrompt.projectName,\n '--yes',\n '--typescript',\n '--tailwind',\n '--app',\n '--turbopack',\n '--biome',\n '--react-compiler',\n `--use-${pm}`\n ]\n if (srcDir) cnaArgs.push('--src-dir')\n else cnaArgs.push('--no-src-dir')\n\n p.log.step(`Creating Next.js app: ${pc.cyan(displayName)}`)\n\n try {\n execFileSync(bin, cnaArgs, {\n cwd,\n stdio: 'inherit',\n timeout: 120_000\n })\n } catch (err) {\n p.log.error(err instanceof Error ? err.message : 'create-next-app failed')\n p.log.info(\n `You can create the project manually:\\n ${pc.cyan(`npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`)}\\n Then run ${pc.cyan('betterstart init')} inside it.`\n )\n process.exit(1)\n }\n\n // Move into the new project directory\n cwd = path.resolve(cwd, projectPrompt.projectName)\n\n // Verify the project was actually created\n const hasPackageJson = fs.existsSync(path.join(cwd, 'package.json'))\n const hasNextConfig = ['next.config.ts', 'next.config.js', 'next.config.mjs'].some((f) =>\n fs.existsSync(path.join(cwd, f))\n )\n\n if (!hasPackageJson || !hasNextConfig) {\n p.log.error(\n 'create-next-app completed but the project was not created. This can happen with nested npx calls.'\n )\n const manualCmd = `npx create-next-app@latest ${projectPrompt.projectName} --typescript --tailwind --app`\n p.log.info(\n `Create the project manually:\\n ${pc.cyan(manualCmd)}\\n Then run ${pc.cyan('betterstart init')} inside it.`\n )\n process.exit(1)\n }\n\n p.log.success(`Created ${displayName} Next.js project`)\n project = detectProject(cwd)\n isFreshProject = true\n }\n\n // Feature prompts\n const features = options.yes\n ? { includeEmail: true, preset: options.preset as 'blank' | 'blog' | 'full' }\n : await promptFeatures(options.preset)\n\n // Database URL — check existing .env.local first, then prompt if needed\n let databaseUrl: string | undefined\n const existingDbUrl = readExistingDbUrl(cwd)\n\n if (options.yes) {\n // Non-interactive mode: --database-url flag > existing env > placeholder\n if (options.databaseUrl) {\n if (!isValidDbUrl(options.databaseUrl)) {\n p.log.error(\n `Invalid database URL. Must start with ${pc.cyan('postgres://')} or ${pc.cyan('postgresql://')}`\n )\n process.exit(1)\n }\n databaseUrl = options.databaseUrl\n } else if (existingDbUrl) {\n databaseUrl = existingDbUrl\n }\n // else: no flag, no existing → use placeholder (databaseUrl stays undefined)\n } else if (existingDbUrl) {\n // Interactive mode but a valid URL already exists — skip the prompt\n const masked = maskDbUrl(existingDbUrl)\n p.log.info(`Using existing database URL from .env.local ${pc.dim(`(${masked})`)}`)\n databaseUrl = existingDbUrl\n } else {\n const dbResult = await promptDatabase()\n databaseUrl = dbResult.url\n }\n\n // Build config\n const config: BetterstartConfig = {\n ...getDefaultConfig(srcDir),\n features: { email: features.includeEmail }\n }\n\n // Run scaffolders — group fast steps under one spinner, then show results in a note box\n interface ScaffoldResult {\n label: string\n result: string\n }\n const results: ScaffoldResult[] = []\n const s = p.spinner()\n\n s.start('Directory structure')\n\n const baseFiles = scaffoldBase({ cwd, config })\n results.push({ label: 'Directory structure', result: `${baseFiles.length} files` })\n\n s.message('TypeScript aliases')\n const tsResult = scaffoldTsconfig(cwd)\n results.push({\n label: 'TypeScript aliases',\n result: tsResult.added.length > 0 ? `${tsResult.added.length} paths` : 'already set'\n })\n\n s.message('Tailwind CSS')\n const twResult = scaffoldTailwind(cwd, srcDir)\n results.push({\n label: 'Tailwind CSS',\n result: twResult.appended ? 'updated' : twResult.file ? 'already set' : 'no CSS file'\n })\n\n s.message('Environment variables')\n const envResult = scaffoldEnv(cwd, { includeEmail: features.includeEmail, databaseUrl })\n const envCount = envResult.added.length + envResult.updated.length\n results.push({\n label: 'Environment variables',\n result: envCount > 0 ? `${envCount} vars` : 'already set'\n })\n\n s.message('Database')\n const dbFiles = scaffoldDatabase({ cwd, config })\n results.push({ label: 'Database', result: `${dbFiles.length} files` })\n\n s.message('Authentication')\n const authFiles = scaffoldAuth({ cwd, config })\n results.push({ label: 'Authentication', result: `${authFiles.length} files` })\n\n s.message('Components')\n const compFiles = scaffoldComponents({ cwd, config })\n results.push({ label: 'Components', result: `${compFiles.length} files` })\n\n s.message('Pages & layouts')\n const layoutFiles = scaffoldLayout({ cwd, config })\n results.push({ label: 'Pages & layouts', result: `${layoutFiles.length} files` })\n\n s.message('API routes')\n const apiFiles = scaffoldApiRoutes({ cwd, config })\n results.push({ label: 'API routes', result: `${apiFiles.length} routes` })\n\n s.message('Linter')\n let linterResult: string\n if (project.linter.type === 'none') {\n const biomeResult = scaffoldBiome(cwd, project.linter)\n linterResult = biomeResult.installed ? 'biome (new)' : 'none'\n } else {\n linterResult = project.linter.type\n }\n results.push({ label: 'Linter', result: linterResult })\n\n // Build the note content before stopping the spinner\n const maxLabel = Math.max(...results.map((r) => r.label.length))\n const noteLines = results.map((r) => {\n const padded = r.label.padEnd(maxLabel + 3)\n return `${pc.green('✓')} ${padded}${pc.dim(r.result)}`\n })\n\n // Stop spinner quietly and erase the empty stop line, then show results card\n s.stop('')\n process.stdout.write('\\x1B[2A\\x1B[J')\n p.note(noteLines.join('\\n'), 'Scaffolded CMS')\n\n // If drizzle.config.ts already existed (wasn't created), offer to update it\n const drizzleConfigPath = path.join(cwd, 'drizzle.config.ts')\n if (!dbFiles.includes('drizzle.config.ts') && fs.existsSync(drizzleConfigPath)) {\n if (options.force) {\n const { drizzleConfigTemplate } = await import('../init/templates/db/drizzle-config.js')\n fs.writeFileSync(drizzleConfigPath, drizzleConfigTemplate(), 'utf-8')\n p.log.success('Updated drizzle.config.ts')\n } else if (!options.yes) {\n const overwrite = await p.confirm({\n message: 'drizzle.config.ts already exists. Overwrite with latest version?',\n initialValue: true\n })\n if (!p.isCancel(overwrite) && overwrite) {\n const { drizzleConfigTemplate } = await import('../init/templates/db/drizzle-config.js')\n fs.writeFileSync(drizzleConfigPath, drizzleConfigTemplate(), 'utf-8')\n p.log.success('Updated drizzle.config.ts')\n }\n }\n }\n\n // Install dependencies (async so spinner can animate)\n s.start('Installing dependencies (this may take a minute)')\n const depsResult = await installDependenciesAsync({\n cwd,\n pm,\n includeEmail: features.includeEmail,\n includeBiome: project.linter.type === 'none'\n })\n let depsInstalled = false\n if (depsResult.success) {\n s.stop('')\n depsInstalled = true\n } else {\n s.stop('Failed to install dependencies')\n p.log.warning(depsResult.error ?? 'Unknown error')\n p.log.info(\n `You can install them manually:\\n ${pc.cyan(`${pm} add ${depsResult.coreDeps.join(' ')}`)}\\n ${pc.cyan(`${pm} add -D ${depsResult.devDeps.join(' ')}`)}`\n )\n }\n\n // Apply preset schemas + run entity generation + regenerate CMS.md\n if (depsInstalled) {\n process.stdout.write('\\x1B[2A\\x1B[J')\n }\n s.start(`Applying ${features.preset} preset`)\n const presetResult = scaffoldPreset({ cwd, config, preset: features.preset })\n // Regenerate CMS.md with full documentation\n {\n const entityNames: string[] = []\n const formNames: string[] = []\n const schemasDir = path.join(cwd, config.paths.schemas)\n const formsDir = path.join(schemasDir, 'forms')\n if (fs.existsSync(schemasDir)) {\n for (const f of fs.readdirSync(schemasDir)) {\n if (f.endsWith('.json')) entityNames.push(f.replace('.json', ''))\n }\n }\n if (fs.existsSync(formsDir)) {\n for (const f of fs.readdirSync(formsDir)) {\n if (f.endsWith('.json')) formNames.push(f.replace('.json', ''))\n }\n }\n regenerateCmsDoc(cwd, config, {\n preset: features.preset,\n schemas: entityNames,\n forms: formNames\n })\n }\n s.stop('')\n process.stdout.write('\\x1B[2A\\x1B[J')\n\n // Build combined note for deps + preset\n const installLines: string[] = []\n if (depsInstalled) {\n installLines.push(\n `${pc.green('✓')} Dependencies ${pc.dim(`${depsResult.coreDeps.length} deps + ${depsResult.devDeps.length} dev deps`)}`\n )\n }\n if (presetResult.errors.length > 0) {\n installLines.push(\n `${pc.yellow('▲')} Preset ${pc.dim(`${features.preset} — ${presetResult.errors.length} warning(s)`)}`\n )\n for (const err of presetResult.errors) {\n installLines.push(` ${pc.dim(err)}`)\n }\n } else {\n installLines.push(\n `${pc.green('✓')} Preset ${pc.dim(`${features.preset} — ${presetResult.schemas.length} schemas, ${presetResult.generatedFiles.length} files`)}`\n )\n }\n p.note(installLines.join('\\n'), 'Installed')\n\n // Push database schema if env var is configured (after preset so entity tables are included)\n let dbPushed = false\n if (depsResult.success && hasDbUrl(cwd)) {\n s.start('Pushing database schema (drizzle-kit push)')\n const pushResult = await runDrizzlePush(cwd)\n if (pushResult.success) {\n s.stop(`${pc.green('✓')} Database schema pushed`)\n dbPushed = true\n } else {\n s.stop('Database push failed')\n p.log.warning(pushResult.error ?? 'Unknown error')\n p.log.info(`You can run it manually: ${pc.cyan('npx drizzle-kit push')}`)\n }\n }\n\n // Auto-seed admin user (only when db push succeeded and interactive mode)\n let seedEmail: string | undefined\n let seedPassword: string | undefined\n let seedSuccess = false\n\n if (dbPushed && !options.yes) {\n p.note(pc.dim('Create your first admin user to access the CMS.'), 'Admin account')\n\n const credentials = await p.group(\n {\n email: () =>\n p.text({\n message: 'Admin email',\n placeholder: 'admin@example.com',\n validate: (v) => {\n if (!v || !v.includes('@')) return 'Please enter a valid email'\n }\n }),\n password: () =>\n p.password({\n message: 'Admin password',\n validate: (v) => {\n if (!v || v.length < 8) return 'Password must be at least 8 characters'\n }\n })\n },\n {\n onCancel: () => {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n }\n )\n\n seedEmail = credentials.email\n seedPassword = credentials.password\n\n s.start('Creating admin user')\n let seedResult = await runSeed(\n cwd,\n config.paths?.cms ?? './cms',\n credentials.email,\n credentials.password\n )\n\n if (seedResult.existingUser) {\n s.stop(`${pc.yellow('▲')} Admin user already exists (${seedResult.existingUser})`)\n const replace = await p.confirm({\n message: 'Replace existing admin user?',\n initialValue: false\n })\n if (!p.isCancel(replace) && replace) {\n s.start('Replacing admin user')\n seedResult = await runSeed(\n cwd,\n config.paths?.cms ?? './cms',\n credentials.email,\n credentials.password,\n true\n )\n } else {\n seedSuccess = true\n }\n }\n\n if (seedResult.success) {\n s.stop(`${pc.green('✓')} Admin user created`)\n seedSuccess = true\n } else if (!seedSuccess && seedResult.error) {\n s.stop(`${pc.red('✗')} Failed to create admin user`)\n p.note(\n `${pc.red(seedResult.error)}\\n\\nRun manually: ${pc.cyan('npx betterstart seed')}`,\n pc.red('Seed failed')\n )\n }\n }\n\n // Git init + commit for fresh projects\n if (isFreshProject) {\n s.start('Creating initial git commit')\n try {\n execFileSync('git', ['init'], { cwd, stdio: 'pipe' })\n execFileSync('git', ['add', '.'], { cwd, stdio: 'pipe' })\n execFileSync('git', ['commit', '-m', 'Initial commit from BetterStart'], {\n cwd,\n stdio: 'pipe'\n })\n s.stop('Created initial git commit')\n } catch {\n s.stop('Git commit skipped')\n }\n }\n\n const totalFiles =\n baseFiles.length +\n dbFiles.length +\n authFiles.length +\n compFiles.length +\n layoutFiles.length +\n apiFiles.length\n\n // Summary\n const summaryLines: string[] = [\n `Preset: ${pc.cyan(features.preset)}`,\n `Files created: ${pc.cyan(String(totalFiles))}`,\n `Env vars: ${envResult.added.length} added, ${envResult.skipped.length} skipped`\n ]\n\n if (seedSuccess && seedEmail && seedPassword) {\n summaryLines.push(\n '',\n `Admin: ${pc.cyan(seedEmail)}`,\n `Password: ${pc.cyan(seedPassword)}`,\n `CMS: ${pc.cyan(`http://localhost:${detectDevPort(cwd)}/cms/login`)}`\n )\n }\n\n // Next steps\n const nextSteps: string[] = []\n let step = 1\n const envStepLabel = databaseUrl\n ? `Fill in remaining values in ${pc.cyan('.env.local')}`\n : `Fill in values in ${pc.cyan('.env.local')}`\n nextSteps.push(` ${step++}. ${envStepLabel}`)\n if (!dbPushed) {\n nextSteps.push(` ${step++}. Run ${pc.cyan('npx drizzle-kit push')} to sync the database`)\n }\n if (!seedSuccess) {\n nextSteps.push(\n ` ${step++}. Run ${pc.cyan('npx betterstart seed')} to create an admin user`\n )\n }\n nextSteps.push(` ${step++}. Run ${pc.cyan('pnpm run dev')} to start the development server`)\n nextSteps.push(\n ` ${step++}. Run ${pc.cyan('npx betterstart generate <schema>')} to create content types`\n )\n\n summaryLines.push('', 'Next steps:', ...nextSteps)\n\n p.note(summaryLines.join('\\n'), 'CMS scaffolded successfully')\n\n // Offer to start the dev server (interactive mode only)\n if (!options.yes) {\n const devCmd = runCommand(pm, 'dev')\n const startDev = await p.confirm({\n message: 'Start the development server?',\n initialValue: true\n })\n\n if (!p.isCancel(startDev) && startDev) {\n p.outro(`Starting ${pc.cyan(devCmd)}...`)\n const [bin, ...args] = devCmd.split(' ')\n spawn(bin, args, { cwd, stdio: 'inherit' })\n return\n }\n }\n\n p.outro('Done!')\n }\n )\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Validate a database connection URL */\nfunction isValidDbUrl(url: string): boolean {\n return url.startsWith('postgres://') || url.startsWith('postgresql://')\n}\n\n/** Read BETTERSTART_DATABASE_URL from .env.local, returning the value if it's a real URL. */\nfunction readExistingDbUrl(cwd: string): string | undefined {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return undefined\n const content = fs.readFileSync(envPath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed.startsWith('#') || !trimmed.includes('=')) continue\n const [key, ...rest] = trimmed.split('=')\n if (key?.trim() === 'BETTERSTART_DATABASE_URL') {\n const val = rest\n .join('=')\n .replace(/^['\"]|['\"]$/g, '')\n .trim()\n if (\n val.length > 0 &&\n !val.startsWith('your_') &&\n val !== 'postgresql://...' &&\n isValidDbUrl(val)\n ) {\n return val\n }\n }\n }\n return undefined\n}\n\n/** Mask a database URL for display: show host only. */\nfunction maskDbUrl(url: string): string {\n try {\n const parsed = new URL(url)\n return `${parsed.protocol}//${parsed.host}/***`\n } catch {\n return 'postgres://***'\n }\n}\n\n/** Check if BETTERSTART_DATABASE_URL is set in .env.local */\nfunction hasDbUrl(cwd: string): boolean {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return false\n const content = fs.readFileSync(envPath, 'utf-8')\n // Check the var exists and has a non-placeholder value\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed.startsWith('#') || !trimmed.includes('=')) continue\n const [key, ...rest] = trimmed.split('=')\n if (key?.trim() === 'BETTERSTART_DATABASE_URL') {\n const val = rest.join('=').trim()\n const unquoted = val.replace(/^['\"]|['\"]$/g, '')\n return unquoted.length > 0 && !unquoted.startsWith('your_') && unquoted !== 'postgresql://...'\n }\n }\n return false\n}\n\ninterface SeedResult {\n success: boolean\n error: string | null\n existingUser?: string\n}\n\n/** Write seed script, run it with tsx, clean up. Returns success/error. */\nfunction runSeed(\n cwd: string,\n cmsDir: string,\n email: string,\n password: string,\n overwrite = false\n): Promise<SeedResult> {\n const scriptsDir = path.join(cwd, cmsDir, 'scripts')\n const seedPath = path.join(scriptsDir, 'seed.ts')\n\n if (!fs.existsSync(scriptsDir)) {\n fs.mkdirSync(scriptsDir, { recursive: true })\n }\n fs.writeFileSync(seedPath, buildSeedScript(), 'utf-8')\n\n const cleanup = () => {\n try {\n fs.unlinkSync(seedPath)\n if (fs.existsSync(scriptsDir) && fs.readdirSync(scriptsDir).length === 0) {\n fs.rmdirSync(scriptsDir)\n }\n } catch {\n // Not critical\n }\n }\n\n return new Promise((resolve) => {\n const tsxBin = path.join(cwd, 'node_modules', '.bin', 'tsx')\n const child = spawn(tsxBin, [seedPath], {\n cwd,\n stdio: 'pipe',\n env: {\n ...process.env,\n SEED_EMAIL: email,\n SEED_PASSWORD: password,\n SEED_NAME: 'Admin',\n ...(overwrite ? { SEED_OVERWRITE: 'true' } : {})\n }\n })\n let stdout = ''\n let stderr = ''\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString()\n })\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n const timeout = setTimeout(() => {\n child.kill()\n cleanup()\n resolve({ success: false, error: 'Seed timed out after 30 seconds' })\n }, 30_000)\n child.on('close', (code) => {\n clearTimeout(timeout)\n cleanup()\n if (code === 0) {\n resolve({ success: true, error: null })\n } else if (code === 2) {\n // Exit code 2 = user already exists\n const name = stdout.match(/EXISTING_USER:(.+)/)?.[1]?.trim()\n resolve({ success: false, error: null, existingUser: name ?? email })\n } else {\n resolve({ success: false, error: parseSeedError(stdout, stderr) })\n }\n })\n child.on('error', (err) => {\n clearTimeout(timeout)\n cleanup()\n resolve({ success: false, error: parseSeedError('', err.message) })\n })\n })\n}\n\n/** Extract a human-readable error from seed script output */\nfunction parseSeedError(stdout: string, stderr: string): string {\n // Check for common patterns in stderr/stdout\n const combined = `${stdout}\\n${stderr}`\n\n // \"Seed failed: <message>\" from the catch handler\n const seedFailed = combined.match(/Seed failed:\\s*(.+)/)?.[1]?.trim()\n if (seedFailed) return seedFailed\n\n // \"Failed to create user\" from auth API failure\n if (combined.includes('Failed to create user')) return 'Auth API failed to create user'\n\n // Connection errors\n if (combined.includes('ECONNREFUSED') || combined.includes('connection refused'))\n return 'Could not connect to database'\n if (combined.includes('BETTERSTART_DATABASE_URL')) return 'Database URL is missing or invalid'\n if (combined.includes('password authentication failed'))\n return 'Database authentication failed — check your connection string'\n if (combined.includes('does not exist') && combined.includes('relation'))\n return 'Database tables not found — run npx drizzle-kit push first'\n if (combined.includes('MODULE_NOT_FOUND') || combined.includes('Cannot find module'))\n return 'Missing dependencies — run your package manager install first'\n\n // Fall back to first meaningful line of stderr\n const firstLine = stderr\n .split('\\n')\n .map((l) => l.trim())\n .find((l) => l.length > 0 && !l.startsWith('at ') && !l.startsWith('node:'))\n if (firstLine) return firstLine\n\n return 'Unknown error — run npx betterstart seed for details'\n}\n\n/** Run drizzle-kit push to sync the database schema */\nfunction runDrizzlePush(cwd: string): Promise<{ success: boolean; error: string | null }> {\n return new Promise((resolve) => {\n const drizzleBin = path.join(cwd, 'node_modules', '.bin', 'drizzle-kit')\n const child = spawn(drizzleBin, ['push', '--force'], {\n cwd,\n stdio: 'pipe',\n env: { ...process.env }\n })\n let stderr = ''\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n child.on('close', (code) => {\n if (code === 0) resolve({ success: true, error: null })\n else resolve({ success: false, error: stderr || `drizzle-kit push exited with code ${code}` })\n })\n child.on('error', (err) => {\n resolve({ success: false, error: err.message })\n })\n })\n}\n","import { execFileSync } from 'node:child_process'\n\nimport * as p from '@clack/prompts'\nimport pc from 'picocolors'\n\nexport interface DatabasePromptResult {\n url: string\n}\n\nconst VERCEL_NEON_URL = 'https://vercel.com/dashboard/integrations/checkout/neon'\n\n/**\n * Prompt the user to configure their database connection.\n *\n * Three paths:\n * 1. Vercel (Neon) — opens the integration page, then asks for the URL\n * 2. Supabase — \"coming soon\", loops back\n * 3. Manual — asks for the URL directly\n */\nexport async function promptDatabase(): Promise<DatabasePromptResult> {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const choice = await p.select({\n message: 'How would you like to connect your database?',\n options: [\n {\n value: 'vercel-neon' as const,\n label: 'Vercel (Neon)',\n hint: 'opens browser to create a free Postgres database'\n },\n {\n value: 'supabase' as const,\n label: 'Supabase',\n hint: 'coming soon'\n },\n {\n value: 'manual' as const,\n label: 'Enter connection string manually'\n }\n ]\n })\n\n if (p.isCancel(choice)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n if (choice === 'supabase') {\n p.log.warning('Supabase support is coming soon. Please choose another option.')\n continue\n }\n\n if (choice === 'vercel-neon') {\n openBrowser(VERCEL_NEON_URL)\n p.log.info(\n `Opening Vercel… Create a Neon Postgres database, then copy the ${pc.cyan('DATABASE_URL')} from the dashboard.`\n )\n }\n\n // Shared URL text prompt for both vercel-neon and manual\n const url = await promptConnectionString()\n return { url }\n }\n}\n\n/** Text prompt for the connection string with quote-stripping validation. */\nasync function promptConnectionString(): Promise<string> {\n const input = await p.text({\n message: 'Paste your database connection string',\n placeholder: 'postgres://user:pass@host/db',\n validate(val) {\n if (!val.trim()) {\n return 'A connection string is required to continue'\n }\n const stripped = val.replace(/^['\"]|['\"]$/g, '')\n if (!stripped.startsWith('postgres://') && !stripped.startsWith('postgresql://')) {\n return 'Must start with postgres:// or postgresql://'\n }\n }\n })\n\n if (p.isCancel(input)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n return (input as string).replace(/^['\"]|['\"]$/g, '').trim()\n}\n\n/** Best-effort browser open. Fails silently in headless / CI environments. */\nfunction openBrowser(url: string): void {\n try {\n const platform = process.platform\n if (platform === 'darwin') {\n execFileSync('open', [url], { stdio: 'ignore' })\n } else if (platform === 'win32') {\n execFileSync('cmd', ['/c', 'start', url], { stdio: 'ignore' })\n } else {\n execFileSync('xdg-open', [url], { stdio: 'ignore' })\n }\n } catch {\n // Silently ignore — user can open the URL manually\n }\n}\n","import * as p from '@clack/prompts'\n\nexport type Preset = 'blank' | 'blog' | 'full'\n\nexport interface FeaturesPromptResult {\n includeEmail: true\n preset: Preset\n}\n\n/**\n * Prompt for preset selection.\n */\nexport async function promptFeatures(presetOverride?: string): Promise<FeaturesPromptResult> {\n let preset: Preset\n if (presetOverride && isValidPreset(presetOverride)) {\n preset = presetOverride\n } else {\n const selected = await p.select({\n message: 'Select a preset:',\n options: [\n { value: 'blog' as const, label: 'Blog', hint: 'Posts + Categories (recommended)' },\n { value: 'blank' as const, label: 'Blank', hint: 'CMS shell only, no content types' },\n { value: 'full' as const, label: 'Full', hint: 'Blog + Navigation + Contact form' }\n ],\n initialValue: 'blog' as const\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n preset = selected\n }\n\n return { includeEmail: true, preset }\n}\n\nfunction isValidPreset(value: string): value is Preset {\n return value === 'blank' || value === 'blog' || value === 'full'\n}\n","import * as p from '@clack/prompts'\n\nexport interface ProjectPromptResult {\n projectName: string\n useSrcDir: boolean\n}\n\n/**\n * Prompt for project name and src/ directory (fresh project only).\n */\nexport async function promptProject(defaultName?: string): Promise<ProjectPromptResult> {\n const projectName = await p.text({\n message: 'What is your project name?',\n placeholder: defaultName ?? 'my-app',\n defaultValue: defaultName ?? 'my-app',\n validate: (value) => {\n if (!value.trim()) return 'Project name is required'\n if (value.trim() === '.') return undefined\n if (!/^[a-z0-9_-]+$/i.test(value.trim())) {\n return 'Project name can only contain letters, numbers, hyphens, and underscores'\n }\n return undefined\n }\n })\n\n if (p.isCancel(projectName)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n const useSrcDir = await p.confirm({\n message: 'Use src/ directory?',\n initialValue: false\n })\n\n if (p.isCancel(useSrcDir)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n return { projectName: projectName.trim(), useSrcDir }\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { ensureDir, safeWriteFile } from '../../utils/fs.js'\n\nimport { authRouteTemplate } from '../templates/api/auth-route.js'\nimport { uploadRouteTemplate } from '../templates/api/upload-route.js'\n\nexport interface ApiRoutesScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create CMS API routes under /api/cms/.\n */\nexport function scaffoldApiRoutes({ cwd, config }: ApiRoutesScaffoldOptions): string[] {\n const created: string[] = []\n const apiDir = path.resolve(cwd, config.paths.api)\n\n function write(relPath: string, content: string): void {\n const fullPath = path.join(apiDir, relPath)\n ensureDir(path.dirname(fullPath))\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.api, relPath))\n }\n }\n\n // Better Auth catch-all: /api/cms/auth/[...all]/route.ts\n write(path.join('auth', '[...all]', 'route.ts'), authRouteTemplate())\n\n // Upload: /api/cms/upload/route.ts\n write(path.join('upload', 'route.ts'), uploadRouteTemplate())\n\n return created\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport fse from 'fs-extra'\n\n/**\n * Ensure a directory exists, creating it recursively if needed.\n */\nexport function ensureDir(dirPath: string): void {\n fse.ensureDirSync(dirPath)\n}\n\n/**\n * Write a file, creating parent directories as needed.\n * Will NOT overwrite an existing file unless `force` is true.\n * Returns true if the file was written, false if skipped.\n */\nexport function safeWriteFile(filePath: string, content: string, force = false): boolean {\n if (!force && fs.existsSync(filePath)) {\n return false\n }\n ensureDir(path.dirname(filePath))\n fs.writeFileSync(filePath, content, 'utf-8')\n return true\n}\n\n/**\n * Copy a single file, creating parent directories as needed.\n * Will NOT overwrite an existing file unless `force` is true.\n */\nexport function safeCopyFile(src: string, dest: string, force = false): boolean {\n if (!force && fs.existsSync(dest)) {\n return false\n }\n ensureDir(path.dirname(dest))\n fs.copyFileSync(src, dest)\n return true\n}\n\n/**\n * Recursively copy a directory of templates.\n * Skips existing files unless `force` is true.\n * Returns lists of written and skipped file paths.\n */\nexport function copyTemplateDir(\n srcDir: string,\n destDir: string,\n force = false\n): { written: string[]; skipped: string[] } {\n const written: string[] = []\n const skipped: string[] = []\n\n function walk(currentSrc: string, currentDest: string): void {\n const entries = fs.readdirSync(currentSrc, { withFileTypes: true })\n for (const entry of entries) {\n const srcPath = path.join(currentSrc, entry.name)\n const destPath = path.join(currentDest, entry.name)\n\n if (entry.isDirectory()) {\n walk(srcPath, destPath)\n } else {\n if (safeCopyFile(srcPath, destPath, force)) {\n written.push(destPath)\n } else {\n skipped.push(destPath)\n }\n }\n }\n }\n\n walk(srcDir, destDir)\n return { written, skipped }\n}\n\n/**\n * Append content to a file if the marker text is not already present.\n * Creates the file if it doesn't exist.\n * Returns true if content was appended.\n */\nexport function appendToFile(filePath: string, content: string, marker: string): boolean {\n if (fs.existsSync(filePath)) {\n const existing = fs.readFileSync(filePath, 'utf-8')\n if (existing.includes(marker)) {\n return false\n }\n fs.writeFileSync(filePath, `${existing.trimEnd()}\\n${content}\\n`, 'utf-8')\n } else {\n ensureDir(path.dirname(filePath))\n fs.writeFileSync(filePath, `${content}\\n`, 'utf-8')\n }\n return true\n}\n","/**\n * Template: app/(cms)/api/cms/auth/[...all]/route.ts\n * Better Auth catch-all route handler\n */\nexport function authRouteTemplate(): string {\n return `import { auth, toNextJsHandler } from '@cms/auth'\n\nexport const { GET, POST } = toNextJsHandler(auth)\n`\n}\n","/**\n * Template: app/(cms)/api/cms/upload/route.ts\n * File upload route handler — uploads to Cloudflare R2\n */\nexport function uploadRouteTemplate(): string {\n return `import { PutObjectCommand } from '@aws-sdk/client-s3'\nimport { BUCKET_NAME, generateFilePath, getPublicUrl, getR2Client } from '@cms/lib/r2'\nimport type { UploadedFile } from '@cms/types'\nimport { validateFiles } from '@cms/utils/validation'\nimport { type NextRequest, NextResponse } from 'next/server'\n\nexport async function POST(request: NextRequest) {\n try {\n const formData = await request.formData()\n const prefix = formData.get('prefix')?.toString() || 'uploads'\n\n const maxSizeInBytes = Number(formData.get('maxSizeInBytes')) || 10 * 1024 * 1024\n const allowedTypesRaw = formData.get('allowedTypes')?.toString()\n const allowedTypes = allowedTypesRaw ? allowedTypesRaw.split(',').filter(Boolean) : []\n\n const files: File[] = []\n for (const [key, value] of formData.entries()) {\n if (value instanceof File && key.startsWith('file')) {\n files.push(value)\n }\n }\n\n if (files.length === 0) {\n return NextResponse.json({ success: false, error: 'No files provided' }, { status: 400 })\n }\n\n const validation = validateFiles(files, {\n maxSizeInBytes,\n allowedTypes,\n maxFiles: 10,\n })\n\n if (!validation.valid) {\n return NextResponse.json(\n {\n success: false,\n error: validation.errors.map((e) => \\`\\${e.filename}: \\${e.error}\\`).join('; '),\n },\n { status: 400 },\n )\n }\n\n const uploadedFiles: UploadedFile[] = []\n\n for (const file of files) {\n const key = generateFilePath(file.name, prefix)\n const arrayBuffer = await file.arrayBuffer()\n const buffer = Buffer.from(arrayBuffer)\n\n const command = new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: key,\n Body: buffer,\n ContentType: file.type,\n ContentLength: file.size,\n })\n\n await getR2Client().send(command)\n\n uploadedFiles.push({\n key,\n url: getPublicUrl(key),\n filename: file.name,\n size: file.size,\n contentType: file.type,\n })\n }\n\n return NextResponse.json({ success: true, files: uploadedFiles })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to upload files'\n return NextResponse.json({ success: false, error: message }, { status: 500 })\n }\n}\n`\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { safeWriteFile } from '../../utils/fs.js'\n\nimport { authTemplate } from '../templates/lib/auth/auth.js'\nimport { authClientTemplate } from '../templates/lib/auth/auth-client.js'\nimport { authMiddlewareTemplate } from '../templates/lib/auth/middleware.js'\n\nexport interface AuthScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create Better Auth config, client, and middleware in cms/lib/auth/.\n */\nexport function scaffoldAuth({ cwd, config }: AuthScaffoldOptions): string[] {\n const created: string[] = []\n const authDir = path.resolve(cwd, config.paths.cms, 'lib', 'auth')\n\n function write(filename: string, content: string): void {\n const fullPath = path.join(authDir, filename)\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.cms, 'lib', 'auth', filename))\n }\n }\n\n write('auth.ts', authTemplate())\n write('auth-client.ts', authClientTemplate())\n write('middleware.ts', authMiddlewareTemplate())\n\n return created\n}\n","/**\n * Template: cms/lib/auth/auth.ts\n * Better Auth server configuration\n */\nexport function authTemplate(): string {\n return `import db from '@cms/db'\nimport * as schema from '@cms/db/schema'\nimport { betterAuth } from 'better-auth'\nimport { drizzleAdapter } from 'better-auth/adapters/drizzle'\nimport { toNextJsHandler } from 'better-auth/next-js'\n\nexport { toNextJsHandler }\n\nexport const auth = betterAuth({\n secret: process.env.BETTERSTART_AUTH_SECRET,\n baseURL: process.env.BETTERSTART_AUTH_URL,\n basePath: process.env.BETTERSTART_AUTH_BASE_PATH || '/api/cms/auth',\n database: drizzleAdapter(db, {\n provider: 'pg',\n schema: {\n user: schema.user,\n session: schema.session,\n account: schema.account,\n verification: schema.verification,\n },\n }),\n emailAndPassword: {\n enabled: true,\n minPasswordLength: 8,\n },\n session: {\n expiresIn: 60 * 60 * 24 * 7, // 7 days\n updateAge: 60 * 60 * 24, // 1 day\n },\n user: {\n additionalFields: {\n role: {\n type: 'string',\n required: false,\n defaultValue: 'member',\n input: false,\n },\n },\n },\n})\n\nexport type Session = typeof auth.$Infer.Session\nexport type User = typeof auth.$Infer.Session.user\n`\n}\n","/**\n * Template: cms/lib/auth/auth-client.ts\n * Better Auth client for use in client components\n */\nexport function authClientTemplate(): string {\n return `'use client'\n\nimport { createAuthClient } from 'better-auth/react'\n\nexport const authClient = createAuthClient({\n baseURL:\n process.env.NEXT_PUBLIC_BETTERSTART_AUTH_URL ||\n (typeof window !== 'undefined' ? window.location.origin : ''),\n basePath: '/api/cms/auth',\n})\n\nexport const { signIn, signUp, signOut, useSession } = authClient\n`\n}\n","/**\n * Template: cms/lib/auth/middleware.ts\n * Server-side auth helpers: getSession, requireRole\n */\nexport function authMiddlewareTemplate(): string {\n return `import { headers } from 'next/headers'\nimport { redirect } from 'next/navigation'\nimport { auth, type User } from './auth'\n\nexport enum UserRole {\n ADMIN = 'admin',\n EDITOR = 'editor',\n MEMBER = 'member',\n}\n\nexport function isUserRole(value: unknown): value is UserRole {\n return typeof value === 'string' && Object.values(UserRole).includes(value as UserRole)\n}\n\n/**\n * Get the current session from Better Auth\n */\nexport async function getSession() {\n const session = await auth.api.getSession({\n headers: await headers(),\n })\n return session\n}\n\n/**\n * Require the user to have one of the specified roles.\n * Redirects to /cms/login if not authenticated or unauthorized.\n */\nexport async function requireRole(allowedRoles: UserRole[]): Promise<User> {\n const session = await getSession()\n\n if (!session?.user) {\n redirect('/cms/login')\n }\n\n const user = session.user\n const role = isUserRole(user.role) ? user.role : UserRole.MEMBER\n\n if (!allowedRoles.includes(role)) {\n redirect('/cms/login')\n }\n\n return user\n}\n`\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { ensureDir, safeWriteFile } from '../../utils/fs.js'\n\nexport interface BaseScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\nexport interface CmsDocOptions {\n preset?: string\n schemas?: string[]\n forms?: string[]\n}\n\n/**\n * Create the cms/ directory structure, cms.config.ts, and CMS.md.\n */\nexport function scaffoldBase({ cwd, config }: BaseScaffoldOptions): string[] {\n const created: string[] = []\n\n // Create cms/ subdirectories\n const cmsDirs = [\n config.paths.cms,\n config.paths.schemas,\n path.join(config.paths.cms, 'db'),\n path.join(config.paths.cms, 'db', 'migrations'),\n path.join(config.paths.cms, 'lib', 'auth'),\n path.join(config.paths.cms, 'lib', 'actions'),\n path.join(config.paths.cms, 'lib', 'cache'),\n path.join(config.paths.cms, 'lib', 'markdown'),\n path.join(config.paths.cms, 'lib', 'emails'),\n path.join(config.paths.cms, 'lib'),\n path.join(config.paths.cms, 'hooks'),\n path.join(config.paths.cms, 'components', 'ui'),\n path.join(config.paths.cms, 'components', 'form'),\n path.join(config.paths.cms, 'components', 'data-table'),\n path.join(config.paths.cms, 'components', 'layout'),\n path.join(config.paths.cms, 'components', 'shared'),\n path.join(config.paths.cms, 'types'),\n path.join(config.paths.cms, 'utils'),\n path.join(config.paths.cms, 'data')\n ]\n\n for (const dir of cmsDirs) {\n ensureDir(path.resolve(cwd, dir))\n }\n\n // Create app route directories\n const appDirs = [config.paths.pages, config.paths.login, config.paths.api]\n\n for (const dir of appDirs) {\n ensureDir(path.resolve(cwd, dir))\n }\n\n // Write cms.config.ts\n const configContent = generateConfigFile(config)\n if (safeWriteFile(path.resolve(cwd, 'cms.config.ts'), configContent)) {\n created.push('cms.config.ts')\n }\n\n // Write CMS.md (basic version — regenerated after preset with full info)\n const cmsDoc = generateCmsDoc(config, {})\n if (safeWriteFile(path.resolve(cwd, 'CMS.md'), cmsDoc)) {\n created.push('CMS.md')\n }\n\n return created\n}\n\n/**\n * Regenerate CMS.md with full documentation including preset and schema info.\n * Called after the preset step so generated schemas can be listed.\n */\nexport function regenerateCmsDoc(\n cwd: string,\n config: BetterstartConfig,\n options: CmsDocOptions\n): void {\n const content = generateCmsDoc(config, options)\n fs.writeFileSync(path.resolve(cwd, 'CMS.md'), content, 'utf-8')\n}\n\nfunction generateConfigFile(config: BetterstartConfig): string {\n return `import { defineConfig } from '@betterstart/cli'\n\nexport default defineConfig({\n srcDir: ${String(config.srcDir)},\n\n paths: {\n cms: '${config.paths.cms}',\n schemas: '${config.paths.schemas}',\n pages: '${config.paths.pages}',\n login: '${config.paths.login}',\n api: '${config.paths.api}',\n },\n\n database: {\n provider: '${config.database.provider}',\n migrationsDir: '${config.database.migrationsDir}',\n },\n\n features: {\n email: ${String(config.features.email)},\n },\n\n linter: '${config.linter}',\n\n generated: {\n entities: [],\n singles: [],\n forms: [],\n },\n})\n`\n}\n\nfunction generateCmsDoc(config: BetterstartConfig, options: CmsDocOptions): string {\n const sections: string[] = []\n\n // Header\n sections.push(`# CMS\n\n> Auto-generated by [BetterStart CLI](https://github.com/betterstart/cli).\n> Regenerated on each \\`betterstart init\\`.`)\n\n // Preset\n if (options.preset) {\n sections.push(`## Preset\n\nThis project was initialized with the **${options.preset}** preset.`)\n }\n\n // Directory structure\n sections.push(`## Directory Structure\n\n| Path | Description |\n|------|-------------|\n| \\`cms/\\` | All CMS source code (you own this) |\n| \\`cms/schemas/\\` | Entity JSON schemas |\n| \\`cms/schemas/forms/\\` | Form JSON schemas |\n| \\`cms/db/\\` | Database client, schema, drizzle config |\n| \\`cms/lib/actions/\\` | Server actions (CRUD) |\n| \\`cms/lib/auth/\\` | Better Auth configuration |\n| \\`cms/lib/cache/\\` | Cache tags, queries, revalidation |\n| \\`cms/lib/emails/\\` | React Email templates |\n| \\`cms/hooks/\\` | React Query hooks |\n| \\`cms/components/\\` | UI components (shadcn-style) |\n| \\`cms/utils/\\` | Utility functions |\n| \\`${config.paths.pages}/\\` | Admin pages (auth-gated) |\n| \\`${config.paths.login}/\\` | Login page |\n| \\`${config.paths.api}/\\` | CMS API routes |`)\n\n // Generated content\n if (\n (options.schemas && options.schemas.length > 0) ||\n (options.forms && options.forms.length > 0)\n ) {\n const lines: string[] = ['## Generated Content', '']\n if (options.schemas && options.schemas.length > 0) {\n lines.push('### Entities')\n for (const s of options.schemas) {\n lines.push(`- **${s}** — \\`cms/schemas/${s}.json\\` → admin at \\`/cms/${s}\\``)\n }\n }\n if (options.forms && options.forms.length > 0) {\n lines.push('')\n lines.push('### Forms')\n for (const f of options.forms) {\n lines.push(`- **${f}** — \\`cms/schemas/forms/${f}.json\\` → admin at \\`/cms/forms/${f}\\``)\n }\n }\n sections.push(lines.join('\\n'))\n }\n\n // Commands\n sections.push(`## Commands\n\n\\`\\`\\`bash\n# Generate entity CRUD from a schema\nnpx betterstart generate <schema-name>\n\n# Generate with force overwrite\nnpx betterstart generate <schema-name> --force\n\n# Remove all generated files for an entity/form\nnpx betterstart remove <schema-name>\n\n# Create initial admin user\nnpx betterstart seed\n\\`\\`\\``)\n\n // Schema format\n sections.push(`## Schema Format\n\n### Entity Schema (\\`cms/schemas/<name>.json\\`)\n\n\\`\\`\\`json\n{\n \"name\": \"posts\",\n \"label\": \"Posts\",\n \"icon\": \"FileText\",\n \"fields\": [\n { \"name\": \"title\", \"type\": \"string\", \"label\": \"Title\", \"required\": true },\n { \"name\": \"content\", \"type\": \"richtext\", \"label\": \"Content\" }\n ]\n}\n\\`\\`\\`\n\nField types: \\`string\\`, \\`text\\`, \\`richtext\\`, \\`number\\`, \\`boolean\\`, \\`date\\`, \\`image\\`, \\`select\\`, \\`relationship\\`.\n\n### Form Schema (\\`cms/schemas/forms/<name>.json\\`)\n\n\\`\\`\\`json\n{\n \"name\": \"contact\",\n \"label\": \"Contact Form\",\n \"submitButtonText\": \"Send Message\",\n \"fields\": [\n { \"name\": \"email\", \"type\": \"email\", \"label\": \"Email\", \"required\": true },\n { \"name\": \"message\", \"type\": \"textarea\", \"label\": \"Message\", \"required\": true }\n ]\n}\n\\`\\`\\`\n\nField types: \\`text\\`, \\`textarea\\`, \\`email\\`, \\`phone\\`, \\`number\\`, \\`url\\`, \\`date\\`, \\`select\\`, \\`radio\\`, \\`checkbox\\`, \\`multiselect\\`, \\`file\\`.`)\n\n // Path aliases\n sections.push(`## Path Aliases\n\n| Alias | Resolves to |\n|-------|-------------|\n| \\`@cms/*\\` | \\`${config.paths.cms}/*\\` |`)\n\n // Environment variables\n sections.push(`## Environment Variables\n\nRequired variables in \\`.env.local\\`:\n\n| Variable | Description |\n|----------|-------------|\n| \\`BETTERSTART_DATABASE_URL\\` | PostgreSQL connection string |\n| \\`BETTERSTART_AUTH_SECRET\\` | Auth secret (\\`openssl rand -base64 32\\`) |\n| \\`BETTERSTART_AUTH_URL\\` | App URL (e.g. \\`http://localhost:3000\\`) |\n| \\`BETTERSTART_R2_*\\` | Cloudflare R2 storage credentials |\n| \\`BETTERSTART_RESEND_API_KEY\\` | Resend API key (if email enabled) |\n| \\`NOTIFICATION_EMAIL\\` | Fallback notification email address |`)\n\n // Configuration\n sections.push(`## Configuration\n\nEdit \\`cms.config.ts\\` to customize paths, database provider, and features.`)\n\n return `${sections.join('\\n\\n')}\\n`\n}\n","/**\n * Biome scaffolder: creates biome.json if no existing linter is detected\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { LinterInfo } from '../../utils/detect.js'\n\nexport interface BiomeScaffoldResult {\n /** Whether Biome was set up */\n installed: boolean\n /** Reason it was skipped (if any) */\n skippedReason: string | null\n}\n\n/**\n * Create biome.json config if no linter exists.\n * Does NOT install the package — the dependency installer (task 5.05) handles that.\n */\nexport function scaffoldBiome(cwd: string, linter: LinterInfo): BiomeScaffoldResult {\n if (linter.type !== 'none') {\n return {\n installed: false,\n skippedReason: `${linter.type} already configured (${linter.configFile})`\n }\n }\n\n const configPath = path.join(cwd, 'biome.json')\n if (fs.existsSync(configPath)) {\n return { installed: false, skippedReason: 'biome.json already exists' }\n }\n\n const config = {\n $schema: 'https://biomejs.dev/schemas/1.9.4/schema.json',\n vcs: {\n enabled: true,\n clientKind: 'git',\n useIgnoreFile: true\n },\n organizeImports: {\n enabled: true\n },\n formatter: {\n enabled: true,\n indentStyle: 'space',\n indentWidth: 2,\n lineWidth: 100\n },\n linter: {\n enabled: true,\n rules: {\n recommended: true,\n correctness: {\n noUnusedImports: 'warn',\n noUnusedVariables: 'warn'\n },\n style: {\n noNonNullAssertion: 'off'\n }\n }\n },\n javascript: {\n formatter: {\n quoteStyle: 'single',\n trailingCommas: 'all',\n semicolons: 'asNeeded'\n }\n },\n files: {\n ignore: [\n 'node_modules',\n '.next',\n 'dist',\n 'build',\n '*.config.js',\n '*.config.mjs',\n '*.config.cjs'\n ]\n }\n }\n\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, 'utf-8')\n return { installed: true, skippedReason: null }\n}\n","import path from 'node:path'\nimport fs from 'fs-extra'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { detectProjectName } from '../../utils/detect.js'\nimport { safeWriteFile } from '../../utils/fs.js'\n// CSS\nimport { cmsGlobalsCssTemplate } from '../templates/components/cms-globals.js'\n// Data table components\nimport { dataTableTemplate } from '../templates/components/data-table/data-table.js'\nimport { dataTablePaginationTemplate } from '../templates/components/data-table/data-table-pagination.js'\nimport { dataTableToolbarTemplate } from '../templates/components/data-table/data-table-toolbar.js'\n// Layout components\nimport { cmsHeaderTemplate } from '../templates/components/layout/cms-header.js'\nimport { cmsNavLinkTemplate } from '../templates/components/layout/cms-nav-link.js'\nimport { cmsProvidersTemplate } from '../templates/components/layout/cms-providers.js'\nimport { cmsSearchTemplate } from '../templates/components/layout/cms-search.js'\nimport { cmsSidebarTemplate } from '../templates/components/layout/cms-sidebar.js'\n// Shared components\nimport { deleteDialogTemplate } from '../templates/components/shared/delete-dialog.js'\nimport { pageHeaderTemplate } from '../templates/components/shared/page-header.js'\nimport { statusBadgeTemplate } from '../templates/components/shared/status-badge.js'\n// Data\nimport { cmsDataTemplate } from '../templates/data/cms.js'\nimport { navigationDataTemplate } from '../templates/data/navigation.js'\nimport { useCmsThemeTemplate } from '../templates/hooks/use-cms-theme.js'\n// Hooks\nimport { useEditorImageUploadHookTemplate } from '../templates/hooks/use-editor-image-upload.js'\nimport { useLocalStorageHookTemplate } from '../templates/hooks/use-local-storage.js'\nimport { useMobileHookTemplate } from '../templates/hooks/use-mobile.js'\nimport { useUploadHookTemplate } from '../templates/hooks/use-upload.js'\nimport { useUsersHookTemplate } from '../templates/hooks/use-users.js'\nimport { formSettingsActionTemplate } from '../templates/lib/actions/form-settings.js'\nimport { uploadActionTemplate } from '../templates/lib/actions/upload.js'\nimport { usersActionTemplate } from '../templates/lib/actions/users.js'\nimport { markdownCachedTemplate } from '../templates/lib/markdown/cached.js'\nimport { markdownFormatTemplate } from '../templates/lib/markdown/format.js'\n// Markdown\nimport { markdownRenderTemplate } from '../templates/lib/markdown/render.js'\n// Lib\nimport { r2ClientTemplate } from '../templates/lib/r2.js'\n// Types\nimport { authTypesTemplate } from '../templates/types/auth.js'\nimport { typesIndexTemplate } from '../templates/types/index.js'\nimport { tableMetaTypesTemplate } from '../templates/types/table-meta.js'\n// Utils\nimport { cnUtilTemplate } from '../templates/utils/cn.js'\nimport { seoUtilTemplate } from '../templates/utils/seo.js'\nimport { validationUtilTemplate } from '../templates/utils/validation.js'\nimport { webhookUtilTemplate } from '../templates/utils/webhook.js'\nimport { mailchimpUtilTemplate } from '../templates/utils/mailchimp.js'\n\nexport interface ComponentScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Copy all CMS components, hooks, types, utils, data, and lib code into the project.\n */\nexport function scaffoldComponents({ cwd, config }: ComponentScaffoldOptions): string[] {\n const cms = path.resolve(cwd, config.paths.cms)\n const created: string[] = []\n\n function write(relPath: string, content: string): void {\n const fullPath = path.join(cms, relPath)\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.cms, relPath))\n }\n }\n\n // --- CSS ---\n write('cms-globals.css', cmsGlobalsCssTemplate())\n\n // --- Components: layout ---\n write('components/layout/cms-providers.tsx', cmsProvidersTemplate())\n write('components/layout/cms-nav-link.tsx', cmsNavLinkTemplate())\n write('components/layout/cms-sidebar.tsx', cmsSidebarTemplate())\n write('components/layout/cms-header.tsx', cmsHeaderTemplate())\n write('components/layout/cms-search.tsx', cmsSearchTemplate())\n // --- Components: shared ---\n write('components/shared/page-header.tsx', pageHeaderTemplate())\n write('components/shared/delete-dialog.tsx', deleteDialogTemplate())\n write('components/shared/status-badge.tsx', statusBadgeTemplate())\n\n // --- Components: data-table ---\n write('components/data-table/data-table.tsx', dataTableTemplate())\n write('components/data-table/data-table-pagination.tsx', dataTablePaginationTemplate())\n write('components/data-table/data-table-toolbar.tsx', dataTableToolbarTemplate())\n\n // --- Components: ui (raw file copy) ---\n const uiCreated = copyUiTemplates(cwd, config)\n created.push(...uiCreated)\n\n // --- Components: ui/tiptap (recursive copy) ---\n const tiptapCreated = copyTiptapTemplates(cwd, config)\n created.push(...tiptapCreated)\n\n // --- Types ---\n write('types/index.ts', typesIndexTemplate())\n write('types/auth.ts', authTypesTemplate())\n write('types/table-meta.ts', tableMetaTypesTemplate())\n\n // --- Utils ---\n write('utils/cn.ts', cnUtilTemplate())\n write('utils/seo.ts', seoUtilTemplate())\n write('utils/validation.ts', validationUtilTemplate())\n write('utils/webhook.ts', webhookUtilTemplate())\n write('utils/mailchimp.ts', mailchimpUtilTemplate())\n\n // --- Hooks ---\n write('hooks/use-upload.ts', useUploadHookTemplate())\n write('hooks/use-editor-image-upload.ts', useEditorImageUploadHookTemplate())\n write('hooks/use-local-storage.ts', useLocalStorageHookTemplate())\n write('hooks/use-cms-theme.tsx', useCmsThemeTemplate())\n write('hooks/use-users.ts', useUsersHookTemplate())\n write('hooks/use-mobile.ts', useMobileHookTemplate())\n\n // --- Data ---\n const projectName = detectProjectName(cwd)\n write('data/cms.ts', cmsDataTemplate(projectName))\n write('data/navigation.ts', navigationDataTemplate())\n\n // --- Lib ---\n write('lib/r2.ts', r2ClientTemplate())\n write('lib/actions/form-settings.ts', formSettingsActionTemplate())\n write('lib/actions/upload.ts', uploadActionTemplate())\n write('lib/actions/users.ts', usersActionTemplate())\n\n // --- Markdown ---\n write('lib/markdown/render.ts', markdownRenderTemplate())\n write('lib/markdown/format.ts', markdownFormatTemplate())\n write('lib/markdown/cached.ts', markdownCachedTemplate())\n\n // --- Schema metaschema ---\n const schemaCreated = copySchemaMetaschema(cwd, config)\n created.push(...schemaCreated)\n\n return created\n}\n\n/**\n * Copy raw .tsx UI component files from the CLI's templates/ui/ directory.\n */\nfunction copyUiTemplates(cwd: string, config: BetterstartConfig): string[] {\n const created: string[] = []\n const destDir = path.resolve(cwd, config.paths.cms, 'components', 'ui')\n\n // Resolve the templates/ui/ directory relative to the CLI package root.\n // When built, this file is at dist/cli.js, so we go up to the package root.\n const cliRoot = findCliRoot()\n const srcDir = path.join(cliRoot, 'templates', 'ui')\n\n if (!fs.existsSync(srcDir)) {\n return created\n }\n\n const files = fs\n .readdirSync(srcDir)\n .filter((f: string) => f.endsWith('.tsx') || f.endsWith('.ts'))\n\n for (const file of files) {\n const destPath = path.join(destDir, file)\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(path.join(srcDir, file), destPath)\n created.push(path.join(config.paths.cms, 'components', 'ui', file))\n }\n }\n\n return created\n}\n\n/**\n * Recursively copy the TipTap editor directory from templates/tiptap/ → cms/components/ui/tiptap/.\n */\nfunction copyTiptapTemplates(cwd: string, config: BetterstartConfig): string[] {\n const created: string[] = []\n const cliRoot = findCliRoot()\n const srcDir = path.join(cliRoot, 'templates', 'tiptap')\n const destDir = path.resolve(cwd, config.paths.cms, 'components', 'ui', 'tiptap')\n\n if (!fs.existsSync(srcDir)) {\n return created\n }\n\n copyDirRecursive(srcDir, destDir, config.paths.cms, created)\n return created\n}\n\nfunction copyDirRecursive(src: string, dest: string, cmsPrefix: string, created: string[]): void {\n fs.ensureDirSync(dest)\n const entries = fs.readdirSync(src, { withFileTypes: true })\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath, cmsPrefix, created)\n } else if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath)\n // Build relative path from cms root for reporting\n const relFromCms = path.relative(path.resolve(dest, '..', '..', '..', '..'), destPath)\n created.push(relFromCms)\n }\n }\n}\n\n/**\n * Copy schema.json metaschema into cms/schemas/ so users get IDE validation.\n */\nfunction copySchemaMetaschema(cwd: string, config: BetterstartConfig): string[] {\n const created: string[] = []\n const cliRoot = findCliRoot()\n const srcPath = path.join(cliRoot, 'templates', 'schema.json')\n const destPath = path.resolve(cwd, config.paths.schemas, 'schema.json')\n\n if (fs.existsSync(srcPath) && !fs.existsSync(destPath)) {\n fs.ensureDirSync(path.dirname(destPath))\n fs.copyFileSync(srcPath, destPath)\n created.push(path.join(config.paths.schemas, 'schema.json'))\n }\n\n return created\n}\n\n/**\n * Find the CLI package root by looking for package.json with our name.\n */\nfunction findCliRoot(): string {\n // __dirname equivalent for ESM: walk up from this file's location\n let dir = new URL('.', import.meta.url).pathname\n for (let i = 0; i < 5; i++) {\n const pkgPath = path.join(dir, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (pkg.name === '@betterstart/cli') {\n return dir\n }\n } catch {\n // continue\n }\n }\n dir = path.dirname(dir)\n }\n // Fallback: assume 2 levels up from dist/\n return path.resolve(new URL('.', import.meta.url).pathname, '..', '..')\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport type LinterType = 'eslint' | 'biome' | 'none'\n\nexport interface LinterInfo {\n /** Detected linter type */\n type: LinterType\n /** Config file found (if any) */\n configFile: string | null\n}\n\nexport interface ProjectInfo {\n /** Whether this is an existing Next.js project */\n isExisting: boolean\n /** Whether the project uses a src/ directory */\n hasSrcDir: boolean\n /** Whether TypeScript is configured */\n hasTypeScript: boolean\n /** Whether Tailwind CSS is configured */\n hasTailwind: boolean\n /** Detected linter info */\n linter: LinterInfo\n /** Conflicts found that would block init */\n conflicts: string[]\n}\n\nconst NEXT_CONFIG_FILES = ['next.config.ts', 'next.config.js', 'next.config.mjs']\n\nexport function detectProjectName(cwd: string): string {\n const pkgPath = path.join(cwd, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (typeof pkg.name === 'string' && pkg.name.length > 0) {\n return formatProjectName(pkg.name)\n }\n } catch {\n /* ignore */\n }\n }\n return formatProjectName(path.basename(cwd))\n}\n\nfunction formatProjectName(name: string): string {\n const base = name.includes('/') ? name.split('/').pop()! : name\n return base\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, (c) => c.toUpperCase())\n .trim()\n}\n\nexport function detectProject(cwd: string): ProjectInfo {\n const isExisting = NEXT_CONFIG_FILES.some((f) => fs.existsSync(path.join(cwd, f)))\n\n const hasSrcDir = fs.existsSync(path.join(cwd, 'src'))\n\n const hasTypeScript =\n fs.existsSync(path.join(cwd, 'tsconfig.json')) ||\n fs.existsSync(path.join(cwd, 'tsconfig.app.json'))\n\n const hasTailwind = detectTailwind(cwd)\n const linter = detectLinter(cwd)\n\n const conflicts: string[] = []\n if (isExisting) {\n if (fs.existsSync(path.join(cwd, 'cms'))) {\n conflicts.push('cms/ directory already exists')\n }\n if (fs.existsSync(path.join(cwd, 'cms.config.ts'))) {\n conflicts.push('cms.config.ts already exists')\n }\n\n const appBase = hasSrcDir ? 'src/app' : 'app'\n if (fs.existsSync(path.join(cwd, appBase, '(cms)'))) {\n conflicts.push(`${appBase}/(cms)/ route group already exists`)\n }\n\n if (hasTsconfigCmsAliases(cwd)) {\n conflicts.push('@cms/* path aliases already exist in tsconfig.json')\n }\n\n if (hasEnvBetterstartVars(cwd)) {\n conflicts.push('BETTERSTART_* variables already exist in .env.local')\n }\n }\n\n return { isExisting, hasSrcDir, hasTypeScript, hasTailwind, linter, conflicts }\n}\n\n// ============================================================================\n// Linter Detection\n// ============================================================================\n\nconst BIOME_CONFIG_FILES = ['biome.json', 'biome.jsonc']\n\nconst ESLINT_CONFIG_FILES = [\n 'eslint.config.js',\n 'eslint.config.mjs',\n 'eslint.config.cjs',\n 'eslint.config.ts',\n '.eslintrc.json',\n '.eslintrc.js',\n '.eslintrc.cjs',\n '.eslintrc.yml',\n '.eslintrc.yaml',\n '.eslintrc'\n]\n\nexport function detectLinter(cwd: string): LinterInfo {\n // Check for Biome first (preferred)\n for (const f of BIOME_CONFIG_FILES) {\n if (fs.existsSync(path.join(cwd, f))) {\n return { type: 'biome', configFile: f }\n }\n }\n\n // Check for ESLint config files\n for (const f of ESLINT_CONFIG_FILES) {\n if (fs.existsSync(path.join(cwd, f))) {\n return { type: 'eslint', configFile: f }\n }\n }\n\n // Check package.json for eslintConfig field\n const pkgPath = path.join(cwd, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (pkg.eslintConfig) {\n return { type: 'eslint', configFile: 'package.json (eslintConfig)' }\n }\n } catch {\n // ignore parse errors\n }\n }\n\n return { type: 'none', configFile: null }\n}\n\n// ============================================================================\n// Tailwind Detection\n// ============================================================================\n\nfunction detectTailwind(cwd: string): boolean {\n // Tailwind v4: check for CSS files with @import \"tailwindcss\" or @theme\n const cssFiles = ['globals.css', 'app.css', 'index.css'].flatMap((f) => [\n path.join(cwd, 'src', 'app', f),\n path.join(cwd, 'app', f),\n path.join(cwd, 'src', f),\n path.join(cwd, f)\n ])\n\n for (const cssFile of cssFiles) {\n if (fs.existsSync(cssFile)) {\n const content = fs.readFileSync(cssFile, 'utf-8')\n if (\n content.includes('@import \"tailwindcss\"') ||\n content.includes(\"@import 'tailwindcss'\") ||\n content.includes('@theme')\n ) {\n return true\n }\n }\n }\n\n // Also check postcss.config for tailwindcss plugin (v3 style)\n const postcssFiles = ['postcss.config.js', 'postcss.config.mjs', 'postcss.config.cjs']\n for (const f of postcssFiles) {\n if (fs.existsSync(path.join(cwd, f))) {\n const content = fs.readFileSync(path.join(cwd, f), 'utf-8')\n if (content.includes('tailwindcss') || content.includes('@tailwindcss')) {\n return true\n }\n }\n }\n\n return false\n}\n\nfunction hasTsconfigCmsAliases(cwd: string): boolean {\n const tsconfigPath = path.join(cwd, 'tsconfig.json')\n if (!fs.existsSync(tsconfigPath)) return false\n\n try {\n const content = fs.readFileSync(tsconfigPath, 'utf-8')\n return content.includes('@cms/')\n } catch {\n return false\n }\n}\n\nfunction hasEnvBetterstartVars(cwd: string): boolean {\n const envPath = path.join(cwd, '.env.local')\n if (!fs.existsSync(envPath)) return false\n\n try {\n const content = fs.readFileSync(envPath, 'utf-8')\n return content.includes('BETTERSTART_')\n } catch {\n return false\n }\n}\n","/**\n * Template: cms/cms-globals.css\n * CMS-scoped styles: tokens under .cms-root, @layer cms\n * Does NOT import Tailwind — the host app already does.\n */\nexport function cmsGlobalsCssTemplate(): string {\n return `@import \"tailwindcss\";\n@import \"tw-animate-css\";\n@import \"shadcn/tailwind.css\";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --font-sans: var(--font-sans);\n --font-mono: var(--font-geist-mono);\n --color-sidebar-ring: var(--sidebar-ring);\n --color-sidebar-border: var(--sidebar-border);\n --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);\n --color-sidebar-accent: var(--sidebar-accent);\n --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);\n --color-sidebar-primary: var(--sidebar-primary);\n --color-sidebar-foreground: var(--sidebar-foreground);\n --color-sidebar: var(--sidebar);\n --color-chart-5: var(--chart-5);\n --color-chart-4: var(--chart-4);\n --color-chart-3: var(--chart-3);\n --color-chart-2: var(--chart-2);\n --color-chart-1: var(--chart-1);\n --color-ring: var(--ring);\n --color-input: var(--input);\n --color-border: var(--border);\n --color-destructive: var(--destructive);\n --color-accent-foreground: var(--accent-foreground);\n --color-accent: var(--accent);\n --color-muted-foreground: var(--muted-foreground);\n --color-muted: var(--muted);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-secondary: var(--secondary);\n --color-primary-foreground: var(--primary-foreground);\n --color-primary: var(--primary);\n --color-popover-foreground: var(--popover-foreground);\n --color-popover: var(--popover);\n --color-card-foreground: var(--card-foreground);\n --color-card: var(--card);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n --radius-2xl: calc(var(--radius) + 8px);\n --radius-3xl: calc(var(--radius) + 12px);\n --radius-4xl: calc(var(--radius) + 16px);\n}\n\n:root {\n --background: oklch(1 0 0);\n --foreground: oklch(0.141 0.005 285.823);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.141 0.005 285.823);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.141 0.005 285.823);\n --primary: oklch(0.21 0.006 285.885);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.967 0.001 286.375);\n --secondary-foreground: oklch(0.21 0.006 285.885);\n --muted: oklch(0.967 0.001 286.375);\n --muted-foreground: oklch(0.552 0.016 285.938);\n --accent: oklch(0.967 0.001 286.375);\n --accent-foreground: oklch(0.21 0.006 285.885);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.92 0.004 286.32);\n --input: oklch(0.92 0.004 286.32);\n --ring: oklch(0.705 0.015 286.067);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n --radius: 0.625rem;\n --sidebar: oklch(0.985 0 0);\n --sidebar-foreground: oklch(0.141 0.005 285.823);\n --sidebar-primary: oklch(0.21 0.006 285.885);\n --sidebar-primary-foreground: oklch(0.985 0 0);\n --sidebar-accent: oklch(0.967 0.001 286.375);\n --sidebar-accent-foreground: oklch(0.21 0.006 285.885);\n --sidebar-border: oklch(0.92 0.004 286.32);\n --sidebar-ring: oklch(0.705 0.015 286.067);\n}\n\n.dark {\n --background: oklch(0.141 0.005 285.823);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.21 0.006 285.885);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.21 0.006 285.885);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.92 0.004 286.32);\n --primary-foreground: oklch(0.21 0.006 285.885);\n --secondary: oklch(0.274 0.006 286.033);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.274 0.006 286.033);\n --muted-foreground: oklch(0.705 0.015 286.067);\n --accent: oklch(0.274 0.006 286.033);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.552 0.016 285.938);\n --chart-1: oklch(0.488 0.243 264.376);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n --sidebar: oklch(0.21 0.006 285.885);\n --sidebar-foreground: oklch(0.985 0 0);\n --sidebar-primary: oklch(0.488 0.243 264.376);\n --sidebar-primary-foreground: oklch(0.985 0 0);\n --sidebar-accent: oklch(0.274 0.006 286.033);\n --sidebar-accent-foreground: oklch(0.985 0 0);\n --sidebar-border: oklch(1 0 0 / 10%);\n --sidebar-ring: oklch(0.552 0.016 285.938);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground;\n }\n}\n\n/* Editor styles */\n.cms-root .tiptap {\n outline: none;\n}\n\n.cms-root .tiptap p.is-editor-empty:first-child::before {\n color: var(--muted-foreground);\n content: attr(data-placeholder);\n float: left;\n height: 0;\n pointer-events: none;\n}\n\n/* Date picker overrides */\n.cms-root .rdp {\n --rdp-accent-color: var(--primary);\n}\n\n/* Toast overrides */\n.cms-root [data-sonner-toaster] {\n font-family: inherit;\n}\n`\n}\n","/**\n * Template: cms/components/data-table/data-table.tsx\n * Generic reusable data table built on TanStack Table\n */\nexport function dataTableTemplate(): string {\n return `'use client'\n\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@cms/components/ui/table'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport { DataTablePagination } from './data-table-pagination'\n\ninterface DataTableProps<TData, TValue> {\n columns: ColumnDef<TData, TValue>[]\n data: TData[]\n isPending?: boolean\n error?: Error | null\n emptyMessage?: string\n loadingMessage?: string\n selectedIds?: number[]\n onSelectedIdsChange?: (ids: number[]) => void\n meta?: Record<string, unknown>\n getId?: (row: TData) => number\n}\n\nexport function DataTable<TData, TValue>({\n columns,\n data,\n isPending = false,\n error = null,\n emptyMessage = 'No results found.',\n loadingMessage = 'Loading...',\n selectedIds,\n onSelectedIdsChange,\n meta,\n getId = (row) => (row as { id: number }).id,\n}: DataTableProps<TData, TValue>) {\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0))\n const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(20))\n\n const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize\n\n // Convert selectedIds to rowSelection object\n const rowSelection = React.useMemo(() => {\n if (!selectedIds) return {}\n const selection: Record<string, boolean> = {}\n data.forEach((row, index) => {\n if (selectedIds.includes(getId(row))) {\n selection[index.toString()] = true\n }\n })\n return selection\n }, [selectedIds, data, getId])\n\n const handleRowSelectionChange = React.useCallback(\n (\n updater:\n | Record<string, boolean>\n | ((old: Record<string, boolean>) => Record<string, boolean>),\n ) => {\n if (!onSelectedIdsChange) return\n const newSelection = typeof updater === 'function' ? updater(rowSelection) : updater\n const newIds = Object.keys(newSelection)\n .filter((key) => newSelection[key])\n .map((key) => getId(data[Number.parseInt(key, 10)]))\n .filter(Boolean)\n onSelectedIdsChange(newIds)\n },\n [data, rowSelection, onSelectedIdsChange, getId],\n )\n\n const handlePaginationChange = React.useCallback(\n (\n updater:\n | { pageIndex: number; pageSize: number }\n | ((old: { pageIndex: number; pageSize: number }) => {\n pageIndex: number\n pageSize: number\n }),\n ) => {\n const current = { pageIndex, pageSize: effectivePageSize }\n const next = typeof updater === 'function' ? updater(current) : updater\n React.startTransition(() => {\n setPageIndex(next.pageIndex)\n })\n },\n [pageIndex, effectivePageSize, setPageIndex],\n )\n\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n onRowSelectionChange: selectedIds ? handleRowSelectionChange : undefined,\n onPaginationChange: handlePaginationChange,\n meta,\n state: {\n sorting,\n columnFilters,\n columnVisibility,\n rowSelection,\n pagination: {\n pageIndex,\n pageSize: effectivePageSize,\n },\n },\n })\n\n return (\n <div className=\"space-y-6\">\n <div className=\"bg-card border overflow-hidden rounded-lg corner-squircle\">\n <Table>\n <TableHeader className=\"bg-secondary\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-muted-foreground\">{loadingMessage}</div>\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-destructive\">Error: {error.message}</div>\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n {emptyMessage}\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n\n <DataTablePagination table={table} pageSize={pageSize} setPageSize={setPageSize} />\n </div>\n )\n}\n\nexport type { DataTableProps }\n`\n}\n","/**\n * Template: cms/components/data-table/data-table-pagination.tsx\n * Pagination controls for data tables\n */\nexport function dataTablePaginationTemplate(): string {\n return `'use client'\n\nimport { Button } from '@cms/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\nimport type { Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nconst PAGE_SIZE_OPTIONS = [\n { value: '10', label: '10' },\n { value: '20', label: '20' },\n { value: '50', label: '50' },\n { value: '100', label: '100' },\n { value: 'all', label: 'All' },\n]\n\ninterface DataTablePaginationProps<TData> {\n table: Table<TData>\n pageSize: number\n setPageSize: (value: number | null) => void\n}\n\nexport function DataTablePagination<TData>({\n table,\n pageSize,\n setPageSize,\n}: DataTablePaginationProps<TData>) {\n const handlePageSizeChange = React.useCallback(\n (value: string) => {\n React.startTransition(() => {\n if (value === 'all') {\n setPageSize(-1)\n } else {\n setPageSize(Number(value))\n }\n table.setPageIndex(0)\n })\n },\n [setPageSize, table],\n )\n\n return (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Rows per page</span>\n <Select\n value={pageSize === -1 ? 'all' : String(pageSize)}\n onValueChange={handlePageSizeChange}\n >\n <SelectTrigger className=\"w-[100px] h-8\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PAGE_SIZE_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center space-x-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n >\n Previous\n </Button>\n <div className=\"text-sm text-muted-foreground\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount() || 1}\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n >\n Next\n </Button>\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Template: cms/components/data-table/data-table-toolbar.tsx\n * Reusable toolbar with search, reorder controls, and action slots\n */\nexport function dataTableToolbarTemplate(): string {\n return `'use client'\n\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport { ArrowUpDown, Save, Search } from 'lucide-react'\nimport type * as React from 'react'\nimport { useFormStatus } from 'react-dom'\n\nfunction SearchButton() {\n const { pending } = useFormStatus()\n return (\n <Button type=\"submit\" variant=\"outline\" size=\"default\" disabled={pending}>\n {pending ? 'Searching...' : 'Search'}\n </Button>\n )\n}\n\ninterface DataTableToolbarProps {\n search: string\n onSearch: (formData: FormData) => void\n searchPlaceholder?: string\n children?: React.ReactNode\n}\n\nexport function DataTableToolbar({\n search,\n onSearch,\n searchPlaceholder = 'Search...',\n children,\n}: DataTableToolbarProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <form action={onSearch} className=\"flex items-center gap-2\">\n <div className=\"relative\">\n <Search className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2\" />\n <Input\n key={search}\n name=\"search\"\n placeholder={searchPlaceholder}\n defaultValue={search}\n className=\"w-64 pl-9\"\n />\n </div>\n <SearchButton />\n </form>\n {children}\n </div>\n )\n}\n\ninterface ReorderControlsProps {\n reorderMode: boolean\n onToggle: () => void\n onSave: () => void\n onCancel: () => void\n hasChanges: boolean\n isSaving: boolean\n}\n\nexport function ReorderControls({\n reorderMode,\n onToggle,\n onSave,\n onCancel,\n hasChanges,\n isSaving,\n}: ReorderControlsProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant={reorderMode ? 'default' : 'outline'}\n size=\"sm\"\n onClick={onToggle}\n disabled={isSaving}\n >\n <ArrowUpDown className=\"size-4 mr-1\" />\n Sort Order\n </Button>\n {reorderMode && (\n <>\n <Button variant=\"default\" size=\"sm\" onClick={onSave} disabled={!hasChanges || isSaving}>\n <Save className=\"size-4 mr-1\" />\n {isSaving ? 'Saving...' : 'Save'}\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={onCancel} disabled={isSaving}>\n Cancel\n </Button>\n {hasChanges && <span className=\"text-sm text-muted-foreground\">Unsaved changes</span>}\n </>\n )}\n </div>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-header.tsx\n * CMS admin header with theme toggle\n */\nexport function cmsHeaderTemplate(): string {\n return `'use client'\n\nimport { Button } from '@cms/components/ui/button'\nimport { SidebarTrigger, useSidebar } from '@cms/components/ui/sidebar'\nimport { useTheme } from '@cms/hooks/use-cms-theme'\nimport { Moon, Sun } from 'lucide-react'\n\nexport function CmsHeader() {\n const { theme, setTheme } = useTheme()\n const { state } = useSidebar()\n\n return (\n <header className=\"flex h-14 shrink-0 items-center gap-2 border-b border-border w-full sticky top-0 z-50\">\n <div className=\"flex items-center px-5 gap-1 flex-1 w-full justify-between\">\n <div className=\"flex items-center gap-2 w-full\">\n {state === 'collapsed' && <SidebarTrigger />}\n </div>\n <div className=\"flex items-center gap-2 ml-auto\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}\n >\n <Sun className=\"size-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n <Moon className=\"absolute size-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n <span className=\"sr-only\">Toggle theme</span>\n </Button>\n </div>\n </div>\n </header>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-nav-link.tsx\n * Client component for sidebar nav links with active state detection\n */\nexport function cmsNavLinkTemplate(): string {\n return `'use client'\n\nimport { SidebarMenuButton } from '@cms/components/ui/sidebar'\nimport Link from 'next/link'\nimport { usePathname } from 'next/navigation'\n\nexport function CmsNavLink({\n href,\n children,\n}: {\n href: string\n children: React.ReactNode\n}) {\n const pathname = usePathname()\n const isActive =\n href === '/cms'\n ? pathname === '/cms'\n : pathname === href || pathname.startsWith(href + '/')\n\n return (\n <SidebarMenuButton asChild isActive={isActive}>\n <Link href={href}>{children}</Link>\n </SidebarMenuButton>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-providers.tsx\n * CMS-scoped providers: QueryClient, CmsThemeProvider, Toaster, NuqsAdapter\n */\nexport function cmsProvidersTemplate(): string {\n return `'use client'\n\nimport { Toaster } from '@cms/components/ui/sonner'\nimport { CmsThemeProvider } from '@cms/hooks/use-cms-theme'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { NuqsAdapter } from 'nuqs/adapters/next/app'\nimport { useState } from 'react'\n\nexport function CmsProviders({ children }: { children: React.ReactNode }) {\n const [queryClient] = useState(\n () =>\n new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n refetchOnReconnect: false,\n },\n },\n }),\n )\n\n return (\n <QueryClientProvider client={queryClient}>\n <CmsThemeProvider>\n <NuqsAdapter>\n {children}\n <Toaster position=\"top-right\" richColors />\n </NuqsAdapter>\n </CmsThemeProvider>\n </QueryClientProvider>\n )\n}\n`\n}\n","/**\n * Template: cms/components/layout/cms-search.tsx\n * CMS admin search on header\n */\nexport function cmsSearchTemplate(): string {\n return `import { Button } from '@cms/components/ui/button'\nimport { Command, Search } from 'lucide-react'\n\nexport const CmsSearch = () => {\n return (\n <div className=\"flex items-center gap-2 relative w-full max-w-[240px]\">\n <Button\n variant=\"outline\"\n className=\"w-full text-left items-center pr-1.5! py-0 rounded-lg bg-white\"\n size=\"lg\"\n >\n <Search className=\"shrink-0 size-3.5 -ml-0.5 text-muted-foreground/70\" />\n <span className=\"w-full font-normal text-sm text-muted-foreground/70 [text-box-trim:trim-both]\">\n Quick search...\n </span>\n <div className=\"flex items-center gap-1 py-0.5 border rounded-full corner-squircle px-2 border-border bg-background\">\n <Command className=\"size-3! text-muted-foreground\" />\n <span className=\"font-mono text-xs font-medium\">K</span>\n </div>\n </Button>\n </div>\n )\n}\n\nCmsSearch.displayName = 'CmsSearch'\n`\n}\n","/**\n * Template: cms/components/layout/cms-sidebar.tsx\n * CMS admin sidebar with grouped navigation\n */\nexport function cmsSidebarTemplate(): string {\n return `import { getSession } from '@cms/auth/middleware'\nimport { Avatar, AvatarFallback, AvatarImage } from '@cms/components/ui/avatar'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuItem,\n} from '@cms/components/ui/sidebar'\nimport { cms } from '@cms/data/cms'\nimport { type CmsNavigationItem, cmsNavigation } from '@cms/data/navigation'\nimport { Settings, Users } from 'lucide-react'\nimport Link from 'next/link'\nimport { Fragment } from 'react'\nimport { getSetting } from '@/cms/lib/actions/settings'\nimport { CmsNavLink } from './cms-nav-link'\nimport { CmsSearch } from './cms-search'\n\nfunction groupNavItems(items: CmsNavigationItem[]) {\n const groups: { label: string | null; items: CmsNavigationItem[] }[] = []\n const groupMap = new Map<string | null, CmsNavigationItem[]>()\n\n for (const item of items) {\n const key = item.group ?? null\n if (!groupMap.has(key)) {\n const arr: CmsNavigationItem[] = []\n groupMap.set(key, arr)\n groups.push({ label: key, items: arr })\n }\n groupMap.get(key)!.push(item)\n }\n\n return groups\n}\n\nexport async function CmsSidebar(props: React.ComponentProps<typeof Sidebar>) {\n const session = await getSession()\n const settings = await getSetting()\n const user = session?.user ?? null\n const groups = groupNavItems(cmsNavigation)\n\n return (\n <Sidebar collapsible=\"icon\" {...props}>\n <SidebarHeader className=\"border-b border-border h-14 items-center flex w-full\">\n <div className=\"flex items-center gap-2 w-full relative h-full\">\n <Link href=\"/cms\" className=\"flex items-center gap-2 w-full\">\n <Avatar className=\"size-8\">\n <AvatarImage src={'/favicon.ico'} />\n <AvatarFallback className=\"text-sm font-semibold text-foreground\">\n {settings?.siteName?.charAt(0) ?? cms.name?.charAt(0)}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex text-foreground items-center gap-1 w-full group-data-[collapsible=icon]:hidden\">\n <span className=\"text-sm font-medium line-clamp-1\">\n {settings?.siteName ?? cms.name}\n </span>\n </div>\n </Link>\n </div>\n </SidebarHeader>\n <SidebarContent>\n <SidebarGroup className=\"pb-1\">\n <CmsSearch />\n </SidebarGroup>\n\n {groups.map((group) => (\n <Fragment key={group.label ?? '_ungrouped'}>\n <SidebarGroup>\n {group.label && <SidebarGroupLabel>{group.label}</SidebarGroupLabel>}\n <SidebarMenu>\n {group.items.map((item) => (\n <SidebarMenuItem key={item.href}>\n <CmsNavLink href={item.href}>\n {item.icon && (\n <item.icon className=\"text-muted-foreground\" absoluteStrokeWidth />\n )}\n <span>{item.label}</span>\n </CmsNavLink>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroup>\n </Fragment>\n ))}\n\n <SidebarGroup className=\"mt-auto\">\n <SidebarMenu>\n <SidebarMenuItem>\n <CmsNavLink href=\"/cms/users\">\n <Users />\n <span>Users</span>\n </CmsNavLink>\n </SidebarMenuItem>\n <SidebarMenuItem>\n <CmsNavLink href=\"/cms/settings\">\n <Settings />\n <span>Settings</span>\n </CmsNavLink>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarGroup>\n </SidebarContent>\n <SidebarFooter>\n {user && (\n <div className=\"flex items-center gap-2 p-2 text-sm\">\n <div className=\"flex-1 truncate\">\n <p className=\"font-medium truncate\">{user.name}</p>\n <p className=\"text-muted-foreground truncate text-xs\">{user.email}</p>\n </div>\n </div>\n )}\n </SidebarFooter>\n </Sidebar>\n )\n}\n`\n}\n","/**\n * Template: cms/components/shared/delete-dialog.tsx\n * Reusable confirmation dialog for delete actions\n */\nexport function deleteDialogTemplate(): string {\n return `'use client'\n\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { Button } from '@cms/components/ui/button'\nimport { Trash2 } from 'lucide-react'\n\ninterface DeleteDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n isPending?: boolean\n title?: string\n description?: string\n trigger?: React.ReactNode\n}\n\nexport function DeleteDialog({\n open,\n onOpenChange,\n onConfirm,\n isPending = false,\n title = 'Are you sure?',\n description = 'This action cannot be undone. This will permanently delete this item.',\n trigger,\n}: DeleteDialogProps) {\n return (\n <AlertDialog open={open} onOpenChange={onOpenChange}>\n {trigger && <AlertDialogTrigger asChild>{trigger}</AlertDialogTrigger>}\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{title}</AlertDialogTitle>\n <AlertDialogDescription>{description}</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n onConfirm()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n\ninterface DeleteButtonProps {\n onClick: () => void\n label?: string\n count?: number\n}\n\nexport function DeleteButton({ onClick, label = 'item', count }: DeleteButtonProps) {\n return (\n <Button variant=\"destructive\" size=\"default\" onClick={onClick}>\n <Trash2 className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Delete {count !== undefined ? \\`\\${count} \\${count === 1 ? label : \\`\\${label}s\\`}\\` : label}\n </Button>\n )\n}\n`\n}\n","/**\n * Template: cms/components/shared/page-header.tsx\n * Simple page header with title and description\n */\nexport function pageHeaderTemplate(): string {\n return `interface PageHeaderProps {\n title: string\n children?: React.ReactNode\n search?: React.ReactNode\n actions?: React.ReactNode\n back?: React.ReactNode\n}\n\nexport function PageHeader({ title, children, search, actions, back }: PageHeaderProps) {\n return (\n <div className=\"grid grid-cols-3 items-center justify-between w-full h-14 px-4 border-b border-border\">\n <div className=\"flex items-center justify-start gap-2 w-full\">{back && back}</div>\n <div className=\"flex items-center justify-center gap-2\">\n <h2 className=\"text-sm font-medium tracking-tight\">{title}</h2>\n </div>\n <div className=\"flex items-center justify-end gap-2\">\n {children && children}\n {search && search}\n {actions && actions}\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Template: cms/components/shared/status-badge.tsx\n * Status badge component for displaying entity states in tables\n */\nexport function statusBadgeTemplate(): string {\n return `import { Badge, type BadgeProps } from '@cms/components/ui/badge'\nimport { cn } from '@cms/utils/cn'\n\ntype StatusVariant = 'default' | 'success' | 'warning' | 'error' | 'info'\n\nconst statusStyles: Record<StatusVariant, string> = {\n default: 'bg-secondary text-secondary-foreground',\n success: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950 dark:text-emerald-300',\n warning: 'bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-300',\n error: 'bg-red-100 text-red-800 dark:bg-red-950 dark:text-red-300',\n info: 'bg-blue-100 text-blue-800 dark:bg-blue-950 dark:text-blue-300',\n}\n\ninterface StatusBadgeProps extends Omit<BadgeProps, 'variant'> {\n status: StatusVariant\n}\n\nexport function StatusBadge({ status, className, ...props }: StatusBadgeProps) {\n return (\n <Badge\n variant=\"outline\"\n className={cn('border-none font-medium', statusStyles[status], className)}\n {...props}\n />\n )\n}\n\n/** Map boolean values to status badges */\nexport function BooleanBadge({\n value,\n trueLabel = 'Yes',\n falseLabel = 'No',\n}: {\n value: boolean\n trueLabel?: string\n falseLabel?: string\n}) {\n return (\n <StatusBadge status={value ? 'success' : 'default'}>\n {value ? trueLabel : falseLabel}\n </StatusBadge>\n )\n}\n`\n}\n","/**\n * Template: cms/data/cms.ts\n * CMS metadata (project name, etc.)\n */\nexport function cmsDataTemplate(projectName: string): string {\n return `export const cms = {\n name: '${projectName}',\n}\n`\n}\n","/**\n * Template: cms/data/navigation.ts\n * CMS sidebar navigation entries — codegen appends to this file\n */\nexport function navigationDataTemplate(): string {\n return `import type { LucideIcon } from 'lucide-react'\nimport { ChartSpline, FileText, House, ImagePlay, Tag } from 'lucide-react'\n\nexport interface CmsNavigationItem {\n label: string\n href: string\n icon?: LucideIcon\n group?: string\n}\n\nexport const cmsNavigation: CmsNavigationItem[] = [\n {\n label: 'Overview',\n href: '/cms',\n icon: House,\n },\n {\n label: 'Analytics',\n href: '/cms/analytics',\n icon: ChartSpline,\n },\n {\n label: 'Media',\n href: '/cms/media',\n icon: ImagePlay,\n },\n {\n label: 'Categories',\n href: '/cms/categories',\n icon: Tag,\n group: 'Blog',\n },\n {\n label: 'Posts',\n href: '/cms/posts',\n icon: FileText,\n group: 'Blog',\n },\n]\n`\n}\n","/**\n * Template: cms/hooks/use-cms-theme.tsx\n * Self-contained CMS theme provider that scopes to .cms-root\n * Replaces next-themes to avoid hydration mismatches on <html>\n */\nexport function useCmsThemeTemplate(): string {\n return `'use client'\n\nimport * as React from 'react'\n\ntype Theme = 'light' | 'dark' | 'system'\n\ninterface ThemeContext {\n theme: Theme\n setTheme: (theme: Theme) => void\n resolvedTheme: 'light' | 'dark'\n}\n\nconst CmsThemeContext = React.createContext<ThemeContext | undefined>(undefined)\n\nconst STORAGE_KEY = 'cms-theme'\n\nfunction getSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light'\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nexport function CmsThemeProvider({ children }: { children: React.ReactNode }) {\n const [theme, setThemeState] = React.useState<Theme>('system')\n const [resolved, setResolved] = React.useState<'light' | 'dark'>('light')\n\n // Read from localStorage on mount\n React.useEffect(() => {\n const stored = localStorage.getItem(STORAGE_KEY) as Theme | null\n if (stored && ['light', 'dark', 'system'].includes(stored)) {\n setThemeState(stored)\n }\n }, [])\n\n // Resolve theme and apply .dark class to .cms-root\n React.useEffect(() => {\n const actual = theme === 'system' ? getSystemTheme() : theme\n setResolved(actual)\n\n const root = document.querySelector('.cms-root')\n if (root) {\n root.classList.toggle('dark', actual === 'dark')\n }\n }, [theme])\n\n // Listen for system theme changes\n React.useEffect(() => {\n if (theme !== 'system') return\n const mq = window.matchMedia('(prefers-color-scheme: dark)')\n const handler = () => {\n const actual = getSystemTheme()\n setResolved(actual)\n const root = document.querySelector('.cms-root')\n if (root) {\n root.classList.toggle('dark', actual === 'dark')\n }\n }\n mq.addEventListener('change', handler)\n return () => mq.removeEventListener('change', handler)\n }, [theme])\n\n const setTheme = React.useCallback((t: Theme) => {\n setThemeState(t)\n localStorage.setItem(STORAGE_KEY, t)\n }, [])\n\n const value = React.useMemo(\n () => ({ theme, setTheme, resolvedTheme: resolved }),\n [theme, setTheme, resolved],\n )\n\n return <CmsThemeContext.Provider value={value}>{children}</CmsThemeContext.Provider>\n}\n\nexport function useTheme(): ThemeContext {\n const ctx = React.useContext(CmsThemeContext)\n if (!ctx) throw new Error('useTheme must be used within CmsThemeProvider')\n return ctx\n}\n`\n}\n","/**\n * Template: cms/hooks/use-editor-image-upload.ts\n * Image upload hook for markdown editor (drag-drop, paste, file picker)\n */\nexport function useEditorImageUploadHookTemplate(): string {\n return `'use client'\n\nimport * as React from 'react'\nimport { useUpload } from './use-upload'\n\nexport interface EditorImageUploadResult {\n url: string\n filename: string\n}\n\nexport interface UseEditorImageUploadOptions {\n onImagesUploaded: (images: EditorImageUploadResult[]) => void\n}\n\nexport function useEditorImageUpload({ onImagesUploaded }: UseEditorImageUploadOptions) {\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n const onImagesUploadedRef = React.useRef(onImagesUploaded)\n onImagesUploadedRef.current = onImagesUploaded\n\n const { upload, progress, mutation } = useUpload({\n accept: 'image/*',\n maxSizeInMB: 10,\n prefix: 'images',\n onSuccess: (result) => {\n if (result.success && result.files) {\n const images: EditorImageUploadResult[] = result.files.map((f) => ({\n url: f.url,\n filename: f.filename,\n }))\n onImagesUploadedRef.current(images)\n }\n },\n })\n\n const isUploading = mutation.isPending\n\n const uploadImages = React.useCallback(\n (files: File[]) => {\n const imageFiles = files.filter((f) => f.type.startsWith('image/'))\n if (imageFiles.length === 0) return\n upload(imageFiles, 'images')\n },\n [upload],\n )\n\n const handleDrop = React.useCallback(\n (e: React.DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n const files = Array.from(e.dataTransfer.files).filter((f) => f.type.startsWith('image/'))\n if (files.length > 0) {\n uploadImages(files)\n }\n },\n [uploadImages],\n )\n\n const openFilePicker = React.useCallback(() => {\n fileInputRef.current?.click()\n }, [])\n\n const handleFileInputChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || [])\n if (files.length > 0) {\n uploadImages(files)\n }\n e.target.value = ''\n },\n [uploadImages],\n )\n\n return {\n uploadImages,\n isUploading,\n progress,\n handleDrop,\n openFilePicker,\n fileInputRef,\n handleFileInputChange,\n }\n}\n`\n}\n","/**\n * Template: cms/hooks/use-local-storage.ts\n * Type-safe localStorage hook with cms- prefix\n */\nexport function useLocalStorageHookTemplate(): string {\n return `import * as React from 'react'\n\nconst CMS_STORAGE_PREFIX = 'cms-'\n\n/** Type-safe wrapper for localStorage operations with cms- prefix. */\nexport function useLocalStorage<T>(key: string) {\n const prefixedKey = CMS_STORAGE_PREFIX + key\n\n const setItem = React.useCallback(\n (value: T) => {\n try {\n localStorage.setItem(prefixedKey, JSON.stringify(value))\n } catch {\n // Silent failure for localStorage access errors\n }\n },\n [prefixedKey],\n )\n\n const getItem = React.useCallback((): T | null => {\n try {\n const stored = localStorage.getItem(prefixedKey)\n return stored ? JSON.parse(stored) : null\n } catch {\n return null\n }\n }, [prefixedKey])\n\n const removeItem = React.useCallback(() => {\n try {\n localStorage.removeItem(prefixedKey)\n } catch {\n // Silent failure for localStorage access errors\n }\n }, [prefixedKey])\n\n const hasItem = React.useCallback((): boolean => {\n try {\n return localStorage.getItem(prefixedKey) !== null\n } catch {\n return false\n }\n }, [prefixedKey])\n\n return { setItem, getItem, removeItem, hasItem }\n}\n`\n}\n","/**\n * Template: cms/hooks/use-mobile.ts\n * Hook to detect mobile viewport using matchMedia\n */\nexport function useMobileHookTemplate(): string {\n return `import * as React from 'react'\n\nconst MOBILE_BREAKPOINT = 768\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)\n\n React.useEffect(() => {\n const mql = window.matchMedia(\\`(max-width: \\${MOBILE_BREAKPOINT - 1}px)\\`)\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n }\n mql.addEventListener('change', onChange)\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n return !!isMobile\n}\n`\n}\n","/**\n * Template: cms/hooks/use-upload.ts\n * File upload hook with validation and progress tracking\n */\nexport function useUploadHookTemplate(): string {\n return `'use client'\n\nimport type { UploadFileResult, UploadProgress } from '@cms/types'\nimport { type FileValidationConfig, validateFiles } from '@cms/utils/validation'\nimport { type UseMutationResult, useMutation } from '@tanstack/react-query'\nimport * as React from 'react'\n\nexport interface UseUploadOptions {\n /** File validation configuration */\n validationConfig?: FileValidationConfig\n /** Accept string (e.g., \"image/*\") */\n accept?: string\n /** Maximum file size in MB */\n maxSizeInMB?: number\n /** Callback fired when upload progress changes */\n onProgress?: (progress: UploadProgress[]) => void\n /** Callback fired when upload succeeds */\n onSuccess?: (result: UploadFileResult) => void\n /** Callback fired when upload fails */\n onError?: (error: Error) => void\n /** Optional prefix for file paths in R2 */\n prefix?: string\n}\n\nexport interface UploadMutationVariables {\n files: File[]\n prefix?: string\n}\n\nexport interface UseUploadReturn {\n mutation: UseMutationResult<UploadFileResult, Error, UploadMutationVariables, unknown>\n progress: UploadProgress[]\n upload: (files: File[], prefix?: string) => void\n validate: (files: File[]) => { valid: boolean; errors: string[] }\n}\n\nfunction parseAcceptTypes(accept: string): string[] {\n return accept\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean)\n}\n\nexport function useUpload(options: UseUploadOptions = {}): UseUploadReturn {\n const {\n validationConfig: providedConfig,\n accept,\n maxSizeInMB,\n onProgress,\n onSuccess,\n onError,\n prefix: defaultPrefix,\n } = options\n\n const validationConfig = React.useMemo<FileValidationConfig>(() => {\n const config: FileValidationConfig = { ...providedConfig }\n\n if (accept) {\n const parsedTypes = parseAcceptTypes(accept)\n if (config.allowedTypes && config.allowedTypes.length > 0) {\n config.allowedTypes = [...config.allowedTypes, ...parsedTypes].filter(\n (v, i, a) => a.indexOf(v) === i,\n )\n } else {\n config.allowedTypes = parsedTypes\n }\n }\n\n if (maxSizeInMB !== undefined) {\n config.maxSizeInBytes = maxSizeInMB * 1024 * 1024\n }\n\n return config\n }, [providedConfig, accept, maxSizeInMB])\n\n const [progress, setProgress] = React.useState<UploadProgress[]>([])\n const [_isPending, startTransition] = React.useTransition()\n\n const mutation = useMutation<UploadFileResult, Error, UploadMutationVariables>({\n mutationFn: async ({ files, prefix = defaultPrefix }) => {\n const initialProgress: UploadProgress[] = files.map((file) => ({\n filename: file.name,\n progress: 0,\n loaded: 0,\n total: file.size,\n }))\n setProgress(initialProgress)\n onProgress?.(initialProgress)\n\n const formData = new FormData()\n if (prefix) {\n formData.append('prefix', prefix)\n }\n\n files.forEach((file, index) => {\n formData.append(\\`file\\${index}\\`, file)\n })\n\n // Simulate progress since server doesn't support streaming\n const progressInterval = setInterval(() => {\n setProgress((prev) =>\n prev.map((p) => {\n const newProgress = Math.min(p.progress + 10, 90)\n return {\n ...p,\n progress: newProgress,\n loaded: Math.floor((p.total * newProgress) / 100),\n }\n }),\n )\n }, 200)\n\n try {\n if (validationConfig?.maxSizeInBytes) {\n formData.append('maxSizeInBytes', validationConfig.maxSizeInBytes.toString())\n }\n if (validationConfig?.allowedTypes?.length) {\n formData.append('allowedTypes', validationConfig.allowedTypes.join(','))\n }\n\n const response = await fetch('/api/cms/upload', {\n method: 'POST',\n body: formData,\n })\n\n const result = (await response.json()) as UploadFileResult\n\n if (result.success) {\n const completeProgress: UploadProgress[] = files.map((file) => ({\n filename: file.name,\n progress: 100,\n loaded: file.size,\n total: file.size,\n }))\n setProgress(completeProgress)\n onProgress?.(completeProgress)\n }\n\n return result\n } finally {\n clearInterval(progressInterval)\n }\n },\n onSuccess: (result) => {\n onSuccess?.(result)\n startTransition(() => {\n setTimeout(() => {\n setProgress([])\n }, 2000)\n })\n },\n onError: (error) => {\n onError?.(error)\n setProgress([])\n },\n })\n\n const upload = React.useCallback(\n (files: File[], prefix?: string) => {\n mutation.mutate({ files, prefix })\n },\n [mutation],\n )\n\n const validate = React.useCallback(\n (files: File[]) => {\n const result = validateFiles(files, validationConfig)\n return {\n valid: result.valid,\n errors: result.errors.map((e) => \\`\\${e.filename}: \\${e.error}\\`),\n }\n },\n [validationConfig],\n )\n\n return { mutation, progress, upload, validate }\n}\n`\n}\n","/**\n * Template: cms/hooks/use-users.ts\n * React Query hook for fetching users\n */\nexport function useUsersHookTemplate(): string {\n return `'use client'\n\nimport { getUsers } from '@cms/actions/users'\nimport type { UsersResponse } from '@cms/types/auth'\nimport { useQuery } from '@tanstack/react-query'\n\nexport function useUsers() {\n return useQuery<UsersResponse>({\n queryKey: ['users'],\n queryFn: () => getUsers(),\n staleTime: 0,\n })\n}\n`\n}\n","/**\n * Template: cms/lib/actions/form-settings.ts\n * Form settings actions — CRUD for per-form webhook/notification configuration\n */\nexport function formSettingsActionTemplate(): string {\n return `'use server'\n\nimport db from '@cms/db'\nimport { formSettings } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\n\nexport interface FormSettingsData {\n id: number\n formName: string\n webhookUrl: string | null\n webhookEnabled: boolean\n notificationEmails: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface UpsertFormSettingsInput {\n webhookUrl?: string | null\n webhookEnabled?: boolean\n notificationEmails?: string | null\n}\n\nexport interface FormSettingsResult {\n success: boolean\n error?: string\n settings?: FormSettingsData\n}\n\nexport async function getFormSettings(formName: string): Promise<FormSettingsData | null> {\n try {\n const [settings] = await db\n .select()\n .from(formSettings)\n .where(eq(formSettings.formName, formName))\n .limit(1)\n return (settings as FormSettingsData) ?? null\n } catch (error) {\n console.error(\\`Error fetching form settings for \\${formName}:\\`, error)\n return null\n }\n}\n\nexport async function upsertFormSettings(\n formName: string,\n data: UpsertFormSettingsInput,\n): Promise<FormSettingsResult> {\n try {\n const existing = await getFormSettings(formName)\n\n if (existing) {\n const [updated] = await db\n .update(formSettings)\n .set({\n ...data,\n updatedAt: new Date().toISOString(),\n })\n .where(eq(formSettings.formName, formName))\n .returning()\n return { success: true, settings: updated as FormSettingsData }\n }\n\n const [created] = await db\n .insert(formSettings)\n .values({\n formName,\n webhookUrl: data.webhookUrl ?? null,\n webhookEnabled: data.webhookEnabled ?? false,\n notificationEmails: data.notificationEmails ?? null,\n })\n .returning()\n return { success: true, settings: created as FormSettingsData }\n } catch (error) {\n console.error(\\`Error upserting form settings for \\${formName}:\\`, error)\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to save form settings',\n }\n }\n}\n\nexport async function getAllFormSettings(): Promise<FormSettingsData[]> {\n try {\n const settings = await db.select().from(formSettings)\n return settings as FormSettingsData[]\n } catch (error) {\n console.error('Error fetching all form settings:', error)\n return []\n }\n}\n\nexport async function testFormWebhook(\n formName: string,\n): Promise<{ success: boolean; error?: string }> {\n try {\n const settings = await getFormSettings(formName)\n if (!settings?.webhookUrl) {\n return { success: false, error: 'No webhook URL configured' }\n }\n\n const formData = new URLSearchParams()\n formData.append('form_name', formName)\n formData.append('test', 'true')\n formData.append('message', 'This is a test webhook from BetterStart')\n formData.append('timestamp', new Date().toISOString())\n\n const response = await fetch(settings.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: formData.toString(),\n })\n\n if (!response.ok) {\n return {\n success: false,\n error: \\`Webhook returned status \\${response.status}\\`,\n }\n }\n\n return { success: true }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to send test webhook',\n }\n }\n}\n`\n}\n","/**\n * Template: cms/lib/actions/upload.ts\n * File upload action using Cloudflare R2\n */\nexport function uploadActionTemplate(): string {\n return `'use server'\n\nimport { PutObjectCommand } from '@aws-sdk/client-s3'\nimport { BUCKET_NAME, generateFilePath, getPublicUrl, getR2Client } from '@cms/lib/r2'\n\ninterface UploadedFile {\n key: string\n url: string\n filename: string\n size: number\n contentType: string\n}\n\ninterface UploadResult {\n success: boolean\n files?: UploadedFile[]\n error?: string\n}\n\ninterface FileValidationConfig {\n maxFiles?: number\n maxSizeInBytes?: number\n allowedTypes?: string[]\n}\n\n/**\n * Upload multiple files to Cloudflare R2\n */\nexport async function uploadFiles(\n formData: FormData,\n config: FileValidationConfig = {},\n): Promise<UploadResult> {\n try {\n const files: File[] = []\n const prefix = formData.get('prefix')?.toString() || 'uploads'\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File && key.startsWith('file')) {\n files.push(value)\n }\n }\n\n if (files.length === 0) {\n return { success: false, error: 'No files provided' }\n }\n\n if (config.maxFiles && files.length > config.maxFiles) {\n return { success: false, error: \\`Too many files. Maximum is \\${config.maxFiles}\\` }\n }\n\n const uploadedFiles: UploadedFile[] = []\n\n for (const file of files) {\n if (config.maxSizeInBytes && file.size > config.maxSizeInBytes) {\n return { success: false, error: \\`File \\${file.name} exceeds size limit\\` }\n }\n if (config.allowedTypes && !config.allowedTypes.includes(file.type)) {\n return { success: false, error: \\`File type \\${file.type} is not allowed\\` }\n }\n\n const key = generateFilePath(file.name, prefix)\n const arrayBuffer = await file.arrayBuffer()\n const buffer = Buffer.from(arrayBuffer)\n\n const command = new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: key,\n Body: buffer,\n ContentType: file.type,\n ContentLength: file.size,\n })\n\n await getR2Client().send(command)\n\n uploadedFiles.push({\n key,\n url: getPublicUrl(key),\n filename: file.name,\n size: file.size,\n contentType: file.type,\n })\n }\n\n return { success: true, files: uploadedFiles }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to upload files'\n return { success: false, error: message }\n }\n}\n\n/**\n * Upload a single file to Cloudflare R2\n */\nexport async function uploadFile(\n formData: FormData,\n config: FileValidationConfig = {},\n): Promise<UploadResult> {\n return uploadFiles(formData, { ...config, maxFiles: 1 })\n}\n\n/**\n * Upload an image from a URL to Cloudflare R2\n */\nexport async function uploadImageFromUrl(\n imageUrl: string,\n prefix = 'images',\n): Promise<{ success: boolean; url?: string; error?: string }> {\n try {\n const url = new URL(imageUrl)\n if (!['http:', 'https:'].includes(url.protocol)) {\n return { success: false, error: 'Only HTTP and HTTPS URLs are allowed' }\n }\n\n const response = await fetch(imageUrl, {\n headers: { 'User-Agent': 'Mozilla/5.0 (compatible; ImageFetcher/1.0)' },\n signal: AbortSignal.timeout(30000),\n })\n\n if (!response.ok) {\n return { success: false, error: \\`Failed to fetch image: \\${response.status}\\` }\n }\n\n const contentType = response.headers.get('content-type') || 'image/jpeg'\n if (!contentType.startsWith('image/')) {\n return { success: false, error: \\`Invalid content type: \\${contentType}\\` }\n }\n\n const arrayBuffer = await response.arrayBuffer()\n const buffer = Buffer.from(arrayBuffer)\n\n if (buffer.length === 0) return { success: false, error: 'Image file is empty' }\n if (buffer.length > 10 * 1024 * 1024) {\n return { success: false, error: 'Image exceeds 10MB limit' }\n }\n\n const filename = url.pathname.split('/').pop()?.split('?')[0] || 'image.jpg'\n const key = generateFilePath(filename, prefix)\n\n const command = new PutObjectCommand({\n Bucket: BUCKET_NAME,\n Key: key,\n Body: buffer,\n ContentType: contentType,\n ContentLength: buffer.length,\n })\n\n await getR2Client().send(command)\n return { success: true, url: getPublicUrl(key) }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to upload image from URL'\n return { success: false, error: message }\n }\n}\n`\n}\n","/**\n * Template: cms/lib/actions/users.ts\n * User management actions (list, create, update role)\n *\n * Fix #5: Uses Better Auth's built-in createUser API instead of SHA-256 hashing.\n */\nexport function usersActionTemplate(): string {\n return `'use server'\n\nimport { auth } from '@cms/auth'\nimport db from '@cms/db'\nimport { user } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\n\nexport interface UserData {\n id: string\n email: string\n name: string\n emailVerified: boolean\n createdAt: string\n updatedAt: string\n role: string\n}\n\nexport interface UsersResponse {\n users: UserData[]\n total: number\n}\n\nexport interface CreateUserInput {\n email: string\n name: string\n password: string\n}\n\nexport interface CreateUserResult {\n success: boolean\n error?: string\n user?: UserData\n}\n\nexport interface UpdateUserRoleResult {\n success: boolean\n error?: string\n}\n\nexport interface DeleteUserResult {\n success: boolean\n error?: string\n}\n\n/**\n * Create a new user via Better Auth's built-in API\n */\nexport async function createUser(input: CreateUserInput): Promise<CreateUserResult> {\n try {\n const result = await auth.api.signUpEmail({\n body: {\n email: input.email,\n password: input.password,\n name: input.name,\n },\n })\n\n if (!result?.user) {\n return { success: false, error: 'Failed to create user' }\n }\n\n return {\n success: true,\n user: {\n id: result.user.id,\n email: result.user.email,\n name: input.name,\n emailVerified: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n role: 'member',\n },\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to create user',\n }\n }\n}\n\n/**\n * Get all users\n */\nexport async function getUsers(): Promise<UsersResponse> {\n try {\n const users = await db\n .select({\n id: user.id,\n email: user.email,\n name: user.name,\n emailVerified: user.emailVerified,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n role: user.role,\n })\n .from(user)\n .orderBy(user.createdAt)\n\n const userData: UserData[] = users.map((u) => ({\n id: u.id,\n email: u.email,\n name: u.name,\n emailVerified: u.emailVerified,\n createdAt: u.createdAt.toISOString(),\n updatedAt: u.updatedAt.toISOString(),\n role: u.role || 'member',\n }))\n\n return { users: userData, total: userData.length }\n } catch {\n return { users: [], total: 0 }\n }\n}\n\n/**\n * Update a user's role\n */\nexport async function updateUserRole(userId: string, role: string): Promise<UpdateUserRoleResult> {\n try {\n await db.update(user).set({ role, updatedAt: new Date() }).where(eq(user.id, userId))\n\n return { success: true }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to update user role',\n }\n }\n}\n\n/**\n * Delete a user\n */\nexport async function deleteUser(userId: string): Promise<DeleteUserResult> {\n try {\n await db.delete(user).where(eq(user.id, userId))\n return { success: true }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Failed to delete user',\n }\n }\n}\n`\n}\n","/**\n * Template: cms/lib/markdown/cached.ts\n * Cached markdown rendering via Next.js 'use cache'\n */\nexport function markdownCachedTemplate(): string {\n return `'use cache'\n\nimport { renderMarkdownSync } from './render'\n\nexport async function renderMarkdown(src: string): Promise<string> {\n return renderMarkdownSync(src)\n}\n`\n}\n","/**\n * Template: cms/lib/markdown/format.ts\n * Markdown formatting / normalization utility\n */\nexport function markdownFormatTemplate(): string {\n return `/**\n * Format markdown content for consistent styling and readability\n */\nexport function formatMarkdown(content: string): string {\n if (!content || !content.trim()) {\n return ''\n }\n\n let formatted = content\n\n // Normalize line endings\n formatted = formatted.replace(/\\\\r\\\\n/g, '\\\\n')\n\n // Trim trailing whitespace from each line\n formatted = formatted\n .split('\\\\n')\n .map((line) => line.trimEnd())\n .join('\\\\n')\n\n // Normalize multiple blank lines to maximum of 2 (one blank line)\n formatted = formatted.replace(/\\\\n{3,}/g, '\\\\n\\\\n')\n\n // Ensure blank line before headings (unless at start)\n formatted = formatted.replace(/([^\\\\n])\\\\n(#{1,6}\\\\s)/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line after headings\n formatted = formatted.replace(/(#{1,6}\\\\s.*)\\\\n([^\\\\n#])/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line before code blocks\n formatted = formatted.replace(/([^\\\\n])\\\\n(\\`\\`\\`)/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line after code blocks\n formatted = formatted.replace(/(\\`\\`\\`)\\\\n([^\\\\n])/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line before horizontal rules\n formatted = formatted.replace(/([^\\\\n])\\\\n(---+)/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line after horizontal rules\n formatted = formatted.replace(/(---+)\\\\n([^\\\\n])/g, '$1\\\\n\\\\n$2')\n\n // Ensure blank line before blockquotes (unless nested)\n formatted = formatted.replace(/([^\\\\n>])\\\\n(>\\\\s)/g, '$1\\\\n\\\\n$2')\n\n // Normalize list item spacing\n formatted = formatted.replace(/^(\\\\s*)([-*+])\\\\s+/gm, '$1$2 ')\n formatted = formatted.replace(/^(\\\\s*)(\\\\d+\\\\.)\\\\s+/gm, '$1$2 ')\n\n // Remove leading blank lines\n formatted = formatted.replace(/^\\\\n+/, '')\n\n // Ensure single trailing newline\n formatted = \\`\\${formatted.trimEnd()}\\\\n\\`\n\n return formatted\n}\n`\n}\n","/**\n * Template: cms/lib/markdown/render.ts\n * Shiki + KaTeX + heading anchors markdown renderer\n */\nexport function markdownRenderTemplate(): string {\n return `import { transformerNotationDiff, transformerNotationHighlight } from '@shikijs/transformers'\nimport { renderToString } from 'katex'\nimport MarkdownIt from 'markdown-it'\nimport { createHighlighterCoreSync } from 'shiki/core'\nimport { createJavaScriptRegexEngine } from 'shiki/engine/javascript'\nimport css from 'shiki/langs/css.mjs'\nimport go from 'shiki/langs/go.mjs'\nimport javascript from 'shiki/langs/javascript.mjs'\nimport json from 'shiki/langs/json.mjs'\nimport jsx from 'shiki/langs/jsx.mjs'\nimport markdown from 'shiki/langs/markdown.mjs'\nimport python from 'shiki/langs/python.mjs'\nimport rust from 'shiki/langs/rust.mjs'\nimport shellscript from 'shiki/langs/shellscript.mjs'\nimport sql from 'shiki/langs/sql.mjs'\nimport tsx from 'shiki/langs/tsx.mjs'\nimport typescript from 'shiki/langs/typescript.mjs'\nimport yaml from 'shiki/langs/yaml.mjs'\nimport githubDark from 'shiki/themes/github-dark.mjs'\nimport githubLight from 'shiki/themes/github-light.mjs'\n\n// --- Helpers ---\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\\\w\\\\s-]/g, '')\n .replace(/\\\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\nfunction trimMathBlock(content: string): string {\n return content.replace(/\\\\$\\\\$([\\\\s\\\\S]*?)\\\\$\\\\$/g, (_match, mathContent: string) => {\n const trimmed = mathContent.trim()\n if (!trimmed) return '$$\\\\n$$'\n const lines = trimmed.split('\\\\n').filter((line: string) => line.trim().length > 0)\n return \\`$$\\\\n\\${lines.join('\\\\n')}\\\\n$$\\`\n })\n}\n\n// --- Shiki Highlighter ---\n\nconst shiki = createHighlighterCoreSync({\n themes: [githubDark, githubLight],\n langs: [\n javascript,\n typescript,\n jsx,\n tsx,\n python,\n rust,\n go,\n json,\n yaml,\n css,\n sql,\n shellscript,\n markdown,\n ],\n engine: createJavaScriptRegexEngine(),\n})\n\nconst loadedLangs = shiki.getLoadedLanguages()\n\n// --- Heading Anchor Plugin ---\n\nfunction headingAnchorPlugin(md: MarkdownIt) {\n md.core.ruler.push('heading_anchors', (state) => {\n const tokens = state.tokens\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]\n if (token.type === 'heading_open') {\n const contentToken = tokens[i + 1]\n if (contentToken && contentToken.type === 'inline' && contentToken.content) {\n const slug = slugify(contentToken.content)\n const idIndex = token.attrIndex('id')\n if (idIndex < 0) {\n token.attrPush(['id', slug])\n } else if (token.attrs) {\n token.attrs[idIndex][1] = slug\n }\n }\n }\n }\n return true\n })\n}\n\n// --- Inline KaTeX math plugin (replaces markdown-it-dollarmath) ---\n\nfunction mathPlugin(md: MarkdownIt) {\n // Inline: $...$\n md.inline.ruler.after('escape', 'math_inline', (state, silent) => {\n if (state.src.charCodeAt(state.pos) !== 0x24) return false\n if (state.src.charCodeAt(state.pos + 1) === 0x24) return false\n const start = state.pos + 1\n let end = start\n while (end < state.posMax && state.src.charCodeAt(end) !== 0x24) {\n if (state.src.charCodeAt(end) === 0x5C) end++\n end++\n }\n if (end >= state.posMax) return false\n const content = state.src.slice(start, end).trim()\n if (!content) return false\n if (!silent) {\n const token = state.push('math_inline', 'math', 0)\n token.content = content\n token.markup = '$'\n }\n state.pos = end + 1\n return true\n })\n\n md.renderer.rules.math_inline = (tokens, idx) => {\n return renderToString(tokens[idx].content, { displayMode: false, throwOnError: false, strict: 'ignore' })\n }\n\n // Block: $$...$$\n md.block.ruler.after('blockquote', 'math_block', (state, startLine, endLine, silent) => {\n const startPos = state.bMarks[startLine] + state.tShift[startLine]\n if (state.src.charCodeAt(startPos) !== 0x24 || state.src.charCodeAt(startPos + 1) !== 0x24) return false\n if (silent) return true\n let nextLine = startLine\n let found = false\n while (nextLine < endLine) {\n nextLine++\n if (nextLine >= endLine) break\n const pos = state.bMarks[nextLine] + state.tShift[nextLine]\n const max = state.eMarks[nextLine]\n const line = state.src.slice(pos, max).trim()\n if (line === '$$') { found = true; break }\n }\n if (!found) return false\n const contentLines: string[] = []\n for (let i = startLine + 1; i < nextLine; i++) {\n contentLines.push(state.src.slice(state.bMarks[i] + state.tShift[i], state.eMarks[i]))\n }\n const token = state.push('math_block', 'math', 0)\n token.content = contentLines.join('\\\\n').trim()\n token.markup = '$$'\n token.map = [startLine, nextLine + 1]\n state.line = nextLine + 1\n return true\n })\n\n md.renderer.rules.math_block = (tokens, idx) => {\n return '<div class=\"math-display\">' + renderToString(tokens[idx].content, { displayMode: true, throwOnError: false, strict: 'ignore' }) + '</div>\\\\n'\n }\n}\n\n// --- Markdown-it Instance ---\n\nconst md = MarkdownIt({\n html: true,\n linkify: true,\n typographer: true,\n breaks: true,\n highlight: (code, lang) => {\n const language = loadedLangs.includes(lang) ? lang : 'bash'\n const highlighted = shiki.codeToHtml(code, {\n lang: language,\n themes: { light: 'github-light', dark: 'github-dark' },\n defaultColor: false,\n transformers: [transformerNotationHighlight(), transformerNotationDiff()],\n })\n const escapedCode = code.replace(/</g, '<').replace(/>/g, '>')\n return \\`<div class=\"code-block-wrapper not-prose\" data-lang=\"\\${language}\"><button class=\"copy-button\" data-code=\"\\${escapedCode.replace(/\"/g, '"')}\" aria-label=\"Copy code\">Copy</button>\\${highlighted}</div>\\`\n },\n})\n .use(headingAnchorPlugin)\n .use(mathPlugin)\n\nexport function renderMarkdownSync(src: string): string {\n const trimmedContent = trimMathBlock(src)\n return md.render(trimmedContent)\n}\n\nexport function renderMarkdownInline(src: string): string {\n return md.renderInline(src)\n}\n`\n}\n","/**\n * Template: cms/lib/r2.ts\n * Cloudflare R2 client (S3-compatible)\n */\nexport function r2ClientTemplate(): string {\n return `import { S3Client } from '@aws-sdk/client-s3'\n\nlet _r2Client: S3Client | null = null\n\n/**\n * Get or create the R2 client (lazy initialization, server-side only)\n */\nexport function getR2Client(): S3Client {\n if (typeof window !== 'undefined') {\n throw new Error('R2 client can only be used on the server side')\n }\n\n if (_r2Client) return _r2Client\n\n if (!process.env.BETTERSTART_R2_ACCESS_KEY_ID) {\n throw new Error('BETTERSTART_R2_ACCESS_KEY_ID is not set')\n }\n if (!process.env.BETTERSTART_R2_SECRET_ACCESS_KEY) {\n throw new Error('BETTERSTART_R2_SECRET_ACCESS_KEY is not set')\n }\n if (!process.env.BETTERSTART_R2_ACCOUNT_ID) {\n throw new Error('BETTERSTART_R2_ACCOUNT_ID is not set')\n }\n\n _r2Client = new S3Client({\n region: 'auto',\n endpoint: \\`https://\\${process.env.BETTERSTART_R2_ACCOUNT_ID}.r2.cloudflarestorage.com\\`,\n credentials: {\n accessKeyId: process.env.BETTERSTART_R2_ACCESS_KEY_ID,\n secretAccessKey: process.env.BETTERSTART_R2_SECRET_ACCESS_KEY,\n },\n })\n\n return _r2Client\n}\n\nexport const BUCKET_NAME = process.env.BETTERSTART_R2_BUCKET_NAME || ''\nexport const PUBLIC_URL = process.env.BETTERSTART_R2_PUBLIC_URL || ''\n\n/**\n * Generate a unique file path for uploads\n */\nexport function generateFilePath(filename: string, prefix = 'uploads'): string {\n const timestamp = Date.now()\n const randomStr = Math.random().toString(36).substring(2, 15)\n const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_')\n return \\`\\${prefix}/\\${timestamp}-\\${randomStr}-\\${sanitizedFilename}\\`\n}\n\n/**\n * Get the public URL for a file\n */\nexport function getPublicUrl(key: string): string {\n return \\`\\${PUBLIC_URL}/\\${key}\\`\n}\n`\n}\n","/**\n * Template: cms/types/auth.ts\n * Auth types: UserRole enum, session types, role utilities\n */\nexport function authTypesTemplate(): string {\n return `export interface AuthUser {\n id: string\n email: string\n name: string\n emailVerified: boolean\n image: string | null\n role: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface AuthSession {\n user: AuthUser\n isAuthenticated: boolean\n}\n\nexport enum UserRole {\n ADMIN = 'admin',\n EDITOR = 'editor',\n MEMBER = 'member',\n}\n\nexport interface UserWithRole extends AuthUser {\n role: UserRole\n}\n\n/** Type guard to check if a value is a valid UserRole */\nexport function isUserRole(value: unknown): value is UserRole {\n return typeof value === 'string' && Object.values(UserRole).includes(value as UserRole)\n}\n\n/** Check if user has one of the allowed roles */\nexport function hasRequiredRole(userRole: UserRole, allowedRoles: UserRole[]): boolean {\n return allowedRoles.includes(userRole)\n}\n\nexport interface AuthState {\n user: AuthUser | null\n loading: boolean\n error: Error | null\n}\n\nexport interface UserData {\n id: string\n email: string\n name: string\n emailVerified: boolean\n createdAt: string\n updatedAt: string\n role: string\n}\n\nexport interface UsersResponse {\n users: UserData[]\n total: number\n}\n\nexport interface CreateUserInput {\n email: string\n name: string\n password: string\n}\n\nexport interface CreateUserResult {\n success: boolean\n error?: string\n user?: UserData\n}\n\nexport interface UpdateUserRoleInput {\n userId: string\n role: UserRole\n}\n\nexport interface UpdateUserRoleResult {\n success: boolean\n error?: string\n}\n`\n}\n","/**\n * Template: cms/types/index.ts\n * Barrel export for all CMS types\n */\nexport function typesIndexTemplate(): string {\n return `export * from './auth'\n\n/** Markdown editor component types */\nexport interface MDXComponent {\n name: string\n snippet: string\n category: string\n}\n\nexport interface MarkdownEditorProps {\n value?: string\n onChange?: (value: string) => void\n placeholder?: string\n disabled?: boolean\n className?: string\n componentSnippets: Record<string, MDXComponent[]>\n}\n\n/** Upload types */\nexport interface UploadedFile {\n key: string\n url: string\n filename: string\n size: number\n contentType: string\n}\n\nexport interface UploadFileResult {\n success: boolean\n error?: string\n files?: UploadedFile[]\n}\n\nexport interface UploadProgress {\n filename: string\n progress: number\n loaded: number\n total: number\n}\n\n/** API response types */\nexport interface ApiResponse<T = unknown> {\n success: boolean\n data?: T\n error?: string\n message?: string\n}\n\n/** Database response types */\nexport interface PaginationParams {\n page: number\n limit: number\n sortBy?: string\n sortOrder?: 'asc' | 'desc'\n}\n\nexport interface PaginatedResponse<T> {\n data: T[]\n total: number\n page: number\n limit: number\n totalPages: number\n}\n\n/** TanStack Table meta augmentation */\ndeclare module '@tanstack/react-table' {\n // biome-ignore lint/correctness/noUnusedVariables: augmenting module\n interface TableMeta<TData extends import('@tanstack/react-table').RowData> {\n reorderMode?: boolean\n onMoveRow?: (id: number, direction: 'up' | 'down') => void\n currentUser?: {\n id: string\n email: string\n name: string\n image?: string | null\n role: string\n } | null\n }\n}\n`\n}\n","/**\n * Template: cms/types/table-meta.ts\n * TanStack Table meta augmentation\n */\nexport function tableMetaTypesTemplate(): string {\n return `import type { RowData } from '@tanstack/react-table'\n\ndeclare module '@tanstack/react-table' {\n // biome-ignore lint/correctness/noUnusedVariables: augmenting module\n interface TableMeta<TData extends RowData> {\n reorderMode?: boolean\n onMoveRow?: (id: number, direction: 'up' | 'down') => void\n currentUser?: {\n id: string\n email: string\n name: string\n image?: string | null\n role: string\n } | null\n }\n}\n`\n}\n","/**\n * Template: cms/utils/cn.ts\n * Tailwind class merge utility\n */\nexport function cnUtilTemplate(): string {\n return `import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n`\n}\n","/**\n * Template: cms/utils/seo.ts\n * SEO metadata utilities for generated pages\n */\nexport function seoUtilTemplate(): string {\n return `import type { Metadata } from 'next'\n\ninterface CreateMetadataOptions {\n title: string\n description: string\n path?: string\n ogImage?: string\n noIndex?: boolean\n}\n\n/**\n * Create consistent Next.js metadata for CMS-generated pages.\n * Use this in page.tsx files for entities that have public-facing pages.\n */\nexport function createMetadata({\n title,\n description,\n path,\n ogImage,\n noIndex = false,\n}: CreateMetadataOptions): Metadata {\n const metadata: Metadata = {\n title,\n description,\n openGraph: {\n title,\n description,\n type: 'website',\n ...(ogImage && { images: [{ url: ogImage }] }),\n },\n twitter: {\n card: ogImage ? 'summary_large_image' : 'summary',\n title,\n description,\n ...(ogImage && { images: [ogImage] }),\n },\n }\n\n if (path) {\n metadata.alternates = { canonical: path }\n }\n\n if (noIndex) {\n metadata.robots = { index: false, follow: false }\n }\n\n return metadata\n}\n\n/**\n * Generate JSON-LD structured data for a blog post / article.\n */\nexport function generateArticleSchema({\n title,\n description,\n url,\n imageUrl,\n datePublished,\n dateModified,\n authorName,\n}: {\n title: string\n description: string\n url: string\n imageUrl?: string\n datePublished: string\n dateModified?: string\n authorName?: string\n}) {\n return {\n '@context': 'https://schema.org',\n '@type': 'BlogPosting',\n headline: title,\n description,\n url,\n ...(imageUrl && { image: imageUrl }),\n datePublished,\n ...(dateModified && { dateModified }),\n ...(authorName && {\n author: { '@type': 'Person', name: authorName },\n }),\n }\n}\n\n/**\n * Serialize a JSON-LD schema object to a string for embedding in a script tag.\n */\nexport function schemaToJson(schema: Record<string, unknown>): string {\n return JSON.stringify(schema)\n}\n`\n}\n","/**\n * Template: cms/utils/validation.ts\n * File upload validation and common validation helpers\n */\nexport function validationUtilTemplate(): string {\n return `export interface FileValidationConfig {\n maxSizeInBytes?: number\n allowedTypes?: string[]\n maxFiles?: number\n}\n\nexport interface FileValidationError {\n filename: string\n error: string\n}\n\nexport interface FileValidationResult {\n valid: boolean\n errors: FileValidationError[]\n}\n\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\nconst DEFAULT_MAX_FILES = 10\n\nfunction isFileTypeAllowed(file: File, allowedTypes: string[]): boolean {\n for (const type of allowedTypes) {\n if (type.endsWith('/*')) {\n const prefix = type.slice(0, -1)\n if (file.type.startsWith(prefix)) return true\n } else if (type.startsWith('.')) {\n if (file.name.toLowerCase().endsWith(type.toLowerCase())) return true\n } else {\n if (file.type === type) return true\n }\n }\n return false\n}\n\n/**\n * Validate an array of files against size, type, and count constraints.\n */\nexport function validateFiles(\n files: File[],\n config: FileValidationConfig = {},\n): FileValidationResult {\n const { maxSizeInBytes = DEFAULT_MAX_SIZE, allowedTypes, maxFiles = DEFAULT_MAX_FILES } = config\n\n const errors: FileValidationError[] = []\n\n if (files.length > maxFiles) {\n errors.push({\n filename: '',\n error: \\`Too many files. Maximum is \\${maxFiles}.\\`,\n })\n }\n\n for (const file of files) {\n if (file.size > maxSizeInBytes) {\n const maxMB = Math.round(maxSizeInBytes / (1024 * 1024))\n errors.push({\n filename: file.name,\n error: \\`File exceeds maximum size of \\${maxMB}MB.\\`,\n })\n }\n\n if (allowedTypes && allowedTypes.length > 0 && !isFileTypeAllowed(file, allowedTypes)) {\n errors.push({\n filename: file.name,\n error: \\`File type \"\\${file.type || 'unknown'}\" is not allowed.\\`,\n })\n }\n }\n\n return { valid: errors.length === 0, errors }\n}\n\n/**\n * Format bytes to a human-readable string.\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B'\n const units = ['B', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(1024))\n return \\`\\${(bytes / 1024 ** i).toFixed(i === 0 ? 0 : 1)} \\${units[i]}\\`\n}\n\n/**\n * Check if a string is a valid URL.\n */\nexport function isValidUrl(str: string): boolean {\n try {\n new URL(str)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Slugify a string for use in URLs.\n */\nexport function slugify(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\\\w\\\\s-]/g, '')\n .replace(/[\\\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n}\n`\n}\n","/**\n * Template: cms/utils/webhook.ts\n * Fire-and-forget webhook sender for form submissions\n */\nexport function webhookUtilTemplate(): string {\n return `/**\n * Send payload to webhook URL (fire-and-forget, non-blocking)\n * @param webhookUrl - The webhook URL to send data to\n * @param payload - The form data to send as URL-encoded\n */\nexport function sendWebhook(\n webhookUrl: string | null | undefined,\n payload: Record<string, unknown>,\n): void {\n if (!webhookUrl) return // Fire-and-forget: runs in background, doesn't block\n ;(async () => {\n try {\n const formData = new URLSearchParams()\n for (const [key, value] of Object.entries(payload)) {\n if (value === null || value === undefined) continue\n const stringValue = typeof value === 'object' ? JSON.stringify(value) : String(value)\n formData.append(key, stringValue)\n }\n await fetch(webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: formData.toString(),\n })\n } catch (error) {\n console.error('Webhook failed:', error)\n }\n })()\n}\n`\n}\n","/**\n * Template: cms/utils/mailchimp.ts\n * Fire-and-forget Mailchimp audience subscription\n */\nexport function mailchimpUtilTemplate(): string {\n return `import mailchimp from '@mailchimp/mailchimp_marketing'\n\nif (process.env.BETTERSTART_MAILCHIMP_API_KEY && process.env.BETTERSTART_MAILCHIMP_SERVER_PREFIX) {\n mailchimp.setConfig({\n apiKey: process.env.BETTERSTART_MAILCHIMP_API_KEY,\n server: process.env.BETTERSTART_MAILCHIMP_SERVER_PREFIX\n })\n}\n\n/**\n * Add an email address to the Mailchimp audience (fire-and-forget, non-blocking)\n * Follows the same pattern as sendWebhook() in utils/webhook.ts\n */\nexport function addToMailchimpAudience(email: string): void {\n if (\n !process.env.BETTERSTART_MAILCHIMP_API_KEY ||\n !process.env.BETTERSTART_MAILCHIMP_SERVER_PREFIX ||\n !process.env.BETTERSTART_MAILCHIMP_AUDIENCE_ID\n )\n return\n\n ;(async () => {\n try {\n await mailchimp.lists.addListMember(process.env.BETTERSTART_MAILCHIMP_AUDIENCE_ID!, {\n email_address: email,\n status: 'subscribed' as const,\n merge_fields: {}\n })\n } catch (error: unknown) {\n // Silently ignore \"Member Exists\" (user re-submitting form)\n if (\n (error as { response?: { body?: { title?: string } } })?.response?.body?.title ===\n 'Member Exists'\n )\n return\n console.error('Failed to add to Mailchimp audience:', error)\n }\n })()\n}\n`\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { safeWriteFile } from '../../utils/fs.js'\n\nimport { dbClientTemplate } from '../templates/db/client.js'\nimport { drizzleConfigTemplate } from '../templates/db/drizzle-config.js'\nimport { dbSchemaTemplate } from '../templates/db/schema.js'\n\nexport interface DatabaseScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create database client, schema, and drizzle config in cms/db/.\n */\nexport function scaffoldDatabase({ cwd, config }: DatabaseScaffoldOptions): string[] {\n const created: string[] = []\n const dbDir = path.resolve(cwd, config.paths.cms, 'db')\n\n function write(filename: string, content: string): void {\n const fullPath = path.join(dbDir, filename)\n if (safeWriteFile(fullPath, content)) {\n created.push(path.join(config.paths.cms, 'db', filename))\n }\n }\n\n write('client.ts', dbClientTemplate())\n write('schema.ts', dbSchemaTemplate())\n\n // Drizzle config goes at project root (where drizzle-kit expects it)\n const drizzleConfigPath = path.resolve(cwd, 'drizzle.config.ts')\n if (safeWriteFile(drizzleConfigPath, drizzleConfigTemplate())) {\n created.push('drizzle.config.ts')\n }\n\n return created\n}\n","/**\n * Template: cms/db/client.ts\n * Neon + Drizzle database client\n */\nexport function dbClientTemplate(): string {\n return `import { neon } from '@neondatabase/serverless'\nimport { drizzle } from 'drizzle-orm/neon-http'\nimport * as schema from './schema'\n\nconst sql = neon(process.env.BETTERSTART_DATABASE_URL!)\nconst db = drizzle({ client: sql, schema })\n\nexport default db\n`\n}\n","/**\n * Template: cms/db/schema.ts\n * Base schema with Better Auth tables only.\n * The generate command appends entity tables to this file.\n */\nexport function dbSchemaTemplate(): string {\n return `import { sql } from 'drizzle-orm'\nimport { boolean, pgTable, serial, text, timestamp, uniqueIndex, varchar } from 'drizzle-orm/pg-core'\n\n// ============================================================================\n// Better Auth tables\n// ============================================================================\n\nexport const user = pgTable('user', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n email: text('email').notNull().unique(),\n emailVerified: boolean('email_verified').notNull().default(false),\n image: text('image'),\n role: text('role').notNull().default('member'),\n createdAt: timestamp('created_at').notNull().defaultNow(),\n updatedAt: timestamp('updated_at').notNull().defaultNow(),\n})\n\nexport const session = pgTable('session', {\n id: text('id').primaryKey(),\n expiresAt: timestamp('expires_at').notNull(),\n token: text('token').notNull().unique(),\n createdAt: timestamp('created_at').notNull().defaultNow(),\n updatedAt: timestamp('updated_at').notNull().defaultNow(),\n ipAddress: text('ip_address'),\n userAgent: text('user_agent'),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n})\n\nexport const account = pgTable('account', {\n id: text('id').primaryKey(),\n accountId: text('account_id').notNull(),\n providerId: text('provider_id').notNull(),\n userId: text('user_id')\n .notNull()\n .references(() => user.id, { onDelete: 'cascade' }),\n accessToken: text('access_token'),\n refreshToken: text('refresh_token'),\n idToken: text('id_token'),\n accessTokenExpiresAt: timestamp('access_token_expires_at'),\n refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),\n scope: text('scope'),\n password: text('password'),\n createdAt: timestamp('created_at').notNull().defaultNow(),\n updatedAt: timestamp('updated_at').notNull().defaultNow(),\n})\n\nexport const verification = pgTable('verification', {\n id: text('id').primaryKey(),\n identifier: text('identifier').notNull(),\n value: text('value').notNull(),\n expiresAt: timestamp('expires_at').notNull(),\n createdAt: timestamp('created_at').defaultNow(),\n updatedAt: timestamp('updated_at').defaultNow(),\n})\n\n// ============================================================================\n// Form Settings (shared table for all form configurations)\n// ============================================================================\n\nexport const formSettings = pgTable(\n 'FormSettings',\n {\n id: serial().primaryKey().notNull(),\n formName: varchar('formName', { length: 100 }).notNull(),\n webhookUrl: text('webhookUrl'),\n webhookEnabled: boolean('webhookEnabled').default(false).notNull(),\n notificationEmails: text('notificationEmails'),\n createdAt: timestamp('createdAt', { precision: 3, mode: 'string' })\n .default(sql\\`CURRENT_TIMESTAMP\\`)\n .notNull(),\n updatedAt: timestamp('updatedAt', { precision: 3, mode: 'string' })\n .default(sql\\`CURRENT_TIMESTAMP\\`)\n .notNull(),\n },\n (table) => [\n uniqueIndex('FormSettings_formName_key').using(\n 'btree',\n table.formName.asc().nullsLast().op('text_ops')\n ),\n ]\n)\n\n// ============================================================================\n// Generated entity tables (appended by \\`betterstart generate\\`)\n// ============================================================================\n`\n}\n","/**\n * Dependency installer: auto-install all required deps via detected package manager.\n * Splits into core (production) and dev dependencies.\n * Optionally includes email deps (resend + @react-email/components).\n * Uses async spawn so the clack spinner can animate during install.\n */\n\nimport { spawn } from 'node:child_process'\nimport type { PackageManager } from '../../utils/package-manager.js'\n\nexport interface InstallDepsOptions {\n cwd: string\n pm: PackageManager\n includeEmail: boolean\n includeBiome: boolean\n}\n\nexport interface InstallDepsResult {\n coreDeps: string[]\n devDeps: string[]\n success: boolean\n error: string | null\n}\n\n// ============================================================================\n// Dependency Lists\n// ============================================================================\n\n/** Core runtime deps — always installed */\nexport const CORE_DEPS = [\n // Database\n 'drizzle-orm',\n '@neondatabase/serverless',\n // Auth\n 'better-auth',\n // Data fetching + tables\n '@tanstack/react-query',\n '@tanstack/react-table',\n '@tanstack/react-virtual',\n // Forms + validation\n 'react-hook-form',\n '@hookform/resolvers',\n 'zod',\n // URL state + toast + theme\n 'nuqs',\n 'sonner',\n // Styling utilities\n 'geist',\n 'class-variance-authority',\n 'clsx',\n 'tailwind-merge',\n // Icons\n 'lucide-react',\n // Storage (R2)\n '@aws-sdk/client-s3',\n // Radix UI primitives\n '@radix-ui/react-accordion',\n '@radix-ui/react-alert-dialog',\n '@radix-ui/react-aspect-ratio',\n '@radix-ui/react-avatar',\n '@radix-ui/react-checkbox',\n '@radix-ui/react-collapsible',\n '@radix-ui/react-context-menu',\n '@radix-ui/react-dialog',\n '@radix-ui/react-dropdown-menu',\n '@radix-ui/react-hover-card',\n '@radix-ui/react-label',\n '@radix-ui/react-menubar',\n '@radix-ui/react-navigation-menu',\n '@radix-ui/react-popover',\n '@radix-ui/react-progress',\n '@radix-ui/react-radio-group',\n '@radix-ui/react-scroll-area',\n '@radix-ui/react-select',\n '@radix-ui/react-separator',\n '@radix-ui/react-slider',\n '@radix-ui/react-slot',\n '@radix-ui/react-switch',\n '@radix-ui/react-tabs',\n '@radix-ui/react-toast',\n '@radix-ui/react-toggle',\n '@radix-ui/react-toggle-group',\n '@radix-ui/react-tooltip',\n // Rich text (TipTap)\n '@tiptap/core',\n '@tiptap/pm',\n '@tiptap/react',\n '@tiptap/starter-kit',\n '@tiptap/extension-highlight',\n '@tiptap/extension-horizontal-rule',\n '@tiptap/extension-image',\n '@tiptap/extension-list',\n '@tiptap/extension-placeholder',\n '@tiptap/extension-subscript',\n '@tiptap/extension-superscript',\n '@tiptap/extension-text-align',\n '@tiptap/extension-typography',\n '@tiptap/extensions',\n 'tiptap-markdown',\n '@floating-ui/react',\n 'react-hotkeys-hook',\n 'lodash.throttle',\n // CodeMirror markdown editor\n '@codemirror/lang-markdown',\n '@codemirror/view',\n '@uiw/codemirror-theme-github',\n '@uiw/react-codemirror',\n // Date\n 'date-fns',\n 'react-day-picker',\n // Markdown rendering\n 'shiki',\n '@shikijs/transformers',\n 'katex',\n 'markdown-it',\n // Drag-and-drop\n '@dnd-kit/core',\n '@dnd-kit/sortable',\n '@dnd-kit/utilities',\n // Other UI\n 'cmdk',\n 'embla-carousel-react',\n 'fuse.js',\n 'input-otp',\n 'react-resizable-panels',\n 'recharts',\n 'tw-animate-css',\n 'usehooks-ts',\n 'vaul'\n]\n\n/** Email deps — only when email feature is enabled */\nexport const EMAIL_DEPS = ['resend', '@react-email/components']\n\n/** Mailchimp deps — always installed (fire-and-forget, no-op without env vars) */\nexport const MAILCHIMP_DEPS = ['@mailchimp/mailchimp_marketing']\n\n/** Mailchimp type definitions */\nexport const MAILCHIMP_DEV_DEPS = ['@types/mailchimp__mailchimp_marketing']\n\n/** Dev deps — always installed */\nexport const DEV_DEPS = ['drizzle-kit', 'tsx', 'sass', '@types/katex', '@types/markdown-it@13']\n\n/** Biome dev dep — only when no existing linter */\nexport const BIOME_DEV_DEPS = ['@biomejs/biome']\n\n// ============================================================================\n// Installer\n// ============================================================================\n\nfunction buildAddArgs(pm: PackageManager, deps: string[], dev: boolean): string[] {\n const devFlag = dev ? (pm === 'yarn' ? '--dev' : '-D') : ''\n\n switch (pm) {\n case 'pnpm':\n return ['add', ...(devFlag ? [devFlag] : []), ...deps]\n case 'yarn':\n return ['add', ...(devFlag ? [devFlag] : []), ...deps]\n case 'bun':\n return ['add', ...(devFlag ? [devFlag] : []), ...deps]\n default:\n return ['install', ...(devFlag ? [devFlag] : []), ...deps]\n }\n}\n\nfunction spawnAsync(cmd: string, args: string[], cwd: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { cwd, stdio: 'pipe' })\n let stderr = ''\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n child.on('close', (code) => {\n if (code === 0) resolve()\n else reject(new Error(stderr || `${cmd} exited with code ${code}`))\n })\n child.on('error', reject)\n })\n}\n\nexport async function installDependenciesAsync({\n cwd,\n pm,\n includeEmail,\n includeBiome\n}: InstallDepsOptions): Promise<InstallDepsResult> {\n const coreDeps = [...CORE_DEPS, ...MAILCHIMP_DEPS]\n if (includeEmail) coreDeps.push(...EMAIL_DEPS)\n\n const devDeps = [...DEV_DEPS, ...MAILCHIMP_DEV_DEPS]\n if (includeBiome) devDeps.push(...BIOME_DEV_DEPS)\n\n try {\n // Install core deps\n await spawnAsync(pm, buildAddArgs(pm, coreDeps, false), cwd)\n\n // Install dev deps\n await spawnAsync(pm, buildAddArgs(pm, devDeps, true), cwd)\n\n return { coreDeps, devDeps, success: true, error: null }\n } catch (err) {\n return {\n coreDeps,\n devDeps,\n success: false,\n error: err instanceof Error ? err.message : 'Install failed'\n }\n }\n}\n","import crypto from 'node:crypto'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { EnvSection } from '../../utils/env.js'\nimport { appendEnvVars } from '../../utils/env.js'\n\nexport function detectDevPort(cwd: string): number {\n const pkgPath = join(cwd, 'package.json')\n if (!existsSync(pkgPath)) return 3000\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {\n scripts?: Record<string, string>\n }\n const devScript = pkg.scripts?.dev ?? ''\n const match = devScript.match(/--port\\s+(\\d+)|-p\\s+(\\d+)/)\n if (match) {\n const port = Number.parseInt(match[1] ?? match[2], 10)\n if (port > 0 && port <= 65535) return port\n }\n } catch {\n // ignore parse errors\n }\n return 3000\n}\n\nfunction getCoreEnvSections(\n databaseUrl: string | undefined,\n devPort: number\n): EnvSection[] {\n const authSecret = crypto.randomBytes(32).toString('base64')\n return [\n {\n header: 'Database (Neon)',\n vars: [{ key: 'BETTERSTART_DATABASE_URL', value: databaseUrl ?? 'postgresql://...' }]\n },\n {\n header: 'Authentication',\n vars: [\n { key: 'BETTERSTART_AUTH_SECRET', value: authSecret },\n { key: 'BETTERSTART_AUTH_URL', value: `http://localhost:${devPort}` },\n { key: 'BETTERSTART_AUTH_BASE_PATH', value: '/api/cms/auth' }\n ]\n },\n {\n header: 'Storage (Cloudflare R2)',\n vars: [\n { key: 'BETTERSTART_R2_ACCOUNT_ID', value: '' },\n { key: 'BETTERSTART_R2_ACCESS_KEY_ID', value: '' },\n { key: 'BETTERSTART_R2_SECRET_ACCESS_KEY', value: '' },\n { key: 'BETTERSTART_R2_BUCKET_NAME', value: '' },\n { key: 'BETTERSTART_R2_PUBLIC_URL', value: '' }\n ]\n }\n ]\n}\n\nfunction getEmailEnvSection(): EnvSection {\n return {\n header: 'Email (Resend)',\n vars: [\n { key: 'BETTERSTART_RESEND_API_KEY', value: '' },\n { key: 'BETTERSTART_EMAIL_FROM', value: 'noreply@yourdomain.com' }\n ]\n }\n}\n\nfunction getMailchimpEnvSection(): EnvSection {\n return {\n header: 'Mailchimp (optional — leave blank to disable)',\n vars: [\n { key: 'BETTERSTART_MAILCHIMP_API_KEY', value: '' },\n { key: 'BETTERSTART_MAILCHIMP_SERVER_PREFIX', value: '' },\n { key: 'BETTERSTART_MAILCHIMP_AUDIENCE_ID', value: '' }\n ]\n }\n}\n\n/**\n * Append BETTERSTART_* environment variables to .env.local.\n */\nexport function scaffoldEnv(\n cwd: string,\n options: { includeEmail: boolean; databaseUrl?: string }\n): { added: string[]; skipped: string[]; updated: string[] } {\n const devPort = detectDevPort(cwd)\n const sections = getCoreEnvSections(options.databaseUrl, devPort)\n if (options.includeEmail) {\n sections.push(getEmailEnvSection())\n }\n sections.push(getMailchimpEnvSection())\n // If the user provided a real database URL, overwrite any existing placeholder\n const overwrite = options.databaseUrl ? new Set(['BETTERSTART_DATABASE_URL']) : undefined\n return appendEnvVars(cwd, sections, overwrite)\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport interface EnvVar {\n key: string\n value: string\n comment?: string\n}\n\nexport interface EnvSection {\n header: string\n vars: EnvVar[]\n}\n\n/**\n * Safely append environment variables to .env.local.\n * Never overwrites existing values — only adds missing keys.\n * Keys listed in `overwrite` will be updated even if they already exist.\n */\nexport function appendEnvVars(\n cwd: string,\n sections: EnvSection[],\n overwrite?: Set<string>\n): { added: string[]; skipped: string[]; updated: string[] } {\n const envPath = path.join(cwd, '.env.local')\n let existing = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf-8') : ''\n\n const existingKeys = new Set(\n existing\n .split('\\n')\n .filter((line) => line.trim() && !line.trim().startsWith('#'))\n .map((line) => line.split('=')[0]?.trim())\n .filter(Boolean)\n )\n\n const added: string[] = []\n const skipped: string[] = []\n const updated: string[] = []\n const lines: string[] = []\n\n // In-place update for overwrite keys that already exist\n if (overwrite) {\n for (const section of sections) {\n for (const v of section.vars) {\n if (overwrite.has(v.key) && existingKeys.has(v.key)) {\n const pattern = new RegExp(`^${v.key}=.*$`, 'm')\n const replacement = v.comment\n ? `${v.key}=\"${v.value}\" # ${v.comment}`\n : `${v.key}=\"${v.value}\"`\n existing = existing.replace(pattern, replacement)\n updated.push(v.key)\n }\n }\n }\n }\n\n if (existing.trim()) {\n lines.push('')\n }\n\n for (const section of sections) {\n const sectionVars = section.vars.filter((v) => {\n if (existingKeys.has(v.key)) {\n if (!updated.includes(v.key)) skipped.push(v.key)\n return false\n }\n added.push(v.key)\n return true\n })\n\n if (sectionVars.length === 0) continue\n\n lines.push(`# ${section.header}`)\n for (const v of sectionVars) {\n const line = v.comment ? `${v.key}=\"${v.value}\" # ${v.comment}` : `${v.key}=\"${v.value}\"`\n lines.push(line)\n }\n lines.push('')\n }\n\n if (added.length > 0 || updated.length > 0) {\n const header = existing.trim()\n ? ''\n : '# ============================================\\n# BetterStart CMS\\n# ============================================\\n'\n const content = existing.trim()\n ? `${existing.trimEnd()}\\n${lines.join('\\n')}`\n : header + lines.join('\\n')\n fs.writeFileSync(envPath, content)\n }\n\n return { added, skipped, updated }\n}\n","import path from 'node:path'\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { ensureDir, safeWriteFile } from '../../utils/fs.js'\nimport { authenticatedLayoutTemplate } from '../templates/pages/authenticated-layout.js'\n// Page templates\nimport { cmsLayoutTemplate } from '../templates/pages/cms-layout.js'\nimport { dashboardPageTemplate } from '../templates/pages/dashboard-page.js'\nimport { loginFormTemplate, loginPageTemplate } from '../templates/pages/login-page.js'\nimport { createUserDialogTemplate } from '../templates/pages/users/create-user-dialog.js'\nimport { editRoleDialogTemplate } from '../templates/pages/users/edit-role-dialog.js'\nimport { usersColumnsTemplate } from '../templates/pages/users/users-columns.js'\n// Users page templates\nimport { usersPageTemplate } from '../templates/pages/users/users-page.js'\nimport { usersTableTemplate } from '../templates/pages/users/users-table.js'\n\nexport interface LayoutScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n}\n\n/**\n * Create all CMS route structures: layouts, login, dashboard, users, settings.\n */\nexport function scaffoldLayout({ cwd, config }: LayoutScaffoldOptions): string[] {\n const created: string[] = []\n\n function write(relPath: string, content: string): void {\n const fullPath = path.resolve(cwd, relPath)\n ensureDir(path.dirname(fullPath))\n if (safeWriteFile(fullPath, content)) {\n created.push(relPath)\n }\n }\n\n // Derive base CMS layout dir from pages path\n // pages = \"./src/app/(cms)/cms/(authenticated)\" → cmsDir = \"./src/app/(cms)/cms\"\n const cmsDir = path.dirname(config.paths.pages)\n\n // --- Shared CMS layout ---\n write(path.join(cmsDir, 'layout.tsx'), cmsLayoutTemplate())\n\n // --- Authenticated layout ---\n write(path.join(config.paths.pages, 'layout.tsx'), authenticatedLayoutTemplate())\n\n // --- Login page ---\n write(path.join(config.paths.login, 'page.tsx'), loginPageTemplate())\n write(path.join(config.paths.login, 'login-form.tsx'), loginFormTemplate())\n\n // --- Dashboard ---\n write(path.join(config.paths.pages, 'page.tsx'), dashboardPageTemplate())\n\n // --- Users pages ---\n const usersDir = path.join(config.paths.pages, 'users')\n write(path.join(usersDir, 'page.tsx'), usersPageTemplate())\n write(path.join(usersDir, 'users-table.tsx'), usersTableTemplate())\n write(path.join(usersDir, 'columns.tsx'), usersColumnsTemplate())\n write(path.join(usersDir, 'create-user-dialog.tsx'), createUserDialogTemplate())\n write(path.join(usersDir, 'edit-role-dialog.tsx'), editRoleDialogTemplate())\n\n return created\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/layout.tsx\n * Auth-gated layout with sidebar + header\n * Requires admin or editor role to access\n */\nexport function authenticatedLayoutTemplate(): string {\n return `import { requireRole } from '@cms/auth/middleware'\nimport { CmsSidebar } from '@cms/components/layout/cms-sidebar'\nimport { SidebarInset, SidebarProvider } from '@cms/components/ui/sidebar'\nimport { UserRole } from '@cms/types/auth'\n\nexport default async function CmsAuthLayout({ children }: { children: React.ReactNode }) {\n await requireRole([UserRole.ADMIN, UserRole.EDITOR])\n\n return (\n <SidebarProvider>\n <CmsSidebar />\n <SidebarInset>\n <main>{children}</main>\n </SidebarInset>\n </SidebarProvider>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/layout.tsx\n * Shared CMS shell — css + providers (NO auth gate)\n * Login page lives under this layout but outside (authenticated)/\n */\nexport function cmsLayoutTemplate(): string {\n return `import '@cms/cms-globals.css'\nimport { CmsProviders } from '@cms/components/layout/cms-providers'\nimport { GeistMono } from 'geist/font/mono'\nimport { GeistSans } from 'geist/font/sans'\n\nexport default function CmsLayout({ children }: { children: React.ReactNode }) {\n return (\n <CmsProviders>\n <div\n className={\\`cms-root min-h-screen antialiased \\${GeistSans.variable} \\${GeistMono.variable}\\`}\n >\n {children}\n </div>\n </CmsProviders>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/page.tsx\n * Dashboard — simple welcome page with quick links\n */\nexport function dashboardPageTemplate(): string {\n return `import { PageHeader } from '@cms/components/shared/page-header'\nimport { Badge } from '@cms/components/ui/badge'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@cms/components/ui/card'\nimport { FileText, Settings, Users } from 'lucide-react'\nimport Link from 'next/link'\n\nconst quickLinks = [\n {\n title: 'Users',\n description: 'Manage admin users and roles',\n href: '/cms/users',\n icon: Users,\n },\n {\n title: 'Settings',\n description: 'Configure CMS settings',\n href: '/cms/settings',\n icon: Settings,\n },\n {\n title: 'Generate',\n description: 'Add a new resource from a schema',\n href: '#',\n icon: FileText,\n hint: 'npx betterstart generate <schema>',\n },\n]\n\nexport default function DashboardPage() {\n return (\n <div className=\"flex flex-col\">\n <PageHeader title=\"Dashboard\" />\n <div className=\"p-6 space-y-6\">\n <div className=\"grid gap-4 md:grid-cols-3\">\n {quickLinks.map((link) => (\n <Link key={link.title} href={link.href}>\n <Card className=\"hover:bg-accent/50 transition-colors h-full\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center gap-2\">\n <link.icon className=\"size-4 text-muted-foreground\" />\n <CardTitle className=\"text-sm font-medium\">{link.title}</CardTitle>\n </div>\n </CardHeader>\n <CardContent>\n <CardDescription>{link.description}</CardDescription>\n {link.hint && (\n <code className=\"mt-2 block rounded bg-muted px-1.5 py-0.5 font-mono text-xs text-muted-foreground\">\n {link.hint}\n </code>\n )}\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm font-medium\">Environment</CardTitle>\n <CardDescription>Current configuration status</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Environment</span>\n <Badge variant=\"outline\">\n {process.env.NODE_ENV === 'production' ? 'Production' : 'Development'}\n </Badge>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Database</span>\n <Badge variant=\"outline\">\n {process.env.BETTERSTART_DATABASE_URL ? 'Connected' : 'Not configured'}\n </Badge>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Storage (R2)</span>\n <Badge variant=\"outline\">\n {process.env.BETTERSTART_R2_BUCKET_NAME ? 'Configured' : 'Not configured'}\n </Badge>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">Email (Resend)</span>\n <Badge variant=\"outline\">\n {process.env.BETTERSTART_RESEND_API_KEY ? 'Configured' : 'Not configured'}\n </Badge>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/login/page.tsx\n * CMS login page — outside (authenticated) route group\n */\nexport function loginPageTemplate(): string {\n return `import type { Metadata } from 'next'\nimport { LoginForm } from './login-form'\n\nexport const metadata: Metadata = {\n title: 'CMS Login',\n robots: { index: false, follow: false },\n}\n\nexport default function LoginPage() {\n return (\n <div className=\"flex min-h-screen items-center justify-center px-4\">\n <div className=\"w-full max-w-sm\">\n <div className=\"mb-8 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">CMS</h1>\n <p className=\"text-muted-foreground text-sm mt-1\">Sign in to access the admin panel</p>\n </div>\n <LoginForm />\n </div>\n </div>\n )\n}\n`\n}\n\n/**\n * Template: app/(cms)/cms/login/login-form.tsx\n * Client-side login form using Better Auth\n */\nexport function loginFormTemplate(): string {\n return `'use client'\n\nimport { authClient } from '@cms/auth/client'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\nimport { Label } from '@cms/components/ui/label'\nimport { LoaderCircle } from 'lucide-react'\nimport { useRouter } from 'next/navigation'\nimport * as React from 'react'\n\nexport function LoginForm() {\n const router = useRouter()\n const [email, setEmail] = React.useState('')\n const [password, setPassword] = React.useState('')\n const [error, setError] = React.useState<string | null>(null)\n const [isLoading, setIsLoading] = React.useState(false)\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n setError(null)\n setIsLoading(true)\n\n try {\n const result = await authClient.signIn.email({\n email,\n password,\n })\n\n if (result.error) {\n setError(result.error.message || 'Invalid email or password')\n setIsLoading(false)\n return\n }\n\n router.push('/cms')\n router.refresh()\n } catch {\n setError('An error occurred. Please try again.')\n setIsLoading(false)\n }\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {error && (\n <div className=\"bg-destructive/10 text-destructive text-sm p-3 rounded-md\">{error}</div>\n )}\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n disabled={isLoading}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <Input\n id=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n placeholder=\"Enter your password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n disabled={isLoading}\n />\n </div>\n\n <Button type=\"submit\" className=\"w-full\" size=\"lg\" disabled={isLoading}>\n {isLoading && <LoaderCircle className=\"animate-spin\" />}\n {isLoading ? 'Signing in...' : 'Sign In'}\n </Button>\n </form>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/create-user-dialog.tsx\n * Dialog for creating new CMS users\n */\nexport function createUserDialogTemplate(): string {\n return `'use client'\n\nimport { createUser } from '@cms/actions/users'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@cms/components/ui/dialog'\nimport { Input } from '@cms/components/ui/input'\nimport { Label } from '@cms/components/ui/label'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Loader2, UserPlus } from 'lucide-react'\nimport * as React from 'react'\nimport { toast } from 'sonner'\n\nexport function CreateUserDialog() {\n const [open, setOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault()\n const formData = new FormData(e.currentTarget)\n const email = formData.get('email') as string\n const name = formData.get('name') as string\n const password = formData.get('password') as string\n\n startTransition(async () => {\n try {\n const result = await createUser({ email, name, password })\n if (result.success) {\n toast.success('User created successfully')\n queryClient.refetchQueries({ queryKey: ['users'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to create user')\n }\n } catch {\n toast.error('An unexpected error occurred')\n }\n })\n }\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button>\n <UserPlus className=\"size-3.5 -ml-0.5\" strokeWidth={2} />\n Create User\n </Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-[425px]\">\n <DialogHeader>\n <DialogTitle>Create New User</DialogTitle>\n <DialogDescription>\n Add a new user to the CMS. They can sign in with these credentials.\n </DialogDescription>\n </DialogHeader>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"create-email\">Email</Label>\n <Input\n id=\"create-email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"user@example.com\"\n required\n disabled={isPending}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"create-name\">Name</Label>\n <Input\n id=\"create-name\"\n name=\"name\"\n type=\"text\"\n placeholder=\"Full name\"\n required\n disabled={isPending}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"create-password\">Password</Label>\n <Input\n id=\"create-password\"\n name=\"password\"\n type=\"password\"\n placeholder=\"Min 8 characters\"\n minLength={8}\n required\n disabled={isPending}\n />\n </div>\n <div className=\"flex justify-end gap-2 pt-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={isPending}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={isPending}>\n {isPending && <Loader2 className=\"size-4 mr-1 animate-spin\" />}\n Create User\n </Button>\n </div>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/edit-role-dialog.tsx\n * Dialog for changing a user's role\n */\nexport function editRoleDialogTemplate(): string {\n return `'use client'\n\nimport { updateUserRole } from '@cms/actions/users'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@cms/components/ui/dialog'\nimport { Label } from '@cms/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\nimport { UserRole } from '@cms/types/auth'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { Loader2 } from 'lucide-react'\nimport * as React from 'react'\nimport { toast } from 'sonner'\n\ninterface EditRoleDialogProps {\n userId: string\n currentRole: string\n userName: string\n children: React.ReactNode\n}\n\nexport function EditRoleDialog({ userId, currentRole, userName, children }: EditRoleDialogProps) {\n const [open, setOpen] = React.useState(false)\n const [role, setRole] = React.useState(currentRole)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n const handleSave = () => {\n startTransition(async () => {\n try {\n const result = await updateUserRole(userId, role as UserRole)\n if (result.success) {\n toast.success(\\`Role updated for \\${userName}\\`)\n queryClient.refetchQueries({ queryKey: ['users'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to update role')\n }\n } catch {\n toast.error('An unexpected error occurred')\n }\n })\n }\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>{children}</DialogTrigger>\n <DialogContent className=\"sm:max-w-[350px]\">\n <DialogHeader>\n <DialogTitle>Edit Role</DialogTitle>\n <DialogDescription>Change the role for {userName}</DialogDescription>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Role</Label>\n <Select value={role} onValueChange={setRole}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={UserRole.ADMIN}>Admin</SelectItem>\n <SelectItem value={UserRole.EDITOR}>Editor</SelectItem>\n <SelectItem value={UserRole.MEMBER}>Member</SelectItem>\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={() => setOpen(false)} disabled={isPending}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={isPending || role === currentRole}>\n {isPending && <Loader2 className=\"size-4 mr-1 animate-spin\" />}\n Save\n </Button>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/columns.tsx\n * Users table column definitions\n */\nexport function usersColumnsTemplate(): string {\n return `'use client'\n\nimport { deleteUser } from '@cms/actions/users'\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@cms/components/ui/alert-dialog'\nimport { Avatar, AvatarFallback } from '@cms/components/ui/avatar'\nimport { Badge } from '@cms/components/ui/badge'\nimport { Button } from '@cms/components/ui/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@cms/components/ui/dropdown-menu'\nimport type { UserData } from '@cms/types/auth'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ArrowUpDown, Edit, MoreHorizontal, Trash } from 'lucide-react'\nimport React from 'react'\nimport { toast } from 'sonner'\nimport { EditRoleDialog } from './edit-role-dialog'\n\nfunction getInitials(nameOrEmail: string): string {\n const parts = nameOrEmail.includes('@')\n ? nameOrEmail.split('@')[0].split(/[._-]/)\n : nameOrEmail.split(' ')\n return parts\n .filter(Boolean)\n .slice(0, 2)\n .map((p) => p[0].toUpperCase())\n .join('')\n}\n\nfunction DeleteUserAction({\n userId,\n userName,\n isCurrentUser,\n}: {\n userId: string\n userName: string\n isCurrentUser: boolean\n}) {\n const [open, setOpen] = React.useState(false)\n const [isPending, startTransition] = React.useTransition()\n const queryClient = useQueryClient()\n\n if (isCurrentUser) return null\n\n const handleDelete = () => {\n startTransition(async () => {\n try {\n const result = await deleteUser(userId)\n\n if (result.success) {\n toast.success('User deleted successfully')\n queryClient.refetchQueries({ queryKey: ['users'] })\n setOpen(false)\n } else {\n toast.error(result.error || 'Failed to delete user')\n }\n } catch (error) {\n toast.error('An error occurred')\n console.error(error)\n }\n })\n }\n\n return (\n <AlertDialog open={open} onOpenChange={setOpen}>\n <AlertDialogTrigger asChild>\n <DropdownMenuItem className=\"text-destructive\" onSelect={(e) => e.preventDefault()}>\n <Trash className=\"size-4 mr-2\" />\n Delete user\n </DropdownMenuItem>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete <strong>{userName}</strong>{' '}\n and all of their data.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault()\n handleDelete()\n }}\n disabled={isPending}\n className=\"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n >\n {isPending ? 'Deleting...' : 'Delete'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )\n}\n\nexport const columns: ColumnDef<UserData>[] = [\n {\n accessorKey: 'email',\n header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50 px-0!\"\n >\n User\n <ArrowUpDown className=\"size-4\" />\n </Button>\n ),\n cell: ({ row }) => {\n const email = row.getValue('email') as string\n const name = row.original.name\n return (\n <div className=\"flex items-center gap-3\">\n <Avatar className=\"size-8\">\n <AvatarFallback>{getInitials(name || email)}</AvatarFallback>\n </Avatar>\n <div className=\"flex flex-col\">\n <div className=\"font-medium\">{name || 'N/A'}</div>\n <div className=\"text-muted-foreground text-sm\">{email}</div>\n </div>\n </div>\n )\n },\n },\n {\n accessorKey: 'emailVerified',\n header: 'Status',\n cell: ({ row }) => {\n const verified = row.getValue('emailVerified') as boolean\n return (\n <Badge variant={verified ? 'outline' : 'secondary'}>\n {verified ? 'Verified' : 'Unverified'}\n </Badge>\n )\n },\n },\n {\n accessorKey: 'role',\n header: 'Role',\n cell: ({ row, table }) => {\n const role = row.getValue('role') as string\n const currentUser = table.options.meta?.currentUser\n const isCurrentUser = currentUser?.email === row.original.email\n\n if (isCurrentUser) {\n return (\n <Badge variant=\"outline\" className=\"capitalize\">\n {role} (you)\n </Badge>\n )\n }\n\n return (\n <EditRoleDialog\n userId={row.original.id}\n currentRole={row.original.role}\n userName={row.original.name}\n >\n <Badge variant=\"outline\" className=\"capitalize cursor-pointer\">\n {role}\n <Edit className=\"size-3 ml-1\" strokeWidth={2} />\n </Badge>\n </EditRoleDialog>\n )\n },\n },\n {\n accessorKey: 'createdAt',\n header: ({ column }) => (\n <Button\n variant=\"ghost\"\n onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n className=\"hover:bg-muted/50\"\n >\n Joined\n <ArrowUpDown className=\"size-4\" />\n </Button>\n ),\n cell: ({ row }) => {\n const date = new Date(row.getValue('createdAt'))\n return (\n <div className=\"text-sm\">\n {date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}\n </div>\n )\n },\n },\n {\n id: 'actions',\n cell: ({ row, table }) => {\n const currentUser = table.options.meta?.currentUser\n const isCurrentUser = currentUser?.email === row.original.email\n\n return (\n <div className=\"flex justify-end\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" className=\"size-8 p-0\">\n <span className=\"sr-only\">Open menu</span>\n <MoreHorizontal className=\"size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuLabel>Actions</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => navigator.clipboard.writeText(row.original.id)}>\n Copy user ID\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DeleteUserAction\n userId={row.original.id}\n userName={row.original.name}\n isCurrentUser={isCurrentUser}\n />\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )\n },\n },\n]\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/page.tsx\n * Users management page (server component)\n */\nexport function usersPageTemplate(): string {\n return `import { PageHeader } from '@cms/components/shared/page-header'\nimport { columns } from './columns'\nimport { CreateUserDialog } from './create-user-dialog'\nimport { UsersTable } from './users-table'\n\nexport default function UsersPage() {\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader title=\"Users\">\n <CreateUserDialog />\n </PageHeader>\n </div>\n <main className=\"p-6\">\n <UsersTable columns={columns} />\n </main>\n </div>\n )\n}\n`\n}\n","/**\n * Template: app/(cms)/cms/(authenticated)/users/users-table.tsx\n * Users data table (client component)\n */\nexport function usersTableTemplate(): string {\n return `'use client'\n\nimport { authClient } from '@cms/auth/client'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@cms/components/ui/table'\nimport { useUsers } from '@cms/hooks/use-users'\nimport type { UserData } from '@cms/types/auth'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport * as React from 'react'\n\ninterface UsersTableProps<TValue> {\n columns: ColumnDef<UserData, TValue>[]\n}\n\nexport function UsersTable<TValue>({ columns }: UsersTableProps<TValue>) {\n const { data: session } = authClient.useSession()\n const { data, error, isPending } = useUsers()\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n\n const table = useReactTable({\n data: data?.users ?? [],\n columns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n onSortingChange: setSorting,\n getSortedRowModel: getSortedRowModel(),\n onColumnFiltersChange: setColumnFilters,\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n meta: {\n currentUser: session?.user\n ? {\n id: session.user.id,\n email: session.user.email,\n name: session.user.name,\n image: session.user.image,\n role: (session.user as { role?: string }).role || 'member',\n }\n : null,\n },\n state: { sorting, columnFilters, columnVisibility },\n })\n\n return (\n <div className=\"space-y-4\">\n <div className=\"bg-card border overflow-hidden rounded-lg corner-squircle\">\n <Table>\n <TableHeader className=\"bg-secondary\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead key={header.id}>\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <TableBody>\n {isPending ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-muted-foreground\">Loading users...</div>\n </TableCell>\n </TableRow>\n ) : error ? (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n <div className=\"text-destructive\">Error: {error.message}</div>\n </TableCell>\n </TableRow>\n ) : table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow key={row.id}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id}>\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n No users found.\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n <div className=\"flex items-center justify-end space-x-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n >\n Previous\n </Button>\n <div className=\"text-sm text-muted-foreground\">\n Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount() || 1}\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n >\n Next\n </Button>\n </div>\n </div>\n )\n}\n`\n}\n","/**\n * Preset scaffolder: copy preset schemas into cms/schemas/ and run generate\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { BetterstartConfig } from '../../config/types.js'\nimport { runFormPipeline } from '../../generators/form-pipeline/index.js'\nimport { runEntityPipeline, runSinglePipeline } from '../../generators/index.js'\nimport type { FormSchema, Schema } from '../../types.js'\nimport type { Preset } from '../prompts/features.js'\nimport { blogCategoriesSchema } from '../templates/presets/blog-categories.js'\nimport { blogPostsSchema } from '../templates/presets/blog-posts.js'\nimport { defaultSettingsSchema } from '../templates/presets/default-settings.js'\nimport { fullContactSchema } from '../templates/presets/full-contact.js'\nimport { fullNavigationSchema } from '../templates/presets/full-navigation.js'\n\nexport interface PresetScaffoldOptions {\n cwd: string\n config: BetterstartConfig\n preset: Preset\n}\n\nexport interface PresetScaffoldResult {\n schemas: string[]\n generatedFiles: string[]\n errors: string[]\n}\n\ninterface PresetSchema {\n filename: string\n content: string\n isForm: boolean\n isSingle: boolean\n}\n\nfunction getPresetSchemas(preset: Preset): PresetSchema[] {\n // Settings schema is always included (even for blank preset)\n const schemas: PresetSchema[] = [\n {\n filename: 'settings.json',\n content: defaultSettingsSchema(),\n isForm: false,\n isSingle: true\n }\n ]\n\n if (preset !== 'blank') {\n schemas.push(\n {\n filename: 'categories.json',\n content: blogCategoriesSchema(),\n isForm: false,\n isSingle: false\n },\n { filename: 'posts.json', content: blogPostsSchema(), isForm: false, isSingle: false }\n )\n }\n\n if (preset === 'full') {\n schemas.push(\n {\n filename: 'navigation.json',\n content: fullNavigationSchema(),\n isForm: false,\n isSingle: false\n },\n {\n filename: 'forms/contact.json',\n content: fullContactSchema(),\n isForm: true,\n isSingle: false\n }\n )\n }\n\n return schemas\n}\n\n/**\n * Apply preset: write schema files and run entity generation for each\n */\nexport function scaffoldPreset({\n cwd,\n config,\n preset\n}: PresetScaffoldOptions): PresetScaffoldResult {\n const result: PresetScaffoldResult = {\n schemas: [],\n generatedFiles: [],\n errors: []\n }\n\n const schemasDir = path.join(cwd, config.paths?.schemas ?? './cms/schemas')\n const presetSchemas = getPresetSchemas(preset)\n\n // 1. Write all schema files first\n for (const ps of presetSchemas) {\n const filePath = path.join(schemasDir, ps.filename)\n const dir = path.dirname(filePath)\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n\n fs.writeFileSync(filePath, ps.content, 'utf-8')\n result.schemas.push(ps.filename)\n }\n\n // 2. Run pipelines for each schema\n for (const ps of presetSchemas) {\n try {\n if (ps.isForm) {\n const schema = JSON.parse(ps.content) as FormSchema\n const pipelineResult = runFormPipeline(schema, cwd, config, { force: true, silent: true })\n result.generatedFiles.push(...pipelineResult.files)\n if (!pipelineResult.success) {\n result.errors.push(...pipelineResult.errors.map((e) => `${ps.filename}: ${e}`))\n }\n } else if (ps.isSingle) {\n const schema = JSON.parse(ps.content) as Schema\n const pipelineResult = runSinglePipeline(schema, cwd, config, {\n force: true,\n silent: true\n })\n result.generatedFiles.push(...pipelineResult.files)\n if (!pipelineResult.success) {\n result.errors.push(...pipelineResult.errors.map((e) => `${ps.filename}: ${e}`))\n }\n } else {\n const schema = JSON.parse(ps.content) as Schema\n const pipelineResult = runEntityPipeline(schema, cwd, config, {\n force: true,\n silent: true\n })\n result.generatedFiles.push(...pipelineResult.files)\n if (!pipelineResult.success) {\n result.errors.push(...pipelineResult.errors.map((e) => `${ps.filename}: ${e}`))\n }\n }\n } catch (err) {\n result.errors.push(`${ps.filename}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n return result\n}\n","/**\n * Blog preset: categories.json schema\n * Simple entity with name, slug, description, color\n */\nexport function blogCategoriesSchema(): string {\n return JSON.stringify(\n {\n name: 'categories',\n label: 'Categories',\n description: 'Organize posts with categories',\n icon: 'Tag',\n navGroup: { label: 'Blog', icon: 'BookOpen' },\n fields: [\n {\n name: 'name',\n type: 'string',\n label: 'Name',\n required: true,\n hint: 'Category name'\n },\n {\n name: 'slug',\n type: 'string',\n label: 'Slug',\n hint: 'URL-friendly identifier (auto-generated from name)',\n hidden: true\n },\n {\n name: 'description',\n type: 'text',\n label: 'Description',\n hint: 'Optional description of the category'\n },\n {\n name: 'color',\n type: 'string',\n label: 'Color',\n hint: 'Optional color code for UI display (e.g., #3B82F6)'\n }\n ],\n columns: [\n {\n accessorKey: 'name',\n header: 'Name',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'slug',\n header: 'Slug',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'description',\n header: 'Description',\n type: 'text',\n sortable: false\n },\n {\n accessorKey: 'createdAt',\n header: 'Created',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n create: true,\n edit: true,\n delete: true\n },\n search: {\n fields: ['name', 'description']\n },\n autoSlugify: {\n enabled: true,\n sourceField: 'name',\n targetField: 'slug'\n }\n },\n null,\n 2\n )\n}\n","/**\n * Blog preset: posts.json schema\n * Entity with M2M relationship to categories, richtext content, auto-slugify\n */\nexport function blogPostsSchema(): string {\n return JSON.stringify(\n {\n name: 'posts',\n label: 'Posts',\n description: 'Manage blog posts and articles',\n icon: 'FileText',\n navGroup: { label: 'Blog', icon: 'BookOpen' },\n fields: [\n {\n name: 'title',\n type: 'string',\n label: 'Title',\n required: true\n },\n {\n name: 'slug',\n type: 'string',\n label: 'Slug',\n hint: 'URL-friendly identifier (auto-generated from title)',\n hidden: true\n },\n {\n name: 'categories',\n type: 'relationship',\n relationship: 'categories',\n label: 'Categories',\n multiple: true,\n hint: 'Assign one or more categories'\n },\n {\n name: 'excerpt',\n type: 'text',\n label: 'Excerpt',\n hint: 'Short summary for listing pages'\n },\n {\n name: 'coverImage',\n type: 'image',\n label: 'Cover Image'\n },\n {\n name: 'content',\n type: 'richtext',\n label: 'Content',\n output: 'html'\n }\n ],\n columns: [\n {\n accessorKey: 'title',\n header: 'Title',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'published',\n header: 'Status',\n type: 'boolean',\n sortable: true\n },\n {\n accessorKey: 'updatedAt',\n header: 'Updated',\n type: 'date',\n sortable: true\n },\n {\n accessorKey: 'createdAt',\n header: 'Created',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n create: true,\n edit: true,\n delete: true,\n draft: true\n },\n search: {\n fields: ['title', 'excerpt']\n },\n autoSlugify: {\n enabled: true,\n sourceField: 'title',\n targetField: 'slug'\n }\n },\n null,\n 2\n )\n}\n","/**\n * Default settings schema (applied to ALL presets including blank)\n * Generates a singleton form at /cms/settings\n */\nexport function defaultSettingsSchema(): string {\n return JSON.stringify(\n {\n name: 'settings',\n type: 'single',\n label: 'Settings',\n description: 'General site settings',\n icon: 'Settings',\n fields: [\n { name: 'siteName', type: 'string', label: 'Site Name', default: 'BetterStart' },\n { name: 'tagline', type: 'string', label: 'Tagline' },\n { name: 'separator1', type: 'separator' },\n { name: 'logo', type: 'image', label: 'Logo' },\n { name: 'favicon', type: 'image', label: 'Favicon' }\n ]\n },\n null,\n 2\n )\n}\n","/**\n * Full preset: contact.json form schema\n * Public contact form with admin submission viewer\n */\nexport function fullContactSchema(): string {\n return JSON.stringify(\n {\n name: 'contact',\n label: 'Contact Form',\n description: 'Website contact form submissions',\n icon: 'Mail',\n submitButtonText: 'Send Message',\n successMessage: \"Thank you! We'll get back to you soon.\",\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Full Name',\n placeholder: 'Jane Doe',\n required: true,\n minLength: 2,\n maxLength: 100\n },\n {\n name: 'email',\n type: 'email',\n label: 'Email Address',\n placeholder: 'jane@example.com',\n required: true\n },\n {\n name: 'subject',\n type: 'select',\n label: 'Subject',\n required: true,\n options: [\n { label: 'General Inquiry', value: 'general' },\n { label: 'Support', value: 'support' },\n { label: 'Feedback', value: 'feedback' },\n { label: 'Other', value: 'other' }\n ]\n },\n {\n name: 'message',\n type: 'textarea',\n label: 'Message',\n placeholder: 'How can we help?',\n required: true,\n minLength: 10\n }\n ],\n columns: [\n {\n accessorKey: 'name',\n header: 'Name',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'email',\n header: 'Email',\n type: 'email',\n sortable: true\n },\n {\n accessorKey: 'subject',\n header: 'Subject',\n type: 'badge',\n sortable: true\n },\n {\n accessorKey: 'submittedAt',\n header: 'Submitted',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n export: true,\n delete: true\n }\n },\n null,\n 2\n )\n}\n","/**\n * Full preset: navigation.json schema\n * Entity for managing website navigation menus with nested items\n */\nexport function fullNavigationSchema(): string {\n return JSON.stringify(\n {\n name: 'navigation',\n label: 'Navigation',\n description: 'Manage website navigation menus',\n icon: 'Navigation',\n fields: [\n {\n name: 'name',\n type: 'string',\n label: 'Name',\n required: true,\n hint: 'Navigation name (e.g., Main, Footer)'\n },\n {\n name: 'slug',\n type: 'string',\n label: 'Slug',\n hint: 'URL-friendly identifier (auto-generated from name)',\n hidden: true\n },\n {\n name: 'navItems',\n type: 'list',\n label: 'Navigation Items',\n fields: [\n {\n name: 'title',\n type: 'string',\n label: 'Title'\n },\n {\n name: 'url',\n type: 'string',\n label: 'URL Path'\n }\n ]\n }\n ],\n columns: [\n {\n accessorKey: 'name',\n header: 'Name',\n type: 'text',\n sortable: true\n },\n {\n accessorKey: 'createdAt',\n header: 'Created',\n type: 'date',\n sortable: true\n }\n ],\n actions: {\n create: true,\n edit: true,\n delete: true\n },\n autoSlugify: {\n enabled: true,\n sourceField: 'name',\n targetField: 'slug'\n }\n },\n null,\n 2\n )\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nconst SOURCE_LINES = ['@source \"../cms/**/*.{ts,tsx}\";', '@source \"./(cms)/**/*.{ts,tsx}\";']\nconst SOURCE_LINES_SRC = ['@source \"../../cms/**/*.{ts,tsx}\";', '@source \"./(cms)/**/*.{ts,tsx}\";']\n\n// Tailwind v4 @theme tokens that map CSS vars to utility classes.\n// These let Tailwind generate bg-primary, text-muted-foreground, border-border, etc.\nconst CMS_THEME_BLOCK = `\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-destructive-foreground: var(--destructive-foreground);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-input-border: var(--input-border);\n --color-ring: var(--ring);\n --color-chart-1: var(--chart-1);\n --color-chart-2: var(--chart-2);\n --color-chart-3: var(--chart-3);\n --color-chart-4: var(--chart-4);\n --color-chart-5: var(--chart-5);\n --color-sidebar: var(--sidebar);\n --color-sidebar-foreground: var(--sidebar-foreground);\n --color-sidebar-primary: var(--sidebar-primary);\n --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);\n --color-sidebar-accent: var(--sidebar-accent);\n --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);\n --color-sidebar-border: var(--sidebar-border);\n --color-sidebar-ring: var(--sidebar-ring);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n}`\n\n/**\n * Find the main CSS file that imports Tailwind.\n */\nfunction findMainCss(cwd: string): string | undefined {\n const candidates = [\n 'src/app/globals.css',\n 'app/globals.css',\n 'src/app/global.css',\n 'app/global.css',\n 'src/app/app.css',\n 'app/app.css',\n 'src/globals.css',\n 'globals.css'\n ]\n\n for (const candidate of candidates) {\n const filePath = path.join(cwd, candidate)\n if (fs.existsSync(filePath)) {\n return filePath\n }\n }\n return undefined\n}\n\n/**\n * Append @source directive and @theme tokens to the user's main CSS file\n * so Tailwind scans CMS component classes and generates utility classes.\n */\nexport function scaffoldTailwind(\n cwd: string,\n hasSrcDir: boolean\n): { file: string | null; appended: boolean } {\n const cssFile = findMainCss(cwd)\n if (!cssFile) {\n return { file: null, appended: false }\n }\n\n let content = fs.readFileSync(cssFile, 'utf-8')\n let changed = false\n\n // 1. Add @source directives if not present\n const sourceLines = hasSrcDir ? SOURCE_LINES_SRC : SOURCE_LINES\n const missingLines = sourceLines.filter((sl) => !content.includes(sl))\n if (missingLines.length > 0) {\n const lines = content.split('\\n')\n let insertIndex = 0\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim()\n if (\n trimmed.startsWith('@import') ||\n trimmed.startsWith('@source') ||\n trimmed.startsWith('@plugin')\n ) {\n insertIndex = i + 1\n }\n }\n lines.splice(insertIndex, 0, ...missingLines)\n content = lines.join('\\n')\n changed = true\n }\n\n // 2. Add @theme tokens if not already present\n if (!content.includes('--color-primary')) {\n // If there's an existing @theme inline block, merge into it.\n // Otherwise append the full block at the end.\n const themeMatch = content.match(/@theme\\s+inline\\s*\\{/)\n if (themeMatch && themeMatch.index !== undefined) {\n // Find the closing brace of the existing @theme block\n let braceDepth = 0\n let insertPos = -1\n for (let i = themeMatch.index; i < content.length; i++) {\n if (content[i] === '{') braceDepth++\n if (content[i] === '}') {\n braceDepth--\n if (braceDepth === 0) {\n insertPos = i\n break\n }\n }\n }\n if (insertPos !== -1) {\n // Extract the existing @theme block content to avoid duplicates\n const existingBlock = content.slice(themeMatch.index, insertPos)\n const varsOnly = CMS_THEME_BLOCK.split('\\n')\n .filter((l) => l.trim().startsWith('--'))\n .filter((l) => {\n const varName = l.trim().split(':')[0]!.trim()\n return !existingBlock.includes(varName)\n })\n .map((l) => ` ${l.trim()}`)\n .join('\\n')\n if (varsOnly) {\n content = `${content.slice(0, insertPos)}${varsOnly}\\n${content.slice(insertPos)}`\n changed = true\n }\n }\n } else {\n // No existing @theme block — append the full block\n content = `${content}\\n${CMS_THEME_BLOCK}\\n`\n changed = true\n }\n }\n\n if (changed) {\n fs.writeFileSync(cssFile, content, 'utf-8')\n }\n\n return { file: cssFile, appended: changed }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\n// Strip line and block comments from JSON, respecting quoted strings.\nfunction stripJsonComments(input: string): string {\n let result = ''\n let i = 0\n while (i < input.length) {\n // Inside a string — copy until closing quote\n if (input[i] === '\"') {\n let j = i + 1\n while (j < input.length) {\n if (input[j] === '\\\\') {\n j += 2\n continue\n }\n if (input[j] === '\"') {\n j++\n break\n }\n j++\n }\n result += input.slice(i, j)\n i = j\n // Line comment\n } else if (input[i] === '/' && input[i + 1] === '/') {\n const nl = input.indexOf('\\n', i)\n i = nl === -1 ? input.length : nl\n // Block comment\n } else if (input[i] === '/' && input[i + 1] === '*') {\n const end = input.indexOf('*/', i + 2)\n i = end === -1 ? input.length : end + 2\n } else {\n result += input[i]\n i++\n }\n }\n return result\n}\n\nconst CMS_PATH_ALIASES: Record<string, string[]> = {\n '@cms/*': ['./cms/*'],\n '@cms/db': ['./cms/db/client'],\n '@cms/db/schema': ['./cms/db/schema'],\n '@cms/actions/*': ['./cms/lib/actions/*'],\n '@cms/auth': ['./cms/lib/auth/auth'],\n '@cms/auth/client': ['./cms/lib/auth/auth-client'],\n '@cms/auth/middleware': ['./cms/lib/auth/middleware'],\n '@cms/hooks/*': ['./cms/hooks/*'],\n '@cms/components/*': ['./cms/components/*'],\n '@cms/types': ['./cms/types'],\n '@cms/types/*': ['./cms/types/*'],\n '@cms/utils/*': ['./cms/utils/*'],\n '@cms/data/*': ['./cms/data/*'],\n '@cms/cache/*': ['./cms/lib/cache/*']\n}\n\n/**\n * Append @cms/* path aliases to tsconfig.json.\n * Preserves existing content and only adds missing aliases.\n */\nexport function scaffoldTsconfig(cwd: string): { added: string[]; skipped: string[] } {\n const tsconfigPath = path.join(cwd, 'tsconfig.json')\n const added: string[] = []\n const skipped: string[] = []\n\n if (!fs.existsSync(tsconfigPath)) {\n skipped.push('tsconfig.json not found')\n return { added, skipped }\n }\n\n const raw = fs.readFileSync(tsconfigPath, 'utf-8')\n\n // Strip JSON comments while preserving string contents.\n // Walks character-by-character to avoid mangling strings that contain /* or //.\n const stripped = stripJsonComments(raw)\n // Remove trailing commas before } or ]\n .replace(/,\\s*([\\]}])/g, '$1')\n\n let tsconfig: Record<string, unknown>\n try {\n tsconfig = JSON.parse(stripped)\n } catch {\n skipped.push('Failed to parse tsconfig.json')\n return { added, skipped }\n }\n\n const compilerOptions = (tsconfig.compilerOptions ?? {}) as Record<string, unknown>\n const paths = (compilerOptions.paths ?? {}) as Record<string, string[]>\n\n for (const [alias, target] of Object.entries(CMS_PATH_ALIASES)) {\n if (alias in paths) {\n skipped.push(alias)\n } else {\n paths[alias] = target\n added.push(alias)\n }\n }\n\n compilerOptions.paths = paths\n tsconfig.compilerOptions = compilerOptions\n\n fs.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\\n`, 'utf-8')\n\n return { added, skipped }\n}\n","/**\n * seed command — create initial admin user via Better Auth\n *\n * Generates a seed script at cms/scripts/seed.ts and runs it with tsx.\n * The script uses Better Auth's server API to create the user, then\n * sets the role to 'admin' via a direct database update.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\n\nexport function buildSeedScript(): string {\n // Self-contained: inlines DB + auth setup so tsx doesn't need @cms/* aliases.\n // Only relative import is ../db/schema which uses npm packages only.\n return `/**\n * BetterStart CMS — Seed Script\n * Creates the initial admin user\n * AUTO-GENERATED — safe to delete after running\n */\n\nimport { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\n// Load .env.local (inline — avoids @next/env dependency)\nfor (const envFile of ['.env.local', '.env']) {\n try {\n const content = readFileSync(resolve(process.cwd(), envFile), 'utf-8')\n for (const line of content.split('\\\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx).trim()\n const val = trimmed.slice(eqIdx + 1).trim().replace(/^['\"]|['\"]$/g, '')\n if (!process.env[key]) process.env[key] = val\n }\n } catch {}\n}\n\nimport { neon } from '@neondatabase/serverless'\nimport { drizzle } from 'drizzle-orm/neon-http'\nimport { eq } from 'drizzle-orm'\nimport * as schema from '../db/schema'\nimport { betterAuth } from 'better-auth'\nimport { drizzleAdapter } from 'better-auth/adapters/drizzle'\n\n// Inline DB connection (mirrors cms/db/client.ts)\nconst sql = neon(process.env.BETTERSTART_DATABASE_URL!)\nconst db = drizzle({ client: sql, schema })\n\n// Inline auth setup (mirrors cms/lib/auth/auth.ts)\nconst auth = betterAuth({\n secret: process.env.BETTERSTART_AUTH_SECRET,\n baseURL: process.env.BETTERSTART_AUTH_URL,\n basePath: process.env.BETTERSTART_AUTH_BASE_PATH || '/api/cms/auth',\n database: drizzleAdapter(db, {\n provider: 'pg',\n schema: {\n user: schema.user,\n session: schema.session,\n account: schema.account,\n verification: schema.verification,\n },\n }),\n emailAndPassword: { enabled: true, minPasswordLength: 8 },\n user: {\n additionalFields: {\n role: { type: 'string', required: false, defaultValue: 'member', input: false },\n },\n },\n})\n\nconst EMAIL = process.env.SEED_EMAIL!\nconst PASSWORD = process.env.SEED_PASSWORD!\nconst NAME = process.env.SEED_NAME || 'Admin'\nconst OVERWRITE = process.env.SEED_OVERWRITE === 'true'\n\nasync function main() {\n // Check if user already exists\n const existing = await db\n .select({ id: schema.user.id, name: schema.user.name })\n .from(schema.user)\n .where(eq(schema.user.email, EMAIL))\n .then((rows: { id: string; name: string }[]) => rows[0])\n\n if (existing && !OVERWRITE) {\n // Exit code 2 signals \"user exists\" to the CLI\n console.log(\\`EXISTING_USER:\\${existing.name}\\`)\n process.exit(2)\n }\n\n if (existing && OVERWRITE) {\n console.log('\\\\n Replacing existing admin user...')\n // Remove existing account + session rows first (foreign key refs)\n await db.delete(schema.session).where(eq(schema.session.userId, existing.id))\n await db.delete(schema.account).where(eq(schema.account.userId, existing.id))\n await db.delete(schema.user).where(eq(schema.user.id, existing.id))\n } else {\n console.log('\\\\n Creating admin user...')\n }\n\n console.log(\\` Email: \\${EMAIL}\\\\n\\`)\n\n const result = await auth.api.signUpEmail({\n body: { email: EMAIL, password: PASSWORD, name: NAME },\n })\n\n if (!result?.user) {\n console.error(' Failed to create user.')\n process.exit(1)\n }\n\n await db\n .update(schema.user)\n .set({ role: 'admin' })\n .where(eq(schema.user.id, result.user.id))\n\n console.log(\\` Admin user \\${existing ? 'replaced' : 'created'}: \\${EMAIL}\\`)\n console.log(' Role: admin\\\\n')\n process.exit(0)\n}\n\nmain().catch((err) => {\n console.error(' Seed failed:', err.message || err)\n process.exit(1)\n})\n`\n}\n\nexport const seedCommand = new Command('seed')\n .description('Create the initial admin user')\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n clack.intro('BetterStart Seed')\n\n // Load config\n let config: BetterstartConfig\n try {\n config = await resolveConfig(cwd)\n } catch (err) {\n clack.cancel(`Error loading config: ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n }\n\n const cmsDir = config.paths?.cms ?? './cms'\n\n // Prompt for user details\n const email = await clack.text({\n message: 'Admin email',\n placeholder: 'admin@example.com',\n validate: (v) => {\n if (!v || !v.includes('@')) return 'Please enter a valid email'\n }\n })\n if (clack.isCancel(email)) {\n clack.cancel('Cancelled.')\n process.exit(0)\n }\n\n const password = await clack.password({\n message: 'Admin password',\n validate: (v) => {\n if (!v || v.length < 8) return 'Password must be at least 8 characters'\n }\n })\n if (clack.isCancel(password)) {\n clack.cancel('Cancelled.')\n process.exit(0)\n }\n\n const name = await clack.text({\n message: 'Admin name',\n placeholder: 'Admin',\n defaultValue: 'Admin'\n })\n if (clack.isCancel(name)) {\n clack.cancel('Cancelled.')\n process.exit(0)\n }\n\n // Write seed script\n const scriptsDir = path.join(cwd, cmsDir, 'scripts')\n const seedPath = path.join(scriptsDir, 'seed.ts')\n\n if (!fs.existsSync(scriptsDir)) {\n fs.mkdirSync(scriptsDir, { recursive: true })\n }\n fs.writeFileSync(seedPath, buildSeedScript(), 'utf-8')\n\n const { execFile } = await import('node:child_process')\n const tsxBin = path.join(cwd, 'node_modules', '.bin', 'tsx')\n\n const runSeed = (overwrite: boolean) =>\n new Promise<{ code: number; stdout: string }>((resolve, reject) => {\n execFile(\n tsxBin,\n [seedPath],\n {\n cwd,\n env: {\n ...process.env,\n SEED_EMAIL: email,\n SEED_PASSWORD: password,\n SEED_NAME: name || 'Admin',\n ...(overwrite ? { SEED_OVERWRITE: 'true' } : {})\n }\n },\n (err, stdout, stderr) => {\n if (err && 'code' in err && err.code === 2) {\n // Exit code 2 = user already exists\n resolve({ code: 2, stdout })\n } else if (err) {\n reject(new Error(stderr || err.message))\n } else {\n resolve({ code: 0, stdout })\n }\n }\n )\n })\n\n const spinner = clack.spinner()\n spinner.start('Creating admin user...')\n\n try {\n const result = await runSeed(false)\n\n if (result.code === 2) {\n // User already exists — ask to overwrite\n const existingName =\n result.stdout\n .split('\\n')\n .find((l) => l.startsWith('EXISTING_USER:'))\n ?.replace('EXISTING_USER:', '')\n ?.trim() || 'unknown'\n\n spinner.stop(`Account already exists for ${email}`)\n\n const overwrite = await clack.confirm({\n message: `An admin account (${existingName}) already exists with this email. Replace it?`\n })\n if (clack.isCancel(overwrite) || !overwrite) {\n clack.cancel('Seed cancelled.')\n // Clean up before exiting\n try {\n fs.unlinkSync(seedPath)\n } catch {}\n process.exit(0)\n }\n\n spinner.start('Replacing admin user...')\n await runSeed(true)\n spinner.stop('Admin user replaced')\n } else {\n spinner.stop('Admin user created')\n }\n } catch (err) {\n spinner.stop('Failed to create admin user')\n\n const errMsg = err instanceof Error ? err.message : String(err)\n clack.log.error(errMsg)\n clack.log.info('You can run the seed script manually:')\n clack.log.info(\n ` SEED_EMAIL=\"${email}\" SEED_PASSWORD=\"...\" npx tsx ${path.relative(cwd, seedPath)}`\n )\n clack.outro('')\n process.exit(1)\n }\n\n // Clean up seed script\n try {\n fs.unlinkSync(seedPath)\n // Remove scripts dir if empty\n if (fs.existsSync(scriptsDir) && fs.readdirSync(scriptsDir).length === 0) {\n fs.rmdirSync(scriptsDir)\n }\n } catch {\n // Not critical\n }\n\n clack.outro(`Admin user ready: ${email}`)\n })\n","/**\n * remove command — delete generated files, clean schema.ts + navigation.ts\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport readline from 'node:readline'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport type { BetterstartConfig } from '../config/types.js'\nimport { toCamelCase, singularize, toKebabCase } from '../utils/string.js'\n\n// ============================================================================\n// Schema.ts Cleaning\n// ============================================================================\n\nfunction findTableEnd(content: string, startIndex: number): number {\n let depth = 0\n let inString = false\n let stringChar = ''\n\n for (let i = startIndex; i < content.length; i++) {\n const char = content[i]\n const prev = i > 0 ? content[i - 1] : ''\n\n if ((char === '\"' || char === \"'\" || char === '`') && prev !== '\\\\') {\n if (!inString) {\n inString = true\n stringChar = char\n } else if (char === stringChar) {\n inString = false\n }\n continue\n }\n if (inString) continue\n\n if (char === '(' || char === '{' || char === '[') depth++\n if (char === ')' || char === '}' || char === ']') depth--\n\n if (depth === 0 && char === ')') {\n // Skip trailing newlines\n let end = i + 1\n while (end < content.length && content[end] === '\\n') end++\n return end\n }\n }\n return content.length\n}\n\nfunction removeTableFromSchema(schemaFilePath: string, name: string): boolean {\n if (!fs.existsSync(schemaFilePath)) return false\n\n let content = fs.readFileSync(schemaFilePath, 'utf-8')\n const variableName = toCamelCase(name)\n let changed = false\n\n // Remove main table\n if (content.includes(`export const ${variableName} =`)) {\n const start = content.indexOf(`export const ${variableName} =`)\n const end = findTableEnd(content, start)\n content = content.slice(0, start) + content.slice(end)\n changed = true\n }\n\n // Remove junction tables (e.g., postCategories for posts schema)\n const singular = singularize(name)\n const junctionPrefix = toCamelCase(singular)\n // Find all exports starting with the singular prefix that are pgTable calls\n const regex = new RegExp(`export const (${junctionPrefix}[A-Z]\\\\w*) = pgTable\\\\(`, 'g')\n let jMatch = regex.exec(content)\n while (jMatch) {\n const jVarName = jMatch[1]\n const jStart = content.indexOf(`export const ${jVarName} =`)\n if (jStart !== -1) {\n const jEnd = findTableEnd(content, jStart)\n content = content.slice(0, jStart) + content.slice(jEnd)\n changed = true\n // Reset regex since content changed\n regex.lastIndex = 0\n jMatch = regex.exec(content)\n } else {\n jMatch = regex.exec(content)\n }\n }\n\n if (changed) {\n // Clean up multiple blank lines\n content = content.replace(/\\n{3,}/g, '\\n\\n')\n fs.writeFileSync(schemaFilePath, content, 'utf-8')\n }\n\n return changed\n}\n\n// ============================================================================\n// Navigation.ts Cleaning\n// ============================================================================\n\nfunction removeFromNavigation(navFilePath: string, name: string): boolean {\n if (!fs.existsSync(navFilePath)) return false\n\n const content = fs.readFileSync(navFilePath, 'utf-8')\n const href = `/cms/${name}`\n\n if (!content.includes(`'${href}'`)) return false\n\n // Flat structure: find the { ... } block containing this href\n const lines = content.split('\\n')\n let startLine = -1\n let endLine = -1\n let depth = 0\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n\n if (startLine === -1 && line.includes(`'${href}'`)) {\n // Walk back to find the opening `{`\n for (let j = i; j >= 0; j--) {\n if (lines[j].trim().startsWith('{')) {\n startLine = j\n break\n }\n }\n }\n\n if (startLine !== -1 && i >= startLine) {\n for (const char of line) {\n if (char === '{') depth++\n if (char === '}') depth--\n }\n if (depth === 0 && line.includes('}')) {\n endLine = i\n break\n }\n }\n }\n\n if (startLine === -1 || endLine === -1) return false\n\n lines.splice(startLine, endLine - startLine + 1)\n\n // Clean up double commas or leading commas\n const updated = lines\n .join('\\n')\n .replace(/,\\s*,/g, ',')\n .replace(/\\[\\s*,/, '[')\n fs.writeFileSync(navFilePath, updated, 'utf-8')\n return true\n}\n\n// ============================================================================\n// Confirmation\n// ============================================================================\n\nasync function promptConfirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout\n })\n return new Promise((resolve) => {\n rl.question(`${message} (y/N) `, (answer) => {\n rl.close()\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes')\n })\n })\n}\n\n// ============================================================================\n// Command\n// ============================================================================\n\nexport const removeCommand = new Command('remove')\n .alias('rm')\n .description('Remove all generated files for an entity or form')\n .argument('<schema>', 'Schema name to remove (e.g. posts, categories, contact)')\n .option('-f, --force', 'Skip confirmation prompt', false)\n .option('--cwd <path>', 'Project root path')\n .action(async (schemaName: string, options: { force: boolean; cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n console.log('\\n BetterStart Remove\\n')\n\n // Load config\n let config: BetterstartConfig\n try {\n config = await resolveConfig(cwd)\n } catch (err) {\n console.error(` Error loading config: ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n }\n\n const cmsDir = config.paths?.cms ?? './cms'\n const pagesDir = config.paths?.pages ?? './src/app/(cms)/cms/(authenticated)'\n const kebabName = toKebabCase(schemaName)\n\n // Collect files/dirs to remove\n const targets: { path: string; label: string; isDir: boolean }[] = []\n\n // Pages directory\n const entityPagesDir = path.join(cwd, pagesDir, schemaName)\n if (fs.existsSync(entityPagesDir)) {\n targets.push({\n path: entityPagesDir,\n label: `${path.join(pagesDir, schemaName)}/`,\n isDir: true\n })\n }\n\n // Actions file\n const actionsFile = path.join(cwd, cmsDir, 'lib', 'actions', `${kebabName}.ts`)\n if (fs.existsSync(actionsFile)) {\n targets.push({\n path: actionsFile,\n label: path.join(cmsDir, 'lib', 'actions', `${kebabName}.ts`),\n isDir: false\n })\n }\n\n // Hook file\n const hookFile = path.join(cwd, cmsDir, 'hooks', `use-${kebabName}.ts`)\n if (fs.existsSync(hookFile)) {\n targets.push({\n path: hookFile,\n label: path.join(cmsDir, 'hooks', `use-${kebabName}.ts`),\n isDir: false\n })\n }\n\n // Check schema.ts for table entry\n const schemaFilePath = path.join(cwd, cmsDir, 'db', 'schema.ts')\n const hasTable =\n fs.existsSync(schemaFilePath) &&\n fs.readFileSync(schemaFilePath, 'utf-8').includes(`export const ${toCamelCase(schemaName)} =`)\n\n // Check navigation.ts for entry\n const navFilePath = path.join(cwd, cmsDir, 'data', 'navigation.ts')\n const hasNavEntry =\n fs.existsSync(navFilePath) &&\n fs.readFileSync(navFilePath, 'utf-8').includes(`'/cms/${schemaName}'`)\n\n if (targets.length === 0 && !hasTable && !hasNavEntry) {\n console.log(` No generated files found for: ${schemaName}`)\n return\n }\n\n // Show what will be removed\n console.log(' Files to remove:\\n')\n for (const t of targets) {\n console.log(` ${t.isDir ? '[dir]' : ' '} ${t.label}`)\n }\n if (hasTable) {\n console.log(` [edit] ${path.join(cmsDir, 'db', 'schema.ts')} (remove table)`)\n }\n if (hasNavEntry) {\n console.log(` [edit] ${path.join(cmsDir, 'data', 'navigation.ts')} (remove entry)`)\n }\n\n // Confirm\n if (!options.force) {\n console.log('')\n const confirmed = await promptConfirm(' Are you sure?')\n if (!confirmed) {\n console.log('\\n Cancelled.\\n')\n return\n }\n }\n\n console.log('')\n\n // Delete files/dirs\n for (const t of targets) {\n if (t.isDir) {\n fs.rmSync(t.path, { recursive: true, force: true })\n } else {\n fs.unlinkSync(t.path)\n }\n console.log(` Removed: ${t.label}`)\n }\n\n // Clean schema.ts\n if (hasTable) {\n removeTableFromSchema(schemaFilePath, schemaName)\n console.log(` Cleaned: ${path.join(cmsDir, 'db', 'schema.ts')}`)\n }\n\n // Clean navigation.ts\n if (hasNavEntry) {\n removeFromNavigation(navFilePath, schemaName)\n console.log(` Cleaned: ${path.join(cmsDir, 'data', 'navigation.ts')}`)\n }\n\n console.log('\\n Removal complete!')\n console.log('\\n Note: You may need to manually:')\n console.log(' - Run a migration to drop the database table')\n console.log(' - Remove the schema file from cms/schemas/')\n console.log(' - Regenerate the cache module (betterstart generate <any-schema>)')\n console.log('')\n })\n","/**\n * setup-r2 command — create a Cloudflare R2 bucket and configure env vars\n *\n * 1. Checks for wrangler CLI\n * 2. Ensures user is logged in to Cloudflare\n * 3. Creates an R2 bucket\n * 4. Enables the r2.dev public URL automatically via CF API\n * 5. Opens the dashboard for API token creation\n * 6. Prompts for credentials and writes them to .env.local\n */\n\nimport { execFileSync, spawnSync } from 'node:child_process'\nimport fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport * as p from '@clack/prompts'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\n\nimport { appendEnvVars } from '../utils/env.js'\n\nexport const setupR2Command = new Command('setup-r2')\n .description('Create a Cloudflare R2 bucket and configure storage env vars')\n .option('--cwd <path>', 'Project root path')\n .option('--bucket <name>', 'Bucket name (skips prompt)')\n .action(async (options: { cwd?: string; bucket?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n p.intro(pc.bgCyan(pc.black(' BetterStart — R2 Storage Setup ')))\n\n const s = p.spinner()\n\n // 1. Check for wrangler\n s.start('Looking for wrangler CLI')\n const wrangler = findWrangler(cwd)\n if (!wrangler) {\n s.stop(`${pc.red('✗')} Wrangler CLI not found`)\n p.log.error(\n `Install it first:\\n ${pc.cyan('npm install -g wrangler')}\\n ${pc.dim('or')} ${pc.cyan('npx wrangler --version')}`\n )\n process.exit(1)\n }\n s.stop(`Wrangler: ${pc.cyan(wrangler.bin === 'npx' ? 'npx wrangler' : 'wrangler')}`)\n\n // 2. Check auth / prompt login\n s.start('Checking Cloudflare authentication')\n const whoami = runWrangler(wrangler, ['whoami'], { cwd })\n const whoamiOut = whoami.stdout?.toString() ?? ''\n\n if (whoami.status !== 0 || whoamiOut.includes('Not authenticated')) {\n s.stop(`${pc.yellow('▲')} Not logged in to Cloudflare`)\n const login = await p.confirm({\n message: 'Open browser to log in to Cloudflare?',\n initialValue: true,\n })\n if (p.isCancel(login) || !login) {\n p.cancel('Setup cancelled. Run `wrangler login` manually first.')\n process.exit(0)\n }\n\n s.start('Waiting for Cloudflare login')\n const loginResult = runWrangler(wrangler, ['login'], { cwd, stdio: 'inherit', timeout: 120_000 })\n if (loginResult.status !== 0) {\n s.stop(`${pc.red('✗')} Login failed`)\n p.cancel('Could not authenticate with Cloudflare. Run `wrangler login` manually.')\n process.exit(1)\n }\n s.stop(`${pc.green('✓')} Logged in to Cloudflare`)\n } else {\n // Table format: \"│ Peiris@kasun.io's Account │ <id> │\"\n // Or \"associated with the email user@example.com\"\n const emailMatch = whoamiOut.match(/associated with the email\\s+(\\S+)/i)\n const tableMatch = whoamiOut.match(/│\\s*([^│]+?)\\s*│\\s*[a-f0-9]{32}\\s*│/)\n const accountLabel = emailMatch?.[1] ?? tableMatch?.[1]?.trim() ?? 'authenticated'\n s.stop(`Logged in as ${pc.cyan(accountLabel)}`)\n }\n\n // 3. Get account ID\n s.start('Fetching account ID')\n const accountId = extractAccountId(wrangler, cwd)\n if (!accountId) {\n s.stop(`${pc.red('✗')} Could not determine account ID`)\n p.log.info(\n `You can find it at: ${pc.cyan('https://dash.cloudflare.com/?to=/:account/r2')}`\n )\n process.exit(1)\n }\n s.stop(`Account ID: ${pc.dim(accountId)}`)\n\n // 4. Prompt for bucket name\n let bucketName = options.bucket\n if (!bucketName) {\n const result = await p.text({\n message: 'R2 bucket name',\n placeholder: 'betterstart-uploads',\n defaultValue: 'betterstart-uploads',\n validate: (v) => {\n if (!v || v.length < 3) return 'Bucket name must be at least 3 characters'\n if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(v))\n return 'Bucket name must be lowercase alphanumeric with hyphens, no leading/trailing hyphens'\n },\n })\n if (p.isCancel(result)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n bucketName = result\n }\n\n // 5. Create bucket\n s.start(`Creating R2 bucket: ${bucketName}`)\n\n const createResult = runWrangler(wrangler, ['r2', 'bucket', 'create', bucketName], {\n cwd,\n timeout: 30_000,\n })\n const createOut = (createResult.stdout?.toString() ?? '') + (createResult.stderr?.toString() ?? '')\n\n if (createResult.status !== 0) {\n if (createOut.includes('already exists') || createOut.includes('AlreadyExists')) {\n s.stop(`Bucket ${pc.cyan(bucketName)} already exists — using it`)\n } else {\n s.stop('Failed to create bucket')\n p.log.error(createOut.trim() || 'Unknown error from wrangler')\n process.exit(1)\n }\n } else {\n s.stop(`Created bucket: ${pc.cyan(bucketName)}`)\n }\n\n // 6. Enable r2.dev public URL automatically\n let publicUrl = ''\n const oauthToken = readWranglerToken()\n if (oauthToken) {\n s.start('Enabling public r2.dev URL')\n const domainResult = await enablePublicDomain(accountId, bucketName, oauthToken)\n if (domainResult.success && domainResult.domain) {\n publicUrl = `https://${domainResult.domain}`\n s.stop(`Public URL: ${pc.cyan(publicUrl)}`)\n } else {\n s.stop('Could not enable public URL automatically')\n p.log.warning(domainResult.error ?? 'Unknown error')\n p.log.info(\n `You can enable it manually in the dashboard:\\n ${pc.cyan(`https://dash.cloudflare.com/${accountId}/r2/default/buckets/${bucketName}/settings`)}`\n )\n }\n } else {\n p.log.warning('Could not read wrangler OAuth token — skipping public URL setup')\n p.log.info(\n `Enable it manually: ${pc.cyan(`https://dash.cloudflare.com/${accountId}/r2/default/buckets/${bucketName}/settings`)}`\n )\n }\n\n // 7. Prompt for S3-compatible API credentials\n p.note(\n [\n `Create an R2 API token with ${pc.bold('Object Read & Write')} permission.`,\n '',\n `Dashboard: ${pc.cyan(`https://dash.cloudflare.com/${accountId}/r2/api-tokens`)}`,\n '',\n pc.dim('The dashboard will give you an Access Key ID and Secret Access Key.'),\n ].join('\\n'),\n 'Create R2 API Token'\n )\n\n const openDashboard = await p.confirm({\n message: 'Open the R2 API tokens page in your browser?',\n initialValue: true,\n })\n if (!p.isCancel(openDashboard) && openDashboard) {\n const url = `https://dash.cloudflare.com/${accountId}/r2/api-tokens`\n try {\n execFileSync('open', [url], { stdio: 'pipe', timeout: 5_000 })\n } catch {\n p.log.warning(`Could not open browser. Visit: ${pc.cyan(url)}`)\n }\n }\n\n const credentials = await p.group(\n {\n accessKeyId: () =>\n p.text({\n message: 'R2 Access Key ID',\n placeholder: 'Paste from Cloudflare dashboard',\n validate: (v) => {\n if (!v || v.trim().length < 10) return 'Please paste a valid Access Key ID'\n },\n }),\n secretAccessKey: () =>\n p.password({\n message: 'R2 Secret Access Key',\n validate: (v) => {\n if (!v || v.trim().length < 10) return 'Please paste a valid Secret Access Key'\n },\n }),\n },\n {\n onCancel: () => {\n p.cancel('Setup cancelled.')\n process.exit(0)\n },\n }\n )\n\n // 8. Write env vars to .env.local\n s.start('Writing environment variables')\n const envResult = appendEnvVars(cwd, [\n {\n header: 'Storage (Cloudflare R2)',\n vars: [\n { key: 'BETTERSTART_R2_ACCOUNT_ID', value: accountId },\n { key: 'BETTERSTART_R2_ACCESS_KEY_ID', value: credentials.accessKeyId.trim() },\n { key: 'BETTERSTART_R2_SECRET_ACCESS_KEY', value: credentials.secretAccessKey.trim() },\n { key: 'BETTERSTART_R2_BUCKET_NAME', value: bucketName },\n ...(publicUrl ? [{ key: 'BETTERSTART_R2_PUBLIC_URL', value: publicUrl }] : []),\n ],\n },\n ], new Set([\n 'BETTERSTART_R2_ACCOUNT_ID',\n 'BETTERSTART_R2_ACCESS_KEY_ID',\n 'BETTERSTART_R2_SECRET_ACCESS_KEY',\n 'BETTERSTART_R2_BUCKET_NAME',\n 'BETTERSTART_R2_PUBLIC_URL',\n ]))\n\n const totalChanged = envResult.added.length + envResult.updated.length\n if (totalChanged > 0) {\n s.stop(`Updated .env.local ${pc.dim(`(${envResult.added.length} added, ${envResult.updated.length} updated)`)}`)\n } else {\n s.stop('All R2 env vars already set in .env.local')\n }\n\n // Summary\n const summaryLines = [\n `Bucket: ${pc.cyan(bucketName)}`,\n `Account: ${pc.dim(accountId)}`,\n `Access Key: ${pc.dim(credentials.accessKeyId.trim().slice(0, 8) + '...')}`,\n ]\n if (publicUrl) {\n summaryLines.push(`Public URL: ${pc.cyan(publicUrl)}`)\n }\n summaryLines.push(`Env file: ${pc.dim('.env.local')}`)\n\n p.note(summaryLines.join('\\n'), pc.green('R2 storage configured'))\n\n p.outro('Done! Your CMS can now upload files to R2.')\n })\n\ninterface WranglerRef {\n bin: string\n prefix: string[] // e.g. ['wrangler'] when using npx, [] when direct\n}\n\n/** Find wrangler binary — check local node_modules, global PATH, then npx */\nfunction findWrangler(cwd: string): WranglerRef | null {\n // Check local\n const localBin = path.join(cwd, 'node_modules', '.bin', 'wrangler')\n if (fs.existsSync(localBin)) return { bin: localBin, prefix: [] }\n\n // Check global via which\n const result = spawnSync('which', ['wrangler'], { stdio: 'pipe', timeout: 5_000 })\n if (result.status === 0) {\n const found = result.stdout?.toString().trim()\n if (found) return { bin: found, prefix: [] }\n }\n\n // Fall back to npx — just check it resolves (fast, no download)\n const npxResult = spawnSync('npx', ['wrangler', '--version'], {\n stdio: 'pipe',\n timeout: 15_000,\n })\n if (npxResult.status === 0) return { bin: 'npx', prefix: ['wrangler'] }\n\n return null\n}\n\n/** Run a wrangler command via the resolved ref */\nfunction runWrangler(\n ref: WranglerRef,\n args: string[],\n opts: { cwd: string; timeout?: number; stdio?: 'pipe' | 'inherit' }\n) {\n const fullArgs = [...ref.prefix, ...args]\n return spawnSync(ref.bin, fullArgs, {\n cwd: opts.cwd,\n stdio: opts.stdio ?? 'pipe',\n timeout: opts.timeout ?? 15_000,\n })\n}\n\n/** Extract account ID from wrangler whoami output */\nfunction extractAccountId(ref: WranglerRef, cwd: string): string | null {\n const result = runWrangler(ref, ['whoami'], { cwd })\n const output = result.stdout?.toString() ?? ''\n\n // wrangler whoami prints account ID in format: \"Account ID: <id>\"\n const idMatch = output.match(/Account ID[:\\s]+([a-f0-9]{32})/i)\n if (idMatch) return idMatch[1]\n\n // Table format: look for 32-char hex string\n const hexMatch = output.match(/\\b([a-f0-9]{32})\\b/)\n if (hexMatch) return hexMatch[1]\n\n return null\n}\n\n/** Read the OAuth token from wrangler's config file */\nfunction readWranglerToken(): string | null {\n // Wrangler stores config at platform-specific paths\n const candidates = [\n path.join(os.homedir(), 'Library', 'Preferences', '.wrangler', 'config', 'default.toml'), // macOS\n path.join(os.homedir(), '.config', '.wrangler', 'config', 'default.toml'), // Linux\n path.join(os.homedir(), '.wrangler', 'config', 'default.toml'), // fallback\n ]\n\n if (process.env.WRANGLER_CONFIG_PATH) {\n candidates.unshift(process.env.WRANGLER_CONFIG_PATH)\n }\n if (process.env.XDG_CONFIG_HOME) {\n candidates.unshift(\n path.join(process.env.XDG_CONFIG_HOME, '.wrangler', 'config', 'default.toml')\n )\n }\n\n for (const configPath of candidates) {\n if (!fs.existsSync(configPath)) continue\n try {\n const content = fs.readFileSync(configPath, 'utf-8')\n const match = content.match(/^oauth_token\\s*=\\s*\"([^\"]+)\"/m)\n if (match) return match[1]\n } catch {\n continue\n }\n }\n return null\n}\n\n/** Enable the r2.dev managed public domain on a bucket via Cloudflare API */\nasync function enablePublicDomain(\n accountId: string,\n bucketName: string,\n token: string\n): Promise<{ success: boolean; domain?: string; error?: string }> {\n try {\n const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/r2/buckets/${bucketName}/domains/managed`\n const res = await fetch(url, {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ enabled: true }),\n })\n const data = (await res.json()) as {\n success: boolean\n result?: { domain?: string; enabled?: boolean }\n errors?: Array<{ message: string }>\n }\n if (data.success && data.result?.domain) {\n return { success: true, domain: data.result.domain }\n }\n const errMsg = data.errors?.[0]?.message ?? 'API returned success=false'\n return { success: false, error: errMsg }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : 'fetch failed' }\n }\n}\n","/**\n * uninstall command — fully reverse everything `betterstart init` did.\n * Removes CMS directories, config files, path aliases, CSS modifications,\n * env vars, and dependencies from package.json.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as p from '@clack/prompts'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { cleanCss, cleanEnvFile, cleanTsconfig } from './uninstall-cleaners.js'\n\n// ============================================================================\n// CSS File Finder (shared logic with tailwind scaffolder)\n// ============================================================================\n\nfunction findMainCss(cwd: string): string | undefined {\n const candidates = [\n 'src/app/globals.css',\n 'app/globals.css',\n 'src/app/global.css',\n 'app/global.css',\n 'src/app/app.css',\n 'app/app.css',\n 'src/globals.css',\n 'globals.css'\n ]\n for (const candidate of candidates) {\n const filePath = path.join(cwd, candidate)\n if (fs.existsSync(filePath)) return filePath\n }\n return undefined\n}\n\n// ============================================================================\n// Biome Detection\n// ============================================================================\n\nfunction isCLICreatedBiome(biomePath: string): boolean {\n if (!fs.existsSync(biomePath)) return false\n try {\n const content = JSON.parse(fs.readFileSync(biomePath, 'utf-8'))\n // Check key structural markers that match our template\n return (\n content.$schema?.includes('biomejs.dev') &&\n content.formatter?.indentStyle === 'space' &&\n content.javascript?.formatter?.quoteStyle === 'single' &&\n Array.isArray(content.files?.ignore) &&\n content.files.ignore.includes('.next')\n )\n } catch {\n return false\n }\n}\n\n// ============================================================================\n// Uninstall Plan\n// ============================================================================\n\ninterface UninstallStep {\n label: string\n items: string[]\n count: number\n unit: string\n execute: () => void\n}\n\nfunction buildUninstallPlan(cwd: string): UninstallStep[] {\n const steps: UninstallStep[] = []\n const hasSrc = fs.existsSync(path.join(cwd, 'src'))\n const appBase = hasSrc ? 'src/app' : 'app'\n\n // Step 1: CMS directories\n const dirs: string[] = []\n const cmsDir = path.join(cwd, 'cms')\n const cmsRouteGroup = path.join(cwd, appBase, '(cms)')\n if (fs.existsSync(cmsDir)) dirs.push('cms/')\n if (fs.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`)\n\n if (dirs.length > 0) {\n steps.push({\n label: 'CMS directories',\n items: dirs,\n count: dirs.length,\n unit: dirs.length === 1 ? 'directory' : 'directories',\n execute() {\n if (fs.existsSync(cmsDir)) fs.rmSync(cmsDir, { recursive: true, force: true })\n if (fs.existsSync(cmsRouteGroup)) fs.rmSync(cmsRouteGroup, { recursive: true, force: true })\n }\n })\n }\n\n // Step 2: Config files\n const configFiles: string[] = []\n const configPaths: string[] = []\n const candidates = [\n ['cms.config.ts', path.join(cwd, 'cms.config.ts')],\n ['drizzle.config.ts', path.join(cwd, 'drizzle.config.ts')],\n ['CMS.md', path.join(cwd, 'CMS.md')]\n ] as const\n\n for (const [label, fullPath] of candidates) {\n if (fs.existsSync(fullPath)) {\n configFiles.push(label)\n configPaths.push(fullPath)\n }\n }\n\n const biomePath = path.join(cwd, 'biome.json')\n if (isCLICreatedBiome(biomePath)) {\n configFiles.push('biome.json (CLI-created)')\n configPaths.push(biomePath)\n }\n\n if (configFiles.length > 0) {\n steps.push({\n label: 'Config files',\n items: configFiles,\n count: configFiles.length,\n unit: configFiles.length === 1 ? 'file' : 'files',\n execute() {\n for (const p of configPaths) {\n if (fs.existsSync(p)) fs.unlinkSync(p)\n }\n }\n })\n }\n\n // Step 3: tsconfig.json @cms/* aliases\n const tsconfigPath = path.join(cwd, 'tsconfig.json')\n if (fs.existsSync(tsconfigPath)) {\n const content = fs.readFileSync(tsconfigPath, 'utf-8')\n const aliasMatches = content.match(/\"@cms\\//g)\n if (aliasMatches && aliasMatches.length > 0) {\n const aliasCount = aliasMatches.length\n steps.push({\n label: 'tsconfig.json path aliases',\n items: [`@cms/* aliases in tsconfig.json`],\n count: aliasCount,\n unit: aliasCount === 1 ? 'alias' : 'aliases',\n execute() {\n cleanTsconfig(tsconfigPath)\n }\n })\n }\n }\n\n // Step 4: CSS @source lines\n const cssFile = findMainCss(cwd)\n if (cssFile) {\n const cssContent = fs.readFileSync(cssFile, 'utf-8')\n const sourceLines = cssContent\n .split('\\n')\n .filter((l) => /^@source\\s+\"[^\"]*cms[^\"]*\";\\s*$/.test(l))\n if (sourceLines.length > 0) {\n const relCss = path.relative(cwd, cssFile)\n steps.push({\n label: `CSS @source lines (${relCss})`,\n items: [`@source lines in ${relCss}`],\n count: sourceLines.length,\n unit: sourceLines.length === 1 ? 'line' : 'lines',\n execute() {\n cleanCss(cssFile)\n }\n })\n }\n }\n\n // Step 5: .env.local BETTERSTART_* vars\n const envPath = path.join(cwd, '.env.local')\n if (fs.existsSync(envPath)) {\n const envContent = fs.readFileSync(envPath, 'utf-8')\n const bsVars = envContent\n .split('\\n')\n .filter((l) => l.trim().match(/^BETTERSTART_\\w+=/))\n .map((l) => l.split('=')[0]!)\n if (bsVars.length > 0) {\n steps.push({\n label: '.env.local variables',\n items: ['BETTERSTART_* vars in .env.local'],\n count: bsVars.length,\n unit: bsVars.length === 1 ? 'variable' : 'variables',\n execute() {\n cleanEnvFile(envPath)\n }\n })\n }\n }\n\n return steps\n}\n\n// ============================================================================\n// Command\n// ============================================================================\n\nexport const uninstallCommand = new Command('uninstall')\n .description('Remove all CMS files and undo modifications made by betterstart init')\n .option('-f, --force', 'Skip all confirmation prompts', false)\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { force: boolean; cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n p.intro(pc.bgRed(pc.white(' BetterStart Uninstall ')))\n\n // Build the plan\n const steps = buildUninstallPlan(cwd)\n\n if (steps.length === 0) {\n p.log.success(`${pc.green('✓')} Nothing to remove — project is already clean.`)\n p.outro('Done')\n return\n }\n\n // Show plan as a formatted note box\n const planLines = steps.map((step) => {\n const names = step.items.join(' ')\n const countLabel = pc.dim(`${step.count} ${step.unit}`)\n return `${pc.red('×')} ${names} ${countLabel}`\n })\n p.note(planLines.join('\\n'), 'Uninstall plan')\n\n // Single confirmation for everything\n if (!options.force) {\n const confirmed = await p.confirm({\n message: 'Proceed with uninstall?',\n initialValue: false\n })\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Uninstall cancelled.')\n process.exit(0)\n }\n }\n\n // Execute all steps with a single spinner\n const s = p.spinner()\n s.start(steps[0]!.label)\n for (const step of steps) {\n s.message(step.label)\n step.execute()\n }\n const parts = steps.map((step) => `${step.count} ${step.unit}`)\n s.stop(`Removed ${parts.join(', ')}`)\n\n p.note(pc.dim('Database tables were NOT dropped — drop them manually if needed.'), 'Next steps')\n\n p.outro('Uninstall complete')\n })\n","/**\n * Cleaner functions for `betterstart uninstall`.\n * Each function modifies a single file type and returns what was removed.\n */\n\nimport fs from 'node:fs'\n\n// ============================================================================\n// JSON Comment Stripper (shared with tsconfig scaffolder)\n// ============================================================================\n\nfunction stripJsonComments(input: string): string {\n let result = ''\n let i = 0\n while (i < input.length) {\n if (input[i] === '\"') {\n let j = i + 1\n while (j < input.length) {\n if (input[j] === '\\\\') {\n j += 2\n continue\n }\n if (input[j] === '\"') {\n j++\n break\n }\n j++\n }\n result += input.slice(i, j)\n i = j\n } else if (input[i] === '/' && input[i + 1] === '/') {\n const nl = input.indexOf('\\n', i)\n i = nl === -1 ? input.length : nl\n } else if (input[i] === '/' && input[i + 1] === '*') {\n const end = input.indexOf('*/', i + 2)\n i = end === -1 ? input.length : end + 2\n } else {\n result += input[i]\n i++\n }\n }\n return result\n}\n\n// ============================================================================\n// cleanTsconfig\n// ============================================================================\n\n/**\n * Remove all `@cms/*` path aliases from tsconfig.json.\n * Returns the list of removed alias keys.\n */\nexport function cleanTsconfig(tsconfigPath: string): string[] {\n if (!fs.existsSync(tsconfigPath)) return []\n\n const raw = fs.readFileSync(tsconfigPath, 'utf-8')\n const stripped = stripJsonComments(raw).replace(/,\\s*([\\]}])/g, '$1')\n\n let tsconfig: Record<string, unknown>\n try {\n tsconfig = JSON.parse(stripped)\n } catch {\n return []\n }\n\n const compilerOptions = (tsconfig.compilerOptions ?? {}) as Record<string, unknown>\n const paths = (compilerOptions.paths ?? {}) as Record<string, string[]>\n\n const removed: string[] = []\n for (const key of Object.keys(paths)) {\n if (key.startsWith('@cms/') || key === '@cms/*') {\n removed.push(key)\n delete paths[key]\n }\n }\n\n if (removed.length === 0) return []\n\n if (Object.keys(paths).length === 0) {\n compilerOptions.paths = undefined\n } else {\n compilerOptions.paths = paths\n }\n tsconfig.compilerOptions = compilerOptions\n\n fs.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\\n`, 'utf-8')\n return removed\n}\n\n// ============================================================================\n// cleanCss\n// ============================================================================\n\n/**\n * Remove @source lines containing \"cms\" from a CSS file.\n * Returns the removed lines.\n */\nexport function cleanCss(cssPath: string): string[] {\n if (!fs.existsSync(cssPath)) return []\n\n const content = fs.readFileSync(cssPath, 'utf-8')\n const lines = content.split('\\n')\n\n const sourcePattern = /^@source\\s+\"[^\"]*cms[^\"]*\";\\s*$/\n const removed: string[] = []\n const kept: string[] = []\n\n for (const line of lines) {\n if (sourcePattern.test(line)) {\n removed.push(line.trim())\n } else {\n kept.push(line)\n }\n }\n\n if (removed.length === 0) return []\n\n // Clean up resulting double blank lines\n const cleaned = kept.join('\\n').replace(/\\n{3,}/g, '\\n\\n')\n fs.writeFileSync(cssPath, cleaned, 'utf-8')\n return removed\n}\n\n// ============================================================================\n// cleanEnvFile\n// ============================================================================\n\n/**\n * Remove BETTERSTART_* vars and the BetterStart header block from .env.local.\n * Returns the removed variable names.\n */\nexport function cleanEnvFile(envPath: string): string[] {\n if (!fs.existsSync(envPath)) return []\n\n const content = fs.readFileSync(envPath, 'utf-8')\n const lines = content.split('\\n')\n const removed: string[] = []\n const kept: string[] = []\n\n // Track header block lines to remove\n const headerPattern = /^# =+$/\n const headerTextPattern = /^# BetterStart CMS$/\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n const trimmed = line.trim()\n\n // Remove BETTERSTART_* variable lines\n if (trimmed.match(/^BETTERSTART_\\w+=/)) {\n const key = trimmed.split('=')[0]!\n removed.push(key)\n continue\n }\n\n // Remove header block: # ====... / # BetterStart CMS / # ====...\n if (headerPattern.test(trimmed)) {\n const next = lines[i + 1]?.trim()\n const afterNext = lines[i + 2]?.trim()\n if (next && headerTextPattern.test(next) && afterNext && headerPattern.test(afterNext)) {\n i += 2 // skip all 3 header lines\n continue\n }\n }\n\n // Remove section comment headers that only precede BETTERSTART_ vars\n // e.g., \"# Database (Neon)\" followed by BETTERSTART_DATABASE_URL\n if (trimmed.startsWith('#') && !headerPattern.test(trimmed)) {\n const nextNonEmpty = findNextNonEmptyLine(lines, i + 1)\n if (nextNonEmpty?.match(/^BETTERSTART_\\w+=/)) {\n continue // skip this comment header\n }\n }\n\n kept.push(line)\n }\n\n if (removed.length === 0) return []\n\n // Clean up multiple blank lines\n const result = kept\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n\n if (result === '') {\n // File is now empty — delete it\n fs.unlinkSync(envPath)\n } else {\n fs.writeFileSync(envPath, `${result}\\n`, 'utf-8')\n }\n\n return removed\n}\n\nfunction findNextNonEmptyLine(lines: string[], startIndex: number): string | null {\n for (let i = startIndex; i < lines.length; i++) {\n const trimmed = lines[i]!.trim()\n if (trimmed !== '') return trimmed\n }\n return null\n}\n\n// ============================================================================\n// cleanPackageJsonDeps\n// ============================================================================\n\n/**\n * Remove CMS dependencies from package.json.\n * Returns the removed dep and devDep names.\n */\nexport function cleanPackageJsonDeps(\n pkgPath: string,\n allDeps: string[],\n allDevDeps: string[]\n): { removed: string[]; removedDev: string[] } {\n if (!fs.existsSync(pkgPath)) return { removed: [], removedDev: [] }\n\n const content = fs.readFileSync(pkgPath, 'utf-8')\n let pkg: Record<string, unknown>\n try {\n pkg = JSON.parse(content)\n } catch {\n return { removed: [], removedDev: [] }\n }\n\n const deps = (pkg.dependencies ?? {}) as Record<string, string>\n const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>\n\n // Build lookup set: handle version-pinned names like @types/markdown-it@13 → @types/markdown-it\n const depNames = new Set(\n allDeps.map((d) =>\n d\n .split('@')\n .slice(0, d.startsWith('@') ? 2 : 1)\n .join('@')\n )\n )\n const devDepNames = new Set(\n allDevDeps.map((d) =>\n d\n .split('@')\n .slice(0, d.startsWith('@') ? 2 : 1)\n .join('@')\n )\n )\n\n const removed: string[] = []\n for (const name of Object.keys(deps)) {\n if (depNames.has(name)) {\n delete deps[name]\n removed.push(name)\n }\n }\n\n const removedDev: string[] = []\n for (const name of Object.keys(devDeps)) {\n if (devDepNames.has(name)) {\n delete devDeps[name]\n removedDev.push(name)\n }\n }\n\n if (removed.length === 0 && removedDev.length === 0) {\n return { removed: [], removedDev: [] }\n }\n\n pkg.dependencies = deps\n pkg.devDependencies = devDeps\n fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`, 'utf-8')\n\n return { removed, removedDev }\n}\n","/**\n * update-component command — update individual CMS components from the latest CLI templates\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport fsExtra from 'fs-extra'\nimport { resolveConfig } from '../config/resolver.js'\nimport { cmsGlobalsCssTemplate } from '../init/templates/components/cms-globals.js'\nimport { dataTableTemplate } from '../init/templates/components/data-table/data-table.js'\nimport { dataTablePaginationTemplate } from '../init/templates/components/data-table/data-table-pagination.js'\nimport { dataTableToolbarTemplate } from '../init/templates/components/data-table/data-table-toolbar.js'\nimport { cmsHeaderTemplate } from '../init/templates/components/layout/cms-header.js'\nimport { cmsNavLinkTemplate } from '../init/templates/components/layout/cms-nav-link.js'\nimport { cmsProvidersTemplate } from '../init/templates/components/layout/cms-providers.js'\nimport { cmsSearchTemplate } from '../init/templates/components/layout/cms-search.js'\nimport { cmsSidebarTemplate } from '../init/templates/components/layout/cms-sidebar.js'\nimport { deleteDialogTemplate } from '../init/templates/components/shared/delete-dialog.js'\nimport { pageHeaderTemplate } from '../init/templates/components/shared/page-header.js'\nimport { statusBadgeTemplate } from '../init/templates/components/shared/status-badge.js'\nimport { useCmsThemeTemplate } from '../init/templates/hooks/use-cms-theme.js'\nimport { useEditorImageUploadHookTemplate } from '../init/templates/hooks/use-editor-image-upload.js'\nimport { useLocalStorageHookTemplate } from '../init/templates/hooks/use-local-storage.js'\nimport { useMobileHookTemplate } from '../init/templates/hooks/use-mobile.js'\nimport { useUploadHookTemplate } from '../init/templates/hooks/use-upload.js'\nimport { useUsersHookTemplate } from '../init/templates/hooks/use-users.js'\nimport { formSettingsActionTemplate } from '../init/templates/lib/actions/form-settings.js'\nimport { uploadActionTemplate } from '../init/templates/lib/actions/upload.js'\nimport { usersActionTemplate } from '../init/templates/lib/actions/users.js'\nimport { markdownCachedTemplate } from '../init/templates/lib/markdown/cached.js'\nimport { markdownFormatTemplate } from '../init/templates/lib/markdown/format.js'\nimport { markdownRenderTemplate } from '../init/templates/lib/markdown/render.js'\nimport { r2ClientTemplate } from '../init/templates/lib/r2.js'\nimport { authTypesTemplate } from '../init/templates/types/auth.js'\nimport { typesIndexTemplate } from '../init/templates/types/index.js'\nimport { tableMetaTypesTemplate } from '../init/templates/types/table-meta.js'\nimport { cnUtilTemplate } from '../init/templates/utils/cn.js'\nimport { mailchimpUtilTemplate } from '../init/templates/utils/mailchimp.js'\nimport { seoUtilTemplate } from '../init/templates/utils/seo.js'\nimport { validationUtilTemplate } from '../init/templates/utils/validation.js'\nimport { webhookUtilTemplate } from '../init/templates/utils/webhook.js'\n\ninterface TemplateEntry {\n relPath: string\n content: () => string\n}\n\n/**\n * Template-function components (layout, shared, hooks, utils, etc.)\n * Key = component name used on CLI, value = { relative path in cms/, content generator }\n */\nconst TEMPLATE_REGISTRY: Record<string, TemplateEntry> = {\n // CSS\n 'cms-globals': { relPath: 'cms-globals.css', content: cmsGlobalsCssTemplate },\n // Layout\n 'cms-providers': { relPath: 'components/layout/cms-providers.tsx', content: cmsProvidersTemplate },\n 'cms-nav-link': { relPath: 'components/layout/cms-nav-link.tsx', content: cmsNavLinkTemplate },\n 'cms-sidebar': { relPath: 'components/layout/cms-sidebar.tsx', content: cmsSidebarTemplate },\n 'cms-header': { relPath: 'components/layout/cms-header.tsx', content: cmsHeaderTemplate },\n 'cms-search': { relPath: 'components/layout/cms-search.tsx', content: cmsSearchTemplate },\n // Shared\n 'page-header': { relPath: 'components/shared/page-header.tsx', content: pageHeaderTemplate },\n 'delete-dialog': { relPath: 'components/shared/delete-dialog.tsx', content: deleteDialogTemplate },\n 'status-badge': { relPath: 'components/shared/status-badge.tsx', content: statusBadgeTemplate },\n // Data table\n 'data-table': { relPath: 'components/data-table/data-table.tsx', content: dataTableTemplate },\n 'data-table-pagination': { relPath: 'components/data-table/data-table-pagination.tsx', content: dataTablePaginationTemplate },\n 'data-table-toolbar': { relPath: 'components/data-table/data-table-toolbar.tsx', content: dataTableToolbarTemplate },\n // Hooks\n 'use-upload': { relPath: 'hooks/use-upload.ts', content: useUploadHookTemplate },\n 'use-editor-image-upload': { relPath: 'hooks/use-editor-image-upload.ts', content: useEditorImageUploadHookTemplate },\n 'use-local-storage': { relPath: 'hooks/use-local-storage.ts', content: useLocalStorageHookTemplate },\n 'use-cms-theme': { relPath: 'hooks/use-cms-theme.tsx', content: useCmsThemeTemplate },\n 'use-users': { relPath: 'hooks/use-users.ts', content: useUsersHookTemplate },\n 'use-mobile': { relPath: 'hooks/use-mobile.ts', content: useMobileHookTemplate },\n // Types\n 'types-index': { relPath: 'types/index.ts', content: typesIndexTemplate },\n 'auth-types': { relPath: 'types/auth.ts', content: authTypesTemplate },\n 'table-meta': { relPath: 'types/table-meta.ts', content: tableMetaTypesTemplate },\n // Utils\n cn: { relPath: 'utils/cn.ts', content: cnUtilTemplate },\n seo: { relPath: 'utils/seo.ts', content: seoUtilTemplate },\n validation: { relPath: 'utils/validation.ts', content: validationUtilTemplate },\n webhook: { relPath: 'utils/webhook.ts', content: webhookUtilTemplate },\n mailchimp: { relPath: 'utils/mailchimp.ts', content: mailchimpUtilTemplate },\n // Lib\n r2: { relPath: 'lib/r2.ts', content: r2ClientTemplate },\n 'form-settings-action': { relPath: 'lib/actions/form-settings.ts', content: formSettingsActionTemplate },\n 'upload-action': { relPath: 'lib/actions/upload.ts', content: uploadActionTemplate },\n 'users-action': { relPath: 'lib/actions/users.ts', content: usersActionTemplate },\n // Markdown\n 'markdown-render': { relPath: 'lib/markdown/render.ts', content: markdownRenderTemplate },\n 'markdown-format': { relPath: 'lib/markdown/format.ts', content: markdownFormatTemplate },\n 'markdown-cached': { relPath: 'lib/markdown/cached.ts', content: markdownCachedTemplate },\n}\n\n/**\n * Find the CLI package root by looking for package.json with our name.\n */\nfunction findCliRoot(): string {\n let dir = new URL('.', import.meta.url).pathname\n for (let i = 0; i < 5; i++) {\n const pkgPath = path.join(dir, 'package.json')\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n if (pkg.name === '@betterstart/cli') {\n return dir\n }\n } catch {\n // continue\n }\n }\n dir = path.dirname(dir)\n }\n return path.resolve(new URL('.', import.meta.url).pathname, '..', '..')\n}\n\n/**\n * Get all available static UI component names from templates/ui/\n */\nfunction getStaticUiComponents(): string[] {\n const cliRoot = findCliRoot()\n const uiDir = path.join(cliRoot, 'templates', 'ui')\n if (!fs.existsSync(uiDir)) return []\n return fs\n .readdirSync(uiDir)\n .filter((f: string) => f.endsWith('.tsx') || f.endsWith('.ts'))\n .map((f: string) => f.replace(/\\.(tsx|ts)$/, ''))\n}\n\nfunction getAllComponentNames(): string[] {\n const staticUi = getStaticUiComponents()\n const templateKeys = Object.keys(TEMPLATE_REGISTRY)\n return [...new Set([...staticUi, ...templateKeys, 'tiptap'])].sort()\n}\n\nexport const updateComponentCommand = new Command('update-component')\n .description('Update individual CMS components from the latest CLI templates')\n .argument('[components...]', 'Component names to update (e.g., media-upload-field button)')\n .option('--list', 'List all available components')\n .option('--all', 'Update all components')\n .option('--cwd <path>', 'Project root path')\n .action(async (components: string[], options: { list?: boolean; all?: boolean; cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n if (options.list) {\n const all = getAllComponentNames()\n clack.intro('Available components')\n\n const uiComponents = getStaticUiComponents()\n const templateKeys = Object.keys(TEMPLATE_REGISTRY).sort()\n\n // UI components table\n console.log()\n console.log(` UI Components (${uiComponents.length})`)\n console.log(` ${'─'.repeat(50)}`)\n console.log(` ${'Name'.padEnd(28)} ${'Path'}`)\n console.log(` ${'─'.repeat(50)}`)\n for (const name of uiComponents) {\n console.log(` ${name.padEnd(28)} components/ui/${name}.tsx`)\n }\n\n // Template components table\n console.log()\n console.log(` Template Components (${templateKeys.length})`)\n console.log(` ${'─'.repeat(56)}`)\n console.log(` ${'Name'.padEnd(28)} ${'Path'}`)\n console.log(` ${'─'.repeat(56)}`)\n for (const name of templateKeys) {\n console.log(` ${name.padEnd(28)} ${TEMPLATE_REGISTRY[name].relPath}`)\n }\n\n // Special\n console.log()\n console.log(` Special`)\n console.log(` ${'─'.repeat(56)}`)\n console.log(` ${'tiptap'.padEnd(28)} components/ui/tiptap/ (all files)`)\n console.log()\n\n clack.outro(`${all.length} components available`)\n return\n }\n\n if (!options.all && components.length === 0) {\n clack.log.error('Provide component names or use --all. Run with --list to see available components.')\n process.exit(1)\n }\n\n const config = await resolveConfig(cwd)\n const cms = path.resolve(cwd, config.paths.cms)\n\n if (!fs.existsSync(cms)) {\n clack.cancel(`CMS directory not found at ${config.paths.cms}. Run 'betterstart init' first.`)\n process.exit(1)\n }\n\n clack.intro('BetterStart Update Components')\n\n const toUpdate = options.all ? getAllComponentNames() : components\n const cliRoot = findCliRoot()\n const uiDir = path.join(cliRoot, 'templates', 'ui')\n let updated = 0\n let skipped = 0\n\n for (const name of toUpdate) {\n // 1. Check template registry (template functions)\n if (TEMPLATE_REGISTRY[name]) {\n const entry = TEMPLATE_REGISTRY[name]\n const destPath = path.join(cms, entry.relPath)\n fsExtra.ensureDirSync(path.dirname(destPath))\n fs.writeFileSync(destPath, entry.content(), 'utf-8')\n clack.log.success(`Updated ${entry.relPath}`)\n updated++\n continue\n }\n\n // 2. Check static UI templates\n const uiFile = fs.readdirSync(uiDir).find(\n (f: string) => f.replace(/\\.(tsx|ts)$/, '') === name,\n )\n if (uiFile) {\n const destPath = path.join(cms, 'components', 'ui', uiFile)\n fsExtra.ensureDirSync(path.dirname(destPath))\n fs.copyFileSync(path.join(uiDir, uiFile), destPath)\n clack.log.success(`Updated components/ui/${uiFile}`)\n updated++\n continue\n }\n\n // 3. Special: tiptap directory\n if (name === 'tiptap') {\n const srcDir = path.join(cliRoot, 'templates', 'tiptap')\n const destDir = path.join(cms, 'components', 'ui', 'tiptap')\n if (fs.existsSync(srcDir)) {\n fsExtra.copySync(srcDir, destDir, { overwrite: true })\n clack.log.success('Updated components/ui/tiptap/ (all files)')\n updated++\n } else {\n clack.log.warning('tiptap templates not found')\n skipped++\n }\n continue\n }\n\n clack.log.warning(`Unknown component: ${name}`)\n skipped++\n }\n\n clack.outro(`Updated ${updated} component${updated !== 1 ? 's' : ''}${skipped > 0 ? `, ${skipped} skipped` : ''}`)\n })\n","/**\n * update-deps command — (re-)install all required CMS dependencies.\n * Safe to run repeatedly; the package manager will skip already-installed packages.\n */\n\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport { installDependenciesAsync } from '../init/scaffolders/dependencies.js'\nimport { detectPackageManager } from '../utils/package-manager.js'\n\nexport const updateDepsCommand = new Command('update-deps')\n .description('Install or update all CMS dependencies')\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n clack.intro('BetterStart Update Dependencies')\n\n const pm = detectPackageManager(cwd)\n clack.log.info(`Package manager: ${pm}`)\n\n const config = await resolveConfig(cwd)\n const includeEmail = config.features?.email ?? true\n\n const s = clack.spinner()\n s.start('Installing dependencies...')\n\n const result = await installDependenciesAsync({\n cwd,\n pm,\n includeEmail,\n includeBiome: false\n })\n\n if (result.success) {\n s.stop(`Installed ${result.coreDeps.length} deps + ${result.devDeps.length} dev deps`)\n } else {\n s.stop('Dependency install failed')\n clack.log.error(result.error ?? 'Unknown error')\n process.exit(1)\n }\n\n clack.outro('Dependencies updated')\n })\n","/**\n * update-styles command — replace cms-globals.css with the latest version\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport * as clack from '@clack/prompts'\nimport { Command } from 'commander'\nimport { resolveConfig } from '../config/resolver.js'\nimport { cmsGlobalsCssTemplate } from '../init/templates/components/cms-globals.js'\n\nexport const updateStylesCommand = new Command('update-styles')\n .description('Replace cms-globals.css with the latest version from the CLI')\n .option('--cwd <path>', 'Project root path')\n .action(async (options: { cwd?: string }) => {\n const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()\n\n clack.intro('BetterStart Update Styles')\n\n const config = await resolveConfig(cwd)\n const cmsDir = config.paths?.cms ?? './cms'\n const targetPath = path.join(cwd, cmsDir, 'cms-globals.css')\n\n if (!fs.existsSync(targetPath)) {\n clack.cancel(`cms-globals.css not found at ${path.relative(cwd, targetPath)}`)\n process.exit(1)\n }\n\n fs.writeFileSync(targetPath, cmsGlobalsCssTemplate(), 'utf-8')\n\n clack.log.success(`Updated ${path.relative(cwd, targetPath)}`)\n clack.outro('Styles updated')\n })\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6LT;;;AC9LO,SAAS,8BAAsC;AACpD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0JT;;;ACzJO,SAAS,sBAA8B;AAC5C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkJT;;;ACrJO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQT;;;ACTO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwDT;;;ACzDO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuLT;;;ACxLO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwDT;;;ACzDO,SAAS,oBAA4B;AAC1C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqHT;;;ACtHO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6FT;;;AC9FO,SAAS,uBAA+B;AAC7C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkPT;;;ACnPO,SAAS,oBAA4B;AAC1C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBT;;;ACrBO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["Command","path","fs","path","path","fs","content","parsed","path","fs","path","p","path","fs","fs","path","path","fs","p","fs","path","path","fs","fs","path","path","fs","fs","path","fs","path","fs","path","path","fs","p","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","fns","fs","path","generateColumnDef","fs","path","path","fs","generateColumns","path","fs","generateColumnDef","fs","path","path","fs","fs","path","findTableEnd","path","fs","fs","path","path","fs","fs","path","base","generateFieldJSX","buildZodFields","buildDefaultValues","path","fs","buildZodFields","buildDefaultValues","generateFieldJSX","fs","path","path","fs","buildZodFields","buildDefaultValues","generateFieldJSX","fs","path","path","fs","fs","path","parseNavigationFile","extractTopLevelArray","parseItemsBlock","parseSingleItem","generateNavigationCode","appendItem","fs","path","generatePage","path","fs","fs","path","generatePageContent","path","fs","fs","path","path","fs","fs","path","generateTable","path","fs","generateColumns","generateTable","generatePageContent","generatePage","execFileSync","fs","path","fs","path","path","fs","execFileSync","path","result","execFileSync","spawn","fs","path","p","Command","pc","execFileSync","p","p","path","fs","path","path","path","path","fs","path","path","fs","fs","path","path","fs","fs","path","path","fs","path","path","fs","path","path","path","fs","path","path","fs","fs","path","fs","path","fs","path","Command","Command","path","password","fs","runSeed","spinner","Command","pc","path","fs","execFileSync","drizzleConfigTemplate","spawn","password","fs","path","Command","findTableEnd","fs","Command","path","execFileSync","fs","path","p","Command","pc","Command","path","pc","execFileSync","fs","fs","path","p","Command","pc","fs","stripJsonComments","findMainCss","path","fs","p","Command","pc","fs","path","clack","Command","findCliRoot","path","fs","Command","path","clack","Command","Command","path","fs","path","clack","Command","Command","path","fs","Command"]}
|