create-efc-app 0.9.3 → 0.10.0
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/index.js +316 -109
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/scaffold.ts","../src/registry.ts"],"sourcesContent":["import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport { scaffold, type ScaffoldOptions } from './scaffold.js';\nimport {\n ITEMS,\n envFromAnswers,\n itemPrompts,\n normalizeAnswer,\n promptApplies,\n promptDefault,\n registryOptions,\n setEnvValues,\n withDependencies,\n writeManifest,\n type PromptAnswers,\n} from './registry.js';\n\nfunction cancel(msg = 'Cancelled'): never {\n p.cancel(msg);\n process.exit(0);\n}\n\nasync function main(): Promise<void> {\n console.log();\n p.intro(pc.bgCyan(pc.black(' create-efc-app ')));\n\n const projectName = await p.text({\n message: 'Project name:',\n placeholder: 'my-api',\n defaultValue: 'my-api',\n validate: (v) => (!v.trim() ? 'Project name is required' : undefined),\n });\n if (p.isCancel(projectName)) cancel();\n\n const language = await p.select({\n message: 'Language:',\n options: [\n { value: 'typescript', label: 'TypeScript', hint: 'recommended' },\n { value: 'javascript', label: 'JavaScript' },\n ],\n });\n if (p.isCancel(language)) cancel();\n\n const database = await p.select({\n message: 'Database:',\n options: [\n { value: 'mongodb', label: 'MongoDB', hint: 'Mongoose' },\n { value: 'postgresql', label: 'PostgreSQL', hint: 'Drizzle ORM' },\n ],\n });\n if (p.isCancel(database)) cancel();\n\n let modelApi: ScaffoldOptions['modelApi'];\n if (database === 'postgresql') {\n const api = await p.select({\n message: 'Models:',\n options: [\n {\n value: 'defineTable',\n label: 'defineTable',\n hint: 'PostgreSQL-native — foreign keys, relations, include, Prisma-style queries',\n },\n { value: 'defineModel', label: 'defineModel', hint: 'portable — the same API on MongoDB' },\n ],\n });\n if (p.isCancel(api)) cancel();\n modelApi = api as ScaffoldOptions['modelApi'];\n }\n\n // pg-boss keeps jobs in the app's own PostgreSQL; BullMQ needs Redis.\n const taskBackend = await p.select({\n message: 'Task queue backend:',\n options:\n database === 'postgresql'\n ? [\n { value: 'pg-boss', label: 'pg-boss', hint: 'uses your PostgreSQL — no Redis' },\n { value: 'bullmq', label: 'BullMQ', hint: 'Redis' },\n ]\n : [{ value: 'bullmq', label: 'BullMQ', hint: 'Redis' }],\n });\n if (p.isCancel(taskBackend)) cancel();\n\n const cluster = await p.confirm({\n message: 'Multi-core clustering? (one worker per CPU in production)',\n initialValue: true,\n });\n if (p.isCancel(cluster)) cancel();\n\n // The base app is the server, src/api, src/tasks and the database. Features are registry\n // items — the same ones `efc add` installs later.\n const groupLabel: Record<string, string> = {\n auth: 'Auth',\n user: 'User portal',\n admin: 'Admin portal',\n integrations: 'Integrations',\n };\n const groups: Record<string, { value: string; label: string; hint: string }[]> = {};\n for (const item of ITEMS) {\n (groups[groupLabel[item.group]!] ??= []).push({\n value: item.name,\n label: item.title,\n hint: item.description,\n });\n }\n const picked = await p.groupMultiselect({\n message: `Add features now? ${pc.dim('(space to toggle, enter to confirm — or add any later with `efc add <item>`)')}`,\n options: groups,\n required: false,\n });\n if (p.isCancel(picked)) cancel();\n const items = withDependencies(picked as string[]);\n\n let authStrategy: ScaffoldOptions['authStrategy'] = 'http-only';\n if (items.includes('auth')) {\n const strategy = await p.select({\n message: 'Authentication strategy:',\n options: [\n { value: 'http-only', label: 'http-only', hint: 'secure cookie — recommended for SSR' },\n { value: 'localStorage', label: 'localStorage', hint: 'bearer token — for SPAs' },\n ],\n });\n if (p.isCancel(strategy)) cancel();\n authStrategy = strategy as ScaffoldOptions['authStrategy'];\n }\n\n // Each feature's own questions (SMTP for the email client, OAuth credentials…) — the same\n // ones `efc add` asks. Answers named like env vars go into .env.\n const answers: PromptAnswers = {};\n const prompts = itemPrompts(items);\n for (const q of prompts) {\n if (!promptApplies(q, answers)) continue;\n if (q.note) p.note(q.note);\n if (q.type === 'select') {\n const choice = await p.select({\n message: q.message,\n options: (q.options ?? []).map((o) => ({\n value: o.value,\n label: o.label,\n ...(o.hint !== undefined && { hint: o.hint }),\n })),\n });\n if (p.isCancel(choice)) cancel();\n answers[q.name] = choice as string;\n continue;\n }\n const def = promptDefault(q, answers);\n const check = (v: string) => {\n const r = normalizeAnswer(q, v.trim() === '' ? (def ?? '') : v);\n return 'error' in r ? r.error : undefined;\n };\n const raw =\n q.type === 'password'\n ? await p.password({ message: q.message, validate: check })\n : await p.text({\n message: q.message,\n ...(q.placeholder !== undefined && { placeholder: q.placeholder }),\n ...(def !== undefined && { placeholder: def, defaultValue: def }),\n validate: check,\n });\n if (p.isCancel(raw)) cancel();\n const r = normalizeAnswer(q, (raw as string).trim() === '' ? (def ?? '') : (raw as string));\n answers[q.name] = 'value' in r ? r.value : '';\n }\n const env = envFromAnswers(prompts, answers);\n\n const opts = registryOptions(\n {\n language: language as ScaffoldOptions['language'],\n database: database as ScaffoldOptions['database'],\n modelApi: modelApi ?? 'defineModel',\n },\n items,\n {\n projectName: projectName as string,\n authStrategy,\n cluster: cluster as boolean,\n taskBackend: taskBackend as 'bullmq' | 'pg-boss',\n ...(answers['provider'] === 'custom' && { smtpProvider: 'custom' as const }),\n },\n );\n\n const spinner = p.spinner();\n spinner.start('Scaffolding project…');\n\n try {\n await scaffold(opts);\n if (Object.keys(env).length) {\n await setEnvValues(path.resolve(process.cwd(), opts.projectName, '.env'), env);\n }\n await writeManifest(path.resolve(process.cwd(), opts.projectName), opts, items);\n spinner.stop('Project created');\n } catch (err) {\n spinner.stop('Failed to scaffold project');\n console.error(err);\n process.exit(1);\n }\n\n spinner.start('Installing dependencies…');\n await npmInstall(projectName as string);\n spinner.stop('Dependencies installed');\n\n spinner.start('Installing efc CLI globally…');\n await npmInstallGlobal().catch(() => {\n /* non-fatal */\n });\n spinner.stop('efc CLI ready');\n\n const secrets = Object.keys(env).filter((k) => /PASS|SECRET|PRIVATE_KEY/.test(k));\n if (secrets.length) {\n p.note(\n `${secrets.join(', ')} ${secrets.length > 1 ? 'were' : 'was'} written to ${projectName as string}/.env — that file is gitignored, never commit it.\\n` +\n 'Rotate any of them immediately if it is ever exposed.',\n 'Credentials',\n );\n }\n\n // Tables (PostgreSQL) and collections/indexes (MongoDB) are created on first use, so\n // there's nothing to set up before the first run; migrations are there when wanted.\n p.outro(\n pc.green(`\\nYour project is ready!\\n\\n`) +\n pc.dim(` cd ${projectName as string}\\n`) +\n pc.dim(` efc start dev\\n`) +\n pc.dim(`\\n (or: npm run dev)\\n`) +\n pc.dim(`\\n Add features any time: efc list · efc add <item>\\n`),\n );\n}\n\nfunction npmInstall(projectDir: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['install'], { cwd: projectDir, stdio: 'ignore' });\n child.on('exit', (code) => (code === 0 ? resolve() : reject(new Error('npm install failed'))));\n });\n}\n\nfunction npmInstallGlobal(): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['install', '-g', 'express-file-cluster'], { stdio: 'ignore' });\n child.on('exit', (code) =>\n code === 0 ? resolve() : reject(new Error('global install failed')),\n );\n });\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n","import fs from 'fs-extra';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\n\nexport interface AdminFeatures {\n userManagement: boolean;\n adminManagement: boolean;\n analytics: boolean;\n contentManagement: boolean;\n billingManagement: boolean;\n supportManagement: boolean;\n notificationsAndLogs: boolean;\n systemSettings: boolean;\n}\n\nexport interface UserFeatures {\n profileViewing: boolean;\n forgotPassword: boolean;\n accountSecurity: boolean;\n emailVerification: boolean;\n accountSettings: boolean;\n notifications: boolean;\n filesAndMedia: boolean;\n apiAndBilling: boolean;\n support: boolean;\n}\n\nexport const NO_ADMIN_FEATURES: AdminFeatures = {\n userManagement: false,\n adminManagement: false,\n analytics: false,\n contentManagement: false,\n billingManagement: false,\n supportManagement: false,\n notificationsAndLogs: false,\n systemSettings: false,\n};\n\nexport const NO_USER_FEATURES: UserFeatures = {\n profileViewing: false,\n forgotPassword: false,\n accountSecurity: false,\n emailVerification: false,\n accountSettings: false,\n notifications: false,\n filesAndMedia: false,\n apiAndBilling: false,\n support: false,\n};\n\nexport interface ScaffoldOptions {\n projectName: string;\n language: 'typescript' | 'javascript';\n database: 'mongodb' | 'postgresql';\n authStrategy: 'http-only' | 'localStorage';\n cluster: boolean;\n tasks: boolean;\n taskBackend?: 'bullmq' | 'pg-boss';\n routeDocs: boolean;\n userPortal: boolean;\n adminPortal: boolean;\n adminFeatures: AdminFeatures;\n userFeatures: UserFeatures;\n rbac: boolean;\n mailer: boolean;\n smtpProvider?: 'gmail' | 'custom';\n smtpHost?: string;\n smtpPort?: string;\n smtpUser?: string;\n smtpPass?: string;\n /**\n * Model API on PostgreSQL: `defineTable` (default — foreign keys, relations, Prisma-style\n * queries) or the portable `defineModel` (same API as on MongoDB). MongoDB always uses\n * `defineModel`.\n */\n modelApi?: 'defineTable' | 'defineModel';\n /**\n * Registry mode (`efc add`): every file renders the same way whatever else is generated,\n * so a feature's files can be added to an app on their own. Login and the password flows\n * always handle both User and Admin (and both models come with auth), routes always send\n * mail through the SendEmail task, and models declare no back-relations.\n */\n registry?: boolean;\n /** OAuth sign-in providers (needs the User model — auth). */\n oauth?: { google?: boolean; apple?: boolean };\n}\n\n/** Whether any OAuth sign-in provider is generated. */\nfunction usesOAuth(opts: ScaffoldOptions): boolean {\n return !!(opts.oauth?.google || opts.oauth?.apple);\n}\n\n/** Which principals the auth routes handle. */\nfunction principals(opts: ScaffoldOptions): { user: boolean; admin: boolean } {\n return {\n user: !!opts.registry || opts.userPortal,\n admin: !!opts.registry || opts.adminPortal,\n };\n}\n\n/** Whether routes email their tokens through the SendEmail task (vs. a TODO). */\nfunction sendsMail(opts: ScaffoldOptions): boolean {\n return !!opts.registry || opts.mailer;\n}\n\n/** Whether the generated models are `defineTable` (PostgreSQL-native) ones. */\nexport function usesTables(opts: ScaffoldOptions): boolean {\n return opts.database === 'postgresql' && opts.modelApi !== 'defineModel';\n}\n\n/**\n * Code for model calls in generated routes, in the vocabulary of the chosen API:\n * `defineModel` (`User.findOne({ email })`) or `defineTable` (`User.findFirst({ where: … })`).\n * Arguments are source text.\n */\nfunction orm(opts: ScaffoldOptions) {\n const t = usesTables(opts);\n const where = (filter: string) =>\n filter.replace(/\\s/g, '') === '{}' ? '' : `{ where: ${filter} }`;\n const byId = (id: string) => (id === 'id' ? '{ id }' : `{ id: ${id} }`);\n return {\n findOne: (m: string, filter: string) =>\n t ? `${m}.findFirst({ where: ${filter} })` : `${m}.findOne(${filter})`,\n findById: (m: string, id: string) =>\n t ? `${m}.findUnique({ where: ${byId(id)} })` : `${m}.findById(${id})`,\n find: (m: string, filter: string) =>\n t ? `${m}.findMany(${where(filter)})` : `${m}.find(${filter})`,\n count: (m: string, filter: string) =>\n t ? `${m}.count(${where(filter)})` : `${m}.count(${filter})`,\n create: (m: string, data: string) =>\n t ? `${m}.create({ data: ${data} })` : `${m}.create(${data})`,\n update: (m: string, id: string, data: string) =>\n t ? `${m}.update({ where: ${byId(id)}, data: ${data} })` : `${m}.update(${id}, ${data})`,\n delete: (m: string, id: string) =>\n t ? `${m}.delete({ where: ${byId(id)} })` : `${m}.delete(${id})`,\n };\n}\n\n/** The models `scaffold()` generates for these options. */\nexport function generatedModels(opts: ScaffoldOptions): Set<string> {\n const uf = opts.userFeatures;\n const af = opts.adminFeatures;\n const user = opts.userPortal;\n const admin = opts.adminPortal;\n const m = new Set<string>();\n // Admin \"user management\" operates on the User collection even when there's\n // no separate self-service user portal, so the model must exist for it too.\n if (user || (admin && af.userManagement)) m.add('User');\n if (admin) m.add('Admin');\n // Registry mode: auth always handles both principals, so it always brings both models.\n if (opts.registry && (user || admin)) m.add('User').add('Admin');\n if (user && uf.accountSecurity) m.add('Session');\n if ((user && uf.notifications) || (admin && af.notificationsAndLogs)) m.add('Notification');\n if (user && uf.filesAndMedia) m.add('File');\n if ((user && uf.support) || (admin && af.supportManagement)) m.add('SupportTicket');\n if (admin && af.notificationsAndLogs) m.add('AuditLog');\n if (user && uf.apiAndBilling) m.add('Subscription').add('Invoice').add('ApiKey');\n if (usesOAuth(opts)) m.add('OAuthAccount');\n if (admin && af.billingManagement) m.add('Plan').add('Coupon');\n if (opts.rbac && admin && af.adminManagement) m.add('Role');\n if (admin && af.contentManagement) m.add('FAQ').add('Blog').add('Category');\n // Registry mode: a reference is always a foreign key, so its target comes along.\n if (opts.registry && m.has('Subscription')) m.add('Plan');\n return m;\n}\n\n/** `import { defineTable }` / `import { defineModel }` and the function's name. */\nfunction modelApi(opts: ScaffoldOptions): { name: string; import: string } {\n const name = usesTables(opts) ? 'defineTable' : 'defineModel';\n return { name, import: `import { ${name} } from 'express-file-cluster';` };\n}\n\n/**\n * A reference field: on defineTable, a real foreign key when its target model is generated;\n * otherwise the plain id string `legacy` describes (defineModel, or no such model).\n */\nfunction refField(\n opts: ScaffoldOptions,\n r: {\n field: string;\n target: string;\n legacy: string;\n required?: boolean;\n onDelete: 'cascade' | 'setNull' | 'restrict';\n },\n): string {\n if (!usesTables(opts) || !generatedModels(opts).has(r.target)) return r.legacy;\n const opts2 = `${r.required ? ', required: true' : ''}${r.onDelete === 'restrict' ? '' : `, onDelete: '${r.onDelete}'`}`;\n return ` ${(r.field + ':').padEnd(13)}{ type: 'uuid', ref: '${r.target}'${opts2} },`;\n}\n\n/** The `relations` option (defineTable): back-relations whose models are generated. */\nfunction relationsOption(\n opts: ScaffoldOptions,\n rels: { name: string; kind: 'hasMany' | 'hasOne'; target: string; foreignKey: string }[],\n): string {\n if (!usesTables(opts) || opts.registry) return '';\n const models = generatedModels(opts);\n const live = rels.filter((r) => models.has(r.target));\n if (live.length === 0) return '';\n const lines = live.map(\n (r) => ` ${r.name}: { ${r.kind}: '${r.target}', foreignKey: '${r.foreignKey}' },`,\n );\n return `, {\\n relations: {\\n${lines.join('\\n')}\\n },\\n}`;\n}\n\nexport async function scaffold(opts: ScaffoldOptions): Promise<void> {\n const dest = path.resolve(process.cwd(), opts.projectName);\n await fs.ensureDir(dest);\n\n const uf = opts.userFeatures;\n const models = generatedModels(opts);\n\n await writePackageJson(dest, opts);\n await writeTsConfig(dest, opts);\n await writeEfcConfig(dest, opts);\n await writeEntryPoint(dest, opts);\n await writeGitignore(dest);\n await writeAgentsMd(dest, opts);\n await writeEnvFiles(dest, opts);\n await writeExampleRoute(dest, opts);\n if (models.has('User')) await writeUserModel(dest, opts);\n if (models.has('Admin')) await writeAdminModel(dest, opts);\n if (!opts.registry || opts.userPortal || opts.adminPortal) await writeAuthRoutes(dest, opts);\n if (opts.adminPortal) await writeAdminRoutes(dest, opts);\n if (opts.userPortal && uf.profileViewing) await writeUserRoutes(dest, opts);\n if (opts.tasks) await writeExampleTask(dest, opts);\n // Extended models — only generated when a feature that uses them is selected\n const extended: [string, (dest: string, opts: ScaffoldOptions) => Promise<void>][] = [\n ['Session', writeSessionModel],\n ['Notification', writeNotificationModel],\n ['File', writeFileModel],\n ['SupportTicket', writeSupportTicketModel],\n ['AuditLog', writeAuditLogModel],\n ['Subscription', writeSubscriptionModel],\n ['Plan', writePlanModel],\n ['Invoice', writeInvoiceModel],\n ['ApiKey', writeApiKeyModel],\n ['Role', writeRoleModel],\n ['FAQ', writeFAQModel],\n ['Blog', writeBlogModel],\n ['Category', writeCategoryModel],\n ['Coupon', writeCouponModel],\n ];\n for (const [name, write] of extended) if (models.has(name)) await write(dest, opts);\n if (models.has('OAuthAccount')) await writeOAuthAccountModel(dest, opts);\n if (usesOAuth(opts)) await writeOAuth(dest, opts);\n if (usesTables(opts)) await writeModelIndex(dest, opts);\n // Extended routes — gated by the same per-feature flags as their models\n if (opts.userPortal) await writeAuthExtendedRoutes(dest, opts);\n if (opts.userPortal) await writeUserExtendedRoutes(dest, opts);\n if (opts.userPortal && uf.apiAndBilling) await writeUserBillingRoutes(dest, opts);\n if (opts.userPortal && uf.support) await writeSupportRoutes(dest, opts);\n if (opts.adminPortal) await writeAdminExtendedRoutes(dest, opts);\n await writeInitMigration(dest, opts);\n}\n\nasync function writePackageJson(dest: string, opts: ScaffoldOptions): Promise<void> {\n const deps: Record<string, string> = {\n 'express-file-cluster': '^0.9.3',\n };\n if (opts.database === 'mongodb') deps['mongoose'] = '^9.7.2';\n if (opts.database === 'postgresql') {\n deps['pg'] = '^8.11.0';\n deps['drizzle-orm'] = '^0.45.0';\n }\n if (opts.tasks && opts.taskBackend === 'bullmq') deps['bullmq'] = '^5.0.0';\n if (opts.tasks && opts.taskBackend === 'pg-boss') deps['pg-boss'] = '^12.0.0';\n if (opts.mailer) deps['nodemailer'] = '^10.2.1';\n if (usesOAuth(opts)) deps['jose'] = '^6.2.3';\n\n const devDeps: Record<string, string> = {\n vitest: '^5.0.3',\n };\n if (opts.language === 'typescript') {\n // JavaScript projects need neither: `efc build prod` copies them, `efc start dev` uses node --watch.\n devDeps['tsup'] = '^8.2.0';\n devDeps['typescript'] = '^5.5.0';\n devDeps['@types/node'] = '^22.0.0';\n devDeps['@types/express'] = '^4.17.21';\n devDeps['tsx'] = '^4.0.0';\n if (opts.mailer) devDeps['@types/nodemailer'] = '^8.0.2';\n if (opts.database === 'postgresql') devDeps['@types/pg'] = '^8.11.0';\n }\n\n const pkg = {\n name: opts.projectName,\n version: '0.1.0',\n type: 'module',\n scripts: {\n dev: 'efc start dev',\n build: 'efc build prod',\n start: 'efc start prod',\n test: 'efc run tests',\n 'db:migrate': 'efc db migrate',\n 'db:rollback': 'efc db rollback',\n 'db:seed': 'efc db seed',\n 'db:studio': 'efc db studio',\n },\n dependencies: deps,\n devDependencies: devDeps,\n // tsup 8 still asks for esbuild 0.27, which has an open advisory; 0.28 builds the same.\n ...(opts.language === 'typescript' ? { overrides: { esbuild: '^0.28.1' } } : {}),\n };\n\n await fs.writeJson(path.join(dest, 'package.json'), pkg, { spaces: 2 });\n}\n\nasync function writeTsConfig(dest: string, opts: ScaffoldOptions): Promise<void> {\n if (opts.language !== 'typescript') return;\n const config = {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: './dist',\n },\n // No explicit rootDir: efc.config.ts lives at the project root, outside src/, and\n // src/index.ts imports it. `efc build prod` only uses this config for `tsc --noEmit`\n // typechecking — tsup writes the actual output (dist/src/**, dist/efc.config.js),\n // so leaving rootDir implicit here has no effect on the production build's output layout.\n include: ['src/**/*', 'efc.config.ts'],\n exclude: ['node_modules', 'dist'],\n };\n await fs.writeJson(path.join(dest, 'tsconfig.json'), config, { spaces: 2 });\n}\n\nasync function writeEfcConfig(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n // pg-boss stores jobs in the app's own Postgres (databaseUrl); BullMQ needs Redis.\n const tasks = !opts.tasks\n ? 'false'\n : opts.taskBackend === 'pg-boss'\n ? `{ backend: 'pg-boss', concurrency: 5 }`\n : `{ backend: 'bullmq', concurrency: 5, redisUrl: process.env.REDIS_URL }`;\n\n const ts = opts.language === 'typescript';\n // JavaScript gets a JSDoc type instead of TypeScript syntax, so editors still check it.\n const typeImport = ts ? \"import type { EFCConfig } from 'express-file-cluster';\\n\\n\" : '';\n const declaration = ts\n ? 'const config: EFCConfig = {'\n : \"/** @type {import('express-file-cluster').EFCConfig} */\\nconst config = {\";\n const content = `${typeImport}// The framework never reads process.env itself — every runtime value it needs is read\n// here, explicitly, and passed in. Edit .env to change values; edit this file to change\n// which env vars are wired up or add new ones.\nconst corsOrigins = process.env.CORS_ORIGINS\n ? process.env.CORS_ORIGINS.split(',').map((o) => o.trim()).filter(Boolean)\n : undefined;\n\n${declaration}\n port: process.env.PORT ? Number(process.env.PORT) : undefined,\n databaseUrl: process.env.DATABASE_URL,\n jwtSecret: process.env.JWT_SECRET,\n jwtExpiresIn: process.env.JWT_EXPIRES_IN,\n cookieDomain: process.env.COOKIE_DOMAIN,\n cors: corsOrigins ? { origin: corsOrigins } : true,\n authStrategy: '${opts.authStrategy}',\n tasks: ${tasks},\n // Cache + session-revocation store (logout really invalidates tokens). Redis when\n // REDIS_URL is set — shared by every instance; otherwise an in-memory store shared by\n // this machine's workers, emptied on restart.\n cache: process.env.REDIS_URL ? { backend: 'redis', url: process.env.REDIS_URL } : { backend: 'memory' },\n globalMiddlewares: [],\n};\n\nexport default config;\n`;\n await fs.outputFile(path.join(dest, `efc.config.${ext}`), content);\n}\n\nasync function writeEntryPoint(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n // Only emit `cluster: false` on opt-out — a literal `cluster: true` would override\n // ignite()'s NODE_ENV-aware default and cluster under `efc start dev` too.\n const clusterLine = opts.cluster ? '' : '\\n cluster: false,';\n const content = `import { ignite, gracefulShutdown } from 'express-file-cluster';\nimport config from '../efc.config.js';\n\n// Every runtime value (PORT, DATABASE_URL, JWT_SECRET, CORS_ORIGINS, ...) is wired from\n// .env in efc.config.${ext} and spread in below — ignite() itself never touches process.env\n// for these, so this object is the single source of truth for what's actually applied.\nignite({\n ...config,${clusterLine}\n}).then(gracefulShutdown).catch(console.error);\n`;\n await fs.outputFile(path.join(dest, 'src', `index.${ext}`), content);\n}\n\nasync function writeGitignore(dest: string): Promise<void> {\n await fs.outputFile(\n path.join(dest, '.gitignore'),\n 'node_modules/\\ndist/\\n.env\\n.env.local\\n*.log\\n',\n );\n}\n\n// Points AI coding agents at the docs bundled with the installed framework version, so\n// they read the real API instead of guessing it.\nasync function writeAgentsMd(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const D = 'node_modules/express-file-cluster/dist/docs';\n const engine = opts.database === 'postgresql' ? 'PostgreSQL' : 'MongoDB';\n const content = `# AGENTS.md\n\nThis is an **express-file-cluster (EFC)** app (${opts.language === 'typescript' ? 'TypeScript' : 'JavaScript'}, ${engine}).\nEFC's API is probably not in your training data — **read its docs before writing code**, and\ndon't use any EFC import, option or method you can't find in them.\n\n## Read the docs first\n\nThe docs for the exact installed version ship inside the package, under \\`${D}/\\`:\n\n1. \\`${D}/skills/api-surface.md\\` — every public export and signature\n2. \\`${D}/skills/what-not-to-invent.md\\` — things that do NOT exist\n3. \\`${D}/index.md\\`, then the page for your task:\n - routes & URL params — \\`core-concepts/file-based-routing.md\\`, \\`skills/routing-rules.md\\`\n - request validation — \\`guides/validation.md\\`\n - models & queries — \\`guides/database.md\\`, \\`api-reference/db.md\\`${opts.database === 'postgresql' ? ', `api-reference/table.md` (PostgreSQL-native `defineTable`)' : ''}\n - migrations — \\`guides/migrations.md\\`\n - auth & roles — \\`guides/authentication.md\\`, \\`guides/rbac.md\\`\n - background tasks — \\`core-concepts/background-tasks.md\\`\n - config & boot — \\`api-reference/ignite.md\\`\n\nSearch them: \\`grep -rn \"<term>\" ${D}\\`\n\nOptional — the same docs over MCP, with search and scaffolding tools:\n\\`claude mcp add efc -- npx -y express-file-cluster-mcp\\`\n(other clients: command \\`npx\\`, args \\`[\"-y\", \"express-file-cluster-mcp\"]\\`).\n\n## Project conventions\n\n- \\`src/api/**\\` — every file is a route (\\`users/[id].${ext}\\` → \\`/v1/api/users/:id\\`); export\n uppercase \\`GET\\`/\\`POST\\`/… handlers.\n- \\`src/tasks/*.${ext}\\` — background tasks; the file name is the task name (not recursive).\n${\n usesTables(opts)\n ? `- \\`src/model/*.${ext}\\` — \\`defineTable\\` models (PostgreSQL-native, Prisma-style queries:\n \\`findMany({ where, include })\\`, \\`create({ data })\\`, \\`update({ where, data })\\`). A \\`ref\\` is a\n foreign key; ${opts.registry ? \"add back-relations to a model's `relations` when you need `include`\" : \"back-relations are in each model's `relations`\"}. \\`src/model/index.${ext}\\` imports\n them all${opts.language === 'typescript' ? ' and declares `Tables` (typed `include`)' : ''} — add new models there.`\n : `- \\`src/model/*.${ext}\\` — \\`defineModel\\` models.`\n}\n- \\`src/index.${ext}\\` is the entry point; it imports \\`efc.config.${ext}\\` and passes it to \\`ignite()\\`.\n- Only three import paths exist: \\`express-file-cluster\\`, \\`express-file-cluster/auth\\`,\n \\`express-file-cluster/tasks\\`.\n${\n opts.registry\n ? `- Ready-made features (auth, user/admin portals, billing, mailer…) come from the registry:\n \\`npx efc list\\`, then \\`npx efc add <item> --yes\\` — check it before hand-writing auth or CRUD\n (\\`${D}/cli/add.md\\`). \\`efc.json\\` tracks what was added; commit it.\n`\n : ''\n}\n## Commands\n\n\\`\\`\\`bash\nnpx efc start dev # dev server with reload\nnpx efc db migrate # run migrations\nnpx efc build prod # type-check + production build\nnpx efc doctor # diagnose the setup\n\\`\\`\\`\n`;\n await fs.outputFile(path.join(dest, 'AGENTS.md'), content);\n}\n\nasync function writeEnvFiles(dest: string, opts: ScaffoldOptions): Promise<void> {\n const secret = crypto.randomBytes(64).toString('hex');\n const projectName = path.basename(dest);\n const dbUrl =\n opts.database === 'mongodb'\n ? `mongodb://localhost:27017/${projectName}`\n : `postgresql://localhost:5432/${projectName}`;\n const dbExampleUrl =\n opts.database === 'mongodb'\n ? `mongodb://localhost:27017/${projectName}`\n : `postgresql://user:password@localhost:5432/${projectName}`;\n\n const isGmail = opts.mailer && opts.smtpProvider !== 'custom';\n const resolvedHost = isGmail ? 'smtp.gmail.com' : (opts.smtpHost ?? 'smtp.gmail.com');\n const resolvedPort = isGmail ? '465' : (opts.smtpPort ?? '587');\n const passComment = isGmail\n ? ' # Gmail App Password (16 chars) — NOT your regular Gmail password. Generate at: Google Account > Security > 2-Step Verification > App passwords'\n : '';\n\n const smtpVars = opts.mailer\n ? `\\nAPP_URL=http://localhost:3000\\nSMTP_HOST=${resolvedHost}\\nSMTP_PORT=${resolvedPort}\\nSMTP_USER=${opts.smtpUser ?? ''}\\nSMTP_PASS=${opts.smtpPass ?? ''}${passComment}\\nSMTP_FROM=${opts.smtpUser ?? 'noreply@example.com'}\\n`\n : '';\n const smtpExample = opts.mailer\n ? `\\nAPP_URL=http://localhost:3000\\nSMTP_HOST=${resolvedHost}\\nSMTP_PORT=${resolvedPort}\\nSMTP_USER=your@email.com\\nSMTP_PASS=${isGmail ? 'your_16_char_app_password' : 'your_smtp_password'}${passComment}\\nSMTP_FROM=noreply@yourapp.com\\n`\n : '';\n // Only BullMQ needs Redis — and `efc tasks failed` picks its backend from REDIS_URL.\n const redis =\n opts.tasks && opts.taskBackend !== 'pg-boss' ? '\\nREDIS_URL=redis://localhost:6379' : '';\n const oauth = opts.oauth ?? {};\n const oauthVars = [\n ...(oauth.google\n ? [\n ['GOOGLE_CLIENT_ID', '', 'your-client-id.apps.googleusercontent.com'],\n ['GOOGLE_CLIENT_SECRET', '', 'your-client-secret'],\n [\n 'GOOGLE_REDIRECT_URI',\n 'http://localhost:3000/v1/api/auth/google/callback',\n 'https://api.yourapp.com/v1/api/auth/google/callback',\n ],\n ]\n : []),\n ...(oauth.apple\n ? [\n ['APPLE_CLIENT_ID', '', 'com.yourapp.signin'],\n ['APPLE_TEAM_ID', '', 'ABCDE12345'],\n ['APPLE_KEY_ID', '', 'FGHIJ67890'],\n [\n 'APPLE_PRIVATE_KEY',\n '',\n '-----BEGIN PRIVATE KEY-----\\\\n...\\\\n-----END PRIVATE KEY-----',\n ],\n [\n 'APPLE_REDIRECT_URI',\n 'https://api.yourapp.com/v1/api/auth/apple/callback',\n 'https://api.yourapp.com/v1/api/auth/apple/callback',\n ],\n ]\n : []),\n ...(usesOAuth(opts)\n ? [['OAUTH_SUCCESS_REDIRECT', 'http://localhost:3000/', 'https://yourapp.com/']]\n : []),\n ];\n const oauthEnv = oauthVars.map(([k, v]) => `\\n${k}=${v}`).join('');\n const oauthExample = oauthVars.map(([k, , ex]) => `\\n${k}=${ex}`).join('');\n const dotenv = `PORT=3000\\nNODE_ENV=development\\nDATABASE_URL=${dbUrl}\\nJWT_SECRET=${secret}${redis}\\nCORS_ORIGINS=http://localhost:3000${smtpVars}${oauthEnv}`;\n const example = `PORT=3000\\nNODE_ENV=development\\nDATABASE_URL=${dbExampleUrl}\\nJWT_SECRET=<generate with: openssl rand -hex 64>${redis}\\nCORS_ORIGINS=http://localhost:3000,https://yourapp.com${smtpExample}${oauthExample}`;\n await fs.outputFile(path.join(dest, '.env'), dotenv);\n await fs.outputFile(path.join(dest, '.env.example'), example);\n}\n\nasync function writeExampleRoute(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const metaTs = opts.routeDocs\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Health check — returns server status and current timestamp.',\\n response: { status: 200, body: { status: 'OK', timestamp: '2024-01-01T00:00:00.000Z' } },\\n },\\n};\\n\\n`\n : '';\n const metaJs = opts.routeDocs\n ? `export const meta = {\\n GET: {\\n description: 'Health check — returns server status and current timestamp.',\\n response: { status: 200, body: { status: 'OK', timestamp: '2024-01-01T00:00:00.000Z' } },\\n },\\n};\\n\\n`\n : '';\n const content =\n opts.language === 'typescript'\n ? `import type { Request, Response } from 'express';\\n${metaTs}export const GET = async (_req: Request, res: Response) => {\\n res.json({ status: 'OK', timestamp: new Date().toISOString() });\\n};\\n`\n : `${metaJs}export const GET = async (_req, res) => {\\n res.json({ status: 'OK', timestamp: new Date().toISOString() });\\n};\\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', `health.${ext}`), content);\n}\n\nasync function writeExampleTask(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n\n const tsMailer = `import { defineTask } from 'express-file-cluster/tasks';\nimport nodemailer from 'nodemailer';\n\ninterface SendEmailPayload {\n to: string;\n subject: string;\n body: string;\n}\n\nconst transporter = nodemailer.createTransport({\n host: process.env.SMTP_HOST,\n port: Number(process.env.SMTP_PORT ?? 587),\n secure: Number(process.env.SMTP_PORT) === 465,\n auth: {\n user: process.env.SMTP_USER,\n pass: process.env.SMTP_PASS,\n },\n});\n\nexport default defineTask<SendEmailPayload>(async (payload) => {\n await transporter.sendMail({\n from: process.env.SMTP_FROM ?? process.env.SMTP_USER,\n to: payload.to,\n subject: payload.subject,\n html: payload.body,\n });\n});\n`;\n\n const jsMailer = `import { defineTask } from 'express-file-cluster/tasks';\nimport nodemailer from 'nodemailer';\n\nconst transporter = nodemailer.createTransport({\n host: process.env.SMTP_HOST,\n port: Number(process.env.SMTP_PORT ?? 587),\n secure: Number(process.env.SMTP_PORT) === 465,\n auth: {\n user: process.env.SMTP_USER,\n pass: process.env.SMTP_PASS,\n },\n});\n\nexport default defineTask(async (payload) => {\n await transporter.sendMail({\n from: process.env.SMTP_FROM ?? process.env.SMTP_USER,\n to: payload.to,\n subject: payload.subject,\n html: payload.body,\n });\n});\n`;\n\n const tsStub = `import { defineTask } from 'express-file-cluster/tasks';\n\ninterface SendEmailPayload {\n to: string;\n subject: string;\n body: string;\n}\n\nexport default defineTask<SendEmailPayload>(async (payload) => {\n // TODO: wire up your mailer\n console.log('[SendEmail] Sending to', payload.to);\n});\n`;\n\n const jsStub = `import { defineTask } from 'express-file-cluster/tasks';\n\nexport default defineTask(async (payload) => {\n // TODO: wire up your mailer\n console.log('[SendEmail] Sending to', payload.to);\n});\n`;\n\n const content = opts.mailer\n ? opts.language === 'typescript'\n ? tsMailer\n : jsMailer\n : opts.language === 'typescript'\n ? tsStub\n : jsStub;\n\n await fs.outputFile(path.join(dest, 'src', 'tasks', `SendEmail.${ext}`), content);\n}\n\nasync function writeUserModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n\n const content = `${modelApi(opts).import}\n\nexport const User = ${modelApi(opts).name}('User', {\n name: { type: 'string', required: true },\n email: { type: 'string', required: true, unique: true },\n password: { type: 'string', required: true },\n role: { type: 'string', required: true, default: 'user' },\n avatar: { type: 'string' },\n isVerified: { type: 'boolean', default: false },\n isActive: { type: 'boolean', default: true },\n verifyToken: { type: 'string' },\n resetToken: { type: 'string' },\n resetTokenExpiry: { type: 'date' },\n refreshToken: { type: 'string' },\n refreshTokenExpiry: { type: 'date' },\n}${relationsOption(opts, [\n { name: 'sessions', kind: 'hasMany', target: 'Session', foreignKey: 'user' },\n { name: 'notifications', kind: 'hasMany', target: 'Notification', foreignKey: 'user' },\n { name: 'files', kind: 'hasMany', target: 'File', foreignKey: 'user' },\n { name: 'tickets', kind: 'hasMany', target: 'SupportTicket', foreignKey: 'user' },\n { name: 'subscriptions', kind: 'hasMany', target: 'Subscription', foreignKey: 'user' },\n { name: 'invoices', kind: 'hasMany', target: 'Invoice', foreignKey: 'user' },\n { name: 'apiKeys', kind: 'hasMany', target: 'ApiKey', foreignKey: 'user' },\n ])});\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'model', `User.${ext}`), content);\n}\n\nasync function writeAdminModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n\n const content = `${modelApi(opts).import}\n\nexport const Admin = ${modelApi(opts).name}('Admin', {\n name: { type: 'string', required: true },\n email: { type: 'string', required: true, unique: true },\n password: { type: 'string', required: true },\n role: { type: 'string', required: true, default: 'admin' },\n permissions: { type: 'array', of: 'string', default: [] },\n isActive: { type: 'boolean', default: true },\n resetToken: { type: 'string' },\n resetTokenExpiry: { type: 'date' },\n refreshToken: { type: 'string' },\n refreshTokenExpiry: { type: 'date' },\n}${relationsOption(opts, [\n { name: 'assignedTickets', kind: 'hasMany', target: 'SupportTicket', foreignKey: 'assignedTo' },\n { name: 'auditLogs', kind: 'hasMany', target: 'AuditLog', foreignKey: 'admin' },\n { name: 'posts', kind: 'hasMany', target: 'Blog', foreignKey: 'author' },\n ])});\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'model', `Admin.${ext}`), content);\n}\n\nasync function writeAuthRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n\n const loginMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n POST: {\\n description: 'Authenticate a user or admin and issue a JWT.',\\n request: { body: { email: 'user@example.com', password: 'user' } },\\n response: { status: 200, body: { message: 'Logged in as user' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n POST: {\\n description: 'Authenticate a user or admin and issue a JWT.',\\n request: { body: { email: 'user@example.com', password: 'user' } },\\n response: { status: 200, body: { message: 'Logged in as user' } },\\n },\\n};\\n\\n`\n : '';\n\n // Only reference the models for the portals actually being generated —\n // referencing both unconditionally broke builds when only one portal was selected.\n const { user: hasUser, admin: hasAdmin } = principals(opts);\n const hasModels = hasUser || hasAdmin;\n\n const loginDbImports = hasModels\n ? `import crypto from 'node:crypto';\\n${hasUser ? `import { User } from '../../model/User.js';\\n` : ''}${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`\n : '';\n\n const loginBody =\n hasAdmin && hasUser\n ? ` const admin = await ${db.findOne('Admin', `{ email }`)};\n if (admin) {\n const match = await verifyPassword(password, admin.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!admin.isActive) return res.status(403).json({ error: 'Account suspended' });\n await issueToken(res, { id: admin.id, role: admin.role, email: admin.email });\n await issueRefreshToken(res, Admin, admin.id);\n return res.json({ message: 'Logged in as admin' });\n }\n\n const user = await ${db.findOne('User', `{ email }`)};\n if (!user) return res.status(401).json({ error: 'Invalid credentials' });\n const match = await verifyPassword(password, user.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!user.isActive) return res.status(403).json({ error: 'Account suspended' });\n await issueToken(res, { id: user.id, role: user.role, email: user.email });\n await issueRefreshToken(res, User, user.id);\n res.json({ message: 'Logged in' });`\n : hasAdmin\n ? ` const admin = await ${db.findOne('Admin', `{ email }`)};\n if (!admin) return res.status(401).json({ error: 'Invalid credentials' });\n const match = await verifyPassword(password, admin.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!admin.isActive) return res.status(403).json({ error: 'Account suspended' });\n await issueToken(res, { id: admin.id, role: admin.role, email: admin.email });\n await issueRefreshToken(res, Admin, admin.id);\n res.json({ message: 'Logged in as admin' });`\n : ` const user = await ${db.findOne('User', `{ email }`)};\n if (!user) return res.status(401).json({ error: 'Invalid credentials' });\n const match = await verifyPassword(password, user.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!user.isActive) return res.status(403).json({ error: 'Account suspended' });\n await issueToken(res, { id: user.id, role: user.role, email: user.email });\n await issueRefreshToken(res, User, user.id);\n res.json({ message: 'Logged in' });`;\n\n const loginContent = hasModels\n ? ts\n ? `import { issueToken, verifyPassword } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${loginDbImports}${loginMeta}const REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nasync function issueRefreshToken(\n res: Response,\n model: ${\n usesTables(opts)\n ? '{ update: (args: { where: { id: string }; data: Record<string, unknown> }) => Promise<unknown> }'\n : '{ update: (id: string, data: Record<string, unknown>) => Promise<unknown> }'\n },\n id: string,\n): Promise<void> {\n const refreshToken = crypto.randomBytes(40).toString('hex');\n await ${db.update('model', 'id', '{ refreshToken, refreshTokenExpiry: new Date(Date.now() + REFRESH_TOKEN_TTL_MS) }')};\n res.cookie('efc_refresh_token', refreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n}\n\nexport const POST = async (req: Request, res: Response) => {\n const { email, password } = req.body;\n if (!email || !password) return res.status(400).json({ error: 'email and password are required' });\n\n${loginBody}\n};\n`\n : `import { issueToken, verifyPassword } from 'express-file-cluster/auth';\n${loginDbImports}${loginMeta}const REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nasync function issueRefreshToken(res, model, id) {\n const refreshToken = crypto.randomBytes(40).toString('hex');\n await ${db.update('model', 'id', '{ refreshToken, refreshTokenExpiry: new Date(Date.now() + REFRESH_TOKEN_TTL_MS) }')};\n res.cookie('efc_refresh_token', refreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n}\n\nexport const POST = async (req, res) => {\n const { email, password } = req.body;\n if (!email || !password) return res.status(400).json({ error: 'email and password are required' });\n\n${loginBody}\n};\n`\n : ts\n ? `import { issueToken } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${loginMeta}export const POST = async (req: Request, res: Response) => {\n const { email, password } = req.body;\n // TODO: look up user in DB and compare password\n res.status(401).json({ error: 'Invalid credentials' });\n};\n`\n : `import { issueToken } from 'express-file-cluster/auth';\n${loginMeta}export const POST = async (req, res) => {\n const { email, password } = req.body;\n // TODO: look up user in DB and compare password\n res.status(401).json({ error: 'Invalid credentials' });\n};\n`;\n\n const logoutMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n POST: {\\n description: 'Revoke the current session and clear the auth cookie.',\\n response: { status: 200, body: { message: 'Logged out successfully' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n POST: {\\n description: 'Revoke the current session and clear the auth cookie.',\\n response: { status: 200, body: { message: 'Logged out successfully' } },\\n },\\n};\\n\\n`\n : '';\n\n const logoutContent = ts\n ? `import { revokeSession } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${logoutMeta}export const POST = async (req: Request, res: Response) => {\n // Rejects this token from now on (not just the cookie) — see \\`cache\\` in efc.config.\n await revokeSession(req, res);\n res.clearCookie('efc_refresh_token');\n res.json({ message: 'Logged out successfully' });\n};\n`\n : `import { revokeSession } from 'express-file-cluster/auth';\n${logoutMeta}export const POST = async (req, res) => {\n // Rejects this token from now on (not just the cookie) — see \\`cache\\` in efc.config.\n await revokeSession(req, res);\n res.clearCookie('efc_refresh_token');\n res.json({ message: 'Logged out successfully' });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `login.${ext}`), loginContent);\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `logout.${ext}`), logoutContent);\n\n if (!hasUser) return;\n\n const registerMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n POST: {\\n description: 'Register a new user account.',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret' } },\\n response: { status: 201, body: { message: 'Account created successfully' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n POST: {\\n description: 'Register a new user account.',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret' } },\\n response: { status: 201, body: { message: 'Account created successfully' } },\\n },\\n};\\n\\n`\n : '';\n\n const registerDbImports = `import { hashPassword } from 'express-file-cluster/auth';\\nimport crypto from 'node:crypto';\\n${sendsMail(opts) ? \"import { enqueue } from 'express-file-cluster/tasks';\\n\" : ''}import { User } from '../../model/User.js';\\n`;\n\n const sendVerifyEmail = sendsMail(opts)\n ? `\n var appUrl = process.env.APP_URL || 'http://localhost:3000';\n await enqueue('SendEmail', {\n to: email,\n subject: 'Verify your email address',\n body: 'Welcome, ' + name + '! Verify your email: ' + appUrl + '/auth/verify-email?token=' + verifyToken,\n });\n`\n : `\n // TODO: email this token to the user — enable the Mailer feature to auto-wire SendEmail\n`;\n\n const registerContent = ts\n ? `import type { Request, Response } from 'express';\n${registerDbImports}${registerMeta}export const POST = async (req: Request, res: Response) => {\n const { name, email, password } = req.body;\n if (!name || !email || !password) {\n return res.status(400).json({ error: 'name, email and password are required' });\n }\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const verifyToken = crypto.randomBytes(32).toString('hex');\n const user = await ${db.create('User', `{ name, email, password: hashed, verifyToken }`)};\n${sendVerifyEmail}\n const { password: _, verifyToken: __, ...safe } = user;\n res.status(201).json({ message: 'Account created successfully', user: safe });\n};\n`\n : `${registerDbImports}${registerMeta}export const POST = async (req, res) => {\n const { name, email, password } = req.body;\n if (!name || !email || !password) {\n return res.status(400).json({ error: 'name, email and password are required' });\n }\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const verifyToken = crypto.randomBytes(32).toString('hex');\n const user = await ${db.create('User', `{ name, email, password: hashed, verifyToken }`)};\n${sendVerifyEmail}\n const { password: _, verifyToken: __, ...safe } = user;\n res.status(201).json({ message: 'Account created successfully', user: safe });\n};\n`;\n\n const meMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Return the currently authenticated user.',\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'Return the currently authenticated user.',\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n};\\n\\n`\n : '';\n const meMiddlewares = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n\\n`\n : `export const middlewares = [requireAuth];\\n\\n`;\n\n const meContent = ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${meMeta}${meMiddlewares}export const GET = async (req: Request, res: Response) => {\n res.json({ user: (req as any).user });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${meMeta}${meMiddlewares}export const GET = async (req, res) => {\n res.json({ user: req.user });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `register.${ext}`), registerContent);\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `me.${ext}`), meContent);\n}\n\nasync function writeAdminRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n const middlewares = opts.rbac\n ? `export const middlewares = [requireAuth('admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const roleGuard = opts.rbac\n ? ''\n : ts\n ? ` const user = (req as any).user;\\n if (user?.role !== 'admin') {\\n return res.status(403).json({ error: 'Forbidden: Admin access required' });\\n }\\n\\n`\n : ` const user = req.user;\\n if (user?.role !== 'admin') {\\n return res.status(403).json({ error: 'Forbidden: Admin access required' });\\n }\\n\\n`;\n\n const dashboardMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Admin dashboard stats. Requires admin role.',\\n response: { status: 200, body: { stats: { totalUsers: 120, activeUsers: 98, verifiedUsers: 84 } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'Admin dashboard stats. Requires admin role.',\\n response: { status: 200, body: { stats: { totalUsers: 120, activeUsers: 98, verifiedUsers: 84 } } },\\n },\\n};\\n\\n`\n : '';\n\n // Real stats need the User model, which only exists when userManagement is on (registry\n // mode: always — auth brings it).\n const dashboardHasUserModel = !!opts.registry || opts.adminFeatures.userManagement;\n\n const dashboardDbImport = dashboardHasUserModel\n ? `import { User } from '../../model/User.js';\\n`\n : '';\n\n const dashboardContent = dashboardHasUserModel\n ? ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${dashboardDbImport}${dashboardMeta}${middlewares}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} const [totalUsers, activeUsers, verifiedUsers] = await Promise.all([\n ${db.count('User', `{}`)},\n ${db.count('User', `{ isActive: true }`)},\n ${db.count('User', `{ isVerified: true }`)},\n ]);\n res.json({ stats: { totalUsers, activeUsers, verifiedUsers } });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${dashboardDbImport}${dashboardMeta}${middlewares}\nexport const GET = async (_req, res) => {\n${roleGuard} const [totalUsers, activeUsers, verifiedUsers] = await Promise.all([\n ${db.count('User', `{}`)},\n ${db.count('User', `{ isActive: true }`)},\n ${db.count('User', `{ isVerified: true }`)},\n ]);\n res.json({ stats: { totalUsers, activeUsers, verifiedUsers } });\n};\n`\n : ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${dashboardMeta}${middlewares}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: aggregate stats from DB\n res.json({ stats: { users: 0 } });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${dashboardMeta}${middlewares}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: aggregate stats from DB\n res.json({ stats: { users: 0 } });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'admin', `dashboard.${ext}`), dashboardContent);\n\n if (!opts.adminFeatures.userManagement) return;\n\n // Admin user management routes\n const usersListMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'List all users, paginated (admin only).',\\n request: { query: { page: '1', limit: '20' } },\\n response: { status: 200, body: { users: [], total: 0, page: 1, limit: 20 } },\\n },\\n POST: {\\n description: 'Create a new user account (admin only).',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret', role: 'user' } },\\n response: { status: 201, body: { message: 'User created', user: { id: 'new-id', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'List all users, paginated (admin only).',\\n request: { query: { page: '1', limit: '20' } },\\n response: { status: 200, body: { users: [], total: 0, page: 1, limit: 20 } },\\n },\\n POST: {\\n description: 'Create a new user account (admin only).',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret', role: 'user' } },\\n response: { status: 201, body: { message: 'User created', user: { id: 'new-id', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n};\\n\\n`\n : '';\n\n const adminUsersDbImport = `import { User } from '../../../model/User.js';\\n`;\n\n const usersListContent = ts\n ? `import { hashPassword, requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${adminUsersDbImport}${usersListMeta}${middlewares}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const page = Math.max(1, Number(req.query.page) || 1);\n const limit = Math.min(100, Number(req.query.limit) || 20);\n const [all, total] = await Promise.all([${db.find('User', `{}`)}, ${db.count('User', `{}`)}]);\n const users = all.slice((page - 1) * limit, page * limit).map(({ password: _, ...u }) => u);\n res.json({ users, total, page, limit });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { name, email, password, role } = req.body;\n if (!name || !email || !password) return res.status(400).json({ error: 'name, email and password are required' });\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const user = await ${db.create('User', `{ name, email, password: hashed, role: role ?? 'user' }`)};\n const { password: _, ...safe } = user;\n res.status(201).json({ message: 'User created', user: safe });\n};\n`\n : `import { hashPassword, requireAuth } from 'express-file-cluster/auth';\n${adminUsersDbImport}${usersListMeta}${middlewares}\nexport const GET = async (req, res) => {\n${roleGuard} const page = Math.max(1, Number(req.query.page) || 1);\n const limit = Math.min(100, Number(req.query.limit) || 20);\n const [all, total] = await Promise.all([${db.find('User', `{}`)}, ${db.count('User', `{}`)}]);\n const users = all.slice((page - 1) * limit, page * limit).map(({ password: _, ...u }) => u);\n res.json({ users, total, page, limit });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { name, email, password, role } = req.body;\n if (!name || !email || !password) return res.status(400).json({ error: 'name, email and password are required' });\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const user = await ${db.create('User', `{ name, email, password: hashed, role: role ?? 'user' }`)};\n const { password: _, ...safe } = user;\n res.status(201).json({ message: 'User created', user: safe });\n};\n`;\n\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', `index.${ext}`),\n usersListContent,\n );\n\n const userByIdMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Fetch a single user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n PUT: {\\n description: 'Update a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' }, body: { name: 'Jane Doe', email: 'jane@example.com', role: 'user', isActive: true } },\\n response: { status: 200, body: { message: 'User updated', user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n DELETE: {\\n description: 'Delete a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { message: 'User usr_01HXZ deleted' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'Fetch a single user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n PUT: {\\n description: 'Update a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' }, body: { name: 'Jane Doe', email: 'jane@example.com', role: 'user', isActive: true } },\\n response: { status: 200, body: { message: 'User updated', user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n DELETE: {\\n description: 'Delete a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { message: 'User usr_01HXZ deleted' } },\\n },\\n};\\n\\n`\n : '';\n\n const adminUserByIdDbImport = `import { User } from '../../../model/User.js';\\n`;\n\n const userByIdContent = ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${adminUserByIdDbImport}${userByIdMeta}${middlewares}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const { name, email, role, isActive } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email, role, isActive }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = updated;\n res.json({ message: 'User updated', user: safe });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n await ${db.delete('User', `id`)};\n res.json({ message: \\`User \\${id} deleted\\` });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${adminUserByIdDbImport}${userByIdMeta}${middlewares}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const { name, email, role, isActive } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email, role, isActive }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = updated;\n res.json({ message: 'User updated', user: safe });\n};\n\nexport const DELETE = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n await ${db.delete('User', `id`)};\n res.json({ message: \\`User \\${id} deleted\\` });\n};\n`;\n\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', `[id].${ext}`),\n userByIdContent,\n );\n}\n\nasync function writeUserRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n const middlewares = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n\n const profileMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: \"Fetch the authenticated user's profile.\",\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n PUT: {\\n description: \"Update the authenticated user's profile.\",\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com' } },\\n response: { status: 200, body: { message: 'Profile updated', user: { id: '1', role: 'user', email: 'jane@example.com' } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: \"Fetch the authenticated user's profile.\",\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n PUT: {\\n description: \"Update the authenticated user's profile.\",\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com' } },\\n response: { status: 200, body: { message: 'Profile updated', user: { id: '1', role: 'user', email: 'jane@example.com' } } },\\n },\\n};\\n\\n`\n : '';\n\n const profileDbImport = `import { User } from '../../model/User.js';\\n`;\n\n const profileContent = ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${profileDbImport}${profileMeta}${middlewares}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = (req as any).user;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { id } = (req as any).user;\n const { name, email } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = updated;\n res.json({ message: 'Profile updated', user: safe });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${profileDbImport}${profileMeta}${middlewares}\nexport const GET = async (req, res) => {\n const { id } = req.user;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req, res) => {\n const { id } = req.user;\n const { name, email } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n const { password: _, ...safe } = updated;\n res.json({ message: 'Profile updated', user: safe });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `profile.${ext}`), profileContent);\n}\n\n// ─── META HELPER ─────────────────────────────────────────────────────────\n\ninterface MethodMetaSpec {\n description: string;\n params?: string;\n query?: string;\n request?: string;\n response?: string;\n status?: number;\n}\n\nfunction mkMeta(opts: ScaffoldOptions, methods: Record<string, MethodMetaSpec>): string {\n if (!opts.routeDocs) return '';\n const blocks = Object.entries(methods)\n .map(([method, m]) => {\n const reqParts: string[] = [];\n if (m.params) reqParts.push(`params: ${m.params}`);\n if (m.query) reqParts.push(`query: ${m.query}`);\n if (m.request) reqParts.push(`body: ${m.request}`);\n const reqLine = reqParts.length ? ` request: { ${reqParts.join(', ')} },\\n` : '';\n const status = m.status ?? 200;\n const respLine =\n m.response !== undefined\n ? ` response: { status: ${status}, body: ${m.response} },\\n`\n : ` response: { status: ${status} },\\n`;\n const description = m.description.replace(/'/g, \"\\\\'\");\n return ` ${method}: {\\n description: '${description}',\\n${reqLine}${respLine} },`;\n })\n .join('\\n');\n return opts.language === 'typescript'\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n${blocks}\\n};\\n\\n`\n : `export const meta = {\\n${blocks}\\n};\\n\\n`;\n}\n\n// ─── EXTENDED MODEL WRITERS ───────────────────────────────────────────────\n\nasync function writeSessionModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Session = ${modelApi(opts).name}('Session', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n token: { type: 'string', required: true, unique: true },\n ip: { type: 'string', required: true },\n userAgent: { type: 'string', required: true },\n expiresAt: { type: 'date', required: true },\n isActive: { type: 'boolean', default: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Session.${ext}`), content);\n}\n\nasync function writeNotificationModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Notification = ${modelApi(opts).name}('Notification', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n title: { type: 'string', required: true },\n message: { type: 'string', required: true },\n type: { type: 'string', required: true, default: 'info' },\n isRead: { type: 'boolean', default: false },\n link: { type: 'string' },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Notification.${ext}`), content);\n}\n\nasync function writeFileModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const File = ${modelApi(opts).name}('File', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n filename: { type: 'string', required: true },\n originalName: { type: 'string', required: true },\n mimeType: { type: 'string', required: true },\n size: { type: 'number', required: true },\n url: { type: 'string', required: true },\n isPublic: { type: 'boolean', default: false },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `File.${ext}`), content);\n}\n\nasync function writeSupportTicketModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const SupportTicket = ${modelApi(opts).name}('SupportTicket', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n subject: { type: 'string', required: true },\n message: { type: 'string', required: true },\n status: { type: 'string', required: true, default: 'open' },\n priority: { type: 'string', required: true, default: 'normal' },\n${refField(opts, { field: 'assignedTo', target: 'Admin', legacy: ` assignedTo: { type: 'string' },`, onDelete: 'setNull' })}\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `SupportTicket.${ext}`), content);\n}\n\nasync function writeAuditLogModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const AuditLog = ${modelApi(opts).name}('AuditLog', {\n${refField(opts, { field: 'admin', target: 'Admin', legacy: ` adminId: { type: 'string', required: true },`, onDelete: 'setNull' })}\n action: { type: 'string', required: true },\n entity: { type: 'string', required: true },\n entityId: { type: 'string', required: true },\n metadata: { type: 'object' },\n ip: { type: 'string', required: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `AuditLog.${ext}`), content);\n}\n\nasync function writeSubscriptionModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Subscription = ${modelApi(opts).name}('Subscription', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n${refField(opts, { field: 'plan', target: 'Plan', legacy: ` planId: { type: 'string', required: true },`, required: true, onDelete: 'restrict' })}\n status: { type: 'string', required: true, default: 'active' },\n startDate: { type: 'date', required: true },\n endDate: { type: 'date', required: true },\n cancelledAt: { type: 'date' },\n}${relationsOption(opts, [{ name: 'invoices', kind: 'hasMany', target: 'Invoice', foreignKey: 'subscription' }])});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Subscription.${ext}`), content);\n}\n\nasync function writePlanModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Plan = ${modelApi(opts).name}('Plan', {\n name: { type: 'string', required: true },\n description: { type: 'string', required: true },\n price: { type: 'number', required: true },\n interval: { type: 'string', required: true, default: 'monthly' },\n features: { type: 'array', of: 'string', default: [] },\n isActive: { type: 'boolean', default: true },\n}${relationsOption(opts, [{ name: 'subscriptions', kind: 'hasMany', target: 'Subscription', foreignKey: 'plan' }])});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Plan.${ext}`), content);\n}\n\nasync function writeInvoiceModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Invoice = ${modelApi(opts).name}('Invoice', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n${refField(opts, { field: 'subscription', target: 'Subscription', legacy: ` subscriptionId: { type: 'string', required: true },`, onDelete: 'setNull' })}\n amount: { type: 'number', required: true },\n currency: { type: 'string', required: true, default: 'USD' },\n status: { type: 'string', required: true, default: 'pending' },\n paidAt: { type: 'date' },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Invoice.${ext}`), content);\n}\n\nasync function writeApiKeyModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const ApiKey = ${modelApi(opts).name}('ApiKey', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n name: { type: 'string', required: true },\n key: { type: 'string', required: true, unique: true },\n lastUsed: { type: 'date' },\n expiresAt: { type: 'date' },\n isActive: { type: 'boolean', default: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `ApiKey.${ext}`), content);\n}\n\nasync function writeRoleModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Role = ${modelApi(opts).name}('Role', {\n name: { type: 'string', required: true, unique: true },\n description: { type: 'string', required: true },\n permissions: { type: 'array', of: 'string', default: [] },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Role.${ext}`), content);\n}\n\nasync function writeFAQModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const FAQ = ${modelApi(opts).name}('FAQ', {\n question: { type: 'string', required: true },\n answer: { type: 'string', required: true },\n category: { type: 'string', required: true, default: 'general' },\n order: { type: 'number', default: 0 },\n isPublished: { type: 'boolean', default: false },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `FAQ.${ext}`), content);\n}\n\nasync function writeBlogModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Blog = ${modelApi(opts).name}('Blog', {\n title: { type: 'string', required: true },\n slug: { type: 'string', required: true, unique: true },\n content: { type: 'string', required: true },\n${refField(opts, { field: 'author', target: 'Admin', legacy: ` authorId: { type: 'string', required: true },`, onDelete: 'setNull' })}\n category: { type: 'string', required: true, default: 'general' },\n tags: { type: 'array', of: 'string', default: [] },\n status: { type: 'string', required: true, default: 'draft' },\n publishedAt: { type: 'date' },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Blog.${ext}`), content);\n}\n\nasync function writeCategoryModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Category = ${modelApi(opts).name}('Category', {\n name: { type: 'string', required: true },\n slug: { type: 'string', required: true, unique: true },\n description: { type: 'string' },\n${refField(opts, { field: 'parent', target: 'Category', legacy: ` parentId: { type: 'string' },`, onDelete: 'setNull' })}\n}${relationsOption(opts, [{ name: 'children', kind: 'hasMany', target: 'Category', foreignKey: 'parent' }])});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Category.${ext}`), content);\n}\n\nasync function writeCouponModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Coupon = ${modelApi(opts).name}('Coupon', {\n code: { type: 'string', required: true, unique: true },\n type: { type: 'string', required: true, default: 'percent' },\n value: { type: 'number', required: true },\n maxUses: { type: 'number', default: 0 },\n usedCount: { type: 'number', default: 0 },\n expiresAt: { type: 'date' },\n isActive: { type: 'boolean', default: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Coupon.${ext}`), content);\n}\n\n// ─── EXTENDED ROUTE WRITERS ───────────────────────────────────────────────\n\nasync function writeAuthExtendedRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n const mwUser2 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mwUser3 = mwUser2;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n const hasAdmin = principals(opts).admin;\n const uf = opts.userFeatures;\n const sendResetEmail = sendsMail(opts)\n ? ` var appUrl = process.env.APP_URL || 'http://localhost:3000';\n await enqueue('SendEmail', {\n to: email,\n subject: 'Reset your password',\n body: 'Reset your password: ' + appUrl + '/auth/reset-password?token=' + resetToken,\n });\n`\n : ` // TODO: email this token to the user — enable the Mailer feature to auto-wire SendEmail\n`;\n const sendVerifyEmailResend = sendsMail(opts)\n ? ` var appUrl = process.env.APP_URL || 'http://localhost:3000';\n await enqueue('SendEmail', {\n to: email,\n subject: 'Verify your email address',\n body: 'Verify your email: ' + appUrl + '/auth/verify-email?token=' + verifyToken,\n });\n`\n : ` // TODO: email this token to the user — enable the Mailer feature to auto-wire SendEmail\n`;\n const mailerTaskImport = sendsMail(opts)\n ? `import { enqueue } from 'express-file-cluster/tasks';\\n`\n : '';\n\n // refresh.ts\n if (uf.accountSecurity) {\n const refreshMeta = mkMeta(opts, {\n POST: {\n description: 'Refresh the JWT using the refresh-token cookie and issue a new access token.',\n response: `{ message: 'Token refreshed' }`,\n },\n });\n const refreshModelImports = `import { User } from '../../model/User.js';\\n${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`;\n const refreshLookup = hasAdmin\n ? ` const user = await ${db.findOne('User', `{ refreshToken: token }`)};\n const admin = user ? null : await ${db.findOne('Admin', `{ refreshToken: token }`)};\n const account = user || admin;`\n : ` const user = await ${db.findOne('User', `{ refreshToken: token }`)};\n const account = user;`;\n const refreshPersist = hasAdmin\n ? ` if (user) await ${db.update('User', `user.id`, `{ refreshToken: newRefreshToken, refreshTokenExpiry }`)};\n else if (admin) await ${db.update('Admin', `admin.id`, `{ refreshToken: newRefreshToken, refreshTokenExpiry }`)};`\n : ` await ${db.update('User', `user.id`, `{ refreshToken: newRefreshToken, refreshTokenExpiry }`)};`;\n const refreshContent = ts\n ? `import { issueToken } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\nimport crypto from 'node:crypto';\n${refreshModelImports}${refreshMeta}const REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nexport const POST = async (req: Request, res: Response) => {\n const token = req.cookies?.['efc_refresh_token'] || req.body?.refreshToken;\n if (!token) return res.status(401).json({ error: 'Refresh token required' });\n\n${refreshLookup}\n\n if (!account || !account.refreshTokenExpiry || new Date(account.refreshTokenExpiry) < new Date()) {\n return res.status(401).json({ error: 'Invalid or expired refresh token' });\n }\n\n const newRefreshToken = crypto.randomBytes(40).toString('hex');\n const refreshTokenExpiry = new Date(Date.now() + REFRESH_TOKEN_TTL_MS);\n${refreshPersist}\n\n res.cookie('efc_refresh_token', newRefreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n\n await issueToken(res, { id: account.id, role: account.role, email: account.email });\n res.json({ message: 'Token refreshed' });\n};\n`\n : `import { issueToken } from 'express-file-cluster/auth';\nimport crypto from 'node:crypto';\n${refreshModelImports}${refreshMeta}const REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nexport const POST = async (req, res) => {\n const token = req.cookies?.efc_refresh_token || req.body?.refreshToken;\n if (!token) return res.status(401).json({ error: 'Refresh token required' });\n\n${refreshLookup}\n\n if (!account || !account.refreshTokenExpiry || new Date(account.refreshTokenExpiry) < new Date()) {\n return res.status(401).json({ error: 'Invalid or expired refresh token' });\n }\n\n const newRefreshToken = crypto.randomBytes(40).toString('hex');\n const refreshTokenExpiry = new Date(Date.now() + REFRESH_TOKEN_TTL_MS);\n${refreshPersist}\n\n res.cookie('efc_refresh_token', newRefreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n\n await issueToken(res, { id: account.id, role: account.role, email: account.email });\n res.json({ message: 'Token refreshed' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `refresh.${ext}`), refreshContent);\n }\n\n // verify-email.ts\n if (uf.emailVerification) {\n const veMeta = mkMeta(opts, {\n GET: {\n description: 'Verify an email address using the token from the verification link.',\n query: `{ token: 'a1b2c3d4' }`,\n response: `{ message: 'Email verified' }`,\n },\n POST: {\n description: 'Resend the verification email to a given address.',\n request: `{ email: 'user@example.com' }`,\n response: `{ message: 'Verification email sent' }`,\n },\n });\n const veContent = ts\n ? `import type { Request, Response } from 'express';\nimport crypto from 'node:crypto';\n${mailerTaskImport}import { User } from '../../model/User.js';\n${veMeta}export const GET = async (req: Request, res: Response) => {\n const { token } = req.query;\n if (!token || typeof token !== 'string') return res.status(400).json({ error: 'token is required' });\n\n const user = await ${db.findOne('User', `{ verifyToken: token }`)};\n if (!user) return res.status(400).json({ error: 'Invalid or expired verification token' });\n\n await ${db.update('User', `user.id`, `{ isVerified: true, verifyToken: '' }`)};\n res.json({ message: 'Email verified' });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { email } = req.body;\n if (!email) return res.status(400).json({ error: 'email is required' });\n\n const user = await ${db.findOne('User', `{ email }`)};\n if (user && !user.isVerified) {\n const verifyToken = crypto.randomBytes(32).toString('hex');\n await ${db.update('User', `user.id`, `{ verifyToken }`)};\n${sendVerifyEmailResend} }\n\n res.json({ message: 'Verification email sent' });\n};\n`\n : `import crypto from 'node:crypto';\n${mailerTaskImport}import { User } from '../../model/User.js';\n${veMeta}export const GET = async (req, res) => {\n const { token } = req.query;\n if (!token || typeof token !== 'string') return res.status(400).json({ error: 'token is required' });\n\n const user = await ${db.findOne('User', `{ verifyToken: token }`)};\n if (!user) return res.status(400).json({ error: 'Invalid or expired verification token' });\n\n await ${db.update('User', `user.id`, `{ isVerified: true, verifyToken: '' }`)};\n res.json({ message: 'Email verified' });\n};\n\nexport const POST = async (req, res) => {\n const { email } = req.body;\n if (!email) return res.status(400).json({ error: 'email is required' });\n\n const user = await ${db.findOne('User', `{ email }`)};\n if (user && !user.isVerified) {\n const verifyToken = crypto.randomBytes(32).toString('hex');\n await ${db.update('User', `user.id`, `{ verifyToken }`)};\n${sendVerifyEmailResend} }\n\n res.json({ message: 'Verification email sent' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `verify-email.${ext}`), veContent);\n }\n\n // forgot-password.ts / reset-password.ts\n if (uf.forgotPassword) {\n const fpMeta = mkMeta(opts, {\n POST: {\n description: 'Send a password reset email to the given address.',\n request: `{ email: 'user@example.com' }`,\n response: `{ message: 'Reset email sent' }`,\n },\n });\n const fpModelImports = `import { User } from '../../model/User.js';\\n${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`;\n const fpLookup = hasAdmin\n ? ` const user = await ${db.findOne('User', `{ email }`)};\n const admin = user ? null : await ${db.findOne('Admin', `{ email }`)};`\n : ` const user = await ${db.findOne('User', `{ email }`)};`;\n const fpGuard = hasAdmin ? 'user || admin' : 'user';\n const fpPersist = hasAdmin\n ? ` if (user) await ${db.update('User', `user.id`, `{ resetToken, resetTokenExpiry }`)};\n else if (admin) await ${db.update('Admin', `admin.id`, `{ resetToken, resetTokenExpiry }`)};`\n : ` await ${db.update('User', `user.id`, `{ resetToken, resetTokenExpiry }`)};`;\n const fpContent = ts\n ? `import type { Request, Response } from 'express';\nimport crypto from 'node:crypto';\n${mailerTaskImport}${fpModelImports}${fpMeta}const RESET_TOKEN_TTL_MS = 1000 * 60 * 60; // 1 hour\n\nexport const POST = async (req: Request, res: Response) => {\n const { email } = req.body;\n if (!email) return res.status(400).json({ error: 'email is required' });\n\n${fpLookup}\n\n // Always respond the same way whether or not the account exists, so this\n // endpoint can't be used to enumerate registered emails.\n if (${fpGuard}) {\n const resetToken = crypto.randomBytes(32).toString('hex');\n const resetTokenExpiry = new Date(Date.now() + RESET_TOKEN_TTL_MS);\n${fpPersist}\n${sendResetEmail} }\n\n res.json({ message: 'Reset email sent' });\n};\n`\n : `import crypto from 'node:crypto';\n${mailerTaskImport}${fpModelImports}${fpMeta}const RESET_TOKEN_TTL_MS = 1000 * 60 * 60; // 1 hour\n\nexport const POST = async (req, res) => {\n const { email } = req.body;\n if (!email) return res.status(400).json({ error: 'email is required' });\n\n${fpLookup}\n\n // Always respond the same way whether or not the account exists, so this\n // endpoint can't be used to enumerate registered emails.\n if (${fpGuard}) {\n const resetToken = crypto.randomBytes(32).toString('hex');\n const resetTokenExpiry = new Date(Date.now() + RESET_TOKEN_TTL_MS);\n${fpPersist}\n${sendResetEmail} }\n\n res.json({ message: 'Reset email sent' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `forgot-password.${ext}`), fpContent);\n\n // reset-password.ts\n const rpMeta = mkMeta(opts, {\n POST: {\n description: 'Reset password using a valid reset token.',\n request: `{ token: 'reset-token', password: 'newpassword' }`,\n response: `{ message: 'Password reset successfully' }`,\n },\n });\n const rpModelImports = `import { User } from '../../model/User.js';\\n${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`;\n const rpLookup = hasAdmin\n ? ` const user = await ${db.findOne('User', `{ resetToken: token }`)};\n const admin = user ? null : await ${db.findOne('Admin', `{ resetToken: token }`)};\n const account = user || admin;`\n : ` const user = await ${db.findOne('User', `{ resetToken: token }`)};\n const account = user;`;\n const rpPersist = hasAdmin\n ? ` if (user) await ${db.update('User', `user.id`, `{ password: hashed, resetToken: '' }`)};\n else if (admin) await ${db.update('Admin', `admin.id`, `{ password: hashed, resetToken: '' }`)};`\n : ` await ${db.update('User', `user.id`, `{ password: hashed, resetToken: '' }`)};`;\n const rpContent = ts\n ? `import type { Request, Response } from 'express';\nimport { hashPassword, revokeAllSessions } from 'express-file-cluster/auth';\n${rpModelImports}${rpMeta}export const POST = async (req: Request, res: Response) => {\n const { token, password } = req.body;\n if (!token || !password) return res.status(400).json({ error: 'token and password are required' });\n\n${rpLookup}\n\n if (!account || !account.resetTokenExpiry || new Date(account.resetTokenExpiry) < new Date()) {\n return res.status(400).json({ error: 'Invalid or expired reset token' });\n }\n\n const hashed = await hashPassword(password);\n${rpPersist}\n // Tokens issued with the old password stop working everywhere.\n await revokeAllSessions(account.id);\n\n res.json({ message: 'Password reset successfully' });\n};\n`\n : `import { hashPassword, revokeAllSessions } from 'express-file-cluster/auth';\n${rpModelImports}${rpMeta}export const POST = async (req, res) => {\n const { token, password } = req.body;\n if (!token || !password) return res.status(400).json({ error: 'token and password are required' });\n\n${rpLookup}\n\n if (!account || !account.resetTokenExpiry || new Date(account.resetTokenExpiry) < new Date()) {\n return res.status(400).json({ error: 'Invalid or expired reset token' });\n }\n\n const hashed = await hashPassword(password);\n${rpPersist}\n // Tokens issued with the old password stop working everywhere.\n await revokeAllSessions(account.id);\n\n res.json({ message: 'Password reset successfully' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `reset-password.${ext}`), rpContent);\n }\n\n // change-password.ts (protected)\n if (uf.accountSecurity) {\n const cpMeta = mkMeta(opts, {\n POST: {\n description: 'Change password for the authenticated user.',\n request: `{ oldPassword: 'current', newPassword: 'newpassword' }`,\n response: `{ message: 'Password changed successfully' }`,\n },\n });\n const cpContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${cpMeta}${mwUser2}\nexport const POST = async (req: Request, res: Response) => {\n const { oldPassword, newPassword } = req.body;\n if (!oldPassword || !newPassword) return res.status(400).json({ error: 'oldPassword and newPassword are required' });\n // TODO: verify old password, hash and update new password, then sign out other devices:\n // await revokeAllSessions(req.user.id) (import from 'express-file-cluster/auth')\n res.json({ message: 'Password changed successfully' });\n};\n`\n : `${RA}${cpMeta}${mwUser2}\nexport const POST = async (req, res) => {\n const { oldPassword, newPassword } = req.body;\n if (!oldPassword || !newPassword) return res.status(400).json({ error: 'oldPassword and newPassword are required' });\n // TODO: verify old password, hash and update new password, then sign out other devices:\n // await revokeAllSessions(req.user.id) (import from 'express-file-cluster/auth')\n res.json({ message: 'Password changed successfully' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `change-password.${ext}`), cpContent);\n\n // 2fa/setup.ts\n const tfaSetupMeta = mkMeta(opts, {\n GET: {\n description: 'Generate a TOTP secret and QR code to set up 2FA.',\n response: `{ qrCode: 'otpauth://totp/...', secret: 'BASE32SECRET' }`,\n },\n POST: {\n description: 'Confirm a TOTP code to enable 2FA for the authenticated user.',\n request: `{ code: '123456' }`,\n response: `{ message: '2FA enabled' }`,\n },\n });\n const tfaSetupContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${tfaSetupMeta}${mwUser3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: generate TOTP secret and return QR code URL\n res.json({ qrCode: 'otpauth://totp/...', secret: 'BASE32SECRET' });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code and enable 2FA\n res.json({ message: '2FA enabled' });\n};\n`\n : `${RA}${tfaSetupMeta}${mwUser3}\nexport const GET = async (req, res) => {\n // TODO: generate TOTP secret and return QR code URL\n res.json({ qrCode: 'otpauth://totp/...', secret: 'BASE32SECRET' });\n};\n\nexport const POST = async (req, res) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code and enable 2FA\n res.json({ message: '2FA enabled' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', '2fa', `setup.${ext}`),\n tfaSetupContent,\n );\n\n // 2fa/verify.ts\n const tfaVerifyMeta = mkMeta(opts, {\n POST: {\n description: 'Verify a TOTP code during login.',\n request: `{ code: '123456' }`,\n response: `{ message: '2FA verified' }`,\n },\n });\n const tfaVerifyContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${tfaVerifyMeta}export const POST = async (req: Request, res: Response) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code\n res.json({ message: '2FA verified' });\n};\n`\n : `${RA}${tfaVerifyMeta}export const POST = async (req, res) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code\n res.json({ message: '2FA verified' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', '2fa', `verify.${ext}`),\n tfaVerifyContent,\n );\n\n // 2fa/disable.ts\n const tfaDisableMeta = mkMeta(opts, {\n POST: {\n description: 'Disable 2FA for the authenticated user.',\n request: `{ code: '123456' }`,\n response: `{ message: '2FA disabled' }`,\n },\n });\n const tfaDisableContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${tfaDisableMeta}${mwUser3}\nexport const POST = async (req: Request, res: Response) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify code and disable 2FA\n res.json({ message: '2FA disabled' });\n};\n`\n : `${RA}${tfaDisableMeta}${mwUser3}\nexport const POST = async (req, res) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify code and disable 2FA\n res.json({ message: '2FA disabled' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', '2fa', `disable.${ext}`),\n tfaDisableContent,\n );\n\n // sessions/index.ts\n const sessListMeta = mkMeta(opts, {\n GET: {\n description: 'List all active sessions for the authenticated user.',\n response: `{ sessions: [] }`,\n },\n });\n const sessListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${sessListMeta}${mwUser3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch sessions for req.user.id\n res.json({ sessions: [] });\n};\n`\n : `${RA}${sessListMeta}${mwUser3}\nexport const GET = async (req, res) => {\n // TODO: fetch sessions for req.user.id\n res.json({ sessions: [] });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'sessions', `index.${ext}`),\n sessListContent,\n );\n\n // sessions/[id].ts\n const sessRevokeMeta = mkMeta(opts, {\n DELETE: {\n description: 'Revoke a single active session by ID.',\n params: `{ id: 'sess_01HXZ' }`,\n response: `{ message: 'Session sess_01HXZ revoked' }`,\n },\n });\n const sessRevokeContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${sessRevokeMeta}${mwUser3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: revoke session by id\n res.json({ message: \\`Session \\${id} revoked\\` });\n};\n`\n : `${RA}${sessRevokeMeta}${mwUser3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: revoke session by id\n res.json({ message: \\`Session \\${id} revoked\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'sessions', `[id].${ext}`),\n sessRevokeContent,\n );\n }\n}\n\nasync function writeUserExtendedRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // user/* = 2 levels up to src/, user/subdir/* = 3 levels\n const mw2 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mw3 = mw2;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n const user = ts ? `(req as any).user` : `req.user`;\n const uf = opts.userFeatures;\n\n // avatar.ts\n if (uf.accountSettings) {\n const avatarMeta = mkMeta(opts, {\n POST: {\n description: 'Upload a new avatar image for the authenticated user.',\n response: `{ message: 'Avatar updated', url: 'https://example.com/avatar.jpg' }`,\n },\n DELETE: {\n description: \"Remove the authenticated user's avatar.\",\n response: `{ message: 'Avatar removed' }`,\n },\n });\n const avatarContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${avatarMeta}${mw2}\nexport const POST = async (req: Request, res: Response) => {\n // TODO: handle multipart upload, store file, update user.avatar\n res.json({ message: 'Avatar updated', url: 'https://example.com/avatar.jpg' });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n // TODO: remove avatar and clear user.avatar\n res.json({ message: 'Avatar removed' });\n};\n`\n : `${RA}${avatarMeta}${mw2}\nexport const POST = async (req, res) => {\n // TODO: handle multipart upload, store file, update user.avatar\n res.json({ message: 'Avatar updated', url: 'https://example.com/avatar.jpg' });\n};\n\nexport const DELETE = async (req, res) => {\n // TODO: remove avatar and clear user.avatar\n res.json({ message: 'Avatar removed' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `avatar.${ext}`), avatarContent);\n\n // settings.ts\n const settingsMeta = mkMeta(opts, {\n GET: {\n description:\n 'Get account settings (notifications, language, theme, privacy) for the authenticated user.',\n response: `{ settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } }`,\n },\n PUT: {\n description: 'Update account settings for the authenticated user.',\n request: `{ notifications: true, language: 'en', theme: 'system', privacy: 'public' }`,\n response: `{ message: 'Settings updated', settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } }`,\n },\n });\n const settingsContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${settingsMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user settings from DB\n res.json({ settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { notifications, language, theme, privacy } = req.body;\n // TODO: update user settings in DB\n res.json({ message: 'Settings updated', settings: { notifications, language, theme, privacy } });\n};\n`\n : `${RA}${settingsMeta}${mw2}\nexport const GET = async (req, res) => {\n // TODO: fetch user settings from DB\n res.json({ settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } });\n};\n\nexport const PUT = async (req, res) => {\n const { notifications, language, theme, privacy } = req.body;\n // TODO: update user settings in DB\n res.json({ message: 'Settings updated', settings: { notifications, language, theme, privacy } });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `settings.${ext}`), settingsContent);\n\n // account.ts\n const accountMeta = mkMeta(opts, {\n GET: {\n description: 'Download a personal data export for the authenticated user.',\n response: `{ data: { user: { id: '1', role: 'user', email: 'user@example.com' }, exportedAt: '2026-01-01T00:00:00.000Z' } }`,\n },\n DELETE: {\n description:\n 'Schedule the authenticated account for deletion (requires password confirmation).',\n request: `{ password: 'current' }`,\n response: `{ message: 'Account scheduled for deletion' }`,\n },\n });\n const accountContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${accountMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: compile and return personal data export\n res.json({ data: { user: ${user}, exportedAt: new Date().toISOString() } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { password } = req.body;\n if (!password) return res.status(400).json({ error: 'password confirmation required' });\n // TODO: verify password, schedule account deletion\n res.json({ message: 'Account scheduled for deletion' });\n};\n`\n : `${RA}${accountMeta}${mw2}\nexport const GET = async (req, res) => {\n // TODO: compile and return personal data export\n res.json({ data: { user: ${user}, exportedAt: new Date().toISOString() } });\n};\n\nexport const DELETE = async (req, res) => {\n const { password } = req.body;\n if (!password) return res.status(400).json({ error: 'password confirmation required' });\n // TODO: verify password, schedule account deletion\n res.json({ message: 'Account scheduled for deletion' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `account.${ext}`), accountContent);\n\n // dashboard.ts\n const dashMeta = mkMeta(opts, {\n GET: {\n description: 'Personal dashboard: stats, recent activity, and quick actions.',\n response: `{ stats: {}, recentActivity: [], quickActions: [] }`,\n },\n });\n const dashContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${dashMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: aggregate personal stats and activity\n res.json({ stats: {}, recentActivity: [], quickActions: [] });\n};\n`\n : `${RA}${dashMeta}${mw2}\nexport const GET = async (req, res) => {\n // TODO: aggregate personal stats and activity\n res.json({ stats: {}, recentActivity: [], quickActions: [] });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `dashboard.${ext}`), dashContent);\n\n // activity.ts\n const actMeta = mkMeta(opts, {\n GET: {\n description: 'Paginated activity history for the authenticated user.',\n query: `{ page: '1', limit: '20' }`,\n response: `{ activities: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const actContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${actMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n const { page = 1, limit = 20 } = req.query;\n // TODO: fetch paginated activity log\n res.json({ activities: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${actMeta}${mw2}\nexport const GET = async (req, res) => {\n const { page = 1, limit = 20 } = req.query;\n // TODO: fetch paginated activity log\n res.json({ activities: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `activity.${ext}`), actContent);\n }\n\n // notifications/index.ts\n if (uf.notifications) {\n const notifListMeta = mkMeta(opts, {\n GET: {\n description: 'List notifications for the authenticated user.',\n response: `{ notifications: [], total: 0, unread: 0 }`,\n },\n POST: {\n description: 'Mark all notifications as read for the authenticated user.',\n response: `{ message: 'All notifications marked as read' }`,\n },\n });\n const notifListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${notifListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch notifications for user\n res.json({ notifications: [], total: 0, unread: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n // TODO: mark all notifications as read\n res.json({ message: 'All notifications marked as read' });\n};\n`\n : `${RA}${notifListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch notifications for user\n res.json({ notifications: [], total: 0, unread: 0 });\n};\n\nexport const POST = async (req, res) => {\n // TODO: mark all notifications as read\n res.json({ message: 'All notifications marked as read' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'notifications', `index.${ext}`),\n notifListContent,\n );\n\n // notifications/[id].ts\n const notifByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single notification by ID.',\n params: `{ id: 'notif_01HXZ' }`,\n response: `{ notification: { id: 'notif_01HXZ' } }`,\n },\n PATCH: {\n description: 'Mark a single notification as read.',\n params: `{ id: 'notif_01HXZ' }`,\n response: `{ message: 'Notification marked as read', id: 'notif_01HXZ' }`,\n },\n DELETE: {\n description: 'Delete a single notification.',\n params: `{ id: 'notif_01HXZ' }`,\n response: `{ message: 'Notification notif_01HXZ deleted' }`,\n },\n });\n const notifByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${notifByIdMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: fetch notification by id\n res.json({ notification: { id } });\n};\n\nexport const PATCH = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: mark notification as read\n res.json({ message: 'Notification marked as read', id });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete notification\n res.json({ message: \\`Notification \\${id} deleted\\` });\n};\n`\n : `${RA}${notifByIdMeta}${mw3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: fetch notification by id\n res.json({ notification: { id } });\n};\n\nexport const PATCH = async (req, res) => {\n const { id } = req.params;\n // TODO: mark notification as read\n res.json({ message: 'Notification marked as read', id });\n};\n\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete notification\n res.json({ message: \\`Notification \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'notifications', `[id].${ext}`),\n notifByIdContent,\n );\n }\n\n // files/index.ts (files, favorites, bookmarks & search share the filesAndMedia toggle)\n if (uf.filesAndMedia) {\n const filesListMeta = mkMeta(opts, {\n GET: {\n description: 'List uploaded files with storage usage for the authenticated user.',\n response: `{ files: [], total: 0, storageUsed: 0 }`,\n },\n POST: {\n description: 'Upload a new file for the authenticated user.',\n response: `{ message: 'File uploaded', file: { id: 'new-id' } }`,\n status: 201,\n },\n });\n const filesListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${filesListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user files and compute storage usage\n res.json({ files: [], total: 0, storageUsed: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n // TODO: handle multipart upload, persist file record\n res.status(201).json({ message: 'File uploaded', file: { id: 'new-id' } });\n};\n`\n : `${RA}${filesListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch user files and compute storage usage\n res.json({ files: [], total: 0, storageUsed: 0 });\n};\n\nexport const POST = async (req, res) => {\n // TODO: handle multipart upload, persist file record\n res.status(201).json({ message: 'File uploaded', file: { id: 'new-id' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'files', `index.${ext}`),\n filesListContent,\n );\n\n // files/[id].ts\n const fileByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Get a download/preview URL for a single file by ID.',\n params: `{ id: 'file_01HXZ' }`,\n response: `{ file: { id: 'file_01HXZ', url: 'https://example.com/files/file_01HXZ' } }`,\n },\n DELETE: {\n description: 'Delete a file from storage.',\n params: `{ id: 'file_01HXZ' }`,\n response: `{ message: 'File file_01HXZ deleted' }`,\n },\n });\n const fileByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${fileByIdMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: stream or redirect to file download/preview URL\n res.json({ file: { id, url: 'https://...' } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete file from storage and DB\n res.json({ message: \\`File \\${id} deleted\\` });\n};\n`\n : `${RA}${fileByIdMeta}${mw3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: stream or redirect to file download/preview URL\n res.json({ file: { id, url: 'https://...' } });\n};\n\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete file from storage and DB\n res.json({ message: \\`File \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'files', `[id].${ext}`),\n fileByIdContent,\n );\n\n // favorites/index.ts\n const favListMeta = mkMeta(opts, {\n GET: {\n description: 'List favorites for the authenticated user.',\n response: `{ favorites: [] }`,\n },\n POST: {\n description: \"Add an entity to the authenticated user's favorites.\",\n request: `{ entityId: 'post_01HXZ', entityType: 'post' }`,\n response: `{ message: 'Added to favorites' }`,\n status: 201,\n },\n });\n const favListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${favListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user favorites\n res.json({ favorites: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { entityId, entityType } = req.body;\n if (!entityId || !entityType) return res.status(400).json({ error: 'entityId and entityType are required' });\n // TODO: add to favorites\n res.status(201).json({ message: 'Added to favorites' });\n};\n`\n : `${RA}${favListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch user favorites\n res.json({ favorites: [] });\n};\n\nexport const POST = async (req, res) => {\n const { entityId, entityType } = req.body;\n if (!entityId || !entityType) return res.status(400).json({ error: 'entityId and entityType are required' });\n // TODO: add to favorites\n res.status(201).json({ message: 'Added to favorites' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'favorites', `index.${ext}`),\n favListContent,\n );\n\n // favorites/[id].ts\n const favByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Remove an entity from the authenticated user favorites.',\n params: `{ id: 'fav_01HXZ' }`,\n response: `{ message: 'Removed favorite fav_01HXZ' }`,\n },\n });\n const favByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${favByIdMeta}${mw3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: remove from favorites\n res.json({ message: \\`Removed favorite \\${id}\\` });\n};\n`\n : `${RA}${favByIdMeta}${mw3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: remove from favorites\n res.json({ message: \\`Removed favorite \\${id}\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'favorites', `[id].${ext}`),\n favByIdContent,\n );\n\n // bookmarks/index.ts\n const bkListMeta = mkMeta(opts, {\n GET: {\n description: 'List bookmarks for the authenticated user.',\n response: `{ bookmarks: [] }`,\n },\n POST: {\n description: 'Save a new bookmark for the authenticated user.',\n request: `{ url: 'https://example.com', title: 'Example' }`,\n response: `{ message: 'Bookmark saved' }`,\n status: 201,\n },\n });\n const bkListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${bkListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user bookmarks\n res.json({ bookmarks: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { url, title } = req.body;\n if (!url) return res.status(400).json({ error: 'url is required' });\n // TODO: save bookmark\n res.status(201).json({ message: 'Bookmark saved' });\n};\n`\n : `${RA}${bkListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch user bookmarks\n res.json({ bookmarks: [] });\n};\n\nexport const POST = async (req, res) => {\n const { url, title } = req.body;\n if (!url) return res.status(400).json({ error: 'url is required' });\n // TODO: save bookmark\n res.status(201).json({ message: 'Bookmark saved' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'bookmarks', `index.${ext}`),\n bkListContent,\n );\n\n // bookmarks/[id].ts\n const bkByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Delete a bookmark by ID.',\n params: `{ id: 'bm_01HXZ' }`,\n response: `{ message: 'Bookmark bm_01HXZ removed' }`,\n },\n });\n const bkByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${bkByIdMeta}${mw3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete bookmark\n res.json({ message: \\`Bookmark \\${id} removed\\` });\n};\n`\n : `${RA}${bkByIdMeta}${mw3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete bookmark\n res.json({ message: \\`Bookmark \\${id} removed\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'bookmarks', `[id].${ext}`),\n bkByIdContent,\n );\n\n // search.ts\n const searchMeta = mkMeta(opts, {\n GET: {\n description: 'Search with filters, sort, and pagination.',\n query: `{ q: 'query', filter: 'active', sort: 'newest', page: '1', limit: '20' }`,\n response: `{ results: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const searchContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${searchMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n const { q, filter, sort, page = 1, limit = 20 } = req.query;\n // TODO: implement search\n res.json({ results: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${searchMeta}${mw2}\nexport const GET = async (req, res) => {\n const { q, filter, sort, page = 1, limit = 20 } = req.query;\n // TODO: implement search\n res.json({ results: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `search.${ext}`), searchContent);\n }\n\n // api-keys/index.ts\n if (uf.apiAndBilling) {\n const akListMeta = mkMeta(opts, {\n GET: {\n description: 'List API keys for the authenticated user.',\n response: `{ apiKeys: [] }`,\n },\n POST: {\n description: 'Generate a new API key for the authenticated user.',\n request: `{ name: 'CI key' }`,\n response: `{ message: 'API key created', key: 'efc_...' }`,\n status: 201,\n },\n });\n const akListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${akListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch api keys for user\n res.json({ apiKeys: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { name } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: generate and store API key\n res.status(201).json({ message: 'API key created', key: 'efc_...' });\n};\n`\n : `${RA}${akListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch api keys for user\n res.json({ apiKeys: [] });\n};\n\nexport const POST = async (req, res) => {\n const { name } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: generate and store API key\n res.status(201).json({ message: 'API key created', key: 'efc_...' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'api-keys', `index.${ext}`),\n akListContent,\n );\n\n // api-keys/[id].ts\n const akByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Revoke and delete an API key by ID.',\n params: `{ id: 'key_01HXZ' }`,\n response: `{ message: 'API key key_01HXZ revoked' }`,\n },\n });\n const akByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${akByIdMeta}${mw3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: revoke and delete API key\n res.json({ message: \\`API key \\${id} revoked\\` });\n};\n`\n : `${RA}${akByIdMeta}${mw3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: revoke and delete API key\n res.json({ message: \\`API key \\${id} revoked\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'api-keys', `[id].${ext}`),\n akByIdContent,\n );\n }\n}\n\nasync function writeUserBillingRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // user/billing/* = 3 levels, user/billing/subdir/* = 4 levels\n const mw3 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mw4 = mw3;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n\n // billing/plans.ts\n const plansMeta = mkMeta(opts, {\n GET: { description: 'List all available subscription plans.', response: `{ plans: [] }` },\n });\n const plansContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${plansMeta}${mw3}\nexport const GET = async (_req: Request, res: Response) => {\n // TODO: fetch active plans from DB\n res.json({ plans: [] });\n};\n`\n : `${RA}${plansMeta}${mw3}\nexport const GET = async (_req, res) => {\n // TODO: fetch active plans from DB\n res.json({ plans: [] });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', `plans.${ext}`),\n plansContent,\n );\n\n // billing/subscription.ts\n const subMeta = mkMeta(opts, {\n GET: {\n description: 'Get the current subscription for the authenticated user.',\n response: `{ subscription: null }`,\n },\n POST: {\n description: 'Subscribe the authenticated user to a plan.',\n request: `{ planId: 'plan_01HXZ' }`,\n response: `{ message: 'Subscribed', subscription: { planId: 'plan_01HXZ' } }`,\n status: 201,\n },\n DELETE: {\n description: 'Cancel the current subscription at period end.',\n response: `{ message: 'Subscription cancelled' }`,\n },\n });\n const subContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${subMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch current subscription for user\n res.json({ subscription: null });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { planId } = req.body;\n if (!planId) return res.status(400).json({ error: 'planId is required' });\n // TODO: create subscription via payment gateway\n res.status(201).json({ message: 'Subscribed', subscription: { planId } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n // TODO: cancel subscription at period end\n res.json({ message: 'Subscription cancelled' });\n};\n`\n : `${RA}${subMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch current subscription for user\n res.json({ subscription: null });\n};\n\nexport const POST = async (req, res) => {\n const { planId } = req.body;\n if (!planId) return res.status(400).json({ error: 'planId is required' });\n // TODO: create subscription via payment gateway\n res.status(201).json({ message: 'Subscribed', subscription: { planId } });\n};\n\nexport const DELETE = async (req, res) => {\n // TODO: cancel subscription at period end\n res.json({ message: 'Subscription cancelled' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', `subscription.${ext}`),\n subContent,\n );\n\n // billing/payment-methods/index.ts\n const pmListMeta = mkMeta(opts, {\n GET: {\n description: 'List payment methods for the authenticated user.',\n response: `{ paymentMethods: [] }`,\n },\n POST: {\n description: 'Attach a new payment method via the payment gateway.',\n request: `{ token: 'tok_...' }`,\n response: `{ message: 'Payment method added' }`,\n status: 201,\n },\n });\n const pmListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${pmListMeta}${mw4}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch payment methods for user\n res.json({ paymentMethods: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { token } = req.body;\n if (!token) return res.status(400).json({ error: 'payment token is required' });\n // TODO: attach payment method via payment gateway\n res.status(201).json({ message: 'Payment method added' });\n};\n`\n : `${RA}${pmListMeta}${mw4}\nexport const GET = async (req, res) => {\n // TODO: fetch payment methods for user\n res.json({ paymentMethods: [] });\n};\n\nexport const POST = async (req, res) => {\n const { token } = req.body;\n if (!token) return res.status(400).json({ error: 'payment token is required' });\n // TODO: attach payment method via payment gateway\n res.status(201).json({ message: 'Payment method added' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'payment-methods', `index.${ext}`),\n pmListContent,\n );\n\n // billing/payment-methods/[id].ts\n const pmByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Detach a payment method from the payment gateway.',\n params: `{ id: 'pm_01HXZ' }`,\n response: `{ message: 'Payment method pm_01HXZ removed' }`,\n },\n });\n const pmByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${pmByIdMeta}${mw4}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: detach payment method from payment gateway\n res.json({ message: \\`Payment method \\${id} removed\\` });\n};\n`\n : `${RA}${pmByIdMeta}${mw4}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: detach payment method from payment gateway\n res.json({ message: \\`Payment method \\${id} removed\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'payment-methods', `[id].${ext}`),\n pmByIdContent,\n );\n\n // billing/invoices/index.ts\n const invListMeta = mkMeta(opts, {\n GET: {\n description: 'List all invoices for the authenticated user.',\n response: `{ invoices: [], total: 0 }`,\n },\n });\n const invListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${invListMeta}${mw4}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch invoices for user\n res.json({ invoices: [], total: 0 });\n};\n`\n : `${RA}${invListMeta}${mw4}\nexport const GET = async (req, res) => {\n // TODO: fetch invoices for user\n res.json({ invoices: [], total: 0 });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'invoices', `index.${ext}`),\n invListContent,\n );\n\n // billing/invoices/[id].ts\n const invByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Get the download URL for a single invoice by ID.',\n params: `{ id: 'inv_01HXZ' }`,\n response: `{ invoice: { id: 'inv_01HXZ', downloadUrl: 'https://example.com/invoices/inv_01HXZ.pdf' } }`,\n },\n });\n const invByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${invByIdMeta}${mw4}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: return invoice PDF URL or inline data\n res.json({ invoice: { id, downloadUrl: 'https://...' } });\n};\n`\n : `${RA}${invByIdMeta}${mw4}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: return invoice PDF URL or inline data\n res.json({ invoice: { id, downloadUrl: 'https://...' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'invoices', `[id].${ext}`),\n invByIdContent,\n );\n}\n\nasync function writeSupportRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // support/tickets/* = 3 levels\n const mw3 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n\n // support/tickets/index.ts\n const ticketListMeta = mkMeta(opts, {\n GET: {\n description: \"List the authenticated user's own support tickets.\",\n response: `{ tickets: [], total: 0 }`,\n },\n POST: {\n description: 'Create a new support ticket.',\n request: `{ subject: 'Issue with login', message: 'I cannot log in', priority: 'normal' }`,\n response: `{ message: 'Ticket created', ticket: { id: 'new-id', subject: 'Issue with login', status: 'open' } }`,\n status: 201,\n },\n });\n const ticketListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${ticketListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch tickets for current user\n res.json({ tickets: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { subject, message, priority } = req.body;\n if (!subject || !message) return res.status(400).json({ error: 'subject and message are required' });\n // TODO: create support ticket in DB\n res.status(201).json({ message: 'Ticket created', ticket: { id: 'new-id', subject, status: 'open' } });\n};\n`\n : `${RA}${ticketListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch tickets for current user\n res.json({ tickets: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n const { subject, message, priority } = req.body;\n if (!subject || !message) return res.status(400).json({ error: 'subject and message are required' });\n // TODO: create support ticket in DB\n res.status(201).json({ message: 'Ticket created', ticket: { id: 'new-id', subject, status: 'open' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'support', 'tickets', `index.${ext}`),\n ticketListContent,\n );\n\n // support/tickets/[id].ts\n const ticketByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single support ticket by ID.',\n params: `{ id: 'tk_01HXZ' }`,\n response: `{ ticket: { id: 'tk_01HXZ', subject: 'Issue', status: 'open', replies: [] } }`,\n },\n PUT: {\n description: 'Add a reply to a support ticket or update its status.',\n params: `{ id: 'tk_01HXZ' }`,\n request: `{ reply: 'Thanks, resolved.', status: 'closed' }`,\n response: `{ message: 'Ticket updated', ticket: { id: 'tk_01HXZ', status: 'closed' } }`,\n },\n });\n const ticketByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${ticketByIdMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: fetch ticket by id, verify ownership\n res.json({ ticket: { id, subject: '', status: 'open', replies: [] } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { id } = req.params;\n const { reply, status } = req.body;\n // TODO: add reply or update status\n res.json({ message: 'Ticket updated', ticket: { id, status: status ?? 'open' } });\n};\n`\n : `${RA}${ticketByIdMeta}${mw3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: fetch ticket by id, verify ownership\n res.json({ ticket: { id, subject: '', status: 'open', replies: [] } });\n};\n\nexport const PUT = async (req, res) => {\n const { id } = req.params;\n const { reply, status } = req.body;\n // TODO: add reply or update status\n res.json({ message: 'Ticket updated', ticket: { id, status: status ?? 'open' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'support', 'tickets', `[id].${ext}`),\n ticketByIdContent,\n );\n}\n\nasync function writeAdminExtendedRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // depth: admin/subdir/* = 3, admin/subdir/subdir/* = 4, admin/users/[id]/* = 4\n const mwAdmin3 = opts.rbac\n ? `export const middlewares = [requireAuth('admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mwAdmin4 = mwAdmin3;\n const roleGuard = opts.rbac\n ? ''\n : ts\n ? ` const user = (req as any).user;\\n if (user?.role !== 'admin') return res.status(403).json({ error: 'Forbidden' });\\n`\n : ` const user = req.user;\\n if (user?.role !== 'admin') return res.status(403).json({ error: 'Forbidden' });\\n`;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n const af = opts.adminFeatures;\n\n // ── Analytics ──────────────────────────────────────────────────────────\n if (af.analytics) {\n // admin/analytics/index.ts\n const analyticsOverviewMeta = mkMeta(opts, {\n GET: {\n description: 'Analytics overview: users, revenue, traffic (admin only).',\n response: `{ users: {}, revenue: {}, traffic: {} }`,\n },\n });\n const analyticsOverviewContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsOverviewMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} // TODO: aggregate analytics overview\n res.json({ users: {}, revenue: {}, traffic: {} });\n};\n`\n : `${RA}${analyticsOverviewMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} // TODO: aggregate analytics overview\n res.json({ users: {}, revenue: {}, traffic: {} });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `index.${ext}`),\n analyticsOverviewContent,\n );\n\n const analyticsUsersMeta = mkMeta(opts, {\n GET: {\n description: 'User analytics: registrations, active users, churn (admin only).',\n query: `{ period: '30d' }`,\n response: `{ registrations: [], activeUsers: 0, churn: 0, period: '30d' }`,\n },\n });\n const analyticsUsersContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsUsersMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch user analytics for period\n res.json({ registrations: [], activeUsers: 0, churn: 0, period });\n};\n`\n : `${RA}${analyticsUsersMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch user analytics for period\n res.json({ registrations: [], activeUsers: 0, churn: 0, period });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `users.${ext}`),\n analyticsUsersContent,\n );\n\n const analyticsRevenueMeta = mkMeta(opts, {\n GET: {\n description: 'Revenue analytics: MRR, ARR, payment history (admin only).',\n query: `{ period: '30d' }`,\n response: `{ mrr: 0, arr: 0, history: [], period: '30d' }`,\n },\n });\n const analyticsRevenueContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsRevenueMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch revenue analytics for period\n res.json({ mrr: 0, arr: 0, history: [], period });\n};\n`\n : `${RA}${analyticsRevenueMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch revenue analytics for period\n res.json({ mrr: 0, arr: 0, history: [], period });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `revenue.${ext}`),\n analyticsRevenueContent,\n );\n\n const analyticsTrafficMeta = mkMeta(opts, {\n GET: {\n description: 'Traffic analytics: page views, devices, countries (admin only).',\n query: `{ period: '30d' }`,\n response: `{ pageViews: 0, devices: {}, countries: {}, period: '30d' }`,\n },\n });\n const analyticsTrafficContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsTrafficMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch traffic analytics for period\n res.json({ pageViews: 0, devices: {}, countries: {}, period });\n};\n`\n : `${RA}${analyticsTrafficMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch traffic analytics for period\n res.json({ pageViews: 0, devices: {}, countries: {}, period });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `traffic.${ext}`),\n analyticsTrafficContent,\n );\n }\n\n // ── User Actions ──────────────────────────────────────────────────────\n if (af.userManagement) {\n // admin/users/[id]/suspend.ts\n const suspendMeta = mkMeta(opts, {\n POST: {\n description: 'Suspend a user account (admin only).',\n params: `{ id: 'usr_01HXZ' }`,\n request: `{ reason: 'Terms of service violation' }`,\n response: `{ message: 'User usr_01HXZ suspended', reason: 'Terms of service violation' }`,\n },\n });\n const suspendContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${suspendMeta}${mwAdmin4}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const { reason } = req.body;\n // TODO: set user.isActive = false, log audit event\n res.json({ message: \\`User \\${id} suspended\\`, reason });\n};\n`\n : `${RA}${suspendMeta}${mwAdmin4}\nexport const POST = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const { reason } = req.body;\n // TODO: set user.isActive = false, log audit event\n res.json({ message: \\`User \\${id} suspended\\`, reason });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', '[id]', `suspend.${ext}`),\n suspendContent,\n );\n\n // admin/users/[id]/activate.ts\n const activateMeta = mkMeta(opts, {\n POST: {\n description: 'Reactivate a suspended user account (admin only).',\n params: `{ id: 'usr_01HXZ' }`,\n response: `{ message: 'User usr_01HXZ activated' }`,\n },\n });\n const activateContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${activateMeta}${mwAdmin4}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isActive = true, log audit event\n res.json({ message: \\`User \\${id} activated\\` });\n};\n`\n : `${RA}${activateMeta}${mwAdmin4}\nexport const POST = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isActive = true, log audit event\n res.json({ message: \\`User \\${id} activated\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', '[id]', `activate.${ext}`),\n activateContent,\n );\n\n // admin/users/[id]/verify.ts\n const verifyUserMeta = mkMeta(opts, {\n POST: {\n description: \"Mark a user's email as verified (admin only).\",\n params: `{ id: 'usr_01HXZ' }`,\n response: `{ message: 'User usr_01HXZ verified' }`,\n },\n });\n const verifyUserContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${verifyUserMeta}${mwAdmin4}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isVerified = true\n res.json({ message: \\`User \\${id} verified\\` });\n};\n`\n : `${RA}${verifyUserMeta}${mwAdmin4}\nexport const POST = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isVerified = true\n res.json({ message: \\`User \\${id} verified\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', '[id]', `verify.${ext}`),\n verifyUserContent,\n );\n\n // admin/users/export.ts\n const exportMeta = mkMeta(opts, {\n GET: {\n description: 'Export all users as a CSV download (admin only).',\n response: `'id,name,email,role,createdAt\\\\n'`,\n },\n });\n const exportContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${exportMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: generate CSV of all users and stream response\n res.setHeader('Content-Type', 'text/csv');\n res.setHeader('Content-Disposition', 'attachment; filename=\"users.csv\"');\n res.send('id,name,email,role,createdAt\\\\n');\n};\n`\n : `${RA}${exportMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: generate CSV of all users and stream response\n res.setHeader('Content-Type', 'text/csv');\n res.setHeader('Content-Disposition', 'attachment; filename=\"users.csv\"');\n res.send('id,name,email,role,createdAt\\\\n');\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', `export.${ext}`),\n exportContent,\n );\n }\n\n // ── Admins ────────────────────────────────────────────────────────────\n if (af.adminManagement) {\n // admin/admins/index.ts\n const adminsListMeta = mkMeta(opts, {\n GET: {\n description: 'List all admin accounts (admin only).',\n response: `{ admins: [], total: 0 }`,\n },\n POST: {\n description: 'Create a new admin account (admin only).',\n request: `{ name: 'Jane Doe', email: 'jane@example.com', role: 'admin' }`,\n response: `{ message: 'Admin created', admin: { id: 'new-id', name: 'Jane Doe', email: 'jane@example.com', role: 'admin' } }`,\n status: 201,\n },\n });\n const adminsListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminsListMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch admins from DB\n res.json({ admins: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { name, email, role } = req.body;\n if (!name || !email) return res.status(400).json({ error: 'name and email are required' });\n // TODO: create admin account\n res.status(201).json({ message: 'Admin created', admin: { id: 'new-id', name, email, role: role ?? 'admin' } });\n};\n`\n : `${RA}${adminsListMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch admins from DB\n res.json({ admins: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { name, email, role } = req.body;\n if (!name || !email) return res.status(400).json({ error: 'name and email are required' });\n // TODO: create admin account\n res.status(201).json({ message: 'Admin created', admin: { id: 'new-id', name, email, role: role ?? 'admin' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'admins', `index.${ext}`),\n adminsListContent,\n );\n\n // admin/admins/[id].ts\n const adminByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single admin account by ID (admin only).',\n params: `{ id: 'adm_01HXZ' }`,\n response: `{ admin: { id: 'adm_01HXZ' } }`,\n },\n PUT: {\n description: 'Update an admin account by ID (admin only).',\n params: `{ id: 'adm_01HXZ' }`,\n request: `{ name: 'Jane Doe', role: 'admin' }`,\n response: `{ message: 'Admin updated', admin: { id: 'adm_01HXZ', name: 'Jane Doe', role: 'admin' } }`,\n },\n DELETE: {\n description: 'Delete an admin account by ID (admin only).',\n params: `{ id: 'adm_01HXZ' }`,\n response: `{ message: 'Admin adm_01HXZ deleted' }`,\n },\n });\n const adminByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminByIdMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch admin by id\n res.json({ admin: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: update admin record\n res.json({ message: 'Admin updated', admin: { id, ...req.body } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete admin\n res.json({ message: \\`Admin \\${id} deleted\\` });\n};\n`\n : `${RA}${adminByIdMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch admin by id\n res.json({ admin: { id } });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: update admin record\n res.json({ message: 'Admin updated', admin: { id, ...req.body } });\n};\n\nexport const DELETE = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete admin\n res.json({ message: \\`Admin \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'admins', `[id].${ext}`),\n adminByIdContent,\n );\n\n // ── Roles (rbac only) ─────────────────────────────────────────────────\n\n if (opts.rbac) {\n const rolesListMeta = mkMeta(opts, {\n GET: { description: 'List all roles (admin only).', response: `{ roles: [] }` },\n POST: {\n description: 'Create a new role (admin only).',\n request: `{ name: 'editor', description: 'Can edit content', permissions: ['content:write'] }`,\n response: `{ message: 'Role created', role: { id: 'new-id', name: 'editor', permissions: ['content:write'] } }`,\n status: 201,\n },\n });\n const rolesListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${rolesListMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n // TODO: fetch all roles\n res.json({ roles: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { name, description, permissions } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: create role\n res.status(201).json({ message: 'Role created', role: { id: 'new-id', name, permissions: permissions ?? [] } });\n};\n`\n : `${RA}${rolesListMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n // TODO: fetch all roles\n res.json({ roles: [] });\n};\n\nexport const POST = async (req, res) => {\n const { name, description, permissions } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: create role\n res.status(201).json({ message: 'Role created', role: { id: 'new-id', name, permissions: permissions ?? [] } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'roles', `index.${ext}`),\n rolesListContent,\n );\n\n const roleByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single role by ID (admin only).',\n params: `{ id: 'role_01HXZ' }`,\n response: `{ role: { id: 'role_01HXZ', name: 'editor', permissions: ['content:write'] } }`,\n },\n PUT: {\n description: 'Update a role by ID (admin only).',\n params: `{ id: 'role_01HXZ' }`,\n request: `{ name: 'editor', permissions: ['content:write'] }`,\n response: `{ message: 'Role updated', role: { id: 'role_01HXZ', name: 'editor', permissions: ['content:write'] } }`,\n },\n DELETE: {\n description: 'Delete a role by ID (admin only).',\n params: `{ id: 'role_01HXZ' }`,\n response: `{ message: 'Role role_01HXZ deleted' }`,\n },\n });\n const roleByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${roleByIdMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: fetch role by id\n res.json({ role: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: update role\n res.json({ message: 'Role updated', role: { id, ...req.body } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete role\n res.json({ message: \\`Role \\${id} deleted\\` });\n};\n`\n : `${RA}${roleByIdMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: fetch role by id\n res.json({ role: { id } });\n};\n\nexport const PUT = async (req, res) => {\n const { id } = req.params;\n // TODO: update role\n res.json({ message: 'Role updated', role: { id, ...req.body } });\n};\n\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete role\n res.json({ message: \\`Role \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'roles', `[id].${ext}`),\n roleByIdContent,\n );\n }\n }\n\n // ── Notifications ─────────────────────────────────────────────────────\n if (af.notificationsAndLogs) {\n // admin/notifications/index.ts\n const adminNotifMeta = mkMeta(opts, {\n GET: {\n description: 'List all sent notifications (admin only).',\n response: `{ notifications: [], total: 0 }`,\n },\n POST: {\n description: 'Send a notification to a specific user (admin only).',\n request: `{ userId: 'usr_01HXZ', title: 'Welcome', message: 'Thanks for joining!', type: 'info' }`,\n response: `{ message: 'Notification sent' }`,\n status: 201,\n },\n });\n const adminNotifContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminNotifMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch sent notifications\n res.json({ notifications: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { userId, title, message, type } = req.body;\n if (!userId || !title || !message) return res.status(400).json({ error: 'userId, title and message are required' });\n // TODO: create and send notification to user\n res.status(201).json({ message: 'Notification sent' });\n};\n`\n : `${RA}${adminNotifMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch sent notifications\n res.json({ notifications: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { userId, title, message, type } = req.body;\n if (!userId || !title || !message) return res.status(400).json({ error: 'userId, title and message are required' });\n // TODO: create and send notification to user\n res.status(201).json({ message: 'Notification sent' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'notifications', `index.${ext}`),\n adminNotifContent,\n );\n\n // admin/notifications/broadcast.ts\n const broadcastMeta = mkMeta(opts, {\n POST: {\n description: 'Broadcast a notification to all users (admin only).',\n request: `{ title: 'Announcement', message: 'Hello everyone!', type: 'info' }`,\n response: `{ message: 'Broadcast sent', count: 0 }`,\n },\n });\n const broadcastContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${broadcastMeta}${mwAdmin3}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { title, message, type } = req.body;\n if (!title || !message) return res.status(400).json({ error: 'title and message are required' });\n // TODO: send notification to all users\n res.json({ message: 'Broadcast sent', count: 0 });\n};\n`\n : `${RA}${broadcastMeta}${mwAdmin3}\nexport const POST = async (req, res) => {\n${roleGuard} const { title, message, type } = req.body;\n if (!title || !message) return res.status(400).json({ error: 'title and message are required' });\n // TODO: send notification to all users\n res.json({ message: 'Broadcast sent', count: 0 });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'notifications', `broadcast.${ext}`),\n broadcastContent,\n );\n\n // ── Logs ──────────────────────────────────────────────────────────────\n\n const mkLogContent = (label: string) => {\n const meta = mkMeta(opts, {\n GET: {\n description: `Paginated ${label} log entries (admin only).`,\n query: `{ page: '1', limit: '50' }`,\n response: `{ logs: [], total: 0, page: 1, limit: 50 }`,\n },\n });\n return ts\n ? `${RA}import type { Request, Response } from 'express';\n${meta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { page = 1, limit = 50 } = req.query;\n // TODO: fetch ${label} logs with pagination\n res.json({ logs: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${meta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { page = 1, limit = 50 } = req.query;\n // TODO: fetch ${label} logs with pagination\n res.json({ logs: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n };\n\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'logs', `audit.${ext}`),\n mkLogContent('audit'),\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'logs', `activity.${ext}`),\n mkLogContent('activity'),\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'logs', `security.${ext}`),\n mkLogContent('security'),\n );\n }\n\n // ── Settings & System ─────────────────────────────────────────────────\n if (af.systemSettings) {\n // admin/settings/index.ts\n const settingsMeta = mkMeta(opts, {\n GET: { description: 'Get system-wide settings (admin only).', response: `{ settings: {} }` },\n PUT: {\n description: 'Update system-wide settings (admin only).',\n request: `{ maintenanceMode: false }`,\n response: `{ message: 'Settings updated', settings: { maintenanceMode: false } }`,\n },\n });\n const settingsContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${settingsMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch system settings from DB\n res.json({ settings: {} });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} // TODO: update system settings\n res.json({ message: 'Settings updated', settings: req.body });\n};\n`\n : `${RA}${settingsMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch system settings from DB\n res.json({ settings: {} });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} // TODO: update system settings\n res.json({ message: 'Settings updated', settings: req.body });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'settings', `index.${ext}`),\n settingsContent,\n );\n\n // admin/system/health.ts\n const healthMeta = mkMeta(opts, {\n GET: {\n description: 'System health check: DB, queue, cache status (admin only).',\n response: `{ status: 'ok', db: 'ok', queue: 'ok', uptime: 12345 }`,\n },\n });\n const healthContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${healthMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: check DB connection, queue, cache health\n res.json({ status: 'ok', db: 'ok', queue: 'ok', uptime: process.uptime() });\n};\n`\n : `${RA}${healthMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: check DB connection, queue, cache health\n res.json({ status: 'ok', db: 'ok', queue: 'ok', uptime: process.uptime() });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'system', `health.${ext}`),\n healthContent,\n );\n\n // admin/system/cache.ts\n const cacheMeta = mkMeta(opts, {\n DELETE: {\n description: 'Flush the application cache (admin only).',\n response: `{ message: 'Cache cleared' }`,\n },\n });\n const cacheContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${cacheMeta}${mwAdmin3}\nexport const DELETE = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: flush Redis or in-memory cache\n res.json({ message: 'Cache cleared' });\n};\n`\n : `${RA}${cacheMeta}${mwAdmin3}\nexport const DELETE = async (_req, res) => {\n${roleGuard} // TODO: flush Redis or in-memory cache\n res.json({ message: 'Cache cleared' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'system', `cache.${ext}`),\n cacheContent,\n );\n }\n\n // ── Support Tickets (admin view) ──────────────────────────────────────\n if (af.supportManagement) {\n // admin/tickets/index.ts\n const adminTicketsListMeta = mkMeta(opts, {\n GET: {\n description: 'List all support tickets with filters (admin only).',\n query: `{ status: 'open', priority: 'normal', page: '1', limit: '20' }`,\n response: `{ tickets: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const adminTicketsListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminTicketsListMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { status, priority, page = 1, limit = 20 } = req.query;\n // TODO: fetch all tickets with filters\n res.json({ tickets: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${adminTicketsListMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { status, priority, page = 1, limit = 20 } = req.query;\n // TODO: fetch all tickets with filters\n res.json({ tickets: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'tickets', `index.${ext}`),\n adminTicketsListContent,\n );\n\n // admin/tickets/[id].ts\n const adminTicketByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single support ticket by ID (admin only).',\n params: `{ id: 'tk_01HXZ' }`,\n response: `{ ticket: { id: 'tk_01HXZ' } }`,\n },\n PUT: {\n description: 'Assign, reply to, or change the status of a support ticket (admin only).',\n params: `{ id: 'tk_01HXZ' }`,\n request: `{ reply: 'Looking into it.', status: 'in_progress', assignedTo: 'adm_01HXZ' }`,\n response: `{ message: 'Ticket updated', ticket: { id: 'tk_01HXZ', status: 'in_progress', assignedTo: 'adm_01HXZ' } }`,\n },\n });\n const adminTicketByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminTicketByIdMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ticket by id\n res.json({ ticket: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const { reply, status, assignedTo } = req.body;\n // TODO: update ticket (assign, change status, add reply)\n res.json({ message: 'Ticket updated', ticket: { id, status, assignedTo } });\n};\n`\n : `${RA}${adminTicketByIdMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ticket by id\n res.json({ ticket: { id } });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const { reply, status, assignedTo } = req.body;\n // TODO: update ticket (assign, change status, add reply)\n res.json({ message: 'Ticket updated', ticket: { id, status, assignedTo } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'tickets', `[id].${ext}`),\n adminTicketByIdContent,\n );\n }\n\n // Shared by Content (FAQs/blogs/categories) and Billing (plans/coupons) below.\n const mkContentCrud = (name: string, namePlural: string, dir: string[], createFields: string) => {\n const lower = name.toLowerCase();\n const firstField = createFields.split(', ')[0];\n const sampleCreateBody = `{ ${createFields\n .split(', ')\n .map((f) => `${f}: 'sample-${f}'`)\n .join(', ')} }`;\n const sampleCreatedRecord = `{ id: 'new-id', ${firstField}: 'sample-${firstField}' }`;\n const sampleFullRecord = `{ id: '${lower}_01HXZ', ${createFields\n .split(', ')\n .map((f) => `${f}: 'sample-${f}'`)\n .join(', ')} }`;\n\n const listMeta = mkMeta(opts, {\n GET: {\n description: `List all ${namePlural} (admin only).`,\n response: `{ ${namePlural}: [], total: 0 }`,\n },\n POST: {\n description: `Create a new ${lower} (admin only).`,\n request: sampleCreateBody,\n response: `{ message: '${name} created', ${lower}: ${sampleCreatedRecord} }`,\n status: 201,\n },\n });\n const listContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${listMeta}${mwAdmin4}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch ${namePlural}\n res.json({ ${namePlural}: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { ${createFields} } = req.body;\n // TODO: create ${name}\n res.status(201).json({ message: '${name} created', ${lower}: { id: 'new-id', ${firstField} } });\n};\n`\n : `${RA}${listMeta}${mwAdmin4}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch ${namePlural}\n res.json({ ${namePlural}: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { ${createFields} } = req.body;\n // TODO: create ${name}\n res.status(201).json({ message: '${name} created', ${lower}: { id: 'new-id' } });\n};\n`;\n const byIdMeta = mkMeta(opts, {\n GET: {\n description: `Fetch a single ${lower} by ID (admin only).`,\n params: `{ id: '${lower}_01HXZ' }`,\n response: `{ ${lower}: ${sampleFullRecord} }`,\n },\n PUT: {\n description: `Update a ${lower} by ID (admin only).`,\n params: `{ id: '${lower}_01HXZ' }`,\n request: sampleCreateBody,\n response: `{ message: '${name} updated', ${lower}: ${sampleFullRecord} }`,\n },\n DELETE: {\n description: `Delete a ${lower} by ID (admin only).`,\n params: `{ id: '${lower}_01HXZ' }`,\n response: `{ message: '${name} ${lower}_01HXZ deleted' }`,\n },\n });\n const byIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${byIdMeta}${mwAdmin4}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ${name} by id\n res.json({ ${lower}: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: update ${name}\n res.json({ message: '${name} updated', ${lower}: { id, ...req.body } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete ${name}\n res.json({ message: \\`${name} \\${id} deleted\\` });\n};\n`\n : `${RA}${byIdMeta}${mwAdmin4}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ${name} by id\n res.json({ ${lower}: { id } });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: update ${name}\n res.json({ message: '${name} updated', ${lower}: { id, ...req.body } });\n};\n\nexport const DELETE = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete ${name}\n res.json({ message: \\`${name} \\${id} deleted\\` });\n};\n`;\n return { listContent, byIdContent };\n };\n\n // ── Content ───────────────────────────────────────────────────────────\n if (af.contentManagement) {\n const { listContent: faqList, byIdContent: faqById } = mkContentCrud(\n 'FAQ',\n 'faqs',\n [],\n 'question, answer, category',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'faqs', `index.${ext}`),\n faqList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'faqs', `[id].${ext}`),\n faqById,\n );\n\n const { listContent: blogList, byIdContent: blogById } = mkContentCrud(\n 'Blog',\n 'blogs',\n [],\n 'title, slug, content',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'blogs', `index.${ext}`),\n blogList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'blogs', `[id].${ext}`),\n blogById,\n );\n\n const { listContent: catList, byIdContent: catById } = mkContentCrud(\n 'Category',\n 'categories',\n [],\n 'name, slug',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'categories', `index.${ext}`),\n catList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'categories', `[id].${ext}`),\n catById,\n );\n }\n\n // ── Billing (admin) ───────────────────────────────────────────────────\n if (af.billingManagement) {\n const { listContent: planList, byIdContent: planById } = mkContentCrud(\n 'Plan',\n 'plans',\n [],\n 'name, price, interval',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'plans', `index.${ext}`),\n planList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'plans', `[id].${ext}`),\n planById,\n );\n\n const { listContent: couponList, byIdContent: couponById } = mkContentCrud(\n 'Coupon',\n 'coupons',\n [],\n 'code, type, value',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'coupons', `index.${ext}`),\n couponList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'coupons', `[id].${ext}`),\n couponById,\n );\n\n // admin/billing/subscriptions/index.ts\n const adminSubsMeta = mkMeta(opts, {\n GET: {\n description: 'List all subscriptions with filters (admin only).',\n query: `{ status: 'active', page: '1', limit: '20' }`,\n response: `{ subscriptions: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const adminSubsContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminSubsMeta}${mwAdmin4}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { status, page = 1, limit = 20 } = req.query;\n // TODO: fetch all subscriptions with filters\n res.json({ subscriptions: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${adminSubsMeta}${mwAdmin4}\nexport const GET = async (req, res) => {\n${roleGuard} const { status, page = 1, limit = 20 } = req.query;\n // TODO: fetch all subscriptions with filters\n res.json({ subscriptions: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'subscriptions', `index.${ext}`),\n adminSubsContent,\n );\n }\n}\n\n// defineTable apps: one import that registers every model (so `include` can reach any of\n// them) and, in TypeScript, the `Tables` map that types what `include` returns.\nasync function writeModelIndex(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ts = opts.language === 'typescript';\n const ext = ts ? 'ts' : 'js';\n const names = [...generatedModels(opts)].sort();\n if (names.length === 0) return;\n const exports = names.map((n) => `export { ${n} } from './${n}.js';`).join('\\n');\n const tables = ts\n ? `\n${names.map((n) => `import type { ${n} } from './${n}.js';`).join('\\n')}\n\n// Types \\`include\\` results: relations name models by string, this maps the names to models.\ndeclare module 'express-file-cluster' {\n interface Tables {\n${names.map((n) => ` ${n}: typeof ${n};`).join('\\n')}\n }\n}\n`\n : '';\n const content = `// Every model, in one import: \\`import { User } from '../model/index.js'\\` also registers the\n// models its relations reach, which \\`include\\` needs.\n${exports}\n${tables}`;\n await fs.outputFile(path.join(dest, 'src', 'model', `index.${ext}`), content);\n}\n\n// Tables before the tables that reference them (create in this order, drop in reverse).\nconst MODEL_ORDER = [\n 'User',\n 'Admin',\n 'Plan',\n 'Category',\n 'Role',\n 'FAQ',\n 'Coupon',\n 'OAuthAccount',\n 'Session',\n 'Notification',\n 'File',\n 'SupportTicket',\n 'AuditLog',\n 'Subscription',\n 'Invoice',\n 'ApiKey',\n 'Blog',\n];\n\n// Creates every generated model's table/collection (plus indexes) on `efc db migrate`.\n// Required on PostgreSQL before first boot; on MongoDB it builds the unique indexes.\nasync function writeInitMigration(dest: string, opts: ScaffoldOptions): Promise<void> {\n const modelDir = path.join(dest, 'src', 'model');\n if (!(await fs.pathExists(modelDir))) return;\n const ts = opts.language === 'typescript';\n const ext = ts ? 'ts' : 'js';\n const rank = (n: string) =>\n MODEL_ORDER.includes(n) ? MODEL_ORDER.indexOf(n) : MODEL_ORDER.length;\n const names = (await fs.readdir(modelDir))\n .filter((f) => f.endsWith(`.${ext}`) && f !== `index.${ext}`)\n .map((f) => f.slice(0, -(ext.length + 1)))\n .sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));\n if (names.length === 0) return;\n\n const imports = names.map((n) => `import { ${n} } from '../model/${n}.js';`).join('\\n');\n const typeImport = ts ? \"import type { MigrationContext } from 'express-file-cluster';\\n\" : '';\n const sig = ts ? '(_ctx: MigrationContext): Promise<void>' : '()';\n const content = `${typeImport}${imports}\n\nconst models = [${names.join(', ')}];\n\nexport async function up${sig} {\n for (const model of models) await model.sync();\n}\n\nexport async function down${sig} {\n for (const model of [...models].reverse()) await model.drop();\n}\n`;\n await fs.outputFile(path.join(dest, 'src', 'migrations', `00000000000000_init.${ext}`), content);\n}\n\n// ── OAuth sign-in (auth@google, auth@apple) ──────────────────────────────────────────────\n// Each provider gets a redirect route and a callback route; both share src/lib/oauth (state\n// cookie, find-or-create the user, sign in) and the OAuthAccount model, which links a\n// provider identity to a User — so signing in with a provider never changes User itself.\n\nasync function writeOAuthAccountModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\n// One row per provider identity (\"google:<sub>\"), linked to the User it signs in as.\nexport const OAuthAccount = ${modelApi(opts).name}('OAuthAccount', {\n key: { type: 'string', required: true, unique: true },\n provider: { type: 'string', required: true, enum: ['google', 'apple'] },\n providerId: { type: 'string', required: true },\n email: { type: 'string' },\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `OAuthAccount.${ext}`), content);\n}\n\nasync function writeOAuth(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ts = opts.language === 'typescript';\n const ext = ts ? 'ts' : 'js';\n const db = orm(opts);\n const T = (s: string) => (ts ? s : '');\n // defineTable: a real foreign key `user`; defineModel: the plain `userId` string.\n const userField = usesTables(opts) && generatedModels(opts).has('User') ? 'user' : 'userId';\n\n const lib = `import crypto from 'node:crypto';\nimport { HttpError } from 'express-file-cluster';\nimport { hashPassword, issueToken } from 'express-file-cluster/auth';\n${T(\"import type { Request, Response } from 'express';\\n\")}import { User } from '../model/User.js';\nimport { OAuthAccount } from '../model/OAuthAccount.js';\n\n// Shared by the OAuth sign-in routes (src/api/auth/<provider>/).\n\nconst STATE_TTL_MS = 10 * 60 * 1000; // a sign-in attempt has 10 minutes to come back\n${T(`\nexport interface OAuthState {\n state: string;\n nonce: string;\n verifier?: string;\n}\n\nexport interface OAuthProfile {\n provider: 'google' | 'apple';\n providerId: string;\n email?: string;\n emailVerified: boolean;\n name?: string;\n}\n`)}\n/** A random URL-safe string (state, nonce, PKCE verifier). */\nexport function randomToken()${T(': string')} {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/** The PKCE S256 challenge for a verifier. */\nexport function pkceChallenge(verifier${T(': string')})${T(': string')} {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\n/**\n * Remembers a sign-in attempt in a short-lived cookie until the provider redirects back.\n * \\`crossSite\\`: the provider POSTs the callback from its own site (Apple), so the cookie must\n * be SameSite=None — which browsers only accept with Secure (https, or localhost).\n */\nexport function rememberState(\n res${T(': Response')},\n provider${T(': string')},\n data${T(': OAuthState')},\n crossSite = false,\n)${T(': void')} {\n res.cookie(\\`efc_oauth_\\${provider}\\`, JSON.stringify(data), {\n httpOnly: true,\n secure: crossSite || process.env.NODE_ENV === 'production',\n sameSite: crossSite ? 'none' : 'lax',\n maxAge: STATE_TTL_MS,\n path: '/',\n });\n}\n\n/** The remembered attempt (cleared) — or undefined if \\`state\\` doesn't match it. */\nexport function takeState(\n req${T(': Request')},\n res${T(': Response')},\n provider${T(': string')},\n state${T(': unknown')},\n)${T(': OAuthState | undefined')} {\n const name = \\`efc_oauth_\\${provider}\\`;\n const raw = ${ts ? '(req as Request & { cookies?: Record<string, string> }).cookies?.[name]' : 'req.cookies?.[name]'};\n res.clearCookie(name, { path: '/' });\n if (!raw || typeof state !== 'string') return undefined;\n try {\n const saved = JSON.parse(raw)${T(' as OAuthState')};\n const a = Buffer.from(String(saved.state));\n const b = Buffer.from(state);\n return a.length === b.length && crypto.timingSafeEqual(a, b) ? saved : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Signs in the user behind a provider identity: the account already linked to it, else the\n * user with the same (provider-verified) email, else a new user. New users get a random\n * password — they can set a real one with the forgot-password flow.\n */\nexport async function signInWithOAuth(res${T(': Response')}, profile${T(': OAuthProfile')})${T(': Promise<void>')} {\n const key = \\`\\${profile.provider}:\\${profile.providerId}\\`;\n const account = await ${db.findOne('OAuthAccount', '{ key }')};\n let user = account ? await ${db.findById('User', `account.${userField}`)} : null;\n if (!user) {\n if (!profile.email || !profile.emailVerified) {\n throw new HttpError(400, \\`\\${profile.provider} did not return a verified email address\\`);\n }\n const email = profile.email;\n user =\n (await ${db.findOne('User', '{ email }')}) ??\n (await ${db.create(\n 'User',\n `{\n name: profile.name || email.split('@')[0],\n email,\n password: await hashPassword(randomToken()),\n isVerified: true,\n }`,\n )});\n if (account) await ${db.update('OAuthAccount', 'account.id', `{ ${userField}: user.id }`)};\n else {\n await ${db.create(\n 'OAuthAccount',\n `{\n key,\n provider: profile.provider,\n providerId: profile.providerId,\n email,\n ${userField}: user.id,\n }`,\n )};\n }\n }\n if (!user.isActive) throw new HttpError(403, 'Account suspended');\n await issueToken(res, { id: user.id, role: user.role, email: user.email });\n}\n\n/** Where the browser goes once signed in. */\nexport function successRedirect()${T(': string')} {\n return process.env.OAUTH_SUCCESS_REDIRECT || '/';\n}\n`;\n\n const reqRes = (r: string) => (ts ? `(${r}: Request, res: Response)` : `(${r}, res)`);\n const typeImport = T(\"import type { Request, Response } from 'express';\\n\");\n\n const meta = (method: string, description: string) =>\n `${ts ? \"import type { RouteMeta } from 'express-file-cluster';\\n\\n\" : ''}export const meta${T(': RouteMeta')} = {\\n ${method}: { description: '${description}' },\\n};\\n\\n`;\n\n const googleStart = `${typeImport}import { pkceChallenge, randomToken, rememberState } from '../../../lib/oauth.js';\n${meta('GET', 'Start \"Sign in with Google\": redirects to Google.')}// Redirects to Google's consent screen; Google sends the browser back to the callback route\n// (GOOGLE_REDIRECT_URI — register that exact URL in the Google Cloud console).\nexport const GET = async ${reqRes('_req')} => {\n const state = randomToken();\n const nonce = randomToken();\n const verifier = randomToken();\n rememberState(res, 'google', { state, nonce, verifier });\n const params = new URLSearchParams({\n client_id: process.env.GOOGLE_CLIENT_ID ?? '',\n redirect_uri: process.env.GOOGLE_REDIRECT_URI ?? '',\n response_type: 'code',\n scope: 'openid email profile',\n state,\n nonce,\n code_challenge: pkceChallenge(verifier),\n code_challenge_method: 'S256',\n prompt: 'select_account',\n });\n res.redirect(\\`https://accounts.google.com/o/oauth2/v2/auth?\\${params}\\`);\n};\n`;\n\n const googleCallback = `import { HttpError } from 'express-file-cluster';\nimport { createRemoteJWKSet, jwtVerify } from 'jose';\n${typeImport}import { signInWithOAuth, successRedirect, takeState } from '../../../lib/oauth.js';\n${meta('GET', 'Google redirects here after sign-in; signs the user in and redirects to OAUTH_SUCCESS_REDIRECT.')}const GOOGLE_KEYS = createRemoteJWKSet(new URL('https://www.googleapis.com/oauth2/v3/certs'));\n\nexport const GET = async ${reqRes('req')} => {\n const { code, state, error } = req.query;\n if (error) throw new HttpError(400, \\`Google sign-in failed: \\${String(error)}\\`);\n const saved = takeState(req, res, 'google', state);\n if (!saved || typeof code !== 'string') {\n throw new HttpError(400, 'Sign-in attempt expired or invalid — start again');\n }\n\n const tokens = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n code,\n client_id: process.env.GOOGLE_CLIENT_ID ?? '',\n client_secret: process.env.GOOGLE_CLIENT_SECRET ?? '',\n redirect_uri: process.env.GOOGLE_REDIRECT_URI ?? '',\n grant_type: 'authorization_code',\n code_verifier: saved.verifier ?? '',\n }),\n });\n if (!tokens.ok) throw new HttpError(502, \\`Google rejected the sign-in (\\${tokens.status})\\`);\n const { id_token } = (await tokens.json())${T(' as { id_token: string }')};\n\n const { payload } = await jwtVerify(id_token, GOOGLE_KEYS, {\n issuer: ['https://accounts.google.com', 'accounts.google.com'],\n audience: process.env.GOOGLE_CLIENT_ID ?? '',\n });\n if (payload.nonce !== saved.nonce) throw new HttpError(400, 'Invalid sign-in response');\n\n await signInWithOAuth(res, {\n provider: 'google',\n providerId: String(payload.sub),\n email: ${ts ? 'payload.email as string | undefined' : 'payload.email'},\n emailVerified: payload.email_verified === true,\n name: ${ts ? 'payload.name as string | undefined' : 'payload.name'},\n });\n res.redirect(successRedirect());\n};\n`;\n\n const appleStart = `${typeImport}import { randomToken, rememberState } from '../../../lib/oauth.js';\n${meta('GET', 'Start \"Sign in with Apple\": redirects to Apple.')}// Redirects to Apple; Apple POSTs the result to the callback route (APPLE_REDIRECT_URI —\n// register it on the Services ID; Apple only accepts https URLs on a verified domain).\nexport const GET = async ${reqRes('_req')} => {\n const state = randomToken();\n const nonce = randomToken();\n rememberState(res, 'apple', { state, nonce }, true);\n const params = new URLSearchParams({\n client_id: process.env.APPLE_CLIENT_ID ?? '',\n redirect_uri: process.env.APPLE_REDIRECT_URI ?? '',\n response_type: 'code',\n response_mode: 'form_post',\n scope: 'name email',\n state,\n nonce,\n });\n res.redirect(\\`https://appleid.apple.com/auth/authorize?\\${params}\\`);\n};\n`;\n\n const appleCallback = `import { HttpError } from 'express-file-cluster';\nimport { SignJWT, createRemoteJWKSet, importPKCS8, jwtVerify } from 'jose';\n${typeImport}import { signInWithOAuth, successRedirect, takeState } from '../../../lib/oauth.js';\n${meta('POST', 'Apple posts here after sign-in; signs the user in and redirects to OAUTH_SUCCESS_REDIRECT.')}const APPLE_KEYS = createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys'));\n\n// Apple's client secret is a short-lived ES256 JWT signed with your Sign in with Apple key\n// (APPLE_PRIVATE_KEY: the .p8 file's contents, newlines written as \\\\n).\nasync function clientSecret()${T(': Promise<string>')} {\n const key = await importPKCS8((process.env.APPLE_PRIVATE_KEY ?? '').replace(/\\\\\\\\n/g, '\\\\n'), 'ES256');\n return new SignJWT({})\n .setProtectedHeader({ alg: 'ES256', kid: process.env.APPLE_KEY_ID ?? '' })\n .setIssuer(process.env.APPLE_TEAM_ID ?? '')\n .setSubject(process.env.APPLE_CLIENT_ID ?? '')\n .setAudience('https://appleid.apple.com')\n .setIssuedAt()\n .setExpirationTime('5m')\n .sign(key);\n}\n\nexport const POST = async ${reqRes('req')} => {\n const { code, state, user, error } = req.body ?? {};\n if (error) throw new HttpError(400, \\`Apple sign-in failed: \\${String(error)}\\`);\n const saved = takeState(req, res, 'apple', state);\n if (!saved || typeof code !== 'string') {\n throw new HttpError(400, 'Sign-in attempt expired or invalid — start again');\n }\n\n const tokens = await fetch('https://appleid.apple.com/auth/token', {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n code,\n client_id: process.env.APPLE_CLIENT_ID ?? '',\n client_secret: await clientSecret(),\n redirect_uri: process.env.APPLE_REDIRECT_URI ?? '',\n grant_type: 'authorization_code',\n }),\n });\n if (!tokens.ok) throw new HttpError(502, \\`Apple rejected the sign-in (\\${tokens.status})\\`);\n const { id_token } = (await tokens.json())${T(' as { id_token: string }')};\n\n const { payload } = await jwtVerify(id_token, APPLE_KEYS, {\n issuer: 'https://appleid.apple.com',\n audience: process.env.APPLE_CLIENT_ID ?? '',\n });\n if (payload.nonce !== saved.nonce) throw new HttpError(400, 'Invalid sign-in response');\n\n // Apple sends the user's name once, on their first sign-in, as a JSON form field.\n let name${T(': string | undefined')};\n try {\n const n = typeof user === 'string' ? JSON.parse(user).name : undefined;\n name = [n?.firstName, n?.lastName].filter(Boolean).join(' ') || undefined;\n } catch {\n name = undefined;\n }\n\n await signInWithOAuth(res, {\n provider: 'apple',\n providerId: String(payload.sub),\n email: ${ts ? 'payload.email as string | undefined' : 'payload.email'},\n emailVerified: payload.email_verified === true || payload.email_verified === 'true',\n name,\n });\n res.redirect(303, successRedirect());\n};\n`;\n\n const oauth = opts.oauth ?? {};\n await fs.outputFile(path.join(dest, 'src', 'lib', `oauth.${ext}`), lib);\n if (oauth.google) {\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'google', `index.${ext}`),\n googleStart,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'google', `callback.${ext}`),\n googleCallback,\n );\n }\n if (oauth.apple) {\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', 'apple', `index.${ext}`), appleStart);\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'apple', `callback.${ext}`),\n appleCallback,\n );\n }\n}\n","import crypto from 'node:crypto';\nimport os from 'node:os';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { scaffold, NO_ADMIN_FEATURES, NO_USER_FEATURES, type ScaffoldOptions } from './scaffold.js';\n\n// The feature registry behind `efc add` (shadcn-style): the base app is the server, src/api,\n// src/tasks and the database; every feature is a registry item whose files are copied into\n// the app and owned by it from then on. Items are rendered from the same templates\n// `create-efc-app` uses, once per variant, by scaffolding in registry mode with and without\n// the item and taking the difference — see `renderVariant`.\n\nexport interface Variant {\n key: string;\n language: ScaffoldOptions['language'];\n database: ScaffoldOptions['database'];\n modelApi: 'defineModel' | 'defineTable';\n}\n\nexport const VARIANTS: Variant[] = (['typescript', 'javascript'] as const).flatMap((language) => {\n const lang = language === 'typescript' ? 'ts' : 'js';\n return [\n {\n key: `${lang}-mongo`,\n language,\n database: 'mongodb' as const,\n modelApi: 'defineModel' as const,\n },\n {\n key: `${lang}-pg-model`,\n language,\n database: 'postgresql' as const,\n modelApi: 'defineModel' as const,\n },\n {\n key: `${lang}-pg-table`,\n language,\n database: 'postgresql' as const,\n modelApi: 'defineTable' as const,\n },\n ];\n});\n\nexport function variantKey(v: Pick<Variant, 'language' | 'database' | 'modelApi'>): string {\n const found = VARIANTS.find(\n (x) =>\n x.language === v.language &&\n x.database === v.database &&\n (x.database === 'mongodb' || x.modelApi === v.modelApi),\n );\n if (!found) throw new Error(`No registry variant for ${JSON.stringify(v)}`);\n return found.key;\n}\n\nexport type ItemGroup = 'auth' | 'user' | 'admin' | 'integrations';\n\n/**\n * A question `efc add` / `create-efc-app` asks when an item is added. Answers named like an\n * env var (UPPER_CASE) are written to .env; lower-case names are choices that only steer\n * later questions (`when`) or set env vars through the chosen option's `env`.\n */\nexport interface ItemPrompt {\n name: string;\n message: string;\n type: 'text' | 'password' | 'select' | 'file';\n options?: { value: string; label: string; hint?: string; env?: Record<string, string> }[];\n /** Default answer; `{{NAME}}` is replaced with an earlier answer. */\n default?: string;\n placeholder?: string;\n /** Only ask when earlier answers match. */\n when?: Record<string, string>;\n required?: boolean;\n /** The answer (after `stripSpaces`) must match this regex. */\n pattern?: string;\n patternMessage?: string;\n stripSpaces?: boolean;\n /** Shown before the question. */\n note?: string;\n}\n\nexport interface ItemDef {\n name: string;\n /** Other names `efc add` accepts for this item. */\n aliases?: string[];\n /** Questions asked when the item is added (written to .env). */\n prompts?: ItemPrompt[];\n title: string;\n description: string;\n group: ItemGroup;\n /** Other items this one needs (installed first). */\n registryDependencies: string[];\n /** Base files this item replaces (e.g. the mailer's real SendEmail task). */\n replaces?: string[];\n /** Printed after `efc add`. */\n docs?: string;\n enable(o: ScaffoldOptions): void;\n}\n\nconst user =\n (flag: keyof ScaffoldOptions['userFeatures']) =>\n (o: ScaffoldOptions): void => {\n o.userPortal = true;\n o.userFeatures = { ...o.userFeatures, [flag]: true };\n };\nconst admin =\n (flag: keyof ScaffoldOptions['adminFeatures']) =>\n (o: ScaffoldOptions): void => {\n o.adminPortal = true;\n o.adminFeatures = { ...o.adminFeatures, [flag]: true };\n };\n\nexport const ITEMS: ItemDef[] = [\n {\n name: 'auth',\n title: 'Authentication',\n description: 'User & Admin models; register, login, logout and me routes',\n group: 'auth',\n registryDependencies: [],\n docs: \"Tokens are issued per `authStrategy` in efc.config — 'http-only' (cookie) or 'localStorage' (Bearer). Verification emails go through the SendEmail task; `efc add email-client` makes it send real mail.\",\n enable: (o) => {\n o.userPortal = true;\n },\n },\n {\n name: 'user-profile',\n title: 'Profile',\n description: 'GET/PUT /user/profile',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('profileViewing'),\n },\n {\n name: 'forgot-password',\n title: 'Forgot / reset password',\n description: 'forgot-password and reset-password routes',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('forgotPassword'),\n },\n {\n name: 'account-security',\n title: 'Account security',\n description: 'change password, 2FA, sessions, token refresh',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('accountSecurity'),\n },\n {\n name: 'email-verification',\n title: 'Email verification',\n description: 'verify-email and resend-verification routes',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('emailVerification'),\n },\n {\n name: 'account-settings',\n title: 'Account settings',\n description: 'avatar, settings, account, dashboard, activity',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('accountSettings'),\n },\n {\n name: 'notifications',\n title: 'Notifications',\n description: 'Notification model + /user/notifications',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('notifications'),\n },\n {\n name: 'files',\n title: 'Files, favorites & bookmarks',\n description: 'File model + files, favorites, bookmarks, search',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('filesAndMedia'),\n },\n {\n name: 'billing',\n title: 'API keys & billing',\n description: 'Plan, Subscription, Invoice, ApiKey models + user billing routes',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('apiAndBilling'),\n },\n {\n name: 'support',\n title: 'Support tickets',\n description: 'SupportTicket model + create & view own tickets',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('support'),\n },\n {\n name: 'admin',\n title: 'Admin portal',\n description: \"admin dashboard stats, behind requireAuth('admin')\",\n group: 'admin',\n registryDependencies: ['auth'],\n enable: (o) => {\n o.adminPortal = true;\n },\n },\n {\n name: 'admin-users',\n title: 'User management',\n description: 'list/create/suspend/verify/export users + stats',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('userManagement'),\n },\n {\n name: 'admin-admins',\n title: 'Admin & role management',\n description: 'manage other admins + Role model',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('adminManagement'),\n },\n {\n name: 'admin-analytics',\n title: 'Analytics',\n description: 'users, revenue, traffic dashboards',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('analytics'),\n },\n {\n name: 'admin-content',\n title: 'Content management',\n description: 'FAQ, Blog, Category models + admin routes',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('contentManagement'),\n },\n {\n name: 'admin-billing',\n title: 'Billing management',\n description: 'Plan, Coupon models + plans, coupons, subscriptions',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('billingManagement'),\n },\n {\n name: 'admin-support',\n title: 'Support desk',\n description: 'view & respond to support tickets',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('supportManagement'),\n },\n {\n name: 'admin-logs',\n title: 'Notifications & audit logs',\n description: 'broadcast + audit/activity/security logs',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('notificationsAndLogs'),\n },\n {\n name: 'admin-system',\n title: 'System settings & health',\n description: 'app settings, health check, cache',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('systemSettings'),\n },\n {\n name: 'auth@google',\n title: 'Sign in with Google',\n description: 'GET /auth/google → Google → /auth/google/callback (OpenID Connect + PKCE)',\n group: 'auth',\n registryDependencies: ['auth'],\n docs: 'Create an OAuth client (type \"Web application\") at console.cloud.google.com → APIs & Services → Credentials, and add GOOGLE_REDIRECT_URI as an authorised redirect URI. Send users to GET /v1/api/auth/google to sign in.',\n prompts: [\n {\n name: 'GOOGLE_CLIENT_ID',\n type: 'text',\n message: 'Google OAuth client ID:',\n placeholder: '1234-abc.apps.googleusercontent.com',\n required: true,\n pattern: '\\\\.apps\\\\.googleusercontent\\\\.com$',\n patternMessage: 'Google client IDs end in .apps.googleusercontent.com',\n note: 'console.cloud.google.com → APIs & Services → Credentials → Create credentials → OAuth client ID (Web application).',\n },\n {\n name: 'GOOGLE_CLIENT_SECRET',\n type: 'password',\n message: 'Google OAuth client secret:',\n required: true,\n },\n {\n name: 'GOOGLE_REDIRECT_URI',\n type: 'text',\n message: 'Redirect URI (register it on the client):',\n default: 'http://localhost:3000/v1/api/auth/google/callback',\n },\n {\n name: 'OAUTH_SUCCESS_REDIRECT',\n type: 'text',\n message: 'Where to send the browser after sign-in:',\n default: 'http://localhost:3000/',\n },\n ],\n enable: (o) => {\n o.userPortal = true;\n o.oauth = { ...o.oauth, google: true };\n },\n },\n {\n name: 'auth@apple',\n title: 'Sign in with Apple',\n description: 'GET /auth/apple → Apple → POST /auth/apple/callback (form_post)',\n group: 'auth',\n registryDependencies: ['auth'],\n docs: 'Needs a Services ID with Sign in with Apple enabled, its return URL set to APPLE_REDIRECT_URI (https, on a verified domain — Apple rejects localhost), and a Sign in with Apple key (.p8). Send users to GET /v1/api/auth/apple to sign in.',\n prompts: [\n {\n name: 'APPLE_CLIENT_ID',\n type: 'text',\n message: 'Services ID (client ID):',\n placeholder: 'com.yourapp.signin',\n required: true,\n note: 'developer.apple.com → Certificates, IDs & Profiles: a Services ID with Sign in with Apple, and a key with Sign in with Apple (.p8).',\n },\n {\n name: 'APPLE_TEAM_ID',\n type: 'text',\n message: 'Team ID:',\n required: true,\n pattern: '^[A-Z0-9]{10}$',\n patternMessage: 'Team IDs are 10 characters (A-Z, 0-9)',\n },\n {\n name: 'APPLE_KEY_ID',\n type: 'text',\n message: 'Key ID:',\n required: true,\n pattern: '^[A-Z0-9]{10}$',\n patternMessage: 'Key IDs are 10 characters (A-Z, 0-9)',\n },\n {\n name: 'APPLE_PRIVATE_KEY',\n type: 'file',\n message: 'Path to the .p8 key file:',\n placeholder: './AuthKey_ABCDE12345.p8',\n required: true,\n pattern: 'BEGIN PRIVATE KEY',\n patternMessage: \"That file doesn't look like a .p8 private key\",\n },\n {\n name: 'APPLE_REDIRECT_URI',\n type: 'text',\n message: 'Return URL (https, registered on the Services ID):',\n default: 'https://api.yourapp.com/v1/api/auth/apple/callback',\n pattern: '^https://',\n patternMessage: 'Apple only accepts https return URLs',\n },\n {\n name: 'OAUTH_SUCCESS_REDIRECT',\n type: 'text',\n message: 'Where to send the browser after sign-in:',\n default: 'http://localhost:3000/',\n },\n ],\n enable: (o) => {\n o.userPortal = true;\n o.oauth = { ...o.oauth, apple: true };\n },\n },\n {\n name: 'email-client',\n aliases: ['mailer'],\n title: 'Email client',\n description: 'SendEmail task over SMTP (nodemailer) — Gmail or any SMTP server',\n group: 'integrations',\n registryDependencies: [],\n replaces: ['src/tasks/SendEmail.ts', 'src/tasks/SendEmail.js'],\n docs: \"Every enqueue('SendEmail', { to, subject, body }) now sends real mail. Change SMTP settings in .env.\",\n prompts: [\n {\n name: 'provider',\n type: 'select',\n message: 'Email provider:',\n options: [\n {\n value: 'gmail',\n label: 'Gmail',\n hint: 'smtp.gmail.com, preconfigured',\n env: { SMTP_HOST: 'smtp.gmail.com', SMTP_PORT: '465' },\n },\n { value: 'custom', label: 'Other (custom SMTP)', hint: \"you'll provide host + port\" },\n ],\n },\n {\n name: 'SMTP_HOST',\n type: 'text',\n message: 'SMTP host:',\n placeholder: 'smtp.mailtrap.io',\n required: true,\n when: { provider: 'custom' },\n },\n {\n name: 'SMTP_PORT',\n type: 'text',\n message: 'SMTP port:',\n default: '587',\n when: { provider: 'custom' },\n },\n {\n name: 'SMTP_USER',\n type: 'text',\n message: 'Gmail address:',\n placeholder: 'you@gmail.com',\n required: true,\n when: { provider: 'gmail' },\n },\n {\n name: 'SMTP_USER',\n type: 'text',\n message: 'SMTP username / email:',\n placeholder: 'you@example.com',\n required: true,\n when: { provider: 'custom' },\n },\n {\n name: 'SMTP_PASS',\n type: 'password',\n message: 'Gmail app password (16 characters):',\n required: true,\n stripSpaces: true,\n pattern: '^\\\\S{16}$',\n patternMessage:\n 'Gmail app passwords are 16 characters — this looks like a regular password, not an app password',\n when: { provider: 'gmail' },\n note: 'Google no longer accepts your regular password for SMTP. Generate a 16-character App Password: Google Account → Security → 2-Step Verification → App passwords.',\n },\n {\n name: 'SMTP_PASS',\n type: 'password',\n message: 'SMTP password:',\n required: true,\n when: { provider: 'custom' },\n },\n { name: 'SMTP_FROM', type: 'text', message: 'From address:', default: '{{SMTP_USER}}' },\n {\n name: 'APP_URL',\n type: 'text',\n message: 'App URL (used in email links):',\n default: 'http://localhost:3000',\n },\n ],\n enable: (o) => {\n o.mailer = true;\n },\n },\n];\n\nconst BY_NAME = new Map(\n ITEMS.flatMap((i) => [i.name, ...(i.aliases ?? [])].map((n) => [n, i] as const)),\n);\n\nexport function getItem(name: string): ItemDef {\n const item = BY_NAME.get(name);\n if (!item) throw new Error(`Unknown registry item \"${name}\"`);\n return item;\n}\n\n/** `names` plus everything they depend on, dependencies first. */\nexport function withDependencies(names: Iterable<string>): string[] {\n const out: string[] = [];\n const visit = (alias: string, stack: string[]): void => {\n const name = getItem(alias).name;\n if (out.includes(name)) return;\n if (stack.includes(name)) throw new Error(`Dependency cycle: ${[...stack, name].join(' → ')}`);\n for (const dep of getItem(name).registryDependencies) visit(dep, [...stack, name]);\n out.push(name);\n };\n for (const name of names) visit(name, []);\n return out;\n}\n\n/**\n * Scaffold options for a registry-mode app of this variant with these items. The base is\n * the server, src/api, src/tasks and the database; everything else comes from the items.\n */\nexport function registryOptions(\n v: Pick<Variant, 'language' | 'database' | 'modelApi'>,\n items: Iterable<string> = [],\n extra: Partial<ScaffoldOptions> = {},\n): ScaffoldOptions {\n const o: ScaffoldOptions = {\n projectName: 'efc-app',\n language: v.language,\n database: v.database,\n ...(v.database === 'postgresql' && { modelApi: v.modelApi }),\n authStrategy: 'http-only',\n cluster: true,\n tasks: true,\n taskBackend: v.database === 'postgresql' ? 'pg-boss' : 'bullmq',\n routeDocs: true,\n userPortal: false,\n adminPortal: false,\n adminFeatures: { ...NO_ADMIN_FEATURES },\n userFeatures: { ...NO_USER_FEATURES },\n rbac: true,\n mailer: false,\n ...extra,\n registry: true,\n };\n for (const name of withDependencies(items)) getItem(name).enable(o);\n return o;\n}\n\n/**\n * Files the CLI owns or merges rather than copies: package.json and .env* are merged,\n * the model index and migrations are generated, the rest belongs to the base.\n */\nexport function isManagedPath(p: string): boolean {\n return (\n p === 'package.json' ||\n p === '.env' ||\n p === '.env.example' ||\n p === 'AGENTS.md' ||\n p === '.gitignore' ||\n p === 'tsconfig.json' ||\n /^efc\\.config\\.[jt]s$/.test(p) ||\n /^src\\/index\\.[jt]s$/.test(p) ||\n /^src\\/model\\/index\\.[jt]s$/.test(p) ||\n p.startsWith('src/migrations/')\n );\n}\n\nexport function sha256(content: string): string {\n return crypto.createHash('sha256').update(content).digest('hex');\n}\n\n/** Every file `scaffold(opts)` writes, keyed by POSIX path relative to the app. */\nexport async function renderTree(opts: ScaffoldOptions): Promise<Map<string, string>> {\n const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'efc-registry-'));\n // An absolute projectName makes scaffold() write there (no chdir — unavailable in workers).\n const root = path.join(tmp, opts.projectName);\n await scaffold({ ...opts, projectName: root });\n const out = new Map<string, string>();\n const walk = async (dir: string): Promise<void> => {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const abs = path.join(dir, entry.name);\n if (entry.isDirectory()) await walk(abs);\n else\n out.set(path.relative(root, abs).split(path.sep).join('/'), await fs.readFile(abs, 'utf8'));\n }\n };\n await walk(root);\n await fs.remove(tmp);\n return out;\n}\n\nexport interface EnvVar {\n key: string;\n /** Value written to .env. */\n value: string;\n /** Value written to .env.example. */\n example: string;\n}\n\nexport interface RenderedItem {\n name: string;\n files: { path: string; content: string }[];\n dependencies: Record<string, string>;\n devDependencies: Record<string, string>;\n env: EnvVar[];\n}\n\nexport interface RegistryIndexItem {\n name: string;\n title: string;\n description: string;\n group: ItemGroup;\n registryDependencies: string[];\n replaces: string[];\n aliases: string[];\n prompts: ItemPrompt[];\n docs?: string;\n /** Whether the item's routes enqueue tasks (needs a task backend). */\n requiresTasks: boolean;\n}\n\nexport function parseEnv(text: string | undefined): Map<string, string> {\n const out = new Map<string, string>();\n for (const line of (text ?? '').split('\\n')) {\n const m = /^([A-Z0-9_]+)=(.*)$/.exec(line);\n if (m) out.set(m[1]!, m[2]!);\n }\n return out;\n}\n\nfunction pkgDeps(text: string | undefined, field: 'dependencies' | 'devDependencies') {\n return (JSON.parse(text ?? '{}')[field] ?? {}) as Record<string, string>;\n}\n\nfunction added(a: Record<string, string>, b: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.entries(b).filter(([k]) => !(k in a)));\n}\n\n/**\n * Render every item of one variant. An item's files are what scaffolding with the item adds\n * to (or, for `replaces`, changes in) scaffolding with only its dependencies. Throws if an\n * item isn't self-contained: if it changes another item's or the base's files, or if its\n * files come out differently once every other item is installed too.\n */\nexport async function renderVariant(v: Variant): Promise<{\n /** The base app's own files (no package.json, .env, config or entry point). */\n base: { path: string; content: string }[];\n items: RenderedItem[];\n index: RegistryIndexItem[];\n}> {\n const cache = new Map<string, Promise<Map<string, string>>>();\n const render = (names: string[]) => {\n const key = withDependencies(names).sort().join(',');\n if (!cache.has(key)) cache.set(key, renderTree(registryOptions(v, names)));\n return cache.get(key)!;\n };\n\n const full = await render(ITEMS.map((i) => i.name));\n const base = await render([]);\n const claimed = new Set([...base.keys()].filter((p) => !isManagedPath(p)));\n const problems: string[] = [];\n const items: RenderedItem[] = [];\n const index: RegistryIndexItem[] = [];\n\n for (const item of ITEMS) {\n const before = await render(item.registryDependencies);\n const after = await render([item.name]);\n const files: { path: string; content: string }[] = [];\n for (const [p, content] of after) {\n if (isManagedPath(p) || before.get(p) === content) continue;\n if (before.has(p) && !item.replaces?.includes(p)) {\n problems.push(`${v.key}: ${item.name} changes ${p}, which its dependencies already write`);\n continue;\n }\n if (full.get(p) !== content) {\n problems.push(`${v.key}: ${item.name}'s ${p} depends on other items being installed`);\n }\n files.push({ path: p, content });\n claimed.add(p);\n }\n for (const p of before.keys()) {\n if (!after.has(p)) problems.push(`${v.key}: ${item.name} removes ${p}`);\n }\n for (const managed of ['AGENTS.md', 'tsconfig.json', '.gitignore']) {\n if (before.get(managed) !== after.get(managed)) {\n problems.push(`${v.key}: ${item.name} changes ${managed}`);\n }\n }\n for (const p of after.keys()) {\n if (/^(efc\\.config|src\\/index)\\.[jt]s$/.test(p) && before.get(p) !== after.get(p)) {\n problems.push(`${v.key}: ${item.name} changes ${p}`);\n }\n }\n\n const envBefore = parseEnv(before.get('.env'));\n const envAfter = parseEnv(after.get('.env'));\n const exampleAfter = parseEnv(after.get('.env.example'));\n const env: EnvVar[] = [...envAfter]\n .filter(([k]) => !envBefore.has(k))\n .map(([key, value]) => ({ key, value, example: exampleAfter.get(key) ?? value }));\n\n files.sort((a, b) => a.path.localeCompare(b.path));\n items.push({\n name: item.name,\n files,\n dependencies: added(\n pkgDeps(before.get('package.json'), 'dependencies'),\n pkgDeps(after.get('package.json'), 'dependencies'),\n ),\n devDependencies: added(\n pkgDeps(before.get('package.json'), 'devDependencies'),\n pkgDeps(after.get('package.json'), 'devDependencies'),\n ),\n env,\n });\n index.push({\n name: item.name,\n title: item.title,\n description: item.description,\n group: item.group,\n registryDependencies: item.registryDependencies,\n replaces: item.replaces ?? [],\n aliases: item.aliases ?? [],\n prompts: item.prompts ?? [],\n ...(item.docs ? { docs: item.docs } : {}),\n requiresTasks: files.some(\n (f) =>\n f.content.includes(\"from 'express-file-cluster/tasks'\") && /\\benqueue\\(/.test(f.content),\n ),\n });\n }\n\n for (const p of full.keys()) {\n if (!isManagedPath(p) && !claimed.has(p)) problems.push(`${v.key}: no item owns ${p}`);\n }\n if (problems.length)\n throw new Error(`Registry items aren't self-contained:\\n ${problems.join('\\n ')}`);\n const baseFiles = [...base]\n .filter(([p]) => !isManagedPath(p))\n .map(([p, content]) => ({ path: p, content }))\n .sort((a, b) => a.path.localeCompare(b.path));\n return { base: baseFiles, items, index };\n}\n\n/**\n * efc.json for a freshly scaffolded app: its variant, the items it was created with, and the\n * hash of every file efc wrote — so `efc add` can later tell untouched files from changed ones.\n */\nexport async function writeManifest(\n dest: string,\n opts: ScaffoldOptions,\n items: string[],\n): Promise<void> {\n const pkg = (await fs.readJson(path.join(dest, 'package.json'))) as {\n dependencies: Record<string, string>;\n };\n const files: Record<string, string> = {};\n const walk = async (dir: string): Promise<void> => {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n if (entry.name === 'node_modules') continue;\n const abs = path.join(dir, entry.name);\n if (entry.isDirectory()) await walk(abs);\n else {\n const rel = path.relative(dest, abs).split(path.sep).join('/');\n if (!isManagedPath(rel)) files[rel] = sha256(await fs.readFile(abs, 'utf8'));\n }\n }\n };\n await walk(dest);\n const manifest = {\n registry: (pkg.dependencies['express-file-cluster'] ?? '').replace(/^[^\\d]*/, ''),\n language: opts.language,\n database: opts.database,\n modelApi: opts.database === 'postgresql' ? (opts.modelApi ?? 'defineTable') : 'defineModel',\n tasks: opts.tasks ? (opts.taskBackend ?? 'bullmq') : null,\n items: [...withDependencies(items)].sort(),\n files: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b))),\n };\n await fs.writeFile(path.join(dest, 'efc.json'), JSON.stringify(manifest, null, 2) + '\\n');\n}\n\n// ── Item prompts (same rules as `efc add` in core's src/cli/registry.ts) ──────────────────\n\nexport type PromptAnswers = Record<string, string>;\n\nconst isEnvName = (name: string): boolean => /^[A-Z][A-Z0-9_]*$/.test(name);\n\n/** Whether a prompt applies, given the answers so far. */\nexport function promptApplies(p: ItemPrompt, answers: PromptAnswers): boolean {\n return Object.entries(p.when ?? {}).every(([k, v]) => answers[k] === v);\n}\n\n/** The default for a prompt, with `{{NAME}}` filled in from earlier answers. */\nexport function promptDefault(p: ItemPrompt, answers: PromptAnswers): string | undefined {\n return p.default?.replace(/\\{\\{(\\w+)\\}\\}/g, (_, k: string) => answers[k] ?? '');\n}\n\n/** The stored value for an answer, or why it's not acceptable. */\nexport function normalizeAnswer(\n p: ItemPrompt,\n raw: string,\n cwd: string = process.cwd(),\n): { value: string } | { error: string } {\n let value = p.stripSpaces ? raw.replace(/\\s/g, '') : raw.trim();\n if (!value) return p.required ? { error: 'Required' } : { value };\n if (p.type === 'file') {\n const file = path.resolve(cwd, value.replace(/^~(?=$|\\/)/, os.homedir()));\n if (!fs.existsSync(file)) return { error: `No such file: ${file}` };\n value = fs.readFileSync(file, 'utf8').trim();\n }\n if (p.pattern && !new RegExp(p.pattern).test(value)) {\n return { error: p.patternMessage ?? `Must match ${p.pattern}` };\n }\n if (p.type === 'file') value = value.replace(/\\r?\\n/g, '\\\\n');\n return { value };\n}\n\n/** Env values from the answers: answers named like env vars, plus what chosen options set. */\nexport function envFromAnswers(\n prompts: ItemPrompt[],\n answers: PromptAnswers,\n): Record<string, string> {\n const env: Record<string, string> = {};\n for (const p of prompts) {\n if (!(p.name in answers) || !promptApplies(p, answers)) continue;\n if (isEnvName(p.name)) env[p.name] = answers[p.name]!;\n const chosen = p.options?.find((o) => o.value === answers[p.name]);\n Object.assign(env, chosen?.env ?? {});\n }\n return env;\n}\n\n/** The prompts of these items, in order, without repeats. */\nexport function itemPrompts(items: string[]): ItemPrompt[] {\n const out: ItemPrompt[] = [];\n for (const name of items) {\n for (const p of getItem(name).prompts ?? []) {\n const dup = out.some(\n (q) => q.name === p.name && JSON.stringify(q.when) === JSON.stringify(p.when),\n );\n if (!dup) out.push(p);\n }\n }\n return out;\n}\n\n/** Sets vars in a .env file: replaces their lines, appends the rest. */\nexport async function setEnvValues(file: string, env: Record<string, string>): Promise<void> {\n const line = (k: string, v: string) =>\n !/[\\s#\"'`]/.test(v)\n ? `${k}=${v}`\n : v.includes(\"'\")\n ? `${k}=\"${v.replace(/\"/g, '\\\\\"')}\"`\n : `${k}='${v}'`;\n const lines = (await fs.pathExists(file)) ? (await fs.readFile(file, 'utf8')).split('\\n') : [];\n const rest = { ...env };\n const out = lines.map((l) => {\n const key = /^([A-Za-z0-9_]+)=/.exec(l)?.[1];\n if (key === undefined || !(key in rest)) return l;\n const v = rest[key]!;\n delete rest[key];\n return line(key, v);\n });\n for (const [k, v] of Object.entries(rest)) out.push(line(k, v));\n await fs.writeFile(file, out.join('\\n'));\n}\n"],"mappings":"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","names":["path","user","admin","crypto","path","fs","p","crypto","fs","path","p","cancel","modelApi","r","spinner","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/scaffold.ts","../src/registry.ts"],"sourcesContent":["import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport { scaffold, type ScaffoldOptions } from './scaffold.js';\nimport {\n AUTH_STRATEGY_OPTIONS,\n ITEMS,\n envFromAnswers,\n itemPrompts,\n normalizeAnswer,\n promptApplies,\n promptDefault,\n registryOptions,\n setEnvValues,\n withDependencies,\n writeManifest,\n type PromptAnswers,\n} from './registry.js';\n\nfunction cancel(msg = 'Cancelled'): never {\n p.cancel(msg);\n process.exit(0);\n}\n\nasync function main(): Promise<void> {\n console.log();\n p.intro(pc.bgCyan(pc.black(' create-efc-app ')));\n\n const projectName = await p.text({\n message: 'Project name:',\n placeholder: 'my-api',\n defaultValue: 'my-api',\n validate: (v) => (!v.trim() ? 'Project name is required' : undefined),\n });\n if (p.isCancel(projectName)) cancel();\n\n const language = await p.select({\n message: 'Language:',\n options: [\n { value: 'typescript', label: 'TypeScript', hint: 'recommended' },\n { value: 'javascript', label: 'JavaScript' },\n ],\n });\n if (p.isCancel(language)) cancel();\n\n const database = await p.select({\n message: 'Database:',\n options: [\n { value: 'mongodb', label: 'MongoDB', hint: 'Mongoose' },\n { value: 'postgresql', label: 'PostgreSQL', hint: 'Drizzle ORM' },\n ],\n });\n if (p.isCancel(database)) cancel();\n\n const api = await p.select({\n message: 'Models:',\n options:\n database === 'postgresql'\n ? [\n {\n value: 'defineTable',\n label: 'defineTable',\n hint: 'PostgreSQL-native — foreign keys, relations, include, Prisma-style queries',\n },\n { value: 'defineModel', label: 'defineModel', hint: 'portable — the same API on MongoDB' },\n ]\n : [\n {\n value: 'defineCollection',\n label: 'defineCollection',\n hint: 'MongoDB-native — mongoose-style queries, typed pipelines, BSON types',\n },\n {\n value: 'defineModel',\n label: 'defineModel',\n hint: 'portable — the same API on PostgreSQL',\n },\n ],\n });\n if (p.isCancel(api)) cancel();\n const modelApi = api as ScaffoldOptions['modelApi'];\n\n // pg-boss keeps jobs in the app's own PostgreSQL; BullMQ needs Redis.\n const taskBackend = await p.select({\n message: 'Task queue backend:',\n options:\n database === 'postgresql'\n ? [\n { value: 'pg-boss', label: 'pg-boss', hint: 'uses your PostgreSQL — no Redis' },\n { value: 'bullmq', label: 'BullMQ', hint: 'Redis' },\n ]\n : [{ value: 'bullmq', label: 'BullMQ', hint: 'Redis' }],\n });\n if (p.isCancel(taskBackend)) cancel();\n\n const cluster = await p.confirm({\n message: 'Multi-core clustering? (one worker per CPU in production)',\n initialValue: true,\n });\n if (p.isCancel(cluster)) cancel();\n\n // The base app is the server, src/api, src/tasks and the database. Features are registry\n // items — the same ones `efc add` installs later.\n const groupLabel: Record<string, string> = {\n auth: 'Auth',\n user: 'User portal',\n admin: 'Admin portal',\n integrations: 'Integrations',\n };\n const groups: Record<string, { value: string; label: string; hint: string }[]> = {};\n for (const item of ITEMS) {\n (groups[groupLabel[item.group]!] ??= []).push({\n value: item.name,\n label: item.title,\n hint: item.description,\n });\n }\n // Asked up front, not only when an auth feature is ticked — it decides how every client\n // (browser, mobile app) talks to the API.\n const auth = await p.select({\n message: 'Authentication:',\n options: [\n ...AUTH_STRATEGY_OPTIONS,\n { value: 'none', label: 'None', hint: 'add it later with `efc add auth`' },\n ],\n });\n if (p.isCancel(auth)) cancel();\n\n const picked = await p.groupMultiselect({\n message: `Add features now? ${pc.dim('(space to toggle, enter to confirm — or add any later with `efc add <item>`)')}`,\n options: groups,\n initialValues: auth === 'none' ? [] : ['auth'],\n required: false,\n });\n if (p.isCancel(picked)) cancel();\n const items = withDependencies(picked as string[]);\n\n // Each feature's own questions (SMTP for the email client, OAuth credentials…) — the same\n // ones `efc add` asks. Answers named like env vars go into .env.\n const answers: PromptAnswers = auth === 'none' ? {} : { authStrategy: auth as string };\n const prompts = itemPrompts(items);\n for (const q of prompts) {\n if (q.name in answers || !promptApplies(q, answers)) continue;\n if (q.note) p.note(q.note);\n if (q.type === 'select') {\n const choice = await p.select({\n message: q.message,\n options: (q.options ?? []).map((o) => ({\n value: o.value,\n label: o.label,\n ...(o.hint !== undefined && { hint: o.hint }),\n })),\n });\n if (p.isCancel(choice)) cancel();\n answers[q.name] = choice as string;\n continue;\n }\n const def = promptDefault(q, answers);\n const check = (v: string) => {\n const r = normalizeAnswer(q, v.trim() === '' ? (def ?? '') : v);\n return 'error' in r ? r.error : undefined;\n };\n const raw =\n q.type === 'password'\n ? await p.password({ message: q.message, validate: check })\n : await p.text({\n message: q.message,\n ...(q.placeholder !== undefined && { placeholder: q.placeholder }),\n ...(def !== undefined && { placeholder: def, defaultValue: def }),\n validate: check,\n });\n if (p.isCancel(raw)) cancel();\n const r = normalizeAnswer(q, (raw as string).trim() === '' ? (def ?? '') : (raw as string));\n answers[q.name] = 'value' in r ? r.value : '';\n }\n const env = envFromAnswers(prompts, answers);\n\n const opts = registryOptions(\n {\n language: language as ScaffoldOptions['language'],\n database: database as ScaffoldOptions['database'],\n modelApi: modelApi ?? 'defineModel',\n },\n items,\n {\n projectName: projectName as string,\n authStrategy: (answers['authStrategy'] ?? 'http-only') as ScaffoldOptions['authStrategy'],\n cluster: cluster as boolean,\n taskBackend: taskBackend as 'bullmq' | 'pg-boss',\n ...(answers['provider'] === 'custom' && { smtpProvider: 'custom' as const }),\n },\n );\n\n const spinner = p.spinner();\n spinner.start('Scaffolding project…');\n\n try {\n await scaffold(opts);\n if (Object.keys(env).length) {\n await setEnvValues(path.resolve(process.cwd(), opts.projectName, '.env'), env);\n }\n await writeManifest(path.resolve(process.cwd(), opts.projectName), opts, items);\n spinner.stop('Project created');\n } catch (err) {\n spinner.stop('Failed to scaffold project');\n console.error(err);\n process.exit(1);\n }\n\n spinner.start('Installing dependencies…');\n await npmInstall(projectName as string);\n spinner.stop('Dependencies installed');\n\n spinner.start('Installing efc CLI globally…');\n await npmInstallGlobal().catch(() => {\n /* non-fatal */\n });\n spinner.stop('efc CLI ready');\n\n const secrets = Object.keys(env).filter((k) => /PASS|SECRET|PRIVATE_KEY/.test(k));\n if (secrets.length) {\n p.note(\n `${secrets.join(', ')} ${secrets.length > 1 ? 'were' : 'was'} written to ${projectName as string}/.env — that file is gitignored, never commit it.\\n` +\n 'Rotate any of them immediately if it is ever exposed.',\n 'Credentials',\n );\n }\n\n if (opts.database === 'postgresql') {\n // EFC creates tables, but not the database or the login — the most common first-run error.\n const db = path.basename(opts.projectName);\n p.note(\n `.env points DATABASE_URL at postgresql://localhost:5432/${db}, with no user or password.\\n` +\n 'EFC creates the tables on first use, but not the database or the login:\\n' +\n ` • Local server: createdb ${db} (add user:password@ to the URL if it asks for one)\\n` +\n ' • Neon, Supabase, RDS: create the database in the dashboard and paste its full\\n' +\n ' connection string into .env as DATABASE_URL',\n 'PostgreSQL',\n );\n }\n\n // Tables (PostgreSQL) and collections/indexes (MongoDB) are created on first use, so\n // there's nothing to set up before the first run; migrations are there when wanted.\n p.outro(\n pc.green(`\\nYour project is ready!\\n\\n`) +\n pc.dim(` cd ${projectName as string}\\n`) +\n pc.dim(` efc start dev\\n`) +\n pc.dim(`\\n (or: npm run dev)\\n`) +\n pc.dim(`\\n Add features any time: efc list · efc add <item>\\n`),\n );\n}\n\nfunction npmInstall(projectDir: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['install'], { cwd: projectDir, stdio: 'ignore' });\n child.on('exit', (code) => (code === 0 ? resolve() : reject(new Error('npm install failed'))));\n });\n}\n\nfunction npmInstallGlobal(): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['install', '-g', 'express-file-cluster'], { stdio: 'ignore' });\n child.on('exit', (code) =>\n code === 0 ? resolve() : reject(new Error('global install failed')),\n );\n });\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n","import fs from 'fs-extra';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\n\nexport interface AdminFeatures {\n userManagement: boolean;\n adminManagement: boolean;\n analytics: boolean;\n contentManagement: boolean;\n billingManagement: boolean;\n supportManagement: boolean;\n notificationsAndLogs: boolean;\n systemSettings: boolean;\n}\n\nexport interface UserFeatures {\n profileViewing: boolean;\n forgotPassword: boolean;\n accountSecurity: boolean;\n emailVerification: boolean;\n accountSettings: boolean;\n notifications: boolean;\n filesAndMedia: boolean;\n apiAndBilling: boolean;\n support: boolean;\n}\n\nexport const NO_ADMIN_FEATURES: AdminFeatures = {\n userManagement: false,\n adminManagement: false,\n analytics: false,\n contentManagement: false,\n billingManagement: false,\n supportManagement: false,\n notificationsAndLogs: false,\n systemSettings: false,\n};\n\nexport const NO_USER_FEATURES: UserFeatures = {\n profileViewing: false,\n forgotPassword: false,\n accountSecurity: false,\n emailVerification: false,\n accountSettings: false,\n notifications: false,\n filesAndMedia: false,\n apiAndBilling: false,\n support: false,\n};\n\nexport interface ScaffoldOptions {\n projectName: string;\n language: 'typescript' | 'javascript';\n database: 'mongodb' | 'postgresql';\n authStrategy: 'http-only' | 'bearer';\n cluster: boolean;\n tasks: boolean;\n taskBackend?: 'bullmq' | 'pg-boss';\n routeDocs: boolean;\n userPortal: boolean;\n adminPortal: boolean;\n adminFeatures: AdminFeatures;\n userFeatures: UserFeatures;\n rbac: boolean;\n mailer: boolean;\n smtpProvider?: 'gmail' | 'custom';\n smtpHost?: string;\n smtpPort?: string;\n smtpUser?: string;\n smtpPass?: string;\n /**\n * Model API on PostgreSQL: `defineTable` (default — foreign keys, relations, Prisma-style\n * queries) or the portable `defineModel` (same API as on MongoDB). MongoDB always uses\n * `defineModel`.\n */\n /** PostgreSQL: defineTable (default) | defineModel. MongoDB: defineCollection (default) | defineModel. */\n modelApi?: 'defineTable' | 'defineModel' | 'defineCollection';\n /**\n * Registry mode (`efc add`): every file renders the same way whatever else is generated,\n * so a feature's files can be added to an app on their own. Login and the password flows\n * always handle both User and Admin (and both models come with auth), routes always send\n * mail through the SendEmail task, and models declare no back-relations.\n */\n registry?: boolean;\n /** OAuth sign-in providers (needs the User model — auth). */\n oauth?: { google?: boolean; apple?: boolean };\n}\n\n/** Whether any OAuth sign-in provider is generated. */\nfunction usesOAuth(opts: ScaffoldOptions): boolean {\n return !!(opts.oauth?.google || opts.oauth?.apple);\n}\n\n/** Which principals the auth routes handle. */\nfunction principals(opts: ScaffoldOptions): { user: boolean; admin: boolean } {\n return {\n user: !!opts.registry || opts.userPortal,\n admin: !!opts.registry || opts.adminPortal,\n };\n}\n\n/** Whether routes email their tokens through the SendEmail task (vs. a TODO). */\nfunction sendsMail(opts: ScaffoldOptions): boolean {\n return !!opts.registry || opts.mailer;\n}\n\n/** Whether the generated models are `defineTable` (PostgreSQL-native) ones. */\nexport function usesTables(opts: ScaffoldOptions): boolean {\n return opts.database === 'postgresql' && opts.modelApi !== 'defineModel';\n}\n\n/** MongoDB apps get defineCollection unless they asked for the portable defineModel. */\nexport function usesCollections(opts: ScaffoldOptions): boolean {\n return opts.database === 'mongodb' && opts.modelApi !== 'defineModel';\n}\n\n/**\n * Code for model calls in generated routes, in the vocabulary of the chosen API:\n * `defineModel` (`User.findOne({ email })`) or `defineTable` (`User.findFirst({ where: … })`).\n * Arguments are source text.\n */\nfunction orm(opts: ScaffoldOptions) {\n const t = usesTables(opts);\n const c = usesCollections(opts);\n const where = (filter: string) =>\n filter.replace(/\\s/g, '') === '{}' ? '' : `{ where: ${filter} }`;\n const byId = (id: string) => (id === 'id' ? '{ id }' : `{ id: ${id} }`);\n return {\n findOne: (m: string, filter: string) =>\n t ? `${m}.findFirst({ where: ${filter} })` : `${m}.findOne(${filter})`,\n findById: (m: string, id: string) =>\n t ? `${m}.findUnique({ where: ${byId(id)} })` : `${m}.findById(${id})`,\n find: (m: string, filter: string) =>\n t ? `${m}.findMany(${where(filter)})` : `${m}.find(${filter})`,\n count: (m: string, filter: string) =>\n t\n ? `${m}.count(${where(filter)})`\n : c\n ? `${m}.countDocuments(${filter})`\n : `${m}.count(${filter})`,\n create: (m: string, data: string) =>\n t ? `${m}.create({ data: ${data} })` : `${m}.create(${data})`,\n update: (m: string, id: string, data: string) =>\n t\n ? `${m}.update({ where: ${byId(id)}, data: ${data} })`\n : c\n ? `${m}.findByIdAndUpdate(${id}, ${data}, { returnDocument: 'after' })`\n : `${m}.update(${id}, ${data})`,\n delete: (m: string, id: string) =>\n t\n ? `${m}.delete({ where: ${byId(id)} })`\n : c\n ? `${m}.findByIdAndDelete(${id})`\n : `${m}.delete(${id})`,\n };\n}\n\n/** The models `scaffold()` generates for these options. */\nexport function generatedModels(opts: ScaffoldOptions): Set<string> {\n const uf = opts.userFeatures;\n const af = opts.adminFeatures;\n const user = opts.userPortal;\n const admin = opts.adminPortal;\n const m = new Set<string>();\n // Admin \"user management\" operates on the User collection even when there's\n // no separate self-service user portal, so the model must exist for it too.\n if (user || (admin && af.userManagement)) m.add('User');\n if (admin) m.add('Admin');\n // Registry mode: auth always handles both principals, so it always brings both models.\n if (opts.registry && (user || admin)) m.add('User').add('Admin');\n if (user && uf.accountSecurity) m.add('Session');\n if ((user && uf.notifications) || (admin && af.notificationsAndLogs)) m.add('Notification');\n if (user && uf.filesAndMedia) m.add('File');\n if ((user && uf.support) || (admin && af.supportManagement)) m.add('SupportTicket');\n if (admin && af.notificationsAndLogs) m.add('AuditLog');\n if (user && uf.apiAndBilling) m.add('Subscription').add('Invoice').add('ApiKey');\n if (usesOAuth(opts)) m.add('OAuthAccount');\n if (admin && af.billingManagement) m.add('Plan').add('Coupon');\n if (opts.rbac && admin && af.adminManagement) m.add('Role');\n if (admin && af.contentManagement) m.add('FAQ').add('Blog').add('Category');\n // Registry mode: a reference is always a foreign key, so its target comes along.\n if (opts.registry && m.has('Subscription')) m.add('Plan');\n return m;\n}\n\n/** `import { defineTable }` / `import { defineModel }` and the function's name. */\nfunction modelApi(opts: ScaffoldOptions): { name: string; import: string } {\n const name = usesTables(opts)\n ? 'defineTable'\n : usesCollections(opts)\n ? 'defineCollection'\n : 'defineModel';\n return { name, import: `import { ${name} } from 'express-file-cluster';` };\n}\n\n/**\n * A reference field: on defineTable, a real foreign key when its target model is generated;\n * otherwise the plain id string `legacy` describes (defineModel, or no such model).\n */\nfunction refField(\n opts: ScaffoldOptions,\n r: {\n field: string;\n target: string;\n legacy: string;\n required?: boolean;\n onDelete: 'cascade' | 'setNull' | 'restrict';\n },\n): string {\n if (!usesTables(opts) || !generatedModels(opts).has(r.target)) return r.legacy;\n const opts2 = `${r.required ? ', required: true' : ''}${r.onDelete === 'restrict' ? '' : `, onDelete: '${r.onDelete}'`}`;\n return ` ${(r.field + ':').padEnd(13)}{ type: 'uuid', ref: '${r.target}'${opts2} },`;\n}\n\n/** The `relations` option (defineTable): back-relations whose models are generated. */\nfunction relationsOption(\n opts: ScaffoldOptions,\n rels: { name: string; kind: 'hasMany' | 'hasOne'; target: string; foreignKey: string }[],\n): string {\n if (!usesTables(opts) || opts.registry) return '';\n const models = generatedModels(opts);\n const live = rels.filter((r) => models.has(r.target));\n if (live.length === 0) return '';\n const lines = live.map(\n (r) => ` ${r.name}: { ${r.kind}: '${r.target}', foreignKey: '${r.foreignKey}' },`,\n );\n return `, {\\n relations: {\\n${lines.join('\\n')}\\n },\\n}`;\n}\n\nexport async function scaffold(opts: ScaffoldOptions): Promise<void> {\n const dest = path.resolve(process.cwd(), opts.projectName);\n await fs.ensureDir(dest);\n\n const uf = opts.userFeatures;\n const models = generatedModels(opts);\n\n await writePackageJson(dest, opts);\n await writeTsConfig(dest, opts);\n await writeEfcConfig(dest, opts);\n await writeEntryPoint(dest, opts);\n await writeGitignore(dest);\n await writeAgentsMd(dest, opts);\n await writeEnvFiles(dest, opts);\n await writeExampleRoute(dest, opts);\n if (models.has('User')) await writeUserModel(dest, opts);\n if (models.has('Admin')) await writeAdminModel(dest, opts);\n if (!opts.registry || opts.userPortal || opts.adminPortal) await writeAuthRoutes(dest, opts);\n if (opts.adminPortal) await writeAdminRoutes(dest, opts);\n if (opts.userPortal && uf.profileViewing) await writeUserRoutes(dest, opts);\n if (opts.tasks) await writeExampleTask(dest, opts);\n // Extended models — only generated when a feature that uses them is selected\n const extended: [string, (dest: string, opts: ScaffoldOptions) => Promise<void>][] = [\n ['Session', writeSessionModel],\n ['Notification', writeNotificationModel],\n ['File', writeFileModel],\n ['SupportTicket', writeSupportTicketModel],\n ['AuditLog', writeAuditLogModel],\n ['Subscription', writeSubscriptionModel],\n ['Plan', writePlanModel],\n ['Invoice', writeInvoiceModel],\n ['ApiKey', writeApiKeyModel],\n ['Role', writeRoleModel],\n ['FAQ', writeFAQModel],\n ['Blog', writeBlogModel],\n ['Category', writeCategoryModel],\n ['Coupon', writeCouponModel],\n ];\n for (const [name, write] of extended) if (models.has(name)) await write(dest, opts);\n if (models.has('OAuthAccount')) await writeOAuthAccountModel(dest, opts);\n if (usesOAuth(opts)) await writeOAuth(dest, opts);\n if (usesTables(opts)) await writeModelIndex(dest, opts);\n // Extended routes — gated by the same per-feature flags as their models\n if (opts.userPortal) await writeAuthExtendedRoutes(dest, opts);\n if (opts.userPortal) await writeUserExtendedRoutes(dest, opts);\n if (opts.userPortal && uf.apiAndBilling) await writeUserBillingRoutes(dest, opts);\n if (opts.userPortal && uf.support) await writeSupportRoutes(dest, opts);\n if (opts.adminPortal) await writeAdminExtendedRoutes(dest, opts);\n await writeInitMigration(dest, opts);\n}\n\nasync function writePackageJson(dest: string, opts: ScaffoldOptions): Promise<void> {\n const deps: Record<string, string> = {\n 'express-file-cluster': '^0.10.0',\n };\n if (opts.database === 'mongodb') deps['mongoose'] = '^9.7.2';\n if (opts.database === 'postgresql') {\n deps['pg'] = '^8.11.0';\n deps['drizzle-orm'] = '^0.45.0';\n }\n if (opts.tasks && opts.taskBackend === 'bullmq') deps['bullmq'] = '^5.0.0';\n if (opts.tasks && opts.taskBackend === 'pg-boss') deps['pg-boss'] = '^12.0.0';\n if (opts.mailer) deps['nodemailer'] = '^10.2.1';\n if (usesOAuth(opts)) deps['jose'] = '^6.2.3';\n\n const devDeps: Record<string, string> = {\n vitest: '^5.0.3',\n };\n if (opts.language === 'typescript') {\n // JavaScript projects need neither: `efc build prod` copies them, `efc start dev` uses node --watch.\n devDeps['tsup'] = '^8.2.0';\n devDeps['typescript'] = '^5.5.0';\n devDeps['@types/node'] = '^22.0.0';\n devDeps['@types/express'] = '^4.17.21';\n devDeps['tsx'] = '^4.0.0';\n if (opts.mailer) devDeps['@types/nodemailer'] = '^8.0.2';\n if (opts.database === 'postgresql') devDeps['@types/pg'] = '^8.11.0';\n }\n\n const pkg = {\n name: opts.projectName,\n version: '0.1.0',\n type: 'module',\n scripts: {\n dev: 'efc start dev',\n build: 'efc build prod',\n start: 'efc start prod',\n test: 'efc run tests',\n 'db:migrate': 'efc db migrate',\n 'db:rollback': 'efc db rollback',\n 'db:seed': 'efc db seed',\n 'db:studio': 'efc db studio',\n },\n dependencies: deps,\n devDependencies: devDeps,\n // tsup 8 still asks for esbuild 0.27, which has an open advisory; 0.28 builds the same.\n ...(opts.language === 'typescript' ? { overrides: { esbuild: '^0.28.1' } } : {}),\n };\n\n await fs.writeJson(path.join(dest, 'package.json'), pkg, { spaces: 2 });\n}\n\nasync function writeTsConfig(dest: string, opts: ScaffoldOptions): Promise<void> {\n if (opts.language !== 'typescript') return;\n const config = {\n compilerOptions: {\n target: 'ES2022',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: './dist',\n },\n // No explicit rootDir: efc.config.ts lives at the project root, outside src/, and\n // src/index.ts imports it. `efc build prod` only uses this config for `tsc --noEmit`\n // typechecking — tsup writes the actual output (dist/src/**, dist/efc.config.js),\n // so leaving rootDir implicit here has no effect on the production build's output layout.\n include: ['src/**/*', 'efc.config.ts'],\n exclude: ['node_modules', 'dist'],\n };\n await fs.writeJson(path.join(dest, 'tsconfig.json'), config, { spaces: 2 });\n}\n\nasync function writeEfcConfig(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n // pg-boss stores jobs in the app's own Postgres (databaseUrl); BullMQ needs Redis.\n const tasks = !opts.tasks\n ? 'false'\n : opts.taskBackend === 'pg-boss'\n ? `{ backend: 'pg-boss', concurrency: 5 }`\n : `{ backend: 'bullmq', concurrency: 5, redisUrl: process.env.REDIS_URL }`;\n\n const ts = opts.language === 'typescript';\n // JavaScript gets a JSDoc type instead of TypeScript syntax, so editors still check it.\n const typeImport = ts ? \"import type { EFCConfig } from 'express-file-cluster';\\n\\n\" : '';\n const declaration = ts\n ? 'const config: EFCConfig = {'\n : \"/** @type {import('express-file-cluster').EFCConfig} */\\nconst config = {\";\n const content = `${typeImport}// The framework never reads process.env itself — every runtime value it needs is read\n// here, explicitly, and passed in. Edit .env to change values; edit this file to change\n// which env vars are wired up or add new ones.\nconst corsOrigins = process.env.CORS_ORIGINS\n ? process.env.CORS_ORIGINS.split(',').map((o) => o.trim()).filter(Boolean)\n : undefined;\n\n${declaration}\n port: process.env.PORT ? Number(process.env.PORT) : undefined,\n databaseUrl: process.env.DATABASE_URL,\n jwtSecret: process.env.JWT_SECRET,\n jwtExpiresIn: process.env.JWT_EXPIRES_IN,\n cookieDomain: process.env.COOKIE_DOMAIN,\n cors: corsOrigins ? { origin: corsOrigins } : true,\n // Behind a proxy / load balancer (Render, Fly, Heroku, nginx): the number of hops, e.g. 1,\n // so req.ip is the client and rate limits count per client.\n trustProxy: process.env.TRUST_PROXY ? Number(process.env.TRUST_PROXY) : undefined,\n authStrategy: '${opts.authStrategy}',\n tasks: ${tasks},\n // Cache + session-revocation store (logout really invalidates tokens). Redis when\n // REDIS_URL is set — shared by every instance; otherwise an in-memory store shared by\n // this machine's workers, emptied on restart.\n cache: process.env.REDIS_URL ? { backend: 'redis', url: process.env.REDIS_URL } : { backend: 'memory' },\n globalMiddlewares: [],\n};\n\nexport default config;\n`;\n await fs.outputFile(path.join(dest, `efc.config.${ext}`), content);\n}\n\nasync function writeEntryPoint(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n // Only emit `cluster: false` on opt-out — a literal `cluster: true` would override\n // ignite()'s NODE_ENV-aware default and cluster under `efc start dev` too.\n const clusterLine = opts.cluster ? '' : '\\n cluster: false,';\n const content = `import { ignite, gracefulShutdown } from 'express-file-cluster';\nimport config from '../efc.config.js';\n\n// Every runtime value (PORT, DATABASE_URL, JWT_SECRET, CORS_ORIGINS, ...) is wired from\n// .env in efc.config.${ext} and spread in below — ignite() itself never touches process.env\n// for these, so this object is the single source of truth for what's actually applied.\nignite({\n ...config,${clusterLine}\n}).then(gracefulShutdown).catch(console.error);\n`;\n await fs.outputFile(path.join(dest, 'src', `index.${ext}`), content);\n}\n\nasync function writeGitignore(dest: string): Promise<void> {\n await fs.outputFile(\n path.join(dest, '.gitignore'),\n 'node_modules/\\ndist/\\n.env\\n.env.local\\n*.log\\n',\n );\n}\n\n// Points AI coding agents at the docs bundled with the installed framework version, so\n// they read the real API instead of guessing it.\nasync function writeAgentsMd(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const D = 'node_modules/express-file-cluster/dist/docs';\n const engine = opts.database === 'postgresql' ? 'PostgreSQL' : 'MongoDB';\n const content = `# AGENTS.md\n\nThis is an **express-file-cluster (EFC)** app (${opts.language === 'typescript' ? 'TypeScript' : 'JavaScript'}, ${engine}).\nEFC's API is probably not in your training data — **read its docs before writing code**, and\ndon't use any EFC import, option or method you can't find in them.\n\n## Read the docs first\n\nThe docs for the exact installed version ship inside the package, under \\`${D}/\\`:\n\n1. \\`${D}/skills/api-surface.md\\` — every public export and signature\n2. \\`${D}/skills/what-not-to-invent.md\\` — things that do NOT exist\n3. \\`${D}/index.md\\`, then the page for your task:\n - routes & URL params — \\`core-concepts/file-based-routing.md\\`, \\`skills/routing-rules.md\\`\n - request validation — \\`guides/validation.md\\`\n - models & queries — \\`guides/database.md\\`, \\`api-reference/db.md\\`${opts.database === 'postgresql' ? ', `api-reference/table.md` (PostgreSQL-native `defineTable`)' : ''}\n - migrations — \\`guides/migrations.md\\`\n - auth & roles — \\`guides/authentication.md\\`, \\`guides/rbac.md\\`\n - background tasks — \\`core-concepts/background-tasks.md\\`\n - config & boot — \\`api-reference/ignite.md\\`\n\nSearch them: \\`grep -rn \"<term>\" ${D}\\`\n\nOptional — the same docs over MCP, with search and scaffolding tools:\n\\`claude mcp add efc -- npx -y express-file-cluster-mcp\\`\n(other clients: command \\`npx\\`, args \\`[\"-y\", \"express-file-cluster-mcp\"]\\`).\n\n## Project conventions\n\n- \\`src/api/**\\` — every file is a route (\\`users/[id].${ext}\\` → \\`/v1/api/users/:id\\`); export\n uppercase \\`GET\\`/\\`POST\\`/… handlers.\n- \\`src/tasks/*.${ext}\\` — background tasks; the file name is the task name (not recursive).\n${\n usesTables(opts)\n ? `- \\`src/model/*.${ext}\\` — \\`defineTable\\` models (PostgreSQL-native, Prisma-style queries:\n \\`findMany({ where, include })\\`, \\`create({ data })\\`, \\`update({ where, data })\\`). A \\`ref\\` is a\n foreign key; ${opts.registry ? \"add back-relations to a model's `relations` when you need `include`\" : \"back-relations are in each model's `relations`\"}. \\`src/model/index.${ext}\\` imports\n them all${opts.language === 'typescript' ? ' and declares `Tables` (typed `include`)' : ''} — add new models there.`\n : usesCollections(opts)\n ? `- \\`src/model/*.${ext}\\` — \\`defineCollection\\` models (MongoDB-native, mongoose-style queries:\n \\`find(filter, { projection, sort })\\`, \\`findByIdAndUpdate\\`, typed \\`pipeline()\\`, \\`lookup()\\`).`\n : `- \\`src/model/*.${ext}\\` — \\`defineModel\\` models.`\n}\n- \\`src/index.${ext}\\` is the entry point; it imports \\`efc.config.${ext}\\` and passes it to \\`ignite()\\`.\n- Only three import paths exist: \\`express-file-cluster\\`, \\`express-file-cluster/auth\\`,\n \\`express-file-cluster/tasks\\`.\n${\n opts.registry\n ? `- Ready-made features (auth, user/admin portals, billing, mailer…) come from the registry:\n \\`npx efc list\\`, then \\`npx efc add <item> --yes\\` — check it before hand-writing auth or CRUD\n (\\`${D}/cli/add.md\\`). \\`efc.json\\` tracks what was added; commit it.\n`\n : ''\n}\n## Commands\n\n\\`\\`\\`bash\nnpx efc start dev # dev server with reload\nnpx efc db migrate # run migrations\nnpx efc build prod # type-check + production build\nnpx efc doctor # diagnose the setup\n\\`\\`\\`\n`;\n await fs.outputFile(path.join(dest, 'AGENTS.md'), content);\n}\n\nasync function writeEnvFiles(dest: string, opts: ScaffoldOptions): Promise<void> {\n const secret = crypto.randomBytes(64).toString('hex');\n const projectName = path.basename(dest);\n const dbUrl =\n opts.database === 'mongodb'\n ? `mongodb://localhost:27017/${projectName}`\n : `postgresql://localhost:5432/${projectName}`;\n const dbExampleUrl =\n opts.database === 'mongodb'\n ? `mongodb://localhost:27017/${projectName}`\n : `postgresql://user:password@localhost:5432/${projectName}`;\n\n const isGmail = opts.mailer && opts.smtpProvider !== 'custom';\n const resolvedHost = isGmail ? 'smtp.gmail.com' : (opts.smtpHost ?? 'smtp.gmail.com');\n const resolvedPort = isGmail ? '465' : (opts.smtpPort ?? '587');\n const passComment = isGmail\n ? ' # Gmail App Password (16 chars) — NOT your regular Gmail password. Generate at: Google Account > Security > 2-Step Verification > App passwords'\n : '';\n\n const smtpVars = opts.mailer\n ? `\\nAPP_URL=http://localhost:3000\\nSMTP_HOST=${resolvedHost}\\nSMTP_PORT=${resolvedPort}\\nSMTP_USER=${opts.smtpUser ?? ''}\\nSMTP_PASS=${opts.smtpPass ?? ''}${passComment}\\nSMTP_FROM=${opts.smtpUser ?? 'noreply@example.com'}\\n`\n : '';\n const smtpExample = opts.mailer\n ? `\\nAPP_URL=http://localhost:3000\\nSMTP_HOST=${resolvedHost}\\nSMTP_PORT=${resolvedPort}\\nSMTP_USER=your@email.com\\nSMTP_PASS=${isGmail ? 'your_16_char_app_password' : 'your_smtp_password'}${passComment}\\nSMTP_FROM=noreply@yourapp.com\\n`\n : '';\n // Only BullMQ needs Redis — and `efc tasks failed` picks its backend from REDIS_URL.\n const redis =\n opts.tasks && opts.taskBackend !== 'pg-boss' ? '\\nREDIS_URL=redis://localhost:6379' : '';\n const oauth = opts.oauth ?? {};\n const oauthVars = [\n ...(oauth.google\n ? [\n ['GOOGLE_CLIENT_ID', '', 'your-client-id.apps.googleusercontent.com'],\n ['GOOGLE_CLIENT_SECRET', '', 'your-client-secret'],\n [\n 'GOOGLE_REDIRECT_URI',\n 'http://localhost:3000/v1/api/auth/google/callback',\n 'https://api.yourapp.com/v1/api/auth/google/callback',\n ],\n ]\n : []),\n ...(oauth.apple\n ? [\n ['APPLE_CLIENT_ID', '', 'com.yourapp.signin'],\n ['APPLE_TEAM_ID', '', 'ABCDE12345'],\n ['APPLE_KEY_ID', '', 'FGHIJ67890'],\n [\n 'APPLE_PRIVATE_KEY',\n '',\n '-----BEGIN PRIVATE KEY-----\\\\n...\\\\n-----END PRIVATE KEY-----',\n ],\n [\n 'APPLE_REDIRECT_URI',\n 'https://api.yourapp.com/v1/api/auth/apple/callback',\n 'https://api.yourapp.com/v1/api/auth/apple/callback',\n ],\n ]\n : []),\n ...(usesOAuth(opts)\n ? [['OAUTH_SUCCESS_REDIRECT', 'http://localhost:3000/', 'https://yourapp.com/']]\n : []),\n ];\n const oauthEnv = oauthVars.map(([k, v]) => `\\n${k}=${v}`).join('');\n const oauthExample = oauthVars.map(([k, , ex]) => `\\n${k}=${ex}`).join('');\n const dotenv = `PORT=3000\\nNODE_ENV=development\\nDATABASE_URL=${dbUrl}\\nJWT_SECRET=${secret}${redis}\\nCORS_ORIGINS=http://localhost:3000${smtpVars}${oauthEnv}`;\n const example = `PORT=3000\\nNODE_ENV=development\\nDATABASE_URL=${dbExampleUrl}\\nJWT_SECRET=<generate with: openssl rand -hex 64>${redis}\\nCORS_ORIGINS=http://localhost:3000,https://yourapp.com\\n# Behind a proxy / load balancer: how many hops to trust, so rate limits see client IPs\\n# TRUST_PROXY=1${smtpExample}${oauthExample}`;\n await fs.outputFile(path.join(dest, '.env'), dotenv);\n await fs.outputFile(path.join(dest, '.env.example'), example);\n}\n\nasync function writeExampleRoute(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const metaTs = opts.routeDocs\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Health check — returns server status and current timestamp.',\\n response: { status: 200, body: { status: 'OK', timestamp: '2024-01-01T00:00:00.000Z' } },\\n },\\n};\\n\\n`\n : '';\n const metaJs = opts.routeDocs\n ? `export const meta = {\\n GET: {\\n description: 'Health check — returns server status and current timestamp.',\\n response: { status: 200, body: { status: 'OK', timestamp: '2024-01-01T00:00:00.000Z' } },\\n },\\n};\\n\\n`\n : '';\n const content =\n opts.language === 'typescript'\n ? `import type { Request, Response } from 'express';\\n${metaTs}export const GET = async (_req: Request, res: Response) => {\\n res.json({ status: 'OK', timestamp: new Date().toISOString() });\\n};\\n`\n : `${metaJs}export const GET = async (_req, res) => {\\n res.json({ status: 'OK', timestamp: new Date().toISOString() });\\n};\\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', `health.${ext}`), content);\n}\n\nasync function writeExampleTask(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n\n const tsMailer = `import { defineTask } from 'express-file-cluster/tasks';\nimport nodemailer from 'nodemailer';\n\ninterface SendEmailPayload {\n to: string;\n subject: string;\n body: string;\n}\n\nconst transporter = nodemailer.createTransport({\n host: process.env.SMTP_HOST,\n port: Number(process.env.SMTP_PORT ?? 587),\n secure: Number(process.env.SMTP_PORT) === 465,\n auth: {\n user: process.env.SMTP_USER,\n pass: process.env.SMTP_PASS,\n },\n});\n\nexport default defineTask<SendEmailPayload>(async (payload) => {\n await transporter.sendMail({\n from: process.env.SMTP_FROM ?? process.env.SMTP_USER,\n to: payload.to,\n subject: payload.subject,\n html: payload.body,\n });\n});\n`;\n\n const jsMailer = `import { defineTask } from 'express-file-cluster/tasks';\nimport nodemailer from 'nodemailer';\n\nconst transporter = nodemailer.createTransport({\n host: process.env.SMTP_HOST,\n port: Number(process.env.SMTP_PORT ?? 587),\n secure: Number(process.env.SMTP_PORT) === 465,\n auth: {\n user: process.env.SMTP_USER,\n pass: process.env.SMTP_PASS,\n },\n});\n\nexport default defineTask(async (payload) => {\n await transporter.sendMail({\n from: process.env.SMTP_FROM ?? process.env.SMTP_USER,\n to: payload.to,\n subject: payload.subject,\n html: payload.body,\n });\n});\n`;\n\n const tsStub = `import { defineTask } from 'express-file-cluster/tasks';\n\ninterface SendEmailPayload {\n to: string;\n subject: string;\n body: string;\n}\n\nexport default defineTask<SendEmailPayload>(async (payload) => {\n // TODO: wire up your mailer\n console.log('[SendEmail] Sending to', payload.to);\n});\n`;\n\n const jsStub = `import { defineTask } from 'express-file-cluster/tasks';\n\nexport default defineTask(async (payload) => {\n // TODO: wire up your mailer\n console.log('[SendEmail] Sending to', payload.to);\n});\n`;\n\n const content = opts.mailer\n ? opts.language === 'typescript'\n ? tsMailer\n : jsMailer\n : opts.language === 'typescript'\n ? tsStub\n : jsStub;\n\n await fs.outputFile(path.join(dest, 'src', 'tasks', `SendEmail.${ext}`), content);\n}\n\nasync function writeUserModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n\n const content = `${modelApi(opts).import}\n\nexport const User = ${modelApi(opts).name}('User', {\n name: { type: 'string', required: true },\n email: { type: 'string', required: true, unique: true },\n password: { type: 'string', required: true },\n role: { type: 'string', required: true, default: 'user' },\n avatar: { type: 'string' },\n isVerified: { type: 'boolean', default: false },\n isActive: { type: 'boolean', default: true },\n verifyToken: { type: 'string' },\n resetToken: { type: 'string' },\n resetTokenExpiry: { type: 'date' },\n refreshToken: { type: 'string' },\n refreshTokenExpiry: { type: 'date' },\n}${relationsOption(opts, [\n { name: 'sessions', kind: 'hasMany', target: 'Session', foreignKey: 'user' },\n { name: 'notifications', kind: 'hasMany', target: 'Notification', foreignKey: 'user' },\n { name: 'files', kind: 'hasMany', target: 'File', foreignKey: 'user' },\n { name: 'tickets', kind: 'hasMany', target: 'SupportTicket', foreignKey: 'user' },\n { name: 'subscriptions', kind: 'hasMany', target: 'Subscription', foreignKey: 'user' },\n { name: 'invoices', kind: 'hasMany', target: 'Invoice', foreignKey: 'user' },\n { name: 'apiKeys', kind: 'hasMany', target: 'ApiKey', foreignKey: 'user' },\n ])});\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'model', `User.${ext}`), content);\n}\n\nasync function writeAdminModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n\n const content = `${modelApi(opts).import}\n\nexport const Admin = ${modelApi(opts).name}('Admin', {\n name: { type: 'string', required: true },\n email: { type: 'string', required: true, unique: true },\n password: { type: 'string', required: true },\n role: { type: 'string', required: true, default: 'admin' },\n permissions: { type: 'array', of: 'string', default: [] },\n isActive: { type: 'boolean', default: true },\n resetToken: { type: 'string' },\n resetTokenExpiry: { type: 'date' },\n refreshToken: { type: 'string' },\n refreshTokenExpiry: { type: 'date' },\n}${relationsOption(opts, [\n { name: 'assignedTickets', kind: 'hasMany', target: 'SupportTicket', foreignKey: 'assignedTo' },\n { name: 'auditLogs', kind: 'hasMany', target: 'AuditLog', foreignKey: 'admin' },\n { name: 'posts', kind: 'hasMany', target: 'Blog', foreignKey: 'author' },\n ])});\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'model', `Admin.${ext}`), content);\n}\n\nasync function writeAuthRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n\n const loginMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n POST: {\\n description: 'Authenticate a user or admin and issue a JWT.',\\n request: { body: { email: 'user@example.com', password: 'user' } },\\n response: { status: 200, body: { message: 'Logged in as user' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n POST: {\\n description: 'Authenticate a user or admin and issue a JWT.',\\n request: { body: { email: 'user@example.com', password: 'user' } },\\n response: { status: 200, body: { message: 'Logged in as user' } },\\n },\\n};\\n\\n`\n : '';\n\n // Only reference the models for the portals actually being generated —\n // referencing both unconditionally broke builds when only one portal was selected.\n const { user: hasUser, admin: hasAdmin } = principals(opts);\n const hasModels = hasUser || hasAdmin;\n\n const loginDbImports = hasModels\n ? `import crypto from 'node:crypto';\\n${hasUser ? `import { User } from '../../model/User.js';\\n` : ''}${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`\n : '';\n\n const loginBody =\n hasAdmin && hasUser\n ? ` const admin = await ${db.findOne('Admin', `{ email }`)};\n if (admin) {\n const match = await verifyPassword(password, admin.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!admin.isActive) return res.status(403).json({ error: 'Account suspended' });\n const token = await issueToken(res, { id: admin.id, role: admin.role, email: admin.email });\n const refreshToken = await issueRefreshToken(res, Admin, admin.id);\n return res.json({ message: 'Logged in as admin', ...(token ? { token, refreshToken } : {}) });\n }\n\n const user = await ${db.findOne('User', `{ email }`)};\n if (!user) return res.status(401).json({ error: 'Invalid credentials' });\n const match = await verifyPassword(password, user.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!user.isActive) return res.status(403).json({ error: 'Account suspended' });\n const token = await issueToken(res, { id: user.id, role: user.role, email: user.email });\n const refreshToken = await issueRefreshToken(res, User, user.id);\n // bearer: the client stores both tokens itself; http-only: they travel as cookies.\n res.json({ message: 'Logged in', ...(token ? { token, refreshToken } : {}) });`\n : hasAdmin\n ? ` const admin = await ${db.findOne('Admin', `{ email }`)};\n if (!admin) return res.status(401).json({ error: 'Invalid credentials' });\n const match = await verifyPassword(password, admin.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!admin.isActive) return res.status(403).json({ error: 'Account suspended' });\n const token = await issueToken(res, { id: admin.id, role: admin.role, email: admin.email });\n const refreshToken = await issueRefreshToken(res, Admin, admin.id);\n // bearer: the client stores both tokens itself; http-only: they travel as cookies.\n res.json({ message: 'Logged in as admin', ...(token ? { token, refreshToken } : {}) });`\n : ` const user = await ${db.findOne('User', `{ email }`)};\n if (!user) return res.status(401).json({ error: 'Invalid credentials' });\n const match = await verifyPassword(password, user.password);\n if (!match) return res.status(401).json({ error: 'Invalid credentials' });\n if (!user.isActive) return res.status(403).json({ error: 'Account suspended' });\n const token = await issueToken(res, { id: user.id, role: user.role, email: user.email });\n const refreshToken = await issueRefreshToken(res, User, user.id);\n // bearer: the client stores both tokens itself; http-only: they travel as cookies.\n res.json({ message: 'Logged in', ...(token ? { token, refreshToken } : {}) });`;\n\n const loginContent = hasModels\n ? ts\n ? `import { issueToken, verifyPassword } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\nimport { rateLimit } from 'express-file-cluster';\n${loginDbImports}${loginMeta}// 10 attempts per 15 minutes per address and account. Keyed on the email too, so behind a\n// proxy without TRUST_PROXY (every client then has the proxy's IP) it still limits one\n// account at a time, never everyone.\nexport const middlewares = [\n rateLimit({\n window: '15m',\n max: 10,\n key: (req) => \\`\\${req.ip}:\\${String(req.body?.email ?? '').toLowerCase()}\\`,\n }),\n];\n\nconst REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nasync function issueRefreshToken(\n res: Response,\n model: ${\n usesTables(opts)\n ? '{ update: (args: { where: { id: string }; data: Record<string, unknown> }) => Promise<unknown> }'\n : usesCollections(opts)\n ? '{ findByIdAndUpdate: (id: string, data: Record<string, unknown>, options: { returnDocument: \\'after\\' }) => Promise<unknown> }'\n : '{ update: (id: string, data: Record<string, unknown>) => Promise<unknown> }'\n },\n id: string,\n): Promise<string> {\n const refreshToken = crypto.randomBytes(40).toString('hex');\n await ${db.update('model', 'id', '{ refreshToken, refreshTokenExpiry: new Date(Date.now() + REFRESH_TOKEN_TTL_MS) }')};\n res.cookie('efc_refresh_token', refreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n return refreshToken;\n}\n\nexport const POST = async (req: Request, res: Response) => {\n const { email, password } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof email !== 'string' || typeof password !== 'string' || !email || !password) {\n return res.status(400).json({ error: 'email and password are required' });\n }\n\n${loginBody}\n};\n`\n : `import { issueToken, verifyPassword } from 'express-file-cluster/auth';\nimport { rateLimit } from 'express-file-cluster';\n${loginDbImports}${loginMeta}// 10 attempts per 15 minutes per address and account. Keyed on the email too, so behind a\n// proxy without TRUST_PROXY (every client then has the proxy's IP) it still limits one\n// account at a time, never everyone.\nexport const middlewares = [\n rateLimit({\n window: '15m',\n max: 10,\n key: (req) => \\`\\${req.ip}:\\${String(req.body?.email ?? '').toLowerCase()}\\`,\n }),\n];\n\nconst REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nasync function issueRefreshToken(res, model, id) {\n const refreshToken = crypto.randomBytes(40).toString('hex');\n await ${db.update('model', 'id', '{ refreshToken, refreshTokenExpiry: new Date(Date.now() + REFRESH_TOKEN_TTL_MS) }')};\n res.cookie('efc_refresh_token', refreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n return refreshToken;\n}\n\nexport const POST = async (req, res) => {\n const { email, password } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof email !== 'string' || typeof password !== 'string' || !email || !password) {\n return res.status(400).json({ error: 'email and password are required' });\n }\n\n${loginBody}\n};\n`\n : ts\n ? `import { issueToken } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${loginMeta}export const POST = async (req: Request, res: Response) => {\n const { email, password } = req.body;\n // TODO: look up user in DB and compare password\n res.status(401).json({ error: 'Invalid credentials' });\n};\n`\n : `import { issueToken } from 'express-file-cluster/auth';\n${loginMeta}export const POST = async (req, res) => {\n const { email, password } = req.body;\n // TODO: look up user in DB and compare password\n res.status(401).json({ error: 'Invalid credentials' });\n};\n`;\n\n const logoutMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n POST: {\\n description: 'Revoke the current session and clear the auth cookie.',\\n response: { status: 200, body: { message: 'Logged out successfully' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n POST: {\\n description: 'Revoke the current session and clear the auth cookie.',\\n response: { status: 200, body: { message: 'Logged out successfully' } },\\n },\\n};\\n\\n`\n : '';\n\n const logoutContent = ts\n ? `import { revokeSession } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${logoutMeta}export const POST = async (req: Request, res: Response) => {\n // Rejects this token from now on (not just the cookie) — see \\`cache\\` in efc.config.\n await revokeSession(req, res);\n res.clearCookie('efc_refresh_token');\n res.json({ message: 'Logged out successfully' });\n};\n`\n : `import { revokeSession } from 'express-file-cluster/auth';\n${logoutMeta}export const POST = async (req, res) => {\n // Rejects this token from now on (not just the cookie) — see \\`cache\\` in efc.config.\n await revokeSession(req, res);\n res.clearCookie('efc_refresh_token');\n res.json({ message: 'Logged out successfully' });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `login.${ext}`), loginContent);\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `logout.${ext}`), logoutContent);\n\n if (!hasUser) return;\n\n const registerMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n POST: {\\n description: 'Register a new user account.',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret' } },\\n response: { status: 201, body: { message: 'Account created successfully' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n POST: {\\n description: 'Register a new user account.',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret' } },\\n response: { status: 201, body: { message: 'Account created successfully' } },\\n },\\n};\\n\\n`\n : '';\n\n const registerDbImports = `import { hashPassword } from 'express-file-cluster/auth';\\nimport crypto from 'node:crypto';\\n${sendsMail(opts) ? \"import { enqueue } from 'express-file-cluster/tasks';\\n\" : ''}import { User } from '../../model/User.js';\\n`;\n\n const sendVerifyEmail = sendsMail(opts)\n ? `\n var appUrl = process.env.APP_URL || 'http://localhost:3000';\n await enqueue('SendEmail', {\n to: email,\n subject: 'Verify your email address',\n body: 'Welcome, ' + name + '! Verify your email: ' + appUrl + '/auth/verify-email?token=' + verifyToken,\n });\n`\n : `\n // TODO: email this token to the user — enable the Mailer feature to auto-wire SendEmail\n`;\n\n const registerContent = ts\n ? `import type { Request, Response } from 'express';\n${registerDbImports}${registerMeta}export const POST = async (req: Request, res: Response) => {\n const { name, email, password } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof name !== 'string' || typeof email !== 'string' || typeof password !== 'string' || !name || !email || !password) {\n return res.status(400).json({ error: 'name, email and password are required' });\n }\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const verifyToken = crypto.randomBytes(32).toString('hex');\n const user = await ${db.create('User', `{ name, email, password: hashed, verifyToken }`)};\n${sendVerifyEmail}\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.status(201).json({ message: 'Account created successfully', user: safe });\n};\n`\n : `${registerDbImports}${registerMeta}export const POST = async (req, res) => {\n const { name, email, password } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof name !== 'string' || typeof email !== 'string' || typeof password !== 'string' || !name || !email || !password) {\n return res.status(400).json({ error: 'name, email and password are required' });\n }\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const verifyToken = crypto.randomBytes(32).toString('hex');\n const user = await ${db.create('User', `{ name, email, password: hashed, verifyToken }`)};\n${sendVerifyEmail}\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.status(201).json({ message: 'Account created successfully', user: safe });\n};\n`;\n\n const meMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Return the currently authenticated user.',\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'Return the currently authenticated user.',\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n};\\n\\n`\n : '';\n const meMiddlewares = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n\\n`\n : `export const middlewares = [requireAuth];\\n\\n`;\n\n const meContent = ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${meMeta}${meMiddlewares}export const GET = async (req: Request, res: Response) => {\n res.json({ user: (req as any).user });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${meMeta}${meMiddlewares}export const GET = async (req, res) => {\n res.json({ user: req.user });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `register.${ext}`), registerContent);\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `me.${ext}`), meContent);\n}\n\nasync function writeAdminRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n const middlewares = opts.rbac\n ? `export const middlewares = [requireAuth('admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const roleGuard = opts.rbac\n ? ''\n : ts\n ? ` const user = (req as any).user;\\n if (user?.role !== 'admin') {\\n return res.status(403).json({ error: 'Forbidden: Admin access required' });\\n }\\n\\n`\n : ` const user = req.user;\\n if (user?.role !== 'admin') {\\n return res.status(403).json({ error: 'Forbidden: Admin access required' });\\n }\\n\\n`;\n\n const dashboardMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Admin dashboard stats. Requires admin role.',\\n response: { status: 200, body: { stats: { totalUsers: 120, activeUsers: 98, verifiedUsers: 84 } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'Admin dashboard stats. Requires admin role.',\\n response: { status: 200, body: { stats: { totalUsers: 120, activeUsers: 98, verifiedUsers: 84 } } },\\n },\\n};\\n\\n`\n : '';\n\n // Real stats need the User model, which only exists when userManagement is on (registry\n // mode: always — auth brings it).\n const dashboardHasUserModel = !!opts.registry || opts.adminFeatures.userManagement;\n\n const dashboardDbImport = dashboardHasUserModel\n ? `import { User } from '../../model/User.js';\\n`\n : '';\n\n const dashboardContent = dashboardHasUserModel\n ? ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${dashboardDbImport}${dashboardMeta}${middlewares}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} const [totalUsers, activeUsers, verifiedUsers] = await Promise.all([\n ${db.count('User', `{}`)},\n ${db.count('User', `{ isActive: true }`)},\n ${db.count('User', `{ isVerified: true }`)},\n ]);\n res.json({ stats: { totalUsers, activeUsers, verifiedUsers } });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${dashboardDbImport}${dashboardMeta}${middlewares}\nexport const GET = async (_req, res) => {\n${roleGuard} const [totalUsers, activeUsers, verifiedUsers] = await Promise.all([\n ${db.count('User', `{}`)},\n ${db.count('User', `{ isActive: true }`)},\n ${db.count('User', `{ isVerified: true }`)},\n ]);\n res.json({ stats: { totalUsers, activeUsers, verifiedUsers } });\n};\n`\n : ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${dashboardMeta}${middlewares}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: aggregate stats from DB\n res.json({ stats: { users: 0 } });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${dashboardMeta}${middlewares}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: aggregate stats from DB\n res.json({ stats: { users: 0 } });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'admin', `dashboard.${ext}`), dashboardContent);\n\n if (!opts.adminFeatures.userManagement) return;\n\n // Admin user management routes\n const usersListMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'List all users, paginated (admin only).',\\n request: { query: { page: '1', limit: '20' } },\\n response: { status: 200, body: { users: [], total: 0, page: 1, limit: 20 } },\\n },\\n POST: {\\n description: 'Create a new user account (admin only).',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret', role: 'user' } },\\n response: { status: 201, body: { message: 'User created', user: { id: 'new-id', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'List all users, paginated (admin only).',\\n request: { query: { page: '1', limit: '20' } },\\n response: { status: 200, body: { users: [], total: 0, page: 1, limit: 20 } },\\n },\\n POST: {\\n description: 'Create a new user account (admin only).',\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com', password: 'secret', role: 'user' } },\\n response: { status: 201, body: { message: 'User created', user: { id: 'new-id', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n};\\n\\n`\n : '';\n\n const adminUsersDbImport = `import { User } from '../../../model/User.js';\\n`;\n\n const usersListContent = ts\n ? `import { hashPassword, requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${adminUsersDbImport}${usersListMeta}${middlewares}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const page = Math.max(1, Number(req.query.page) || 1);\n const limit = Math.min(100, Number(req.query.limit) || 20);\n const [all, total] = await Promise.all([${db.find('User', `{}`)}, ${db.count('User', `{}`)}]);\n const users = all.slice((page - 1) * limit, page * limit).map(({ password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...u }) => u);\n res.json({ users, total, page, limit });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { name, email, password, role } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof name !== 'string' || typeof email !== 'string' || typeof password !== 'string' || !name || !email || !password) {\n return res.status(400).json({ error: 'name, email and password are required' });\n }\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const user = await ${db.create('User', `{ name, email, password: hashed, role: role ?? 'user' }`)};\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.status(201).json({ message: 'User created', user: safe });\n};\n`\n : `import { hashPassword, requireAuth } from 'express-file-cluster/auth';\n${adminUsersDbImport}${usersListMeta}${middlewares}\nexport const GET = async (req, res) => {\n${roleGuard} const page = Math.max(1, Number(req.query.page) || 1);\n const limit = Math.min(100, Number(req.query.limit) || 20);\n const [all, total] = await Promise.all([${db.find('User', `{}`)}, ${db.count('User', `{}`)}]);\n const users = all.slice((page - 1) * limit, page * limit).map(({ password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...u }) => u);\n res.json({ users, total, page, limit });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { name, email, password, role } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof name !== 'string' || typeof email !== 'string' || typeof password !== 'string' || !name || !email || !password) {\n return res.status(400).json({ error: 'name, email and password are required' });\n }\n const existing = await ${db.findOne('User', `{ email }`)};\n if (existing) return res.status(409).json({ error: 'Email already in use' });\n const hashed = await hashPassword(password);\n const user = await ${db.create('User', `{ name, email, password: hashed, role: role ?? 'user' }`)};\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.status(201).json({ message: 'User created', user: safe });\n};\n`;\n\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', `index.${ext}`),\n usersListContent,\n );\n\n const userByIdMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: 'Fetch a single user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n PUT: {\\n description: 'Update a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' }, body: { name: 'Jane Doe', email: 'jane@example.com', role: 'user', isActive: true } },\\n response: { status: 200, body: { message: 'User updated', user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n DELETE: {\\n description: 'Delete a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { message: 'User usr_01HXZ deleted' } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: 'Fetch a single user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n PUT: {\\n description: 'Update a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' }, body: { name: 'Jane Doe', email: 'jane@example.com', role: 'user', isActive: true } },\\n response: { status: 200, body: { message: 'User updated', user: { id: 'usr_01HXZ', name: 'Jane Doe', email: 'jane@example.com', role: 'user' } } },\\n },\\n DELETE: {\\n description: 'Delete a user by ID (admin only).',\\n request: { params: { id: 'usr_01HXZ' } },\\n response: { status: 200, body: { message: 'User usr_01HXZ deleted' } },\\n },\\n};\\n\\n`\n : '';\n\n const adminUserByIdDbImport = `import { User } from '../../../model/User.js';\\n`;\n\n const userByIdContent = ts\n ? `import { requireAuth, revokeAllSessions } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${adminUserByIdDbImport}${userByIdMeta}${middlewares}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const { name, email, role, isActive } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email, role, isActive }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n // The role lives in the user's JWTs: end them, or a demoted/suspended user keeps access\n // until they expire. (/auth/refresh also refuses inactive accounts.)\n if (role !== undefined || isActive === false) await revokeAllSessions(id);\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = updated;\n res.json({ message: 'User updated', user: safe });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n await ${db.delete('User', `id`)};\n await revokeAllSessions(id);\n res.json({ message: \\`User \\${id} deleted\\` });\n};\n`\n : `import { requireAuth, revokeAllSessions } from 'express-file-cluster/auth';\n${adminUserByIdDbImport}${userByIdMeta}${middlewares}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const { name, email, role, isActive } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email, role, isActive }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n // The role lives in the user's JWTs: end them, or a demoted/suspended user keeps access\n // until they expire. (/auth/refresh also refuses inactive accounts.)\n if (role !== undefined || isActive === false) await revokeAllSessions(id);\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = updated;\n res.json({ message: 'User updated', user: safe });\n};\n\nexport const DELETE = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n await ${db.delete('User', `id`)};\n await revokeAllSessions(id);\n res.json({ message: \\`User \\${id} deleted\\` });\n};\n`;\n\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', `[id].${ext}`),\n userByIdContent,\n );\n}\n\nasync function writeUserRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n const middlewares = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n\n const profileMeta = opts.routeDocs\n ? ts\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n GET: {\\n description: \"Fetch the authenticated user's profile.\",\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n PUT: {\\n description: \"Update the authenticated user's profile.\",\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com' } },\\n response: { status: 200, body: { message: 'Profile updated', user: { id: '1', role: 'user', email: 'jane@example.com' } } },\\n },\\n};\\n\\n`\n : `export const meta = {\\n GET: {\\n description: \"Fetch the authenticated user's profile.\",\\n response: { status: 200, body: { user: { id: '1', role: 'user', email: 'user@example.com' } } },\\n },\\n PUT: {\\n description: \"Update the authenticated user's profile.\",\\n request: { body: { name: 'Jane Doe', email: 'jane@example.com' } },\\n response: { status: 200, body: { message: 'Profile updated', user: { id: '1', role: 'user', email: 'jane@example.com' } } },\\n },\\n};\\n\\n`\n : '';\n\n const profileDbImport = `import { User } from '../../model/User.js';\\n`;\n\n const profileContent = ts\n ? `import { requireAuth } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\n${profileDbImport}${profileMeta}${middlewares}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = (req as any).user;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { id } = (req as any).user;\n const { name, email } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = updated;\n res.json({ message: 'Profile updated', user: safe });\n};\n`\n : `import { requireAuth } from 'express-file-cluster/auth';\n${profileDbImport}${profileMeta}${middlewares}\nexport const GET = async (req, res) => {\n const { id } = req.user;\n const user = await ${db.findById('User', `id`)};\n if (!user) return res.status(404).json({ error: 'User not found' });\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = user;\n res.json({ user: safe });\n};\n\nexport const PUT = async (req, res) => {\n const { id } = req.user;\n const { name, email } = req.body;\n const updated = await ${db.update('User', `id`, `{ name, email }`)};\n if (!updated) return res.status(404).json({ error: 'User not found' });\n const { password: _, verifyToken: _vt, resetToken: _rt, resetTokenExpiry: _re, refreshToken: _ft, refreshTokenExpiry: _fe, ...safe } = updated;\n res.json({ message: 'Profile updated', user: safe });\n};\n`;\n\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `profile.${ext}`), profileContent);\n}\n\n// ─── META HELPER ─────────────────────────────────────────────────────────\n\ninterface MethodMetaSpec {\n description: string;\n params?: string;\n query?: string;\n request?: string;\n response?: string;\n status?: number;\n}\n\nfunction mkMeta(opts: ScaffoldOptions, methods: Record<string, MethodMetaSpec>): string {\n if (!opts.routeDocs) return '';\n const blocks = Object.entries(methods)\n .map(([method, m]) => {\n const reqParts: string[] = [];\n if (m.params) reqParts.push(`params: ${m.params}`);\n if (m.query) reqParts.push(`query: ${m.query}`);\n if (m.request) reqParts.push(`body: ${m.request}`);\n const reqLine = reqParts.length ? ` request: { ${reqParts.join(', ')} },\\n` : '';\n const status = m.status ?? 200;\n const respLine =\n m.response !== undefined\n ? ` response: { status: ${status}, body: ${m.response} },\\n`\n : ` response: { status: ${status} },\\n`;\n const description = m.description.replace(/'/g, \"\\\\'\");\n return ` ${method}: {\\n description: '${description}',\\n${reqLine}${respLine} },`;\n })\n .join('\\n');\n return opts.language === 'typescript'\n ? `import type { RouteMeta } from 'express-file-cluster';\\n\\nexport const meta: RouteMeta = {\\n${blocks}\\n};\\n\\n`\n : `export const meta = {\\n${blocks}\\n};\\n\\n`;\n}\n\n// ─── EXTENDED MODEL WRITERS ───────────────────────────────────────────────\n\nasync function writeSessionModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Session = ${modelApi(opts).name}('Session', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n token: { type: 'string', required: true, unique: true },\n ip: { type: 'string', required: true },\n userAgent: { type: 'string', required: true },\n expiresAt: { type: 'date', required: true },\n isActive: { type: 'boolean', default: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Session.${ext}`), content);\n}\n\nasync function writeNotificationModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Notification = ${modelApi(opts).name}('Notification', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n title: { type: 'string', required: true },\n message: { type: 'string', required: true },\n type: { type: 'string', required: true, default: 'info' },\n isRead: { type: 'boolean', default: false },\n link: { type: 'string' },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Notification.${ext}`), content);\n}\n\nasync function writeFileModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const File = ${modelApi(opts).name}('File', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n filename: { type: 'string', required: true },\n originalName: { type: 'string', required: true },\n mimeType: { type: 'string', required: true },\n size: { type: 'number', required: true },\n url: { type: 'string', required: true },\n isPublic: { type: 'boolean', default: false },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `File.${ext}`), content);\n}\n\nasync function writeSupportTicketModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const SupportTicket = ${modelApi(opts).name}('SupportTicket', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n subject: { type: 'string', required: true },\n message: { type: 'string', required: true },\n status: { type: 'string', required: true, default: 'open' },\n priority: { type: 'string', required: true, default: 'normal' },\n${refField(opts, { field: 'assignedTo', target: 'Admin', legacy: ` assignedTo: { type: 'string' },`, onDelete: 'setNull' })}\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `SupportTicket.${ext}`), content);\n}\n\nasync function writeAuditLogModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const AuditLog = ${modelApi(opts).name}('AuditLog', {\n${refField(opts, { field: 'admin', target: 'Admin', legacy: ` adminId: { type: 'string', required: true },`, onDelete: 'setNull' })}\n action: { type: 'string', required: true },\n entity: { type: 'string', required: true },\n entityId: { type: 'string', required: true },\n metadata: { type: 'object' },\n ip: { type: 'string', required: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `AuditLog.${ext}`), content);\n}\n\nasync function writeSubscriptionModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Subscription = ${modelApi(opts).name}('Subscription', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n${refField(opts, { field: 'plan', target: 'Plan', legacy: ` planId: { type: 'string', required: true },`, required: true, onDelete: 'restrict' })}\n status: { type: 'string', required: true, default: 'active' },\n startDate: { type: 'date', required: true },\n endDate: { type: 'date', required: true },\n cancelledAt: { type: 'date' },\n}${relationsOption(opts, [{ name: 'invoices', kind: 'hasMany', target: 'Invoice', foreignKey: 'subscription' }])});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Subscription.${ext}`), content);\n}\n\nasync function writePlanModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Plan = ${modelApi(opts).name}('Plan', {\n name: { type: 'string', required: true },\n description: { type: 'string', required: true },\n price: { type: 'number', required: true },\n interval: { type: 'string', required: true, default: 'monthly' },\n features: { type: 'array', of: 'string', default: [] },\n isActive: { type: 'boolean', default: true },\n}${relationsOption(opts, [{ name: 'subscriptions', kind: 'hasMany', target: 'Subscription', foreignKey: 'plan' }])});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Plan.${ext}`), content);\n}\n\nasync function writeInvoiceModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Invoice = ${modelApi(opts).name}('Invoice', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n${refField(opts, { field: 'subscription', target: 'Subscription', legacy: ` subscriptionId: { type: 'string', required: true },`, onDelete: 'setNull' })}\n amount: { type: 'number', required: true },\n currency: { type: 'string', required: true, default: 'USD' },\n status: { type: 'string', required: true, default: 'pending' },\n paidAt: { type: 'date' },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Invoice.${ext}`), content);\n}\n\nasync function writeApiKeyModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const ApiKey = ${modelApi(opts).name}('ApiKey', {\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n name: { type: 'string', required: true },\n key: { type: 'string', required: true, unique: true },\n lastUsed: { type: 'date' },\n expiresAt: { type: 'date' },\n isActive: { type: 'boolean', default: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `ApiKey.${ext}`), content);\n}\n\nasync function writeRoleModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Role = ${modelApi(opts).name}('Role', {\n name: { type: 'string', required: true, unique: true },\n description: { type: 'string', required: true },\n permissions: { type: 'array', of: 'string', default: [] },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Role.${ext}`), content);\n}\n\nasync function writeFAQModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const FAQ = ${modelApi(opts).name}('FAQ', {\n question: { type: 'string', required: true },\n answer: { type: 'string', required: true },\n category: { type: 'string', required: true, default: 'general' },\n order: { type: 'number', default: 0 },\n isPublished: { type: 'boolean', default: false },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `FAQ.${ext}`), content);\n}\n\nasync function writeBlogModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Blog = ${modelApi(opts).name}('Blog', {\n title: { type: 'string', required: true },\n slug: { type: 'string', required: true, unique: true },\n content: { type: 'string', required: true },\n${refField(opts, { field: 'author', target: 'Admin', legacy: ` authorId: { type: 'string', required: true },`, onDelete: 'setNull' })}\n category: { type: 'string', required: true, default: 'general' },\n tags: { type: 'array', of: 'string', default: [] },\n status: { type: 'string', required: true, default: 'draft' },\n publishedAt: { type: 'date' },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Blog.${ext}`), content);\n}\n\nasync function writeCategoryModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Category = ${modelApi(opts).name}('Category', {\n name: { type: 'string', required: true },\n slug: { type: 'string', required: true, unique: true },\n description: { type: 'string' },\n${refField(opts, { field: 'parent', target: 'Category', legacy: ` parentId: { type: 'string' },`, onDelete: 'setNull' })}\n}${relationsOption(opts, [{ name: 'children', kind: 'hasMany', target: 'Category', foreignKey: 'parent' }])});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Category.${ext}`), content);\n}\n\nasync function writeCouponModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\nexport const Coupon = ${modelApi(opts).name}('Coupon', {\n code: { type: 'string', required: true, unique: true },\n type: { type: 'string', required: true, default: 'percent' },\n value: { type: 'number', required: true },\n maxUses: { type: 'number', default: 0 },\n usedCount: { type: 'number', default: 0 },\n expiresAt: { type: 'date' },\n isActive: { type: 'boolean', default: true },\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `Coupon.${ext}`), content);\n}\n\n// ─── EXTENDED ROUTE WRITERS ───────────────────────────────────────────────\n\nasync function writeAuthExtendedRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const db = orm(opts);\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n const mwUser2 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mwUser3 = mwUser2;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n const hasAdmin = principals(opts).admin;\n const uf = opts.userFeatures;\n const sendResetEmail = sendsMail(opts)\n ? ` var appUrl = process.env.APP_URL || 'http://localhost:3000';\n await enqueue('SendEmail', {\n to: email,\n subject: 'Reset your password',\n body: 'Reset your password: ' + appUrl + '/auth/reset-password?token=' + resetToken,\n });\n`\n : ` // TODO: email this token to the user — enable the Mailer feature to auto-wire SendEmail\n`;\n const sendVerifyEmailResend = sendsMail(opts)\n ? ` var appUrl = process.env.APP_URL || 'http://localhost:3000';\n await enqueue('SendEmail', {\n to: email,\n subject: 'Verify your email address',\n body: 'Verify your email: ' + appUrl + '/auth/verify-email?token=' + verifyToken,\n });\n`\n : ` // TODO: email this token to the user — enable the Mailer feature to auto-wire SendEmail\n`;\n const mailerTaskImport = sendsMail(opts)\n ? `import { enqueue } from 'express-file-cluster/tasks';\\n`\n : '';\n\n // refresh.ts\n if (uf.accountSecurity) {\n const refreshMeta = mkMeta(opts, {\n POST: {\n description: 'Refresh the JWT using the refresh-token cookie and issue a new access token.',\n response: `{ message: 'Token refreshed' }`,\n },\n });\n const refreshModelImports = `import { User } from '../../model/User.js';\\n${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`;\n const refreshLookup = hasAdmin\n ? ` const user = await ${db.findOne('User', `{ refreshToken: token }`)};\n const admin = user ? null : await ${db.findOne('Admin', `{ refreshToken: token }`)};\n const account = user || admin;`\n : ` const user = await ${db.findOne('User', `{ refreshToken: token }`)};\n const account = user;`;\n const refreshPersist = hasAdmin\n ? ` if (user) await ${db.update('User', `user.id`, `{ refreshToken: newRefreshToken, refreshTokenExpiry }`)};\n else if (admin) await ${db.update('Admin', `admin.id`, `{ refreshToken: newRefreshToken, refreshTokenExpiry }`)};`\n : ` await ${db.update('User', `user.id`, `{ refreshToken: newRefreshToken, refreshTokenExpiry }`)};`;\n const refreshContent = ts\n ? `import { issueToken } from 'express-file-cluster/auth';\nimport type { Request, Response } from 'express';\nimport crypto from 'node:crypto';\n${refreshModelImports}${refreshMeta}const REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nexport const POST = async (req: Request, res: Response) => {\n const token = req.cookies?.['efc_refresh_token'] || req.body?.refreshToken;\n if (!token) return res.status(401).json({ error: 'Refresh token required' });\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof token !== 'string') return res.status(400).json({ error: 'Invalid refresh token' });\n\n${refreshLookup}\n\n if (!account || !account.refreshTokenExpiry || new Date(account.refreshTokenExpiry) < new Date()) {\n return res.status(401).json({ error: 'Invalid or expired refresh token' });\n }\n if (account.isActive === false) return res.status(403).json({ error: 'Account suspended' });\n\n const newRefreshToken = crypto.randomBytes(40).toString('hex');\n const refreshTokenExpiry = new Date(Date.now() + REFRESH_TOKEN_TTL_MS);\n${refreshPersist}\n\n res.cookie('efc_refresh_token', newRefreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n\n const accessToken = await issueToken(res, { id: account.id, role: account.role, email: account.email });\n // bearer: the client stores both tokens itself; http-only: they travel as cookies.\n res.json({\n message: 'Token refreshed',\n ...(accessToken ? { token: accessToken, refreshToken: newRefreshToken } : {}),\n });\n};\n`\n : `import { issueToken } from 'express-file-cluster/auth';\nimport crypto from 'node:crypto';\n${refreshModelImports}${refreshMeta}const REFRESH_TOKEN_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\nexport const POST = async (req, res) => {\n const token = req.cookies?.efc_refresh_token || req.body?.refreshToken;\n if (!token) return res.status(401).json({ error: 'Refresh token required' });\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof token !== 'string') return res.status(400).json({ error: 'Invalid refresh token' });\n\n${refreshLookup}\n\n if (!account || !account.refreshTokenExpiry || new Date(account.refreshTokenExpiry) < new Date()) {\n return res.status(401).json({ error: 'Invalid or expired refresh token' });\n }\n if (account.isActive === false) return res.status(403).json({ error: 'Account suspended' });\n\n const newRefreshToken = crypto.randomBytes(40).toString('hex');\n const refreshTokenExpiry = new Date(Date.now() + REFRESH_TOKEN_TTL_MS);\n${refreshPersist}\n\n res.cookie('efc_refresh_token', newRefreshToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: REFRESH_TOKEN_TTL_MS,\n });\n\n const accessToken = await issueToken(res, { id: account.id, role: account.role, email: account.email });\n // bearer: the client stores both tokens itself; http-only: they travel as cookies.\n res.json({\n message: 'Token refreshed',\n ...(accessToken ? { token: accessToken, refreshToken: newRefreshToken } : {}),\n });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `refresh.${ext}`), refreshContent);\n }\n\n // verify-email.ts\n if (uf.emailVerification) {\n const veMeta = mkMeta(opts, {\n GET: {\n description: 'Verify an email address using the token from the verification link.',\n query: `{ token: 'a1b2c3d4' }`,\n response: `{ message: 'Email verified' }`,\n },\n POST: {\n description: 'Resend the verification email to a given address.',\n request: `{ email: 'user@example.com' }`,\n response: `{ message: 'Verification email sent' }`,\n },\n });\n const veContent = ts\n ? `import type { Request, Response } from 'express';\nimport crypto from 'node:crypto';\n${mailerTaskImport}import { User } from '../../model/User.js';\n${veMeta}export const GET = async (req: Request, res: Response) => {\n const { token } = req.query;\n if (!token || typeof token !== 'string') return res.status(400).json({ error: 'token is required' });\n\n const user = await ${db.findOne('User', `{ verifyToken: token }`)};\n if (!user) return res.status(400).json({ error: 'Invalid or expired verification token' });\n\n await ${db.update('User', `user.id`, `{ isVerified: true, verifyToken: '' }`)};\n res.json({ message: 'Email verified' });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { email } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof email !== 'string' || !email) return res.status(400).json({ error: 'email is required' });\n\n const user = await ${db.findOne('User', `{ email }`)};\n if (user && !user.isVerified) {\n const verifyToken = crypto.randomBytes(32).toString('hex');\n await ${db.update('User', `user.id`, `{ verifyToken }`)};\n${sendVerifyEmailResend} }\n\n res.json({ message: 'Verification email sent' });\n};\n`\n : `import crypto from 'node:crypto';\n${mailerTaskImport}import { User } from '../../model/User.js';\n${veMeta}export const GET = async (req, res) => {\n const { token } = req.query;\n if (!token || typeof token !== 'string') return res.status(400).json({ error: 'token is required' });\n\n const user = await ${db.findOne('User', `{ verifyToken: token }`)};\n if (!user) return res.status(400).json({ error: 'Invalid or expired verification token' });\n\n await ${db.update('User', `user.id`, `{ isVerified: true, verifyToken: '' }`)};\n res.json({ message: 'Email verified' });\n};\n\nexport const POST = async (req, res) => {\n const { email } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof email !== 'string' || !email) return res.status(400).json({ error: 'email is required' });\n\n const user = await ${db.findOne('User', `{ email }`)};\n if (user && !user.isVerified) {\n const verifyToken = crypto.randomBytes(32).toString('hex');\n await ${db.update('User', `user.id`, `{ verifyToken }`)};\n${sendVerifyEmailResend} }\n\n res.json({ message: 'Verification email sent' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `verify-email.${ext}`), veContent);\n }\n\n // forgot-password.ts / reset-password.ts\n if (uf.forgotPassword) {\n const fpMeta = mkMeta(opts, {\n POST: {\n description: 'Send a password reset email to the given address.',\n request: `{ email: 'user@example.com' }`,\n response: `{ message: 'Reset email sent' }`,\n },\n });\n const fpModelImports = `import { User } from '../../model/User.js';\\n${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`;\n const fpLookup = hasAdmin\n ? ` const user = await ${db.findOne('User', `{ email }`)};\n const admin = user ? null : await ${db.findOne('Admin', `{ email }`)};`\n : ` const user = await ${db.findOne('User', `{ email }`)};`;\n const fpGuard = hasAdmin ? 'user || admin' : 'user';\n const fpPersist = hasAdmin\n ? ` if (user) await ${db.update('User', `user.id`, `{ resetToken, resetTokenExpiry }`)};\n else if (admin) await ${db.update('Admin', `admin.id`, `{ resetToken, resetTokenExpiry }`)};`\n : ` await ${db.update('User', `user.id`, `{ resetToken, resetTokenExpiry }`)};`;\n const fpContent = ts\n ? `import type { Request, Response } from 'express';\nimport crypto from 'node:crypto';\nimport { rateLimit } from 'express-file-cluster';\n${mailerTaskImport}${fpModelImports}${fpMeta}// 5 reset emails per hour per address — keeps the endpoint from mail-bombing someone.\nexport const middlewares = [\n rateLimit({ window: '1h', max: 5, key: (req) => String(req.body?.email ?? '').toLowerCase() }),\n];\n\nconst RESET_TOKEN_TTL_MS = 1000 * 60 * 60; // 1 hour\n\nexport const POST = async (req: Request, res: Response) => {\n const { email } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof email !== 'string' || !email) return res.status(400).json({ error: 'email is required' });\n\n${fpLookup}\n\n // Always respond the same way whether or not the account exists, so this\n // endpoint can't be used to enumerate registered emails.\n if (${fpGuard}) {\n const resetToken = crypto.randomBytes(32).toString('hex');\n const resetTokenExpiry = new Date(Date.now() + RESET_TOKEN_TTL_MS);\n${fpPersist}\n${sendResetEmail} }\n\n res.json({ message: 'Reset email sent' });\n};\n`\n : `import crypto from 'node:crypto';\nimport { rateLimit } from 'express-file-cluster';\n${mailerTaskImport}${fpModelImports}${fpMeta}// 5 reset emails per hour per address — keeps the endpoint from mail-bombing someone.\nexport const middlewares = [\n rateLimit({ window: '1h', max: 5, key: (req) => String(req.body?.email ?? '').toLowerCase() }),\n];\n\nconst RESET_TOKEN_TTL_MS = 1000 * 60 * 60; // 1 hour\n\nexport const POST = async (req, res) => {\n const { email } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof email !== 'string' || !email) return res.status(400).json({ error: 'email is required' });\n\n${fpLookup}\n\n // Always respond the same way whether or not the account exists, so this\n // endpoint can't be used to enumerate registered emails.\n if (${fpGuard}) {\n const resetToken = crypto.randomBytes(32).toString('hex');\n const resetTokenExpiry = new Date(Date.now() + RESET_TOKEN_TTL_MS);\n${fpPersist}\n${sendResetEmail} }\n\n res.json({ message: 'Reset email sent' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `forgot-password.${ext}`), fpContent);\n\n // reset-password.ts\n const rpMeta = mkMeta(opts, {\n POST: {\n description: 'Reset password using a valid reset token.',\n request: `{ token: 'reset-token', password: 'newpassword' }`,\n response: `{ message: 'Password reset successfully' }`,\n },\n });\n const rpModelImports = `import { User } from '../../model/User.js';\\n${hasAdmin ? `import { Admin } from '../../model/Admin.js';\\n` : ''}`;\n const rpLookup = hasAdmin\n ? ` const user = await ${db.findOne('User', `{ resetToken: token }`)};\n const admin = user ? null : await ${db.findOne('Admin', `{ resetToken: token }`)};\n const account = user || admin;`\n : ` const user = await ${db.findOne('User', `{ resetToken: token }`)};\n const account = user;`;\n const rpPersist = hasAdmin\n ? ` if (user) await ${db.update('User', `user.id`, `{ password: hashed, resetToken: '' }`)};\n else if (admin) await ${db.update('Admin', `admin.id`, `{ password: hashed, resetToken: '' }`)};`\n : ` await ${db.update('User', `user.id`, `{ password: hashed, resetToken: '' }`)};`;\n const rpContent = ts\n ? `import type { Request, Response } from 'express';\nimport { hashPassword, revokeAllSessions } from 'express-file-cluster/auth';\n${rpModelImports}${rpMeta}export const POST = async (req: Request, res: Response) => {\n const { token, password } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof token !== 'string' || typeof password !== 'string' || !token || !password) {\n return res.status(400).json({ error: 'token and password are required' });\n }\n\n${rpLookup}\n\n if (!account || !account.resetTokenExpiry || new Date(account.resetTokenExpiry) < new Date()) {\n return res.status(400).json({ error: 'Invalid or expired reset token' });\n }\n\n const hashed = await hashPassword(password);\n${rpPersist}\n // Tokens issued with the old password stop working everywhere.\n await revokeAllSessions(account.id);\n\n res.json({ message: 'Password reset successfully' });\n};\n`\n : `import { hashPassword, revokeAllSessions } from 'express-file-cluster/auth';\n${rpModelImports}${rpMeta}export const POST = async (req, res) => {\n const { token, password } = req.body;\n // Strings only: an object such as {\"$ne\": null} would be read as a filter operator and match any account.\n if (typeof token !== 'string' || typeof password !== 'string' || !token || !password) {\n return res.status(400).json({ error: 'token and password are required' });\n }\n\n${rpLookup}\n\n if (!account || !account.resetTokenExpiry || new Date(account.resetTokenExpiry) < new Date()) {\n return res.status(400).json({ error: 'Invalid or expired reset token' });\n }\n\n const hashed = await hashPassword(password);\n${rpPersist}\n // Tokens issued with the old password stop working everywhere.\n await revokeAllSessions(account.id);\n\n res.json({ message: 'Password reset successfully' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `reset-password.${ext}`), rpContent);\n }\n\n // change-password.ts (protected)\n if (uf.accountSecurity) {\n const cpMeta = mkMeta(opts, {\n POST: {\n description: 'Change password for the authenticated user.',\n request: `{ oldPassword: 'current', newPassword: 'newpassword' }`,\n response: `{ message: 'Password changed successfully' }`,\n },\n });\n const cpContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${cpMeta}${mwUser2}\nexport const POST = async (req: Request, res: Response) => {\n const { oldPassword, newPassword } = req.body;\n if (!oldPassword || !newPassword) return res.status(400).json({ error: 'oldPassword and newPassword are required' });\n // TODO: verify old password, hash and update new password, then sign out other devices:\n // await revokeAllSessions(req.user.id) (import from 'express-file-cluster/auth')\n res.json({ message: 'Password changed successfully' });\n};\n`\n : `${RA}${cpMeta}${mwUser2}\nexport const POST = async (req, res) => {\n const { oldPassword, newPassword } = req.body;\n if (!oldPassword || !newPassword) return res.status(400).json({ error: 'oldPassword and newPassword are required' });\n // TODO: verify old password, hash and update new password, then sign out other devices:\n // await revokeAllSessions(req.user.id) (import from 'express-file-cluster/auth')\n res.json({ message: 'Password changed successfully' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', `change-password.${ext}`), cpContent);\n\n // 2fa/setup.ts\n const tfaSetupMeta = mkMeta(opts, {\n GET: {\n description: 'Generate a TOTP secret and QR code to set up 2FA.',\n response: `{ qrCode: 'otpauth://totp/...', secret: 'BASE32SECRET' }`,\n },\n POST: {\n description: 'Confirm a TOTP code to enable 2FA for the authenticated user.',\n request: `{ code: '123456' }`,\n response: `{ message: '2FA enabled' }`,\n },\n });\n const tfaSetupContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${tfaSetupMeta}${mwUser3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: generate TOTP secret and return QR code URL\n res.json({ qrCode: 'otpauth://totp/...', secret: 'BASE32SECRET' });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code and enable 2FA\n res.json({ message: '2FA enabled' });\n};\n`\n : `${RA}${tfaSetupMeta}${mwUser3}\nexport const GET = async (req, res) => {\n // TODO: generate TOTP secret and return QR code URL\n res.json({ qrCode: 'otpauth://totp/...', secret: 'BASE32SECRET' });\n};\n\nexport const POST = async (req, res) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code and enable 2FA\n res.json({ message: '2FA enabled' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', '2fa', `setup.${ext}`),\n tfaSetupContent,\n );\n\n // 2fa/verify.ts\n const tfaVerifyMeta = mkMeta(opts, {\n POST: {\n description: 'Verify a TOTP code during login.',\n request: `{ code: '123456' }`,\n response: `{ message: '2FA verified' }`,\n },\n });\n const tfaVerifyContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${tfaVerifyMeta}export const POST = async (req: Request, res: Response) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code\n res.json({ message: '2FA verified' });\n};\n`\n : `${RA}${tfaVerifyMeta}export const POST = async (req, res) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify TOTP code\n res.json({ message: '2FA verified' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', '2fa', `verify.${ext}`),\n tfaVerifyContent,\n );\n\n // 2fa/disable.ts\n const tfaDisableMeta = mkMeta(opts, {\n POST: {\n description: 'Disable 2FA for the authenticated user.',\n request: `{ code: '123456' }`,\n response: `{ message: '2FA disabled' }`,\n },\n });\n const tfaDisableContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${tfaDisableMeta}${mwUser3}\nexport const POST = async (req: Request, res: Response) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify code and disable 2FA\n res.json({ message: '2FA disabled' });\n};\n`\n : `${RA}${tfaDisableMeta}${mwUser3}\nexport const POST = async (req, res) => {\n const { code } = req.body;\n if (!code) return res.status(400).json({ error: 'code is required' });\n // TODO: verify code and disable 2FA\n res.json({ message: '2FA disabled' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', '2fa', `disable.${ext}`),\n tfaDisableContent,\n );\n\n // sessions/index.ts\n const sessListMeta = mkMeta(opts, {\n GET: {\n description: 'List all active sessions for the authenticated user.',\n response: `{ sessions: [] }`,\n },\n });\n const sessListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${sessListMeta}${mwUser3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch sessions for req.user.id\n res.json({ sessions: [] });\n};\n`\n : `${RA}${sessListMeta}${mwUser3}\nexport const GET = async (req, res) => {\n // TODO: fetch sessions for req.user.id\n res.json({ sessions: [] });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'sessions', `index.${ext}`),\n sessListContent,\n );\n\n // sessions/[id].ts\n const sessRevokeMeta = mkMeta(opts, {\n DELETE: {\n description: 'Revoke a single active session by ID.',\n params: `{ id: 'sess_01HXZ' }`,\n response: `{ message: 'Session sess_01HXZ revoked' }`,\n },\n });\n const sessRevokeContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${sessRevokeMeta}${mwUser3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: revoke session by id\n res.json({ message: \\`Session \\${id} revoked\\` });\n};\n`\n : `${RA}${sessRevokeMeta}${mwUser3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: revoke session by id\n res.json({ message: \\`Session \\${id} revoked\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'sessions', `[id].${ext}`),\n sessRevokeContent,\n );\n }\n}\n\nasync function writeUserExtendedRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // user/* = 2 levels up to src/, user/subdir/* = 3 levels\n const mw2 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mw3 = mw2;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n const user = ts ? `(req as any).user` : `req.user`;\n const uf = opts.userFeatures;\n\n // avatar.ts\n if (uf.accountSettings) {\n const avatarMeta = mkMeta(opts, {\n POST: {\n description: 'Upload a new avatar image for the authenticated user.',\n response: `{ message: 'Avatar updated', url: 'https://example.com/avatar.jpg' }`,\n },\n DELETE: {\n description: \"Remove the authenticated user's avatar.\",\n response: `{ message: 'Avatar removed' }`,\n },\n });\n const avatarContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${avatarMeta}${mw2}\nexport const POST = async (req: Request, res: Response) => {\n // TODO: handle multipart upload, store file, update user.avatar\n res.json({ message: 'Avatar updated', url: 'https://example.com/avatar.jpg' });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n // TODO: remove avatar and clear user.avatar\n res.json({ message: 'Avatar removed' });\n};\n`\n : `${RA}${avatarMeta}${mw2}\nexport const POST = async (req, res) => {\n // TODO: handle multipart upload, store file, update user.avatar\n res.json({ message: 'Avatar updated', url: 'https://example.com/avatar.jpg' });\n};\n\nexport const DELETE = async (req, res) => {\n // TODO: remove avatar and clear user.avatar\n res.json({ message: 'Avatar removed' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `avatar.${ext}`), avatarContent);\n\n // settings.ts\n const settingsMeta = mkMeta(opts, {\n GET: {\n description:\n 'Get account settings (notifications, language, theme, privacy) for the authenticated user.',\n response: `{ settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } }`,\n },\n PUT: {\n description: 'Update account settings for the authenticated user.',\n request: `{ notifications: true, language: 'en', theme: 'system', privacy: 'public' }`,\n response: `{ message: 'Settings updated', settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } }`,\n },\n });\n const settingsContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${settingsMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user settings from DB\n res.json({ settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { notifications, language, theme, privacy } = req.body;\n // TODO: update user settings in DB\n res.json({ message: 'Settings updated', settings: { notifications, language, theme, privacy } });\n};\n`\n : `${RA}${settingsMeta}${mw2}\nexport const GET = async (req, res) => {\n // TODO: fetch user settings from DB\n res.json({ settings: { notifications: true, language: 'en', theme: 'system', privacy: 'public' } });\n};\n\nexport const PUT = async (req, res) => {\n const { notifications, language, theme, privacy } = req.body;\n // TODO: update user settings in DB\n res.json({ message: 'Settings updated', settings: { notifications, language, theme, privacy } });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `settings.${ext}`), settingsContent);\n\n // account.ts\n const accountMeta = mkMeta(opts, {\n GET: {\n description: 'Download a personal data export for the authenticated user.',\n response: `{ data: { user: { id: '1', role: 'user', email: 'user@example.com' }, exportedAt: '2026-01-01T00:00:00.000Z' } }`,\n },\n DELETE: {\n description:\n 'Schedule the authenticated account for deletion (requires password confirmation).',\n request: `{ password: 'current' }`,\n response: `{ message: 'Account scheduled for deletion' }`,\n },\n });\n const accountContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${accountMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: compile and return personal data export\n res.json({ data: { user: ${user}, exportedAt: new Date().toISOString() } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { password } = req.body;\n if (!password) return res.status(400).json({ error: 'password confirmation required' });\n // TODO: verify password, schedule account deletion\n res.json({ message: 'Account scheduled for deletion' });\n};\n`\n : `${RA}${accountMeta}${mw2}\nexport const GET = async (req, res) => {\n // TODO: compile and return personal data export\n res.json({ data: { user: ${user}, exportedAt: new Date().toISOString() } });\n};\n\nexport const DELETE = async (req, res) => {\n const { password } = req.body;\n if (!password) return res.status(400).json({ error: 'password confirmation required' });\n // TODO: verify password, schedule account deletion\n res.json({ message: 'Account scheduled for deletion' });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `account.${ext}`), accountContent);\n\n // dashboard.ts\n const dashMeta = mkMeta(opts, {\n GET: {\n description: 'Personal dashboard: stats, recent activity, and quick actions.',\n response: `{ stats: {}, recentActivity: [], quickActions: [] }`,\n },\n });\n const dashContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${dashMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: aggregate personal stats and activity\n res.json({ stats: {}, recentActivity: [], quickActions: [] });\n};\n`\n : `${RA}${dashMeta}${mw2}\nexport const GET = async (req, res) => {\n // TODO: aggregate personal stats and activity\n res.json({ stats: {}, recentActivity: [], quickActions: [] });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `dashboard.${ext}`), dashContent);\n\n // activity.ts\n const actMeta = mkMeta(opts, {\n GET: {\n description: 'Paginated activity history for the authenticated user.',\n query: `{ page: '1', limit: '20' }`,\n response: `{ activities: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const actContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${actMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n const { page = 1, limit = 20 } = req.query;\n // TODO: fetch paginated activity log\n res.json({ activities: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${actMeta}${mw2}\nexport const GET = async (req, res) => {\n const { page = 1, limit = 20 } = req.query;\n // TODO: fetch paginated activity log\n res.json({ activities: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `activity.${ext}`), actContent);\n }\n\n // notifications/index.ts\n if (uf.notifications) {\n const notifListMeta = mkMeta(opts, {\n GET: {\n description: 'List notifications for the authenticated user.',\n response: `{ notifications: [], total: 0, unread: 0 }`,\n },\n POST: {\n description: 'Mark all notifications as read for the authenticated user.',\n response: `{ message: 'All notifications marked as read' }`,\n },\n });\n const notifListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${notifListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch notifications for user\n res.json({ notifications: [], total: 0, unread: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n // TODO: mark all notifications as read\n res.json({ message: 'All notifications marked as read' });\n};\n`\n : `${RA}${notifListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch notifications for user\n res.json({ notifications: [], total: 0, unread: 0 });\n};\n\nexport const POST = async (req, res) => {\n // TODO: mark all notifications as read\n res.json({ message: 'All notifications marked as read' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'notifications', `index.${ext}`),\n notifListContent,\n );\n\n // notifications/[id].ts\n const notifByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single notification by ID.',\n params: `{ id: 'notif_01HXZ' }`,\n response: `{ notification: { id: 'notif_01HXZ' } }`,\n },\n PATCH: {\n description: 'Mark a single notification as read.',\n params: `{ id: 'notif_01HXZ' }`,\n response: `{ message: 'Notification marked as read', id: 'notif_01HXZ' }`,\n },\n DELETE: {\n description: 'Delete a single notification.',\n params: `{ id: 'notif_01HXZ' }`,\n response: `{ message: 'Notification notif_01HXZ deleted' }`,\n },\n });\n const notifByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${notifByIdMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: fetch notification by id\n res.json({ notification: { id } });\n};\n\nexport const PATCH = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: mark notification as read\n res.json({ message: 'Notification marked as read', id });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete notification\n res.json({ message: \\`Notification \\${id} deleted\\` });\n};\n`\n : `${RA}${notifByIdMeta}${mw3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: fetch notification by id\n res.json({ notification: { id } });\n};\n\nexport const PATCH = async (req, res) => {\n const { id } = req.params;\n // TODO: mark notification as read\n res.json({ message: 'Notification marked as read', id });\n};\n\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete notification\n res.json({ message: \\`Notification \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'notifications', `[id].${ext}`),\n notifByIdContent,\n );\n }\n\n // files/index.ts (files, favorites, bookmarks & search share the filesAndMedia toggle)\n if (uf.filesAndMedia) {\n const filesListMeta = mkMeta(opts, {\n GET: {\n description: 'List uploaded files with storage usage for the authenticated user.',\n response: `{ files: [], total: 0, storageUsed: 0 }`,\n },\n POST: {\n description: 'Upload a new file for the authenticated user.',\n response: `{ message: 'File uploaded', file: { id: 'new-id' } }`,\n status: 201,\n },\n });\n const filesListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${filesListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user files and compute storage usage\n res.json({ files: [], total: 0, storageUsed: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n // TODO: handle multipart upload, persist file record\n res.status(201).json({ message: 'File uploaded', file: { id: 'new-id' } });\n};\n`\n : `${RA}${filesListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch user files and compute storage usage\n res.json({ files: [], total: 0, storageUsed: 0 });\n};\n\nexport const POST = async (req, res) => {\n // TODO: handle multipart upload, persist file record\n res.status(201).json({ message: 'File uploaded', file: { id: 'new-id' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'files', `index.${ext}`),\n filesListContent,\n );\n\n // files/[id].ts\n const fileByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Get a download/preview URL for a single file by ID.',\n params: `{ id: 'file_01HXZ' }`,\n response: `{ file: { id: 'file_01HXZ', url: 'https://example.com/files/file_01HXZ' } }`,\n },\n DELETE: {\n description: 'Delete a file from storage.',\n params: `{ id: 'file_01HXZ' }`,\n response: `{ message: 'File file_01HXZ deleted' }`,\n },\n });\n const fileByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${fileByIdMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: stream or redirect to file download/preview URL\n res.json({ file: { id, url: 'https://...' } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete file from storage and DB\n res.json({ message: \\`File \\${id} deleted\\` });\n};\n`\n : `${RA}${fileByIdMeta}${mw3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: stream or redirect to file download/preview URL\n res.json({ file: { id, url: 'https://...' } });\n};\n\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete file from storage and DB\n res.json({ message: \\`File \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'files', `[id].${ext}`),\n fileByIdContent,\n );\n\n // favorites/index.ts\n const favListMeta = mkMeta(opts, {\n GET: {\n description: 'List favorites for the authenticated user.',\n response: `{ favorites: [] }`,\n },\n POST: {\n description: \"Add an entity to the authenticated user's favorites.\",\n request: `{ entityId: 'post_01HXZ', entityType: 'post' }`,\n response: `{ message: 'Added to favorites' }`,\n status: 201,\n },\n });\n const favListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${favListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user favorites\n res.json({ favorites: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { entityId, entityType } = req.body;\n if (!entityId || !entityType) return res.status(400).json({ error: 'entityId and entityType are required' });\n // TODO: add to favorites\n res.status(201).json({ message: 'Added to favorites' });\n};\n`\n : `${RA}${favListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch user favorites\n res.json({ favorites: [] });\n};\n\nexport const POST = async (req, res) => {\n const { entityId, entityType } = req.body;\n if (!entityId || !entityType) return res.status(400).json({ error: 'entityId and entityType are required' });\n // TODO: add to favorites\n res.status(201).json({ message: 'Added to favorites' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'favorites', `index.${ext}`),\n favListContent,\n );\n\n // favorites/[id].ts\n const favByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Remove an entity from the authenticated user favorites.',\n params: `{ id: 'fav_01HXZ' }`,\n response: `{ message: 'Removed favorite fav_01HXZ' }`,\n },\n });\n const favByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${favByIdMeta}${mw3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: remove from favorites\n res.json({ message: \\`Removed favorite \\${id}\\` });\n};\n`\n : `${RA}${favByIdMeta}${mw3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: remove from favorites\n res.json({ message: \\`Removed favorite \\${id}\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'favorites', `[id].${ext}`),\n favByIdContent,\n );\n\n // bookmarks/index.ts\n const bkListMeta = mkMeta(opts, {\n GET: {\n description: 'List bookmarks for the authenticated user.',\n response: `{ bookmarks: [] }`,\n },\n POST: {\n description: 'Save a new bookmark for the authenticated user.',\n request: `{ url: 'https://example.com', title: 'Example' }`,\n response: `{ message: 'Bookmark saved' }`,\n status: 201,\n },\n });\n const bkListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${bkListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch user bookmarks\n res.json({ bookmarks: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { url, title } = req.body;\n if (!url) return res.status(400).json({ error: 'url is required' });\n // TODO: save bookmark\n res.status(201).json({ message: 'Bookmark saved' });\n};\n`\n : `${RA}${bkListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch user bookmarks\n res.json({ bookmarks: [] });\n};\n\nexport const POST = async (req, res) => {\n const { url, title } = req.body;\n if (!url) return res.status(400).json({ error: 'url is required' });\n // TODO: save bookmark\n res.status(201).json({ message: 'Bookmark saved' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'bookmarks', `index.${ext}`),\n bkListContent,\n );\n\n // bookmarks/[id].ts\n const bkByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Delete a bookmark by ID.',\n params: `{ id: 'bm_01HXZ' }`,\n response: `{ message: 'Bookmark bm_01HXZ removed' }`,\n },\n });\n const bkByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${bkByIdMeta}${mw3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete bookmark\n res.json({ message: \\`Bookmark \\${id} removed\\` });\n};\n`\n : `${RA}${bkByIdMeta}${mw3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete bookmark\n res.json({ message: \\`Bookmark \\${id} removed\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'bookmarks', `[id].${ext}`),\n bkByIdContent,\n );\n\n // search.ts\n const searchMeta = mkMeta(opts, {\n GET: {\n description: 'Search with filters, sort, and pagination.',\n query: `{ q: 'query', filter: 'active', sort: 'newest', page: '1', limit: '20' }`,\n response: `{ results: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const searchContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${searchMeta}${mw2}\nexport const GET = async (req: Request, res: Response) => {\n const { q, filter, sort, page = 1, limit = 20 } = req.query;\n // TODO: implement search\n res.json({ results: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${searchMeta}${mw2}\nexport const GET = async (req, res) => {\n const { q, filter, sort, page = 1, limit = 20 } = req.query;\n // TODO: implement search\n res.json({ results: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(path.join(dest, 'src', 'api', 'user', `search.${ext}`), searchContent);\n }\n\n // api-keys/index.ts\n if (uf.apiAndBilling) {\n const akListMeta = mkMeta(opts, {\n GET: {\n description: 'List API keys for the authenticated user.',\n response: `{ apiKeys: [] }`,\n },\n POST: {\n description: 'Generate a new API key for the authenticated user.',\n request: `{ name: 'CI key' }`,\n response: `{ message: 'API key created', key: 'efc_...' }`,\n status: 201,\n },\n });\n const akListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${akListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch api keys for user\n res.json({ apiKeys: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { name } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: generate and store API key\n res.status(201).json({ message: 'API key created', key: 'efc_...' });\n};\n`\n : `${RA}${akListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch api keys for user\n res.json({ apiKeys: [] });\n};\n\nexport const POST = async (req, res) => {\n const { name } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: generate and store API key\n res.status(201).json({ message: 'API key created', key: 'efc_...' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'api-keys', `index.${ext}`),\n akListContent,\n );\n\n // api-keys/[id].ts\n const akByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Revoke and delete an API key by ID.',\n params: `{ id: 'key_01HXZ' }`,\n response: `{ message: 'API key key_01HXZ revoked' }`,\n },\n });\n const akByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${akByIdMeta}${mw3}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: revoke and delete API key\n res.json({ message: \\`API key \\${id} revoked\\` });\n};\n`\n : `${RA}${akByIdMeta}${mw3}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: revoke and delete API key\n res.json({ message: \\`API key \\${id} revoked\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'api-keys', `[id].${ext}`),\n akByIdContent,\n );\n }\n}\n\nasync function writeUserBillingRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // user/billing/* = 3 levels, user/billing/subdir/* = 4 levels\n const mw3 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mw4 = mw3;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n\n // billing/plans.ts\n const plansMeta = mkMeta(opts, {\n GET: { description: 'List all available subscription plans.', response: `{ plans: [] }` },\n });\n const plansContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${plansMeta}${mw3}\nexport const GET = async (_req: Request, res: Response) => {\n // TODO: fetch active plans from DB\n res.json({ plans: [] });\n};\n`\n : `${RA}${plansMeta}${mw3}\nexport const GET = async (_req, res) => {\n // TODO: fetch active plans from DB\n res.json({ plans: [] });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', `plans.${ext}`),\n plansContent,\n );\n\n // billing/subscription.ts\n const subMeta = mkMeta(opts, {\n GET: {\n description: 'Get the current subscription for the authenticated user.',\n response: `{ subscription: null }`,\n },\n POST: {\n description: 'Subscribe the authenticated user to a plan.',\n request: `{ planId: 'plan_01HXZ' }`,\n response: `{ message: 'Subscribed', subscription: { planId: 'plan_01HXZ' } }`,\n status: 201,\n },\n DELETE: {\n description: 'Cancel the current subscription at period end.',\n response: `{ message: 'Subscription cancelled' }`,\n },\n });\n const subContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${subMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch current subscription for user\n res.json({ subscription: null });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { planId } = req.body;\n if (!planId) return res.status(400).json({ error: 'planId is required' });\n // TODO: create subscription via payment gateway\n res.status(201).json({ message: 'Subscribed', subscription: { planId } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n // TODO: cancel subscription at period end\n res.json({ message: 'Subscription cancelled' });\n};\n`\n : `${RA}${subMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch current subscription for user\n res.json({ subscription: null });\n};\n\nexport const POST = async (req, res) => {\n const { planId } = req.body;\n if (!planId) return res.status(400).json({ error: 'planId is required' });\n // TODO: create subscription via payment gateway\n res.status(201).json({ message: 'Subscribed', subscription: { planId } });\n};\n\nexport const DELETE = async (req, res) => {\n // TODO: cancel subscription at period end\n res.json({ message: 'Subscription cancelled' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', `subscription.${ext}`),\n subContent,\n );\n\n // billing/payment-methods/index.ts\n const pmListMeta = mkMeta(opts, {\n GET: {\n description: 'List payment methods for the authenticated user.',\n response: `{ paymentMethods: [] }`,\n },\n POST: {\n description: 'Attach a new payment method via the payment gateway.',\n request: `{ token: 'tok_...' }`,\n response: `{ message: 'Payment method added' }`,\n status: 201,\n },\n });\n const pmListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${pmListMeta}${mw4}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch payment methods for user\n res.json({ paymentMethods: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { token } = req.body;\n if (!token) return res.status(400).json({ error: 'payment token is required' });\n // TODO: attach payment method via payment gateway\n res.status(201).json({ message: 'Payment method added' });\n};\n`\n : `${RA}${pmListMeta}${mw4}\nexport const GET = async (req, res) => {\n // TODO: fetch payment methods for user\n res.json({ paymentMethods: [] });\n};\n\nexport const POST = async (req, res) => {\n const { token } = req.body;\n if (!token) return res.status(400).json({ error: 'payment token is required' });\n // TODO: attach payment method via payment gateway\n res.status(201).json({ message: 'Payment method added' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'payment-methods', `index.${ext}`),\n pmListContent,\n );\n\n // billing/payment-methods/[id].ts\n const pmByIdMeta = mkMeta(opts, {\n DELETE: {\n description: 'Detach a payment method from the payment gateway.',\n params: `{ id: 'pm_01HXZ' }`,\n response: `{ message: 'Payment method pm_01HXZ removed' }`,\n },\n });\n const pmByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${pmByIdMeta}${mw4}\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: detach payment method from payment gateway\n res.json({ message: \\`Payment method \\${id} removed\\` });\n};\n`\n : `${RA}${pmByIdMeta}${mw4}\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: detach payment method from payment gateway\n res.json({ message: \\`Payment method \\${id} removed\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'payment-methods', `[id].${ext}`),\n pmByIdContent,\n );\n\n // billing/invoices/index.ts\n const invListMeta = mkMeta(opts, {\n GET: {\n description: 'List all invoices for the authenticated user.',\n response: `{ invoices: [], total: 0 }`,\n },\n });\n const invListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${invListMeta}${mw4}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch invoices for user\n res.json({ invoices: [], total: 0 });\n};\n`\n : `${RA}${invListMeta}${mw4}\nexport const GET = async (req, res) => {\n // TODO: fetch invoices for user\n res.json({ invoices: [], total: 0 });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'invoices', `index.${ext}`),\n invListContent,\n );\n\n // billing/invoices/[id].ts\n const invByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Get the download URL for a single invoice by ID.',\n params: `{ id: 'inv_01HXZ' }`,\n response: `{ invoice: { id: 'inv_01HXZ', downloadUrl: 'https://example.com/invoices/inv_01HXZ.pdf' } }`,\n },\n });\n const invByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${invByIdMeta}${mw4}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: return invoice PDF URL or inline data\n res.json({ invoice: { id, downloadUrl: 'https://...' } });\n};\n`\n : `${RA}${invByIdMeta}${mw4}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: return invoice PDF URL or inline data\n res.json({ invoice: { id, downloadUrl: 'https://...' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'user', 'billing', 'invoices', `[id].${ext}`),\n invByIdContent,\n );\n}\n\nasync function writeSupportRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // support/tickets/* = 3 levels\n const mw3 = opts.rbac\n ? `export const middlewares = [requireAuth('user', 'admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n\n // support/tickets/index.ts\n const ticketListMeta = mkMeta(opts, {\n GET: {\n description: \"List the authenticated user's own support tickets.\",\n response: `{ tickets: [], total: 0 }`,\n },\n POST: {\n description: 'Create a new support ticket.',\n request: `{ subject: 'Issue with login', message: 'I cannot log in', priority: 'normal' }`,\n response: `{ message: 'Ticket created', ticket: { id: 'new-id', subject: 'Issue with login', status: 'open' } }`,\n status: 201,\n },\n });\n const ticketListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${ticketListMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n // TODO: fetch tickets for current user\n res.json({ tickets: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { subject, message, priority } = req.body;\n if (!subject || !message) return res.status(400).json({ error: 'subject and message are required' });\n // TODO: create support ticket in DB\n res.status(201).json({ message: 'Ticket created', ticket: { id: 'new-id', subject, status: 'open' } });\n};\n`\n : `${RA}${ticketListMeta}${mw3}\nexport const GET = async (req, res) => {\n // TODO: fetch tickets for current user\n res.json({ tickets: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n const { subject, message, priority } = req.body;\n if (!subject || !message) return res.status(400).json({ error: 'subject and message are required' });\n // TODO: create support ticket in DB\n res.status(201).json({ message: 'Ticket created', ticket: { id: 'new-id', subject, status: 'open' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'support', 'tickets', `index.${ext}`),\n ticketListContent,\n );\n\n // support/tickets/[id].ts\n const ticketByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single support ticket by ID.',\n params: `{ id: 'tk_01HXZ' }`,\n response: `{ ticket: { id: 'tk_01HXZ', subject: 'Issue', status: 'open', replies: [] } }`,\n },\n PUT: {\n description: 'Add a reply to a support ticket or update its status.',\n params: `{ id: 'tk_01HXZ' }`,\n request: `{ reply: 'Thanks, resolved.', status: 'closed' }`,\n response: `{ message: 'Ticket updated', ticket: { id: 'tk_01HXZ', status: 'closed' } }`,\n },\n });\n const ticketByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${ticketByIdMeta}${mw3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: fetch ticket by id, verify ownership\n res.json({ ticket: { id, subject: '', status: 'open', replies: [] } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { id } = req.params;\n const { reply, status } = req.body;\n // TODO: add reply or update status\n res.json({ message: 'Ticket updated', ticket: { id, status: status ?? 'open' } });\n};\n`\n : `${RA}${ticketByIdMeta}${mw3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: fetch ticket by id, verify ownership\n res.json({ ticket: { id, subject: '', status: 'open', replies: [] } });\n};\n\nexport const PUT = async (req, res) => {\n const { id } = req.params;\n const { reply, status } = req.body;\n // TODO: add reply or update status\n res.json({ message: 'Ticket updated', ticket: { id, status: status ?? 'open' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'support', 'tickets', `[id].${ext}`),\n ticketByIdContent,\n );\n}\n\nasync function writeAdminExtendedRoutes(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const ts = opts.language === 'typescript';\n // depth: admin/subdir/* = 3, admin/subdir/subdir/* = 4, admin/users/[id]/* = 4\n const mwAdmin3 = opts.rbac\n ? `export const middlewares = [requireAuth('admin')];\\n`\n : `export const middlewares = [requireAuth];\\n`;\n const mwAdmin4 = mwAdmin3;\n const roleGuard = opts.rbac\n ? ''\n : ts\n ? ` const user = (req as any).user;\\n if (user?.role !== 'admin') return res.status(403).json({ error: 'Forbidden' });\\n`\n : ` const user = req.user;\\n if (user?.role !== 'admin') return res.status(403).json({ error: 'Forbidden' });\\n`;\n const RA = `import { requireAuth } from 'express-file-cluster/auth';\\n`;\n const af = opts.adminFeatures;\n\n // ── Analytics ──────────────────────────────────────────────────────────\n if (af.analytics) {\n // admin/analytics/index.ts\n const analyticsOverviewMeta = mkMeta(opts, {\n GET: {\n description: 'Analytics overview: users, revenue, traffic (admin only).',\n response: `{ users: {}, revenue: {}, traffic: {} }`,\n },\n });\n const analyticsOverviewContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsOverviewMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} // TODO: aggregate analytics overview\n res.json({ users: {}, revenue: {}, traffic: {} });\n};\n`\n : `${RA}${analyticsOverviewMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} // TODO: aggregate analytics overview\n res.json({ users: {}, revenue: {}, traffic: {} });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `index.${ext}`),\n analyticsOverviewContent,\n );\n\n const analyticsUsersMeta = mkMeta(opts, {\n GET: {\n description: 'User analytics: registrations, active users, churn (admin only).',\n query: `{ period: '30d' }`,\n response: `{ registrations: [], activeUsers: 0, churn: 0, period: '30d' }`,\n },\n });\n const analyticsUsersContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsUsersMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch user analytics for period\n res.json({ registrations: [], activeUsers: 0, churn: 0, period });\n};\n`\n : `${RA}${analyticsUsersMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch user analytics for period\n res.json({ registrations: [], activeUsers: 0, churn: 0, period });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `users.${ext}`),\n analyticsUsersContent,\n );\n\n const analyticsRevenueMeta = mkMeta(opts, {\n GET: {\n description: 'Revenue analytics: MRR, ARR, payment history (admin only).',\n query: `{ period: '30d' }`,\n response: `{ mrr: 0, arr: 0, history: [], period: '30d' }`,\n },\n });\n const analyticsRevenueContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsRevenueMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch revenue analytics for period\n res.json({ mrr: 0, arr: 0, history: [], period });\n};\n`\n : `${RA}${analyticsRevenueMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch revenue analytics for period\n res.json({ mrr: 0, arr: 0, history: [], period });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `revenue.${ext}`),\n analyticsRevenueContent,\n );\n\n const analyticsTrafficMeta = mkMeta(opts, {\n GET: {\n description: 'Traffic analytics: page views, devices, countries (admin only).',\n query: `{ period: '30d' }`,\n response: `{ pageViews: 0, devices: {}, countries: {}, period: '30d' }`,\n },\n });\n const analyticsTrafficContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${analyticsTrafficMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch traffic analytics for period\n res.json({ pageViews: 0, devices: {}, countries: {}, period });\n};\n`\n : `${RA}${analyticsTrafficMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { period = '30d' } = req.query;\n // TODO: fetch traffic analytics for period\n res.json({ pageViews: 0, devices: {}, countries: {}, period });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'analytics', `traffic.${ext}`),\n analyticsTrafficContent,\n );\n }\n\n // ── User Actions ──────────────────────────────────────────────────────\n if (af.userManagement) {\n // admin/users/[id]/suspend.ts\n const suspendMeta = mkMeta(opts, {\n POST: {\n description: 'Suspend a user account (admin only).',\n params: `{ id: 'usr_01HXZ' }`,\n request: `{ reason: 'Terms of service violation' }`,\n response: `{ message: 'User usr_01HXZ suspended', reason: 'Terms of service violation' }`,\n },\n });\n const suspendContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${suspendMeta}${mwAdmin4}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const { reason } = req.body;\n // TODO: set user.isActive = false (then revokeAllSessions(id) so open sessions end), log audit event\n res.json({ message: \\`User \\${id} suspended\\`, reason });\n};\n`\n : `${RA}${suspendMeta}${mwAdmin4}\nexport const POST = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const { reason } = req.body;\n // TODO: set user.isActive = false (then revokeAllSessions(id) so open sessions end), log audit event\n res.json({ message: \\`User \\${id} suspended\\`, reason });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', '[id]', `suspend.${ext}`),\n suspendContent,\n );\n\n // admin/users/[id]/activate.ts\n const activateMeta = mkMeta(opts, {\n POST: {\n description: 'Reactivate a suspended user account (admin only).',\n params: `{ id: 'usr_01HXZ' }`,\n response: `{ message: 'User usr_01HXZ activated' }`,\n },\n });\n const activateContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${activateMeta}${mwAdmin4}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isActive = true, log audit event\n res.json({ message: \\`User \\${id} activated\\` });\n};\n`\n : `${RA}${activateMeta}${mwAdmin4}\nexport const POST = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isActive = true, log audit event\n res.json({ message: \\`User \\${id} activated\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', '[id]', `activate.${ext}`),\n activateContent,\n );\n\n // admin/users/[id]/verify.ts\n const verifyUserMeta = mkMeta(opts, {\n POST: {\n description: \"Mark a user's email as verified (admin only).\",\n params: `{ id: 'usr_01HXZ' }`,\n response: `{ message: 'User usr_01HXZ verified' }`,\n },\n });\n const verifyUserContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${verifyUserMeta}${mwAdmin4}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isVerified = true\n res.json({ message: \\`User \\${id} verified\\` });\n};\n`\n : `${RA}${verifyUserMeta}${mwAdmin4}\nexport const POST = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: set user.isVerified = true\n res.json({ message: \\`User \\${id} verified\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', '[id]', `verify.${ext}`),\n verifyUserContent,\n );\n\n // admin/users/export.ts\n const exportMeta = mkMeta(opts, {\n GET: {\n description: 'Export all users as a CSV download (admin only).',\n response: `'id,name,email,role,createdAt\\\\n'`,\n },\n });\n const exportContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${exportMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: generate CSV of all users and stream response\n res.setHeader('Content-Type', 'text/csv');\n res.setHeader('Content-Disposition', 'attachment; filename=\"users.csv\"');\n res.send('id,name,email,role,createdAt\\\\n');\n};\n`\n : `${RA}${exportMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: generate CSV of all users and stream response\n res.setHeader('Content-Type', 'text/csv');\n res.setHeader('Content-Disposition', 'attachment; filename=\"users.csv\"');\n res.send('id,name,email,role,createdAt\\\\n');\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'users', `export.${ext}`),\n exportContent,\n );\n }\n\n // ── Admins ────────────────────────────────────────────────────────────\n if (af.adminManagement) {\n // admin/admins/index.ts\n const adminsListMeta = mkMeta(opts, {\n GET: {\n description: 'List all admin accounts (admin only).',\n response: `{ admins: [], total: 0 }`,\n },\n POST: {\n description: 'Create a new admin account (admin only).',\n request: `{ name: 'Jane Doe', email: 'jane@example.com', role: 'admin' }`,\n response: `{ message: 'Admin created', admin: { id: 'new-id', name: 'Jane Doe', email: 'jane@example.com', role: 'admin' } }`,\n status: 201,\n },\n });\n const adminsListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminsListMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch admins from DB\n res.json({ admins: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { name, email, role } = req.body;\n if (!name || !email) return res.status(400).json({ error: 'name and email are required' });\n // TODO: create admin account\n res.status(201).json({ message: 'Admin created', admin: { id: 'new-id', name, email, role: role ?? 'admin' } });\n};\n`\n : `${RA}${adminsListMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch admins from DB\n res.json({ admins: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { name, email, role } = req.body;\n if (!name || !email) return res.status(400).json({ error: 'name and email are required' });\n // TODO: create admin account\n res.status(201).json({ message: 'Admin created', admin: { id: 'new-id', name, email, role: role ?? 'admin' } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'admins', `index.${ext}`),\n adminsListContent,\n );\n\n // admin/admins/[id].ts\n const adminByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single admin account by ID (admin only).',\n params: `{ id: 'adm_01HXZ' }`,\n response: `{ admin: { id: 'adm_01HXZ' } }`,\n },\n PUT: {\n description: 'Update an admin account by ID (admin only).',\n params: `{ id: 'adm_01HXZ' }`,\n request: `{ name: 'Jane Doe', role: 'admin' }`,\n response: `{ message: 'Admin updated', admin: { id: 'adm_01HXZ', name: 'Jane Doe', role: 'admin' } }`,\n },\n DELETE: {\n description: 'Delete an admin account by ID (admin only).',\n params: `{ id: 'adm_01HXZ' }`,\n response: `{ message: 'Admin adm_01HXZ deleted' }`,\n },\n });\n const adminByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminByIdMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch admin by id\n res.json({ admin: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: update admin record\n res.json({ message: 'Admin updated', admin: { id, ...req.body } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete admin\n res.json({ message: \\`Admin \\${id} deleted\\` });\n};\n`\n : `${RA}${adminByIdMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch admin by id\n res.json({ admin: { id } });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: update admin record\n res.json({ message: 'Admin updated', admin: { id, ...req.body } });\n};\n\nexport const DELETE = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete admin\n res.json({ message: \\`Admin \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'admins', `[id].${ext}`),\n adminByIdContent,\n );\n\n // ── Roles (rbac only) ─────────────────────────────────────────────────\n\n if (opts.rbac) {\n const rolesListMeta = mkMeta(opts, {\n GET: { description: 'List all roles (admin only).', response: `{ roles: [] }` },\n POST: {\n description: 'Create a new role (admin only).',\n request: `{ name: 'editor', description: 'Can edit content', permissions: ['content:write'] }`,\n response: `{ message: 'Role created', role: { id: 'new-id', name: 'editor', permissions: ['content:write'] } }`,\n status: 201,\n },\n });\n const rolesListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${rolesListMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n // TODO: fetch all roles\n res.json({ roles: [] });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n const { name, description, permissions } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: create role\n res.status(201).json({ message: 'Role created', role: { id: 'new-id', name, permissions: permissions ?? [] } });\n};\n`\n : `${RA}${rolesListMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n // TODO: fetch all roles\n res.json({ roles: [] });\n};\n\nexport const POST = async (req, res) => {\n const { name, description, permissions } = req.body;\n if (!name) return res.status(400).json({ error: 'name is required' });\n // TODO: create role\n res.status(201).json({ message: 'Role created', role: { id: 'new-id', name, permissions: permissions ?? [] } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'roles', `index.${ext}`),\n rolesListContent,\n );\n\n const roleByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single role by ID (admin only).',\n params: `{ id: 'role_01HXZ' }`,\n response: `{ role: { id: 'role_01HXZ', name: 'editor', permissions: ['content:write'] } }`,\n },\n PUT: {\n description: 'Update a role by ID (admin only).',\n params: `{ id: 'role_01HXZ' }`,\n request: `{ name: 'editor', permissions: ['content:write'] }`,\n response: `{ message: 'Role updated', role: { id: 'role_01HXZ', name: 'editor', permissions: ['content:write'] } }`,\n },\n DELETE: {\n description: 'Delete a role by ID (admin only).',\n params: `{ id: 'role_01HXZ' }`,\n response: `{ message: 'Role role_01HXZ deleted' }`,\n },\n });\n const roleByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${roleByIdMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: fetch role by id\n res.json({ role: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: update role\n res.json({ message: 'Role updated', role: { id, ...req.body } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n const { id } = req.params;\n // TODO: delete role\n res.json({ message: \\`Role \\${id} deleted\\` });\n};\n`\n : `${RA}${roleByIdMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n const { id } = req.params;\n // TODO: fetch role by id\n res.json({ role: { id } });\n};\n\nexport const PUT = async (req, res) => {\n const { id } = req.params;\n // TODO: update role\n res.json({ message: 'Role updated', role: { id, ...req.body } });\n};\n\nexport const DELETE = async (req, res) => {\n const { id } = req.params;\n // TODO: delete role\n res.json({ message: \\`Role \\${id} deleted\\` });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'roles', `[id].${ext}`),\n roleByIdContent,\n );\n }\n }\n\n // ── Notifications ─────────────────────────────────────────────────────\n if (af.notificationsAndLogs) {\n // admin/notifications/index.ts\n const adminNotifMeta = mkMeta(opts, {\n GET: {\n description: 'List all sent notifications (admin only).',\n response: `{ notifications: [], total: 0 }`,\n },\n POST: {\n description: 'Send a notification to a specific user (admin only).',\n request: `{ userId: 'usr_01HXZ', title: 'Welcome', message: 'Thanks for joining!', type: 'info' }`,\n response: `{ message: 'Notification sent' }`,\n status: 201,\n },\n });\n const adminNotifContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminNotifMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch sent notifications\n res.json({ notifications: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { userId, title, message, type } = req.body;\n if (!userId || !title || !message) return res.status(400).json({ error: 'userId, title and message are required' });\n // TODO: create and send notification to user\n res.status(201).json({ message: 'Notification sent' });\n};\n`\n : `${RA}${adminNotifMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch sent notifications\n res.json({ notifications: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { userId, title, message, type } = req.body;\n if (!userId || !title || !message) return res.status(400).json({ error: 'userId, title and message are required' });\n // TODO: create and send notification to user\n res.status(201).json({ message: 'Notification sent' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'notifications', `index.${ext}`),\n adminNotifContent,\n );\n\n // admin/notifications/broadcast.ts\n const broadcastMeta = mkMeta(opts, {\n POST: {\n description: 'Broadcast a notification to all users (admin only).',\n request: `{ title: 'Announcement', message: 'Hello everyone!', type: 'info' }`,\n response: `{ message: 'Broadcast sent', count: 0 }`,\n },\n });\n const broadcastContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${broadcastMeta}${mwAdmin3}\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { title, message, type } = req.body;\n if (!title || !message) return res.status(400).json({ error: 'title and message are required' });\n // TODO: send notification to all users\n res.json({ message: 'Broadcast sent', count: 0 });\n};\n`\n : `${RA}${broadcastMeta}${mwAdmin3}\nexport const POST = async (req, res) => {\n${roleGuard} const { title, message, type } = req.body;\n if (!title || !message) return res.status(400).json({ error: 'title and message are required' });\n // TODO: send notification to all users\n res.json({ message: 'Broadcast sent', count: 0 });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'notifications', `broadcast.${ext}`),\n broadcastContent,\n );\n\n // ── Logs ──────────────────────────────────────────────────────────────\n\n const mkLogContent = (label: string) => {\n const meta = mkMeta(opts, {\n GET: {\n description: `Paginated ${label} log entries (admin only).`,\n query: `{ page: '1', limit: '50' }`,\n response: `{ logs: [], total: 0, page: 1, limit: 50 }`,\n },\n });\n return ts\n ? `${RA}import type { Request, Response } from 'express';\n${meta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { page = 1, limit = 50 } = req.query;\n // TODO: fetch ${label} logs with pagination\n res.json({ logs: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${meta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { page = 1, limit = 50 } = req.query;\n // TODO: fetch ${label} logs with pagination\n res.json({ logs: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n };\n\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'logs', `audit.${ext}`),\n mkLogContent('audit'),\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'logs', `activity.${ext}`),\n mkLogContent('activity'),\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'logs', `security.${ext}`),\n mkLogContent('security'),\n );\n }\n\n // ── Settings & System ─────────────────────────────────────────────────\n if (af.systemSettings) {\n // admin/settings/index.ts\n const settingsMeta = mkMeta(opts, {\n GET: { description: 'Get system-wide settings (admin only).', response: `{ settings: {} }` },\n PUT: {\n description: 'Update system-wide settings (admin only).',\n request: `{ maintenanceMode: false }`,\n response: `{ message: 'Settings updated', settings: { maintenanceMode: false } }`,\n },\n });\n const settingsContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${settingsMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch system settings from DB\n res.json({ settings: {} });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} // TODO: update system settings\n res.json({ message: 'Settings updated', settings: req.body });\n};\n`\n : `${RA}${settingsMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch system settings from DB\n res.json({ settings: {} });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} // TODO: update system settings\n res.json({ message: 'Settings updated', settings: req.body });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'settings', `index.${ext}`),\n settingsContent,\n );\n\n // admin/system/health.ts\n const healthMeta = mkMeta(opts, {\n GET: {\n description: 'System health check: DB, queue, cache status (admin only).',\n response: `{ status: 'ok', db: 'ok', queue: 'ok', uptime: 12345 }`,\n },\n });\n const healthContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${healthMeta}${mwAdmin3}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: check DB connection, queue, cache health\n res.json({ status: 'ok', db: 'ok', queue: 'ok', uptime: process.uptime() });\n};\n`\n : `${RA}${healthMeta}${mwAdmin3}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: check DB connection, queue, cache health\n res.json({ status: 'ok', db: 'ok', queue: 'ok', uptime: process.uptime() });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'system', `health.${ext}`),\n healthContent,\n );\n\n // admin/system/cache.ts\n const cacheMeta = mkMeta(opts, {\n DELETE: {\n description: 'Flush the application cache (admin only).',\n response: `{ message: 'Cache cleared' }`,\n },\n });\n const cacheContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${cacheMeta}${mwAdmin3}\nexport const DELETE = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: flush Redis or in-memory cache\n res.json({ message: 'Cache cleared' });\n};\n`\n : `${RA}${cacheMeta}${mwAdmin3}\nexport const DELETE = async (_req, res) => {\n${roleGuard} // TODO: flush Redis or in-memory cache\n res.json({ message: 'Cache cleared' });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'system', `cache.${ext}`),\n cacheContent,\n );\n }\n\n // ── Support Tickets (admin view) ──────────────────────────────────────\n if (af.supportManagement) {\n // admin/tickets/index.ts\n const adminTicketsListMeta = mkMeta(opts, {\n GET: {\n description: 'List all support tickets with filters (admin only).',\n query: `{ status: 'open', priority: 'normal', page: '1', limit: '20' }`,\n response: `{ tickets: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const adminTicketsListContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminTicketsListMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { status, priority, page = 1, limit = 20 } = req.query;\n // TODO: fetch all tickets with filters\n res.json({ tickets: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${adminTicketsListMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { status, priority, page = 1, limit = 20 } = req.query;\n // TODO: fetch all tickets with filters\n res.json({ tickets: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'tickets', `index.${ext}`),\n adminTicketsListContent,\n );\n\n // admin/tickets/[id].ts\n const adminTicketByIdMeta = mkMeta(opts, {\n GET: {\n description: 'Fetch a single support ticket by ID (admin only).',\n params: `{ id: 'tk_01HXZ' }`,\n response: `{ ticket: { id: 'tk_01HXZ' } }`,\n },\n PUT: {\n description: 'Assign, reply to, or change the status of a support ticket (admin only).',\n params: `{ id: 'tk_01HXZ' }`,\n request: `{ reply: 'Looking into it.', status: 'in_progress', assignedTo: 'adm_01HXZ' }`,\n response: `{ message: 'Ticket updated', ticket: { id: 'tk_01HXZ', status: 'in_progress', assignedTo: 'adm_01HXZ' } }`,\n },\n });\n const adminTicketByIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminTicketByIdMeta}${mwAdmin3}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ticket by id\n res.json({ ticket: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n const { reply, status, assignedTo } = req.body;\n // TODO: update ticket (assign, change status, add reply)\n res.json({ message: 'Ticket updated', ticket: { id, status, assignedTo } });\n};\n`\n : `${RA}${adminTicketByIdMeta}${mwAdmin3}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ticket by id\n res.json({ ticket: { id } });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n const { reply, status, assignedTo } = req.body;\n // TODO: update ticket (assign, change status, add reply)\n res.json({ message: 'Ticket updated', ticket: { id, status, assignedTo } });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'tickets', `[id].${ext}`),\n adminTicketByIdContent,\n );\n }\n\n // Shared by Content (FAQs/blogs/categories) and Billing (plans/coupons) below.\n const mkContentCrud = (name: string, namePlural: string, dir: string[], createFields: string) => {\n const lower = name.toLowerCase();\n const firstField = createFields.split(', ')[0];\n const sampleCreateBody = `{ ${createFields\n .split(', ')\n .map((f) => `${f}: 'sample-${f}'`)\n .join(', ')} }`;\n const sampleCreatedRecord = `{ id: 'new-id', ${firstField}: 'sample-${firstField}' }`;\n const sampleFullRecord = `{ id: '${lower}_01HXZ', ${createFields\n .split(', ')\n .map((f) => `${f}: 'sample-${f}'`)\n .join(', ')} }`;\n\n const listMeta = mkMeta(opts, {\n GET: {\n description: `List all ${namePlural} (admin only).`,\n response: `{ ${namePlural}: [], total: 0 }`,\n },\n POST: {\n description: `Create a new ${lower} (admin only).`,\n request: sampleCreateBody,\n response: `{ message: '${name} created', ${lower}: ${sampleCreatedRecord} }`,\n status: 201,\n },\n });\n const listContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${listMeta}${mwAdmin4}\nexport const GET = async (_req: Request, res: Response) => {\n${roleGuard} // TODO: fetch ${namePlural}\n res.json({ ${namePlural}: [], total: 0 });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n${roleGuard} const { ${createFields} } = req.body;\n // TODO: create ${name}\n res.status(201).json({ message: '${name} created', ${lower}: { id: 'new-id', ${firstField} } });\n};\n`\n : `${RA}${listMeta}${mwAdmin4}\nexport const GET = async (_req, res) => {\n${roleGuard} // TODO: fetch ${namePlural}\n res.json({ ${namePlural}: [], total: 0 });\n};\n\nexport const POST = async (req, res) => {\n${roleGuard} const { ${createFields} } = req.body;\n // TODO: create ${name}\n res.status(201).json({ message: '${name} created', ${lower}: { id: 'new-id' } });\n};\n`;\n const byIdMeta = mkMeta(opts, {\n GET: {\n description: `Fetch a single ${lower} by ID (admin only).`,\n params: `{ id: '${lower}_01HXZ' }`,\n response: `{ ${lower}: ${sampleFullRecord} }`,\n },\n PUT: {\n description: `Update a ${lower} by ID (admin only).`,\n params: `{ id: '${lower}_01HXZ' }`,\n request: sampleCreateBody,\n response: `{ message: '${name} updated', ${lower}: ${sampleFullRecord} }`,\n },\n DELETE: {\n description: `Delete a ${lower} by ID (admin only).`,\n params: `{ id: '${lower}_01HXZ' }`,\n response: `{ message: '${name} ${lower}_01HXZ deleted' }`,\n },\n });\n const byIdContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${byIdMeta}${mwAdmin4}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ${name} by id\n res.json({ ${lower}: { id } });\n};\n\nexport const PUT = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: update ${name}\n res.json({ message: '${name} updated', ${lower}: { id, ...req.body } });\n};\n\nexport const DELETE = async (req: Request, res: Response) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete ${name}\n res.json({ message: \\`${name} \\${id} deleted\\` });\n};\n`\n : `${RA}${byIdMeta}${mwAdmin4}\nexport const GET = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: fetch ${name} by id\n res.json({ ${lower}: { id } });\n};\n\nexport const PUT = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: update ${name}\n res.json({ message: '${name} updated', ${lower}: { id, ...req.body } });\n};\n\nexport const DELETE = async (req, res) => {\n${roleGuard} const { id } = req.params;\n // TODO: delete ${name}\n res.json({ message: \\`${name} \\${id} deleted\\` });\n};\n`;\n return { listContent, byIdContent };\n };\n\n // ── Content ───────────────────────────────────────────────────────────\n if (af.contentManagement) {\n const { listContent: faqList, byIdContent: faqById } = mkContentCrud(\n 'FAQ',\n 'faqs',\n [],\n 'question, answer, category',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'faqs', `index.${ext}`),\n faqList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'faqs', `[id].${ext}`),\n faqById,\n );\n\n const { listContent: blogList, byIdContent: blogById } = mkContentCrud(\n 'Blog',\n 'blogs',\n [],\n 'title, slug, content',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'blogs', `index.${ext}`),\n blogList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'blogs', `[id].${ext}`),\n blogById,\n );\n\n const { listContent: catList, byIdContent: catById } = mkContentCrud(\n 'Category',\n 'categories',\n [],\n 'name, slug',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'categories', `index.${ext}`),\n catList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'content', 'categories', `[id].${ext}`),\n catById,\n );\n }\n\n // ── Billing (admin) ───────────────────────────────────────────────────\n if (af.billingManagement) {\n const { listContent: planList, byIdContent: planById } = mkContentCrud(\n 'Plan',\n 'plans',\n [],\n 'name, price, interval',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'plans', `index.${ext}`),\n planList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'plans', `[id].${ext}`),\n planById,\n );\n\n const { listContent: couponList, byIdContent: couponById } = mkContentCrud(\n 'Coupon',\n 'coupons',\n [],\n 'code, type, value',\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'coupons', `index.${ext}`),\n couponList,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'coupons', `[id].${ext}`),\n couponById,\n );\n\n // admin/billing/subscriptions/index.ts\n const adminSubsMeta = mkMeta(opts, {\n GET: {\n description: 'List all subscriptions with filters (admin only).',\n query: `{ status: 'active', page: '1', limit: '20' }`,\n response: `{ subscriptions: [], total: 0, page: 1, limit: 20 }`,\n },\n });\n const adminSubsContent = ts\n ? `${RA}import type { Request, Response } from 'express';\n${adminSubsMeta}${mwAdmin4}\nexport const GET = async (req: Request, res: Response) => {\n${roleGuard} const { status, page = 1, limit = 20 } = req.query;\n // TODO: fetch all subscriptions with filters\n res.json({ subscriptions: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`\n : `${RA}${adminSubsMeta}${mwAdmin4}\nexport const GET = async (req, res) => {\n${roleGuard} const { status, page = 1, limit = 20 } = req.query;\n // TODO: fetch all subscriptions with filters\n res.json({ subscriptions: [], total: 0, page: Number(page), limit: Number(limit) });\n};\n`;\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'admin', 'billing', 'subscriptions', `index.${ext}`),\n adminSubsContent,\n );\n }\n}\n\n// defineTable apps: one import that registers every model (so `include` can reach any of\n// them) and, in TypeScript, the `Tables` map that types what `include` returns.\nasync function writeModelIndex(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ts = opts.language === 'typescript';\n const ext = ts ? 'ts' : 'js';\n const names = [...generatedModels(opts)].sort();\n if (names.length === 0) return;\n const exports = names.map((n) => `export { ${n} } from './${n}.js';`).join('\\n');\n const tables = ts\n ? `\n${names.map((n) => `import type { ${n} } from './${n}.js';`).join('\\n')}\n\n// Types \\`include\\` results: relations name models by string, this maps the names to models.\ndeclare module 'express-file-cluster' {\n interface Tables {\n${names.map((n) => ` ${n}: typeof ${n};`).join('\\n')}\n }\n}\n`\n : '';\n const content = `// Every model, in one import: \\`import { User } from '../model/index.js'\\` also registers the\n// models its relations reach, which \\`include\\` needs.\n${exports}\n${tables}`;\n await fs.outputFile(path.join(dest, 'src', 'model', `index.${ext}`), content);\n}\n\n// Tables before the tables that reference them (create in this order, drop in reverse).\nconst MODEL_ORDER = [\n 'User',\n 'Admin',\n 'Plan',\n 'Category',\n 'Role',\n 'FAQ',\n 'Coupon',\n 'OAuthAccount',\n 'Session',\n 'Notification',\n 'File',\n 'SupportTicket',\n 'AuditLog',\n 'Subscription',\n 'Invoice',\n 'ApiKey',\n 'Blog',\n];\n\n// Creates every generated model's table/collection (plus indexes) on `efc db migrate`.\n// Required on PostgreSQL before first boot; on MongoDB it builds the unique indexes.\nasync function writeInitMigration(dest: string, opts: ScaffoldOptions): Promise<void> {\n const modelDir = path.join(dest, 'src', 'model');\n if (!(await fs.pathExists(modelDir))) return;\n const ts = opts.language === 'typescript';\n const ext = ts ? 'ts' : 'js';\n const rank = (n: string) =>\n MODEL_ORDER.includes(n) ? MODEL_ORDER.indexOf(n) : MODEL_ORDER.length;\n const names = (await fs.readdir(modelDir))\n .filter((f) => f.endsWith(`.${ext}`) && f !== `index.${ext}`)\n .map((f) => f.slice(0, -(ext.length + 1)))\n .sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));\n if (names.length === 0) return;\n\n const imports = names.map((n) => `import { ${n} } from '../model/${n}.js';`).join('\\n');\n const typeImport = ts ? \"import type { MigrationContext } from 'express-file-cluster';\\n\" : '';\n const sig = ts ? '(_ctx: MigrationContext): Promise<void>' : '()';\n const content = `${typeImport}${imports}\n\nconst models = [${names.join(', ')}];\n\nexport async function up${sig} {\n for (const model of models) await model.sync();\n}\n\nexport async function down${sig} {\n for (const model of [...models].reverse()) await model.drop();\n}\n`;\n await fs.outputFile(path.join(dest, 'src', 'migrations', `00000000000000_init.${ext}`), content);\n}\n\n// ── OAuth sign-in (auth@google, auth@apple) ──────────────────────────────────────────────\n// Each provider gets a redirect route and a callback route; both share src/lib/oauth (state\n// cookie, find-or-create the user, sign in) and the OAuthAccount model, which links a\n// provider identity to a User — so signing in with a provider never changes User itself.\n\nasync function writeOAuthAccountModel(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ext = opts.language === 'typescript' ? 'ts' : 'js';\n const content = `${modelApi(opts).import}\n\n// One row per provider identity (\"google:<sub>\"), linked to the User it signs in as.\nexport const OAuthAccount = ${modelApi(opts).name}('OAuthAccount', {\n key: { type: 'string', required: true, unique: true },\n provider: { type: 'string', required: true, enum: ['google', 'apple'] },\n providerId: { type: 'string', required: true },\n email: { type: 'string' },\n${refField(opts, { field: 'user', target: 'User', legacy: ` userId: { type: 'string', required: true },`, required: true, onDelete: 'cascade' })}\n});\n`;\n await fs.outputFile(path.join(dest, 'src', 'model', `OAuthAccount.${ext}`), content);\n}\n\nasync function writeOAuth(dest: string, opts: ScaffoldOptions): Promise<void> {\n const ts = opts.language === 'typescript';\n const ext = ts ? 'ts' : 'js';\n const db = orm(opts);\n const T = (s: string) => (ts ? s : '');\n // defineTable: a real foreign key `user`; defineModel: the plain `userId` string.\n const userField = usesTables(opts) && generatedModels(opts).has('User') ? 'user' : 'userId';\n\n const lib = `import crypto from 'node:crypto';\nimport { HttpError, cache } from 'express-file-cluster';\nimport { hashPassword, issueToken } from 'express-file-cluster/auth';\n${T(\"import type { Request, Response } from 'express';\\n\")}import { User } from '../model/User.js';\nimport { OAuthAccount } from '../model/OAuthAccount.js';\n\n// Shared by the OAuth sign-in routes (src/api/auth/<provider>/).\n\nconst STATE_TTL_MS = 10 * 60 * 1000; // a sign-in attempt has 10 minutes to come back\nconst CODE_TTL_S = 60; // a bearer app has a minute to exchange its sign-in code\n${T(`\nexport interface OAuthState {\n state: string;\n nonce: string;\n verifier?: string;\n /** Bearer apps: the S256 challenge of a verifier only the app knows (app ↔ this server). */\n appChallenge?: string;\n}\n\nexport interface OAuthProfile {\n provider: 'google' | 'apple';\n providerId: string;\n email?: string;\n emailVerified: boolean;\n name?: string;\n}\n`)}\n/** A random URL-safe string (state, nonce, PKCE verifier). */\nexport function randomToken()${T(': string')} {\n return crypto.randomBytes(32).toString('base64url');\n}\n\n/** The PKCE S256 challenge for a verifier. */\nexport function pkceChallenge(verifier${T(': string')})${T(': string')} {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\n/**\n * Remembers a sign-in attempt in a short-lived cookie until the provider redirects back.\n * \\`crossSite\\`: the provider POSTs the callback from its own site (Apple), so the cookie must\n * be SameSite=None — which browsers only accept with Secure (https, or localhost).\n */\nexport function rememberState(\n res${T(': Response')},\n provider${T(': string')},\n data${T(': OAuthState')},\n crossSite = false,\n)${T(': void')} {\n res.cookie(\\`efc_oauth_\\${provider}\\`, JSON.stringify(data), {\n httpOnly: true,\n secure: crossSite || process.env.NODE_ENV === 'production',\n sameSite: crossSite ? 'none' : 'lax',\n maxAge: STATE_TTL_MS,\n path: '/',\n });\n}\n\n/** The remembered attempt (cleared) — or undefined if \\`state\\` doesn't match it. */\nexport function takeState(\n req${T(': Request')},\n res${T(': Response')},\n provider${T(': string')},\n state${T(': unknown')},\n)${T(': OAuthState | undefined')} {\n const name = \\`efc_oauth_\\${provider}\\`;\n const raw = ${ts ? '(req as Request & { cookies?: Record<string, string> }).cookies?.[name]' : 'req.cookies?.[name]'};\n res.clearCookie(name, { path: '/' });\n if (!raw || typeof state !== 'string') return undefined;\n try {\n const saved = JSON.parse(raw)${T(' as OAuthState')};\n const a = Buffer.from(String(saved.state));\n const b = Buffer.from(state);\n return a.length === b.length && crypto.timingSafeEqual(a, b) ? saved : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Signs in the user behind a provider identity: the account already linked to it, else the\n * user with the same (provider-verified) email, else a new user. New users get a random\n * password — they can set a real one with the forgot-password flow.\n */\nexport async function signInWithOAuth(res${T(': Response')}, profile${T(': OAuthProfile')})${T(': Promise<string | undefined>')} {\n const key = \\`\\${profile.provider}:\\${profile.providerId}\\`;\n const account = await ${db.findOne('OAuthAccount', '{ key }')};\n let user = account ? await ${db.findById('User', `account.${userField}`)} : null;\n if (!user) {\n if (!profile.email || !profile.emailVerified) {\n throw new HttpError(400, \\`\\${profile.provider} did not return a verified email address\\`);\n }\n const email = profile.email;\n user =\n (await ${db.findOne('User', '{ email }')}) ??\n (await ${db.create(\n 'User',\n `{\n name: profile.name || email.split('@')[0],\n email,\n password: await hashPassword(randomToken()),\n isVerified: true,\n }`,\n )});\n if (account) await ${db.update('OAuthAccount', 'account.id', `{ ${userField}: user.id }`)};\n else {\n await ${db.create(\n 'OAuthAccount',\n `{\n key,\n provider: profile.provider,\n providerId: profile.providerId,\n email,\n ${userField}: user.id,\n }`,\n )};\n }\n }\n if (!user.isActive) throw new HttpError(403, 'Account suspended');\n // http-only: sets the cookie, returns undefined. bearer: returns the token.\n return issueToken(res, { id: user.id, role: user.role, email: user.email });\n}\n\n/**\n * Bearer apps start sign-in with \\`?code_challenge=<base64url SHA-256 of a random verifier>\\`\n * (PKCE, RFC 7636, between the app and this server). Only the app holding the verifier can\n * redeem the sign-in code — another app catching the myapp:// redirect can't.\n */\nexport function appChallengeFrom(query${T(': Request[\\'query\\']')})${T(': string | undefined')} {\n const challenge = query.code_challenge;\n if (challenge === undefined) return undefined;\n if (typeof challenge !== 'string' || !/^[A-Za-z0-9_-]{43}$/.test(challenge)) {\n throw new HttpError(400, 'code_challenge must be the base64url SHA-256 of your code_verifier');\n }\n return challenge;\n}\n\n/**\n * Where the browser goes once signed in. With authStrategy 'bearer' the JWT never goes in the\n * URL (history, screenshots, logs): it gets a one-time code, valid for a minute, which the app\n * that started the sign-in trades for the token at POST /auth/oauth/exchange.\n */\nexport async function successRedirect(\n token${T('?: string')},\n appChallenge${T('?: string')},\n)${T(': Promise<string>')} {\n const to = process.env.OAUTH_SUCCESS_REDIRECT || '/';\n if (!token) return to;\n if (!appChallenge) {\n throw new HttpError(\n 400,\n 'Bearer sign-in needs a code_challenge — start at /auth/<provider>?code_challenge=…',\n );\n }\n const code = randomToken();\n await cache.set(\\`oauth:code:\\${code}\\`, { token, appChallenge }, { ttl: CODE_TTL_S });\n return \\`\\${to}#code=\\${code}\\`;\n}\n\n/**\n * The token for a one-time sign-in code, given the verifier behind the challenge the sign-in\n * started with. Once: a second use (or after a minute) gets 400.\n */\nexport async function exchangeCode(code${T(': unknown')}, verifier${T(': unknown')})${T(': Promise<string>')} {\n if (typeof code !== 'string' || !code) throw new HttpError(400, 'code is required');\n if (typeof verifier !== 'string' || !/^[A-Za-z0-9._~-]{43,128}$/.test(verifier)) {\n throw new HttpError(400, 'code_verifier is required (43-128 characters)');\n }\n const key = \\`oauth:code:\\${code}\\`;\n const saved = await cache.get${T('<{ token: string; appChallenge: string }>')}(key);\n const expected = Buffer.from(saved?.appChallenge ?? '');\n const actual = Buffer.from(pkceChallenge(verifier));\n // A wrong verifier leaves the code alone, so it can't be used to burn someone's sign-in.\n if (!saved || expected.length !== actual.length || !crypto.timingSafeEqual(expected, actual)) {\n throw new HttpError(400, 'Invalid or expired sign-in code');\n }\n // del is atomic: of two requests racing with the same code, only one removes it.\n if ((await cache.del(key)) !== 1) throw new HttpError(400, 'Invalid or expired sign-in code');\n return saved.token;\n}\n`;\n\n const reqRes = (r: string) => (ts ? `(${r}: Request, res: Response)` : `(${r}, res)`);\n const typeImport = T(\"import type { Request, Response } from 'express';\\n\");\n\n const meta = (method: string, description: string) =>\n `${ts ? \"import type { RouteMeta } from 'express-file-cluster';\\n\\n\" : ''}export const meta${T(': RouteMeta')} = {\\n ${method}: { description: '${description}' },\\n};\\n\\n`;\n\n const googleStart = `${typeImport}import { appChallengeFrom, pkceChallenge, randomToken, rememberState } from '../../../lib/oauth.js';\n${meta('GET', 'Start \"Sign in with Google\": redirects to Google.')}// Redirects to Google's consent screen; Google sends the browser back to the callback route\n// (GOOGLE_REDIRECT_URI — register that exact URL in the Google Cloud console).\n// Bearer apps add ?code_challenge=… (see appChallengeFrom in src/lib/oauth).\nexport const GET = async ${reqRes('req')} => {\n const appChallenge = appChallengeFrom(req.query);\n const state = randomToken();\n const nonce = randomToken();\n const verifier = randomToken();\n rememberState(res, 'google', { state, nonce, verifier, ...(appChallenge ? { appChallenge } : {}) });\n const params = new URLSearchParams({\n client_id: process.env.GOOGLE_CLIENT_ID ?? '',\n redirect_uri: process.env.GOOGLE_REDIRECT_URI ?? '',\n response_type: 'code',\n scope: 'openid email profile',\n state,\n nonce,\n code_challenge: pkceChallenge(verifier),\n code_challenge_method: 'S256',\n prompt: 'select_account',\n });\n res.redirect(\\`https://accounts.google.com/o/oauth2/v2/auth?\\${params}\\`);\n};\n`;\n\n const googleCallback = `import { HttpError } from 'express-file-cluster';\nimport { createRemoteJWKSet, jwtVerify } from 'jose';\n${typeImport}import { signInWithOAuth, successRedirect, takeState } from '../../../lib/oauth.js';\n${meta('GET', 'Google redirects here after sign-in; signs the user in and redirects to OAUTH_SUCCESS_REDIRECT.')}const GOOGLE_KEYS = createRemoteJWKSet(new URL('https://www.googleapis.com/oauth2/v3/certs'));\n\nexport const GET = async ${reqRes('req')} => {\n const { code, state, error } = req.query;\n if (error) throw new HttpError(400, \\`Google sign-in failed: \\${String(error)}\\`);\n const saved = takeState(req, res, 'google', state);\n if (!saved || typeof code !== 'string') {\n throw new HttpError(400, 'Sign-in attempt expired or invalid — start again');\n }\n\n const tokens = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n code,\n client_id: process.env.GOOGLE_CLIENT_ID ?? '',\n client_secret: process.env.GOOGLE_CLIENT_SECRET ?? '',\n redirect_uri: process.env.GOOGLE_REDIRECT_URI ?? '',\n grant_type: 'authorization_code',\n code_verifier: saved.verifier ?? '',\n }),\n });\n if (!tokens.ok) throw new HttpError(502, \\`Google rejected the sign-in (\\${tokens.status})\\`);\n const { id_token } = (await tokens.json())${T(' as { id_token: string }')};\n\n const { payload } = await jwtVerify(id_token, GOOGLE_KEYS, {\n issuer: ['https://accounts.google.com', 'accounts.google.com'],\n audience: process.env.GOOGLE_CLIENT_ID ?? '',\n });\n if (payload.nonce !== saved.nonce) throw new HttpError(400, 'Invalid sign-in response');\n\n const token = await signInWithOAuth(res, {\n provider: 'google',\n providerId: String(payload.sub),\n email: ${ts ? 'payload.email as string | undefined' : 'payload.email'},\n emailVerified: payload.email_verified === true,\n name: ${ts ? 'payload.name as string | undefined' : 'payload.name'},\n });\n res.redirect(await successRedirect(token, saved.appChallenge));\n};\n`;\n\n const appleStart = `${typeImport}import { appChallengeFrom, randomToken, rememberState } from '../../../lib/oauth.js';\n${meta('GET', 'Start \"Sign in with Apple\": redirects to Apple.')}// Redirects to Apple; Apple POSTs the result to the callback route (APPLE_REDIRECT_URI —\n// register it on the Services ID; Apple only accepts https URLs on a verified domain).\n// Bearer apps add ?code_challenge=… (see appChallengeFrom in src/lib/oauth).\nexport const GET = async ${reqRes('req')} => {\n const appChallenge = appChallengeFrom(req.query);\n const state = randomToken();\n const nonce = randomToken();\n rememberState(res, 'apple', { state, nonce, ...(appChallenge ? { appChallenge } : {}) }, true);\n const params = new URLSearchParams({\n client_id: process.env.APPLE_CLIENT_ID ?? '',\n redirect_uri: process.env.APPLE_REDIRECT_URI ?? '',\n response_type: 'code',\n response_mode: 'form_post',\n scope: 'name email',\n state,\n nonce,\n });\n res.redirect(\\`https://appleid.apple.com/auth/authorize?\\${params}\\`);\n};\n`;\n\n const appleCallback = `import { HttpError } from 'express-file-cluster';\nimport { SignJWT, createRemoteJWKSet, importPKCS8, jwtVerify } from 'jose';\n${typeImport}import { signInWithOAuth, successRedirect, takeState } from '../../../lib/oauth.js';\n${meta('POST', 'Apple posts here after sign-in; signs the user in and redirects to OAUTH_SUCCESS_REDIRECT.')}const APPLE_KEYS = createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys'));\n\n// Apple's client secret is a short-lived ES256 JWT signed with your Sign in with Apple key\n// (APPLE_PRIVATE_KEY: the .p8 file's contents, newlines written as \\\\n).\nasync function clientSecret()${T(': Promise<string>')} {\n const key = await importPKCS8((process.env.APPLE_PRIVATE_KEY ?? '').replace(/\\\\\\\\n/g, '\\\\n'), 'ES256');\n return new SignJWT({})\n .setProtectedHeader({ alg: 'ES256', kid: process.env.APPLE_KEY_ID ?? '' })\n .setIssuer(process.env.APPLE_TEAM_ID ?? '')\n .setSubject(process.env.APPLE_CLIENT_ID ?? '')\n .setAudience('https://appleid.apple.com')\n .setIssuedAt()\n .setExpirationTime('5m')\n .sign(key);\n}\n\nexport const POST = async ${reqRes('req')} => {\n const { code, state, user, error } = req.body ?? {};\n if (error) throw new HttpError(400, \\`Apple sign-in failed: \\${String(error)}\\`);\n const saved = takeState(req, res, 'apple', state);\n if (!saved || typeof code !== 'string') {\n throw new HttpError(400, 'Sign-in attempt expired or invalid — start again');\n }\n\n const tokens = await fetch('https://appleid.apple.com/auth/token', {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n code,\n client_id: process.env.APPLE_CLIENT_ID ?? '',\n client_secret: await clientSecret(),\n redirect_uri: process.env.APPLE_REDIRECT_URI ?? '',\n grant_type: 'authorization_code',\n }),\n });\n if (!tokens.ok) throw new HttpError(502, \\`Apple rejected the sign-in (\\${tokens.status})\\`);\n const { id_token } = (await tokens.json())${T(' as { id_token: string }')};\n\n const { payload } = await jwtVerify(id_token, APPLE_KEYS, {\n issuer: 'https://appleid.apple.com',\n audience: process.env.APPLE_CLIENT_ID ?? '',\n });\n if (payload.nonce !== saved.nonce) throw new HttpError(400, 'Invalid sign-in response');\n\n // Apple sends the user's name once, on their first sign-in, as a JSON form field.\n let name${T(': string | undefined')};\n try {\n const n = typeof user === 'string' ? JSON.parse(user).name : undefined;\n name = [n?.firstName, n?.lastName].filter(Boolean).join(' ') || undefined;\n } catch {\n name = undefined;\n }\n\n const token = await signInWithOAuth(res, {\n provider: 'apple',\n providerId: String(payload.sub),\n email: ${ts ? 'payload.email as string | undefined' : 'payload.email'},\n emailVerified: payload.email_verified === true || payload.email_verified === 'true',\n name,\n });\n res.redirect(303, await successRedirect(token, saved.appChallenge));\n};\n`;\n\n const exchange = `${typeImport}import { exchangeCode } from '../../../lib/oauth.js';\n${meta('POST', 'Bearer apps: trade the one-time code from the sign-in redirect (plus the PKCE code_verifier) for a token.')}export const POST = async ${reqRes('req')} => {\n res.json({ token: await exchangeCode(req.body?.code, req.body?.code_verifier) });\n};\n`;\n\n const oauth = opts.oauth ?? {};\n await fs.outputFile(path.join(dest, 'src', 'lib', `oauth.${ext}`), lib);\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', 'oauth', `exchange.${ext}`), exchange);\n if (oauth.google) {\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'google', `index.${ext}`),\n googleStart,\n );\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'google', `callback.${ext}`),\n googleCallback,\n );\n }\n if (oauth.apple) {\n await fs.outputFile(path.join(dest, 'src', 'api', 'auth', 'apple', `index.${ext}`), appleStart);\n await fs.outputFile(\n path.join(dest, 'src', 'api', 'auth', 'apple', `callback.${ext}`),\n appleCallback,\n );\n }\n}\n","import crypto from 'node:crypto';\nimport os from 'node:os';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { scaffold, NO_ADMIN_FEATURES, NO_USER_FEATURES, type ScaffoldOptions } from './scaffold.js';\n\n// The feature registry behind `efc add` (shadcn-style): the base app is the server, src/api,\n// src/tasks and the database; every feature is a registry item whose files are copied into\n// the app and owned by it from then on. Items are rendered from the same templates\n// `create-efc-app` uses, once per variant, by scaffolding in registry mode with and without\n// the item and taking the difference — see `renderVariant`.\n\nexport interface Variant {\n key: string;\n language: ScaffoldOptions['language'];\n database: ScaffoldOptions['database'];\n modelApi: 'defineModel' | 'defineTable' | 'defineCollection';\n}\n\nexport const VARIANTS: Variant[] = (['typescript', 'javascript'] as const).flatMap((language) => {\n const lang = language === 'typescript' ? 'ts' : 'js';\n return [\n {\n key: `${lang}-mongo`,\n language,\n database: 'mongodb' as const,\n modelApi: 'defineModel' as const,\n },\n {\n key: `${lang}-mongo-collection`,\n language,\n database: 'mongodb' as const,\n modelApi: 'defineCollection' as const,\n },\n {\n key: `${lang}-pg-model`,\n language,\n database: 'postgresql' as const,\n modelApi: 'defineModel' as const,\n },\n {\n key: `${lang}-pg-table`,\n language,\n database: 'postgresql' as const,\n modelApi: 'defineTable' as const,\n },\n ];\n});\n\nexport function variantKey(v: Pick<Variant, 'language' | 'database' | 'modelApi'>): string {\n const found = VARIANTS.find(\n (x) =>\n x.language === v.language &&\n x.database === v.database &&\n (x.database === 'mongodb'\n ? (x.modelApi === 'defineCollection') === (v.modelApi === 'defineCollection')\n : x.modelApi === v.modelApi),\n );\n if (!found) throw new Error(`No registry variant for ${JSON.stringify(v)}`);\n return found.key;\n}\n\nexport type ItemGroup = 'auth' | 'user' | 'admin' | 'integrations';\n\n/**\n * A question `efc add` / `create-efc-app` asks when an item is added. Answers named like an\n * env var (UPPER_CASE) are written to .env; lower-case names are choices that only steer\n * later questions (`when`) or set env vars through the chosen option's `env`.\n */\nexport interface ItemPrompt {\n name: string;\n message: string;\n type: 'text' | 'password' | 'select' | 'file';\n options?: { value: string; label: string; hint?: string; env?: Record<string, string> }[];\n /** Default answer; `{{NAME}}` is replaced with an earlier answer. */\n default?: string;\n placeholder?: string;\n /** Only ask when earlier answers match. */\n when?: Record<string, string>;\n required?: boolean;\n /** The answer (after `stripSpaces`) must match this regex. */\n pattern?: string;\n patternMessage?: string;\n stripSpaces?: boolean;\n /** Shown before the question. */\n note?: string;\n /** Write the answer to this efc.config key instead of .env (e.g. `authStrategy`). */\n config?: string;\n}\n\nexport interface ItemDef {\n name: string;\n /** Other names `efc add` accepts for this item. */\n aliases?: string[];\n /** Questions asked when the item is added (written to .env). */\n prompts?: ItemPrompt[];\n title: string;\n description: string;\n group: ItemGroup;\n /** Other items this one needs (installed first). */\n registryDependencies: string[];\n /** Base files this item replaces (e.g. the mailer's real SendEmail task). */\n replaces?: string[];\n /** Printed after `efc add`. */\n docs?: string;\n enable(o: ScaffoldOptions): void;\n}\n\nconst user =\n (flag: keyof ScaffoldOptions['userFeatures']) =>\n (o: ScaffoldOptions): void => {\n o.userPortal = true;\n o.userFeatures = { ...o.userFeatures, [flag]: true };\n };\nconst admin =\n (flag: keyof ScaffoldOptions['adminFeatures']) =>\n (o: ScaffoldOptions): void => {\n o.adminPortal = true;\n o.adminFeatures = { ...o.adminFeatures, [flag]: true };\n };\n\n/** The token strategies, as create-efc-app and `efc add auth` offer them. */\nexport const AUTH_STRATEGY_OPTIONS = [\n {\n value: 'http-only',\n label: 'http-only cookie',\n hint: 'browsers — websites and SPAs (recommended)',\n },\n {\n value: 'bearer',\n label: 'Bearer token',\n hint: 'mobile/desktop apps, API clients — keep it in Keychain/Keystore, not localStorage',\n },\n];\n\nexport const ITEMS: ItemDef[] = [\n {\n name: 'auth',\n title: 'Authentication',\n description: 'User & Admin models; register, login, logout and me routes',\n group: 'auth',\n registryDependencies: [],\n docs: \"Tokens are issued per `authStrategy` in efc.config — 'http-only' (cookie) or 'bearer' (login returns the token; send it as Authorization: Bearer). Verification emails go through the SendEmail task; `efc add email-client` makes it send real mail.\",\n prompts: [\n {\n name: 'authStrategy',\n config: 'authStrategy',\n type: 'select',\n message: 'Authentication strategy:',\n options: AUTH_STRATEGY_OPTIONS,\n },\n ],\n enable: (o) => {\n o.userPortal = true;\n },\n },\n {\n name: 'user-profile',\n title: 'Profile',\n description: 'GET/PUT /user/profile',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('profileViewing'),\n },\n {\n name: 'forgot-password',\n title: 'Forgot / reset password',\n description: 'forgot-password and reset-password routes',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('forgotPassword'),\n },\n {\n name: 'account-security',\n title: 'Account security',\n description: 'change password, 2FA, sessions, token refresh',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('accountSecurity'),\n },\n {\n name: 'email-verification',\n title: 'Email verification',\n description: 'verify-email and resend-verification routes',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('emailVerification'),\n },\n {\n name: 'account-settings',\n title: 'Account settings',\n description: 'avatar, settings, account, dashboard, activity',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('accountSettings'),\n },\n {\n name: 'notifications',\n title: 'Notifications',\n description: 'Notification model + /user/notifications',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('notifications'),\n },\n {\n name: 'files',\n title: 'Files, favorites & bookmarks',\n description: 'File model + files, favorites, bookmarks, search',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('filesAndMedia'),\n },\n {\n name: 'billing',\n title: 'API keys & billing',\n description: 'Plan, Subscription, Invoice, ApiKey models + user billing routes',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('apiAndBilling'),\n },\n {\n name: 'support',\n title: 'Support tickets',\n description: 'SupportTicket model + create & view own tickets',\n group: 'user',\n registryDependencies: ['auth'],\n enable: user('support'),\n },\n {\n name: 'admin',\n title: 'Admin portal',\n description: \"admin dashboard stats, behind requireAuth('admin')\",\n group: 'admin',\n registryDependencies: ['auth'],\n enable: (o) => {\n o.adminPortal = true;\n },\n },\n {\n name: 'admin-users',\n title: 'User management',\n description: 'list/create/suspend/verify/export users + stats',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('userManagement'),\n },\n {\n name: 'admin-admins',\n title: 'Admin & role management',\n description: 'manage other admins + Role model',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('adminManagement'),\n },\n {\n name: 'admin-analytics',\n title: 'Analytics',\n description: 'users, revenue, traffic dashboards',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('analytics'),\n },\n {\n name: 'admin-content',\n title: 'Content management',\n description: 'FAQ, Blog, Category models + admin routes',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('contentManagement'),\n },\n {\n name: 'admin-billing',\n title: 'Billing management',\n description: 'Plan, Coupon models + plans, coupons, subscriptions',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('billingManagement'),\n },\n {\n name: 'admin-support',\n title: 'Support desk',\n description: 'view & respond to support tickets',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('supportManagement'),\n },\n {\n name: 'admin-logs',\n title: 'Notifications & audit logs',\n description: 'broadcast + audit/activity/security logs',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('notificationsAndLogs'),\n },\n {\n name: 'admin-system',\n title: 'System settings & health',\n description: 'app settings, health check, cache',\n group: 'admin',\n registryDependencies: ['admin'],\n enable: admin('systemSettings'),\n },\n {\n name: 'auth@google',\n title: 'Sign in with Google',\n description: 'GET /auth/google → Google → /auth/google/callback (OpenID Connect + PKCE)',\n group: 'auth',\n registryDependencies: ['auth'],\n docs: 'Create an OAuth client (type \"Web application\") at console.cloud.google.com → APIs & Services → Credentials, and add GOOGLE_REDIRECT_URI as an authorised redirect URI. Send users to GET /v1/api/auth/google to sign in.',\n prompts: [\n {\n name: 'GOOGLE_CLIENT_ID',\n type: 'text',\n message: 'Google OAuth client ID:',\n placeholder: '1234-abc.apps.googleusercontent.com',\n required: true,\n pattern: '\\\\.apps\\\\.googleusercontent\\\\.com$',\n patternMessage: 'Google client IDs end in .apps.googleusercontent.com',\n note: 'console.cloud.google.com → APIs & Services → Credentials → Create credentials → OAuth client ID (Web application).',\n },\n {\n name: 'GOOGLE_CLIENT_SECRET',\n type: 'password',\n message: 'Google OAuth client secret:',\n required: true,\n },\n {\n name: 'GOOGLE_REDIRECT_URI',\n type: 'text',\n message: 'Redirect URI (register it on the client):',\n default: 'http://localhost:3000/v1/api/auth/google/callback',\n },\n {\n name: 'OAUTH_SUCCESS_REDIRECT',\n type: 'text',\n message: 'Where to send the browser after sign-in:',\n default: 'http://localhost:3000/',\n },\n ],\n enable: (o) => {\n o.userPortal = true;\n o.oauth = { ...o.oauth, google: true };\n },\n },\n {\n name: 'auth@apple',\n title: 'Sign in with Apple',\n description: 'GET /auth/apple → Apple → POST /auth/apple/callback (form_post)',\n group: 'auth',\n registryDependencies: ['auth'],\n docs: 'Needs a Services ID with Sign in with Apple enabled, its return URL set to APPLE_REDIRECT_URI (https, on a verified domain — Apple rejects localhost), and a Sign in with Apple key (.p8). Send users to GET /v1/api/auth/apple to sign in.',\n prompts: [\n {\n name: 'APPLE_CLIENT_ID',\n type: 'text',\n message: 'Services ID (client ID):',\n placeholder: 'com.yourapp.signin',\n required: true,\n note: 'developer.apple.com → Certificates, IDs & Profiles: a Services ID with Sign in with Apple, and a key with Sign in with Apple (.p8).',\n },\n {\n name: 'APPLE_TEAM_ID',\n type: 'text',\n message: 'Team ID:',\n required: true,\n pattern: '^[A-Z0-9]{10}$',\n patternMessage: 'Team IDs are 10 characters (A-Z, 0-9)',\n },\n {\n name: 'APPLE_KEY_ID',\n type: 'text',\n message: 'Key ID:',\n required: true,\n pattern: '^[A-Z0-9]{10}$',\n patternMessage: 'Key IDs are 10 characters (A-Z, 0-9)',\n },\n {\n name: 'APPLE_PRIVATE_KEY',\n type: 'file',\n message: 'Path to the .p8 key file:',\n placeholder: './AuthKey_ABCDE12345.p8',\n required: true,\n pattern: 'BEGIN PRIVATE KEY',\n patternMessage: \"That file doesn't look like a .p8 private key\",\n },\n {\n name: 'APPLE_REDIRECT_URI',\n type: 'text',\n message: 'Return URL (https, registered on the Services ID):',\n default: 'https://api.yourapp.com/v1/api/auth/apple/callback',\n pattern: '^https://',\n patternMessage: 'Apple only accepts https return URLs',\n },\n {\n name: 'OAUTH_SUCCESS_REDIRECT',\n type: 'text',\n message: 'Where to send the browser after sign-in:',\n default: 'http://localhost:3000/',\n },\n ],\n enable: (o) => {\n o.userPortal = true;\n o.oauth = { ...o.oauth, apple: true };\n },\n },\n {\n name: 'email-client',\n aliases: ['mailer'],\n title: 'Email client',\n description: 'SendEmail task over SMTP (nodemailer) — Gmail or any SMTP server',\n group: 'integrations',\n registryDependencies: [],\n replaces: ['src/tasks/SendEmail.ts', 'src/tasks/SendEmail.js'],\n docs: \"Every enqueue('SendEmail', { to, subject, body }) now sends real mail. Change SMTP settings in .env.\",\n prompts: [\n {\n name: 'provider',\n type: 'select',\n message: 'Email provider:',\n options: [\n {\n value: 'gmail',\n label: 'Gmail',\n hint: 'smtp.gmail.com, preconfigured',\n env: { SMTP_HOST: 'smtp.gmail.com', SMTP_PORT: '465' },\n },\n { value: 'custom', label: 'Other (custom SMTP)', hint: \"you'll provide host + port\" },\n ],\n },\n {\n name: 'SMTP_HOST',\n type: 'text',\n message: 'SMTP host:',\n placeholder: 'smtp.mailtrap.io',\n required: true,\n when: { provider: 'custom' },\n },\n {\n name: 'SMTP_PORT',\n type: 'text',\n message: 'SMTP port:',\n default: '587',\n when: { provider: 'custom' },\n },\n {\n name: 'SMTP_USER',\n type: 'text',\n message: 'Gmail address:',\n placeholder: 'you@gmail.com',\n required: true,\n when: { provider: 'gmail' },\n },\n {\n name: 'SMTP_USER',\n type: 'text',\n message: 'SMTP username / email:',\n placeholder: 'you@example.com',\n required: true,\n when: { provider: 'custom' },\n },\n {\n name: 'SMTP_PASS',\n type: 'password',\n message: 'Gmail app password (16 characters):',\n required: true,\n stripSpaces: true,\n pattern: '^\\\\S{16}$',\n patternMessage:\n 'Gmail app passwords are 16 characters — this looks like a regular password, not an app password',\n when: { provider: 'gmail' },\n note: 'Google no longer accepts your regular password for SMTP. Generate a 16-character App Password: Google Account → Security → 2-Step Verification → App passwords.',\n },\n {\n name: 'SMTP_PASS',\n type: 'password',\n message: 'SMTP password:',\n required: true,\n when: { provider: 'custom' },\n },\n { name: 'SMTP_FROM', type: 'text', message: 'From address:', default: '{{SMTP_USER}}' },\n {\n name: 'APP_URL',\n type: 'text',\n message: 'App URL (used in email links):',\n default: 'http://localhost:3000',\n },\n ],\n enable: (o) => {\n o.mailer = true;\n },\n },\n];\n\nconst BY_NAME = new Map(\n ITEMS.flatMap((i) => [i.name, ...(i.aliases ?? [])].map((n) => [n, i] as const)),\n);\n\nexport function getItem(name: string): ItemDef {\n const item = BY_NAME.get(name);\n if (!item) throw new Error(`Unknown registry item \"${name}\"`);\n return item;\n}\n\n/** `names` plus everything they depend on, dependencies first. */\nexport function withDependencies(names: Iterable<string>): string[] {\n const out: string[] = [];\n const visit = (alias: string, stack: string[]): void => {\n const name = getItem(alias).name;\n if (out.includes(name)) return;\n if (stack.includes(name)) throw new Error(`Dependency cycle: ${[...stack, name].join(' → ')}`);\n for (const dep of getItem(name).registryDependencies) visit(dep, [...stack, name]);\n out.push(name);\n };\n for (const name of names) visit(name, []);\n return out;\n}\n\n/**\n * Scaffold options for a registry-mode app of this variant with these items. The base is\n * the server, src/api, src/tasks and the database; everything else comes from the items.\n */\nexport function registryOptions(\n v: Pick<Variant, 'language' | 'database' | 'modelApi'>,\n items: Iterable<string> = [],\n extra: Partial<ScaffoldOptions> = {},\n): ScaffoldOptions {\n const o: ScaffoldOptions = {\n projectName: 'efc-app',\n language: v.language,\n database: v.database,\n modelApi: v.modelApi,\n authStrategy: 'http-only',\n cluster: true,\n tasks: true,\n taskBackend: v.database === 'postgresql' ? 'pg-boss' : 'bullmq',\n routeDocs: true,\n userPortal: false,\n adminPortal: false,\n adminFeatures: { ...NO_ADMIN_FEATURES },\n userFeatures: { ...NO_USER_FEATURES },\n rbac: true,\n mailer: false,\n ...extra,\n registry: true,\n };\n for (const name of withDependencies(items)) getItem(name).enable(o);\n return o;\n}\n\n/**\n * Files the CLI owns or merges rather than copies: package.json and .env* are merged,\n * the model index and migrations are generated, the rest belongs to the base.\n */\nexport function isManagedPath(p: string): boolean {\n return (\n p === 'package.json' ||\n p === '.env' ||\n p === '.env.example' ||\n p === 'AGENTS.md' ||\n p === '.gitignore' ||\n p === 'tsconfig.json' ||\n /^efc\\.config\\.[jt]s$/.test(p) ||\n /^src\\/index\\.[jt]s$/.test(p) ||\n /^src\\/model\\/index\\.[jt]s$/.test(p) ||\n p.startsWith('src/migrations/')\n );\n}\n\nexport function sha256(content: string): string {\n return crypto.createHash('sha256').update(content).digest('hex');\n}\n\n/** Every file `scaffold(opts)` writes, keyed by POSIX path relative to the app. */\nexport async function renderTree(opts: ScaffoldOptions): Promise<Map<string, string>> {\n const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'efc-registry-'));\n // An absolute projectName makes scaffold() write there (no chdir — unavailable in workers).\n const root = path.join(tmp, opts.projectName);\n await scaffold({ ...opts, projectName: root });\n const out = new Map<string, string>();\n const walk = async (dir: string): Promise<void> => {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const abs = path.join(dir, entry.name);\n if (entry.isDirectory()) await walk(abs);\n else\n out.set(path.relative(root, abs).split(path.sep).join('/'), await fs.readFile(abs, 'utf8'));\n }\n };\n await walk(root);\n await fs.remove(tmp);\n return out;\n}\n\nexport interface EnvVar {\n key: string;\n /** Value written to .env. */\n value: string;\n /** Value written to .env.example. */\n example: string;\n}\n\nexport interface RenderedItem {\n name: string;\n files: { path: string; content: string }[];\n dependencies: Record<string, string>;\n devDependencies: Record<string, string>;\n env: EnvVar[];\n}\n\nexport interface RegistryIndexItem {\n name: string;\n title: string;\n description: string;\n group: ItemGroup;\n registryDependencies: string[];\n replaces: string[];\n aliases: string[];\n prompts: ItemPrompt[];\n docs?: string;\n /** Whether the item's routes enqueue tasks (needs a task backend). */\n requiresTasks: boolean;\n}\n\nexport function parseEnv(text: string | undefined): Map<string, string> {\n const out = new Map<string, string>();\n for (const line of (text ?? '').split('\\n')) {\n const m = /^([A-Z0-9_]+)=(.*)$/.exec(line);\n if (m) out.set(m[1]!, m[2]!);\n }\n return out;\n}\n\nfunction pkgDeps(text: string | undefined, field: 'dependencies' | 'devDependencies') {\n return (JSON.parse(text ?? '{}')[field] ?? {}) as Record<string, string>;\n}\n\nfunction added(a: Record<string, string>, b: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.entries(b).filter(([k]) => !(k in a)));\n}\n\n/**\n * Render every item of one variant. An item's files are what scaffolding with the item adds\n * to (or, for `replaces`, changes in) scaffolding with only its dependencies. Throws if an\n * item isn't self-contained: if it changes another item's or the base's files, or if its\n * files come out differently once every other item is installed too.\n */\nexport async function renderVariant(v: Variant): Promise<{\n /** The base app's own files (no package.json, .env, config or entry point). */\n base: { path: string; content: string }[];\n items: RenderedItem[];\n index: RegistryIndexItem[];\n}> {\n const cache = new Map<string, Promise<Map<string, string>>>();\n const render = (names: string[]) => {\n const key = withDependencies(names).sort().join(',');\n if (!cache.has(key)) cache.set(key, renderTree(registryOptions(v, names)));\n return cache.get(key)!;\n };\n\n const full = await render(ITEMS.map((i) => i.name));\n const base = await render([]);\n const claimed = new Set([...base.keys()].filter((p) => !isManagedPath(p)));\n const problems: string[] = [];\n const items: RenderedItem[] = [];\n const index: RegistryIndexItem[] = [];\n\n for (const item of ITEMS) {\n const before = await render(item.registryDependencies);\n const after = await render([item.name]);\n const files: { path: string; content: string }[] = [];\n for (const [p, content] of after) {\n if (isManagedPath(p) || before.get(p) === content) continue;\n if (before.has(p) && !item.replaces?.includes(p)) {\n problems.push(`${v.key}: ${item.name} changes ${p}, which its dependencies already write`);\n continue;\n }\n if (full.get(p) !== content) {\n problems.push(`${v.key}: ${item.name}'s ${p} depends on other items being installed`);\n }\n files.push({ path: p, content });\n claimed.add(p);\n }\n for (const p of before.keys()) {\n if (!after.has(p)) problems.push(`${v.key}: ${item.name} removes ${p}`);\n }\n for (const managed of ['AGENTS.md', 'tsconfig.json', '.gitignore']) {\n if (before.get(managed) !== after.get(managed)) {\n problems.push(`${v.key}: ${item.name} changes ${managed}`);\n }\n }\n for (const p of after.keys()) {\n if (/^(efc\\.config|src\\/index)\\.[jt]s$/.test(p) && before.get(p) !== after.get(p)) {\n problems.push(`${v.key}: ${item.name} changes ${p}`);\n }\n }\n\n const envBefore = parseEnv(before.get('.env'));\n const envAfter = parseEnv(after.get('.env'));\n const exampleAfter = parseEnv(after.get('.env.example'));\n const env: EnvVar[] = [...envAfter]\n .filter(([k]) => !envBefore.has(k))\n .map(([key, value]) => ({ key, value, example: exampleAfter.get(key) ?? value }));\n\n files.sort((a, b) => a.path.localeCompare(b.path));\n items.push({\n name: item.name,\n files,\n dependencies: added(\n pkgDeps(before.get('package.json'), 'dependencies'),\n pkgDeps(after.get('package.json'), 'dependencies'),\n ),\n devDependencies: added(\n pkgDeps(before.get('package.json'), 'devDependencies'),\n pkgDeps(after.get('package.json'), 'devDependencies'),\n ),\n env,\n });\n index.push({\n name: item.name,\n title: item.title,\n description: item.description,\n group: item.group,\n registryDependencies: item.registryDependencies,\n replaces: item.replaces ?? [],\n aliases: item.aliases ?? [],\n prompts: item.prompts ?? [],\n ...(item.docs ? { docs: item.docs } : {}),\n requiresTasks: files.some(\n (f) =>\n f.content.includes(\"from 'express-file-cluster/tasks'\") && /\\benqueue\\(/.test(f.content),\n ),\n });\n }\n\n for (const p of full.keys()) {\n if (!isManagedPath(p) && !claimed.has(p)) problems.push(`${v.key}: no item owns ${p}`);\n }\n if (problems.length)\n throw new Error(`Registry items aren't self-contained:\\n ${problems.join('\\n ')}`);\n const baseFiles = [...base]\n .filter(([p]) => !isManagedPath(p))\n .map(([p, content]) => ({ path: p, content }))\n .sort((a, b) => a.path.localeCompare(b.path));\n return { base: baseFiles, items, index };\n}\n\n/**\n * efc.json for a freshly scaffolded app: its variant, the items it was created with, and the\n * hash of every file efc wrote — so `efc add` can later tell untouched files from changed ones.\n */\nexport async function writeManifest(\n dest: string,\n opts: ScaffoldOptions,\n items: string[],\n): Promise<void> {\n const pkg = (await fs.readJson(path.join(dest, 'package.json'))) as {\n dependencies: Record<string, string>;\n };\n const files: Record<string, string> = {};\n const walk = async (dir: string): Promise<void> => {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n if (entry.name === 'node_modules') continue;\n const abs = path.join(dir, entry.name);\n if (entry.isDirectory()) await walk(abs);\n else {\n const rel = path.relative(dest, abs).split(path.sep).join('/');\n if (!isManagedPath(rel)) files[rel] = sha256(await fs.readFile(abs, 'utf8'));\n }\n }\n };\n await walk(dest);\n const manifest = {\n registry: (pkg.dependencies['express-file-cluster'] ?? '').replace(/^[^\\d]*/, ''),\n language: opts.language,\n database: opts.database,\n modelApi:\n opts.database === 'postgresql'\n ? (opts.modelApi ?? 'defineTable')\n : opts.modelApi === 'defineModel'\n ? 'defineModel'\n : 'defineCollection',\n tasks: opts.tasks ? (opts.taskBackend ?? 'bullmq') : null,\n items: [...withDependencies(items)].sort(),\n files: Object.fromEntries(Object.entries(files).sort(([a], [b]) => a.localeCompare(b))),\n };\n await fs.writeFile(path.join(dest, 'efc.json'), JSON.stringify(manifest, null, 2) + '\\n');\n}\n\n// ── Item prompts (same rules as `efc add` in core's src/cli/registry.ts) ──────────────────\n\nexport type PromptAnswers = Record<string, string>;\n\nconst isEnvName = (name: string): boolean => /^[A-Z][A-Z0-9_]*$/.test(name);\n\n/** Whether a prompt applies, given the answers so far. */\nexport function promptApplies(p: ItemPrompt, answers: PromptAnswers): boolean {\n return Object.entries(p.when ?? {}).every(([k, v]) => answers[k] === v);\n}\n\n/** The default for a prompt, with `{{NAME}}` filled in from earlier answers. */\nexport function promptDefault(p: ItemPrompt, answers: PromptAnswers): string | undefined {\n return p.default?.replace(/\\{\\{(\\w+)\\}\\}/g, (_, k: string) => answers[k] ?? '');\n}\n\n/** The stored value for an answer, or why it's not acceptable. */\nexport function normalizeAnswer(\n p: ItemPrompt,\n raw: string,\n cwd: string = process.cwd(),\n): { value: string } | { error: string } {\n let value = p.stripSpaces ? raw.replace(/\\s/g, '') : raw.trim();\n if (!value) return p.required ? { error: 'Required' } : { value };\n if (p.type === 'file') {\n const file = path.resolve(cwd, value.replace(/^~(?=$|\\/)/, os.homedir()));\n if (!fs.existsSync(file)) return { error: `No such file: ${file}` };\n value = fs.readFileSync(file, 'utf8').trim();\n }\n if (p.pattern && !new RegExp(p.pattern).test(value)) {\n return { error: p.patternMessage ?? `Must match ${p.pattern}` };\n }\n if (p.type === 'file') value = value.replace(/\\r?\\n/g, '\\\\n');\n return { value };\n}\n\n/** Env values from the answers: answers named like env vars, plus what chosen options set. */\nexport function envFromAnswers(\n prompts: ItemPrompt[],\n answers: PromptAnswers,\n): Record<string, string> {\n const env: Record<string, string> = {};\n for (const p of prompts) {\n if (!(p.name in answers) || !promptApplies(p, answers)) continue;\n if (isEnvName(p.name)) env[p.name] = answers[p.name]!;\n const chosen = p.options?.find((o) => o.value === answers[p.name]);\n Object.assign(env, chosen?.env ?? {});\n }\n return env;\n}\n\n/** The prompts of these items, in order, without repeats. */\nexport function itemPrompts(items: string[]): ItemPrompt[] {\n const out: ItemPrompt[] = [];\n for (const name of items) {\n for (const p of getItem(name).prompts ?? []) {\n const dup = out.some(\n (q) => q.name === p.name && JSON.stringify(q.when) === JSON.stringify(p.when),\n );\n if (!dup) out.push(p);\n }\n }\n return out;\n}\n\n/** Sets vars in a .env file: replaces their lines, appends the rest. */\nexport async function setEnvValues(file: string, env: Record<string, string>): Promise<void> {\n const line = (k: string, v: string) =>\n !/[\\s#\"'`]/.test(v)\n ? `${k}=${v}`\n : v.includes(\"'\")\n ? `${k}=\"${v.replace(/\"/g, '\\\\\"')}\"`\n : `${k}='${v}'`;\n const lines = (await fs.pathExists(file)) ? (await fs.readFile(file, 'utf8')).split('\\n') : [];\n const rest = { ...env };\n const out = lines.map((l) => {\n const key = /^([A-Za-z0-9_]+)=/.exec(l)?.[1];\n if (key === undefined || !(key in rest)) return l;\n const v = rest[key]!;\n delete rest[key];\n return line(key, v);\n });\n for (const [k, v] of Object.entries(rest)) out.push(line(k, v));\n await fs.writeFile(file, out.join('\\n'));\n}\n"],"mappings":"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","names":["path","user","admin","crypto","path","fs","p","crypto","fs","path","p","cancel","modelApi","r","spinner","path"]}
|