@betterstart/cli 0.1.16 → 0.1.17
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 +25 -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.ts","../src/generators/form-generator.ts","../src/core/type-mappers.ts","../src/generators/email-template.ts","../src/generators/form-admin-pages.ts","../src/generators/form-navigation.ts","../src/generators/actions.ts","../src/generators/cache.ts","../src/generators/columns.ts","../src/generators/create-page.ts","../src/generators/database.ts","../src/generators/edit-page.ts","../src/generators/form.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-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-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/scaffolders/database.ts","../src/init/templates/db/client.ts","../src/init/templates/db/drizzle-config.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"],"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'\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)\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-generator.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.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 helper utilities for the codegen system\n * Consolidates duplicated field-checking functions from generators\n */\n\nimport type { FormField, FormSchema, 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// Field Collection\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/**\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(\n fields: SchemaField[],\n options?: WalkFieldsOptions\n): SchemaField[] {\n const result: SchemaField[] = []\n walkFields(\n fields,\n (field) => {\n if (field.type === 'relationship' && field.relationship && !field.multiple) {\n result.push(field)\n }\n },\n options\n )\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// ============================================================================\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// Form Field Helpers\n// ============================================================================\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// Field Analysis\n// ============================================================================\n\nexport interface FieldAnalysis {\n hasBoolean: boolean\n hasImage: boolean\n hasVideo: boolean\n hasMedia: boolean\n hasDate: boolean\n hasList: boolean\n hasNestedList: boolean\n hasSelect: boolean\n hasMarkdown: boolean\n hasTextarea: boolean\n hasSeparator: boolean\n hasIcon: boolean\n hasRelationship: boolean\n hasManyToMany: boolean\n fieldTypes: Set<string>\n}\n\n/**\n * Analyze all field types in a schema\n */\nexport function analyzeFields(fields: SchemaField[]): FieldAnalysis {\n const fieldTypes = new Set<string>()\n let hasIcon = false\n let hasNestedList = false\n\n walkFields(fields, (field) => {\n fieldTypes.add(field.type)\n if (field.type === 'icon' || field.hasIcon) hasIcon = true\n })\n\n const listFields = getListFieldsWithNestedFields(fields)\n for (const listField of listFields) {\n if (listField.fields?.some((f) => f.type === 'list')) {\n hasNestedList = true\n break\n }\n }\n\n return {\n hasBoolean: fieldTypes.has('boolean'),\n hasImage: fieldTypes.has('image'),\n hasVideo: fieldTypes.has('video'),\n hasMedia: fieldTypes.has('media'),\n hasDate: fieldTypes.has('date'),\n hasList: fieldTypes.has('list'),\n hasNestedList,\n hasSelect: fieldTypes.has('select'),\n hasMarkdown: fieldTypes.has('markdown'),\n hasTextarea: fieldTypes.has('text'),\n hasSeparator: fieldTypes.has('separator'),\n hasIcon,\n hasRelationship: fieldTypes.has('relationship'),\n hasManyToMany: getManyToManyFields(fields).length > 0,\n fieldTypes\n }\n}\n","/**\n * Form generator: generates database schema, server actions, React Query hook,\n * and public form component for \"type\": \"form\" schemas.\n *\n * Orchestrated by runFormPipeline() — called from the generate command.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { BetterstartConfig } from '../config/types.js'\nimport { formFieldToDrizzleType, formFieldToZodType } from '../core/type-mappers.js'\nimport type { FormField, FormSchema, GeneratorOptions } from '../types.js'\nimport { generateEmailTemplate } from './email-template.js'\nimport { generateFormAdminPages } from './form-admin-pages.js'\nimport { updateFormNavigation } from './form-navigation.js'\n\n// ============================================================================\n// String Helpers (local to this generator)\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n// ============================================================================\n// Field Helpers\n// ============================================================================\n\n/**\n * Get all fields from a form schema (flatten steps and groups)\n * Skips dynamicFields since they have no database columns\n */\nfunction getAllFields(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) {\n return flatten(field.fields)\n }\n return field.type === 'group' ? [] : [field]\n })\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 * Check if a form schema has dynamicFields\n */\nfunction hasDynamicFields(schema: FormSchema): boolean {\n const check = (fields: FormField[]): boolean => {\n for (const field of fields) {\n if (field.type === 'dynamicFields') return true\n if (field.type === 'group' && field.fields && check(field.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// ============================================================================\n// Result Types\n// ============================================================================\n\nexport interface FormPipelineResult {\n success: boolean\n files: string[]\n errors: string[]\n}\n\ninterface StepResult {\n files: string[]\n}\n\n// ============================================================================\n// Step 1: Database Schema\n// ============================================================================\n\nfunction 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 = getAllFields(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 existing table if --force\n if (content.includes(`export const ${tableName}`)) {\n if (!options.force) {\n return { files: [dbSchemaPath] }\n }\n const regex = new RegExp(`\\\\nexport const ${tableName} = pgTable\\\\([\\\\s\\\\S]*?\\\\n\\\\}\\\\)\\\\n`, 'g')\n content = content.replace(regex, '')\n }\n\n content += `\\n${tableSchema}`\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [dbSchemaPath] }\n}\n\n// ============================================================================\n// Step 2: Server Actions\n// ============================================================================\n\nfunction 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 = getAllFields(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 filePath = path.join(cwd, actionsDir, `${formName}-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 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'\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) => 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 }\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) => {\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// ============================================================================\n// Step 3: React Query Hook\n// ============================================================================\n\nfunction 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\n const filePath = path.join(cwd, hooksDir, `use-${toKebabCase(formName)}-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/${formName}-form'\nimport type { Create${pascal}SubmissionInput } from '@cms/actions/${formName}-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// ============================================================================\n// Step 4: Public Form Component\n// ============================================================================\n\nfunction generateFormComponent(\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 = getAllFields(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 // Build zod schema fields\n const zodFields = fields\n .filter((f) => f.name)\n .map((f) => ` ${f.name}: ${formFieldToZodType(f)}`)\n .join(',\\n')\n\n // Build default values\n const defaults = 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.defaultValue !== undefined) return ` ${f.name}: '${f.defaultValue}'`\n return ` ${f.name}: ''`\n })\n .join(',\\n')\n\n // Build form field JSX\n const fieldJSX = fields\n .filter((f) => f.name && !f.hidden)\n .map((f) => generateFieldJSX(f))\n .join('\\n\\n')\n\n const submitText = schema.submitButtonText || 'Submit'\n const successMessage = (schema.successMessage || 'Form submitted successfully!').replace(\n /'/g,\n \"\\\\'\"\n )\n\n const content = `'use client'\n\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useState } from 'react'\nimport { useForm } from 'react-hook-form'\nimport { z } from 'zod'\nimport { create${pascal}Submission } from '@cms/actions/${formName}-form'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@cms/components/ui/form'\nimport { Input } from '@cms/components/ui/input'\nimport { Textarea } from '@cms/components/ui/textarea'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\ntype FormValues = z.infer<typeof formSchema>\n\nexport function ${pascal}Form() {\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\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`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n\n/**\n * Generate JSX for a single form field\n */\nfunction generateFieldJSX(field: FormField): string {\n const name = field.name || ''\n const label = field.label\n const placeholder = field.placeholder || ''\n const hint = field.hint || ''\n\n const hintJSX = hint ? `\\n <FormDescription>${hint}</FormDescription>` : ''\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 'select':\n case 'radio':\n if (field.options && field.options.length > 0) {\n const optionItems = field.options\n .map(\n (opt) =>\n ` <SelectItem value=\"${opt.value}\">${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(\n name,\n label,\n placeholder || 'email@example.com',\n hintJSX,\n requiredStar,\n 'email'\n )\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(\n name,\n label,\n placeholder || 'https://',\n hintJSX,\n requiredStar,\n 'url'\n )\n\n case 'phone':\n return generateTextFieldJSX(\n name,\n label,\n placeholder || '+1 (555) 000-0000',\n hintJSX,\n requiredStar,\n 'tel'\n )\n\n default:\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n }\n}\n\nfunction 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\n// ============================================================================\n// Pipeline Orchestrator\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 * Type mapping utilities for the codegen system\n * Single deduped implementation (fixes known issue #8)\n *\n * Consolidates type mapping from: database.ts, form.ts, actions.ts, form-generator.ts\n */\n\nimport type { FormField, SchemaField } from '../types.js'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DRIZZLE_DEFAULTS = {\n VARCHAR_LENGTH: 255,\n DECIMAL_PRECISION: 10,\n DECIMAL_SCALE: 2\n} as const\n\n// ============================================================================\n// Internal helpers (ported from monorepo utils.ts)\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('')\n}\n\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\n\n/**\n * Quote a property name if it's not a valid JS identifier\n */\nfunction quotePropertyName(name: string): string {\n const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/\n return validIdentifier.test(name) ? name : `'${name}'`\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// 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// 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// ============================================================================\n// Form Field → Drizzle Type (for form-generator)\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// ============================================================================\n// Form Field → Zod Type (for form-generator)\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.literal(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 * 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 type { FormField, FormSchema, GeneratorOptions } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\n// ============================================================================\n// Field Helpers\n// ============================================================================\n\nfunction getAllFields(schema: FormSchema): FormField[] {\n const flatten = (fields: FormField[]): FormField[] => {\n return fields.flatMap((field) => {\n if (field.type === 'dynamicFields' || field.type === 'group') {\n if (field.type === 'group' && field.fields) return flatten(field.fields)\n return []\n }\n return [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\nfunction 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// ============================================================================\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 = getAllFields(schema).filter((f) => f.name)\n const includeDynamic = hasDynamicFields(schema)\n\n const filePath = path.join(cwd, cmsDir, 'lib', 'emails', `${formName}-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 * 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 type { FormColumn, FormField, FormSchema, GeneratorOptions } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n// ============================================================================\n// Field Helpers\n// ============================================================================\n\nfunction getAllFields(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\nfunction 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// ============================================================================\n// Result Type\n// ============================================================================\n\nexport interface FormAdminPagesResult {\n files: string[]\n}\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// 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 = getAllFields(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\n// ============================================================================\n// File Generators\n// ============================================================================\n\nfunction 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\nfunction 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) => { 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) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => 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\nfunction 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\nfunction 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 { 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 { PageHeader } from '@cms/components/shared/page-header'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Search, Settings, Trash2 } from 'lucide-react'\nimport Link from 'next/link'\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 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 <div className=\"flex items-center justify-between border-b px-6 py-4\">\n <PageHeader title=\"${label}\" description=\"View and manage form submissions\" />\n <div className=\"flex items-center gap-2\">\n <form action={searchAction} 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=\"Search submissions...\"\n defaultValue={search}\n className=\"w-64 pl-9\"\n />\n </div>\n <Button type=\"submit\" variant=\"outline\">Search</Button>\n </form>\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 {selectedIds.length > 0 && (\n <AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\">\n <Trash2 className=\"size-3.5\" />\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) => { 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 </div>\n </div>\n\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\nfunction 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 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 { Button } from '@cms/components/ui/button'\nimport { ArrowLeft } 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 <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">${label} Submission</h1>\n <p className=\"text-muted-foreground\">Viewing submission #{id}</p>\n </div>\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/forms/${kebab}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${label}\n </Link>\n </Button>\n </div>\n\n <div className=\"rounded-lg border p-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 </div>\n )\n}\n`\n}\n\nfunction 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 { 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 { ArrowLeft, Loader2 } from 'lucide-react'\nimport Link from 'next/link'\nimport { useEffect, useState, useTransition } from 'react'\nimport { toast } from 'sonner'\n\nexport default function ${pascal}SettingsPage() {\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 <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">${label} Settings</h1>\n <p className=\"text-muted-foreground\">\n Configure notifications and webhooks for this form\n </p>\n </div>\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/forms/${kebab}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${label}\n </Link>\n </Button>\n </div>\n\n <div className=\"space-y-6 rounded-lg border p-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 </div>\n )\n}\n`\n}\n","/**\n * Form navigation generator: adds form submissions entry to cms/data/navigation.ts\n * Groups forms under a \"Forms\" parent with FileInput icon, each form gets Inbox icon\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { FormSchema, GeneratorOptions } from '../types.js'\n\n// ============================================================================\n// Types (same as entity navigation generator)\n// ============================================================================\n\ninterface NavItem {\n label: string\n href: string\n icon?: string\n children?: NavItem[]\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\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\n const childrenMatch = str.match(/children:\\s*\\[([\\s\\S]*?)\\]/)\n if (childrenMatch) {\n item.children = parseItemsBlock(childrenMatch[1])\n }\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 { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push(\"import type { LucideIcon } 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(' children?: CmsNavigationItem[]')\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], 2, 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, indent: number, isLast: boolean): void {\n const pad = ' '.repeat(indent)\n\n if (item.children && item.children.length > 0) {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}',`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon},`)\n lines.push(`${pad} children: [`)\n for (let j = 0; j < item.children.length; j++) {\n appendItem(lines, item.children[j], indent + 4, j === item.children.length - 1)\n }\n lines.push(`${pad} ]`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n } else {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}'${item.icon ? ',' : ''}`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon}`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n }\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface FormNavigationResult {\n files: string[]\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Update cms/data/navigation.ts to add form under a \"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 // Find or create Forms group\n let formsGroup = items.find((item) => item.label === 'Forms')\n\n if (!formsGroup) {\n formsGroup = {\n label: 'Forms',\n href: '#',\n icon: 'FileInput',\n children: []\n }\n // Insert before Users/Settings\n items.push(formsGroup)\n }\n\n if (!formsGroup.children) {\n formsGroup.children = []\n }\n\n // Create form sub-item\n const kebab = toKebabCase(schema.name)\n const formHref = `/cms/forms/${kebab}`\n const existingIndex = formsGroup.children.findIndex((c) => c.href === formHref)\n\n const newChild: NavItem = {\n label: schema.label,\n href: formHref,\n icon: 'Inbox'\n }\n\n if (existingIndex >= 0) {\n if (options.force) {\n formsGroup.children[existingIndex] = newChild\n } else {\n return { files: [] }\n }\n } else {\n formsGroup.children.push(newChild)\n formsGroup.children.sort((a, b) => a.label.localeCompare(b.label))\n }\n\n // Reorganize: Dashboard first, then alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => a.label.localeCompare(b.label))\n\n items = [...(dashboard ? [dashboard] : []), ...others]\n\n // Ensure required icons are imported\n for (const icon of ['FileInput', 'Inbox']) {\n if (!iconImports.includes(icon)) {\n iconImports.push(icon)\n }\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 * 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.js'\nimport { toTypeScriptType } from '../core/type-mappers.js'\nimport type { Schema, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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}\nfunction 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}\nfunction quotePropertyName(name: string): string {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`\n}\n\n// ============================================================================\n// Field Mapping Helpers\n// ============================================================================\n\nfunction 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\nfunction getFieldType(field: SchemaField, mode: 'input' | 'output' = 'output'): string {\n return toTypeScriptType(field, mode)\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface ActionsGeneratorResult {\n files: string[]\n}\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 } 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: path.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 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 // 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\n const dataInterface = `export interface ${Singular}Data {\\n${dataFields}${m2mFieldTypes ? `\\n${m2mFieldTypes}` : ''}\\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 // --- 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 // --- 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 // --- 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/getBySlug) ---\n const singleRowReturn = (() => {\n if (hasRelationships && hasListRels) {\n return `const row = result[0]\\n return await populate${Singular}ListRelationships(${buildSingleRowMapping(allDbFields, relationshipFields, Singular)})`\n }\n if (hasRelationships) {\n return `const row = result[0]\\n return ${buildSingleRowMapping(allDbFields, relationshipFields, Singular)}`\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 // --- 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}\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 = ${selectClause}\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${resultMapping}\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<${Singular}Data | null> {\n try {\n const result = await ${selectClause}.where(eq(${tableVar}.slug, slug)).limit(1)\n if (result.length === 0) return null\n ${singleRowReturn}\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\n const result = await db.insert(${tableVar}).values({\n${createMappings},${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\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/**\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 // 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 dataInterface = `export interface ${Singular}Data {\\n${dataFields}\\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 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\n const now = new Date().toISOString()\n\n const result = await db\n .insert(${tableVar})\n .values({\n id: 1,\n${upsertMappings},\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// ============================================================================\n// Helper builders for relationship queries\n// ============================================================================\n\nfunction buildRelationshipSelect(\n allDbFields: SchemaField[],\n relationshipFields: SchemaField[],\n tableVar: string\n): string {\n const regularSelects = allDbFields\n .filter((f) => f.type !== 'relationship')\n .map((f) => ` ${f.name}: ${tableVar}.${f.name}`)\n .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\nfunction 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\nfunction buildSingleRowMapping(\n allDbFields: SchemaField[],\n _relationshipFields: SchemaField[],\n Singular: string\n): string {\n const mappings = 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 return `{\\n${mappings}\\n } as ${Singular}Data`\n}\n\n// ============================================================================\n// List-relationship helpers\n// ============================================================================\n\nfunction 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\nfunction 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 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.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toScreamingSnake(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toUpperCase()\n}\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.js'\nimport type { GeneratorOptions, Schema, SchemaColumn, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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\n// ============================================================================\n// Column Helpers\n// ============================================================================\n\nfunction 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\nfunction 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\nfunction 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\nfunction 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// ============================================================================\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 ? `\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 // --- Reorder handler ---\n const reorderHandler = `\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 // --- 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 ? `\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 // --- 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// ============================================================================\n// Custom Cell Component\n// ============================================================================\n\nfunction 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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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 { ArrowLeft } 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 <div className=\"flex flex-col w-full pb-20\">\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader\n title=\"Create ${singLabel}\"\n description=\"Add a new ${singLabel.toLowerCase()} to the system\"\n />\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/${schema.name}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${schema.label}\n </Link>\n </Button>\n </div>\n <main className=\"container mx-auto max-w-5xl p-6\">\n <${Singular}Form key={Date.now()} />\n </main>\n </div>\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.js'\nimport { toDrizzleType } from '../core/type-mappers.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers (local to this generator)\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\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 return ` ${field.name}: ${drizzleType}${modifiers}`\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 const hasSqlImport = content.includes(\"import { sql } from 'drizzle-orm'\")\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 (hasSqlImport) {\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 updated = `import { sql } from 'drizzle-orm'\\n${updated}`\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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 { ArrowLeft } 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 <div className=\"flex flex-col w-full pb-20\">\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader\n title=\"Edit ${Singular}\"\n description=\"Update ${singular} information\"\n />\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/${schema.name}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${schema.label}\n </Link>\n </Button>\n </div>\n <main className=\"container mx-auto max-w-5xl p-6\">\n <${Singular}Form key={${camelSingular}.id} initialData={${camelSingular}} />\n </main>\n </div>\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 * Generator 8: Form — (authenticated)/<n>/<n>-form.tsx\n * Generates 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 } from '../core/field-helpers.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction quotePropertyName(name: string): string {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`\n}\n\n// ============================================================================\n// Form Field Type Mapping\n// ============================================================================\n\nfunction 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\n// ============================================================================\n// Zod Schema Generation\n// ============================================================================\n\nfunction 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// ============================================================================\n// Form Field JSX Generation\n// ============================================================================\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\nfunction generateFieldJSX(field: SchemaField, indent = ' '): string {\n if (field.hidden) return ''\n\n const mainJSX = generateFieldJSXCore(field, indent)\n if (!mainJSX) return ''\n\n // Append icon picker postfix for fields with hasIcon\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 const listHintJSX = field.hint\n ? `${indent} <p className=\"text-[0.8rem] text-muted-foreground\">${field.hint}</p>`\n : ''\n\n // Group\n if (field.type === 'group' && field.fields) {\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\n // Separator\n if (field.type === 'separator') {\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\n // Boolean (checkbox)\n if (field.type === 'boolean') {\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\n // Image upload\n if (field.type === 'image') {\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\n // Video upload\n if (field.type === 'video') {\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\n // Media upload (image or video)\n if (field.type === 'media') {\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\n // Icon picker\n if (field.type === 'icon') {\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\n // Date picker\n if (field.type === 'date') {\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\n // Select\n if (field.type === 'select') {\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\n // Rich text editor (TipTap WYSIWYG)\n if (field.type === 'richtext') {\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\n // Markdown editor (CodeMirror plain-text)\n if (field.type === 'markdown') {\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\n // Textarea (text type)\n if (field.type === 'text') {\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\n // Relationship (combobox)\n if (field.type === 'relationship' && field.relationship) {\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 `${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\n // Single relationship\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\n // List field\n if (field.type === 'list') {\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 // 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 // Default: text input\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// ============================================================================\n// Field Analysis Helpers\n// ============================================================================\n\nfunction checkForFieldType(fields: SchemaField[], type: string): boolean {\n for (const f of fields) {\n if (f.type === type) return true\n if (f.type === 'group' && f.fields && checkForFieldType(f.fields, type)) return true\n if (f.type === 'list' && f.fields && checkForFieldType(f.fields, type)) return true\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields && checkForFieldType(tab.fields, type)) return true\n }\n }\n }\n return false\n}\n\nfunction checkForHasIconProperty(fields: SchemaField[]): boolean {\n for (const f of fields) {\n if (f.hasIcon) return true\n if (f.type === 'group' && f.fields && checkForHasIconProperty(f.fields)) return true\n if (f.type === 'list' && f.fields && checkForHasIconProperty(f.fields)) return true\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields && checkForHasIconProperty(tab.fields)) return true\n }\n }\n }\n return false\n}\n\nfunction 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\n// ============================================================================\n// Default Values Generation\n// ============================================================================\n\nfunction 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\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface FormGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate create/edit form for an entity\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 = checkForFieldType(schema.fields, 'boolean')\n const hasImage = checkForFieldType(schema.fields, 'image')\n const hasVideo = checkForFieldType(schema.fields, 'video')\n const hasMedia = checkForFieldType(schema.fields, 'media')\n const hasIcon = checkForFieldType(schema.fields, 'icon')\n const hasIconPostfix = checkForHasIconProperty(schema.fields)\n const hasDate = checkForFieldType(schema.fields, 'date')\n const hasSelect = checkForFieldType(schema.fields, 'select')\n const hasMarkdown = checkForFieldType(schema.fields, 'markdown')\n const hasRichtext = checkForFieldType(schema.fields, 'richtext')\n const hasTextarea = checkForFieldType(schema.fields, 'text')\n const hasSeparator = checkForFieldType(schema.fields, 'separator')\n const hasRelationship = checkForFieldType(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 if (!tabFieldNames.has(f.name)) listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFields(f.fields)\n }\n }\n collectListFields(allFormFields)\n const hasList = checkForFieldType(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 = 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 // Build default values\n const defaultValues = 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 // 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: 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 (hasBoolean) uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (hasTextarea) uiImports.push(\"import { Textarea } from '@cms/components/ui/textarea'\")\n if (hasImage)\n uiImports.push(\"import { ImageUploadField } from '@cms/components/ui/image-upload-field'\")\n if (hasVideo)\n uiImports.push(\"import { VideoUploadField } from '@cms/components/ui/video-upload-field'\")\n if (hasMedia)\n uiImports.push(\"import { MediaUploadField } from '@cms/components/ui/media-upload-field'\")\n if (hasIcon || hasIconPostfix)\n uiImports.push(\"import { IconPicker } from '@cms/components/ui/icon-picker'\")\n if (hasDate) uiImports.push(\"import { DatePicker } from '@cms/components/ui/date-picker'\")\n if (hasMarkdown)\n uiImports.push(\"import { MarkdownEditor } from '@cms/components/ui/markdown-editor'\")\n if (hasRichtext)\n uiImports.push(\"import { RichTextEditor } from '@cms/components/ui/rich-text-editor'\")\n if (hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n if (hasSelect) {\n uiImports.push(`import {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'`)\n }\n if (hasTabsField) {\n uiImports.push(`import {\n Tabs,\n TabsList,\n TabsTrigger,\n TabsContent\n} from '@cms/components/ui/tabs'`)\n }\n if (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 (hasSimpleList)\n uiImports.push(\"import { DynamicListField } from '@cms/components/ui/dynamic-list-field'\")\n if (hasNestedList) {\n uiImports.push(`import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger\n} from '@cms/components/ui/accordion'`)\n if (!hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n uiImports.push(\"import { Label } from '@cms/components/ui/label'\")\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'${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/**\n * Generate form for a single (singleton) schema.\n * Uses upsertXxx mutation, no router navigation, \"Save\" button.\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 = checkForFieldType(schema.fields, 'boolean')\n const hasImage = checkForFieldType(schema.fields, 'image')\n const hasVideo = checkForFieldType(schema.fields, 'video')\n const hasMedia = checkForFieldType(schema.fields, 'media')\n const hasIcon = checkForFieldType(schema.fields, 'icon')\n const hasIconPostfix = checkForHasIconProperty(schema.fields)\n const hasDate = checkForFieldType(schema.fields, 'date')\n const hasSelect = checkForFieldType(schema.fields, 'select')\n const hasMarkdown = checkForFieldType(schema.fields, 'markdown')\n const hasRichtext = checkForFieldType(schema.fields, 'richtext')\n const hasTextarea = checkForFieldType(schema.fields, 'text')\n const hasSeparator = checkForFieldType(schema.fields, 'separator')\n const hasRelationship = checkForFieldType(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 if (!tabFieldNames.has(f.name)) listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFieldsSingle(f.fields)\n }\n }\n collectListFieldsSingle(allFormFields)\n const hasList = checkForFieldType(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 = 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 // Build default values\n const defaultValues = 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 // 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: 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 (hasBoolean) uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (hasTextarea) uiImports.push(\"import { Textarea } from '@cms/components/ui/textarea'\")\n if (hasImage)\n uiImports.push(\"import { ImageUploadField } from '@cms/components/ui/image-upload-field'\")\n if (hasVideo)\n uiImports.push(\"import { VideoUploadField } from '@cms/components/ui/video-upload-field'\")\n if (hasMedia)\n uiImports.push(\"import { MediaUploadField } from '@cms/components/ui/media-upload-field'\")\n if (hasIcon || hasIconPostfix)\n uiImports.push(\"import { IconPicker } from '@cms/components/ui/icon-picker'\")\n if (hasDate) uiImports.push(\"import { DatePicker } from '@cms/components/ui/date-picker'\")\n if (hasMarkdown)\n uiImports.push(\"import { MarkdownEditor } from '@cms/components/ui/markdown-editor'\")\n if (hasRichtext)\n uiImports.push(\"import { RichTextEditor } from '@cms/components/ui/rich-text-editor'\")\n if (hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n if (hasSelect) {\n uiImports.push(`import {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'`)\n }\n if (hasTabsField) {\n uiImports.push(`import {\n Tabs,\n TabsList,\n TabsTrigger,\n TabsContent\n} from '@cms/components/ui/tabs'`)\n }\n if (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 if (hasSimpleList)\n uiImports.push(\"import { DynamicListField } from '@cms/components/ui/dynamic-list-field'\")\n if (hasNestedList) {\n uiImports.push(`import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger\n} from '@cms/components/ui/accordion'`)\n if (!hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n uiImports.push(\"import { Label } from '@cms/components/ui/label'\")\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'${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.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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\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\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 = [`type ${Singular}Data`, `type ${Plural}Response`, `type Get${Plural}Filters`]\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 slugHook = hasSlugField\n ? `\n\nexport function use${Singular}BySlug(slug: string | null | undefined): UseQueryResult<${Singular}Data | 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 */\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 children?: NavItem[]\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 // Extract icon imports from lucide-react\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 // Extract array content using bracket counting (handles nested children arrays)\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 // Find `= [` to skip the `[]` in the type annotation (CmsNavigationItem[])\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 // Count brackets to find the matching `]`\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\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\n // Check for children array\n const childrenMatch = str.match(/children:\\s*\\[([\\s\\S]*?)\\]/)\n if (childrenMatch) {\n item.children = parseItemsBlock(childrenMatch[1])\n }\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 // Icon imports\n lines.push(`import { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push(\"import type { LucideIcon } 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(' children?: CmsNavigationItem[]')\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, 2, isLast)\n }\n\n lines.push(']')\n lines.push('')\n\n return lines.join('\\n')\n}\n\nfunction appendItem(lines: string[], item: NavItem, indent: number, isLast: boolean): void {\n const pad = ' '.repeat(indent)\n\n if (item.children && item.children.length > 0) {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}',`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon},`)\n lines.push(`${pad} children: [`)\n for (let j = 0; j < item.children.length; j++) {\n appendItem(lines, item.children[j], indent + 4, j === item.children.length - 1)\n }\n lines.push(`${pad} ]`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n } else {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}'${item.icon ? ',' : ''}`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon}`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n }\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 // Check if item already exists (including inside groups)\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.navGroup) {\n // Insert into a parent group\n let group = items.find((item) => item.label === schema.navGroup?.label)\n\n if (!group) {\n group = {\n label: schema.navGroup.label,\n href: '#',\n icon: schema.navGroup.icon,\n children: []\n }\n items.push(group)\n }\n\n if (!group.children) {\n group.children = []\n }\n\n const existingChild = group.children.findIndex((c) => c.href === entityHref)\n\n if (existingChild >= 0) {\n if (options.force) {\n group.children[existingChild] = newItem\n } else {\n return { files: [] }\n }\n } else {\n group.children.push(newItem)\n group.children.sort((a, b) => a.label.localeCompare(b.label))\n }\n\n // Add group icon import\n if (schema.navGroup.icon && !iconImports.includes(schema.navGroup.icon)) {\n iconImports.push(schema.navGroup.icon)\n }\n } else {\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\n // Reorganize: Dashboard first, then alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => a.label.localeCompare(b.label))\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\nfunction 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 // Re-capitalize first letter\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// ============================================================================\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[] = ['Search']\n if (hasCreate) lucideIcons.push('FilePlus')\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 { 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\">\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=\"Search ${schema.label.toLowerCase()}...\"\n defaultValue={search}\n className=\"w-64 pl-9\"\n />\n </div>\n <SearchButton />\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 <FilePlus 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 queryClient = useQueryClient()\n${searchLogic}${deleteLogic}\n return (\n <>\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader title=\"${schema.label}\" description=\"${schema.description}\" />\n <div className=\"flex items-center gap-2\">\n${filterDropdowns ? `${filterDropdowns}\\n` : ''}${searchInput}\n${deleteButton}\n${createButton}\n </div>\n </div>\n\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\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 <div className=\"flex flex-col\">\n <PageHeader title=\"${schema.label}\" />\n <div className=\"max-w-5xl mx-auto w-full pb-24\">\n <${Singular}Form initialData={data} />\n </div>\n </div>\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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.js'\nimport { generateCache } from './cache.js'\nimport { generateColumns } from './columns.js'\nimport { generateCreatePage } from './create-page.js'\nimport { generateDatabase } from './database.js'\nimport { generateEditPage } from './edit-page.js'\nimport { generateForm, generateSingleForm } from './form.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.js'\nexport { generateCache } from './cache.js'\nexport { generateColumns } from './columns.js'\nexport { generateCreatePage } from './create-page.js'\nexport { generateDatabase } from './database.js'\nexport { generateEditPage } from './edit-page.js'\nexport { generateForm, generateSingleForm } from './form.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\n console.log('\\n Running drizzle-kit push...')\n try {\n execFileSync('npx', ['drizzle-kit', 'push'], { cwd, stdio: 'pipe' })\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\n try {\n execFileSync('npx', ['biome', '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 for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) {\n if (fs.existsSync(path.join(cwd, lockfile))) {\n return pm\n }\n }\n\n // Check packageManager field in package.json\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')) 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\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 { 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 {\n createNextAppCommand,\n detectPackageManager,\n runCommand\n} 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 .action(\n async (\n name: string | undefined,\n options: { preset: string; yes?: boolean; databaseUrl?: string }\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(`Existing Next.js project detected`)\n p.log.info(`Package manager: ${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 (project.conflicts.length > 0) {\n p.log.error('Conflicts detected:')\n for (const conflict of project.conflicts) {\n p.log.warning(` - ${conflict}`)\n }\n if (!options.yes) {\n const proceed = await p.confirm({\n message: 'Continue anyway? (existing files will NOT be overwritten)',\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 = projectPrompt.projectName === '.'\n ? path.basename(cwd)\n : 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\n const s = p.spinner()\n\n s.start('Creating CMS directory structure...')\n const baseFiles = scaffoldBase({ cwd, config })\n s.stop(`Created ${baseFiles.length} files`)\n\n s.start('Configuring TypeScript path aliases...')\n const tsResult = scaffoldTsconfig(cwd)\n s.stop(`Added ${tsResult.added.length} path aliases`)\n\n s.start('Configuring Tailwind CSS...')\n const twResult = scaffoldTailwind(cwd, srcDir)\n if (twResult.appended) {\n s.stop(`Updated ${twResult.file}`)\n } else if (twResult.file) {\n s.stop('Tailwind already configured for CMS')\n } else {\n s.stop('No CSS file found (will configure later)')\n }\n\n s.start('Setting up environment variables...')\n const envResult = scaffoldEnv(cwd, { includeEmail: features.includeEmail, databaseUrl })\n const envParts = [`Added ${envResult.added.length}`]\n if (envResult.updated.length > 0) envParts.push(`updated ${envResult.updated.length}`)\n s.stop(`${envParts.join(', ')} env vars in .env.local`)\n\n s.start('Setting up database...')\n const dbFiles = scaffoldDatabase({ cwd, config })\n s.stop(`Created ${dbFiles.length} database files`)\n\n s.start('Setting up authentication...')\n const authFiles = scaffoldAuth({ cwd, config })\n s.stop(`Created ${authFiles.length} auth files`)\n\n s.start('Copying CMS components...')\n const compFiles = scaffoldComponents({ cwd, config })\n s.stop(`Created ${compFiles.length} component files`)\n\n s.start('Creating CMS pages and layouts...')\n const layoutFiles = scaffoldLayout({ cwd, config })\n s.stop(`Created ${layoutFiles.length} page files`)\n\n s.start('Creating API routes...')\n const apiFiles = scaffoldApiRoutes({ cwd, config })\n s.stop(`Created ${apiFiles.length} API routes`)\n\n // Set up Biome if no linter detected\n s.start('Checking for linter...')\n if (project.linter.type === 'none') {\n s.stop('No linter found')\n s.start('Setting up Biome linter...')\n const biomeResult = scaffoldBiome(cwd, project.linter)\n if (biomeResult.installed) {\n s.stop('Created biome.json')\n } else {\n s.stop(`Biome skipped: ${biomeResult.skippedReason}`)\n }\n } else {\n s.stop(`Linter: ${pc.cyan(project.linter.type)} (${project.linter.configFile})`)\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 if (depsResult.success) {\n s.stop(\n `Installed ${depsResult.coreDeps.length} deps + ${depsResult.devDeps.length} dev deps`\n )\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 (always runs — settings schema needed for all presets)\n s.start(`Applying ${features.preset} preset...`)\n const presetResult = scaffoldPreset({ cwd, config, preset: features.preset })\n if (presetResult.errors.length > 0) {\n s.stop(`Preset applied with ${presetResult.errors.length} warning(s)`)\n for (const err of presetResult.errors) {\n p.log.warning(` ${err}`)\n }\n } else {\n s.stop(\n `Created ${presetResult.schemas.length} schemas, generated ${presetResult.generatedFiles.length} files`\n )\n }\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('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.log.step('Create your admin account')\n\n const email = await 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 if (p.isCancel(email)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n const password = await 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 if (p.isCancel(password)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n seedEmail = email\n seedPassword = password\n\n s.start('Creating admin user...')\n const seedResult = await runSeed(cwd, config.paths?.cms ?? './cms', email, password)\n if (seedResult.success) {\n s.stop('Admin user created')\n seedSuccess = true\n } else {\n s.stop('Failed to create admin user')\n p.log.warning(seedResult.error ?? 'Unknown error')\n p.log.info(`You can run it manually: ${pc.cyan('npx betterstart seed')}`)\n }\n }\n\n // Regenerate CMS.md with full documentation\n {\n const entityNames: string[] = []\n const formNames: string[] = []\n // Scan schemas dir for generated entities and forms\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\n // Git init + commit for fresh projects\n if (isFreshProject) {\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 p.log.success('Created initial git commit')\n } catch {\n // Non-critical — don't block init if git fails\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 `Email: ${features.includeEmail ? pc.green('yes') : pc.dim('no')}`,\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:3000/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\n/** Write seed script, run it with tsx, clean up. Returns success/error. */\nasync function runSeed(\n cwd: string,\n cmsDir: string,\n email: string,\n password: string\n): Promise<{ success: boolean; error: string | null }> {\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 try {\n execFileSync('npx', ['tsx', seedPath], {\n cwd,\n stdio: 'pipe',\n timeout: 30_000,\n env: { ...process.env, SEED_EMAIL: email, SEED_PASSWORD: password, SEED_NAME: 'Admin' }\n })\n return { success: true, error: null }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, error: msg }\n } finally {\n // Clean up seed script\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\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 child = spawn('npx', ['drizzle-kit', '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: boolean\n preset: Preset\n}\n\n/**\n * Prompt for email system and preset selection.\n */\nexport async function promptFeatures(presetOverride?: string): Promise<FeaturesPromptResult> {\n const includeEmail = await p.confirm({\n message: 'Include email system? (Resend + React Email)',\n initialValue: true\n })\n\n if (p.isCancel(includeEmail)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\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, 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 { validateFiles } from '@cms/utils/validation'\nimport type { UploadedFile } from '@cms/types'\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(\n { success: false, error: 'No files provided' },\n { status: 400 }\n )\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\n .map((e) => \\`\\${e.filename}: \\${e.error}\\`)\n .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 =\n error instanceof Error ? error.message : 'Failed to upload files'\n return NextResponse.json(\n { success: false, error: message },\n { status: 500 }\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 { 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: process.env.NEXT_PUBLIC_BETTERSTART_AUTH_URL || (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 (\n typeof value === 'string' &&\n Object.values(UserRole).includes(value as UserRole)\n )\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 { 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 { 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'\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-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\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\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\n@custom-variant dark (&:is(.dark *));\n\n:root {\n --background: oklch(0.9850 0 0);\n --foreground: oklch(0 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0 0 0);\n --popover: oklch(0.9900 0 0);\n --popover-foreground: oklch(0 0 0);\n --primary: oklch(0 0 0);\n --primary-foreground: oklch(1 0 0);\n --secondary: oklch(0.9700 0 0);\n --secondary-foreground: oklch(0 0 0);\n --muted: oklch(0.9700 0 0);\n --muted-foreground: oklch(0.4400 0 0);\n --accent: oklch(0.9700 0 0);\n --accent-foreground: oklch(0 0 0);\n --destructive: oklch(0.6300 0.1900 23.0300);\n --destructive-foreground: oklch(1 0 0);\n --border: oklch(0.9200 0 0);\n --input: oklch(0.9400 0 0);\n --ring: oklch(0 0 0);\n --chart-1: oklch(0.8100 0.1700 75.3500);\n --chart-2: oklch(0.5500 0.2200 264.5300);\n --chart-3: oklch(0.7200 0 0);\n --chart-4: oklch(0.9200 0 0);\n --chart-5: oklch(0.5600 0 0);\n --sidebar: oklch(1 0 0);\n --sidebar-foreground: oklch(0 0 0);\n --sidebar-primary: oklch(0 0 0);\n --sidebar-primary-foreground: oklch(1 0 0);\n --sidebar-accent: oklch(0.9400 0 0);\n --sidebar-accent-foreground: oklch(0 0 0);\n --sidebar-border: oklch(0.9400 0 0);\n --sidebar-ring: oklch(0 0 0);\n --font-sans: Geist, sans-serif;\n --font-serif: Georgia, serif;\n --font-mono: Geist Mono, monospace;\n --radius: 0.4rem;\n --shadow-x: 0px;\n --shadow-y: 1px;\n --shadow-blur: 3px;\n --shadow-spread: 0px;\n --shadow-opacity: 0.02;\n --shadow-color: hsl(0 0% 0%);\n --shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 2px 4px -1px hsl(0 0% 0% / 0.02);\n --shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 4px 6px -1px hsl(0 0% 0% / 0.02);\n --shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 8px 10px -1px hsl(0 0% 0% / 0.02);\n --shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);\n --tracking-normal: 0em;\n --spacing: 0.25rem;\n}\n\n.dark {\n --background: oklch(0 0 0);\n --foreground: oklch(1 0 0);\n --card: oklch(0.1400 0 0);\n --card-foreground: oklch(1 0 0);\n --popover: oklch(0.1800 0 0);\n --popover-foreground: oklch(1 0 0);\n --primary: oklch(1 0 0);\n --primary-foreground: oklch(0 0 0);\n --secondary: oklch(0.2500 0 0);\n --secondary-foreground: oklch(1 0 0);\n --muted: oklch(0.2300 0 0);\n --muted-foreground: oklch(0.7200 0 0);\n --accent: oklch(0.3200 0 0);\n --accent-foreground: oklch(1 0 0);\n --destructive: oklch(0.6900 0.2000 23.9100);\n --destructive-foreground: oklch(0 0 0);\n --border: oklch(0.2600 0 0);\n --input: oklch(0.3200 0 0);\n --ring: oklch(0.7200 0 0);\n --chart-1: oklch(0.8100 0.1700 75.3500);\n --chart-2: oklch(0.5800 0.2100 260.8400);\n --chart-3: oklch(0.5600 0 0);\n --chart-4: oklch(0.4400 0 0);\n --chart-5: oklch(0.9200 0 0);\n --sidebar: oklch(0.1800 0 0);\n --sidebar-foreground: oklch(1 0 0);\n --sidebar-primary: oklch(1 0 0);\n --sidebar-primary-foreground: oklch(0 0 0);\n --sidebar-accent: oklch(0.3200 0 0);\n --sidebar-accent-foreground: oklch(1 0 0);\n --sidebar-border: oklch(0.3200 0 0);\n --sidebar-ring: oklch(0.7200 0 0);\n --font-sans: Geist, sans-serif;\n --font-serif: Georgia, serif;\n --font-mono: Geist Mono, monospace;\n --radius: 0.4rem;\n --shadow-x: 0px;\n --shadow-y: 1px;\n --shadow-blur: 3px;\n --shadow-spread: 0px;\n --shadow-opacity: 0.02;\n --shadow-color: hsl(0 0% 0%);\n --shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 2px 4px -1px hsl(0 0% 0% / 0.02);\n --shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 4px 6px -1px hsl(0 0% 0% / 0.02);\n --shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 8px 10px -1px hsl(0 0% 0% / 0.02);\n --shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);\n}\n\n.cms-root {\n --font-sans: var(--font-geist-sans, sans-serif);\n --font-mono: var(--font-geist-mono, monospace);\n font-family: var(--font-sans);\n}\n\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-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\n --font-sans: var(--font-sans);\n --font-mono: var(--font-mono);\n --font-serif: var(--font-serif);\n\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 --shadow-2xs: var(--shadow-2xs);\n --shadow-xs: var(--shadow-xs);\n --shadow-sm: var(--shadow-sm);\n --shadow: var(--shadow);\n --shadow-md: var(--shadow-md);\n --shadow-lg: var(--shadow-lg);\n --shadow-xl: var(--shadow-xl);\n --shadow-2xl: var(--shadow-2xl);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground antialiased;\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 type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n type Table as TanstackTable,\n useReactTable,\n type VisibilityState\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow\n} from '@cms/components/ui/table'\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 (updater: Record<string, boolean> | ((old: Record<string, boolean>) => Record<string, boolean>)) => {\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)]))\n .filter(Boolean)\n onSelectedIdsChange(newIds)\n },\n [data, rowSelection, onSelectedIdsChange, getId]\n )\n\n const handlePaginationChange = React.useCallback(\n (updater: { pageIndex: number; pageSize: number } | ((old: { pageIndex: number; pageSize: number }) => { pageIndex: number; pageSize: number })) => {\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 type { Table } from '@tanstack/react-table'\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'\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 { ArrowUpDown, Save, Search } from 'lucide-react'\nimport * as React from 'react'\nimport { useFormStatus } from 'react-dom'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\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\n variant=\"default\"\n size=\"sm\"\n onClick={onSave}\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={onCancel}\n disabled={isSaving}\n >\n Cancel\n </Button>\n {hasChanges && (\n <span className=\"text-sm text-muted-foreground\">Unsaved changes</span>\n )}\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 { CmsSearch } from '@cms/components/layout/cms-search'\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 bg-sidebar\">\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 <CmsSearch />\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-providers.tsx\n * CMS-scoped providers: QueryClient, CmsThemeProvider, Toaster, NuqsAdapter\n */\nexport function cmsProvidersTemplate(): string {\n return `'use client'\n\nimport { useState } from 'react'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { CmsThemeProvider } from '@cms/hooks/use-cms-theme'\nimport { Toaster } from '@cms/components/ui/sonner'\nimport { NuqsAdapter } from 'nuqs/adapters/next/app'\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! rounded-full\"\n size=\"sm\"\n >\n <Search className=\"shrink-0 size-3.5 -ml-0.5 text-muted-foreground\" strokeWidth={2} />\n <span className=\"w-full font-medium text-xs pt-px text-muted-foreground leading-0\">\n Find...\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\" strokeWidth={1.5} />\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 navigation\n */\nexport function cmsSidebarTemplate(): string {\n return `import { getSetting } from '@/cms/lib/actions/settings'\nimport { getSession } from '@cms/auth/middleware'\nimport { Avatar, AvatarFallback, AvatarImage } from '@cms/components/ui/avatar'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '@cms/components/ui/collapsible'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarRail,\n SidebarTrigger,\n} from '@cms/components/ui/sidebar'\nimport { cms } from '@cms/data/cms'\nimport { type CmsNavigationItem, cmsNavigation } from '@cms/data/navigation'\nimport { ChevronRight, Settings, Users } from 'lucide-react'\nimport Link from 'next/link'\n\nfunction NavItem({ item }: { item: CmsNavigationItem }) {\n if (item.children && item.children.length > 0) {\n return (\n <Collapsible asChild defaultOpen className=\"group/collapsible border-y border-border py-2 px-2\">\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton>\n {item.icon && <item.icon className=\"size-3.5!\" />}\n <span>{item.label}</span>\n <ChevronRight className=\"ml-auto size-3.5! transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <SidebarMenuSubItem key={child.href}>\n <SidebarMenuSubButton asChild>\n <Link href={child.href}>\n {child.icon && <child.icon className=\"size-3.5!\" />}\n <span>{child.label}</span>\n </Link>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n return (\n <SidebarMenuItem className=\"px-2\">\n <SidebarMenuButton asChild>\n <Link href={item.href}>\n {item.icon && <item.icon className=\"size-3.5!\" />}\n <span>{item.label}</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n )\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\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-6.5\">\n <AvatarImage src={'/favicon.ico'} />\n <AvatarFallback className=\"text-sm font-semibold\">\n {settings?.siteName?.charAt(0) ?? cms.name?.charAt(0)}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex items-center gap-1 w-full group-data-[collapsible=icon]:hidden\">\n <span className=\"text-sm font-semibold line-clamp-1\">{settings?.siteName ?? cms.name}</span>\n </div>\n </Link>\n <SidebarTrigger className=\"hidden md:flex\" />\n </div>\n </SidebarHeader>\n <SidebarContent className=\"gap-2\">\n <SidebarMenu className=\"py-2 gap-2\">\n {cmsNavigation.map((item) => (\n <NavItem key={item.href + item.label} item={item} />\n ))}\n </SidebarMenu>\n <SidebarMenu className=\"py-2 mt-auto border-t border-border px-2\">\n <SidebarMenuItem>\n <SidebarMenuButton asChild>\n <Link href=\"/cms/users\">\n <Users className=\"size-3.5!\" />\n <span>Users</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n <SidebarMenuItem>\n <SidebarMenuButton asChild>\n <Link href=\"/cms/settings\">\n <Settings className=\"size-3.5!\" />\n <span>Settings</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\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 <SidebarRail />\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 description: string\n children?: React.ReactNode\n}\n\nexport function PageHeader({ title, description, children }: PageHeaderProps) {\n return (\n <div className=\"flex items-center justify-between w-full\">\n <div className=\"flex flex-col\">\n <h2 className=\"text-base font-semibold tracking-tight\">{title}</h2>\n <p className=\"text-muted-foreground text-sm\">{description}</p>\n </div>\n {children && <div className=\"flex items-center gap-2\">{children}</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({ value, trueLabel = 'Yes', falseLabel = 'No' }: {\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 { House } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nexport interface CmsNavigationItem {\n label: string\n href: string\n icon?: LucideIcon\n children?: CmsNavigationItem[]\n}\n\nexport const cmsNavigation: CmsNavigationItem[] = [\n {\n label: 'Dashboard',\n href: '/cms',\n icon: House\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 (\n <CmsThemeContext.Provider value={value}>\n {children}\n </CmsThemeContext.Provider>\n )\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) =>\n f.type.startsWith('image/')\n )\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-upload.ts\n * File upload hook with validation and progress tracking\n */\nexport function useUploadHookTemplate(): string {\n return `'use client'\n\nimport type {\n UploadFileResult,\n UploadProgress\n} from '@cms/types'\nimport {\n type FileValidationConfig,\n validateFiles\n} 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 { eq } from 'drizzle-orm'\nimport db from '@cms/db'\nimport { formSettings } from '@cms/db/schema'\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(\n formName: string\n): 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:\n 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:\n 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 db from '@cms/db'\nimport { user, account } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\nimport { auth } from '@cms/auth'\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(\n userId: string,\n role: string,\n): Promise<UpdateUserRoleResult> {\n try {\n await db\n .update(user)\n .set({ role, updatedAt: new Date() })\n .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 dollarmath from 'markdown-it-dollarmath'\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, typescript, jsx, tsx, python, rust, go,\n json, yaml, css, sql, shellscript, 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// --- 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(dollarmath, {\n allow_space: false,\n allow_digits: false,\n double_inline: true,\n allow_labels: true,\n allow_blank_lines: true,\n renderer(content: string, { displayMode }: { displayMode: boolean }) {\n return renderToString(content, {\n displayMode,\n throwOnError: false,\n strict: 'ignore'\n })\n },\n labelNormalizer(label: string) {\n return label.replace(/[\\\\s]+/g, '-')\n },\n labelRenderer(label: string) {\n return \\`<a href=\"#\\${label}\" class=\"mathlabel\" title=\"Permalink to this equation\">¶</a>\\`\n }\n })\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 (\n typeof value === 'string' &&\n Object.values(UserRole).includes(value as UserRole)\n )\n}\n\n/** Check if user has one of the allowed roles */\nexport function hasRequiredRole(\n userRole: UserRole,\n allowedRoles: UserRole[]\n): 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 {\n maxSizeInBytes = DEFAULT_MAX_SIZE,\n allowedTypes,\n maxFiles = DEFAULT_MAX_FILES\n } = 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\n // 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 =\n 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","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/drizzle.config.ts\n * Drizzle Kit configuration for CMS database\n */\nexport function drizzleConfigTemplate(): string {\n return `import { loadEnvConfig } from '@next/env'\nimport { defineConfig } from 'drizzle-kit'\n\nloadEnvConfig(process.cwd())\n\nexport default defineConfig({\n out: './cms/db/migrations',\n schema: './cms/db/schema.ts',\n dialect: 'postgresql',\n dbCredentials: {\n url: process.env.BETTERSTART_DATABASE_URL!,\n },\n})\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 */\nconst 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 '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 'markdown-it-dollarmath',\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 'usehooks-ts',\n 'vaul'\n]\n\n/** Email deps — only when email feature is enabled */\nconst EMAIL_DEPS = ['resend', '@react-email/components']\n\n/** Dev deps — always installed */\nconst DEV_DEPS = ['drizzle-kit', 'sass', '@types/katex', '@types/markdown-it']\n\n/** Biome dev dep — only when no existing linter */\nconst 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]\n if (includeEmail) coreDeps.push(...EMAIL_DEPS)\n\n const devDeps = [...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'\n\nimport type { EnvSection } from '../../utils/env.js'\nimport { appendEnvVars } from '../../utils/env.js'\n\nfunction getCoreEnvSections(databaseUrl?: string): 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:3000' },\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\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 sections = getCoreEnvSections(options.databaseUrl)\n if (options.includeEmail) {\n sections.push(getEmailEnvSection())\n }\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 { CmsHeader } from '@cms/components/layout/cms-header'\nimport { CmsSidebar } from '@cms/components/layout/cms-sidebar'\nimport { requireRole } from '@cms/auth/middleware'\nimport { UserRole } from '@cms/types/auth'\nimport { SidebarInset, SidebarProvider } from '@cms/components/ui/sidebar'\n\nexport default async function CmsAuthLayout({\n children\n}: {\n children: React.ReactNode\n}) {\n await requireRole([UserRole.ADMIN, UserRole.EDITOR])\n\n return (\n <SidebarProvider>\n <CmsSidebar />\n <SidebarInset>\n <CmsHeader />\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'\n\nexport default function CmsLayout({ children }: { children: React.ReactNode }) {\n return (\n <CmsProviders>\n <div className=\"cms-root min-h-screen\">{children}</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 { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@cms/components/ui/card'\nimport { Badge } from '@cms/components/ui/badge'\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 <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader\n title=\"Dashboard\"\n description=\"Welcome to your CMS admin panel\"\n />\n </div>\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\">\n Sign in to access the admin panel\n </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 { 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\">\n {error}\n </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 ? '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 { 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 { createUser } from '@cms/actions/users'\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 { 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 { updateUserRole } from '@cms/actions/users'\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({\n userId,\n currentRole,\n userName,\n children\n}: 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>\n Change the role for {userName}\n </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\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={isPending}\n >\n Cancel\n </Button>\n <Button\n onClick={handleSave}\n disabled={isPending || role === currentRole}\n >\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 React from 'react'\nimport {\n Avatar,\n AvatarFallback\n} from '@cms/components/ui/avatar'\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 { 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 type { ColumnDef } from '@tanstack/react-table'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ArrowUpDown, Edit, MoreHorizontal, Trash } from 'lucide-react'\nimport { toast } from 'sonner'\nimport { deleteUser } from '@cms/actions/users'\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\n className=\"text-destructive\"\n onSelect={(e) => e.preventDefault()}\n >\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{' '}\n <strong>{userName}</strong> 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\n onClick={() => navigator.clipboard.writeText(row.original.id)}\n >\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\n title=\"Users\"\n description=\"Manage all CMS users\"\n >\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 {\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'\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 { authClient } from '@cms/auth/client'\nimport type { UserData } from '@cms/types/auth'\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-generator.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 }\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 { loadEnvConfig } from '@next/env'\nloadEnvConfig(process.cwd())\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'\n\nasync function main() {\n console.log('\\\\n Creating admin user...')\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 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 spinner = clack.spinner()\n spinner.start('Creating admin user...')\n\n // Run the seed script with tsx\n try {\n const { execFileSync } = await import('node:child_process')\n execFileSync('npx', ['tsx', seedPath], {\n cwd,\n stdio: 'pipe',\n env: {\n ...process.env,\n SEED_EMAIL: email,\n SEED_PASSWORD: password,\n SEED_NAME: name || 'Admin'\n }\n })\n spinner.stop('Admin user created')\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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 // Find the nav item 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"],"mappings":"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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;AA2MT;;;AC7MO,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmLT;;;ACpLO,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;AAAA;AAAA;AAAA;AA2FT;;;AC5FO,SAAS,2BAAmC;AACjD,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;AA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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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwLT;;;ACzLO,SAAS,uBAA+B;AAC7C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcT;;;ACfO,SAAS,6BAAqC;AACnD,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;AAmIT;;;ACpIO,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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwJT;;;AC3JO,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;AAkIT;;;ACnIO,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;AA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oFT;;;ACpHO,SAAS,2BAAmC;AACjD,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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2GT;;;AC5GO,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;A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","names":["Command","path","fs","path","path","fs","content","parsed","path","fs","path","fs","path","toPascalCase","fs","path","toPascalCase","p","getAllFields","hasDynamicFields","fs","path","toKebabCase","toPascalCase","toCamelCase","p","toKebabCase","getAllFields","hasDynamicFields","path","fs","fs","path","toPascalCase","toCamelCase","p","singularize","quotePropertyName","path","fs","fs","path","toPascalCase","toCamelCase","p","singularize","pluralize","path","fs","fns","fs","path","toPascalCase","singularize","pluralize","generateColumnDef","generateColumns","path","fs","fs","path","toPascalCase","singularize","toKebabCase","fs","path","toPascalCase","toCamelCase","p","singularize","path","fs","fs","path","toPascalCase","toCamelCase","p","singularize","toKebabCase","fs","path","toPascalCase","singularize","pluralize","quotePropertyName","base","generateFieldJSX","path","fs","fs","path","toPascalCase","singularize","pluralize","path","fs","fs","path","parseNavigationFile","extractTopLevelArray","parseItemsBlock","parseSingleItem","generateNavigationCode","appendItem","fs","path","toPascalCase","pluralize","toKebabCase","generatePage","fs","path","toPascalCase","singularize","pluralize","toKebabCase","singularizeLabel","generatePageContent","fs","path","toPascalCase","singularize","fs","path","toPascalCase","toCamelCase","p","singularize","pluralize","toKebabCase","generateTable","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","spinner","execFileSync","Command","pc","path","execFileSync","fs","password","spawn","fs","path","Command","toPascalCase","toCamelCase","p","singularize","toKebabCase","findTableEnd","fs","Command","path","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.ts","../src/generators/form-generator.ts","../src/core/type-mappers.ts","../src/generators/email-template.ts","../src/generators/form-admin-pages.ts","../src/generators/form-navigation.ts","../src/generators/actions.ts","../src/generators/cache.ts","../src/generators/columns.ts","../src/generators/create-page.ts","../src/generators/database.ts","../src/generators/edit-page.ts","../src/generators/form.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-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-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/scaffolders/database.ts","../src/init/templates/db/client.ts","../src/init/templates/db/drizzle-config.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"],"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'\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)\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-generator.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.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 helper utilities for the codegen system\n * Consolidates duplicated field-checking functions from generators\n */\n\nimport type { FormField, FormSchema, 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// Field Collection\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/**\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(\n fields: SchemaField[],\n options?: WalkFieldsOptions\n): SchemaField[] {\n const result: SchemaField[] = []\n walkFields(\n fields,\n (field) => {\n if (field.type === 'relationship' && field.relationship && !field.multiple) {\n result.push(field)\n }\n },\n options\n )\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// ============================================================================\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// Form Field Helpers\n// ============================================================================\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// Field Analysis\n// ============================================================================\n\nexport interface FieldAnalysis {\n hasBoolean: boolean\n hasImage: boolean\n hasVideo: boolean\n hasMedia: boolean\n hasDate: boolean\n hasList: boolean\n hasNestedList: boolean\n hasSelect: boolean\n hasMarkdown: boolean\n hasTextarea: boolean\n hasSeparator: boolean\n hasIcon: boolean\n hasRelationship: boolean\n hasManyToMany: boolean\n fieldTypes: Set<string>\n}\n\n/**\n * Analyze all field types in a schema\n */\nexport function analyzeFields(fields: SchemaField[]): FieldAnalysis {\n const fieldTypes = new Set<string>()\n let hasIcon = false\n let hasNestedList = false\n\n walkFields(fields, (field) => {\n fieldTypes.add(field.type)\n if (field.type === 'icon' || field.hasIcon) hasIcon = true\n })\n\n const listFields = getListFieldsWithNestedFields(fields)\n for (const listField of listFields) {\n if (listField.fields?.some((f) => f.type === 'list')) {\n hasNestedList = true\n break\n }\n }\n\n return {\n hasBoolean: fieldTypes.has('boolean'),\n hasImage: fieldTypes.has('image'),\n hasVideo: fieldTypes.has('video'),\n hasMedia: fieldTypes.has('media'),\n hasDate: fieldTypes.has('date'),\n hasList: fieldTypes.has('list'),\n hasNestedList,\n hasSelect: fieldTypes.has('select'),\n hasMarkdown: fieldTypes.has('markdown'),\n hasTextarea: fieldTypes.has('text'),\n hasSeparator: fieldTypes.has('separator'),\n hasIcon,\n hasRelationship: fieldTypes.has('relationship'),\n hasManyToMany: getManyToManyFields(fields).length > 0,\n fieldTypes\n }\n}\n","/**\n * Form generator: generates database schema, server actions, React Query hook,\n * and public form component for \"type\": \"form\" schemas.\n *\n * Orchestrated by runFormPipeline() — called from the generate command.\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { BetterstartConfig } from '../config/types.js'\nimport { formFieldToDrizzleType, formFieldToZodType } from '../core/type-mappers.js'\nimport type { FormField, FormSchema, GeneratorOptions } from '../types.js'\nimport { generateEmailTemplate } from './email-template.js'\nimport { generateFormAdminPages } from './form-admin-pages.js'\nimport { updateFormNavigation } from './form-navigation.js'\n\n// ============================================================================\n// String Helpers (local to this generator)\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n// ============================================================================\n// Field Helpers\n// ============================================================================\n\n/**\n * Get all fields from a form schema (flatten steps and groups)\n * Skips dynamicFields since they have no database columns\n */\nfunction getAllFields(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) {\n return flatten(field.fields)\n }\n return field.type === 'group' ? [] : [field]\n })\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 * Check if a form schema has dynamicFields\n */\nfunction hasDynamicFields(schema: FormSchema): boolean {\n const check = (fields: FormField[]): boolean => {\n for (const field of fields) {\n if (field.type === 'dynamicFields') return true\n if (field.type === 'group' && field.fields && check(field.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// ============================================================================\n// Result Types\n// ============================================================================\n\nexport interface FormPipelineResult {\n success: boolean\n files: string[]\n errors: string[]\n}\n\ninterface StepResult {\n files: string[]\n}\n\n// ============================================================================\n// Step 1: Database Schema\n// ============================================================================\n\nfunction 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 = getAllFields(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 existing table if --force\n if (content.includes(`export const ${tableName}`)) {\n if (!options.force) {\n return { files: [dbSchemaPath] }\n }\n const regex = new RegExp(`\\\\nexport const ${tableName} = pgTable\\\\([\\\\s\\\\S]*?\\\\n\\\\}\\\\)\\\\n`, 'g')\n content = content.replace(regex, '')\n }\n\n content += `\\n${tableSchema}`\n fs.writeFileSync(filePath, content, 'utf-8')\n\n return { files: [dbSchemaPath] }\n}\n\n// ============================================================================\n// Step 2: Server Actions\n// ============================================================================\n\nfunction 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 = getAllFields(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 filePath = path.join(cwd, actionsDir, `${formName}-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 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'\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) => 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 }\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) => {\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// ============================================================================\n// Step 3: React Query Hook\n// ============================================================================\n\nfunction 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\n const filePath = path.join(cwd, hooksDir, `use-${toKebabCase(formName)}-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/${formName}-form'\nimport type { Create${pascal}SubmissionInput } from '@cms/actions/${formName}-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// ============================================================================\n// Step 4: Public Form Component\n// ============================================================================\n\nfunction generateFormComponent(\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 = getAllFields(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 // Build zod schema fields\n const zodFields = fields\n .filter((f) => f.name)\n .map((f) => ` ${f.name}: ${formFieldToZodType(f)}`)\n .join(',\\n')\n\n // Build default values\n const defaults = 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.defaultValue !== undefined) return ` ${f.name}: '${f.defaultValue}'`\n return ` ${f.name}: ''`\n })\n .join(',\\n')\n\n // Build form field JSX\n const fieldJSX = fields\n .filter((f) => f.name && !f.hidden)\n .map((f) => generateFieldJSX(f))\n .join('\\n\\n')\n\n const submitText = schema.submitButtonText || 'Submit'\n const successMessage = (schema.successMessage || 'Form submitted successfully!').replace(\n /'/g,\n \"\\\\'\"\n )\n\n const content = `'use client'\n\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { useState } from 'react'\nimport { useForm } from 'react-hook-form'\nimport { z } from 'zod'\nimport { create${pascal}Submission } from '@cms/actions/${formName}-form'\nimport { Button } from '@cms/components/ui/button'\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@cms/components/ui/form'\nimport { Input } from '@cms/components/ui/input'\nimport { Textarea } from '@cms/components/ui/textarea'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@cms/components/ui/select'\n\nconst formSchema = z.object({\n${zodFields}\n})\n\ntype FormValues = z.infer<typeof formSchema>\n\nexport function ${pascal}Form() {\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\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`\n\n fs.writeFileSync(filePath, content, 'utf-8')\n return { files: [path.relative(cwd, filePath)] }\n}\n\n/**\n * Generate JSX for a single form field\n */\nfunction generateFieldJSX(field: FormField): string {\n const name = field.name || ''\n const label = field.label\n const placeholder = field.placeholder || ''\n const hint = field.hint || ''\n\n const hintJSX = hint ? `\\n <FormDescription>${hint}</FormDescription>` : ''\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 'select':\n case 'radio':\n if (field.options && field.options.length > 0) {\n const optionItems = field.options\n .map(\n (opt) =>\n ` <SelectItem value=\"${opt.value}\">${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(\n name,\n label,\n placeholder || 'email@example.com',\n hintJSX,\n requiredStar,\n 'email'\n )\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(\n name,\n label,\n placeholder || 'https://',\n hintJSX,\n requiredStar,\n 'url'\n )\n\n case 'phone':\n return generateTextFieldJSX(\n name,\n label,\n placeholder || '+1 (555) 000-0000',\n hintJSX,\n requiredStar,\n 'tel'\n )\n\n default:\n return generateTextFieldJSX(name, label, placeholder, hintJSX, requiredStar, 'text')\n }\n}\n\nfunction 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\n// ============================================================================\n// Pipeline Orchestrator\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 * Type mapping utilities for the codegen system\n * Single deduped implementation (fixes known issue #8)\n *\n * Consolidates type mapping from: database.ts, form.ts, actions.ts, form-generator.ts\n */\n\nimport type { FormField, SchemaField } from '../types.js'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DRIZZLE_DEFAULTS = {\n VARCHAR_LENGTH: 255,\n DECIMAL_PRECISION: 10,\n DECIMAL_SCALE: 2\n} as const\n\n// ============================================================================\n// Internal helpers (ported from monorepo utils.ts)\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('')\n}\n\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\n\n/**\n * Quote a property name if it's not a valid JS identifier\n */\nfunction quotePropertyName(name: string): string {\n const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/\n return validIdentifier.test(name) ? name : `'${name}'`\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// 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// 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// ============================================================================\n// Form Field → Drizzle Type (for form-generator)\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// ============================================================================\n// Form Field → Zod Type (for form-generator)\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.literal(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 * 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 type { FormField, FormSchema, GeneratorOptions } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\n// ============================================================================\n// Field Helpers\n// ============================================================================\n\nfunction getAllFields(schema: FormSchema): FormField[] {\n const flatten = (fields: FormField[]): FormField[] => {\n return fields.flatMap((field) => {\n if (field.type === 'dynamicFields' || field.type === 'group') {\n if (field.type === 'group' && field.fields) return flatten(field.fields)\n return []\n }\n return [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\nfunction 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// ============================================================================\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 = getAllFields(schema).filter((f) => f.name)\n const includeDynamic = hasDynamicFields(schema)\n\n const filePath = path.join(cwd, cmsDir, 'lib', 'emails', `${formName}-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 * 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 type { FormColumn, FormField, FormSchema, GeneratorOptions } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n// ============================================================================\n// Field Helpers\n// ============================================================================\n\nfunction getAllFields(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\nfunction 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// ============================================================================\n// Result Type\n// ============================================================================\n\nexport interface FormAdminPagesResult {\n files: string[]\n}\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// 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 = getAllFields(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\n// ============================================================================\n// File Generators\n// ============================================================================\n\nfunction 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\nfunction 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) => { 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) => table.toggleAllPageRowsSelected(!!value)}\n aria-label=\"Select all\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n checked={row.getIsSelected()}\n onCheckedChange={(value) => 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\nfunction 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\nfunction 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 { 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 { PageHeader } from '@cms/components/shared/page-header'\nimport { useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Search, Settings, Trash2 } from 'lucide-react'\nimport Link from 'next/link'\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 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 <div className=\"flex items-center justify-between border-b px-6 py-4\">\n <PageHeader title=\"${label}\" description=\"View and manage form submissions\" />\n <div className=\"flex items-center gap-2\">\n <form action={searchAction} 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=\"Search submissions...\"\n defaultValue={search}\n className=\"w-64 pl-9\"\n />\n </div>\n <Button type=\"submit\" variant=\"outline\">Search</Button>\n </form>\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 {selectedIds.length > 0 && (\n <AlertDialog open={deleteOpen} onOpenChange={setDeleteOpen}>\n <AlertDialogTrigger asChild>\n <Button variant=\"destructive\">\n <Trash2 className=\"size-3.5\" />\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) => { 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 </div>\n </div>\n\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\nfunction 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 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 { Button } from '@cms/components/ui/button'\nimport { ArrowLeft } 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 <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">${label} Submission</h1>\n <p className=\"text-muted-foreground\">Viewing submission #{id}</p>\n </div>\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/forms/${kebab}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${label}\n </Link>\n </Button>\n </div>\n\n <div className=\"rounded-lg border p-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 </div>\n )\n}\n`\n}\n\nfunction 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 { 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 { ArrowLeft, Loader2 } from 'lucide-react'\nimport Link from 'next/link'\nimport { useEffect, useState, useTransition } from 'react'\nimport { toast } from 'sonner'\n\nexport default function ${pascal}SettingsPage() {\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 <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">${label} Settings</h1>\n <p className=\"text-muted-foreground\">\n Configure notifications and webhooks for this form\n </p>\n </div>\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/forms/${kebab}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${label}\n </Link>\n </Button>\n </div>\n\n <div className=\"space-y-6 rounded-lg border p-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 </div>\n )\n}\n`\n}\n","/**\n * Form navigation generator: adds form submissions entry to cms/data/navigation.ts\n * Groups forms under a \"Forms\" parent with FileInput icon, each form gets Inbox icon\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport type { FormSchema, GeneratorOptions } from '../types.js'\n\n// ============================================================================\n// Types (same as entity navigation generator)\n// ============================================================================\n\ninterface NavItem {\n label: string\n href: string\n icon?: string\n children?: NavItem[]\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\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\n const childrenMatch = str.match(/children:\\s*\\[([\\s\\S]*?)\\]/)\n if (childrenMatch) {\n item.children = parseItemsBlock(childrenMatch[1])\n }\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 { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push(\"import type { LucideIcon } 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(' children?: CmsNavigationItem[]')\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], 2, 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, indent: number, isLast: boolean): void {\n const pad = ' '.repeat(indent)\n\n if (item.children && item.children.length > 0) {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}',`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon},`)\n lines.push(`${pad} children: [`)\n for (let j = 0; j < item.children.length; j++) {\n appendItem(lines, item.children[j], indent + 4, j === item.children.length - 1)\n }\n lines.push(`${pad} ]`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n } else {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}'${item.icon ? ',' : ''}`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon}`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n }\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface FormNavigationResult {\n files: string[]\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Update cms/data/navigation.ts to add form under a \"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 // Find or create Forms group\n let formsGroup = items.find((item) => item.label === 'Forms')\n\n if (!formsGroup) {\n formsGroup = {\n label: 'Forms',\n href: '#',\n icon: 'FileInput',\n children: []\n }\n // Insert before Users/Settings\n items.push(formsGroup)\n }\n\n if (!formsGroup.children) {\n formsGroup.children = []\n }\n\n // Create form sub-item\n const kebab = toKebabCase(schema.name)\n const formHref = `/cms/forms/${kebab}`\n const existingIndex = formsGroup.children.findIndex((c) => c.href === formHref)\n\n const newChild: NavItem = {\n label: schema.label,\n href: formHref,\n icon: 'Inbox'\n }\n\n if (existingIndex >= 0) {\n if (options.force) {\n formsGroup.children[existingIndex] = newChild\n } else {\n return { files: [] }\n }\n } else {\n formsGroup.children.push(newChild)\n formsGroup.children.sort((a, b) => a.label.localeCompare(b.label))\n }\n\n // Reorganize: Dashboard first, then alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => a.label.localeCompare(b.label))\n\n items = [...(dashboard ? [dashboard] : []), ...others]\n\n // Ensure required icons are imported\n for (const icon of ['FileInput', 'Inbox']) {\n if (!iconImports.includes(icon)) {\n iconImports.push(icon)\n }\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 * 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.js'\nimport { toTypeScriptType } from '../core/type-mappers.js'\nimport type { Schema, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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}\nfunction 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}\nfunction quotePropertyName(name: string): string {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`\n}\n\n// ============================================================================\n// Field Mapping Helpers\n// ============================================================================\n\nfunction 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\nfunction getFieldType(field: SchemaField, mode: 'input' | 'output' = 'output'): string {\n return toTypeScriptType(field, mode)\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface ActionsGeneratorResult {\n files: string[]\n}\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 } 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: path.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 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 // 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\n const dataInterface = `export interface ${Singular}Data {\\n${dataFields}${m2mFieldTypes ? `\\n${m2mFieldTypes}` : ''}\\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 // --- 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 // --- 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 // --- 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/getBySlug) ---\n const singleRowReturn = (() => {\n if (hasRelationships && hasListRels) {\n return `const row = result[0]\\n return await populate${Singular}ListRelationships(${buildSingleRowMapping(allDbFields, relationshipFields, Singular)})`\n }\n if (hasRelationships) {\n return `const row = result[0]\\n return ${buildSingleRowMapping(allDbFields, relationshipFields, Singular)}`\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 // --- 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}\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 = ${selectClause}\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${resultMapping}\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<${Singular}Data | null> {\n try {\n const result = await ${selectClause}.where(eq(${tableVar}.slug, slug)).limit(1)\n if (result.length === 0) return null\n ${singleRowReturn}\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\n const result = await db.insert(${tableVar}).values({\n${createMappings},${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\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/**\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 // 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 dataInterface = `export interface ${Singular}Data {\\n${dataFields}\\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 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\n const now = new Date().toISOString()\n\n const result = await db\n .insert(${tableVar})\n .values({\n id: 1,\n${upsertMappings},\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// ============================================================================\n// Helper builders for relationship queries\n// ============================================================================\n\nfunction buildRelationshipSelect(\n allDbFields: SchemaField[],\n relationshipFields: SchemaField[],\n tableVar: string\n): string {\n const regularSelects = allDbFields\n .filter((f) => f.type !== 'relationship')\n .map((f) => ` ${f.name}: ${tableVar}.${f.name}`)\n .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\nfunction 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\nfunction buildSingleRowMapping(\n allDbFields: SchemaField[],\n _relationshipFields: SchemaField[],\n Singular: string\n): string {\n const mappings = 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 return `{\\n${mappings}\\n } as ${Singular}Data`\n}\n\n// ============================================================================\n// List-relationship helpers\n// ============================================================================\n\nfunction 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\nfunction 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 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.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toScreamingSnake(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toUpperCase()\n}\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.js'\nimport type { GeneratorOptions, Schema, SchemaColumn, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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\n// ============================================================================\n// Column Helpers\n// ============================================================================\n\nfunction 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\nfunction 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\nfunction 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\nfunction 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// ============================================================================\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 ? `\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 // --- Reorder handler ---\n const reorderHandler = `\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 // --- 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 ? `\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 // --- 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// ============================================================================\n// Custom Cell Component\n// ============================================================================\n\nfunction 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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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 { ArrowLeft } 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 <div className=\"flex flex-col w-full pb-20\">\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader\n title=\"Create ${singLabel}\"\n description=\"Add a new ${singLabel.toLowerCase()} to the system\"\n />\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/${schema.name}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${schema.label}\n </Link>\n </Button>\n </div>\n <main className=\"container mx-auto max-w-5xl p-6\">\n <${Singular}Form key={Date.now()} />\n </main>\n </div>\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.js'\nimport { toDrizzleType } from '../core/type-mappers.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers (local to this generator)\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\n\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\n\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\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 return ` ${field.name}: ${drizzleType}${modifiers}`\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 const hasSqlImport = content.includes(\"import { sql } from 'drizzle-orm'\")\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 (hasSqlImport) {\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 updated = `import { sql } from 'drizzle-orm'\\n${updated}`\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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 { ArrowLeft } 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 <div className=\"flex flex-col w-full pb-20\">\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader\n title=\"Edit ${Singular}\"\n description=\"Update ${singular} information\"\n />\n <Button variant=\"outline\" asChild>\n <Link href=\"/cms/${schema.name}\">\n <ArrowLeft className=\"size-4\" />\n Back to ${schema.label}\n </Link>\n </Button>\n </div>\n <main className=\"container mx-auto max-w-5xl p-6\">\n <${Singular}Form key={${camelSingular}.id} initialData={${camelSingular}} />\n </main>\n </div>\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 * Generator 8: Form — (authenticated)/<n>/<n>-form.tsx\n * Generates 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 } from '../core/field-helpers.js'\nimport type { GeneratorOptions, Schema, SchemaField } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction quotePropertyName(name: string): string {\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${name}'`\n}\n\n// ============================================================================\n// Form Field Type Mapping\n// ============================================================================\n\nfunction 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\n// ============================================================================\n// Zod Schema Generation\n// ============================================================================\n\nfunction 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// ============================================================================\n// Form Field JSX Generation\n// ============================================================================\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\nfunction generateFieldJSX(field: SchemaField, indent = ' '): string {\n if (field.hidden) return ''\n\n const mainJSX = generateFieldJSXCore(field, indent)\n if (!mainJSX) return ''\n\n // Append icon picker postfix for fields with hasIcon\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 const listHintJSX = field.hint\n ? `${indent} <p className=\"text-[0.8rem] text-muted-foreground\">${field.hint}</p>`\n : ''\n\n // Group\n if (field.type === 'group' && field.fields) {\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\n // Separator\n if (field.type === 'separator') {\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\n // Boolean (checkbox)\n if (field.type === 'boolean') {\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\n // Image upload\n if (field.type === 'image') {\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\n // Video upload\n if (field.type === 'video') {\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\n // Media upload (image or video)\n if (field.type === 'media') {\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\n // Icon picker\n if (field.type === 'icon') {\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\n // Date picker\n if (field.type === 'date') {\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\n // Select\n if (field.type === 'select') {\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\n // Rich text editor (TipTap WYSIWYG)\n if (field.type === 'richtext') {\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\n // Markdown editor (CodeMirror plain-text)\n if (field.type === 'markdown') {\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\n // Textarea (text type)\n if (field.type === 'text') {\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\n // Relationship (combobox)\n if (field.type === 'relationship' && field.relationship) {\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 `${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\n // Single relationship\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\n // List field\n if (field.type === 'list') {\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 // 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 // Default: text input\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// ============================================================================\n// Field Analysis Helpers\n// ============================================================================\n\nfunction checkForFieldType(fields: SchemaField[], type: string): boolean {\n for (const f of fields) {\n if (f.type === type) return true\n if (f.type === 'group' && f.fields && checkForFieldType(f.fields, type)) return true\n if (f.type === 'list' && f.fields && checkForFieldType(f.fields, type)) return true\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields && checkForFieldType(tab.fields, type)) return true\n }\n }\n }\n return false\n}\n\nfunction checkForHasIconProperty(fields: SchemaField[]): boolean {\n for (const f of fields) {\n if (f.hasIcon) return true\n if (f.type === 'group' && f.fields && checkForHasIconProperty(f.fields)) return true\n if (f.type === 'list' && f.fields && checkForHasIconProperty(f.fields)) return true\n if (f.type === 'tabs' && f.tabs) {\n for (const tab of f.tabs) {\n if (tab.fields && checkForHasIconProperty(tab.fields)) return true\n }\n }\n }\n return false\n}\n\nfunction 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\n// ============================================================================\n// Default Values Generation\n// ============================================================================\n\nfunction 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\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface FormGeneratorResult {\n files: string[]\n}\n\n/**\n * Generate create/edit form for an entity\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 = checkForFieldType(schema.fields, 'boolean')\n const hasImage = checkForFieldType(schema.fields, 'image')\n const hasVideo = checkForFieldType(schema.fields, 'video')\n const hasMedia = checkForFieldType(schema.fields, 'media')\n const hasIcon = checkForFieldType(schema.fields, 'icon')\n const hasIconPostfix = checkForHasIconProperty(schema.fields)\n const hasDate = checkForFieldType(schema.fields, 'date')\n const hasSelect = checkForFieldType(schema.fields, 'select')\n const hasMarkdown = checkForFieldType(schema.fields, 'markdown')\n const hasRichtext = checkForFieldType(schema.fields, 'richtext')\n const hasTextarea = checkForFieldType(schema.fields, 'text')\n const hasSeparator = checkForFieldType(schema.fields, 'separator')\n const hasRelationship = checkForFieldType(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 if (!tabFieldNames.has(f.name)) listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFields(f.fields)\n }\n }\n collectListFields(allFormFields)\n const hasList = checkForFieldType(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 = 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 // Build default values\n const defaultValues = 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 // 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: 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 (hasBoolean) uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (hasTextarea) uiImports.push(\"import { Textarea } from '@cms/components/ui/textarea'\")\n if (hasImage)\n uiImports.push(\"import { ImageUploadField } from '@cms/components/ui/image-upload-field'\")\n if (hasVideo)\n uiImports.push(\"import { VideoUploadField } from '@cms/components/ui/video-upload-field'\")\n if (hasMedia)\n uiImports.push(\"import { MediaUploadField } from '@cms/components/ui/media-upload-field'\")\n if (hasIcon || hasIconPostfix)\n uiImports.push(\"import { IconPicker } from '@cms/components/ui/icon-picker'\")\n if (hasDate) uiImports.push(\"import { DatePicker } from '@cms/components/ui/date-picker'\")\n if (hasMarkdown)\n uiImports.push(\"import { MarkdownEditor } from '@cms/components/ui/markdown-editor'\")\n if (hasRichtext)\n uiImports.push(\"import { RichTextEditor } from '@cms/components/ui/rich-text-editor'\")\n if (hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n if (hasSelect) {\n uiImports.push(`import {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'`)\n }\n if (hasTabsField) {\n uiImports.push(`import {\n Tabs,\n TabsList,\n TabsTrigger,\n TabsContent\n} from '@cms/components/ui/tabs'`)\n }\n if (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 (hasSimpleList)\n uiImports.push(\"import { DynamicListField } from '@cms/components/ui/dynamic-list-field'\")\n if (hasNestedList) {\n uiImports.push(`import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger\n} from '@cms/components/ui/accordion'`)\n if (!hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n uiImports.push(\"import { Label } from '@cms/components/ui/label'\")\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'${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/**\n * Generate form for a single (singleton) schema.\n * Uses upsertXxx mutation, no router navigation, \"Save\" button.\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 = checkForFieldType(schema.fields, 'boolean')\n const hasImage = checkForFieldType(schema.fields, 'image')\n const hasVideo = checkForFieldType(schema.fields, 'video')\n const hasMedia = checkForFieldType(schema.fields, 'media')\n const hasIcon = checkForFieldType(schema.fields, 'icon')\n const hasIconPostfix = checkForHasIconProperty(schema.fields)\n const hasDate = checkForFieldType(schema.fields, 'date')\n const hasSelect = checkForFieldType(schema.fields, 'select')\n const hasMarkdown = checkForFieldType(schema.fields, 'markdown')\n const hasRichtext = checkForFieldType(schema.fields, 'richtext')\n const hasTextarea = checkForFieldType(schema.fields, 'text')\n const hasSeparator = checkForFieldType(schema.fields, 'separator')\n const hasRelationship = checkForFieldType(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 if (!tabFieldNames.has(f.name)) listFieldsWithNested.push(f)\n }\n if (f.type === 'group' && f.fields) collectListFieldsSingle(f.fields)\n }\n }\n collectListFieldsSingle(allFormFields)\n const hasList = checkForFieldType(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 = 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 // Build default values\n const defaultValues = 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 // 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: 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 (hasBoolean) uiImports.push(\"import { Checkbox } from '@cms/components/ui/checkbox'\")\n if (hasTextarea) uiImports.push(\"import { Textarea } from '@cms/components/ui/textarea'\")\n if (hasImage)\n uiImports.push(\"import { ImageUploadField } from '@cms/components/ui/image-upload-field'\")\n if (hasVideo)\n uiImports.push(\"import { VideoUploadField } from '@cms/components/ui/video-upload-field'\")\n if (hasMedia)\n uiImports.push(\"import { MediaUploadField } from '@cms/components/ui/media-upload-field'\")\n if (hasIcon || hasIconPostfix)\n uiImports.push(\"import { IconPicker } from '@cms/components/ui/icon-picker'\")\n if (hasDate) uiImports.push(\"import { DatePicker } from '@cms/components/ui/date-picker'\")\n if (hasMarkdown)\n uiImports.push(\"import { MarkdownEditor } from '@cms/components/ui/markdown-editor'\")\n if (hasRichtext)\n uiImports.push(\"import { RichTextEditor } from '@cms/components/ui/rich-text-editor'\")\n if (hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n if (hasSelect) {\n uiImports.push(`import {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue\n} from '@cms/components/ui/select'`)\n }\n if (hasTabsField) {\n uiImports.push(`import {\n Tabs,\n TabsList,\n TabsTrigger,\n TabsContent\n} from '@cms/components/ui/tabs'`)\n }\n if (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 if (hasSimpleList)\n uiImports.push(\"import { DynamicListField } from '@cms/components/ui/dynamic-list-field'\")\n if (hasNestedList) {\n uiImports.push(`import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger\n} from '@cms/components/ui/accordion'`)\n if (!hasSeparator) uiImports.push(\"import { Separator } from '@cms/components/ui/separator'\")\n uiImports.push(\"import { Label } from '@cms/components/ui/label'\")\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'${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.js'\nimport type { GeneratorOptions, Schema } from '../types.js'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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\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\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 = [`type ${Singular}Data`, `type ${Plural}Response`, `type Get${Plural}Filters`]\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 slugHook = hasSlugField\n ? `\n\nexport function use${Singular}BySlug(slug: string | null | undefined): UseQueryResult<${Singular}Data | 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 */\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 children?: NavItem[]\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 // Extract icon imports from lucide-react\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 // Extract array content using bracket counting (handles nested children arrays)\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 // Find `= [` to skip the `[]` in the type annotation (CmsNavigationItem[])\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 // Count brackets to find the matching `]`\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\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\n // Check for children array\n const childrenMatch = str.match(/children:\\s*\\[([\\s\\S]*?)\\]/)\n if (childrenMatch) {\n item.children = parseItemsBlock(childrenMatch[1])\n }\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 // Icon imports\n lines.push(`import { ${iconImports.join(', ')} } from 'lucide-react'`)\n lines.push(\"import type { LucideIcon } 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(' children?: CmsNavigationItem[]')\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, 2, isLast)\n }\n\n lines.push(']')\n lines.push('')\n\n return lines.join('\\n')\n}\n\nfunction appendItem(lines: string[], item: NavItem, indent: number, isLast: boolean): void {\n const pad = ' '.repeat(indent)\n\n if (item.children && item.children.length > 0) {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}',`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon},`)\n lines.push(`${pad} children: [`)\n for (let j = 0; j < item.children.length; j++) {\n appendItem(lines, item.children[j], indent + 4, j === item.children.length - 1)\n }\n lines.push(`${pad} ]`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n } else {\n lines.push(`${pad}{`)\n lines.push(`${pad} label: '${item.label}',`)\n lines.push(`${pad} href: '${item.href}'${item.icon ? ',' : ''}`)\n if (item.icon) lines.push(`${pad} icon: ${item.icon}`)\n lines.push(`${pad}}${isLast ? '' : ','}`)\n }\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 // Check if item already exists (including inside groups)\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.navGroup) {\n // Insert into a parent group\n let group = items.find((item) => item.label === schema.navGroup?.label)\n\n if (!group) {\n group = {\n label: schema.navGroup.label,\n href: '#',\n icon: schema.navGroup.icon,\n children: []\n }\n items.push(group)\n }\n\n if (!group.children) {\n group.children = []\n }\n\n const existingChild = group.children.findIndex((c) => c.href === entityHref)\n\n if (existingChild >= 0) {\n if (options.force) {\n group.children[existingChild] = newItem\n } else {\n return { files: [] }\n }\n } else {\n group.children.push(newItem)\n group.children.sort((a, b) => a.label.localeCompare(b.label))\n }\n\n // Add group icon import\n if (schema.navGroup.icon && !iconImports.includes(schema.navGroup.icon)) {\n iconImports.push(schema.navGroup.icon)\n }\n } else {\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\n // Reorganize: Dashboard first, then alphabetical\n const dashboard = items.find((item) => item.href === '/cms')\n const others = items.filter((item) => item.href !== '/cms')\n others.sort((a, b) => a.label.localeCompare(b.label))\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\nfunction 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 // Re-capitalize first letter\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// ============================================================================\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[] = ['Search']\n if (hasCreate) lucideIcons.push('FilePlus')\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 { 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\">\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=\"Search ${schema.label.toLowerCase()}...\"\n defaultValue={search}\n className=\"w-64 pl-9\"\n />\n </div>\n <SearchButton />\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 <FilePlus 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 queryClient = useQueryClient()\n${searchLogic}${deleteLogic}\n return (\n <>\n <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader title=\"${schema.label}\" description=\"${schema.description}\" />\n <div className=\"flex items-center gap-2\">\n${filterDropdowns ? `${filterDropdowns}\\n` : ''}${searchInput}\n${deleteButton}\n${createButton}\n </div>\n </div>\n\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\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 <div className=\"flex flex-col\">\n <PageHeader title=\"${schema.label}\" />\n <div className=\"max-w-5xl mx-auto w-full pb-24\">\n <${Singular}Form initialData={data} />\n </div>\n </div>\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction 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}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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.js'\nimport { generateCache } from './cache.js'\nimport { generateColumns } from './columns.js'\nimport { generateCreatePage } from './create-page.js'\nimport { generateDatabase } from './database.js'\nimport { generateEditPage } from './edit-page.js'\nimport { generateForm, generateSingleForm } from './form.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.js'\nexport { generateCache } from './cache.js'\nexport { generateColumns } from './columns.js'\nexport { generateCreatePage } from './create-page.js'\nexport { generateDatabase } from './database.js'\nexport { generateEditPage } from './edit-page.js'\nexport { generateForm, generateSingleForm } from './form.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\n console.log('\\n Running drizzle-kit push...')\n try {\n execFileSync('npx', ['drizzle-kit', 'push'], { cwd, stdio: 'pipe' })\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\n try {\n execFileSync('npx', ['biome', '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 for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) {\n if (fs.existsSync(path.join(cwd, lockfile))) {\n return pm\n }\n }\n\n // Check packageManager field in package.json\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')) 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\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 { 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 {\n createNextAppCommand,\n detectPackageManager,\n runCommand\n} 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 .action(\n async (\n name: string | undefined,\n options: { preset: string; yes?: boolean; databaseUrl?: string }\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(`Existing Next.js project detected`)\n p.log.info(`Package manager: ${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 (project.conflicts.length > 0) {\n p.log.error('Conflicts detected:')\n for (const conflict of project.conflicts) {\n p.log.warning(` - ${conflict}`)\n }\n if (!options.yes) {\n const proceed = await p.confirm({\n message: 'Continue anyway? (existing files will NOT be overwritten)',\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 = projectPrompt.projectName === '.'\n ? path.basename(cwd)\n : 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\n const s = p.spinner()\n\n s.start('Creating CMS directory structure...')\n const baseFiles = scaffoldBase({ cwd, config })\n s.stop(`Created ${baseFiles.length} files`)\n\n s.start('Configuring TypeScript path aliases...')\n const tsResult = scaffoldTsconfig(cwd)\n s.stop(`Added ${tsResult.added.length} path aliases`)\n\n s.start('Configuring Tailwind CSS...')\n const twResult = scaffoldTailwind(cwd, srcDir)\n if (twResult.appended) {\n s.stop(`Updated ${twResult.file}`)\n } else if (twResult.file) {\n s.stop('Tailwind already configured for CMS')\n } else {\n s.stop('No CSS file found (will configure later)')\n }\n\n s.start('Setting up environment variables...')\n const envResult = scaffoldEnv(cwd, { includeEmail: features.includeEmail, databaseUrl })\n const envParts = [`Added ${envResult.added.length}`]\n if (envResult.updated.length > 0) envParts.push(`updated ${envResult.updated.length}`)\n s.stop(`${envParts.join(', ')} env vars in .env.local`)\n\n s.start('Setting up database...')\n const dbFiles = scaffoldDatabase({ cwd, config })\n s.stop(`Created ${dbFiles.length} database files`)\n\n s.start('Setting up authentication...')\n const authFiles = scaffoldAuth({ cwd, config })\n s.stop(`Created ${authFiles.length} auth files`)\n\n s.start('Copying CMS components...')\n const compFiles = scaffoldComponents({ cwd, config })\n s.stop(`Created ${compFiles.length} component files`)\n\n s.start('Creating CMS pages and layouts...')\n const layoutFiles = scaffoldLayout({ cwd, config })\n s.stop(`Created ${layoutFiles.length} page files`)\n\n s.start('Creating API routes...')\n const apiFiles = scaffoldApiRoutes({ cwd, config })\n s.stop(`Created ${apiFiles.length} API routes`)\n\n // Set up Biome if no linter detected\n s.start('Checking for linter...')\n if (project.linter.type === 'none') {\n s.stop('No linter found')\n s.start('Setting up Biome linter...')\n const biomeResult = scaffoldBiome(cwd, project.linter)\n if (biomeResult.installed) {\n s.stop('Created biome.json')\n } else {\n s.stop(`Biome skipped: ${biomeResult.skippedReason}`)\n }\n } else {\n s.stop(`Linter: ${pc.cyan(project.linter.type)} (${project.linter.configFile})`)\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 if (depsResult.success) {\n s.stop(\n `Installed ${depsResult.coreDeps.length} deps + ${depsResult.devDeps.length} dev deps`\n )\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 (always runs — settings schema needed for all presets)\n s.start(`Applying ${features.preset} preset...`)\n const presetResult = scaffoldPreset({ cwd, config, preset: features.preset })\n if (presetResult.errors.length > 0) {\n s.stop(`Preset applied with ${presetResult.errors.length} warning(s)`)\n for (const err of presetResult.errors) {\n p.log.warning(` ${err}`)\n }\n } else {\n s.stop(\n `Created ${presetResult.schemas.length} schemas, generated ${presetResult.generatedFiles.length} files`\n )\n }\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('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.log.step('Create your admin account')\n\n const email = await 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 if (p.isCancel(email)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n const password = await 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 if (p.isCancel(password)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\n seedEmail = email\n seedPassword = password\n\n s.start('Creating admin user...')\n const seedResult = await runSeed(cwd, config.paths?.cms ?? './cms', email, password)\n if (seedResult.success) {\n s.stop('Admin user created')\n seedSuccess = true\n } else {\n s.stop('Failed to create admin user')\n p.log.warning(seedResult.error ?? 'Unknown error')\n p.log.info(`You can run it manually: ${pc.cyan('npx betterstart seed')}`)\n }\n }\n\n // Regenerate CMS.md with full documentation\n {\n const entityNames: string[] = []\n const formNames: string[] = []\n // Scan schemas dir for generated entities and forms\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\n // Git init + commit for fresh projects\n if (isFreshProject) {\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 p.log.success('Created initial git commit')\n } catch {\n // Non-critical — don't block init if git fails\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 `Email: ${features.includeEmail ? pc.green('yes') : pc.dim('no')}`,\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:3000/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\n/** Write seed script, run it with tsx, clean up. Returns success/error. */\nasync function runSeed(\n cwd: string,\n cmsDir: string,\n email: string,\n password: string\n): Promise<{ success: boolean; error: string | null }> {\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 try {\n const tsxBin = path.join(cwd, 'node_modules', '.bin', 'tsx')\n execFileSync(tsxBin, [seedPath], {\n cwd,\n stdio: 'pipe',\n timeout: 30_000,\n env: { ...process.env, SEED_EMAIL: email, SEED_PASSWORD: password, SEED_NAME: 'Admin' }\n })\n return { success: true, error: null }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, error: msg }\n } finally {\n // Clean up seed script\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\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: boolean\n preset: Preset\n}\n\n/**\n * Prompt for email system and preset selection.\n */\nexport async function promptFeatures(presetOverride?: string): Promise<FeaturesPromptResult> {\n const includeEmail = await p.confirm({\n message: 'Include email system? (Resend + React Email)',\n initialValue: true\n })\n\n if (p.isCancel(includeEmail)) {\n p.cancel('Setup cancelled.')\n process.exit(0)\n }\n\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, 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 { validateFiles } from '@cms/utils/validation'\nimport type { UploadedFile } from '@cms/types'\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(\n { success: false, error: 'No files provided' },\n { status: 400 }\n )\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\n .map((e) => \\`\\${e.filename}: \\${e.error}\\`)\n .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 =\n error instanceof Error ? error.message : 'Failed to upload files'\n return NextResponse.json(\n { success: false, error: message },\n { status: 500 }\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 { 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: process.env.NEXT_PUBLIC_BETTERSTART_AUTH_URL || (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 (\n typeof value === 'string' &&\n Object.values(UserRole).includes(value as UserRole)\n )\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 { 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 { 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'\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-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\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\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\n@custom-variant dark (&:is(.dark *));\n\n:root {\n --background: oklch(0.9850 0 0);\n --foreground: oklch(0 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0 0 0);\n --popover: oklch(0.9900 0 0);\n --popover-foreground: oklch(0 0 0);\n --primary: oklch(0 0 0);\n --primary-foreground: oklch(1 0 0);\n --secondary: oklch(0.9700 0 0);\n --secondary-foreground: oklch(0 0 0);\n --muted: oklch(0.9700 0 0);\n --muted-foreground: oklch(0.4400 0 0);\n --accent: oklch(0.9700 0 0);\n --accent-foreground: oklch(0 0 0);\n --destructive: oklch(0.6300 0.1900 23.0300);\n --destructive-foreground: oklch(1 0 0);\n --border: oklch(0.9200 0 0);\n --input: oklch(0.9400 0 0);\n --ring: oklch(0 0 0);\n --chart-1: oklch(0.8100 0.1700 75.3500);\n --chart-2: oklch(0.5500 0.2200 264.5300);\n --chart-3: oklch(0.7200 0 0);\n --chart-4: oklch(0.9200 0 0);\n --chart-5: oklch(0.5600 0 0);\n --sidebar: oklch(1 0 0);\n --sidebar-foreground: oklch(0 0 0);\n --sidebar-primary: oklch(0 0 0);\n --sidebar-primary-foreground: oklch(1 0 0);\n --sidebar-accent: oklch(0.9400 0 0);\n --sidebar-accent-foreground: oklch(0 0 0);\n --sidebar-border: oklch(0.9400 0 0);\n --sidebar-ring: oklch(0 0 0);\n --font-sans: Geist, sans-serif;\n --font-serif: Georgia, serif;\n --font-mono: Geist Mono, monospace;\n --radius: 0.4rem;\n --shadow-x: 0px;\n --shadow-y: 1px;\n --shadow-blur: 3px;\n --shadow-spread: 0px;\n --shadow-opacity: 0.02;\n --shadow-color: hsl(0 0% 0%);\n --shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 2px 4px -1px hsl(0 0% 0% / 0.02);\n --shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 4px 6px -1px hsl(0 0% 0% / 0.02);\n --shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 8px 10px -1px hsl(0 0% 0% / 0.02);\n --shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);\n --tracking-normal: 0em;\n --spacing: 0.25rem;\n}\n\n.dark {\n --background: oklch(0 0 0);\n --foreground: oklch(1 0 0);\n --card: oklch(0.1400 0 0);\n --card-foreground: oklch(1 0 0);\n --popover: oklch(0.1800 0 0);\n --popover-foreground: oklch(1 0 0);\n --primary: oklch(1 0 0);\n --primary-foreground: oklch(0 0 0);\n --secondary: oklch(0.2500 0 0);\n --secondary-foreground: oklch(1 0 0);\n --muted: oklch(0.2300 0 0);\n --muted-foreground: oklch(0.7200 0 0);\n --accent: oklch(0.3200 0 0);\n --accent-foreground: oklch(1 0 0);\n --destructive: oklch(0.6900 0.2000 23.9100);\n --destructive-foreground: oklch(0 0 0);\n --border: oklch(0.2600 0 0);\n --input: oklch(0.3200 0 0);\n --ring: oklch(0.7200 0 0);\n --chart-1: oklch(0.8100 0.1700 75.3500);\n --chart-2: oklch(0.5800 0.2100 260.8400);\n --chart-3: oklch(0.5600 0 0);\n --chart-4: oklch(0.4400 0 0);\n --chart-5: oklch(0.9200 0 0);\n --sidebar: oklch(0.1800 0 0);\n --sidebar-foreground: oklch(1 0 0);\n --sidebar-primary: oklch(1 0 0);\n --sidebar-primary-foreground: oklch(0 0 0);\n --sidebar-accent: oklch(0.3200 0 0);\n --sidebar-accent-foreground: oklch(1 0 0);\n --sidebar-border: oklch(0.3200 0 0);\n --sidebar-ring: oklch(0.7200 0 0);\n --font-sans: Geist, sans-serif;\n --font-serif: Georgia, serif;\n --font-mono: Geist Mono, monospace;\n --radius: 0.4rem;\n --shadow-x: 0px;\n --shadow-y: 1px;\n --shadow-blur: 3px;\n --shadow-spread: 0px;\n --shadow-opacity: 0.02;\n --shadow-color: hsl(0 0% 0%);\n --shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.01);\n --shadow-sm: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 1px 2px -1px hsl(0 0% 0% / 0.02);\n --shadow-md: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 2px 4px -1px hsl(0 0% 0% / 0.02);\n --shadow-lg: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 4px 6px -1px hsl(0 0% 0% / 0.02);\n --shadow-xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.02), 0px 8px 10px -1px hsl(0 0% 0% / 0.02);\n --shadow-2xl: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);\n}\n\n.cms-root {\n --font-sans: var(--font-geist-sans, sans-serif);\n --font-mono: var(--font-geist-mono, monospace);\n font-family: var(--font-sans);\n}\n\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-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\n --font-sans: var(--font-sans);\n --font-mono: var(--font-mono);\n --font-serif: var(--font-serif);\n\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 --shadow-2xs: var(--shadow-2xs);\n --shadow-xs: var(--shadow-xs);\n --shadow-sm: var(--shadow-sm);\n --shadow: var(--shadow);\n --shadow-md: var(--shadow-md);\n --shadow-lg: var(--shadow-lg);\n --shadow-xl: var(--shadow-xl);\n --shadow-2xl: var(--shadow-2xl);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground antialiased;\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 type ColumnDef,\n type ColumnFiltersState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type SortingState,\n type Table as TanstackTable,\n useReactTable,\n type VisibilityState\n} from '@tanstack/react-table'\nimport { parseAsInteger, useQueryState } from 'nuqs'\nimport * as React from 'react'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow\n} from '@cms/components/ui/table'\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 (updater: Record<string, boolean> | ((old: Record<string, boolean>) => Record<string, boolean>)) => {\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)]))\n .filter(Boolean)\n onSelectedIdsChange(newIds)\n },\n [data, rowSelection, onSelectedIdsChange, getId]\n )\n\n const handlePaginationChange = React.useCallback(\n (updater: { pageIndex: number; pageSize: number } | ((old: { pageIndex: number; pageSize: number }) => { pageIndex: number; pageSize: number })) => {\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 type { Table } from '@tanstack/react-table'\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'\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 { ArrowUpDown, Save, Search } from 'lucide-react'\nimport * as React from 'react'\nimport { useFormStatus } from 'react-dom'\nimport { Button } from '@cms/components/ui/button'\nimport { Input } from '@cms/components/ui/input'\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\n variant=\"default\"\n size=\"sm\"\n onClick={onSave}\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={onCancel}\n disabled={isSaving}\n >\n Cancel\n </Button>\n {hasChanges && (\n <span className=\"text-sm text-muted-foreground\">Unsaved changes</span>\n )}\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 { CmsSearch } from '@cms/components/layout/cms-search'\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 bg-sidebar\">\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 <CmsSearch />\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-providers.tsx\n * CMS-scoped providers: QueryClient, CmsThemeProvider, Toaster, NuqsAdapter\n */\nexport function cmsProvidersTemplate(): string {\n return `'use client'\n\nimport { useState } from 'react'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport { CmsThemeProvider } from '@cms/hooks/use-cms-theme'\nimport { Toaster } from '@cms/components/ui/sonner'\nimport { NuqsAdapter } from 'nuqs/adapters/next/app'\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! rounded-full\"\n size=\"sm\"\n >\n <Search className=\"shrink-0 size-3.5 -ml-0.5 text-muted-foreground\" strokeWidth={2} />\n <span className=\"w-full font-medium text-xs pt-px text-muted-foreground leading-0\">\n Find...\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\" strokeWidth={1.5} />\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 navigation\n */\nexport function cmsSidebarTemplate(): string {\n return `import { getSetting } from '@/cms/lib/actions/settings'\nimport { getSession } from '@cms/auth/middleware'\nimport { Avatar, AvatarFallback, AvatarImage } from '@cms/components/ui/avatar'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '@cms/components/ui/collapsible'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarRail,\n SidebarTrigger,\n} from '@cms/components/ui/sidebar'\nimport { cms } from '@cms/data/cms'\nimport { type CmsNavigationItem, cmsNavigation } from '@cms/data/navigation'\nimport { ChevronRight, Settings, Users } from 'lucide-react'\nimport Link from 'next/link'\n\nfunction NavItem({ item }: { item: CmsNavigationItem }) {\n if (item.children && item.children.length > 0) {\n return (\n <Collapsible asChild defaultOpen className=\"group/collapsible border-y border-border py-2 px-2\">\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton>\n {item.icon && <item.icon className=\"size-3.5!\" />}\n <span>{item.label}</span>\n <ChevronRight className=\"ml-auto size-3.5! transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => (\n <SidebarMenuSubItem key={child.href}>\n <SidebarMenuSubButton asChild>\n <Link href={child.href}>\n {child.icon && <child.icon className=\"size-3.5!\" />}\n <span>{child.label}</span>\n </Link>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n return (\n <SidebarMenuItem className=\"px-2\">\n <SidebarMenuButton asChild>\n <Link href={item.href}>\n {item.icon && <item.icon className=\"size-3.5!\" />}\n <span>{item.label}</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n )\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\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-6.5\">\n <AvatarImage src={'/favicon.ico'} />\n <AvatarFallback className=\"text-sm font-semibold\">\n {settings?.siteName?.charAt(0) ?? cms.name?.charAt(0)}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex items-center gap-1 w-full group-data-[collapsible=icon]:hidden\">\n <span className=\"text-sm font-semibold line-clamp-1\">{settings?.siteName ?? cms.name}</span>\n </div>\n </Link>\n <SidebarTrigger className=\"hidden md:flex\" />\n </div>\n </SidebarHeader>\n <SidebarContent className=\"gap-2\">\n <SidebarMenu className=\"py-2 gap-2\">\n {cmsNavigation.map((item) => (\n <NavItem key={item.href + item.label} item={item} />\n ))}\n </SidebarMenu>\n <SidebarMenu className=\"py-2 mt-auto border-t border-border px-2\">\n <SidebarMenuItem>\n <SidebarMenuButton asChild>\n <Link href=\"/cms/users\">\n <Users className=\"size-3.5!\" />\n <span>Users</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n <SidebarMenuItem>\n <SidebarMenuButton asChild>\n <Link href=\"/cms/settings\">\n <Settings className=\"size-3.5!\" />\n <span>Settings</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\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 <SidebarRail />\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 description: string\n children?: React.ReactNode\n}\n\nexport function PageHeader({ title, description, children }: PageHeaderProps) {\n return (\n <div className=\"flex items-center justify-between w-full\">\n <div className=\"flex flex-col\">\n <h2 className=\"text-base font-semibold tracking-tight\">{title}</h2>\n <p className=\"text-muted-foreground text-sm\">{description}</p>\n </div>\n {children && <div className=\"flex items-center gap-2\">{children}</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({ value, trueLabel = 'Yes', falseLabel = 'No' }: {\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 { House } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nexport interface CmsNavigationItem {\n label: string\n href: string\n icon?: LucideIcon\n children?: CmsNavigationItem[]\n}\n\nexport const cmsNavigation: CmsNavigationItem[] = [\n {\n label: 'Dashboard',\n href: '/cms',\n icon: House\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 (\n <CmsThemeContext.Provider value={value}>\n {children}\n </CmsThemeContext.Provider>\n )\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) =>\n f.type.startsWith('image/')\n )\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-upload.ts\n * File upload hook with validation and progress tracking\n */\nexport function useUploadHookTemplate(): string {\n return `'use client'\n\nimport type {\n UploadFileResult,\n UploadProgress\n} from '@cms/types'\nimport {\n type FileValidationConfig,\n validateFiles\n} 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 { eq } from 'drizzle-orm'\nimport db from '@cms/db'\nimport { formSettings } from '@cms/db/schema'\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(\n formName: string\n): 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:\n 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:\n 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 db from '@cms/db'\nimport { user, account } from '@cms/db/schema'\nimport { eq } from 'drizzle-orm'\nimport { auth } from '@cms/auth'\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(\n userId: string,\n role: string,\n): Promise<UpdateUserRoleResult> {\n try {\n await db\n .update(user)\n .set({ role, updatedAt: new Date() })\n .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 dollarmath from 'markdown-it-dollarmath'\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, typescript, jsx, tsx, python, rust, go,\n json, yaml, css, sql, shellscript, 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// --- 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(dollarmath, {\n allow_space: false,\n allow_digits: false,\n double_inline: true,\n allow_labels: true,\n allow_blank_lines: true,\n renderer(content: string, { displayMode }: { displayMode: boolean }) {\n return renderToString(content, {\n displayMode,\n throwOnError: false,\n strict: 'ignore'\n })\n },\n labelNormalizer(label: string) {\n return label.replace(/[\\\\s]+/g, '-')\n },\n labelRenderer(label: string) {\n return \\`<a href=\"#\\${label}\" class=\"mathlabel\" title=\"Permalink to this equation\">¶</a>\\`\n }\n })\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 (\n typeof value === 'string' &&\n Object.values(UserRole).includes(value as UserRole)\n )\n}\n\n/** Check if user has one of the allowed roles */\nexport function hasRequiredRole(\n userRole: UserRole,\n allowedRoles: UserRole[]\n): 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 {\n maxSizeInBytes = DEFAULT_MAX_SIZE,\n allowedTypes,\n maxFiles = DEFAULT_MAX_FILES\n } = 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\n // 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 =\n 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","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/drizzle.config.ts\n * Drizzle Kit configuration for CMS database\n */\nexport function drizzleConfigTemplate(): string {\n return `import { loadEnvConfig } from '@next/env'\nimport { defineConfig } from 'drizzle-kit'\n\nloadEnvConfig(process.cwd())\n\nexport default defineConfig({\n out: './cms/db/migrations',\n schema: './cms/db/schema.ts',\n dialect: 'postgresql',\n dbCredentials: {\n url: process.env.BETTERSTART_DATABASE_URL!,\n },\n})\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 */\nconst 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 '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 'markdown-it-dollarmath',\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 'usehooks-ts',\n 'vaul'\n]\n\n/** Email deps — only when email feature is enabled */\nconst EMAIL_DEPS = ['resend', '@react-email/components']\n\n/** Dev deps — always installed */\nconst DEV_DEPS = ['drizzle-kit', 'tsx', 'sass', '@types/katex', '@types/markdown-it']\n\n/** Biome dev dep — only when no existing linter */\nconst 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]\n if (includeEmail) coreDeps.push(...EMAIL_DEPS)\n\n const devDeps = [...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'\n\nimport type { EnvSection } from '../../utils/env.js'\nimport { appendEnvVars } from '../../utils/env.js'\n\nfunction getCoreEnvSections(databaseUrl?: string): 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:3000' },\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\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 sections = getCoreEnvSections(options.databaseUrl)\n if (options.includeEmail) {\n sections.push(getEmailEnvSection())\n }\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 { CmsHeader } from '@cms/components/layout/cms-header'\nimport { CmsSidebar } from '@cms/components/layout/cms-sidebar'\nimport { requireRole } from '@cms/auth/middleware'\nimport { UserRole } from '@cms/types/auth'\nimport { SidebarInset, SidebarProvider } from '@cms/components/ui/sidebar'\n\nexport default async function CmsAuthLayout({\n children\n}: {\n children: React.ReactNode\n}) {\n await requireRole([UserRole.ADMIN, UserRole.EDITOR])\n\n return (\n <SidebarProvider>\n <CmsSidebar />\n <SidebarInset>\n <CmsHeader />\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'\n\nexport default function CmsLayout({ children }: { children: React.ReactNode }) {\n return (\n <CmsProviders>\n <div className=\"cms-root min-h-screen\">{children}</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 { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@cms/components/ui/card'\nimport { Badge } from '@cms/components/ui/badge'\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 <div className=\"flex items-center justify-between bg-card px-6 py-4 border-b\">\n <PageHeader\n title=\"Dashboard\"\n description=\"Welcome to your CMS admin panel\"\n />\n </div>\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\">\n Sign in to access the admin panel\n </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 { 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\">\n {error}\n </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 ? '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 { 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 { createUser } from '@cms/actions/users'\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 { 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 { updateUserRole } from '@cms/actions/users'\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({\n userId,\n currentRole,\n userName,\n children\n}: 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>\n Change the role for {userName}\n </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\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={isPending}\n >\n Cancel\n </Button>\n <Button\n onClick={handleSave}\n disabled={isPending || role === currentRole}\n >\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 React from 'react'\nimport {\n Avatar,\n AvatarFallback\n} from '@cms/components/ui/avatar'\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 { 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 type { ColumnDef } from '@tanstack/react-table'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { ArrowUpDown, Edit, MoreHorizontal, Trash } from 'lucide-react'\nimport { toast } from 'sonner'\nimport { deleteUser } from '@cms/actions/users'\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\n className=\"text-destructive\"\n onSelect={(e) => e.preventDefault()}\n >\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{' '}\n <strong>{userName}</strong> 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\n onClick={() => navigator.clipboard.writeText(row.original.id)}\n >\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\n title=\"Users\"\n description=\"Manage all CMS users\"\n >\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 {\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'\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 { authClient } from '@cms/auth/client'\nimport type { UserData } from '@cms/types/auth'\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-generator.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 }\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'\n\nasync function main() {\n console.log('\\\\n Creating admin user...')\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 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 spinner = clack.spinner()\n spinner.start('Creating admin user...')\n\n // Run the seed script with project-local tsx (avoids npx cache issues)\n try {\n const { execFileSync } = await import('node:child_process')\n const tsxBin = path.join(cwd, 'node_modules', '.bin', 'tsx')\n execFileSync(tsxBin, [seedPath], {\n cwd,\n stdio: 'pipe',\n env: {\n ...process.env,\n SEED_EMAIL: email,\n SEED_PASSWORD: password,\n SEED_NAME: name || 'Admin'\n }\n })\n spinner.stop('Admin user created')\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'\n\n// ============================================================================\n// String Helpers\n// ============================================================================\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join('')\n}\nfunction toCamelCase(str: string): string {\n const p = toPascalCase(str)\n return p.charAt(0).toLowerCase() + p.slice(1)\n}\nfunction 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 }\n if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1)\n return str\n}\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\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 // Find the nav item 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"],"mappings":"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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;AA2MT;;;AC7MO,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmLT;;;ACpLO,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;AAAA;AAAA;AAAA;AA2FT;;;AC5FO,SAAS,2BAAmC;AACjD,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;AA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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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwLT;;;ACzLO,SAAS,uBAA+B;AAC7C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcT;;;ACfO,SAAS,6BAAqC;AACnD,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;AAmIT;;;ACpIO,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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwJT;;;AC3JO,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;AAkIT;;;ACnIO,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;AA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,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;A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","names":["Command","path","fs","path","path","fs","content","parsed","path","fs","path","fs","path","toPascalCase","fs","path","toPascalCase","p","getAllFields","hasDynamicFields","fs","path","toKebabCase","toPascalCase","toCamelCase","p","toKebabCase","getAllFields","hasDynamicFields","path","fs","fs","path","toPascalCase","toCamelCase","p","singularize","quotePropertyName","path","fs","fs","path","toPascalCase","toCamelCase","p","singularize","pluralize","path","fs","fns","fs","path","toPascalCase","singularize","pluralize","generateColumnDef","generateColumns","path","fs","fs","path","toPascalCase","singularize","toKebabCase","fs","path","toPascalCase","toCamelCase","p","singularize","path","fs","fs","path","toPascalCase","toCamelCase","p","singularize","toKebabCase","fs","path","toPascalCase","singularize","pluralize","quotePropertyName","base","generateFieldJSX","path","fs","fs","path","toPascalCase","singularize","pluralize","path","fs","fs","path","parseNavigationFile","extractTopLevelArray","parseItemsBlock","parseSingleItem","generateNavigationCode","appendItem","fs","path","toPascalCase","pluralize","toKebabCase","generatePage","fs","path","toPascalCase","singularize","pluralize","toKebabCase","singularizeLabel","generatePageContent","fs","path","toPascalCase","singularize","fs","path","toPascalCase","toCamelCase","p","singularize","pluralize","toKebabCase","generateTable","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","spinner","execFileSync","Command","pc","path","execFileSync","fs","password","spawn","fs","path","Command","toPascalCase","toCamelCase","p","singularize","toKebabCase","findTableEnd","fs","Command","path","Command"]}
|