@forinda/kickjs-cli 3.0.3 → 3.0.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["colors","generateController","generateController","colors"],"sources":["../src/utils/fs.ts","../src/utils/colors.ts","../src/utils/prompts.ts","../src/utils/naming.ts","../src/generators/templates/module-index.ts","../src/generators/templates/controller.ts","../src/generators/templates/constants.ts","../src/generators/templates/dtos.ts","../src/generators/templates/use-cases.ts","../src/generators/templates/repository.ts","../src/generators/templates/domain.ts","../src/generators/templates/tests.ts","../src/generators/templates/rest-service.ts","../src/generators/templates/cqrs.ts","../src/generators/templates/drizzle/index.ts","../src/generators/templates/prisma/index.ts","../src/generators/templates/project-app.ts","../src/generators/patterns/minimal.ts","../src/generators/patterns/rest.ts","../src/generators/patterns/cqrs.ts","../src/generators/patterns/ddd.ts","../src/generators/module.ts","../src/generators/adapter.ts","../src/utils/resolve-out-dir.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/templates/project-config.ts","../src/generators/templates/project-docs.ts","../src/generators/project.ts","../src/config.ts"],"sourcesContent":["import { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\nlet _dryRun = false\n\n/** Enable/disable dry run mode globally for all writeFileSafe calls */\nexport function setDryRun(enabled: boolean): void {\n _dryRun = enabled\n}\n\n/** Write a file, creating parent directories if needed. Skips writing in dry run mode. */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n if (_dryRun) return\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/** Read a JSON file */\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n const content = await readFile(filePath, 'utf-8')\n return JSON.parse(content)\n}\n","import pc from 'picocolors'\n\nexport { pc as colors }\n\nconst METHOD_COLOR_MAP: Record<string, (s: string) => string> = {\n GET: pc.green,\n POST: pc.cyan,\n PUT: pc.yellow,\n PATCH: pc.magenta,\n DELETE: pc.red,\n}\n\n/** Color an HTTP method string for terminal display */\nexport function httpMethodColor(method: string): string {\n const fn = METHOD_COLOR_MAP[method] ?? pc.dim\n return fn(method.padEnd(7))\n}\n\n/** Color a severity tag for terminal display (padded to 10 chars) */\nexport function severityColor(severity: string): string {\n const tag = `[${severity}]`.padEnd(10)\n switch (severity) {\n case 'CRITICAL':\n return pc.red(tag)\n case 'WARNING':\n return pc.yellow(tag)\n case 'INFO':\n return pc.blue(pc.dim(tag))\n default:\n return tag\n }\n}\n","import * as clack from '@clack/prompts'\nimport { colors } from './colors'\n\nexport const symbols = {\n success: colors.green('✓'),\n error: colors.red('✖'),\n warning: colors.yellow('⚠'),\n info: colors.blue('ℹ'),\n}\n\n/** Show branded intro banner */\nexport function intro(title: string): void {\n clack.intro(colors.bgCyan(colors.black(` ${title} `)))\n}\n\n/** Show closing message */\nexport function outro(message: string): void {\n clack.outro(message)\n}\n\n/** Handle cancellation — print message and exit */\nfunction handleCancel(value: unknown): void {\n if (clack.isCancel(value)) {\n clack.cancel('Operation cancelled.')\n process.exit(0)\n }\n}\n\n/** Text input prompt */\nexport async function text(opts: {\n message: string\n placeholder?: string\n defaultValue?: string\n validate?: (value: string) => string | void\n}): Promise<string> {\n const value = await clack.text(opts)\n handleCancel(value)\n return value as string\n}\n\n/** Single select prompt */\nexport async function select<T>(opts: {\n message: string\n options: { value: T; label: string; hint?: string }[]\n initialValue?: T\n}): Promise<T> {\n const value = await clack.select(opts)\n handleCancel(value)\n return value as T\n}\n\n/** Multi-select prompt with checkboxes */\nexport async function multiSelect<T>(opts: {\n message: string\n options: { value: T; label: string; hint?: string }[]\n required?: boolean\n initialValues?: T[]\n}): Promise<T[]> {\n const value = await clack.multiselect(opts)\n handleCancel(value)\n return value as T[]\n}\n\n/** Yes/no confirmation prompt */\nexport async function confirm(opts: {\n message: string\n active?: string\n inactive?: string\n initialValue?: boolean\n}): Promise<boolean> {\n const value = await clack.confirm(opts)\n handleCancel(value)\n return value as boolean\n}\n\n/** Create a spinner for progress indication */\nexport function spinner() {\n return clack.spinner()\n}\n\n/** Log utilities for styled messages inside clack flow */\nexport const log = clack.log\n","import pkg from 'pluralize'\n\n/** Convert a name to PascalCase */\nexport function toPascalCase(name: string): string {\n return name\n .replace(/[-_\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/** Convert a name to camelCase */\nexport function toCamelCase(name: string): string {\n const pascal = toPascalCase(name)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/** Convert a name to kebab-case */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Pluralize a kebab-case name for directory/file names.\n * Uses the `pluralize` npm package for correct English pluralization\n * including irregulars (person → people, status → statuses, child → children).\n */\nexport function pluralize(name: string): string {\n return pkg.plural(name)\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n return pkg.plural(name)\n}\n","import type { RepoType } from '../module'\nimport type { TemplateContext } from './types'\n\nconst repoLabelMap: Record<string, string> = {\n inmemory: 'in-memory',\n drizzle: 'Drizzle',\n prisma: 'Prisma',\n}\n\nfunction toPascalRepoType(repo: string): string {\n return (\n repo.charAt(0).toUpperCase() +\n repo.slice(1).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n )\n}\n\nfunction toKebabRepoType(repo: string): string {\n return repo.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n}\n\nfunction repoLabel(repo: RepoType): string {\n return repoLabelMap[repo] ?? toPascalRepoType(repo)\n}\n\nfunction repoMaps(pascal: string, kebab: string, repo: RepoType) {\n const repoClassMap: Record<string, string> = {\n inmemory: `InMemory${pascal}Repository`,\n drizzle: `Drizzle${pascal}Repository`,\n prisma: `Prisma${pascal}Repository`,\n }\n const repoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n return {\n repoClass: repoClassMap[repo] ?? `${toPascalRepoType(repo)}${pascal}Repository`,\n repoFile: repoFileMap[repo] ?? `${toKebabRepoType(repo)}-${kebab}`,\n }\n}\n\n/** DDD module index — nested folders, use-cases, domain services */\nexport function generateModuleIndex(ctx: TemplateContext & { repo: RepoType }): string {\n const { pascal, kebab, plural = '', repo } = ctx\n const { repoClass, repoFile } = repoMaps(pascal, kebab, repo)\n\n return `/**\n * ${pascal} Module\n *\n * Self-contained feature module following Domain-Driven Design (DDD).\n * Registers dependencies in the DI container and declares HTTP routes.\n *\n * Structure:\n * presentation/ — HTTP controllers (entry points)\n * application/ — Use cases (orchestration) and DTOs (validation)\n * domain/ — Entities, value objects, repository interfaces, domain services\n * infrastructure/ — Repository implementations (currently ${repoLabel(repo)})\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repoClass} } from './infrastructure/repositories/${repoFile}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(\n ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n /**\n * Register module dependencies in the DI container.\n * Bind repository interface tokens to their implementations here.\n * Currently wired to ${repoLabel(repo)}. To swap implementations, change the factory target.\n */\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repoClass}),\n )\n }\n\n /**\n * Declare HTTP routes for this module.\n * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${plural}).\n * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.\n */\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n\n/** REST module index — flat folder, service + controller, no use-cases */\nexport function generateRestModuleIndex(ctx: TemplateContext & { repo: RepoType }): string {\n const { pascal, kebab, plural = '', repo } = ctx\n const { repoClass, repoFile } = repoMaps(pascal, kebab, repo)\n\n return `/**\n * ${pascal} Module\n *\n * REST module with a flat folder structure.\n * Controller delegates to service, service wraps the repository.\n *\n * Structure:\n * ${kebab}.controller.ts — HTTP routes (CRUD)\n * ${kebab}.service.ts — Business logic\n * ${kebab}.repository.ts — Repository interface\n * ${repoFile}.repository.ts — Repository implementation\n * dtos/ — Request/response schemas\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './${kebab}.repository'\nimport { ${repoClass} } from './${repoFile}.repository'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(['./**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'], { eager: true })\n\nexport class ${pascal}Module implements AppModule {\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repoClass}),\n )\n }\n\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n\n/** Minimal module index — just controller, no service/repo */\nexport function generateMinimalModuleIndex(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '' } = ctx\n return `import { type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\nexport class ${pascal}Module implements AppModule {\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\n/** DDD controller — injects use-cases, nested import paths */\nexport function generateController(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\nimport { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'\nimport { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'\nimport { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'\nimport { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}.use-case'\nimport { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'\nimport { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from '../constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private readonly create${pascal}UseCase!: Create${pascal}UseCase\n @Autowired() private readonly get${pascal}UseCase!: Get${pascal}UseCase\n @Autowired() private readonly list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n @Autowired() private readonly update${pascal}UseCase!: Update${pascal}UseCase\n @Autowired() private readonly delete${pascal}UseCase!: Delete${pascal}UseCase\n\n @Get('/')\n @ApiTags('${pascal}')\n @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n return ctx.paginate(\n (parsed) => this.list${pluralPascal}UseCase.execute(parsed),\n ${pascal.toUpperCase()}_QUERY_CONFIG,\n )\n }\n\n @Get('/:id')\n @ApiTags('${pascal}')\n async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\n const result = await this.get${pascal}UseCase.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n @ApiTags('${pascal}')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n const result = await this.create${pascal}UseCase.execute(ctx.body)\n ctx.created(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n @ApiTags('${pascal}')\n async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n @ApiTags('${pascal}')\n async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n await this.delete${pascal}UseCase.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`\n}\n\n/** REST controller — injects service directly, flat import paths */\nexport function generateRestController(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n const camel = pascal.charAt(0).toLowerCase() + pascal.slice(1)\n return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\nimport { ${pascal}Service } from './${kebab}.service'\nimport { create${pascal}Schema } from './dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from './dtos/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from './${kebab}.constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private readonly ${camel}Service!: ${pascal}Service\n\n @Get('/')\n @ApiTags('${pascal}')\n @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n return ctx.paginate(\n (parsed) => this.${camel}Service.findPaginated(parsed),\n ${pascal.toUpperCase()}_QUERY_CONFIG,\n )\n }\n\n @Get('/:id')\n @ApiTags('${pascal}')\n async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\n const result = await this.${camel}Service.findById(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n @ApiTags('${pascal}')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n const result = await this.${camel}Service.create(ctx.body)\n ctx.created(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n @ApiTags('${pascal}')\n async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n const result = await this.${camel}Service.update(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n @ApiTags('${pascal}')\n async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n await this.${camel}Service.delete(ctx.params.id)\n ctx.noContent()\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateConstants(ctx: TemplateContext): string {\n const { pascal } = ctx\n return `import type { QueryParamsConfig } from '@forinda/kickjs'\n\nexport const ${pascal.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {\n filterable: ['name'],\n sortable: ['name', 'createdAt'],\n searchable: ['name'],\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateCreateDTO(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import { z } from 'zod'\n\n/**\n * Create ${pascal} DTO — Zod schema for validating POST request bodies.\n * This schema is passed to @Post('/', { body: create${pascal}Schema }) for automatic validation.\n * It also generates OpenAPI request body docs when SwaggerAdapter is used.\n *\n * Add more fields as needed. Supported Zod types:\n * z.string(), z.number(), z.boolean(), z.enum([...]),\n * z.array(), z.object(), .optional(), .default(), .transform()\n */\nexport const create${pascal}Schema = z.object({\n name: z.string().min(1, 'Name is required').max(200),\n})\n\nexport type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>\n`\n}\n\nexport function generateUpdateDTO(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import { z } from 'zod'\n\nexport const update${pascal}Schema = z.object({\n name: z.string().min(1).max(200).optional(),\n})\n\nexport type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>\n`\n}\n\nexport function generateResponseDTO(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `export interface ${pascal}ResponseDTO {\n id: string\n name: string\n createdAt: string\n updatedAt: string\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateUseCases(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return [\n {\n file: `create-${kebab}.use-case.ts`,\n content: `/**\n * Create ${pascal} Use Case\n *\n * Application layer — orchestrates a single business operation.\n * Use cases are thin: validate input (via DTO), call domain/repo, return response.\n * Keep business rules in the domain service, not here.\n */\nimport { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n}\n`,\n },\n {\n file: `get-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ParsedQuery } from '@forinda/kickjs'\n\n@Service()\nexport class List${pluralPascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(parsed: ParsedQuery) {\n return this.repo.findPaginated(parsed)\n }\n}\n`,\n },\n {\n file: `update-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Update${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\n\n@Service()\nexport class Delete${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`,\n },\n ]\n}\n","import type { TemplateContext } from './types'\n\nexport function generateRepositoryInterface(ctx: TemplateContext): string {\n const { pascal, kebab, dtoPrefix = '../../application/dtos' } = ctx\n return `/**\n * ${pascal} Repository Interface\n *\n * Defines the contract for data access.\n * The interface declares what operations are available;\n * implementations (in-memory, Drizzle, Prisma) fulfill the contract.\n *\n * To swap implementations, change the factory in the module's register() method.\n */\nimport { createToken } from '@forinda/kickjs'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\nimport type { ParsedQuery } from '@forinda/kickjs'\n\nexport interface I${pascal}Repository {\n findById(id: string): Promise<${pascal}ResponseDTO | null>\n findAll(): Promise<${pascal}ResponseDTO[]>\n findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }>\n create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>\n update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>\n delete(id: string): Promise<void>\n}\n\n/**\n * Collision-safe DI token bound to \\`I${pascal}Repository\\`.\n * \\`container.resolve(${pascal.toUpperCase()}_REPOSITORY)\\` and\n * \\`@Inject(${pascal.toUpperCase()}_REPOSITORY)\\` both return the typed\n * interface — no manual generic, no \\`any\\` cast.\n */\nexport const ${pascal.toUpperCase()}_REPOSITORY = createToken<I${pascal}Repository>('${pascal}/Repository')\n`\n}\n\nexport function generateInMemoryRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n return `/**\n * In-Memory ${pascal} Repository\n *\n * Implements the repository interface using a Map.\n * Useful for prototyping and testing. Replace with a database implementation\n * (Drizzle, Prisma, etc.) for production use.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\n\n@Repository()\nexport class InMemory${pascal}Repository implements I${pascal}Repository {\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return Array.from(this.store.values())\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n const all = Array.from(this.store.values())\n const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)\n return { data, total: all.length }\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`\n}\n\nexport function generateCustomRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoType = '',\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n const repoTypePascal =\n repoType.charAt(0).toUpperCase() +\n repoType.slice(1).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n return `/**\n * ${repoTypePascal} ${pascal} Repository\n *\n * Stub implementation for a custom '${repoType}' repository.\n * Implements the repository interface using an in-memory Map as a placeholder.\n *\n * TODO: Replace the in-memory Map with your ${repoType} data-access logic.\n * See I${pascal}Repository for the interface contract.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\n\n@Repository()\nexport class ${repoTypePascal}${pascal}Repository implements I${pascal}Repository {\n // TODO: Replace with your ${repoType} client/connection\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n // TODO: Implement with ${repoType}\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n // TODO: Implement with ${repoType}\n return Array.from(this.store.values())\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n // TODO: Implement with ${repoType}\n const all = Array.from(this.store.values())\n const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)\n return { data, total: all.length }\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with ${repoType}\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with ${repoType}\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n // TODO: Implement with ${repoType}\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateDomainService(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `/**\n * ${pascal} Domain Service\n *\n * Domain layer — contains business rules that don't belong to a single entity.\n * Use this for cross-entity logic, validation rules, and domain invariants.\n * Keep it free of HTTP/framework concerns.\n */\nimport { Service, Inject, HttpException } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'\n\n@Service()\nexport class ${pascal}DomainService {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async ensureExists(id: string): Promise<void> {\n const entity = await this.repo.findById(id)\n if (!entity) {\n throw HttpException.notFound('${pascal} not found')\n }\n }\n}\n`\n}\n\nexport function generateEntity(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `/**\n * ${pascal} Entity\n *\n * Domain layer — the core business object.\n * Uses a private constructor with static factory methods (create, reconstitute)\n * to enforce invariants. Properties are accessed via getters to maintain encapsulation.\n *\n * Patterns used:\n * - Private constructor: prevents direct instantiation\n * - create(): factory for new entities (generates ID, sets timestamps)\n * - reconstitute(): factory for rebuilding from persistence (no side effects)\n * - changeName(): mutation method that enforces business rules\n */\nimport { ${pascal}Id } from '../value-objects/${kebab}-id.vo'\n\ninterface ${pascal}Props {\n id: ${pascal}Id\n name: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport class ${pascal} {\n private constructor(private props: ${pascal}Props) {}\n\n static create(params: { name: string }): ${pascal} {\n const now = new Date()\n return new ${pascal}({\n id: ${pascal}Id.create(),\n name: params.name,\n createdAt: now,\n updatedAt: now,\n })\n }\n\n static reconstitute(props: ${pascal}Props): ${pascal} {\n return new ${pascal}(props)\n }\n\n get id(): ${pascal}Id {\n return this.props.id\n }\n get name(): string {\n return this.props.name\n }\n get createdAt(): Date {\n return this.props.createdAt\n }\n get updatedAt(): Date {\n return this.props.updatedAt\n }\n\n changeName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Name cannot be empty')\n }\n this.props.name = name.trim()\n this.props.updatedAt = new Date()\n }\n\n toJSON() {\n return {\n id: this.props.id.toString(),\n name: this.props.name,\n createdAt: this.props.createdAt.toISOString(),\n updatedAt: this.props.updatedAt.toISOString(),\n }\n }\n}\n`\n}\n\nexport function generateValueObject(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `/**\n * ${pascal} ID Value Object\n *\n * Domain layer — wraps a primitive ID with type safety and validation.\n * Value objects are immutable and compared by value, not reference.\n *\n * ${pascal}Id.create() — generate a new UUID\n * ${pascal}Id.from(id) — wrap an existing ID string (validates non-empty)\n * id.equals(other) — compare two IDs by value\n */\nimport { randomUUID } from 'node:crypto'\n\nexport class ${pascal}Id {\n private constructor(private readonly value: string) {}\n\n static create(): ${pascal}Id {\n return new ${pascal}Id(randomUUID())\n }\n\n static from(id: string): ${pascal}Id {\n if (!id || id.trim().length === 0) {\n throw new Error('${pascal}Id cannot be empty')\n }\n return new ${pascal}Id(id)\n }\n\n toString(): string {\n return this.value\n }\n\n equals(other: ${pascal}Id): boolean {\n return this.value === other.value\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateControllerTest(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '' } = ctx\n return `import { describe, it, expect, beforeEach } from 'vitest'\nimport { Container } from '@forinda/kickjs'\n\ndescribe('${pascal}Controller', () => {\n beforeEach(() => {\n Container.reset()\n })\n\n it('should be defined', () => {\n expect(true).toBe(true)\n })\n\n describe('POST /${plural}', () => {\n it('should create a new ${kebab}', async () => {\n // TODO: Set up test module, call create endpoint, assert 201\n expect(true).toBe(true)\n })\n })\n\n describe('GET /${plural}', () => {\n it('should return paginated ${plural}', async () => {\n // TODO: Set up test module, call list endpoint, assert { data, meta }\n expect(true).toBe(true)\n })\n })\n\n describe('GET /${plural}/:id', () => {\n it('should return a ${kebab} by id', async () => {\n // TODO: Create a ${kebab}, then fetch by id, assert match\n expect(true).toBe(true)\n })\n\n it('should return 404 for non-existent ${kebab}', async () => {\n // TODO: Fetch non-existent id, assert 404\n expect(true).toBe(true)\n })\n })\n\n describe('PUT /${plural}/:id', () => {\n it('should update an existing ${kebab}', async () => {\n // TODO: Create, update, assert changes\n expect(true).toBe(true)\n })\n })\n\n describe('DELETE /${plural}/:id', () => {\n it('should delete a ${kebab}', async () => {\n // TODO: Create, delete, assert gone\n expect(true).toBe(true)\n })\n })\n})\n`\n}\n\nexport function generateRepositoryTest(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n plural = '',\n repoPrefix = `../infrastructure/repositories/in-memory-${kebab}.repository`,\n } = ctx\n return `import { describe, it, expect, beforeEach } from 'vitest'\nimport { InMemory${pascal}Repository } from '${repoPrefix}'\n\ndescribe('InMemory${pascal}Repository', () => {\n let repo: InMemory${pascal}Repository\n\n beforeEach(() => {\n repo = new InMemory${pascal}Repository()\n })\n\n it('should create and retrieve a ${kebab}', async () => {\n const created = await repo.create({ name: 'Test ${pascal}' })\n expect(created).toBeDefined()\n expect(created.name).toBe('Test ${pascal}')\n expect(created.id).toBeDefined()\n\n const found = await repo.findById(created.id)\n expect(found).toEqual(created)\n })\n\n it('should return null for non-existent id', async () => {\n const found = await repo.findById('non-existent')\n expect(found).toBeNull()\n })\n\n it('should list all ${plural}', async () => {\n await repo.create({ name: '${pascal} 1' })\n await repo.create({ name: '${pascal} 2' })\n\n const all = await repo.findAll()\n expect(all).toHaveLength(2)\n })\n\n it('should return paginated results', async () => {\n await repo.create({ name: '${pascal} 1' })\n await repo.create({ name: '${pascal} 2' })\n await repo.create({ name: '${pascal} 3' })\n\n const result = await repo.findPaginated({\n filters: [],\n sort: [],\n search: '',\n pagination: { page: 1, limit: 2, offset: 0 },\n })\n\n expect(result.data).toHaveLength(2)\n expect(result.total).toBe(3)\n })\n\n it('should update a ${kebab}', async () => {\n const created = await repo.create({ name: 'Original' })\n const updated = await repo.update(created.id, { name: 'Updated' })\n expect(updated.name).toBe('Updated')\n })\n\n it('should delete a ${kebab}', async () => {\n const created = await repo.create({ name: 'To Delete' })\n await repo.delete(created.id)\n const found = await repo.findById(created.id)\n expect(found).toBeNull()\n })\n})\n`\n}\n","import type { TemplateContext } from './types'\n\n/** REST service — wraps repository with CRUD methods, replaces use-cases for flat pattern */\nexport function generateRestService(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import { Service, Inject, HttpException } from '@forinda/kickjs'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from './${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from './dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from './dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from './dtos/update-${kebab}.dto'\n\n@Service()\nexport class ${pascal}Service {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return this.repo.findAll()\n }\n\n async findPaginated(parsed: ParsedQuery) {\n return this.repo.findPaginated(parsed)\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n\n async delete(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`\n}\n\n/** REST constants — query config for flat pattern */\nexport function generateRestConstants(ctx: TemplateContext): string {\n const { pascal } = ctx\n return `import type { QueryFieldConfig } from '@forinda/kickjs'\n\nexport const ${pascal.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {\n filterable: ['name'],\n sortable: ['name', 'createdAt'],\n searchable: ['name'],\n}\n`\n}\n","import type { TemplateContext } from './types'\n\n/** CQRS module index — commands, queries, events, WebSocket + queue integration */\nexport function generateCqrsModuleIndex(ctx: TemplateContext & { repo: string }): string {\n const { pascal, kebab, plural = '', repo } = ctx\n const repoClassMap: Record<string, string> = {\n inmemory: `InMemory${pascal}Repository`,\n drizzle: `Drizzle${pascal}Repository`,\n prisma: `Prisma${pascal}Repository`,\n }\n const repoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const repoClass = repoClassMap[repo] ?? repoClassMap.inmemory\n const repoFile = repoFileMap[repo] ?? repoFileMap.inmemory\n\n return `/**\n * ${pascal} Module — CQRS Pattern\n *\n * Separates read (queries) and write (commands) operations.\n * Events are emitted after state changes and can be handled via\n * WebSocket broadcasts, queue jobs, or ETL pipelines.\n *\n * Structure:\n * commands/ — Write operations (create, update, delete)\n * queries/ — Read operations (get, list)\n * events/ — Domain events + handlers (WS broadcast, queue dispatch)\n * dtos/ — Request/response schemas\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './${kebab}.repository'\nimport { ${repoClass} } from './${repoFile}.repository'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\n// Eagerly load decorated classes\nimport.meta.glob(\n [\n './commands/**/*.ts',\n './queries/**/*.ts',\n './events/**/*.ts',\n '!./**/*.test.ts',\n ],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repoClass}),\n )\n }\n\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n\n/** CQRS controller — dispatches to command/query handlers */\nexport function generateCqrsController(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\nimport { Create${pascal}Command } from './commands/create-${kebab}.command'\nimport { Update${pascal}Command } from './commands/update-${kebab}.command'\nimport { Delete${pascal}Command } from './commands/delete-${kebab}.command'\nimport { Get${pascal}Query } from './queries/get-${kebab}.query'\nimport { List${pluralPascal}Query } from './queries/list-${plural}.query'\nimport { create${pascal}Schema } from './dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from './dtos/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from './${kebab}.constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private readonly create${pascal}Command!: Create${pascal}Command\n @Autowired() private readonly update${pascal}Command!: Update${pascal}Command\n @Autowired() private readonly delete${pascal}Command!: Delete${pascal}Command\n @Autowired() private readonly get${pascal}Query!: Get${pascal}Query\n @Autowired() private readonly list${pluralPascal}Query!: List${pluralPascal}Query\n\n @Get('/')\n @ApiTags('${pascal}')\n @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n return ctx.paginate(\n (parsed) => this.list${pluralPascal}Query.execute(parsed),\n ${pascal.toUpperCase()}_QUERY_CONFIG,\n )\n }\n\n @Get('/:id')\n @ApiTags('${pascal}')\n async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\n const result = await this.get${pascal}Query.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n @ApiTags('${pascal}')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n const result = await this.create${pascal}Command.execute(ctx.body)\n ctx.created(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n @ApiTags('${pascal}')\n async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n const result = await this.update${pascal}Command.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n @ApiTags('${pascal}')\n async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n await this.delete${pascal}Command.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`\n}\n\n/** CQRS commands — write operations that emit events */\nexport function generateCqrsCommands(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab } = ctx\n return [\n {\n file: `create-${kebab}.command.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\nimport { ${pascal}Events } from '../events/${kebab}.events'\n\n@Service()\nexport class Create${pascal}Command {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n @Inject(${pascal}Events) private readonly events: ${pascal}Events,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const result = await this.repo.create(dto)\n this.events.emit('${kebab}.created', result)\n return result\n }\n}\n`,\n },\n {\n file: `update-${kebab}.command.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\nimport { ${pascal}Events } from '../events/${kebab}.events'\n\n@Service()\nexport class Update${pascal}Command {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n @Inject(${pascal}Events) private readonly events: ${pascal}Events,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const result = await this.repo.update(id, dto)\n this.events.emit('${kebab}.updated', result)\n return result\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.command.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport { ${pascal}Events } from '../events/${kebab}.events'\n\n@Service()\nexport class Delete${pascal}Command {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n @Inject(${pascal}Events) private readonly events: ${pascal}Events,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n this.events.emit('${kebab}.deleted', { id })\n }\n}\n`,\n },\n ]\n}\n\n/** CQRS queries — read operations */\nexport function generateCqrsQueries(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return [\n {\n file: `get-${kebab}.query.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}Query {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.query.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { ParsedQuery } from '@forinda/kickjs'\n\n@Service()\nexport class List${pluralPascal}Query {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(parsed: ParsedQuery) {\n return this.repo.findPaginated(parsed)\n }\n}\n`,\n },\n ]\n}\n\n/** CQRS events — domain event emitter + handler with WS/queue integration */\nexport function generateCqrsEvents(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab } = ctx\n return [\n {\n file: `${kebab}.events.ts`,\n content: `import { Service } from '@forinda/kickjs'\nimport { EventEmitter } from 'node:events'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n/**\n * ${pascal} domain event types.\n *\n * These events are emitted by commands after state changes.\n * Subscribe to them in event handlers for side effects:\n * - WebSocket broadcasts (real-time UI updates)\n * - Queue jobs (async processing, ETL pipelines)\n * - Audit logging\n * - Cache invalidation\n */\nexport interface ${pascal}EventMap {\n '${kebab}.created': ${pascal}ResponseDTO\n '${kebab}.updated': ${pascal}ResponseDTO\n '${kebab}.deleted': { id: string }\n}\n\n@Service()\nexport class ${pascal}Events {\n private emitter = new EventEmitter()\n\n emit<K extends keyof ${pascal}EventMap>(event: K, data: ${pascal}EventMap[K]): void {\n this.emitter.emit(event, data)\n }\n\n on<K extends keyof ${pascal}EventMap>(event: K, handler: (data: ${pascal}EventMap[K]) => void): void {\n this.emitter.on(event, handler)\n }\n\n off<K extends keyof ${pascal}EventMap>(event: K, handler: (data: ${pascal}EventMap[K]) => void): void {\n this.emitter.off(event, handler)\n }\n}\n`,\n },\n {\n file: `on-${kebab}-change.handler.ts`,\n content: `import { Service, Autowired } from '@forinda/kickjs'\nimport { ${pascal}Events } from './${kebab}.events'\n\n/**\n * ${pascal} Change Event Handler\n *\n * Reacts to domain events emitted by commands.\n * Wire up side effects here:\n *\n * 1. WebSocket broadcast — notify connected clients in real-time\n * import { WsGateway } from '@forinda/kickjs-ws'\n * this.ws.broadcast('${kebab}-channel', { event, data })\n *\n * 2. Queue dispatch — offload heavy processing to background workers\n * import { QueueService } from '@forinda/kickjs-queue'\n * this.queue.add('${kebab}-etl', { action: event, payload: data })\n *\n * 3. ETL pipeline — transform and load data to external systems\n * await this.etlPipeline.process(data)\n */\n@Service()\nexport class On${pascal}ChangeHandler {\n @Autowired() private events!: ${pascal}Events\n\n // Uncomment to inject WebSocket and Queue services:\n // @Autowired() private ws!: WsGateway\n // @Autowired() private queue!: QueueService\n\n onInit(): void {\n this.events.on('${kebab}.created', (data) => {\n console.log('[${pascal}] Created:', data.id)\n // TODO: Broadcast via WebSocket\n // this.ws.broadcast('${kebab}-channel', { event: '${kebab}.created', data })\n // TODO: Dispatch to queue for async processing / ETL\n // this.queue.add('${kebab}-etl', { action: 'create', payload: data })\n })\n\n this.events.on('${kebab}.updated', (data) => {\n console.log('[${pascal}] Updated:', data.id)\n // TODO: Broadcast via WebSocket\n // this.ws.broadcast('${kebab}-channel', { event: '${kebab}.updated', data })\n })\n\n this.events.on('${kebab}.deleted', (data) => {\n console.log('[${pascal}] Deleted:', data.id)\n // TODO: Broadcast via WebSocket\n // this.ws.broadcast('${kebab}-channel', { event: '${kebab}.deleted', data })\n })\n }\n}\n`,\n },\n ]\n}\n","import type { TemplateContext } from '../types'\n\nexport function generateDrizzleRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n return `/**\n * Drizzle ${pascal} Repository\n *\n * Implements the repository interface using Drizzle ORM.\n * Uses buildFromColumns() with Column objects for type-safe query building.\n *\n * TODO: Update the schema import to match your Drizzle schema file.\n * TODO: Replace DRIZZLE_DB injection token with your actual database token.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc, count, sql } from 'drizzle-orm'\nimport { Repository, HttpException, Inject } from '@forinda/kickjs'\nimport { DRIZZLE_DB, DrizzleQueryAdapter } from '@forinda/kickjs-drizzle'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from '../../constants'\n\n// TODO: Import your Drizzle schema table — e.g.:\n// import { ${kebab}s } from '@/db/schema'\n\nconst queryAdapter = new DrizzleQueryAdapter({\n eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc,\n})\n\n@Repository()\nexport class Drizzle${pascal}Repository implements I${pascal}Repository {\n constructor(@Inject(DRIZZLE_DB) private db: any) {}\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n // TODO: Implement with Drizzle\n // const row = this.db.select().from(${kebab}s).where(eq(${kebab}s.id, id)).get()\n // return row ?? null\n throw new Error('Drizzle ${pascal} repository not yet implemented — update schema imports and queries')\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n // TODO: Implement with Drizzle\n // return this.db.select().from(${kebab}s).all()\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n // TODO: Use buildFromColumns() with your query config for type-safe filtering\n // const query = queryAdapter.buildFromColumns(parsed, ${pascal.toUpperCase()}_QUERY_CONFIG)\n //\n // const data = this.db\n // .select().from(${kebab}s).$dynamic()\n // .where(query.where).orderBy(...query.orderBy)\n // .limit(query.limit).offset(query.offset).all()\n //\n // const totalResult = this.db\n // .select({ count: count() }).from(${kebab}s)\n // .$dynamic().where(query.where).get()\n //\n // return { data, total: totalResult?.count ?? 0 }\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with Drizzle\n // return this.db.insert(${kebab}s).values(dto).returning().get()\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with Drizzle\n // const row = this.db.update(${kebab}s).set(dto).where(eq(${kebab}s.id, id)).returning().get()\n // if (!row) throw HttpException.notFound('${pascal} not found')\n // return row\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async delete(id: string): Promise<void> {\n // TODO: Implement with Drizzle\n // this.db.delete(${kebab}s).where(eq(${kebab}s.id, id)).run()\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n}\n`\n}\n\nexport function generateDrizzleConstants(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'\n// TODO: Import your schema table and reference actual columns for type safety\n// import { ${kebab}s } from '@/db/schema'\n\nexport const ${pascal.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {\n columns: {\n // Replace with actual Drizzle Column references for type-safe filtering:\n // name: ${kebab}s.name,\n // status: ${kebab}s.status,\n },\n sortable: {\n // name: ${kebab}s.name,\n // createdAt: ${kebab}s.createdAt,\n },\n searchColumns: [\n // ${kebab}s.name,\n ],\n}\n`\n}\n","import type { TemplateContext } from '../types'\n\nexport function generatePrismaRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n const camel = kebab.replace(/-([a-z])/g, (_, c) => c.toUpperCase())\n return `/**\n * Prisma ${pascal} Repository\n *\n * Implements the repository interface using Prisma Client.\n * Requires a PrismaClient instance injected via the DI container.\n *\n * Ensure your Prisma schema has a '${pascal}' model defined.\n *\n * For full Prisma field-level type safety, replace PrismaModelDelegate with your PrismaClient:\n * @Inject(PRISMA_CLIENT) private prisma!: PrismaClient\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { Repository, HttpException, Inject } from '@forinda/kickjs'\nimport { PRISMA_CLIENT, type PrismaModelDelegate } from '@forinda/kickjs-prisma'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\n\n@Repository()\nexport class Prisma${pascal}Repository implements I${pascal}Repository {\n @Inject(PRISMA_CLIENT) private prisma!: { ${camel}: PrismaModelDelegate }\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.prisma.${camel}.findUnique({ where: { id } }) as Promise<${pascal}ResponseDTO | null>\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return this.prisma.${camel}.findMany() as Promise<${pascal}ResponseDTO[]>\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n const [data, total] = await Promise.all([\n this.prisma.${camel}.findMany({\n skip: parsed.pagination.offset,\n take: parsed.pagination.limit,\n }) as Promise<${pascal}ResponseDTO[]>,\n this.prisma.${camel}.count(),\n ])\n return { data, total }\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.prisma.${camel}.create({ data: dto as Record<string, unknown> }) as Promise<${pascal}ResponseDTO>\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = await this.prisma.${camel}.findUnique({ where: { id } })\n if (!existing) throw HttpException.notFound('${pascal} not found')\n return this.prisma.${camel}.update({ where: { id }, data: dto as Record<string, unknown> }) as Promise<${pascal}ResponseDTO>\n }\n\n async delete(id: string): Promise<void> {\n await this.prisma.${camel}.deleteMany({ where: { id } })\n }\n}\n`\n}\n","type ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/**\n * Generate src/index.ts entry file with template-specific bootstrap.\n *\n * All templates export the app for the Vite plugin (dev mode).\n * In production, bootstrap() auto-starts the HTTP server when\n * `globalThis.__kickjs_httpServer` is not set.\n */\nexport function generateEntryFile(\n name: string,\n template: ProjectTemplate,\n version: string,\n packages: string[] = [],\n): string {\n switch (template) {\n case 'graphql': {\n // GraphQL adapter is always included (it's the template); others only if selected\n const gqlImports: string[] = []\n const gqlAdapters: string[] = []\n\n if (packages.includes('devtools')) {\n gqlImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n gqlAdapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('otel')) {\n gqlImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n gqlAdapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n if (packages.includes('swagger')) {\n gqlImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n gqlAdapters.push(\n ` new SwaggerAdapter({ info: { title: '${name}', version: '${version}' } }),`,\n )\n }\n\n const gqlImportsBlock = gqlImports.length ? gqlImports.join('\\n') + '\\n' : ''\n const gqlAdaptersBlock = gqlAdapters.length ? gqlAdapters.join('\\n') + '\\n' : ''\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport { bootstrap } from '@forinda/kickjs'\nimport { GraphQLAdapter } from '@forinda/kickjs-graphql'\n${gqlImportsBlock}import { modules } from './modules'\n\n// Import your resolvers here\n// import { UserResolver } from './resolvers/user.resolver'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({\n modules,\n adapters: [\n${gqlAdaptersBlock} new GraphQLAdapter({\n resolvers: [/* UserResolver */],\n // Add custom type definitions here:\n // typeDefs: userTypeDefs,\n }),\n ],\n})\n`\n }\n\n case 'cqrs': {\n // Build adapters based on user-selected packages\n const cqrsImports: string[] = []\n const cqrsAdapters: string[] = []\n\n if (packages.includes('otel')) {\n cqrsImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n cqrsAdapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n if (packages.includes('devtools')) {\n cqrsImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n cqrsAdapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('swagger')) {\n cqrsImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n cqrsAdapters.push(\n ` new SwaggerAdapter({\\n info: { title: '${name}', version: '${version}' },\\n }),`,\n )\n }\n if (packages.includes('graphql')) {\n cqrsImports.push(`import { GraphQLAdapter } from '@forinda/kickjs-graphql'`)\n cqrsAdapters.push(` new GraphQLAdapter({ resolvers: [] }),`)\n }\n\n const cqrsImportsBlock = cqrsImports.length ? cqrsImports.join('\\n') + '\\n' : ''\n const cqrsAdaptersBlock = cqrsImports.length\n ? `\\n adapters: [\\n${cqrsAdapters.join('\\n')}\\n // Uncomment for WebSocket support:\\n // new WsAdapter(),\\n // Uncomment when Redis is available:\\n // new QueueAdapter({\\n // provider: new BullMQProvider({ host: 'localhost', port: 6379 }),\\n // }),\\n ],`\n : `\\n adapters: [\\n // Uncomment for WebSocket support:\\n // new WsAdapter(),\\n // Uncomment when Redis is available:\\n // new QueueAdapter({\\n // provider: new BullMQProvider({ host: 'localhost', port: 6379 }),\\n // }),\\n ],`\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport { bootstrap } from '@forinda/kickjs'\n// import { WsAdapter } from '@forinda/kickjs-ws'\n// import { QueueAdapter, BullMQProvider } from '@forinda/kickjs-queue'\n${cqrsImportsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({\n modules,${cqrsAdaptersBlock}\n})\n`\n }\n\n case 'minimal': {\n const imports: string[] = []\n const adapters: string[] = []\n\n if (packages.includes('swagger')) {\n imports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n adapters.push(\n ` new SwaggerAdapter({ info: { title: '${name}', version: '${version}' } }),`,\n )\n }\n if (packages.includes('devtools')) {\n imports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n adapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('otel')) {\n imports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n adapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n if (packages.includes('graphql')) {\n imports.push(`import { GraphQLAdapter } from '@forinda/kickjs-graphql'`)\n adapters.push(` new GraphQLAdapter({ resolvers: [] }),`)\n }\n\n const importsBlock = imports.length ? imports.join('\\n') + '\\n' : ''\n const adaptersBlock = adapters.length ? `,\\n adapters: [\\n${adapters.join('\\n')}\\n ]` : ''\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport { bootstrap } from '@forinda/kickjs'\n${importsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({ modules${adaptersBlock} })\n`\n }\n\n case 'ddd':\n case 'rest':\n default: {\n // Build adapters based on user-selected packages\n const restImports: string[] = []\n const restAdapters: string[] = []\n\n if (packages.includes('devtools')) {\n restImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n restAdapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('swagger')) {\n restImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n restAdapters.push(\n ` new SwaggerAdapter({\\n info: { title: '${name}', version: '${version}' },\\n }),`,\n )\n }\n if (packages.includes('otel')) {\n restImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n restAdapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n\n const restImportsBlock = restImports.length ? restImports.join('\\n') + '\\n' : ''\n const restAdaptersBlock = restAdapters.length\n ? `\\n adapters: [\\n${restAdapters.join('\\n')}\\n ],`\n : ''\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport express from 'express'\nimport {\n bootstrap,\n requestId,\n requestLogger,\n helmet,\n cors,\n} from '@forinda/kickjs'\n${restImportsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({\n modules,${restAdaptersBlock}\n middleware: [\n helmet(),\n cors({ origin: '*' }),\n requestId(),\n requestLogger(),\n express.json(),\n ],\n})\n`\n }\n }\n}\n\n/** Generate src/modules/index.ts module registry */\nexport function generateModulesIndex(): string {\n return `import type { AppModuleClass } from '@forinda/kickjs'\nimport { HelloModule } from './hello/hello.module'\n\n// Remove HelloModule and run: kick g module <name>\nexport const modules: AppModuleClass[] = [HelloModule]\n`\n}\n\n/**\n * Generate `src/config/index.ts` — the project's typed env schema.\n *\n * Default-exports a `defineEnv(...)` schema so `kick typegen` can\n * infer it into the global `KickEnv` registry, and *also* calls\n * `loadEnv(envSchema)` as a module-load side effect so `ConfigService`\n * and `@Value()` see the extended shape from the very first DI\n * resolution. The companion `src/index.ts` template adds\n * `import './config'` immediately after `reflect-metadata` so the\n * registration runs before `bootstrap()` constructs anything.\n *\n * After typegen runs:\n *\n * @Value('DATABASE_URL') private url!: Env<'DATABASE_URL'>\n * process.env.DATABASE_URL // typed as string\n *\n * Both autocomplete and type-check at compile time.\n */\nexport function generateEnvFile(): string {\n return `import { defineEnv, loadEnv } from '@forinda/kickjs/config'\nimport { z } from 'zod'\n\n/**\n * Project environment schema.\n *\n * Extend the base schema with your application's variables. The\n * default export is the contract \\`kick typegen\\` reads to populate\n * the global \\`KickEnv\\` registry — that's what makes \\`@Value('FOO')\\`\n * autocomplete and \\`process.env.FOO\\` typed.\n *\n * @example\n * DATABASE_URL: z.string().url(),\n * JWT_SECRET: z.string().min(32),\n * REDIS_URL: z.string().url().optional(),\n */\nconst envSchema = defineEnv((base) =>\n base.extend({\n // DATABASE_URL: z.string().url(),\n }),\n)\n\n/**\n * IMPORTANT — side effect: register the schema with kickjs's env cache\n * **at module-load time**. \\`ConfigService\\` and \\`@Value()\\` both consume\n * this cache, and they will fall back to the base schema (or undefined)\n * if no extended schema has been registered before they're resolved.\n *\n * As long as \\`src/index.ts\\` imports this file (\\`import './env'\\`) at the\n * top — before \\`bootstrap()\\` runs — every controller and service in the\n * app sees the typed extended values.\n */\nexport const env = loadEnv(envSchema)\n\nexport default envSchema\n`\n}\n\n/** Generate src/modules/hello/hello.service.ts */\nexport function generateHelloService(): string {\n return `import { Service } from '@forinda/kickjs'\n\n@Service()\nexport class HelloService {\n greet(name: string) {\n return { message: \\`Hello \\${name} from KickJS!\\`, timestamp: new Date().toISOString() }\n }\n\n healthCheck() {\n return { status: 'ok', uptime: process.uptime() }\n }\n}\n`\n}\n\n/** Generate src/modules/hello/hello.controller.ts */\nexport function generateHelloController(): string {\n return `import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'\nimport { HelloService } from './hello.service'\n\n// \\`Ctx<KickRoutes.HelloController['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`). The first run after a fresh\n// scaffold creates \\`.kickjs/types/routes.ts\\` so this file typechecks.\n// See https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class HelloController {\n @Autowired() private readonly helloService!: HelloService\n\n @Get('/')\n index(ctx: Ctx<KickRoutes.HelloController['index']>) {\n ctx.json(this.helloService.greet('World'))\n }\n\n @Get('/health')\n health(ctx: Ctx<KickRoutes.HelloController['health']>) {\n ctx.json(this.helloService.healthCheck())\n }\n}\n`\n}\n\n/** Generate src/modules/hello/hello.module.ts */\nexport function generateHelloModule(): string {\n return `import { type AppModule, type ModuleRoutes, buildRoutes } from '@forinda/kickjs'\nimport { HelloController } from './hello.controller'\n\nexport class HelloModule implements AppModule {\n // \\`register(container)\\` is optional — only implement it when you need\n // to bind a token to a concrete implementation, e.g.\n // register(container) {\n // container.registerFactory(USER_REPOSITORY, () => container.resolve(InMemoryUserRepository))\n // }\n // The HelloService uses @Service() so the decorator handles registration.\n\n routes(): ModuleRoutes {\n return {\n path: '/hello',\n router: buildRoutes(HelloController),\n controller: HelloController,\n }\n }\n}\n`\n}\n\n/** Generate kick.config.ts CLI configuration */\nexport function generateKickConfig(\n template: ProjectTemplate,\n defaultRepo: string = 'inmemory',\n): string {\n const builtinRepos = ['drizzle', 'inmemory', 'prisma']\n const repoValue = builtinRepos.includes(defaultRepo)\n ? `'${defaultRepo}'`\n : `{ name: '${defaultRepo}' }`\n\n return `import { defineConfig } from '@forinda/kickjs-cli'\n\nexport default defineConfig({\n pattern: '${template}',\n modules: {\n dir: 'src/modules',\n repo: ${repoValue},\n pluralize: true,\n },\n\n // \\`kick typegen\\` populates \\`.kickjs/types/\\` so \\`Ctx<KickRoutes.X['method']>\\`\n // resolves to fully-typed params/body/query. Auto-runs on \\`kick dev\\`.\n // Set \\`schemaValidator: false\\` to skip schema-driven body typing entirely.\n typegen: {\n schemaValidator: 'zod',\n },\n\n commands: [\n {\n name: 'test',\n description: 'Run tests with Vitest',\n steps: 'npx vitest run',\n },\n {\n name: 'format',\n description: 'Format code with Prettier',\n steps: 'npx prettier --write src/',\n },\n {\n name: 'format:check',\n description: 'Check formatting without writing',\n steps: 'npx prettier --check src/',\n },\n {\n name: 'check',\n description: 'Run typecheck + format check',\n steps: ['npx tsc --noEmit', 'npx prettier --check src/'],\n aliases: ['verify', 'ci'],\n },\n ],\n})\n`\n}\n","import type { ModuleContext } from './types'\nimport { generateMinimalModuleIndex } from '../templates'\n\nexport async function generateMinimalFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, write } = ctx\n\n await write('index.ts', generateMinimalModuleIndex({ pascal, kebab, plural }))\n\n await write(\n `${kebab}.controller.ts`,\n `import { Controller, Get, type Ctx } from '@forinda/kickjs'\n\n// \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`).\n\n@Controller()\nexport class ${pascal}Controller {\n @Get('/')\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n ctx.json({ message: '${pascal} list' })\n }\n}\n`,\n )\n}\n","import type { ModuleContext } from './types'\nimport { toKebabCase } from '../../utils/naming'\nimport {\n generateRestModuleIndex,\n generateRestController,\n generateRestConstants,\n generateRestService,\n generateCreateDTO,\n generateUpdateDTO,\n generateResponseDTO,\n generateRepositoryInterface,\n generateInMemoryRepository,\n generateCustomRepository,\n generateDrizzleRepository,\n generatePrismaRepository,\n generateControllerTest,\n generateRepositoryTest,\n} from '../templates'\n\nexport async function generateRestFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, write } = ctx\n\n // Module index\n await write('index.ts', generateRestModuleIndex({ pascal, kebab, plural, repo }))\n\n // Constants\n await write(`${kebab}.constants.ts`, generateRestConstants({ pascal, kebab }))\n\n // Controller (injects service)\n await write(\n `${kebab}.controller.ts`,\n generateRestController({ pascal, kebab, plural, pluralPascal }),\n )\n\n // Service (wraps repository)\n await write(`${kebab}.service.ts`, generateRestService({ pascal, kebab }))\n\n // DTOs\n await write(`dtos/create-${kebab}.dto.ts`, generateCreateDTO({ pascal, kebab }))\n await write(`dtos/update-${kebab}.dto.ts`, generateUpdateDTO({ pascal, kebab }))\n await write(`dtos/${kebab}-response.dto.ts`, generateResponseDTO({ pascal, kebab }))\n\n // Repository interface (flat imports)\n await write(\n `${kebab}.repository.ts`,\n generateRepositoryInterface({ pascal, kebab, dtoPrefix: './dtos' }),\n )\n\n // Repository implementation (flat imports)\n const builtinRepoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const builtinRepoGeneratorMap: Record<string, () => string> = {\n inmemory: () =>\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n drizzle: () =>\n generateDrizzleRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n prisma: () =>\n generatePrismaRepository({\n pascal,\n kebab,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n prismaClientPath,\n }),\n }\n const repoFile = builtinRepoFileMap[repo] ?? `${toKebabCase(repo)}-${kebab}`\n const repoGenerator =\n builtinRepoGeneratorMap[repo] ??\n (() =>\n generateCustomRepository({\n pascal,\n kebab,\n repoType: repo,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n }))\n await write(`${repoFile}.repository.ts`, repoGenerator())\n\n // Tests\n if (!noTests) {\n // Always generate an in-memory repo for testing — even when using drizzle/prisma\n if (repo !== 'inmemory') {\n await write(\n `in-memory-${kebab}.repository.ts`,\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n )\n }\n await write(\n `__tests__/${kebab}.controller.test.ts`,\n generateControllerTest({ pascal, kebab, plural }),\n )\n await write(\n `__tests__/${kebab}.repository.test.ts`,\n generateRepositoryTest({\n pascal,\n kebab,\n plural,\n repoPrefix: `../${builtinRepoFileMap.inmemory ?? `in-memory-${kebab}`}.repository`,\n }),\n )\n }\n}\n","import type { ModuleContext } from './types'\nimport { toKebabCase } from '../../utils/naming'\nimport {\n generateCqrsModuleIndex,\n generateRestConstants,\n generateCqrsController,\n generateCreateDTO,\n generateUpdateDTO,\n generateResponseDTO,\n generateCqrsCommands,\n generateCqrsQueries,\n generateCqrsEvents,\n generateRepositoryInterface,\n generateInMemoryRepository,\n generateCustomRepository,\n generateDrizzleRepository,\n generatePrismaRepository,\n generateControllerTest,\n generateRepositoryTest,\n} from '../templates'\n\nexport async function generateCqrsFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, write } = ctx\n\n // Module index\n await write('index.ts', generateCqrsModuleIndex({ pascal, kebab, plural, repo }))\n\n // Constants\n await write(`${kebab}.constants.ts`, generateRestConstants({ pascal, kebab }))\n\n // Controller (dispatches commands/queries)\n await write(\n `${kebab}.controller.ts`,\n generateCqrsController({ pascal, kebab, plural, pluralPascal }),\n )\n\n // DTOs\n await write(`dtos/create-${kebab}.dto.ts`, generateCreateDTO({ pascal, kebab }))\n await write(`dtos/update-${kebab}.dto.ts`, generateUpdateDTO({ pascal, kebab }))\n await write(`dtos/${kebab}-response.dto.ts`, generateResponseDTO({ pascal, kebab }))\n\n // Commands\n const commands = generateCqrsCommands({ pascal, kebab })\n for (const cmd of commands) {\n await write(`commands/${cmd.file}`, cmd.content)\n }\n\n // Queries\n const queries = generateCqrsQueries({ pascal, kebab, plural, pluralPascal })\n for (const q of queries) {\n await write(`queries/${q.file}`, q.content)\n }\n\n // Events\n const events = generateCqrsEvents({ pascal, kebab })\n for (const e of events) {\n await write(`events/${e.file}`, e.content)\n }\n\n // Repository interface (flat imports)\n await write(\n `${kebab}.repository.ts`,\n generateRepositoryInterface({ pascal, kebab, dtoPrefix: './dtos' }),\n )\n\n // Repository implementation (flat imports)\n const builtinRepoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const builtinRepoGeneratorMap: Record<string, () => string> = {\n inmemory: () =>\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n drizzle: () =>\n generateDrizzleRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n prisma: () =>\n generatePrismaRepository({\n pascal,\n kebab,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n prismaClientPath,\n }),\n }\n const repoFile = builtinRepoFileMap[repo] ?? `${toKebabCase(repo)}-${kebab}`\n const repoGenerator =\n builtinRepoGeneratorMap[repo] ??\n (() =>\n generateCustomRepository({\n pascal,\n kebab,\n repoType: repo,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n }))\n await write(`${repoFile}.repository.ts`, repoGenerator())\n\n // Tests\n if (!noTests) {\n // Always generate an in-memory repo for testing — even when using drizzle/prisma\n if (repo !== 'inmemory') {\n await write(\n `in-memory-${kebab}.repository.ts`,\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n )\n }\n await write(\n `__tests__/${kebab}.controller.test.ts`,\n generateControllerTest({ pascal, kebab, plural }),\n )\n await write(\n `__tests__/${kebab}.repository.test.ts`,\n generateRepositoryTest({\n pascal,\n kebab,\n plural,\n repoPrefix: `../${builtinRepoFileMap.inmemory ?? `in-memory-${kebab}`}.repository`,\n }),\n )\n }\n}\n","import type { ModuleContext } from './types'\nimport { toKebabCase } from '../../utils/naming'\nimport {\n generateModuleIndex,\n generateConstants,\n generateDrizzleConstants,\n generateController,\n generateCreateDTO,\n generateUpdateDTO,\n generateResponseDTO,\n generateUseCases,\n generateRepositoryInterface,\n generateDomainService,\n generateInMemoryRepository,\n generateCustomRepository,\n generateDrizzleRepository,\n generatePrismaRepository,\n generateEntity,\n generateValueObject,\n generateControllerTest,\n generateRepositoryTest,\n} from '../templates'\n\nexport async function generateDddFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, pluralPascal, repo, noEntity, noTests, prismaClientPath, write } =\n ctx\n\n // Module index\n await write('index.ts', generateModuleIndex({ pascal, kebab, plural, repo }))\n\n // Constants — use Drizzle-specific type-safe config when repo is drizzle\n await write(\n 'constants.ts',\n repo === 'drizzle'\n ? generateDrizzleConstants({ pascal, kebab })\n : generateConstants({ pascal, kebab }),\n )\n\n // Controller (injects use-cases)\n await write(\n `presentation/${kebab}.controller.ts`,\n generateController({ pascal, kebab, plural, pluralPascal }),\n )\n\n // DTOs\n await write(`application/dtos/create-${kebab}.dto.ts`, generateCreateDTO({ pascal, kebab }))\n await write(`application/dtos/update-${kebab}.dto.ts`, generateUpdateDTO({ pascal, kebab }))\n await write(`application/dtos/${kebab}-response.dto.ts`, generateResponseDTO({ pascal, kebab }))\n\n // Use Cases\n const useCases = generateUseCases({ pascal, kebab, plural, pluralPascal })\n for (const uc of useCases) {\n await write(`application/use-cases/${uc.file}`, uc.content)\n }\n\n // Repository Interface\n await write(\n `domain/repositories/${kebab}.repository.ts`,\n generateRepositoryInterface({ pascal, kebab }),\n )\n\n // Domain Service\n await write(\n `domain/services/${kebab}-domain.service.ts`,\n generateDomainService({ pascal, kebab }),\n )\n\n // Repository Implementation\n const builtinRepoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const builtinRepoGeneratorMap: Record<string, () => string> = {\n inmemory: () => generateInMemoryRepository({ pascal, kebab }),\n drizzle: () => generateDrizzleRepository({ pascal, kebab }),\n prisma: () => generatePrismaRepository({ pascal, kebab, prismaClientPath }),\n }\n const repoFile = builtinRepoFileMap[repo] ?? `${toKebabCase(repo)}-${kebab}`\n const repoGenerator =\n builtinRepoGeneratorMap[repo] ??\n (() => generateCustomRepository({ pascal, kebab, repoType: repo }))\n await write(`infrastructure/repositories/${repoFile}.repository.ts`, repoGenerator())\n\n // Entity & Value Objects\n if (!noEntity) {\n await write(`domain/entities/${kebab}.entity.ts`, generateEntity({ pascal, kebab }))\n await write(`domain/value-objects/${kebab}-id.vo.ts`, generateValueObject({ pascal, kebab }))\n }\n\n // Tests\n if (!noTests) {\n // Always generate an in-memory repo for testing — even when using drizzle/prisma\n if (repo !== 'inmemory') {\n await write(\n `infrastructure/repositories/in-memory-${kebab}.repository.ts`,\n generateInMemoryRepository({ pascal, kebab }),\n )\n }\n await write(\n `__tests__/${kebab}.controller.test.ts`,\n generateControllerTest({ pascal, kebab, plural }),\n )\n await write(\n `__tests__/${kebab}.repository.test.ts`,\n generateRepositoryTest({ pascal, kebab, plural }),\n )\n }\n}\n","import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { confirm, log } from '../utils/prompts'\nimport { colors } from '../utils/colors'\nimport { toPascalCase, toKebabCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport type { ProjectPattern, RepoTypeConfig } from '../config'\nimport {\n generateMinimalFiles,\n generateRestFiles,\n generateCqrsFiles,\n generateDddFiles,\n} from './patterns'\nimport type { ModuleContext } from './patterns'\n\nexport type BuiltinRepoType = 'drizzle' | 'inmemory' | 'prisma'\nexport type RepoType = BuiltinRepoType | (string & {})\n\n/** Resolve a RepoTypeConfig (from kick.config.ts) into a flat repo type string */\nexport function resolveRepoType(config?: RepoTypeConfig): RepoType {\n if (!config) return 'inmemory'\n if (typeof config === 'string') return config\n return config.name\n}\n\ninterface GenerateModuleOptions {\n name: string\n modulesDir: string\n noEntity?: boolean\n noTests?: boolean\n repo?: RepoType\n minimal?: boolean\n force?: boolean\n pattern?: ProjectPattern\n dryRun?: boolean\n /** When false, skip pluralization — use singular names for folders, routes, and classes */\n pluralize?: boolean\n /** Prisma client import path (default: '@prisma/client', Prisma 7+: '@/generated/prisma/client') */\n prismaClientPath?: string\n}\n\n/**\n * Generate a module — structure depends on the project pattern.\n *\n * Patterns:\n * rest — flat folder: controller + service + DTOs + repo\n * ddd — nested DDD: presentation/ application/ domain/ infrastructure/\n * graphql — flat folder: resolver + service + DTOs + repo (future)\n * cqrs — commands, queries, events with WS/queue integration\n * minimal — just controller + module index\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n const { name, modulesDir, noEntity, noTests, repo = 'inmemory', force, dryRun } = options\n const shouldPluralize = options.pluralize !== false\n\n let pattern = options.pattern ?? 'ddd'\n if (options.minimal) pattern = 'minimal'\n\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const plural = shouldPluralize ? pluralize(kebab) : kebab\n const pluralPascal = shouldPluralize ? pluralizePascal(pascal) : pascal\n const moduleDir = join(modulesDir, plural)\n\n const files: string[] = []\n let overwriteAll = force ?? false\n\n const write = async (relativePath: string, content: string) => {\n const fullPath = join(moduleDir, relativePath)\n if (dryRun) {\n files.push(fullPath)\n return\n }\n if (!overwriteAll && (await fileExists(fullPath))) {\n const shouldOverwrite = await confirm({\n message: `File exists: ${colors.dim(relativePath)}. Overwrite?`,\n initialValue: false,\n })\n if (!shouldOverwrite) {\n log.warn(`Skipped: ${relativePath}`)\n return\n }\n }\n await writeFileSafe(fullPath, content)\n files.push(fullPath)\n }\n\n const ctx: ModuleContext = {\n kebab,\n pascal,\n plural,\n pluralPascal,\n moduleDir,\n repo,\n noEntity: noEntity ?? false,\n noTests: noTests ?? false,\n prismaClientPath: options.prismaClientPath ?? '@prisma/client',\n write,\n files,\n }\n\n switch (pattern) {\n case 'minimal':\n await generateMinimalFiles(ctx)\n break\n case 'rest':\n await generateRestFiles(ctx)\n break\n case 'cqrs':\n await generateCqrsFiles(ctx)\n break\n case 'graphql':\n case 'ddd':\n default:\n await generateDddFiles(ctx)\n break\n }\n\n // Auto-register in modules index (all patterns need this)\n if (!dryRun) {\n await autoRegisterModule(modulesDir, pascal, plural)\n }\n\n return files\n}\n\n// ── Auto-register in modules index ──────────────────────────────────────\n\n/** Add the new module to src/modules/index.ts */\nasync function autoRegisterModule(\n modulesDir: string,\n pascal: string,\n plural: string,\n): Promise<void> {\n const indexPath = join(modulesDir, 'index.ts')\n const exists = await fileExists(indexPath)\n\n if (!exists) {\n await writeFileSafe(\n indexPath,\n `import type { AppModuleClass } from '@forinda/kickjs'\nimport { ${pascal}Module } from './${plural}'\n\nexport const modules: AppModuleClass[] = [${pascal}Module]\n`,\n )\n return\n }\n\n let content = await readFile(indexPath, 'utf-8')\n\n // Add import if not present\n const importLine = `import { ${pascal}Module } from './${plural}'`\n if (!content.includes(`${pascal}Module`)) {\n // Insert import after last existing import\n const lastImportIdx = content.lastIndexOf('import ')\n if (lastImportIdx !== -1) {\n const lineEnd = content.indexOf('\\n', lastImportIdx)\n content = content.slice(0, lineEnd + 1) + importLine + '\\n' + content.slice(lineEnd + 1)\n } else {\n content = importLine + '\\n' + content\n }\n\n // Add to modules array — handle both empty and existing entries\n // Match the array assignment: `= [...]` or `= [\\n...\\n]`\n content = content.replace(/(=\\s*\\[)([\\s\\S]*?)(])/, (_match, open, existing, close) => {\n const trimmed = existing.trim()\n if (!trimmed) {\n // Empty array: `= []`\n return `${open}${pascal}Module${close}`\n }\n // Existing entries: append with comma\n const needsComma = trimmed.endsWith(',') ? '' : ','\n return `${open}${existing.trimEnd()}${needsComma} ${pascal}Module${close}`\n })\n }\n\n await writeFile(indexPath, content, 'utf-8')\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateAdapterOptions {\n name: string\n outDir: string\n}\n\nexport async function generateAdapter(options: GenerateAdapterOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.adapter.ts`)\n await writeFileSafe(\n filePath,\n `import type { AppAdapter, AdapterContext, AdapterMiddleware } from '@forinda/kickjs'\n\nexport interface ${pascal}AdapterOptions {\n // Add your adapter configuration here\n}\n\n/**\n * ${pascal} adapter.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * or external service connections.\n *\n * Usage:\n * bootstrap({\n * adapters: [new ${pascal}Adapter({ ... })],\n * })\n */\nexport class ${pascal}Adapter implements AppAdapter {\n name = '${pascal}Adapter'\n\n constructor(private options: ${pascal}AdapterOptions = {}) {}\n\n /**\n * Return middleware entries that the Application will mount.\n * Use \\`phase\\` to control where in the pipeline they run:\n * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'\n */\n middleware(): AdapterMiddleware[] {\n return [\n // Example: add a custom header to all responses\n // {\n // phase: 'beforeGlobal',\n // handler: (_req: any, res: any, next: any) => {\n // res.setHeader('X-${pascal}', 'true')\n // next()\n // },\n // },\n // Example: scope middleware to a specific path\n // {\n // phase: 'beforeRoutes',\n // path: '/api/v1/admin',\n // handler: myAdminMiddleware(),\n // },\n ]\n }\n\n /**\n * Called before global middleware.\n * Use this to mount routes that bypass the middleware stack\n * (health checks, docs UI, static assets).\n */\n beforeMount({ app }: AdapterContext): void {\n // Example: mount a status route\n // app.get('/${kebab}/status', (_req, res) => {\n // res.json({ status: 'ok' })\n // })\n }\n\n /**\n * Called after modules and routes are registered, before the server starts.\n * Use this for late-stage DI registrations or config validation.\n */\n beforeStart({ container }: AdapterContext): void {\n // Example: register a service in the DI container\n // container.registerInstance(MY_TOKEN, new MyService(this.options))\n }\n\n /**\n * Called after the HTTP server is listening.\n * Use this to attach to the raw http.Server (Socket.IO, gRPC, etc).\n */\n afterStart({ server, container }: AdapterContext): void {\n // Example: attach Socket.IO\n // const io = new Server(server)\n // container.registerInstance(SOCKET_IO, io)\n }\n\n /**\n * Called on graceful shutdown. Clean up connections.\n */\n async shutdown(): Promise<void> {\n // Example: close a connection pool\n // await this.pool.end()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { resolve, join } from 'node:path'\nimport { pluralize, toKebabCase } from './naming'\nimport type { ProjectPattern } from '../config'\n\n/**\n * DDD folder mapping — nested layered architecture.\n */\nconst DDD_FOLDER_MAP: Record<string, string> = {\n controller: 'presentation',\n service: 'domain/services',\n dto: 'application/dtos',\n guard: 'presentation/guards',\n middleware: 'middleware',\n}\n\n/**\n * Flat folder mapping — REST/GraphQL/minimal patterns.\n * Files live at the module root or in minimal subdirectories.\n */\nconst FLAT_FOLDER_MAP: Record<string, string> = {\n controller: '',\n service: '',\n dto: 'dtos',\n guard: 'guards',\n middleware: 'middleware',\n}\n\n/**\n * CQRS folder mapping — commands, queries, events.\n */\nconst CQRS_FOLDER_MAP: Record<string, string> = {\n controller: '',\n service: '',\n dto: 'dtos',\n guard: 'guards',\n middleware: 'middleware',\n command: 'commands',\n query: 'queries',\n event: 'events',\n}\n\nexport interface ResolveOutDirOptions {\n /** The artifact type (controller, service, dto, guard, middleware) */\n type: string\n /** Explicit -o / --out dir from CLI flag (takes highest priority) */\n outDir?: string\n /** Module name from --module flag */\n moduleName?: string\n /** Modules directory (from config or default) */\n modulesDir?: string\n /** Standalone default directory when no --module is used (e.g. 'src/controllers') */\n defaultDir: string\n /** Project pattern — determines folder structure inside modules */\n pattern?: ProjectPattern\n /** Whether to pluralize the module folder name (default: true) */\n shouldPluralize?: boolean\n}\n\n/**\n * Resolve the output directory for a generator artifact.\n *\n * Priority:\n * 1. Explicit --out flag (always wins)\n * 2. --module flag → maps into module's folder (DDD or flat based on pattern)\n * 3. Standalone default directory\n */\nexport function resolveOutDir(options: ResolveOutDirOptions): string {\n const {\n type,\n outDir,\n moduleName,\n modulesDir = 'src/modules',\n defaultDir,\n pattern = 'ddd',\n shouldPluralize = true,\n } = options\n\n // Explicit --out always wins\n if (outDir) return resolve(outDir)\n\n // Module-scoped: place inside the module's folder\n if (moduleName) {\n const folderMap =\n pattern === 'ddd' ? DDD_FOLDER_MAP : pattern === 'cqrs' ? CQRS_FOLDER_MAP : FLAT_FOLDER_MAP\n const kebab = toKebabCase(moduleName)\n const folder = shouldPluralize ? pluralize(kebab) : kebab\n const subfolder = folderMap[type] ?? ''\n const base = join(modulesDir, folder)\n return resolve(subfolder ? join(base, subfolder) : base)\n }\n\n // Standalone default\n return resolve(defaultDir)\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateMiddlewareOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'middleware',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/middleware',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.middleware.ts`)\n await writeFileSafe(\n filePath,\n `import type { Request, Response, NextFunction } from 'express'\n\nexport interface ${toPascalCase(name)}Options {\n // Add configuration options here\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap:\n * middleware: [${camel}()]\n *\n * Usage with adapter:\n * middleware() { return [{ handler: ${camel}(), phase: 'afterGlobal' }] }\n *\n * Usage with @Middleware decorator:\n * @Middleware(${camel}())\n */\nexport function ${camel}(options: ${toPascalCase(name)}Options = {}) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Implement your middleware logic here\n next()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateGuardOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'guard',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/guards',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.guard.ts`)\n await writeFileSafe(\n filePath,\n `import { Container, HttpException } from '@forinda/kickjs'\nimport type { RequestContext } from '@forinda/kickjs'\n\n/**\n * ${pascal} guard.\n *\n * Guards protect routes by checking conditions before the handler runs.\n * Return early with an error response to block access.\n *\n * Usage:\n * @Middleware(${camel}Guard)\n * @Get('/protected')\n * async handler(ctx: RequestContext) { ... }\n */\nexport async function ${camel}Guard(ctx: RequestContext, next: () => void): Promise<void> {\n // Example: check for an authorization header\n const header = ctx.headers.authorization\n if (!header?.startsWith('Bearer ')) {\n ctx.res.status(401).json({ message: 'Missing or invalid authorization header' })\n return\n }\n\n const token = header.slice(7)\n\n try {\n // Verify the token using a service from the DI container\n // const container = Container.getInstance()\n // const authService = container.resolve(AuthService)\n // const payload = authService.verifyToken(token)\n // ctx.set('auth', payload)\n\n next()\n } catch {\n ctx.res.status(401).json({ message: 'Invalid or expired token' })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateServiceOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'service',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/services',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.service.ts`)\n await writeFileSafe(\n filePath,\n `import { Service } from '@forinda/kickjs'\n\n@Service()\nexport class ${pascal}Service {\n // Inject dependencies via constructor\n // constructor(\n // @Inject(MY_REPO) private readonly repo: IMyRepository,\n // ) {}\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateControllerOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'controller',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/controllers',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.controller.ts`)\n await writeFileSafe(\n filePath,\n `import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'\n\n// \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`). After the first run, your IDE\n// will autocomplete \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\`.\n// See https://forinda.github.io/kick-js/guide/typegen for details.\n\n@Controller()\nexport class ${pascal}Controller {\n // @Autowired() private readonly myService!: MyService\n\n @Get('/')\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n ctx.json({ message: '${pascal} list' })\n }\n\n @Post('/')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n ctx.created({ message: '${pascal} created', data: ctx.body })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateDtoOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'dto',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/dtos',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.dto.ts`)\n await writeFileSafe(\n filePath,\n `import { z } from 'zod'\n\nexport const ${camel}Schema = z.object({\n // Define your schema fields here\n name: z.string().min(1).max(200),\n})\n\nexport type ${pascal}DTO = z.infer<typeof ${camel}Schema>\n`,\n )\n files.push(filePath)\n\n return files\n}\n","type ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/** Map of optional package names to their npm package identifiers */\nconst PACKAGE_DEPS: Record<string, string> = {\n auth: '@forinda/kickjs-auth',\n swagger: '@forinda/kickjs-swagger',\n otel: '@forinda/kickjs-otel',\n ws: '@forinda/kickjs-ws',\n queue: '@forinda/kickjs-queue',\n cron: '@forinda/kickjs-cron',\n mailer: '@forinda/kickjs-mailer',\n graphql: '@forinda/kickjs-graphql',\n devtools: '@forinda/kickjs-devtools',\n notifications: '@forinda/kickjs-notifications',\n 'multi-tenant': '@forinda/kickjs-multi-tenant',\n}\n\n/** Generate package.json with template-aware dependencies */\nexport function generatePackageJson(\n name: string,\n template: ProjectTemplate,\n kickjsVersion: string,\n packages: string[] = [],\n): string {\n const baseDeps: Record<string, string> = {\n '@forinda/kickjs': kickjsVersion,\n // `dotenv` is an optional peer of @forinda/kickjs — scaffolded apps\n // get it pre-installed so `.env` files Just Work. Apps that load\n // env from the shell or a secret manager can drop this safely.\n dotenv: '^17.3.1',\n express: '^5.1.0',\n 'reflect-metadata': '^0.2.2',\n zod: '^4.3.6',\n pino: '^10.3.1',\n 'pino-pretty': '^13.1.3',\n }\n\n // graphql template always needs the graphql runtime\n if (template === 'graphql') {\n baseDeps['@forinda/kickjs-graphql'] = kickjsVersion\n baseDeps['graphql'] = '^16.11.0'\n }\n\n // Add user-selected optional packages\n for (const pkg of packages) {\n const dep = PACKAGE_DEPS[pkg]\n if (dep && !baseDeps[dep]) {\n baseDeps[dep] = kickjsVersion\n }\n }\n\n // graphql package needs the graphql peer dep\n if (packages.includes('graphql') && !baseDeps['graphql']) {\n baseDeps['graphql'] = '^16.11.0'\n }\n\n return JSON.stringify(\n {\n name,\n version: kickjsVersion.replace('^', ''), // Remove the ^ prefix for project version\n type: 'module',\n scripts: {\n dev: 'vite',\n 'dev:debug': 'kick dev:debug',\n build: 'kick build',\n start: 'kick start',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n typegen: 'kick typegen',\n lint: 'eslint src/',\n format: 'prettier --write src/',\n },\n dependencies: baseDeps,\n devDependencies: {\n '@forinda/kickjs-cli': kickjsVersion,\n '@forinda/kickjs-vite': kickjsVersion,\n '@swc/core': '^1.15.21',\n '@types/express': '^5.0.6',\n '@types/node': '^25.0.0',\n 'unplugin-swc': '^1.5.9',\n vite: '^8.0.3',\n vitest: '^4.1.2',\n typescript: '^5.9.2',\n prettier: '^3.8.1',\n },\n },\n null,\n 2,\n )\n}\n\n/**\n * Generate vite.config.ts with the KickJS Vite plugin.\n *\n * The plugin handles:\n * - SSR environment setup for backend Node.js code\n * - Virtual module generation (virtual:kickjs/app)\n * - Module auto-discovery (scans *.module.ts files)\n * - HMR with selective container invalidation\n * - Express mounting via configureServer() post-hook\n * - httpServer piping to adapters (WsAdapter, Socket.IO, etc.)\n */\nexport function generateViteConfig(): string {\n return `import { defineConfig } from 'vite'\nimport { resolve } from 'node:path'\nimport swc from 'unplugin-swc'\nimport { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'\n\nexport default defineConfig({\n oxc: false,\n plugins: [\n swc.vite(),\n kickjsVitePlugin({ entry: 'src/index.ts' }),\n // Watches .env files and triggers a full reload on change so the\n // dev server picks up env tweaks without a manual restart.\n envWatchPlugin(),\n ],\n resolve: {\n alias: {\n '@': resolve(__dirname, 'src'),\n },\n },\n ssr: {\n // Don't bundle pino — its worker-thread transport needs Node.js resolution\n // to find pino-pretty at runtime for colored log output\n external: ['pino', 'pino-pretty'],\n },\n build: {\n target: 'node20',\n ssr: true,\n outDir: 'dist',\n sourcemap: true,\n rollupOptions: {\n input: resolve(__dirname, 'src/index.ts'),\n output: { format: 'esm' },\n },\n },\n})\n`\n}\n\n/** Generate tsconfig.json with decorator support */\nexport function generateTsConfig(): string {\n return JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['node', 'vite/client'],\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n sourceMap: true,\n declaration: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: 'dist',\n // rootDir omitted so .kickjs/types/*.d.ts can sit outside src/\n paths: { '@/*': ['./src/*'] },\n },\n // .kickjs/types is generated by `kick typegen` and refreshed\n // automatically on `kick dev`. Including it here makes\n // `container.resolve()` and module discovery type-safe.\n // Both .d.ts and .ts are matched: registry/services/modules are\n // declarations, but routes.ts holds resolvable imports from your\n // controllers' Zod schemas (TS silently degrades inline `import('...')`\n // inside `.d.ts` files under `moduleResolution: 'bundler'`).\n include: ['src', '.kickjs/types/**/*.d.ts', '.kickjs/types/**/*.ts'],\n },\n null,\n 2,\n )\n}\n\n/** Generate .prettierrc with project formatting rules */\nexport function generatePrettierConfig(): string {\n return JSON.stringify(\n {\n semi: false,\n singleQuote: true,\n trailingComma: 'all',\n printWidth: 100,\n tabWidth: 2,\n },\n null,\n 2,\n )\n}\n\n/** Generate .editorconfig for consistent editor settings */\nexport function generateEditorConfig(): string {\n return `# https://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n`\n}\n\n/** Generate .gitignore with common Node.js patterns */\nexport function generateGitIgnore(): string {\n return `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n.kickjs/\n`\n}\n\n/** Generate .gitattributes for consistent line endings */\nexport function generateGitAttributes(): string {\n return `# Auto-detect text files and normalise line endings to LF\n* text=auto eol=lf\n\n# Explicitly mark generated / binary files\n*.png binary\n*.jpg binary\n*.jpeg binary\n*.gif binary\n*.ico binary\n*.woff binary\n*.woff2 binary\n*.ttf binary\n*.eot binary\n\n# Lock files — treat as generated\npnpm-lock.yaml -diff linguist-generated\nyarn.lock -diff linguist-generated\npackage-lock.json -diff linguist-generated\n`\n}\n\n/** Generate .env file with default environment variables */\nexport function generateEnv(): string {\n return `PORT=3000\nNODE_ENV=development\n`\n}\n\n/** Generate .env.example file as a template */\nexport function generateEnvExample(): string {\n return `PORT=3000\nNODE_ENV=development\n`\n}\n\n/** Generate vitest.config.ts for test configuration */\nexport function generateVitestConfig(): string {\n return `import { defineConfig } from 'vitest/config'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.test.ts'],\n },\n})\n`\n}\n","type ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/** Generate README.md with project documentation */\nexport function generateReadme(name: string, template: ProjectTemplate, pm: string): string {\n const templateLabels: Record<string, string> = {\n rest: 'REST API',\n graphql: 'GraphQL API',\n ddd: 'Domain-Driven Design',\n cqrs: 'CQRS + Event-Driven',\n minimal: 'Minimal',\n }\n\n const packages = ['@forinda/kickjs', '@forinda/kickjs-vite']\n if (template !== 'minimal') {\n packages.push('@forinda/kickjs-swagger', '@forinda/kickjs-devtools')\n }\n if (template === 'graphql') packages.push('@forinda/kickjs-graphql')\n if (template === 'cqrs') {\n packages.push('@forinda/kickjs-queue', '@forinda/kickjs-ws', '@forinda/kickjs-otel')\n }\n\n return `# ${name}\n\nA **${templateLabels[template] ?? 'REST API'}** built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.\n\n## Getting Started\n\n\\`\\`\\`bash\n${pm} install\nkick dev\n\\`\\`\\`\n\n## Scripts\n\n| Command | Description |\n|---|---|\n| \\`kick dev\\` | Start dev server with Vite HMR |\n| \\`kick build\\` | Production build |\n| \\`kick start\\` | Run production build |\n| \\`${pm} run test\\` | Run tests with Vitest |\n| \\`kick g module <name>\\` | Generate a DDD module |\n| \\`kick g scaffold <name> <fields...>\\` | Generate CRUD from field definitions |\n| \\`kick add <package>\\` | Add a KickJS package |\n\n## Project Structure\n\n\\`\\`\\`\nsrc/\n├── index.ts # Application entry point\n├── modules/ # Feature modules (controllers, services, repos)\n│ └── index.ts # Module registry\n└── ...\n\\`\\`\\`\n\n## Packages\n\n${packages.map((p) => `- \\`${p}\\``).join('\\n')}\n\n## Adding Features\n\n\\`\\`\\`bash\nkick add auth # Authentication (JWT, API key, OAuth)\nkick add swagger # OpenAPI documentation\nkick add ws # WebSocket support\nkick add queue # Background job processing\nkick add mailer # Email sending\nkick add cron # Scheduled tasks\nkick add --list # Show all available packages\n\\`\\`\\`\n\n## Environment Variables\n\nCopy \\`.env.example\\` to \\`.env\\` and configure:\n\n| Variable | Default | Description |\n|---|---|---|\n| \\`PORT\\` | \\`3000\\` | Server port |\n| \\`NODE_ENV\\` | \\`development\\` | Environment |\n\n## Learn More\n\n- [KickJS Documentation](https://forinda.github.io/kick-js/)\n- [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)\n`\n}\n\n/** Generate CLAUDE.md with AI development guide */\nexport function generateClaude(name: string, template: ProjectTemplate, pm: string): string {\n const templateLabels: Record<string, string> = {\n rest: 'REST API',\n graphql: 'GraphQL API',\n ddd: 'Domain-Driven Design',\n cqrs: 'CQRS + Event-Driven',\n minimal: 'Minimal Express',\n }\n\n return `# CLAUDE.md — ${name} Development Guide\n\n## Project Overview\n\nThis is a **${templateLabels[template] ?? 'REST API'}** application built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.\n\n## Quick Commands\n\n\\`\\`\\`bash\n${pm} install # Install dependencies\nkick dev # Start dev server with HMR\nkick build # Production build via Vite\nkick start # Run production build\n${pm} run test # Run tests with Vitest\n${pm} run typecheck # TypeScript type checking\n${pm} run format # Format code with Prettier\n\\`\\`\\`\n\n## Project Structure\n\n\\`\\`\\`\nsrc/\n├── index.ts # Application bootstrap\n├── modules/ # Feature modules (DDD/CQRS pattern)\n│ └── index.ts # Module registry\n${template === 'graphql' ? '├── resolvers/ # GraphQL resolvers\\n' : ''}└── ...\n\\`\\`\\`\n\n## Package Manager\n\n- Always use **${pm}** for this project\n- Run \\`${pm} install\\` to sync dependencies\n- Never mix package managers (npm/yarn/pnpm)\n\n## Code Style\n\n- **Prettier** — no semicolons, single quotes, trailing commas, 100 char width\n- **TypeScript strict mode** — all types required\n- Format before committing: \\`${pm} run format\\`\n- Type check with: \\`${pm} run typecheck\\`\n\n## Key Patterns\n\n### Controllers\n\nUse decorators to define routes. Annotate \\`ctx\\` with \\`Ctx<KickRoutes.X['method']>\\`\nto get fully-typed \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` from the\ngenerated \\`KickRoutes\\` namespace (refreshed on \\`kick dev\\` and \\`kick typegen\\`).\n\n\\`\\`\\`ts\nimport { Controller, Get, Post, type Ctx } from '@forinda/kickjs'\n\n@Controller('/users')\nexport class UserController {\n @Get('/')\n async findAll(ctx: Ctx<KickRoutes.UserController['findAll']>) {\n return ctx.json({ users: [] })\n }\n\n @Post('/')\n async create(ctx: Ctx<KickRoutes.UserController['create']>) {\n const data = ctx.body\n return ctx.created({ user: data })\n }\n}\n\\`\\`\\`\n\n### Services\n\nInject dependencies with \\`@Service()\\` and \\`@Autowired()\\`:\n\n\\`\\`\\`ts\nimport { Service, Autowired } from '@forinda/kickjs'\n\n@Service()\nexport class UserService {\n @Autowired()\n private userRepository!: UserRepository\n\n async findAll() {\n return this.userRepository.findAll()\n }\n}\n\\`\\`\\`\n\n### Modules\n\nModules implement \\`AppModule\\` and wire controllers via \\`buildRoutes()\\`:\n\n\\`\\`\\`ts\nimport { type AppModule, type ModuleRoutes, buildRoutes } from '@forinda/kickjs'\nimport { UserController } from './user.controller'\n\nexport class UserModule implements AppModule {\n routes(): ModuleRoutes {\n return {\n path: '/users',\n router: buildRoutes(UserController),\n controller: UserController,\n }\n }\n}\n\\`\\`\\`\n\nRegister all modules in \\`src/modules/index.ts\\`:\n\n\\`\\`\\`ts\nimport type { AppModuleClass } from '@forinda/kickjs'\nimport { UserModule } from './user/user.module'\n\nexport const modules: AppModuleClass[] = [UserModule]\n\\`\\`\\`\n\n### RequestContext\n\nEvery controller method receives a \\`ctx\\` (alias \\`Ctx<TRoute>\\` or the\nloose \\`RequestContext\\`):\n\n\\`\\`\\`ts\nctx.body // Request body (parsed JSON)\nctx.params // Route params\nctx.query // Query string\nctx.headers // Request headers\nctx.requestId // Auto-generated request ID\nctx.session // Session data (if session middleware enabled)\nctx.file // Uploaded file (single)\nctx.files // Uploaded files (multiple)\n\n// Pagination helpers\nctx.qs(config) // Parse query with filters/sort/pagination\nctx.paginate(handler) // Auto-paginated response\n\n// Response helpers\nctx.json(data) // 200 OK with JSON\nctx.created(data) // 201 Created\nctx.noContent() // 204 No Content\nctx.notFound() // 404 Not Found\nctx.badRequest(msg) // 400 Bad Request\n\\`\\`\\`\n\n## CLI Generators\n\nGenerate code with the \\`kick\\` CLI:\n\n\\`\\`\\`bash\nkick g module <name> # Full module (controller, service, DTOs, repo)\nkick g scaffold <name> <fields> # CRUD module from field definitions\nkick g controller <name> # Standalone controller\nkick g service <name> # Service class\nkick g middleware <name> # Express middleware\nkick g guard <name> # Route guard (auth, roles)\nkick g adapter <name> # AppAdapter with lifecycle hooks\nkick g dto <name> # Zod DTO schema\n${template === 'graphql' ? 'kick g resolver <name> # GraphQL resolver\\n' : ''}${template === 'cqrs' ? 'kick g job <name> # Queue job processor\\n' : ''}\\`\\`\\`\n\n## Adding Packages\n\n\\`\\`\\`bash\nkick add auth # JWT, API key, OAuth strategies\nkick add swagger # OpenAPI docs from decorators\nkick add ws # WebSocket support\nkick add queue # Background jobs (BullMQ/RabbitMQ/Kafka)\nkick add mailer # Email (SMTP, Resend, SES)\nkick add cron # Scheduled tasks\nkick add prisma # Prisma ORM adapter\nkick add drizzle # Drizzle ORM adapter\nkick add otel # OpenTelemetry tracing\nkick add --list # Show all available packages\n\\`\\`\\`\n\n## Environment Configuration\n\nThe project's typed env schema lives in **\\`src/config/index.ts\\`** —\nextend the base schema there with your application-specific keys, and\nthe schema is auto-registered with kickjs at module load. The companion\n\\`src/index.ts\\` imports it as a side effect (\\`import './config'\\`) **before**\n\\`bootstrap()\\` runs, so every \\`@Service\\`, \\`@Controller\\`, \\`@Value\\`, and\n\\`ConfigService\\` resolution sees the validated extended values.\n\n> **Do not delete \\`import './config'\\` from \\`src/index.ts\\`.** It is the\n> registration step that wires \\`ConfigService\\` to your env schema.\n> Without it, \\`config.get('YOUR_KEY')\\` returns \\`undefined\\` for every\n> user-defined key and \\`@Value('YOUR_KEY')\\` only works because of a\n> raw \\`process.env\\` fallback (Zod coercion + defaults are skipped).\n\nEdit \\`.env\\` for variable values. Access them with \\`@Value()\\`:\n\n\\`\\`\\`ts\nimport { Value } from '@forinda/kickjs'\n\n@Service()\nexport class ApiService {\n @Value('API_KEY')\n private apiKey!: string\n\n @Value('PORT', 3000) // With default\n private port!: number\n}\n\\`\\`\\`\n\nOr use \\`ConfigService\\`:\n\n\\`\\`\\`ts\nimport { Service, Autowired, ConfigService } from '@forinda/kickjs'\n\n@Service()\nexport class AppService {\n @Autowired()\n private config!: ConfigService\n\n getPort() {\n // typed: number, Zod-coerced from baseEnvSchema\n return this.config.get('PORT')\n }\n}\n\\`\\`\\`\n\nHot-reload of \\`.env\\` changes during dev is wired up automatically via\n\\`envWatchPlugin()\\` in \\`vite.config.ts\\` — edit \\`.env\\`, the dev server\nreloads, and the next \\`config.get()\\` re-parses with the new values.\n\n### Standalone Env Utilities (No DI Required)\n\nThese functions work anywhere — scripts, CLI tools, plain files, outside \\`@Service\\`/\\`@Controller\\`:\n\n\\`\\`\\`ts\nimport { defineEnv, loadEnv, getEnv, reloadEnv, resetEnvCache, baseEnvSchema } from '@forinda/kickjs/config'\nimport { z } from 'zod'\n\n// Define and parse schema\nconst schema = defineEnv((base) =>\n base.extend({ DATABASE_URL: z.string().url() })\n)\nconst env = loadEnv(schema) // Parse + validate process.env\nconsole.log(env.PORT) // 3000 (coerced to number)\nconsole.log(env.DATABASE_URL) // validated URL string\n\n// Get single value\nconst port = getEnv('PORT') // typed after kick typegen\n\n// Reload after .env changes (HMR calls this automatically)\nreloadEnv()\n\n// Reset cache in tests that swap schemas\nresetEnvCache()\n\\`\\`\\`\n\n| Function | Purpose |\n|----------|---------|\n| \\`defineEnv(fn)\\` | Extend base schema with custom Zod keys |\n| \\`loadEnv(schema?)\\` | Parse \\`process.env\\`, validate, cache, return typed object |\n| \\`getEnv(key, schema?)\\` | Get single validated env value |\n| \\`reloadEnv()\\` | Re-read \\`.env\\` from disk, re-parse with same schema |\n| \\`resetEnvCache()\\` | Clear parsed cache AND registered schema (for tests) |\n| \\`baseEnvSchema\\` | Base Zod schema: \\`PORT\\`, \\`NODE_ENV\\`, \\`LOG_LEVEL\\` |\n\n## Standalone Utilities (No DI Required)\n\nThese utilities work outside decorated classes:\n\n### Logger\n\n\\`\\`\\`ts\nimport { Logger, createLogger } from '@forinda/kickjs'\n\nconst log = Logger.for('MyScript') // Static factory\nlog.info('Processing started')\nlog.error('Something failed')\n\nconst log2 = createLogger('Worker') // Function form\n\\`\\`\\`\n\n### Injection Tokens\n\n\\`\\`\\`ts\nimport { createToken } from '@forinda/kickjs'\n\n// Type-safe DI tokens for factory/interface binding\nconst DB_URL = createToken<string>('config.database.url')\nconst FEATURE_FLAGS = createToken<FeatureFlags>('app.features')\n\\`\\`\\`\n\n### Reactivity\n\n\\`\\`\\`ts\nimport { ref, computed, watch, reactive } from '@forinda/kickjs'\n\nconst count = ref(0)\nconst doubled = computed(() => count.value * 2)\nconst stop = watch(() => count.value, (val) => console.log(val))\ncount.value++ // logs 1\n\\`\\`\\`\n\n### HTTP Errors\n\n\\`\\`\\`ts\nimport { HttpException, HttpStatus } from '@forinda/kickjs'\n\nthrow new HttpException(HttpStatus.NOT_FOUND, 'User not found')\n\\`\\`\\`\n\n## Testing\n\nTests live in \\`src/**/*.test.ts\\`:\n\n\\`\\`\\`ts\nimport { describe, it, expect, beforeEach } from 'vitest'\nimport { Container } from '@forinda/kickjs'\nimport { createTestApp } from '@forinda/kickjs-testing'\n\ndescribe('UserController', () => {\n beforeEach(() => Container.reset())\n\n it('should return users', async () => {\n const app = await createTestApp([UserModule])\n const res = await app.get('/users')\n expect(res.status).toBe(200)\n })\n})\n\\`\\`\\`\n\nRun tests:\n- \\`${pm} run test\\` — run all tests\n- \\`${pm} run test:watch\\` — watch mode\n\n## Decorators Reference\n\n### Route Decorators\n- \\`@Controller('/path')\\` — define controller prefix\n- \\`@Get('/'), @Post('/'), @Put('/'), @Delete('/'), @Patch('/')\\` — HTTP methods\n- \\`@Middleware(fn)\\` — attach middleware\n- \\`@Public()\\` — skip authentication (requires @forinda/kickjs-auth)\n- \\`@Roles('admin', 'user')\\` — role-based access control\n\n### DI Decorators\n- \\`@Service()\\` — singleton service (DI-registered)\n- \\`@Repository()\\` — repository (semantic alias for @Service)\n- \\`@Autowired()\\` — property injection\n- \\`@Inject('token')\\` — token-based injection\n- \\`@Value('ENV_VAR')\\` — inject config value\n\n${\n template === 'cqrs'\n ? `### CQRS/Event Decorators\n- \\`@Job('job-name')\\` — queue job handler\n- \\`@Process('queue-name')\\` — queue processor\n- \\`@Cron('0 * * * *')\\` — cron schedule\n- \\`@WsController('/path')\\` — WebSocket controller\n- \\`@Subscribe('event')\\` — WebSocket event handler\n\n`\n : ''\n}${\n template === 'graphql'\n ? `### GraphQL Decorators\n- \\`@Resolver()\\` — GraphQL resolver\n- \\`@Query()\\` — GraphQL query\n- \\`@Mutation()\\` — GraphQL mutation\n- \\`@Arg('name')\\` — resolver argument\n\n`\n : ''\n }## Common Pitfalls\n\n1. **Decorators fire at import time** — make sure to import module classes in \\`src/modules/index.ts\\`\n2. **Tests need \\`Container.reset()\\`** — call in \\`beforeEach\\` to isolate DI state\n3. **Always use \\`ctx.body\\`** — never \\`req.body\\` directly\n4. **DI requires \\`reflect-metadata\\`** — already imported in \\`src/index.ts\\`\n5. **Vite HMR requires proper cleanup** — adapters should implement \\`shutdown()\\`\n6. **Never delete \\`import './config'\\` from \\`src/index.ts\\`** — that side-effect import registers the env schema with kickjs. Without it \\`ConfigService.get('YOUR_KEY')\\` returns \\`undefined\\` for every user-defined key. \\`@Value('YOUR_KEY')\\` *appears* to keep working but only via a raw \\`process.env\\` fallback (Zod coercion + schema defaults are silently skipped).\n\n## Learn More\n\n- [KickJS Documentation](https://forinda.github.io/kick-js/)\n- [API Reference](https://forinda.github.io/kick-js/api/)\n- [CLI Commands](https://forinda.github.io/kick-js/guide/cli-commands.html)\n- [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)\n`\n}\n\n/** Generate AGENTS.md with AI agent guide */\nexport function generateAgents(name: string, template: ProjectTemplate, pm: string): string {\n return `# AGENTS.md — AI Agent Guide for ${name}\n\nThis guide helps AI agents (Claude, Copilot, etc.) work effectively on this KickJS application.\n\n## Before You Start\n\n1. Read \\`CLAUDE.md\\` for project conventions and commands\n2. Run \\`${pm} install\\` to install dependencies\n3. Run \\`kick dev\\` to verify the app starts\n4. Read the [KickJS documentation](https://forinda.github.io/kick-js/) for framework details\n\n## Where to Find Things\n\n### Application Structure\n\n| What | Where |\n|------|-------|\n| Entry point | \\`src/index.ts\\` |\n| Module registry | \\`src/modules/index.ts\\` |\n| Feature modules | \\`src/modules/<module-name>/\\` |\n${template === 'graphql' ? '| GraphQL resolvers | `src/resolvers/` |\\n' : ''}| Env values | \\`.env\\` |\n| Env schema (Zod) | \\`src/config/index.ts\\` |\n| TypeScript config | \\`tsconfig.json\\` |\n| Vite config (HMR) | \\`vite.config.ts\\` |\n| Vitest config | \\`vitest.config.ts\\` |\n| Prettier config | \\`.prettierrc\\` |\n| CLI config | \\`kick.config.ts\\` |\n\n### Module Pattern (${template.toUpperCase()})\n\nEach module in \\`src/modules/<name>/\\` typically contains:\n\n${\n template === 'ddd'\n ? `\\`\\`\\`\n<name>/\n├── <name>.controller.ts # HTTP routes (@Controller)\n├── <name>.service.ts # Business logic (@Service)\n├── <name>.repository.ts # Data access (@Repository)\n├── <name>.dto.ts # Request/response schemas (Zod)\n├── <name>.entity.ts # Domain entity (optional)\n└── <name>.module.ts # Module definition (implements AppModule)\n\\`\\`\\`\n`\n : template === 'cqrs'\n ? `\\`\\`\\`\n<name>/\n├── commands/ # Write operations\n│ ├── create-<name>.command.ts\n│ └── create-<name>.handler.ts\n├── queries/ # Read operations\n│ ├── get-<name>.query.ts\n│ └── get-<name>.handler.ts\n├── events/ # Domain events\n│ └── <name>-created.event.ts\n├── <name>.controller.ts # HTTP routes\n├── <name>.repository.ts # Data access\n└── <name>.module.ts # Module definition (implements AppModule)\n\\`\\`\\`\n`\n : template === 'graphql'\n ? `\\`\\`\\`\nresolvers/\n├── <name>.resolver.ts # @Resolver, @Query, @Mutation\n├── <name>.types.ts # GraphQL type definitions\n└── <name>.service.ts # Business logic\n\\`\\`\\`\n`\n : template === 'rest'\n ? `\\`\\`\\`\n<name>/\n├── <name>.controller.ts # HTTP routes (@Controller)\n├── <name>.service.ts # Business logic (@Service)\n├── <name>.dto.ts # Request/response schemas (Zod)\n└── <name>.module.ts # Module definition (implements AppModule)\n\\`\\`\\`\n`\n : `\\`\\`\\`\nsrc/\n├── index.ts # Add routes here\n└── ... # Custom structure\n\\`\\`\\`\n`\n}\n\n## Checklist: Adding a Feature\n\n### New Module (Recommended)\n\nUse the CLI generator for consistency:\n\n\\`\\`\\`bash\nkick g module <name> # Generate full module\n# or\nkick g scaffold <name> <fields> # Generate CRUD from fields\n\\`\\`\\`\n\nThen:\n- [ ] Review generated files in \\`src/modules/<name>/\\`\n- [ ] Verify module is registered in \\`src/modules/index.ts\\`\n- [ ] Update DTOs in \\`<name>.dto.ts\\` if needed\n- [ ] Implement business logic in \\`<name>.service.ts\\`\n- [ ] Run \\`kick dev\\` to test with HMR\n- [ ] Write tests in \\`<name>.test.ts\\`\n\n### Manual Controller\n\nIf not using generators:\n\n- [ ] Create \\`src/modules/<name>/<name>.controller.ts\\`\n- [ ] Add \\`@Controller('/path')\\` decorator\n- [ ] Add route handlers with \\`@Get()\\`, \\`@Post()\\`, etc.\n- [ ] Create module file implementing \\`AppModule\\` with \\`routes()\\` returning \\`{ path, router: buildRoutes(Controller), controller }\\`\n- [ ] Register module in \\`src/modules/index.ts\\` (\\`AppModuleClass[]\\` array)\n- [ ] Test with \\`kick dev\\`\n\n### Manual Service\n\n- [ ] Create \\`src/modules/<name>/<name>.service.ts\\`\n- [ ] Add \\`@Service()\\` decorator\n- [ ] Inject dependencies with \\`@Autowired()\\`\n- [ ] Inject via \\`@Autowired()\\` where needed\n- [ ] Write unit tests\n\n### New Middleware\n\n- [ ] Create \\`src/middleware/<name>.middleware.ts\\`\n- [ ] Export middleware function (Express format)\n- [ ] Register in \\`src/index.ts\\` or attach to routes with \\`@Middleware()\\`\n- [ ] Test with sample requests\n\n### Adding a Package\n\nUse \\`kick add\\` to install KickJS packages with correct peer dependencies:\n\n- [ ] Run \\`kick add <package>\\` (e.g., \\`kick add auth\\`)\n- [ ] Follow package-specific setup in terminal output\n- [ ] Update \\`src/index.ts\\` to register adapter (if needed)\n- [ ] Configure environment variables in \\`.env\\`\n- [ ] Test integration with \\`kick dev\\`\n\n## Common Tasks\n\n### Generate CRUD Module\n\n\\`\\`\\`bash\nkick g scaffold user name:string email:string:optional age:number\n\\`\\`\\`\n\nAppend \\`:optional\\` for optional fields (shell-safe, no quoting needed).\nQuoted \\`?\\` syntax also works: \\`\"email:string?\"\\` or \\`\"email?:string\"\\`.\n\nThis creates a full CRUD module with:\n- Controller with GET, POST, PUT, DELETE routes\n- Service with business logic\n- Repository with data access\n- DTOs with Zod validation\n\n### Add Authentication\n\n\\`\\`\\`bash\nkick add auth\n\\`\\`\\`\n\nThen configure in \\`src/index.ts\\`:\n\n\\`\\`\\`ts\nimport { AuthAdapter, JwtStrategy } from '@forinda/kickjs-auth'\n\nbootstrap({\n modules,\n adapters: [\n new AuthAdapter({\n strategies: [new JwtStrategy({ secret: process.env.JWT_SECRET! })],\n }),\n ],\n})\n\\`\\`\\`\n\n### Add Database (Prisma)\n\n\\`\\`\\`bash\nkick add prisma\n${pm} install prisma @prisma/client\nnpx prisma init\n# Edit prisma/schema.prisma\nnpx prisma migrate dev --name init\nkick g module user --repo prisma\n\\`\\`\\`\n\n### Add WebSocket Support\n\n\\`\\`\\`bash\nkick add ws\n\\`\\`\\`\n\nThen add adapter in \\`src/index.ts\\`:\n\n\\`\\`\\`ts\nimport { WsAdapter } from '@forinda/kickjs-ws'\n\nbootstrap({\n modules,\n adapters: [new WsAdapter()],\n})\n\\`\\`\\`\n\nCreate WebSocket controller:\n\n\\`\\`\\`bash\nkick g controller chat --ws\n\\`\\`\\`\n\n## Testing Guidelines\n\nAll tests use Vitest:\n\n\\`\\`\\`ts\nimport { describe, it, expect, beforeEach } from 'vitest'\nimport { Container } from '@forinda/kickjs'\nimport { createTestApp } from '@forinda/kickjs-testing'\n\ndescribe('UserController', () => {\n beforeEach(() => {\n Container.reset() // Important: isolate DI state\n })\n\n it('should return users', async () => {\n const app = await createTestApp([UserModule])\n const res = await app.get('/users')\n \n expect(res.status).toBe(200)\n expect(res.body).toHaveProperty('users')\n })\n})\n\\`\\`\\`\n\nRun tests:\n- \\`${pm} run test\\` — run all tests once\n- \\`${pm} run test:watch\\` — watch mode\n- Individual file: \\`${pm} run test src/modules/user/user.test.ts\\`\n\n## Environment Variables\n\nSchema is declared in \\`src/config/index.ts\\` (extends the base\n\\`PORT\\`/\\`NODE_ENV\\`/\\`LOG_LEVEL\\` shape via \\`defineEnv\\`) and registered\nwith kickjs at module load. \\`src/index.ts\\` imports it via\n\\`import './config'\\` **before** \\`bootstrap()\\` so the cache is populated\nin time for DI. Add new keys to the schema, drop their values into\n\\`.env\\`, and they're typed everywhere.\n\nAccess patterns:\n\n1. **@Value() decorator** (recommended for known-at-construction keys):\n\\`\\`\\`ts\n@Value('DATABASE_URL')\nprivate dbUrl!: string\n\\`\\`\\`\n\n2. **ConfigService** (recommended for dynamic / method-scoped access):\n\\`\\`\\`ts\n@Autowired()\nprivate config!: ConfigService\n\nconst port = this.config.get('PORT') // typed: number\n\\`\\`\\`\n\n3. **Standalone utilities** (no DI — works in scripts, CLI, plain files):\n\\`\\`\\`ts\nimport { loadEnv, getEnv, reloadEnv, resetEnvCache } from '@forinda/kickjs/config'\n\nconst env = loadEnv(schema) // Parse + validate all vars\nconst port = getEnv('PORT') // Single value lookup\nreloadEnv() // Re-read .env from disk\nresetEnvCache() // Full reset (for tests)\n\\`\\`\\`\n\n4. **Direct \\`process.env\\`** — avoid in app code; bypasses Zod\n coercion and the typed \\`KickEnv\\` registry.\n\n> **Pitfall**: never delete \\`import './config'\\` from \\`src/index.ts\\`.\n> If the schema is not registered before DI runs, \\`config.get()\\`\n> returns \\`undefined\\` for user keys (the base shape only) and\n> \\`@Value()\\` only works because of its raw \\`process.env\\` fallback —\n> Zod coercion + schema defaults are silently skipped.\n\n## Standalone Utilities (No DI Required)\n\nThese work anywhere — scripts, plain files, outside \\`@Service\\`/\\`@Controller\\`:\n\n| Utility | Import | Example |\n|---------|--------|---------|\n| \\`Logger.for(name)\\` | \\`@forinda/kickjs\\` | \\`const log = Logger.for('MyScript')\\` |\n| \\`createLogger(name)\\` | \\`@forinda/kickjs\\` | \\`const log = createLogger('Worker')\\` |\n| \\`createToken<T>(name)\\` | \\`@forinda/kickjs\\` | \\`const TOKEN = createToken<string>('db.url')\\` |\n| \\`ref(value)\\` | \\`@forinda/kickjs\\` | \\`const count = ref(0)\\` |\n| \\`computed(fn)\\` | \\`@forinda/kickjs\\` | \\`const doubled = computed(() => count.value * 2)\\` |\n| \\`watch(source, cb)\\` | \\`@forinda/kickjs\\` | \\`watch(() => count.value, (v) => log(v))\\` |\n| \\`reactive(obj)\\` | \\`@forinda/kickjs\\` | \\`const state = reactive({ count: 0 })\\` |\n| \\`HttpException\\` | \\`@forinda/kickjs\\` | \\`throw new HttpException(404, 'Not found')\\` |\n| \\`HttpStatus\\` | \\`@forinda/kickjs\\` | \\`HttpStatus.NOT_FOUND // 404\\` |\n\n## Key Decorators\n\n### HTTP Routes\n| Decorator | Purpose |\n|-----------|---------|\n| \\`@Controller('/path')\\` | Define route prefix |\n| \\`@Get('/'), @Post('/')\\` | HTTP method handlers |\n| \\`@Middleware(fn)\\` | Attach middleware |\n| \\`@Public()\\` | Skip auth (requires auth adapter) |\n| \\`@Roles('admin')\\` | Role-based access |\n\n### Dependency Injection\n| Decorator | Purpose |\n|-----------|---------|\n| \\`AppModule\\` interface | Define feature module (implements \\`routes()\\`) |\n| \\`@Service()\\` | Register singleton service |\n| \\`@Repository()\\` | Register repository |\n| \\`@Autowired()\\` | Property injection |\n| \\`@Inject('token')\\` | Token-based injection |\n| \\`@Value('VAR')\\` | Inject env variable |\n\n${\n template === 'graphql'\n ? `### GraphQL\n| Decorator | Purpose |\n|-----------|---------|\n| \\`@Resolver()\\` | GraphQL resolver class |\n| \\`@Query()\\` | Query handler |\n| \\`@Mutation()\\` | Mutation handler |\n| \\`@Arg('name')\\` | Resolver argument |\n\n`\n : ''\n}${\n template === 'cqrs'\n ? `### Background Jobs\n| Decorator | Purpose |\n|-----------|---------|\n| \\`@Job('name')\\` | Queue job handler |\n| \\`@Process('queue')\\` | Queue processor |\n| \\`@Cron('0 * * * *')\\` | Cron schedule |\n| \\`@WsController()\\` | WebSocket controller |\n\n`\n : ''\n }## Common Pitfalls\n\n1. **Forgot to register module** — Add to \\`src/modules/index.ts\\` exports array\n2. **DI not working** — Ensure \\`reflect-metadata\\` is imported in \\`src/index.ts\\`\n3. **Tests failing randomly** — Missing \\`Container.reset()\\` in \\`beforeEach\\`\n4. **Routes not found** — Check controller path and module registration\n5. **HMR not working** — Verify \\`vite.config.ts\\` has \\`hmr: true\\`\n6. **Decorators not working** — Check \\`tsconfig.json\\` has \\`experimentalDecorators: true\\`\n7. **\\`config.get('YOUR_KEY')\\` returns \\`undefined\\`** — \\`src/index.ts\\` is missing \\`import './config'\\`. That side-effect import registers the env schema with kickjs (\\`loadEnv(envSchema)\\` runs at module load). Without it, \\`ConfigService\\` falls back to the base schema (\\`PORT\\`/\\`NODE_ENV\\`/\\`LOG_LEVEL\\` only) and every user-defined key reads as \\`undefined\\`. \\`@Value()\\` may *appear* to work because of a raw \\`process.env\\` fallback, but Zod coercion and schema defaults are silently skipped — investigate \\`src/index.ts\\` and \\`src/config/index.ts\\` first.\n\n## CLI Commands Reference\n\n| Command | Description |\n|---------|-------------|\n| \\`kick dev\\` | Dev server with HMR |\n| \\`kick dev:debug\\` | Dev server with debugger |\n| \\`kick build\\` | Production build |\n| \\`kick start\\` | Run production build |\n| \\`kick g module <names...>\\` | Generate one or more modules |\n| \\`kick g scaffold <name> <fields>\\` | Generate CRUD |\n| \\`kick g controller <name>\\` | Generate controller |\n| \\`kick g service <name>\\` | Generate service |\n| \\`kick g middleware <name>\\` | Generate middleware |\n| \\`kick add <package>\\` | Add KickJS package |\n| \\`kick add --list\\` | List available packages |\n| \\`kick rm module <names...>\\` | Remove one or more modules |\n\n> **Note:** When using \\`kick new\\` in scripts or CI, pass \\`-t\\` (or \\`--template\\`) and \\`-r\\` (or \\`--repo\\`) flags to bypass interactive prompts:\n> \\`\\`\\`bash\n> kick new my-api -t ddd -r prisma --pm ${pm} --no-git --no-install -f\n> \\`\\`\\`\n\n## Learn More\n\n- [KickJS Docs](https://forinda.github.io/kick-js/)\n- [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)\n- [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)\n- [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)\n- [Testing](https://forinda.github.io/kick-js/api/testing.html)\n`\n}\n","import { join, dirname } from 'node:path'\nimport { execSync } from 'node:child_process'\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { writeFileSafe } from '../utils/fs'\nimport {\n generatePackageJson,\n generateViteConfig,\n generateTsConfig,\n generatePrettierConfig,\n generateEditorConfig,\n generateGitIgnore,\n generateGitAttributes,\n generateEnv,\n generateEnvExample,\n generateVitestConfig,\n} from './templates/project-config'\nimport {\n generateEntryFile,\n generateEnvFile,\n generateModulesIndex,\n generateKickConfig,\n generateHelloService,\n generateHelloController,\n generateHelloModule,\n} from './templates/project-app'\nimport { generateReadme, generateClaude, generateAgents } from './templates/project-docs'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst cliPkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'))\nconst KICKJS_VERSION = `^${cliPkg.version}`\n\ntype ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\ninterface InitProjectOptions {\n name: string\n directory: string\n packageManager?: 'pnpm' | 'npm' | 'yarn'\n initGit?: boolean\n installDeps?: boolean\n template?: ProjectTemplate\n defaultRepo?: string\n packages?: string[]\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n const {\n name,\n directory,\n packageManager = 'pnpm',\n template = 'rest',\n defaultRepo = 'inmemory',\n packages = [],\n } = options\n const dir = directory\n\n const log = (msg: string) => console.log(` ${msg}`)\n\n console.log(`\\n Creating KickJS project: ${name}\\n`)\n\n // ── package.json — template-aware deps ────────────────────────────\n await writeFileSafe(\n join(dir, 'package.json'),\n generatePackageJson(name, template, KICKJS_VERSION, packages),\n )\n\n // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n await writeFileSafe(join(dir, 'vite.config.ts'), generateViteConfig())\n\n // ── tsconfig.json ───────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'tsconfig.json'), generateTsConfig())\n\n // ── .prettierrc ─────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.prettierrc'), generatePrettierConfig())\n\n // ── .editorconfig ─────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.editorconfig'), generateEditorConfig())\n\n // ── .gitignore ──────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.gitignore'), generateGitIgnore())\n\n // ── .gitattributes ────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.gitattributes'), generateGitAttributes())\n\n // ── .env ────────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.env'), generateEnv())\n\n await writeFileSafe(join(dir, '.env.example'), generateEnvExample())\n\n // ── src/config/index.ts — typed env schema (read by `kick typegen`) ─\n // Lives under `src/config/` so the framework's \"config\" concept has a\n // single, conventional home. Old projects with `src/env.ts` still\n // work — `detectEnvFile()` searches both locations.\n await writeFileSafe(join(dir, 'src/config/index.ts'), generateEnvFile())\n\n // ── src/index.ts — template-aware entry point ─────────────────────\n await writeFileSafe(\n join(dir, 'src/index.ts'),\n generateEntryFile(name, template, cliPkg.version, packages),\n )\n\n // ── src/modules/index.ts ────────────────────────────────────────────\n await writeFileSafe(join(dir, 'src/modules/index.ts'), generateModulesIndex())\n\n // ── src/modules/hello/ — sample module ─────────────────────────────\n await writeFileSafe(join(dir, 'src/modules/hello/hello.service.ts'), generateHelloService())\n await writeFileSafe(join(dir, 'src/modules/hello/hello.controller.ts'), generateHelloController())\n await writeFileSafe(join(dir, 'src/modules/hello/hello.module.ts'), generateHelloModule())\n\n // ── Template-specific files ─────────────────────────────────────────\n if (template === 'graphql') {\n await writeFileSafe(join(dir, 'src/resolvers/.gitkeep'), '')\n }\n\n // ── kick.config.ts — CLI configuration ─────────────────────────────\n await writeFileSafe(join(dir, 'kick.config.ts'), generateKickConfig(template, defaultRepo))\n\n // ── vitest.config.ts ────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'vitest.config.ts'), generateVitestConfig())\n\n // ── README.md ────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'README.md'), generateReadme(name, template, packageManager))\n\n // ── CLAUDE.md ────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'CLAUDE.md'), generateClaude(name, template, packageManager))\n\n // ── AGENTS.md ────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'AGENTS.md'), generateAgents(name, template, packageManager))\n\n // ── Install Dependencies ────────────────────────────────────────────\n // Install BEFORE git init so the lockfile is included in the first commit.\n if (options.installDeps) {\n console.log(`\\n Installing dependencies with ${packageManager}...\\n`)\n try {\n execSync(`${packageManager} install`, { cwd: dir, stdio: 'inherit' })\n console.log('\\n Dependencies installed successfully!')\n } catch {\n console.log(`\\n Warning: ${packageManager} install failed. Run it manually.`)\n }\n }\n\n // ── Initial typegen ────────────────────────────────────────────────\n // Run typegen once so the freshly-scaffolded HelloController's\n // `Ctx<KickRoutes.HelloController['index']>` references resolve in\n // the user's editor immediately. Failures are non-fatal.\n try {\n const { runTypegen } = await import('../typegen')\n await runTypegen({ cwd: dir, allowDuplicates: true, silent: true })\n } catch {\n // First-run typegen errors are non-fatal — `kick dev` will retry.\n }\n\n // ── Git Init ─────────────────────────────────────────────────────────\n // Runs after install + typegen so lockfile and generated types are\n // included in the initial commit.\n if (options.initGit) {\n try {\n execSync('git init', { cwd: dir, stdio: 'pipe' })\n execSync('git branch -M main', { cwd: dir, stdio: 'pipe' })\n execSync('git add -A', { cwd: dir, stdio: 'pipe' })\n execSync('git commit -m \"chore: initial commit from kick new\"', {\n cwd: dir,\n stdio: 'pipe',\n })\n log('Git repository initialized')\n } catch {\n log('Warning: git init failed (git may not be installed)')\n }\n }\n\n console.log('\\n Project scaffolded successfully!')\n console.log()\n\n const needsCd = dir !== process.cwd()\n log('Next steps:')\n if (needsCd) log(` cd ${name}`)\n if (!options.installDeps) log(` ${packageManager} install`)\n\n const genHint: Record<string, string> = {\n rest: 'kick g module user',\n graphql: 'kick g resolver user',\n ddd: 'kick g module user --repo drizzle',\n cqrs: 'kick g module user --pattern cqrs',\n minimal: '# add your routes to src/index.ts',\n }\n log(` ${genHint[template] ?? genHint.rest}`)\n log(' kick dev')\n log('')\n log('Commands:')\n log(' kick dev Start dev server with Vite HMR')\n log(' kick build Production build via Vite')\n log(' kick start Run production build')\n log('')\n log('Generators:')\n log(' kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)')\n log(' kick g scaffold <n> <f..> CRUD module from field definitions')\n log(' kick g controller <name> Standalone controller')\n log(' kick g service <name> @Service() class')\n log(' kick g middleware <name> Express middleware')\n log(' kick g guard <name> Route guard (auth, roles, etc.)')\n log(' kick g adapter <name> AppAdapter with lifecycle hooks')\n log(' kick g dto <name> Zod DTO schema')\n if (template === 'graphql') log(' kick g resolver <name> GraphQL resolver')\n if (template === 'cqrs') log(' kick g job <name> Queue job processor')\n log(' kick g config Generate kick.config.ts')\n log('')\n log('Add packages:')\n log(' kick add <pkg> Install a KickJS package + peers')\n log(' kick add --list Show all available packages')\n log('')\n log('Available: auth, swagger, graphql, drizzle, prisma, ws,')\n log(' cron, queue, mailer, otel, multi-tenant, notifications, testing')\n log('')\n}\n","import { readFile, access } from 'node:fs/promises'\nimport { join } from 'node:path'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Project pattern — controls what generators produce and which deps are installed */\nexport type ProjectPattern = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/** Built-in repository types with first-class code generation support */\nexport type BuiltinRepoType = 'drizzle' | 'inmemory' | 'prisma'\n\nexport const BUILTIN_REPO_TYPES: readonly string[] = ['drizzle', 'inmemory', 'prisma']\n\n/** Custom repository type — generates a stub with TODO markers */\nexport interface CustomRepoType {\n name: string\n}\n\n/** Repository type — built-in string or custom object */\nexport type RepoTypeConfig = BuiltinRepoType | CustomRepoType\n\n/**\n * Supported schema validators for `kick typegen` body/query/params\n * type extraction. Only `'zod'` ships built-in for now; other libraries\n * (Joi, Yup, JSON Schema) will be added later as the adapter system\n * grows. Set to `false` (or omit) to disable schema-driven body typing\n * entirely (the route entries will keep `body: unknown`).\n */\nexport type SchemaValidator = 'zod' | false\n\n/** Typegen settings — controls .kickjs/types/* generation */\nexport interface TypegenConfig {\n /**\n * Source directory to scan for controllers and decorators.\n * Defaults to `'src'`.\n */\n srcDir?: string\n /**\n * Output directory for generated `.d.ts` files.\n * Defaults to `'.kickjs/types'`.\n */\n outDir?: string\n /**\n * Schema validator used to derive `body` types from route metadata.\n *\n * - `'zod'` — emit `z.infer<typeof <importedSchema>>` for any schema\n * referenced as a named identifier in `@Get/@Post/...({ body, query, params })`.\n * - `false` — disable schema-driven body typing.\n *\n * Future: `'joi' | 'yup' | 'json-schema'` plus a `{ name; module }`\n * escape hatch for custom adapters.\n *\n * @default 'zod'\n */\n schemaValidator?: SchemaValidator\n /**\n * Path to the project's env schema file (relative to project root).\n * Must default-export a `defineEnv(...)` schema for typegen to emit\n * the typed `KickEnv` global registry.\n *\n * Set to `false` to disable env typing entirely.\n *\n * @default 'src/env.ts'\n */\n envFile?: string | false\n}\n\n/** Module generation settings — controls how `kick g module` produces code */\nexport interface ModuleConfig {\n /** Where modules live (default: 'src/modules') */\n dir?: string\n /**\n * Default repository implementation for generators.\n *\n * Built-in types (string): `'drizzle'`, `'inmemory'`, `'prisma'`\n * — generate fully working repository code.\n *\n * Custom types (object): `{ name: 'typeorm' }`\n * — generate a stub repository with TODO markers.\n *\n * @example\n * repo: 'prisma' // built-in\n * repo: { name: 'typeorm' } // custom\n */\n repo?: RepoTypeConfig\n /** Schema output directory (e.g. 'src/db/schema' for Drizzle, 'prisma/' for Prisma) */\n schemaDir?: string\n /**\n * Whether to pluralize module names in generated code.\n * When true (default), `kick g module user` creates `src/modules/users/`.\n * When false, it creates `src/modules/user/` and uses singular names throughout.\n */\n pluralize?: boolean\n /**\n * Import path for the Prisma generated client in `--repo prisma` templates.\n * Must resolve within `src/` for path alias compatibility.\n *\n * @default '@prisma/client' (Prisma 5/6)\n * @example\n * prismaClientPath: '@/generated/prisma/client' // Prisma 7+\n * prismaClientPath: './generated/prisma/client' // relative\n */\n prismaClientPath?: string\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /**\n * Project pattern — controls default generator behavior.\n * - 'rest' — Express + Swagger (default)\n * - 'graphql' — GraphQL + GraphiQL\n * - 'ddd' — Full DDD modules with use cases, entities, value objects\n * - 'cqrs' — CQRS with commands, queries, events, WebSocket + queue\n * - 'minimal' — Bare Express with no scaffolding\n */\n pattern?: ProjectPattern\n /**\n * Module generation settings — directory, repo type, pluralization, schema dir.\n *\n * @example\n * modules: {\n * dir: 'src/modules',\n * repo: 'prisma',\n * pluralize: false,\n * schemaDir: 'prisma/',\n * }\n */\n modules?: ModuleConfig\n\n // ── Backward-compatible top-level aliases (deprecated, use modules.* instead) ──\n /** @deprecated Use `modules.dir` instead */\n modulesDir?: string\n /** @deprecated Use `modules.repo` instead */\n defaultRepo?: RepoTypeConfig\n /** @deprecated Use `modules.schemaDir` instead */\n schemaDir?: string\n /** @deprecated Use `modules.pluralize` instead */\n pluralize?: boolean\n /**\n * Directories to copy to dist/ after build.\n * Useful for EJS templates, email templates, static assets, etc.\n *\n * @example\n * ```ts\n * copyDirs: [\n * 'src/views', // copies to dist/src/views\n * { src: 'src/views', dest: 'dist/views' }, // custom dest\n * 'src/emails',\n * ]\n * ```\n */\n copyDirs?: Array<string | { src: string; dest?: string }>\n /**\n * Typegen settings — controls `.kickjs/types/*` generation including\n * the schema validator used for body type extraction.\n *\n * @example\n * ```ts\n * typegen: {\n * schemaValidator: 'zod',\n * }\n * ```\n */\n typegen?: TypegenConfig\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\n/** Resolve module config with backward-compatible fallbacks from top-level fields */\nexport function resolveModuleConfig(config: KickConfig | null): ModuleConfig {\n if (!config) return {}\n const mc: ModuleConfig = {\n dir: config.modules?.dir ?? config.modulesDir,\n repo: config.modules?.repo ?? config.defaultRepo,\n schemaDir: config.modules?.schemaDir ?? config.schemaDir,\n pluralize: config.modules?.pluralize ?? config.pluralize,\n prismaClientPath: config.modules?.prismaClientPath,\n }\n\n // Warn if a string repo value isn't a known built-in\n if (mc.repo && typeof mc.repo === 'string' && !BUILTIN_REPO_TYPES.includes(mc.repo)) {\n console.warn(\n ` Warning: modules.repo '${mc.repo}' is not a built-in type (${BUILTIN_REPO_TYPES.join(', ')}).` +\n ` It will generate a stub repository. Use { name: '${mc.repo}' } to silence this warning.`,\n )\n }\n\n return mc\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n return mod.default ?? mod\n } catch (err) {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["colors","generateController","generateController","colors"],"sources":["../src/utils/fs.ts","../src/utils/colors.ts","../src/utils/prompts.ts","../src/utils/naming.ts","../src/generators/templates/module-index.ts","../src/generators/templates/controller.ts","../src/generators/templates/constants.ts","../src/generators/templates/dtos.ts","../src/generators/templates/use-cases.ts","../src/generators/templates/repository.ts","../src/generators/templates/domain.ts","../src/generators/templates/tests.ts","../src/generators/templates/rest-service.ts","../src/generators/templates/cqrs.ts","../src/generators/templates/drizzle/index.ts","../src/generators/templates/prisma/index.ts","../src/generators/templates/project-app.ts","../src/generators/patterns/minimal.ts","../src/generators/patterns/rest.ts","../src/generators/patterns/cqrs.ts","../src/generators/patterns/ddd.ts","../src/generators/module.ts","../src/generators/adapter.ts","../src/utils/resolve-out-dir.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/generators/templates/project-config.ts","../src/generators/templates/project-docs.ts","../src/generators/project.ts","../src/config.ts"],"sourcesContent":["import { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\nlet _dryRun = false\n\n/** Enable/disable dry run mode globally for all writeFileSafe calls */\nexport function setDryRun(enabled: boolean): void {\n _dryRun = enabled\n}\n\n/** Write a file, creating parent directories if needed. Skips writing in dry run mode. */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n if (_dryRun) return\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/** Read a JSON file */\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n const content = await readFile(filePath, 'utf-8')\n return JSON.parse(content)\n}\n","import pc from 'picocolors'\n\nexport { pc as colors }\n\nconst METHOD_COLOR_MAP: Record<string, (s: string) => string> = {\n GET: pc.green,\n POST: pc.cyan,\n PUT: pc.yellow,\n PATCH: pc.magenta,\n DELETE: pc.red,\n}\n\n/** Color an HTTP method string for terminal display */\nexport function httpMethodColor(method: string): string {\n const fn = METHOD_COLOR_MAP[method] ?? pc.dim\n return fn(method.padEnd(7))\n}\n\n/** Color a severity tag for terminal display (padded to 10 chars) */\nexport function severityColor(severity: string): string {\n const tag = `[${severity}]`.padEnd(10)\n switch (severity) {\n case 'CRITICAL':\n return pc.red(tag)\n case 'WARNING':\n return pc.yellow(tag)\n case 'INFO':\n return pc.blue(pc.dim(tag))\n default:\n return tag\n }\n}\n","import * as clack from '@clack/prompts'\nimport { colors } from './colors'\n\nexport const symbols = {\n success: colors.green('✓'),\n error: colors.red('✖'),\n warning: colors.yellow('⚠'),\n info: colors.blue('ℹ'),\n}\n\n/** Show branded intro banner */\nexport function intro(title: string): void {\n clack.intro(colors.bgCyan(colors.black(` ${title} `)))\n}\n\n/** Show closing message */\nexport function outro(message: string): void {\n clack.outro(message)\n}\n\n/** Handle cancellation — print message and exit */\nfunction handleCancel(value: unknown): void {\n if (clack.isCancel(value)) {\n clack.cancel('Operation cancelled.')\n process.exit(0)\n }\n}\n\n/** Text input prompt */\nexport async function text(opts: {\n message: string\n placeholder?: string\n defaultValue?: string\n validate?: (value: string) => string | void\n}): Promise<string> {\n const value = await clack.text(opts)\n handleCancel(value)\n return value as string\n}\n\n/** Single select prompt */\nexport async function select<T>(opts: {\n message: string\n options: { value: T; label: string; hint?: string }[]\n initialValue?: T\n}): Promise<T> {\n const value = await clack.select(opts)\n handleCancel(value)\n return value as T\n}\n\n/** Multi-select prompt with checkboxes */\nexport async function multiSelect<T>(opts: {\n message: string\n options: { value: T; label: string; hint?: string }[]\n required?: boolean\n initialValues?: T[]\n}): Promise<T[]> {\n const value = await clack.multiselect(opts)\n handleCancel(value)\n return value as T[]\n}\n\n/** Yes/no confirmation prompt */\nexport async function confirm(opts: {\n message: string\n active?: string\n inactive?: string\n initialValue?: boolean\n}): Promise<boolean> {\n const value = await clack.confirm(opts)\n handleCancel(value)\n return value as boolean\n}\n\n/** Create a spinner for progress indication */\nexport function spinner() {\n return clack.spinner()\n}\n\n/** Log utilities for styled messages inside clack flow */\nexport const log = clack.log\n","import pkg from 'pluralize'\n\n/** Convert a name to PascalCase */\nexport function toPascalCase(name: string): string {\n return name\n .replace(/[-_\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/** Convert a name to camelCase */\nexport function toCamelCase(name: string): string {\n const pascal = toPascalCase(name)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/** Convert a name to kebab-case */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Pluralize a kebab-case name for directory/file names.\n * Uses the `pluralize` npm package for correct English pluralization\n * including irregulars (person → people, status → statuses, child → children).\n */\nexport function pluralize(name: string): string {\n return pkg.plural(name)\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n return pkg.plural(name)\n}\n","import type { RepoType } from '../module'\nimport type { TemplateContext } from './types'\n\nconst repoLabelMap: Record<string, string> = {\n inmemory: 'in-memory',\n drizzle: 'Drizzle',\n prisma: 'Prisma',\n}\n\nfunction toPascalRepoType(repo: string): string {\n return (\n repo.charAt(0).toUpperCase() +\n repo.slice(1).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n )\n}\n\nfunction toKebabRepoType(repo: string): string {\n return repo.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n}\n\nfunction repoLabel(repo: RepoType): string {\n return repoLabelMap[repo] ?? toPascalRepoType(repo)\n}\n\nfunction repoMaps(pascal: string, kebab: string, repo: RepoType) {\n const repoClassMap: Record<string, string> = {\n inmemory: `InMemory${pascal}Repository`,\n drizzle: `Drizzle${pascal}Repository`,\n prisma: `Prisma${pascal}Repository`,\n }\n const repoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n return {\n repoClass: repoClassMap[repo] ?? `${toPascalRepoType(repo)}${pascal}Repository`,\n repoFile: repoFileMap[repo] ?? `${toKebabRepoType(repo)}-${kebab}`,\n }\n}\n\n/** DDD module index — nested folders, use-cases, domain services */\nexport function generateModuleIndex(ctx: TemplateContext & { repo: RepoType }): string {\n const { pascal, kebab, plural = '', repo } = ctx\n const { repoClass, repoFile } = repoMaps(pascal, kebab, repo)\n\n return `/**\n * ${pascal} Module\n *\n * Self-contained feature module following Domain-Driven Design (DDD).\n * Registers dependencies in the DI container and declares HTTP routes.\n *\n * Structure:\n * presentation/ — HTTP controllers (entry points)\n * application/ — Use cases (orchestration) and DTOs (validation)\n * domain/ — Entities, value objects, repository interfaces, domain services\n * infrastructure/ — Repository implementations (currently ${repoLabel(repo)})\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repoClass} } from './infrastructure/repositories/${repoFile}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(\n ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n /**\n * Register module dependencies in the DI container.\n * Bind repository interface tokens to their implementations here.\n * Currently wired to ${repoLabel(repo)}. To swap implementations, change the factory target.\n */\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repoClass}),\n )\n }\n\n /**\n * Declare HTTP routes for this module.\n * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${plural}).\n * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.\n */\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n\n/** REST module index — flat folder, service + controller, no use-cases */\nexport function generateRestModuleIndex(ctx: TemplateContext & { repo: RepoType }): string {\n const { pascal, kebab, plural = '', repo } = ctx\n const { repoClass, repoFile } = repoMaps(pascal, kebab, repo)\n\n return `/**\n * ${pascal} Module\n *\n * REST module with a flat folder structure.\n * Controller delegates to service, service wraps the repository.\n *\n * Structure:\n * ${kebab}.controller.ts — HTTP routes (CRUD)\n * ${kebab}.service.ts — Business logic\n * ${kebab}.repository.ts — Repository interface\n * ${repoFile}.repository.ts — Repository implementation\n * dtos/ — Request/response schemas\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './${kebab}.repository'\nimport { ${repoClass} } from './${repoFile}.repository'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(['./**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'], { eager: true })\n\nexport class ${pascal}Module implements AppModule {\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repoClass}),\n )\n }\n\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n\n/** Minimal module index — just controller, no service/repo */\nexport function generateMinimalModuleIndex(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '' } = ctx\n return `import { type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\nexport class ${pascal}Module implements AppModule {\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\n/** DDD controller — injects use-cases, nested import paths */\nexport function generateController(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\nimport { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'\nimport { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'\nimport { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'\nimport { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}.use-case'\nimport { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'\nimport { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from '../constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private readonly create${pascal}UseCase!: Create${pascal}UseCase\n @Autowired() private readonly get${pascal}UseCase!: Get${pascal}UseCase\n @Autowired() private readonly list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n @Autowired() private readonly update${pascal}UseCase!: Update${pascal}UseCase\n @Autowired() private readonly delete${pascal}UseCase!: Delete${pascal}UseCase\n\n @Get('/')\n @ApiTags('${pascal}')\n @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n return ctx.paginate(\n (parsed) => this.list${pluralPascal}UseCase.execute(parsed),\n ${pascal.toUpperCase()}_QUERY_CONFIG,\n )\n }\n\n @Get('/:id')\n @ApiTags('${pascal}')\n async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\n const result = await this.get${pascal}UseCase.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n @ApiTags('${pascal}')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n const result = await this.create${pascal}UseCase.execute(ctx.body)\n ctx.created(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n @ApiTags('${pascal}')\n async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n @ApiTags('${pascal}')\n async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n await this.delete${pascal}UseCase.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`\n}\n\n/** REST controller — injects service directly, flat import paths */\nexport function generateRestController(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n const camel = pascal.charAt(0).toLowerCase() + pascal.slice(1)\n return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\nimport { ${pascal}Service } from './${kebab}.service'\nimport { create${pascal}Schema } from './dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from './dtos/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from './${kebab}.constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private readonly ${camel}Service!: ${pascal}Service\n\n @Get('/')\n @ApiTags('${pascal}')\n @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n return ctx.paginate(\n (parsed) => this.${camel}Service.findPaginated(parsed),\n ${pascal.toUpperCase()}_QUERY_CONFIG,\n )\n }\n\n @Get('/:id')\n @ApiTags('${pascal}')\n async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\n const result = await this.${camel}Service.findById(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n @ApiTags('${pascal}')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n const result = await this.${camel}Service.create(ctx.body)\n ctx.created(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n @ApiTags('${pascal}')\n async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n const result = await this.${camel}Service.update(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n @ApiTags('${pascal}')\n async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n await this.${camel}Service.delete(ctx.params.id)\n ctx.noContent()\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateConstants(ctx: TemplateContext): string {\n const { pascal } = ctx\n return `import type { QueryParamsConfig } from '@forinda/kickjs'\n\nexport const ${pascal.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {\n filterable: ['name'],\n sortable: ['name', 'createdAt'],\n searchable: ['name'],\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateCreateDTO(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import { z } from 'zod'\n\n/**\n * Create ${pascal} DTO — Zod schema for validating POST request bodies.\n * This schema is passed to @Post('/', { body: create${pascal}Schema }) for automatic validation.\n * It also generates OpenAPI request body docs when SwaggerAdapter is used.\n *\n * Add more fields as needed. Supported Zod types:\n * z.string(), z.number(), z.boolean(), z.enum([...]),\n * z.array(), z.object(), .optional(), .default(), .transform()\n */\nexport const create${pascal}Schema = z.object({\n name: z.string().min(1, 'Name is required').max(200),\n})\n\nexport type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>\n`\n}\n\nexport function generateUpdateDTO(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import { z } from 'zod'\n\nexport const update${pascal}Schema = z.object({\n name: z.string().min(1).max(200).optional(),\n})\n\nexport type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>\n`\n}\n\nexport function generateResponseDTO(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `export interface ${pascal}ResponseDTO {\n id: string\n name: string\n createdAt: string\n updatedAt: string\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateUseCases(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return [\n {\n file: `create-${kebab}.use-case.ts`,\n content: `/**\n * Create ${pascal} Use Case\n *\n * Application layer — orchestrates a single business operation.\n * Use cases are thin: validate input (via DTO), call domain/repo, return response.\n * Keep business rules in the domain service, not here.\n */\nimport { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n}\n`,\n },\n {\n file: `get-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ParsedQuery } from '@forinda/kickjs'\n\n@Service()\nexport class List${pluralPascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(parsed: ParsedQuery) {\n return this.repo.findPaginated(parsed)\n }\n}\n`,\n },\n {\n file: `update-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Update${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\n\n@Service()\nexport class Delete${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`,\n },\n ]\n}\n","import type { TemplateContext } from './types'\n\nexport function generateRepositoryInterface(ctx: TemplateContext): string {\n const { pascal, kebab, dtoPrefix = '../../application/dtos' } = ctx\n return `/**\n * ${pascal} Repository Interface\n *\n * Defines the contract for data access.\n * The interface declares what operations are available;\n * implementations (in-memory, Drizzle, Prisma) fulfill the contract.\n *\n * To swap implementations, change the factory in the module's register() method.\n */\nimport { createToken } from '@forinda/kickjs'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\nimport type { ParsedQuery } from '@forinda/kickjs'\n\nexport interface I${pascal}Repository {\n findById(id: string): Promise<${pascal}ResponseDTO | null>\n findAll(): Promise<${pascal}ResponseDTO[]>\n findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }>\n create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>\n update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>\n delete(id: string): Promise<void>\n}\n\n/**\n * Collision-safe DI token bound to \\`I${pascal}Repository\\`.\n * \\`container.resolve(${pascal.toUpperCase()}_REPOSITORY)\\` and\n * \\`@Inject(${pascal.toUpperCase()}_REPOSITORY)\\` both return the typed\n * interface — no manual generic, no \\`any\\` cast.\n */\nexport const ${pascal.toUpperCase()}_REPOSITORY = createToken<I${pascal}Repository>('${pascal}/Repository')\n`\n}\n\nexport function generateInMemoryRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n return `/**\n * In-Memory ${pascal} Repository\n *\n * Implements the repository interface using a Map.\n * Useful for prototyping and testing. Replace with a database implementation\n * (Drizzle, Prisma, etc.) for production use.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\n\n@Repository()\nexport class InMemory${pascal}Repository implements I${pascal}Repository {\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return Array.from(this.store.values())\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n const all = Array.from(this.store.values())\n const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)\n return { data, total: all.length }\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`\n}\n\nexport function generateCustomRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoType = '',\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n const repoTypePascal =\n repoType.charAt(0).toUpperCase() +\n repoType.slice(1).replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())\n return `/**\n * ${repoTypePascal} ${pascal} Repository\n *\n * Stub implementation for a custom '${repoType}' repository.\n * Implements the repository interface using an in-memory Map as a placeholder.\n *\n * TODO: Replace the in-memory Map with your ${repoType} data-access logic.\n * See I${pascal}Repository for the interface contract.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\n\n@Repository()\nexport class ${repoTypePascal}${pascal}Repository implements I${pascal}Repository {\n // TODO: Replace with your ${repoType} client/connection\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n // TODO: Implement with ${repoType}\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n // TODO: Implement with ${repoType}\n return Array.from(this.store.values())\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n // TODO: Implement with ${repoType}\n const all = Array.from(this.store.values())\n const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)\n return { data, total: all.length }\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with ${repoType}\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with ${repoType}\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n // TODO: Implement with ${repoType}\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateDomainService(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `/**\n * ${pascal} Domain Service\n *\n * Domain layer — contains business rules that don't belong to a single entity.\n * Use this for cross-entity logic, validation rules, and domain invariants.\n * Keep it free of HTTP/framework concerns.\n */\nimport { Service, Inject, HttpException } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'\n\n@Service()\nexport class ${pascal}DomainService {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async ensureExists(id: string): Promise<void> {\n const entity = await this.repo.findById(id)\n if (!entity) {\n throw HttpException.notFound('${pascal} not found')\n }\n }\n}\n`\n}\n\nexport function generateEntity(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `/**\n * ${pascal} Entity\n *\n * Domain layer — the core business object.\n * Uses a private constructor with static factory methods (create, reconstitute)\n * to enforce invariants. Properties are accessed via getters to maintain encapsulation.\n *\n * Patterns used:\n * - Private constructor: prevents direct instantiation\n * - create(): factory for new entities (generates ID, sets timestamps)\n * - reconstitute(): factory for rebuilding from persistence (no side effects)\n * - changeName(): mutation method that enforces business rules\n */\nimport { ${pascal}Id } from '../value-objects/${kebab}-id.vo'\n\ninterface ${pascal}Props {\n id: ${pascal}Id\n name: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport class ${pascal} {\n private constructor(private props: ${pascal}Props) {}\n\n static create(params: { name: string }): ${pascal} {\n const now = new Date()\n return new ${pascal}({\n id: ${pascal}Id.create(),\n name: params.name,\n createdAt: now,\n updatedAt: now,\n })\n }\n\n static reconstitute(props: ${pascal}Props): ${pascal} {\n return new ${pascal}(props)\n }\n\n get id(): ${pascal}Id {\n return this.props.id\n }\n get name(): string {\n return this.props.name\n }\n get createdAt(): Date {\n return this.props.createdAt\n }\n get updatedAt(): Date {\n return this.props.updatedAt\n }\n\n changeName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Name cannot be empty')\n }\n this.props.name = name.trim()\n this.props.updatedAt = new Date()\n }\n\n toJSON() {\n return {\n id: this.props.id.toString(),\n name: this.props.name,\n createdAt: this.props.createdAt.toISOString(),\n updatedAt: this.props.updatedAt.toISOString(),\n }\n }\n}\n`\n}\n\nexport function generateValueObject(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `/**\n * ${pascal} ID Value Object\n *\n * Domain layer — wraps a primitive ID with type safety and validation.\n * Value objects are immutable and compared by value, not reference.\n *\n * ${pascal}Id.create() — generate a new UUID\n * ${pascal}Id.from(id) — wrap an existing ID string (validates non-empty)\n * id.equals(other) — compare two IDs by value\n */\nimport { randomUUID } from 'node:crypto'\n\nexport class ${pascal}Id {\n private constructor(private readonly value: string) {}\n\n static create(): ${pascal}Id {\n return new ${pascal}Id(randomUUID())\n }\n\n static from(id: string): ${pascal}Id {\n if (!id || id.trim().length === 0) {\n throw new Error('${pascal}Id cannot be empty')\n }\n return new ${pascal}Id(id)\n }\n\n toString(): string {\n return this.value\n }\n\n equals(other: ${pascal}Id): boolean {\n return this.value === other.value\n }\n}\n`\n}\n","import type { TemplateContext } from './types'\n\nexport function generateControllerTest(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '' } = ctx\n return `import { describe, it, expect, beforeEach } from 'vitest'\nimport { Container } from '@forinda/kickjs'\n\ndescribe('${pascal}Controller', () => {\n beforeEach(() => {\n Container.reset()\n })\n\n it('should be defined', () => {\n expect(true).toBe(true)\n })\n\n describe('POST /${plural}', () => {\n it('should create a new ${kebab}', async () => {\n // TODO: Set up test module, call create endpoint, assert 201\n expect(true).toBe(true)\n })\n })\n\n describe('GET /${plural}', () => {\n it('should return paginated ${plural}', async () => {\n // TODO: Set up test module, call list endpoint, assert { data, meta }\n expect(true).toBe(true)\n })\n })\n\n describe('GET /${plural}/:id', () => {\n it('should return a ${kebab} by id', async () => {\n // TODO: Create a ${kebab}, then fetch by id, assert match\n expect(true).toBe(true)\n })\n\n it('should return 404 for non-existent ${kebab}', async () => {\n // TODO: Fetch non-existent id, assert 404\n expect(true).toBe(true)\n })\n })\n\n describe('PUT /${plural}/:id', () => {\n it('should update an existing ${kebab}', async () => {\n // TODO: Create, update, assert changes\n expect(true).toBe(true)\n })\n })\n\n describe('DELETE /${plural}/:id', () => {\n it('should delete a ${kebab}', async () => {\n // TODO: Create, delete, assert gone\n expect(true).toBe(true)\n })\n })\n})\n`\n}\n\nexport function generateRepositoryTest(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n plural = '',\n repoPrefix = `../infrastructure/repositories/in-memory-${kebab}.repository`,\n } = ctx\n return `import { describe, it, expect, beforeEach } from 'vitest'\nimport { InMemory${pascal}Repository } from '${repoPrefix}'\n\ndescribe('InMemory${pascal}Repository', () => {\n let repo: InMemory${pascal}Repository\n\n beforeEach(() => {\n repo = new InMemory${pascal}Repository()\n })\n\n it('should create and retrieve a ${kebab}', async () => {\n const created = await repo.create({ name: 'Test ${pascal}' })\n expect(created).toBeDefined()\n expect(created.name).toBe('Test ${pascal}')\n expect(created.id).toBeDefined()\n\n const found = await repo.findById(created.id)\n expect(found).toEqual(created)\n })\n\n it('should return null for non-existent id', async () => {\n const found = await repo.findById('non-existent')\n expect(found).toBeNull()\n })\n\n it('should list all ${plural}', async () => {\n await repo.create({ name: '${pascal} 1' })\n await repo.create({ name: '${pascal} 2' })\n\n const all = await repo.findAll()\n expect(all).toHaveLength(2)\n })\n\n it('should return paginated results', async () => {\n await repo.create({ name: '${pascal} 1' })\n await repo.create({ name: '${pascal} 2' })\n await repo.create({ name: '${pascal} 3' })\n\n const result = await repo.findPaginated({\n filters: [],\n sort: [],\n search: '',\n pagination: { page: 1, limit: 2, offset: 0 },\n })\n\n expect(result.data).toHaveLength(2)\n expect(result.total).toBe(3)\n })\n\n it('should update a ${kebab}', async () => {\n const created = await repo.create({ name: 'Original' })\n const updated = await repo.update(created.id, { name: 'Updated' })\n expect(updated.name).toBe('Updated')\n })\n\n it('should delete a ${kebab}', async () => {\n const created = await repo.create({ name: 'To Delete' })\n await repo.delete(created.id)\n const found = await repo.findById(created.id)\n expect(found).toBeNull()\n })\n})\n`\n}\n","import type { TemplateContext } from './types'\n\n/** REST service — wraps repository with CRUD methods, replaces use-cases for flat pattern */\nexport function generateRestService(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import { Service, Inject, HttpException } from '@forinda/kickjs'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from './${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from './dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from './dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from './dtos/update-${kebab}.dto'\n\n@Service()\nexport class ${pascal}Service {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return this.repo.findAll()\n }\n\n async findPaginated(parsed: ParsedQuery) {\n return this.repo.findPaginated(parsed)\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n\n async delete(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`\n}\n\n/** REST constants — query config for flat pattern */\nexport function generateRestConstants(ctx: TemplateContext): string {\n const { pascal } = ctx\n return `import type { QueryFieldConfig } from '@forinda/kickjs'\n\nexport const ${pascal.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {\n filterable: ['name'],\n sortable: ['name', 'createdAt'],\n searchable: ['name'],\n}\n`\n}\n","import type { TemplateContext } from './types'\n\n/** CQRS module index — commands, queries, events, WebSocket + queue integration */\nexport function generateCqrsModuleIndex(ctx: TemplateContext & { repo: string }): string {\n const { pascal, kebab, plural = '', repo } = ctx\n const repoClassMap: Record<string, string> = {\n inmemory: `InMemory${pascal}Repository`,\n drizzle: `Drizzle${pascal}Repository`,\n prisma: `Prisma${pascal}Repository`,\n }\n const repoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const repoClass = repoClassMap[repo] ?? repoClassMap.inmemory\n const repoFile = repoFileMap[repo] ?? repoFileMap.inmemory\n\n return `/**\n * ${pascal} Module — CQRS Pattern\n *\n * Separates read (queries) and write (commands) operations.\n * Events are emitted after state changes and can be handled via\n * WebSocket broadcasts, queue jobs, or ETL pipelines.\n *\n * Structure:\n * commands/ — Write operations (create, update, delete)\n * queries/ — Read operations (get, list)\n * events/ — Domain events + handlers (WS broadcast, queue dispatch)\n * dtos/ — Request/response schemas\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'\nimport { buildRoutes } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './${kebab}.repository'\nimport { ${repoClass} } from './${repoFile}.repository'\nimport { ${pascal}Controller } from './${kebab}.controller'\n\n// Eagerly load decorated classes\nimport.meta.glob(\n [\n './commands/**/*.ts',\n './queries/**/*.ts',\n './events/**/*.ts',\n '!./**/*.test.ts',\n ],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repoClass}),\n )\n }\n\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`\n}\n\n/** CQRS controller — dispatches to command/query handlers */\nexport function generateCqrsController(ctx: TemplateContext): string {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'\nimport { ApiTags } from '@forinda/kickjs-swagger'\nimport { Create${pascal}Command } from './commands/create-${kebab}.command'\nimport { Update${pascal}Command } from './commands/update-${kebab}.command'\nimport { Delete${pascal}Command } from './commands/delete-${kebab}.command'\nimport { Get${pascal}Query } from './queries/get-${kebab}.query'\nimport { List${pluralPascal}Query } from './queries/list-${plural}.query'\nimport { create${pascal}Schema } from './dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from './dtos/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from './${kebab}.constants'\n\n// Each handler annotates its \\`ctx\\` with \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\`\n// so \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` are typed end-to-end.\n// The \\`KickRoutes\\` namespace is generated by \\`kick typegen\\` (auto-run on\n// \\`kick dev\\`) — see https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private readonly create${pascal}Command!: Create${pascal}Command\n @Autowired() private readonly update${pascal}Command!: Update${pascal}Command\n @Autowired() private readonly delete${pascal}Command!: Delete${pascal}Command\n @Autowired() private readonly get${pascal}Query!: Get${pascal}Query\n @Autowired() private readonly list${pluralPascal}Query!: List${pluralPascal}Query\n\n @Get('/')\n @ApiTags('${pascal}')\n @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n return ctx.paginate(\n (parsed) => this.list${pluralPascal}Query.execute(parsed),\n ${pascal.toUpperCase()}_QUERY_CONFIG,\n )\n }\n\n @Get('/:id')\n @ApiTags('${pascal}')\n async getById(ctx: Ctx<KickRoutes.${pascal}Controller['getById']>) {\n const result = await this.get${pascal}Query.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })\n @ApiTags('${pascal}')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n const result = await this.create${pascal}Command.execute(ctx.body)\n ctx.created(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })\n @ApiTags('${pascal}')\n async update(ctx: Ctx<KickRoutes.${pascal}Controller['update']>) {\n const result = await this.update${pascal}Command.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n @ApiTags('${pascal}')\n async remove(ctx: Ctx<KickRoutes.${pascal}Controller['remove']>) {\n await this.delete${pascal}Command.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`\n}\n\n/** CQRS commands — write operations that emit events */\nexport function generateCqrsCommands(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab } = ctx\n return [\n {\n file: `create-${kebab}.command.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\nimport { ${pascal}Events } from '../events/${kebab}.events'\n\n@Service()\nexport class Create${pascal}Command {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n @Inject(${pascal}Events) private readonly events: ${pascal}Events,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const result = await this.repo.create(dto)\n this.events.emit('${kebab}.created', result)\n return result\n }\n}\n`,\n },\n {\n file: `update-${kebab}.command.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\nimport { ${pascal}Events } from '../events/${kebab}.events'\n\n@Service()\nexport class Update${pascal}Command {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n @Inject(${pascal}Events) private readonly events: ${pascal}Events,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const result = await this.repo.update(id, dto)\n this.events.emit('${kebab}.updated', result)\n return result\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.command.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport { ${pascal}Events } from '../events/${kebab}.events'\n\n@Service()\nexport class Delete${pascal}Command {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n @Inject(${pascal}Events) private readonly events: ${pascal}Events,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n this.events.emit('${kebab}.deleted', { id })\n }\n}\n`,\n },\n ]\n}\n\n/** CQRS queries — read operations */\nexport function generateCqrsQueries(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab, plural = '', pluralPascal = '' } = ctx\n return [\n {\n file: `get-${kebab}.query.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}Query {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.query.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../${kebab}.repository'\nimport type { ParsedQuery } from '@forinda/kickjs'\n\n@Service()\nexport class List${pluralPascal}Query {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(parsed: ParsedQuery) {\n return this.repo.findPaginated(parsed)\n }\n}\n`,\n },\n ]\n}\n\n/** CQRS events — domain event emitter + handler with WS/queue integration */\nexport function generateCqrsEvents(ctx: TemplateContext): { file: string; content: string }[] {\n const { pascal, kebab } = ctx\n return [\n {\n file: `${kebab}.events.ts`,\n content: `import { Service } from '@forinda/kickjs'\nimport { EventEmitter } from 'node:events'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n/**\n * ${pascal} domain event types.\n *\n * These events are emitted by commands after state changes.\n * Subscribe to them in event handlers for side effects:\n * - WebSocket broadcasts (real-time UI updates)\n * - Queue jobs (async processing, ETL pipelines)\n * - Audit logging\n * - Cache invalidation\n */\nexport interface ${pascal}EventMap {\n '${kebab}.created': ${pascal}ResponseDTO\n '${kebab}.updated': ${pascal}ResponseDTO\n '${kebab}.deleted': { id: string }\n}\n\n@Service()\nexport class ${pascal}Events {\n private emitter = new EventEmitter()\n\n emit<K extends keyof ${pascal}EventMap>(event: K, data: ${pascal}EventMap[K]): void {\n this.emitter.emit(event, data)\n }\n\n on<K extends keyof ${pascal}EventMap>(event: K, handler: (data: ${pascal}EventMap[K]) => void): void {\n this.emitter.on(event, handler)\n }\n\n off<K extends keyof ${pascal}EventMap>(event: K, handler: (data: ${pascal}EventMap[K]) => void): void {\n this.emitter.off(event, handler)\n }\n}\n`,\n },\n {\n file: `on-${kebab}-change.handler.ts`,\n content: `import { Service, Autowired } from '@forinda/kickjs'\nimport { ${pascal}Events } from './${kebab}.events'\n\n/**\n * ${pascal} Change Event Handler\n *\n * Reacts to domain events emitted by commands.\n * Wire up side effects here:\n *\n * 1. WebSocket broadcast — notify connected clients in real-time\n * import { WsGateway } from '@forinda/kickjs-ws'\n * this.ws.broadcast('${kebab}-channel', { event, data })\n *\n * 2. Queue dispatch — offload heavy processing to background workers\n * import { QueueService } from '@forinda/kickjs-queue'\n * this.queue.add('${kebab}-etl', { action: event, payload: data })\n *\n * 3. ETL pipeline — transform and load data to external systems\n * await this.etlPipeline.process(data)\n */\n@Service()\nexport class On${pascal}ChangeHandler {\n @Autowired() private events!: ${pascal}Events\n\n // Uncomment to inject WebSocket and Queue services:\n // @Autowired() private ws!: WsGateway\n // @Autowired() private queue!: QueueService\n\n onInit(): void {\n this.events.on('${kebab}.created', (data) => {\n console.log('[${pascal}] Created:', data.id)\n // TODO: Broadcast via WebSocket\n // this.ws.broadcast('${kebab}-channel', { event: '${kebab}.created', data })\n // TODO: Dispatch to queue for async processing / ETL\n // this.queue.add('${kebab}-etl', { action: 'create', payload: data })\n })\n\n this.events.on('${kebab}.updated', (data) => {\n console.log('[${pascal}] Updated:', data.id)\n // TODO: Broadcast via WebSocket\n // this.ws.broadcast('${kebab}-channel', { event: '${kebab}.updated', data })\n })\n\n this.events.on('${kebab}.deleted', (data) => {\n console.log('[${pascal}] Deleted:', data.id)\n // TODO: Broadcast via WebSocket\n // this.ws.broadcast('${kebab}-channel', { event: '${kebab}.deleted', data })\n })\n }\n}\n`,\n },\n ]\n}\n","import type { TemplateContext } from '../types'\n\nexport function generateDrizzleRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n return `/**\n * Drizzle ${pascal} Repository\n *\n * Implements the repository interface using Drizzle ORM.\n * Uses buildFromColumns() with Column objects for type-safe query building.\n *\n * TODO: Update the schema import to match your Drizzle schema file.\n * TODO: Replace DRIZZLE_DB injection token with your actual database token.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc, count, sql } from 'drizzle-orm'\nimport { Repository, HttpException, Inject } from '@forinda/kickjs'\nimport { DRIZZLE_DB, DrizzleQueryAdapter } from '@forinda/kickjs-drizzle'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\nimport { ${pascal.toUpperCase()}_QUERY_CONFIG } from '../../constants'\n\n// TODO: Import your Drizzle schema table — e.g.:\n// import { ${kebab}s } from '@/db/schema'\n\nconst queryAdapter = new DrizzleQueryAdapter({\n eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc,\n})\n\n@Repository()\nexport class Drizzle${pascal}Repository implements I${pascal}Repository {\n constructor(@Inject(DRIZZLE_DB) private db: any) {}\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n // TODO: Implement with Drizzle\n // const row = this.db.select().from(${kebab}s).where(eq(${kebab}s.id, id)).get()\n // return row ?? null\n throw new Error('Drizzle ${pascal} repository not yet implemented — update schema imports and queries')\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n // TODO: Implement with Drizzle\n // return this.db.select().from(${kebab}s).all()\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n // TODO: Use buildFromColumns() with your query config for type-safe filtering\n // const query = queryAdapter.buildFromColumns(parsed, ${pascal.toUpperCase()}_QUERY_CONFIG)\n //\n // const data = this.db\n // .select().from(${kebab}s).$dynamic()\n // .where(query.where).orderBy(...query.orderBy)\n // .limit(query.limit).offset(query.offset).all()\n //\n // const totalResult = this.db\n // .select({ count: count() }).from(${kebab}s)\n // .$dynamic().where(query.where).get()\n //\n // return { data, total: totalResult?.count ?? 0 }\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with Drizzle\n // return this.db.insert(${kebab}s).values(dto).returning().get()\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n // TODO: Implement with Drizzle\n // const row = this.db.update(${kebab}s).set(dto).where(eq(${kebab}s.id, id)).returning().get()\n // if (!row) throw HttpException.notFound('${pascal} not found')\n // return row\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n\n async delete(id: string): Promise<void> {\n // TODO: Implement with Drizzle\n // this.db.delete(${kebab}s).where(eq(${kebab}s.id, id)).run()\n throw new Error('Drizzle ${pascal} repository not yet implemented')\n }\n}\n`\n}\n\nexport function generateDrizzleConstants(ctx: TemplateContext): string {\n const { pascal, kebab } = ctx\n return `import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'\n// TODO: Import your schema table and reference actual columns for type safety\n// import { ${kebab}s } from '@/db/schema'\n\nexport const ${pascal.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {\n columns: {\n // Replace with actual Drizzle Column references for type-safe filtering:\n // name: ${kebab}s.name,\n // status: ${kebab}s.status,\n },\n sortable: {\n // name: ${kebab}s.name,\n // createdAt: ${kebab}s.createdAt,\n },\n searchColumns: [\n // ${kebab}s.name,\n ],\n}\n`\n}\n","import type { TemplateContext } from '../types'\n\nexport function generatePrismaRepository(ctx: TemplateContext): string {\n const {\n pascal,\n kebab,\n repoPrefix = '../../domain/repositories',\n dtoPrefix = '../../application/dtos',\n } = ctx\n const camel = kebab.replace(/-([a-z])/g, (_, c) => c.toUpperCase())\n return `/**\n * Prisma ${pascal} Repository\n *\n * Implements the repository interface using Prisma Client.\n * Requires a PrismaClient instance injected via the DI container.\n *\n * Ensure your Prisma schema has a '${pascal}' model defined.\n *\n * For full Prisma field-level type safety, replace PrismaModelDelegate with your PrismaClient:\n * @Inject(PRISMA_CLIENT) private prisma!: PrismaClient\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { Repository, HttpException, Inject } from '@forinda/kickjs'\nimport { PRISMA_CLIENT, type PrismaModelDelegate } from '@forinda/kickjs-prisma'\nimport type { ParsedQuery } from '@forinda/kickjs'\nimport type { I${pascal}Repository } from '${repoPrefix}/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '${dtoPrefix}/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '${dtoPrefix}/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '${dtoPrefix}/update-${kebab}.dto'\n\n@Repository()\nexport class Prisma${pascal}Repository implements I${pascal}Repository {\n @Inject(PRISMA_CLIENT) private prisma!: { ${camel}: PrismaModelDelegate }\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.prisma.${camel}.findUnique({ where: { id } }) as Promise<${pascal}ResponseDTO | null>\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return this.prisma.${camel}.findMany() as Promise<${pascal}ResponseDTO[]>\n }\n\n async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {\n const [data, total] = await Promise.all([\n this.prisma.${camel}.findMany({\n skip: parsed.pagination.offset,\n take: parsed.pagination.limit,\n }) as Promise<${pascal}ResponseDTO[]>,\n this.prisma.${camel}.count(),\n ])\n return { data, total }\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.prisma.${camel}.create({ data: dto as Record<string, unknown> }) as Promise<${pascal}ResponseDTO>\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = await this.prisma.${camel}.findUnique({ where: { id } })\n if (!existing) throw HttpException.notFound('${pascal} not found')\n return this.prisma.${camel}.update({ where: { id }, data: dto as Record<string, unknown> }) as Promise<${pascal}ResponseDTO>\n }\n\n async delete(id: string): Promise<void> {\n await this.prisma.${camel}.deleteMany({ where: { id } })\n }\n}\n`\n}\n","type ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/**\n * Generate src/index.ts entry file with template-specific bootstrap.\n *\n * All templates export the app for the Vite plugin (dev mode).\n * In production, bootstrap() auto-starts the HTTP server when\n * `globalThis.__kickjs_httpServer` is not set.\n */\nexport function generateEntryFile(\n name: string,\n template: ProjectTemplate,\n version: string,\n packages: string[] = [],\n): string {\n switch (template) {\n case 'graphql': {\n // GraphQL adapter is always included (it's the template); others only if selected\n const gqlImports: string[] = []\n const gqlAdapters: string[] = []\n\n if (packages.includes('devtools')) {\n gqlImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n gqlAdapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('otel')) {\n gqlImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n gqlAdapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n if (packages.includes('swagger')) {\n gqlImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n gqlAdapters.push(\n ` new SwaggerAdapter({ info: { title: '${name}', version: '${version}' } }),`,\n )\n }\n\n const gqlImportsBlock = gqlImports.length ? gqlImports.join('\\n') + '\\n' : ''\n const gqlAdaptersBlock = gqlAdapters.length ? gqlAdapters.join('\\n') + '\\n' : ''\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport { bootstrap } from '@forinda/kickjs'\nimport { GraphQLAdapter } from '@forinda/kickjs-graphql'\n${gqlImportsBlock}import { modules } from './modules'\n\n// Import your resolvers here\n// import { UserResolver } from './resolvers/user.resolver'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({\n modules,\n adapters: [\n${gqlAdaptersBlock} new GraphQLAdapter({\n resolvers: [/* UserResolver */],\n // Add custom type definitions here:\n // typeDefs: userTypeDefs,\n }),\n ],\n})\n`\n }\n\n case 'cqrs': {\n // Build adapters based on user-selected packages\n const cqrsImports: string[] = []\n const cqrsAdapters: string[] = []\n\n if (packages.includes('otel')) {\n cqrsImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n cqrsAdapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n if (packages.includes('devtools')) {\n cqrsImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n cqrsAdapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('swagger')) {\n cqrsImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n cqrsAdapters.push(\n ` new SwaggerAdapter({\\n info: { title: '${name}', version: '${version}' },\\n }),`,\n )\n }\n if (packages.includes('graphql')) {\n cqrsImports.push(`import { GraphQLAdapter } from '@forinda/kickjs-graphql'`)\n cqrsAdapters.push(` new GraphQLAdapter({ resolvers: [] }),`)\n }\n\n const cqrsImportsBlock = cqrsImports.length ? cqrsImports.join('\\n') + '\\n' : ''\n const cqrsAdaptersBlock = cqrsImports.length\n ? `\\n adapters: [\\n${cqrsAdapters.join('\\n')}\\n // Uncomment for WebSocket support:\\n // new WsAdapter(),\\n // Uncomment when Redis is available:\\n // new QueueAdapter({\\n // provider: new BullMQProvider({ host: 'localhost', port: 6379 }),\\n // }),\\n ],`\n : `\\n adapters: [\\n // Uncomment for WebSocket support:\\n // new WsAdapter(),\\n // Uncomment when Redis is available:\\n // new QueueAdapter({\\n // provider: new BullMQProvider({ host: 'localhost', port: 6379 }),\\n // }),\\n ],`\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport { bootstrap } from '@forinda/kickjs'\n// import { WsAdapter } from '@forinda/kickjs-ws'\n// import { QueueAdapter, BullMQProvider } from '@forinda/kickjs-queue'\n${cqrsImportsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({\n modules,${cqrsAdaptersBlock}\n})\n`\n }\n\n case 'minimal': {\n const imports: string[] = []\n const adapters: string[] = []\n\n if (packages.includes('swagger')) {\n imports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n adapters.push(\n ` new SwaggerAdapter({ info: { title: '${name}', version: '${version}' } }),`,\n )\n }\n if (packages.includes('devtools')) {\n imports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n adapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('otel')) {\n imports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n adapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n if (packages.includes('graphql')) {\n imports.push(`import { GraphQLAdapter } from '@forinda/kickjs-graphql'`)\n adapters.push(` new GraphQLAdapter({ resolvers: [] }),`)\n }\n\n const importsBlock = imports.length ? imports.join('\\n') + '\\n' : ''\n const adaptersBlock = adapters.length ? `,\\n adapters: [\\n${adapters.join('\\n')}\\n ]` : ''\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport { bootstrap } from '@forinda/kickjs'\n${importsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({ modules${adaptersBlock} })\n`\n }\n\n case 'ddd':\n case 'rest':\n default: {\n // Build adapters based on user-selected packages\n const restImports: string[] = []\n const restAdapters: string[] = []\n\n if (packages.includes('devtools')) {\n restImports.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`)\n restAdapters.push(` new DevToolsAdapter(),`)\n }\n if (packages.includes('swagger')) {\n restImports.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`)\n restAdapters.push(\n ` new SwaggerAdapter({\\n info: { title: '${name}', version: '${version}' },\\n }),`,\n )\n }\n if (packages.includes('otel')) {\n restImports.push(`import { OtelAdapter } from '@forinda/kickjs-otel'`)\n restAdapters.push(` new OtelAdapter({ serviceName: '${name}' }),`)\n }\n\n const restImportsBlock = restImports.length ? restImports.join('\\n') + '\\n' : ''\n const restAdaptersBlock = restAdapters.length\n ? `\\n adapters: [\\n${restAdapters.join('\\n')}\\n ],`\n : ''\n\n return `import 'reflect-metadata'\n// Side-effect import — registers the extended env schema with kickjs\n// **before** any controller / service / @Value gets resolved. Without\n// this line ConfigService.get('YOUR_KEY') returns undefined because the\n// cached schema would still be the base shape. See guide/configuration.\nimport './config'\nimport express from 'express'\nimport {\n bootstrap,\n requestId,\n requestLogger,\n helmet,\n cors,\n} from '@forinda/kickjs'\n${restImportsBlock}import { modules } from './modules'\n\n// Export the app for the Vite plugin (dev mode)\nexport const app = await bootstrap({\n modules,${restAdaptersBlock}\n middleware: [\n helmet(),\n cors({ origin: '*' }),\n requestId(),\n requestLogger(),\n express.json(),\n ],\n})\n`\n }\n }\n}\n\n/** Generate src/modules/index.ts module registry */\nexport function generateModulesIndex(): string {\n return `import type { AppModuleClass } from '@forinda/kickjs'\nimport { HelloModule } from './hello/hello.module'\n\n// Remove HelloModule and run: kick g module <name>\nexport const modules: AppModuleClass[] = [HelloModule]\n`\n}\n\n/**\n * Generate `src/config/index.ts` — the project's typed env schema.\n *\n * Default-exports a `defineEnv(...)` schema so `kick typegen` can\n * infer it into the global `KickEnv` registry, and *also* calls\n * `loadEnv(envSchema)` as a module-load side effect so `ConfigService`\n * and `@Value()` see the extended shape from the very first DI\n * resolution. The companion `src/index.ts` template adds\n * `import './config'` immediately after `reflect-metadata` so the\n * registration runs before `bootstrap()` constructs anything.\n *\n * After typegen runs:\n *\n * @Value('DATABASE_URL') private url!: Env<'DATABASE_URL'>\n * process.env.DATABASE_URL // typed as string\n *\n * Both autocomplete and type-check at compile time.\n */\nexport function generateEnvFile(): string {\n return `import { defineEnv, loadEnv } from '@forinda/kickjs/config'\nimport { z } from 'zod'\n\n/**\n * Project environment schema.\n *\n * Extend the base schema with your application's variables. The\n * default export is the contract \\`kick typegen\\` reads to populate\n * the global \\`KickEnv\\` registry — that's what makes \\`@Value('FOO')\\`\n * autocomplete and \\`process.env.FOO\\` typed.\n *\n * @example\n * DATABASE_URL: z.string().url(),\n * JWT_SECRET: z.string().min(32),\n * REDIS_URL: z.string().url().optional(),\n */\nconst envSchema = defineEnv((base) =>\n base.extend({\n // DATABASE_URL: z.string().url(),\n }),\n)\n\n/**\n * IMPORTANT — side effect: register the schema with kickjs's env cache\n * **at module-load time**. \\`ConfigService\\` and \\`@Value()\\` both consume\n * this cache, and they will fall back to the base schema (or undefined)\n * if no extended schema has been registered before they're resolved.\n *\n * As long as \\`src/index.ts\\` imports this file (\\`import './env'\\`) at the\n * top — before \\`bootstrap()\\` runs — every controller and service in the\n * app sees the typed extended values.\n */\nexport const env = loadEnv(envSchema)\n\nexport default envSchema\n`\n}\n\n/** Generate src/modules/hello/hello.service.ts */\nexport function generateHelloService(): string {\n return `import { Service } from '@forinda/kickjs'\n\n@Service()\nexport class HelloService {\n greet(name: string) {\n return { message: \\`Hello \\${name} from KickJS!\\`, timestamp: new Date().toISOString() }\n }\n\n healthCheck() {\n return { status: 'ok', uptime: process.uptime() }\n }\n}\n`\n}\n\n/** Generate src/modules/hello/hello.controller.ts */\nexport function generateHelloController(): string {\n return `import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'\nimport { HelloService } from './hello.service'\n\n// \\`Ctx<KickRoutes.HelloController['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`). The first run after a fresh\n// scaffold creates \\`.kickjs/types/routes.ts\\` so this file typechecks.\n// See https://forinda.github.io/kick-js/guide/typegen.\n\n@Controller()\nexport class HelloController {\n @Autowired() private readonly helloService!: HelloService\n\n @Get('/')\n index(ctx: Ctx<KickRoutes.HelloController['index']>) {\n ctx.json(this.helloService.greet('World'))\n }\n\n @Get('/health')\n health(ctx: Ctx<KickRoutes.HelloController['health']>) {\n ctx.json(this.helloService.healthCheck())\n }\n}\n`\n}\n\n/** Generate src/modules/hello/hello.module.ts */\nexport function generateHelloModule(): string {\n return `import { type AppModule, type ModuleRoutes, buildRoutes } from '@forinda/kickjs'\nimport { HelloController } from './hello.controller'\n\nexport class HelloModule implements AppModule {\n // \\`register(container)\\` is optional — only implement it when you need\n // to bind a token to a concrete implementation, e.g.\n // register(container) {\n // container.registerFactory(USER_REPOSITORY, () => container.resolve(InMemoryUserRepository))\n // }\n // The HelloService uses @Service() so the decorator handles registration.\n\n routes(): ModuleRoutes {\n return {\n path: '/hello',\n router: buildRoutes(HelloController),\n controller: HelloController,\n }\n }\n}\n`\n}\n\n/** Generate kick.config.ts CLI configuration */\nexport function generateKickConfig(\n template: ProjectTemplate,\n defaultRepo: string = 'inmemory',\n): string {\n const builtinRepos = ['drizzle', 'inmemory', 'prisma']\n const repoValue = builtinRepos.includes(defaultRepo)\n ? `'${defaultRepo}'`\n : `{ name: '${defaultRepo}' }`\n\n return `import { defineConfig } from '@forinda/kickjs-cli'\n\nexport default defineConfig({\n pattern: '${template}',\n modules: {\n dir: 'src/modules',\n repo: ${repoValue},\n pluralize: true,\n },\n\n // \\`kick typegen\\` populates \\`.kickjs/types/\\` so \\`Ctx<KickRoutes.X['method']>\\`\n // resolves to fully-typed params/body/query. Auto-runs on \\`kick dev\\`.\n // Set \\`schemaValidator: false\\` to skip schema-driven body typing entirely.\n typegen: {\n schemaValidator: 'zod',\n },\n\n commands: [\n {\n name: 'test',\n description: 'Run tests with Vitest',\n steps: 'npx vitest run',\n },\n {\n name: 'format',\n description: 'Format code with Prettier',\n steps: 'npx prettier --write src/',\n },\n {\n name: 'format:check',\n description: 'Check formatting without writing',\n steps: 'npx prettier --check src/',\n },\n {\n name: 'ci:check',\n description: 'Run typecheck + format check',\n steps: ['npx tsc --noEmit', 'npx prettier --check src/'],\n aliases: ['verify'],\n },\n ],\n})\n`\n}\n","import type { ModuleContext } from './types'\nimport { generateMinimalModuleIndex } from '../templates'\n\nexport async function generateMinimalFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, write } = ctx\n\n await write('index.ts', generateMinimalModuleIndex({ pascal, kebab, plural }))\n\n await write(\n `${kebab}.controller.ts`,\n `import { Controller, Get, type Ctx } from '@forinda/kickjs'\n\n// \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`).\n\n@Controller()\nexport class ${pascal}Controller {\n @Get('/')\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n ctx.json({ message: '${pascal} list' })\n }\n}\n`,\n )\n}\n","import type { ModuleContext } from './types'\nimport { toKebabCase } from '../../utils/naming'\nimport {\n generateRestModuleIndex,\n generateRestController,\n generateRestConstants,\n generateRestService,\n generateCreateDTO,\n generateUpdateDTO,\n generateResponseDTO,\n generateRepositoryInterface,\n generateInMemoryRepository,\n generateCustomRepository,\n generateDrizzleRepository,\n generatePrismaRepository,\n generateControllerTest,\n generateRepositoryTest,\n} from '../templates'\n\nexport async function generateRestFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, write } = ctx\n\n // Module index\n await write('index.ts', generateRestModuleIndex({ pascal, kebab, plural, repo }))\n\n // Constants\n await write(`${kebab}.constants.ts`, generateRestConstants({ pascal, kebab }))\n\n // Controller (injects service)\n await write(\n `${kebab}.controller.ts`,\n generateRestController({ pascal, kebab, plural, pluralPascal }),\n )\n\n // Service (wraps repository)\n await write(`${kebab}.service.ts`, generateRestService({ pascal, kebab }))\n\n // DTOs\n await write(`dtos/create-${kebab}.dto.ts`, generateCreateDTO({ pascal, kebab }))\n await write(`dtos/update-${kebab}.dto.ts`, generateUpdateDTO({ pascal, kebab }))\n await write(`dtos/${kebab}-response.dto.ts`, generateResponseDTO({ pascal, kebab }))\n\n // Repository interface (flat imports)\n await write(\n `${kebab}.repository.ts`,\n generateRepositoryInterface({ pascal, kebab, dtoPrefix: './dtos' }),\n )\n\n // Repository implementation (flat imports)\n const builtinRepoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const builtinRepoGeneratorMap: Record<string, () => string> = {\n inmemory: () =>\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n drizzle: () =>\n generateDrizzleRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n prisma: () =>\n generatePrismaRepository({\n pascal,\n kebab,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n prismaClientPath,\n }),\n }\n const repoFile = builtinRepoFileMap[repo] ?? `${toKebabCase(repo)}-${kebab}`\n const repoGenerator =\n builtinRepoGeneratorMap[repo] ??\n (() =>\n generateCustomRepository({\n pascal,\n kebab,\n repoType: repo,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n }))\n await write(`${repoFile}.repository.ts`, repoGenerator())\n\n // Tests\n if (!noTests) {\n // Always generate an in-memory repo for testing — even when using drizzle/prisma\n if (repo !== 'inmemory') {\n await write(\n `in-memory-${kebab}.repository.ts`,\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n )\n }\n await write(\n `__tests__/${kebab}.controller.test.ts`,\n generateControllerTest({ pascal, kebab, plural }),\n )\n await write(\n `__tests__/${kebab}.repository.test.ts`,\n generateRepositoryTest({\n pascal,\n kebab,\n plural,\n repoPrefix: `../${builtinRepoFileMap.inmemory ?? `in-memory-${kebab}`}.repository`,\n }),\n )\n }\n}\n","import type { ModuleContext } from './types'\nimport { toKebabCase } from '../../utils/naming'\nimport {\n generateCqrsModuleIndex,\n generateRestConstants,\n generateCqrsController,\n generateCreateDTO,\n generateUpdateDTO,\n generateResponseDTO,\n generateCqrsCommands,\n generateCqrsQueries,\n generateCqrsEvents,\n generateRepositoryInterface,\n generateInMemoryRepository,\n generateCustomRepository,\n generateDrizzleRepository,\n generatePrismaRepository,\n generateControllerTest,\n generateRepositoryTest,\n} from '../templates'\n\nexport async function generateCqrsFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, pluralPascal, repo, noTests, prismaClientPath, write } = ctx\n\n // Module index\n await write('index.ts', generateCqrsModuleIndex({ pascal, kebab, plural, repo }))\n\n // Constants\n await write(`${kebab}.constants.ts`, generateRestConstants({ pascal, kebab }))\n\n // Controller (dispatches commands/queries)\n await write(\n `${kebab}.controller.ts`,\n generateCqrsController({ pascal, kebab, plural, pluralPascal }),\n )\n\n // DTOs\n await write(`dtos/create-${kebab}.dto.ts`, generateCreateDTO({ pascal, kebab }))\n await write(`dtos/update-${kebab}.dto.ts`, generateUpdateDTO({ pascal, kebab }))\n await write(`dtos/${kebab}-response.dto.ts`, generateResponseDTO({ pascal, kebab }))\n\n // Commands\n const commands = generateCqrsCommands({ pascal, kebab })\n for (const cmd of commands) {\n await write(`commands/${cmd.file}`, cmd.content)\n }\n\n // Queries\n const queries = generateCqrsQueries({ pascal, kebab, plural, pluralPascal })\n for (const q of queries) {\n await write(`queries/${q.file}`, q.content)\n }\n\n // Events\n const events = generateCqrsEvents({ pascal, kebab })\n for (const e of events) {\n await write(`events/${e.file}`, e.content)\n }\n\n // Repository interface (flat imports)\n await write(\n `${kebab}.repository.ts`,\n generateRepositoryInterface({ pascal, kebab, dtoPrefix: './dtos' }),\n )\n\n // Repository implementation (flat imports)\n const builtinRepoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const builtinRepoGeneratorMap: Record<string, () => string> = {\n inmemory: () =>\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n drizzle: () =>\n generateDrizzleRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n prisma: () =>\n generatePrismaRepository({\n pascal,\n kebab,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n prismaClientPath,\n }),\n }\n const repoFile = builtinRepoFileMap[repo] ?? `${toKebabCase(repo)}-${kebab}`\n const repoGenerator =\n builtinRepoGeneratorMap[repo] ??\n (() =>\n generateCustomRepository({\n pascal,\n kebab,\n repoType: repo,\n repoPrefix: '.',\n dtoPrefix: './dtos',\n }))\n await write(`${repoFile}.repository.ts`, repoGenerator())\n\n // Tests\n if (!noTests) {\n // Always generate an in-memory repo for testing — even when using drizzle/prisma\n if (repo !== 'inmemory') {\n await write(\n `in-memory-${kebab}.repository.ts`,\n generateInMemoryRepository({ pascal, kebab, repoPrefix: '.', dtoPrefix: './dtos' }),\n )\n }\n await write(\n `__tests__/${kebab}.controller.test.ts`,\n generateControllerTest({ pascal, kebab, plural }),\n )\n await write(\n `__tests__/${kebab}.repository.test.ts`,\n generateRepositoryTest({\n pascal,\n kebab,\n plural,\n repoPrefix: `../${builtinRepoFileMap.inmemory ?? `in-memory-${kebab}`}.repository`,\n }),\n )\n }\n}\n","import type { ModuleContext } from './types'\nimport { toKebabCase } from '../../utils/naming'\nimport {\n generateModuleIndex,\n generateConstants,\n generateDrizzleConstants,\n generateController,\n generateCreateDTO,\n generateUpdateDTO,\n generateResponseDTO,\n generateUseCases,\n generateRepositoryInterface,\n generateDomainService,\n generateInMemoryRepository,\n generateCustomRepository,\n generateDrizzleRepository,\n generatePrismaRepository,\n generateEntity,\n generateValueObject,\n generateControllerTest,\n generateRepositoryTest,\n} from '../templates'\n\nexport async function generateDddFiles(ctx: ModuleContext): Promise<void> {\n const { pascal, kebab, plural, pluralPascal, repo, noEntity, noTests, prismaClientPath, write } =\n ctx\n\n // Module index\n await write('index.ts', generateModuleIndex({ pascal, kebab, plural, repo }))\n\n // Constants — use Drizzle-specific type-safe config when repo is drizzle\n await write(\n 'constants.ts',\n repo === 'drizzle'\n ? generateDrizzleConstants({ pascal, kebab })\n : generateConstants({ pascal, kebab }),\n )\n\n // Controller (injects use-cases)\n await write(\n `presentation/${kebab}.controller.ts`,\n generateController({ pascal, kebab, plural, pluralPascal }),\n )\n\n // DTOs\n await write(`application/dtos/create-${kebab}.dto.ts`, generateCreateDTO({ pascal, kebab }))\n await write(`application/dtos/update-${kebab}.dto.ts`, generateUpdateDTO({ pascal, kebab }))\n await write(`application/dtos/${kebab}-response.dto.ts`, generateResponseDTO({ pascal, kebab }))\n\n // Use Cases\n const useCases = generateUseCases({ pascal, kebab, plural, pluralPascal })\n for (const uc of useCases) {\n await write(`application/use-cases/${uc.file}`, uc.content)\n }\n\n // Repository Interface\n await write(\n `domain/repositories/${kebab}.repository.ts`,\n generateRepositoryInterface({ pascal, kebab }),\n )\n\n // Domain Service\n await write(\n `domain/services/${kebab}-domain.service.ts`,\n generateDomainService({ pascal, kebab }),\n )\n\n // Repository Implementation\n const builtinRepoFileMap: Record<string, string> = {\n inmemory: `in-memory-${kebab}`,\n drizzle: `drizzle-${kebab}`,\n prisma: `prisma-${kebab}`,\n }\n const builtinRepoGeneratorMap: Record<string, () => string> = {\n inmemory: () => generateInMemoryRepository({ pascal, kebab }),\n drizzle: () => generateDrizzleRepository({ pascal, kebab }),\n prisma: () => generatePrismaRepository({ pascal, kebab, prismaClientPath }),\n }\n const repoFile = builtinRepoFileMap[repo] ?? `${toKebabCase(repo)}-${kebab}`\n const repoGenerator =\n builtinRepoGeneratorMap[repo] ??\n (() => generateCustomRepository({ pascal, kebab, repoType: repo }))\n await write(`infrastructure/repositories/${repoFile}.repository.ts`, repoGenerator())\n\n // Entity & Value Objects\n if (!noEntity) {\n await write(`domain/entities/${kebab}.entity.ts`, generateEntity({ pascal, kebab }))\n await write(`domain/value-objects/${kebab}-id.vo.ts`, generateValueObject({ pascal, kebab }))\n }\n\n // Tests\n if (!noTests) {\n // Always generate an in-memory repo for testing — even when using drizzle/prisma\n if (repo !== 'inmemory') {\n await write(\n `infrastructure/repositories/in-memory-${kebab}.repository.ts`,\n generateInMemoryRepository({ pascal, kebab }),\n )\n }\n await write(\n `__tests__/${kebab}.controller.test.ts`,\n generateControllerTest({ pascal, kebab, plural }),\n )\n await write(\n `__tests__/${kebab}.repository.test.ts`,\n generateRepositoryTest({ pascal, kebab, plural }),\n )\n }\n}\n","import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { confirm, log } from '../utils/prompts'\nimport { colors } from '../utils/colors'\nimport { toPascalCase, toKebabCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport type { ProjectPattern, RepoTypeConfig } from '../config'\nimport {\n generateMinimalFiles,\n generateRestFiles,\n generateCqrsFiles,\n generateDddFiles,\n} from './patterns'\nimport type { ModuleContext } from './patterns'\n\nexport type BuiltinRepoType = 'drizzle' | 'inmemory' | 'prisma'\nexport type RepoType = BuiltinRepoType | (string & {})\n\n/** Resolve a RepoTypeConfig (from kick.config.ts) into a flat repo type string */\nexport function resolveRepoType(config?: RepoTypeConfig): RepoType {\n if (!config) return 'inmemory'\n if (typeof config === 'string') return config\n return config.name\n}\n\ninterface GenerateModuleOptions {\n name: string\n modulesDir: string\n noEntity?: boolean\n noTests?: boolean\n repo?: RepoType\n minimal?: boolean\n force?: boolean\n pattern?: ProjectPattern\n dryRun?: boolean\n /** When false, skip pluralization — use singular names for folders, routes, and classes */\n pluralize?: boolean\n /** Prisma client import path (default: '@prisma/client', Prisma 7+: '@/generated/prisma/client') */\n prismaClientPath?: string\n}\n\n/**\n * Generate a module — structure depends on the project pattern.\n *\n * Patterns:\n * rest — flat folder: controller + service + DTOs + repo\n * ddd — nested DDD: presentation/ application/ domain/ infrastructure/\n * graphql — flat folder: resolver + service + DTOs + repo (future)\n * cqrs — commands, queries, events with WS/queue integration\n * minimal — just controller + module index\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n const { name, modulesDir, noEntity, noTests, repo = 'inmemory', force, dryRun } = options\n const shouldPluralize = options.pluralize !== false\n\n let pattern = options.pattern ?? 'ddd'\n if (options.minimal) pattern = 'minimal'\n\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const plural = shouldPluralize ? pluralize(kebab) : kebab\n const pluralPascal = shouldPluralize ? pluralizePascal(pascal) : pascal\n const moduleDir = join(modulesDir, plural)\n\n const files: string[] = []\n let overwriteAll = force ?? false\n\n const write = async (relativePath: string, content: string) => {\n const fullPath = join(moduleDir, relativePath)\n if (dryRun) {\n files.push(fullPath)\n return\n }\n if (!overwriteAll && (await fileExists(fullPath))) {\n const shouldOverwrite = await confirm({\n message: `File exists: ${colors.dim(relativePath)}. Overwrite?`,\n initialValue: false,\n })\n if (!shouldOverwrite) {\n log.warn(`Skipped: ${relativePath}`)\n return\n }\n }\n await writeFileSafe(fullPath, content)\n files.push(fullPath)\n }\n\n const ctx: ModuleContext = {\n kebab,\n pascal,\n plural,\n pluralPascal,\n moduleDir,\n repo,\n noEntity: noEntity ?? false,\n noTests: noTests ?? false,\n prismaClientPath: options.prismaClientPath ?? '@prisma/client',\n write,\n files,\n }\n\n switch (pattern) {\n case 'minimal':\n await generateMinimalFiles(ctx)\n break\n case 'rest':\n await generateRestFiles(ctx)\n break\n case 'cqrs':\n await generateCqrsFiles(ctx)\n break\n case 'graphql':\n case 'ddd':\n default:\n await generateDddFiles(ctx)\n break\n }\n\n // Auto-register in modules index (all patterns need this)\n if (!dryRun) {\n await autoRegisterModule(modulesDir, pascal, plural)\n }\n\n return files\n}\n\n// ── Auto-register in modules index ──────────────────────────────────────\n\n/** Add the new module to src/modules/index.ts */\nasync function autoRegisterModule(\n modulesDir: string,\n pascal: string,\n plural: string,\n): Promise<void> {\n const indexPath = join(modulesDir, 'index.ts')\n const exists = await fileExists(indexPath)\n\n if (!exists) {\n await writeFileSafe(\n indexPath,\n `import type { AppModuleClass } from '@forinda/kickjs'\nimport { ${pascal}Module } from './${plural}'\n\nexport const modules: AppModuleClass[] = [${pascal}Module]\n`,\n )\n return\n }\n\n let content = await readFile(indexPath, 'utf-8')\n\n // Add import if not present\n const importLine = `import { ${pascal}Module } from './${plural}'`\n if (!content.includes(`${pascal}Module`)) {\n // Insert import after last existing import\n const lastImportIdx = content.lastIndexOf('import ')\n if (lastImportIdx !== -1) {\n const lineEnd = content.indexOf('\\n', lastImportIdx)\n content = content.slice(0, lineEnd + 1) + importLine + '\\n' + content.slice(lineEnd + 1)\n } else {\n content = importLine + '\\n' + content\n }\n\n // Add to modules array — handle both empty and existing entries\n // Match the array assignment: `= [...]` or `= [\\n...\\n]`\n content = content.replace(/(=\\s*\\[)([\\s\\S]*?)(])/, (_match, open, existing, close) => {\n const trimmed = existing.trim()\n if (!trimmed) {\n // Empty array: `= []`\n return `${open}${pascal}Module${close}`\n }\n // Existing entries: append with comma\n const needsComma = trimmed.endsWith(',') ? '' : ','\n return `${open}${existing.trimEnd()}${needsComma} ${pascal}Module${close}`\n })\n }\n\n await writeFile(indexPath, content, 'utf-8')\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateAdapterOptions {\n name: string\n outDir: string\n}\n\nexport async function generateAdapter(options: GenerateAdapterOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.adapter.ts`)\n await writeFileSafe(\n filePath,\n `import type { AppAdapter, AdapterContext, AdapterMiddleware } from '@forinda/kickjs'\n\nexport interface ${pascal}AdapterOptions {\n // Add your adapter configuration here\n}\n\n/**\n * ${pascal} adapter.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * or external service connections.\n *\n * Usage:\n * bootstrap({\n * adapters: [new ${pascal}Adapter({ ... })],\n * })\n */\nexport class ${pascal}Adapter implements AppAdapter {\n name = '${pascal}Adapter'\n\n constructor(private options: ${pascal}AdapterOptions = {}) {}\n\n /**\n * Return middleware entries that the Application will mount.\n * Use \\`phase\\` to control where in the pipeline they run:\n * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'\n */\n middleware(): AdapterMiddleware[] {\n return [\n // Example: add a custom header to all responses\n // {\n // phase: 'beforeGlobal',\n // handler: (_req: any, res: any, next: any) => {\n // res.setHeader('X-${pascal}', 'true')\n // next()\n // },\n // },\n // Example: scope middleware to a specific path\n // {\n // phase: 'beforeRoutes',\n // path: '/api/v1/admin',\n // handler: myAdminMiddleware(),\n // },\n ]\n }\n\n /**\n * Called before global middleware.\n * Use this to mount routes that bypass the middleware stack\n * (health checks, docs UI, static assets).\n */\n beforeMount({ app }: AdapterContext): void {\n // Example: mount a status route\n // app.get('/${kebab}/status', (_req, res) => {\n // res.json({ status: 'ok' })\n // })\n }\n\n /**\n * Called after modules and routes are registered, before the server starts.\n * Use this for late-stage DI registrations or config validation.\n */\n beforeStart({ container }: AdapterContext): void {\n // Example: register a service in the DI container\n // container.registerInstance(MY_TOKEN, new MyService(this.options))\n }\n\n /**\n * Called after the HTTP server is listening.\n * Use this to attach to the raw http.Server (Socket.IO, gRPC, etc).\n */\n afterStart({ server, container }: AdapterContext): void {\n // Example: attach Socket.IO\n // const io = new Server(server)\n // container.registerInstance(SOCKET_IO, io)\n }\n\n /**\n * Called on graceful shutdown. Clean up connections.\n */\n async shutdown(): Promise<void> {\n // Example: close a connection pool\n // await this.pool.end()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { resolve, join } from 'node:path'\nimport { pluralize, toKebabCase } from './naming'\nimport type { ProjectPattern } from '../config'\n\n/**\n * DDD folder mapping — nested layered architecture.\n */\nconst DDD_FOLDER_MAP: Record<string, string> = {\n controller: 'presentation',\n service: 'domain/services',\n dto: 'application/dtos',\n guard: 'presentation/guards',\n middleware: 'middleware',\n}\n\n/**\n * Flat folder mapping — REST/GraphQL/minimal patterns.\n * Files live at the module root or in minimal subdirectories.\n */\nconst FLAT_FOLDER_MAP: Record<string, string> = {\n controller: '',\n service: '',\n dto: 'dtos',\n guard: 'guards',\n middleware: 'middleware',\n}\n\n/**\n * CQRS folder mapping — commands, queries, events.\n */\nconst CQRS_FOLDER_MAP: Record<string, string> = {\n controller: '',\n service: '',\n dto: 'dtos',\n guard: 'guards',\n middleware: 'middleware',\n command: 'commands',\n query: 'queries',\n event: 'events',\n}\n\nexport interface ResolveOutDirOptions {\n /** The artifact type (controller, service, dto, guard, middleware) */\n type: string\n /** Explicit -o / --out dir from CLI flag (takes highest priority) */\n outDir?: string\n /** Module name from --module flag */\n moduleName?: string\n /** Modules directory (from config or default) */\n modulesDir?: string\n /** Standalone default directory when no --module is used (e.g. 'src/controllers') */\n defaultDir: string\n /** Project pattern — determines folder structure inside modules */\n pattern?: ProjectPattern\n /** Whether to pluralize the module folder name (default: true) */\n shouldPluralize?: boolean\n}\n\n/**\n * Resolve the output directory for a generator artifact.\n *\n * Priority:\n * 1. Explicit --out flag (always wins)\n * 2. --module flag → maps into module's folder (DDD or flat based on pattern)\n * 3. Standalone default directory\n */\nexport function resolveOutDir(options: ResolveOutDirOptions): string {\n const {\n type,\n outDir,\n moduleName,\n modulesDir = 'src/modules',\n defaultDir,\n pattern = 'ddd',\n shouldPluralize = true,\n } = options\n\n // Explicit --out always wins\n if (outDir) return resolve(outDir)\n\n // Module-scoped: place inside the module's folder\n if (moduleName) {\n const folderMap =\n pattern === 'ddd' ? DDD_FOLDER_MAP : pattern === 'cqrs' ? CQRS_FOLDER_MAP : FLAT_FOLDER_MAP\n const kebab = toKebabCase(moduleName)\n const folder = shouldPluralize ? pluralize(kebab) : kebab\n const subfolder = folderMap[type] ?? ''\n const base = join(modulesDir, folder)\n return resolve(subfolder ? join(base, subfolder) : base)\n }\n\n // Standalone default\n return resolve(defaultDir)\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateMiddlewareOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'middleware',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/middleware',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.middleware.ts`)\n await writeFileSafe(\n filePath,\n `import type { Request, Response, NextFunction } from 'express'\n\nexport interface ${toPascalCase(name)}Options {\n // Add configuration options here\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap:\n * middleware: [${camel}()]\n *\n * Usage with adapter:\n * middleware() { return [{ handler: ${camel}(), phase: 'afterGlobal' }] }\n *\n * Usage with @Middleware decorator:\n * @Middleware(${camel}())\n */\nexport function ${camel}(options: ${toPascalCase(name)}Options = {}) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Implement your middleware logic here\n next()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateGuardOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'guard',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/guards',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.guard.ts`)\n await writeFileSafe(\n filePath,\n `import { Container, HttpException } from '@forinda/kickjs'\nimport type { RequestContext } from '@forinda/kickjs'\n\n/**\n * ${pascal} guard.\n *\n * Guards protect routes by checking conditions before the handler runs.\n * Return early with an error response to block access.\n *\n * Usage:\n * @Middleware(${camel}Guard)\n * @Get('/protected')\n * async handler(ctx: RequestContext) { ... }\n */\nexport async function ${camel}Guard(ctx: RequestContext, next: () => void): Promise<void> {\n // Example: check for an authorization header\n const header = ctx.headers.authorization\n if (!header?.startsWith('Bearer ')) {\n ctx.res.status(401).json({ message: 'Missing or invalid authorization header' })\n return\n }\n\n const token = header.slice(7)\n\n try {\n // Verify the token using a service from the DI container\n // const container = Container.getInstance()\n // const authService = container.resolve(AuthService)\n // const payload = authService.verifyToken(token)\n // ctx.set('auth', payload)\n\n next()\n } catch {\n ctx.res.status(401).json({ message: 'Invalid or expired token' })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateServiceOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'service',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/services',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.service.ts`)\n await writeFileSafe(\n filePath,\n `import { Service } from '@forinda/kickjs'\n\n@Service()\nexport class ${pascal}Service {\n // Inject dependencies via constructor\n // constructor(\n // @Inject(MY_REPO) private readonly repo: IMyRepository,\n // ) {}\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateControllerOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'controller',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/controllers',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.controller.ts`)\n await writeFileSafe(\n filePath,\n `import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'\n\n// \\`Ctx<KickRoutes.${pascal}Controller['<method>']>\\` is generated by\n// \\`kick typegen\\` (auto-run on \\`kick dev\\`). After the first run, your IDE\n// will autocomplete \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\`.\n// See https://forinda.github.io/kick-js/guide/typegen for details.\n\n@Controller()\nexport class ${pascal}Controller {\n // @Autowired() private readonly myService!: MyService\n\n @Get('/')\n async list(ctx: Ctx<KickRoutes.${pascal}Controller['list']>) {\n ctx.json({ message: '${pascal} list' })\n }\n\n @Post('/')\n async create(ctx: Ctx<KickRoutes.${pascal}Controller['create']>) {\n ctx.created({ message: '${pascal} created', data: ctx.body })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\nimport { resolveOutDir } from '../utils/resolve-out-dir'\nimport type { ProjectPattern } from '../config'\n\ninterface GenerateDtoOptions {\n name: string\n outDir?: string\n moduleName?: string\n modulesDir?: string\n pattern?: ProjectPattern\n pluralize?: boolean\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n const { name, moduleName, modulesDir, pattern } = options\n const outDir = resolveOutDir({\n type: 'dto',\n outDir: options.outDir,\n moduleName,\n modulesDir,\n defaultDir: 'src/dtos',\n pattern,\n shouldPluralize: options.pluralize ?? true,\n })\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.dto.ts`)\n await writeFileSafe(\n filePath,\n `import { z } from 'zod'\n\nexport const ${camel}Schema = z.object({\n // Define your schema fields here\n name: z.string().min(1).max(200),\n})\n\nexport type ${pascal}DTO = z.infer<typeof ${camel}Schema>\n`,\n )\n files.push(filePath)\n\n return files\n}\n","type ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/** Map of optional package names to their npm package identifiers */\nconst PACKAGE_DEPS: Record<string, string> = {\n auth: '@forinda/kickjs-auth',\n swagger: '@forinda/kickjs-swagger',\n otel: '@forinda/kickjs-otel',\n ws: '@forinda/kickjs-ws',\n queue: '@forinda/kickjs-queue',\n cron: '@forinda/kickjs-cron',\n mailer: '@forinda/kickjs-mailer',\n graphql: '@forinda/kickjs-graphql',\n devtools: '@forinda/kickjs-devtools',\n notifications: '@forinda/kickjs-notifications',\n 'multi-tenant': '@forinda/kickjs-multi-tenant',\n}\n\n/** Generate package.json with template-aware dependencies */\nexport function generatePackageJson(\n name: string,\n template: ProjectTemplate,\n kickjsVersion: string,\n packages: string[] = [],\n): string {\n const baseDeps: Record<string, string> = {\n '@forinda/kickjs': kickjsVersion,\n // `dotenv` is an optional peer of @forinda/kickjs — scaffolded apps\n // get it pre-installed so `.env` files Just Work. Apps that load\n // env from the shell or a secret manager can drop this safely.\n dotenv: '^17.3.1',\n express: '^5.1.0',\n 'reflect-metadata': '^0.2.2',\n zod: '^4.3.6',\n pino: '^10.3.1',\n 'pino-pretty': '^13.1.3',\n }\n\n // graphql template always needs the graphql runtime\n if (template === 'graphql') {\n baseDeps['@forinda/kickjs-graphql'] = kickjsVersion\n baseDeps['graphql'] = '^16.11.0'\n }\n\n // Add user-selected optional packages\n for (const pkg of packages) {\n const dep = PACKAGE_DEPS[pkg]\n if (dep && !baseDeps[dep]) {\n baseDeps[dep] = kickjsVersion\n }\n }\n\n // graphql package needs the graphql peer dep\n if (packages.includes('graphql') && !baseDeps['graphql']) {\n baseDeps['graphql'] = '^16.11.0'\n }\n\n return JSON.stringify(\n {\n name,\n version: kickjsVersion.replace('^', ''), // Remove the ^ prefix for project version\n type: 'module',\n scripts: {\n dev: 'vite',\n 'dev:debug': 'kick dev:debug',\n build: 'kick build',\n start: 'kick start',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n typegen: 'kick typegen',\n lint: 'eslint src/',\n format: 'prettier --write src/',\n },\n dependencies: baseDeps,\n devDependencies: {\n '@forinda/kickjs-cli': kickjsVersion,\n '@forinda/kickjs-vite': kickjsVersion,\n '@swc/core': '^1.15.21',\n '@types/express': '^5.0.6',\n '@types/node': '^25.0.0',\n 'unplugin-swc': '^1.5.9',\n vite: '^8.0.3',\n vitest: '^4.1.2',\n typescript: '^5.9.2',\n prettier: '^3.8.1',\n },\n },\n null,\n 2,\n )\n}\n\n/**\n * Generate vite.config.ts with the KickJS Vite plugin.\n *\n * The plugin handles:\n * - SSR environment setup for backend Node.js code\n * - Virtual module generation (virtual:kickjs/app)\n * - Module auto-discovery (scans *.module.ts files)\n * - HMR with selective container invalidation\n * - Express mounting via configureServer() post-hook\n * - httpServer piping to adapters (WsAdapter, Socket.IO, etc.)\n */\nexport function generateViteConfig(): string {\n return `import { defineConfig } from 'vite'\nimport { resolve } from 'node:path'\nimport swc from 'unplugin-swc'\nimport { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'\n\nexport default defineConfig({\n oxc: false,\n plugins: [\n swc.vite(),\n kickjsVitePlugin({ entry: 'src/index.ts' }),\n // Watches .env files and triggers a full reload on change so the\n // dev server picks up env tweaks without a manual restart.\n envWatchPlugin(),\n ],\n resolve: {\n alias: {\n '@': resolve(__dirname, 'src'),\n },\n },\n ssr: {\n // Don't bundle pino — its worker-thread transport needs Node.js resolution\n // to find pino-pretty at runtime for colored log output\n external: ['pino', 'pino-pretty'],\n },\n build: {\n target: 'node20',\n ssr: true,\n outDir: 'dist',\n sourcemap: true,\n rollupOptions: {\n input: resolve(__dirname, 'src/index.ts'),\n output: { format: 'esm' },\n },\n },\n})\n`\n}\n\n/** Generate tsconfig.json with decorator support */\nexport function generateTsConfig(): string {\n return JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['node', 'vite/client'],\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n sourceMap: true,\n declaration: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: 'dist',\n // rootDir omitted so .kickjs/types/*.d.ts can sit outside src/\n paths: { '@/*': ['./src/*'] },\n },\n // .kickjs/types is generated by `kick typegen` and refreshed\n // automatically on `kick dev`. Including it here makes\n // `container.resolve()` and module discovery type-safe.\n // Both .d.ts and .ts are matched: registry/services/modules are\n // declarations, but routes.ts holds resolvable imports from your\n // controllers' Zod schemas (TS silently degrades inline `import('...')`\n // inside `.d.ts` files under `moduleResolution: 'bundler'`).\n include: ['src', '.kickjs/types/**/*.d.ts', '.kickjs/types/**/*.ts'],\n },\n null,\n 2,\n )\n}\n\n/** Generate .prettierrc with project formatting rules */\nexport function generatePrettierConfig(): string {\n return JSON.stringify(\n {\n semi: false,\n singleQuote: true,\n trailingComma: 'all',\n printWidth: 100,\n tabWidth: 2,\n },\n null,\n 2,\n )\n}\n\n/** Generate .editorconfig for consistent editor settings */\nexport function generateEditorConfig(): string {\n return `# https://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n`\n}\n\n/** Generate .gitignore with common Node.js patterns */\nexport function generateGitIgnore(): string {\n return `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n.kickjs/\n`\n}\n\n/** Generate .gitattributes for consistent line endings */\nexport function generateGitAttributes(): string {\n return `# Auto-detect text files and normalise line endings to LF\n* text=auto eol=lf\n\n# Explicitly mark generated / binary files\n*.png binary\n*.jpg binary\n*.jpeg binary\n*.gif binary\n*.ico binary\n*.woff binary\n*.woff2 binary\n*.ttf binary\n*.eot binary\n\n# Lock files — treat as generated\npnpm-lock.yaml -diff linguist-generated\nyarn.lock -diff linguist-generated\npackage-lock.json -diff linguist-generated\n`\n}\n\n/** Generate .env file with default environment variables */\nexport function generateEnv(): string {\n return `PORT=3000\nNODE_ENV=development\n`\n}\n\n/** Generate .env.example file as a template */\nexport function generateEnvExample(): string {\n return `PORT=3000\nNODE_ENV=development\n`\n}\n\n/** Generate vitest.config.ts for test configuration */\nexport function generateVitestConfig(): string {\n return `import { defineConfig } from 'vitest/config'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.test.ts'],\n },\n})\n`\n}\n","type ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/** Generate README.md with project documentation */\nexport function generateReadme(name: string, template: ProjectTemplate, pm: string): string {\n const templateLabels: Record<string, string> = {\n rest: 'REST API',\n graphql: 'GraphQL API',\n ddd: 'Domain-Driven Design',\n cqrs: 'CQRS + Event-Driven',\n minimal: 'Minimal',\n }\n\n const packages = ['@forinda/kickjs', '@forinda/kickjs-vite']\n if (template !== 'minimal') {\n packages.push('@forinda/kickjs-swagger', '@forinda/kickjs-devtools')\n }\n if (template === 'graphql') packages.push('@forinda/kickjs-graphql')\n if (template === 'cqrs') {\n packages.push('@forinda/kickjs-queue', '@forinda/kickjs-ws', '@forinda/kickjs-otel')\n }\n\n return `# ${name}\n\nA **${templateLabels[template] ?? 'REST API'}** built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.\n\n## Getting Started\n\n\\`\\`\\`bash\n${pm} install\nkick dev\n\\`\\`\\`\n\n## Scripts\n\n| Command | Description |\n|---|---|\n| \\`kick dev\\` | Start dev server with Vite HMR |\n| \\`kick build\\` | Production build |\n| \\`kick start\\` | Run production build |\n| \\`${pm} run test\\` | Run tests with Vitest |\n| \\`kick g module <name>\\` | Generate a DDD module |\n| \\`kick g scaffold <name> <fields...>\\` | Generate CRUD from field definitions |\n| \\`kick add <package>\\` | Add a KickJS package |\n\n## Project Structure\n\n\\`\\`\\`\nsrc/\n├── index.ts # Application entry point\n├── modules/ # Feature modules (controllers, services, repos)\n│ └── index.ts # Module registry\n└── ...\n\\`\\`\\`\n\n## Packages\n\n${packages.map((p) => `- \\`${p}\\``).join('\\n')}\n\n## Adding Features\n\n\\`\\`\\`bash\nkick add auth # Authentication (JWT, API key, OAuth)\nkick add swagger # OpenAPI documentation\nkick add ws # WebSocket support\nkick add queue # Background job processing\nkick add mailer # Email sending\nkick add cron # Scheduled tasks\nkick add --list # Show all available packages\n\\`\\`\\`\n\n## Environment Variables\n\nCopy \\`.env.example\\` to \\`.env\\` and configure:\n\n| Variable | Default | Description |\n|---|---|---|\n| \\`PORT\\` | \\`3000\\` | Server port |\n| \\`NODE_ENV\\` | \\`development\\` | Environment |\n\n## Learn More\n\n- [KickJS Documentation](https://forinda.github.io/kick-js/)\n- [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)\n`\n}\n\n/** Generate CLAUDE.md with AI development guide */\nexport function generateClaude(name: string, template: ProjectTemplate, pm: string): string {\n const templateLabels: Record<string, string> = {\n rest: 'REST API',\n graphql: 'GraphQL API',\n ddd: 'Domain-Driven Design',\n cqrs: 'CQRS + Event-Driven',\n minimal: 'Minimal Express',\n }\n\n return `# CLAUDE.md — ${name} Development Guide\n\n## Project Overview\n\nThis is a **${templateLabels[template] ?? 'REST API'}** application built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.\n\n## Quick Commands\n\n\\`\\`\\`bash\n${pm} install # Install dependencies\nkick dev # Start dev server with HMR\nkick build # Production build via Vite\nkick start # Run production build\n${pm} run test # Run tests with Vitest\n${pm} run typecheck # TypeScript type checking\n${pm} run format # Format code with Prettier\n\\`\\`\\`\n\n## Project Structure\n\n\\`\\`\\`\nsrc/\n├── index.ts # Application bootstrap\n├── modules/ # Feature modules (DDD/CQRS pattern)\n│ └── index.ts # Module registry\n${template === 'graphql' ? '├── resolvers/ # GraphQL resolvers\\n' : ''}└── ...\n\\`\\`\\`\n\n## Package Manager\n\n- Always use **${pm}** for this project\n- Run \\`${pm} install\\` to sync dependencies\n- Never mix package managers (npm/yarn/pnpm)\n\n## Code Style\n\n- **Prettier** — no semicolons, single quotes, trailing commas, 100 char width\n- **TypeScript strict mode** — all types required\n- Format before committing: \\`${pm} run format\\`\n- Type check with: \\`${pm} run typecheck\\`\n\n## Key Patterns\n\n### Controllers\n\nUse decorators to define routes. Annotate \\`ctx\\` with \\`Ctx<KickRoutes.X['method']>\\`\nto get fully-typed \\`ctx.params\\`, \\`ctx.body\\`, and \\`ctx.query\\` from the\ngenerated \\`KickRoutes\\` namespace (refreshed on \\`kick dev\\` and \\`kick typegen\\`).\n\n\\`\\`\\`ts\nimport { Controller, Get, Post, type Ctx } from '@forinda/kickjs'\n\n@Controller('/users')\nexport class UserController {\n @Get('/')\n async findAll(ctx: Ctx<KickRoutes.UserController['findAll']>) {\n return ctx.json({ users: [] })\n }\n\n @Post('/')\n async create(ctx: Ctx<KickRoutes.UserController['create']>) {\n const data = ctx.body\n return ctx.created({ user: data })\n }\n}\n\\`\\`\\`\n\n### Services\n\nInject dependencies with \\`@Service()\\` and \\`@Autowired()\\`:\n\n\\`\\`\\`ts\nimport { Service, Autowired } from '@forinda/kickjs'\n\n@Service()\nexport class UserService {\n @Autowired()\n private userRepository!: UserRepository\n\n async findAll() {\n return this.userRepository.findAll()\n }\n}\n\\`\\`\\`\n\n### Modules\n\nModules implement \\`AppModule\\` and wire controllers via \\`buildRoutes()\\`:\n\n\\`\\`\\`ts\nimport { type AppModule, type ModuleRoutes, buildRoutes } from '@forinda/kickjs'\nimport { UserController } from './user.controller'\n\nexport class UserModule implements AppModule {\n routes(): ModuleRoutes {\n return {\n path: '/users',\n router: buildRoutes(UserController),\n controller: UserController,\n }\n }\n}\n\\`\\`\\`\n\nRegister all modules in \\`src/modules/index.ts\\`:\n\n\\`\\`\\`ts\nimport type { AppModuleClass } from '@forinda/kickjs'\nimport { UserModule } from './user/user.module'\n\nexport const modules: AppModuleClass[] = [UserModule]\n\\`\\`\\`\n\n### RequestContext\n\nEvery controller method receives a \\`ctx\\` (alias \\`Ctx<TRoute>\\` or the\nloose \\`RequestContext\\`):\n\n\\`\\`\\`ts\nctx.body // Request body (parsed JSON)\nctx.params // Route params\nctx.query // Query string\nctx.headers // Request headers\nctx.requestId // Auto-generated request ID\nctx.session // Session data (if session middleware enabled)\nctx.file // Uploaded file (single)\nctx.files // Uploaded files (multiple)\n\n// Pagination helpers\nctx.qs(config) // Parse query with filters/sort/pagination\nctx.paginate(handler) // Auto-paginated response\n\n// Response helpers\nctx.json(data) // 200 OK with JSON\nctx.created(data) // 201 Created\nctx.noContent() // 204 No Content\nctx.notFound() // 404 Not Found\nctx.badRequest(msg) // 400 Bad Request\n\\`\\`\\`\n\n## CLI Generators\n\nGenerate code with the \\`kick\\` CLI:\n\n\\`\\`\\`bash\nkick g module <name> # Full module (controller, service, DTOs, repo)\nkick g scaffold <name> <fields> # CRUD module from field definitions\nkick g controller <name> # Standalone controller\nkick g service <name> # Service class\nkick g middleware <name> # Express middleware\nkick g guard <name> # Route guard (auth, roles)\nkick g adapter <name> # AppAdapter with lifecycle hooks\nkick g dto <name> # Zod DTO schema\n${template === 'graphql' ? 'kick g resolver <name> # GraphQL resolver\\n' : ''}${template === 'cqrs' ? 'kick g job <name> # Queue job processor\\n' : ''}\\`\\`\\`\n\n## Adding Packages\n\n\\`\\`\\`bash\nkick add auth # JWT, API key, OAuth strategies\nkick add swagger # OpenAPI docs from decorators\nkick add ws # WebSocket support\nkick add queue # Background jobs (BullMQ/RabbitMQ/Kafka)\nkick add mailer # Email (SMTP, Resend, SES)\nkick add cron # Scheduled tasks\nkick add prisma # Prisma ORM adapter\nkick add drizzle # Drizzle ORM adapter\nkick add otel # OpenTelemetry tracing\nkick add --list # Show all available packages\n\\`\\`\\`\n\n## Environment Configuration\n\nThe project's typed env schema lives in **\\`src/config/index.ts\\`** —\nextend the base schema there with your application-specific keys, and\nthe schema is auto-registered with kickjs at module load. The companion\n\\`src/index.ts\\` imports it as a side effect (\\`import './config'\\`) **before**\n\\`bootstrap()\\` runs, so every \\`@Service\\`, \\`@Controller\\`, \\`@Value\\`, and\n\\`ConfigService\\` resolution sees the validated extended values.\n\n> **Do not delete \\`import './config'\\` from \\`src/index.ts\\`.** It is the\n> registration step that wires \\`ConfigService\\` to your env schema.\n> Without it, \\`config.get('YOUR_KEY')\\` returns \\`undefined\\` for every\n> user-defined key and \\`@Value('YOUR_KEY')\\` only works because of a\n> raw \\`process.env\\` fallback (Zod coercion + defaults are skipped).\n\nEdit \\`.env\\` for variable values. Access them with \\`@Value()\\`:\n\n\\`\\`\\`ts\nimport { Value } from '@forinda/kickjs'\n\n@Service()\nexport class ApiService {\n @Value('API_KEY')\n private apiKey!: string\n\n @Value('PORT', 3000) // With default\n private port!: number\n}\n\\`\\`\\`\n\nOr use \\`ConfigService\\`:\n\n\\`\\`\\`ts\nimport { Service, Autowired, ConfigService } from '@forinda/kickjs'\n\n@Service()\nexport class AppService {\n @Autowired()\n private config!: ConfigService\n\n getPort() {\n // typed: number, Zod-coerced from baseEnvSchema\n return this.config.get('PORT')\n }\n}\n\\`\\`\\`\n\nHot-reload of \\`.env\\` changes during dev is wired up automatically via\n\\`envWatchPlugin()\\` in \\`vite.config.ts\\` — edit \\`.env\\`, the dev server\nreloads, and the next \\`config.get()\\` re-parses with the new values.\n\n### Standalone Env Utilities (No DI Required)\n\nThese functions work anywhere — scripts, CLI tools, plain files, outside \\`@Service\\`/\\`@Controller\\`:\n\n\\`\\`\\`ts\nimport { defineEnv, loadEnv, getEnv, reloadEnv, resetEnvCache, baseEnvSchema } from '@forinda/kickjs/config'\nimport { z } from 'zod'\n\n// Define and parse schema\nconst schema = defineEnv((base) =>\n base.extend({ DATABASE_URL: z.string().url() })\n)\nconst env = loadEnv(schema) // Parse + validate process.env\nconsole.log(env.PORT) // 3000 (coerced to number)\nconsole.log(env.DATABASE_URL) // validated URL string\n\n// Get single value\nconst port = getEnv('PORT') // typed after kick typegen\n\n// Reload after .env changes (HMR calls this automatically)\nreloadEnv()\n\n// Reset cache in tests that swap schemas\nresetEnvCache()\n\\`\\`\\`\n\n| Function | Purpose |\n|----------|---------|\n| \\`defineEnv(fn)\\` | Extend base schema with custom Zod keys |\n| \\`loadEnv(schema?)\\` | Parse \\`process.env\\`, validate, cache, return typed object |\n| \\`getEnv(key, schema?)\\` | Get single validated env value |\n| \\`reloadEnv()\\` | Re-read \\`.env\\` from disk, re-parse with same schema |\n| \\`resetEnvCache()\\` | Clear parsed cache AND registered schema (for tests) |\n| \\`baseEnvSchema\\` | Base Zod schema: \\`PORT\\`, \\`NODE_ENV\\`, \\`LOG_LEVEL\\` |\n\n## Standalone Utilities (No DI Required)\n\nThese utilities work outside decorated classes:\n\n### Logger\n\n\\`\\`\\`ts\nimport { Logger, createLogger } from '@forinda/kickjs'\n\nconst log = Logger.for('MyScript') // Static factory\nlog.info('Processing started')\nlog.error('Something failed')\n\nconst log2 = createLogger('Worker') // Function form\n\\`\\`\\`\n\n### Injection Tokens\n\n\\`\\`\\`ts\nimport { createToken } from '@forinda/kickjs'\n\n// Type-safe DI tokens for factory/interface binding\nconst DB_URL = createToken<string>('config.database.url')\nconst FEATURE_FLAGS = createToken<FeatureFlags>('app.features')\n\\`\\`\\`\n\n### Reactivity\n\n\\`\\`\\`ts\nimport { ref, computed, watch, reactive } from '@forinda/kickjs'\n\nconst count = ref(0)\nconst doubled = computed(() => count.value * 2)\nconst stop = watch(() => count.value, (val) => console.log(val))\ncount.value++ // logs 1\n\\`\\`\\`\n\n### HTTP Errors\n\n\\`\\`\\`ts\nimport { HttpException, HttpStatus } from '@forinda/kickjs'\n\nthrow new HttpException(HttpStatus.NOT_FOUND, 'User not found')\n\\`\\`\\`\n\n## Testing\n\nTests live in \\`src/**/*.test.ts\\`:\n\n\\`\\`\\`ts\nimport { describe, it, expect, beforeEach } from 'vitest'\nimport { Container } from '@forinda/kickjs'\nimport { createTestApp } from '@forinda/kickjs-testing'\n\ndescribe('UserController', () => {\n beforeEach(() => Container.reset())\n\n it('should return users', async () => {\n const app = await createTestApp([UserModule])\n const res = await app.get('/users')\n expect(res.status).toBe(200)\n })\n})\n\\`\\`\\`\n\nRun tests:\n- \\`${pm} run test\\` — run all tests\n- \\`${pm} run test:watch\\` — watch mode\n\n## Decorators Reference\n\n### Route Decorators\n- \\`@Controller('/path')\\` — define controller prefix\n- \\`@Get('/'), @Post('/'), @Put('/'), @Delete('/'), @Patch('/')\\` — HTTP methods\n- \\`@Middleware(fn)\\` — attach middleware\n- \\`@Public()\\` — skip authentication (requires @forinda/kickjs-auth)\n- \\`@Roles('admin', 'user')\\` — role-based access control\n\n### DI Decorators\n- \\`@Service()\\` — singleton service (DI-registered)\n- \\`@Repository()\\` — repository (semantic alias for @Service)\n- \\`@Autowired()\\` — property injection\n- \\`@Inject('token')\\` — token-based injection\n- \\`@Value('ENV_VAR')\\` — inject config value\n\n${\n template === 'cqrs'\n ? `### CQRS/Event Decorators\n- \\`@Job('job-name')\\` — queue job handler\n- \\`@Process('queue-name')\\` — queue processor\n- \\`@Cron('0 * * * *')\\` — cron schedule\n- \\`@WsController('/path')\\` — WebSocket controller\n- \\`@Subscribe('event')\\` — WebSocket event handler\n\n`\n : ''\n}${\n template === 'graphql'\n ? `### GraphQL Decorators\n- \\`@Resolver()\\` — GraphQL resolver\n- \\`@Query()\\` — GraphQL query\n- \\`@Mutation()\\` — GraphQL mutation\n- \\`@Arg('name')\\` — resolver argument\n\n`\n : ''\n }## Common Pitfalls\n\n1. **Decorators fire at import time** — make sure to import module classes in \\`src/modules/index.ts\\`\n2. **Tests need \\`Container.reset()\\`** — call in \\`beforeEach\\` to isolate DI state\n3. **Always use \\`ctx.body\\`** — never \\`req.body\\` directly\n4. **DI requires \\`reflect-metadata\\`** — already imported in \\`src/index.ts\\`\n5. **Vite HMR requires proper cleanup** — adapters should implement \\`shutdown()\\`\n6. **Never delete \\`import './config'\\` from \\`src/index.ts\\`** — that side-effect import registers the env schema with kickjs. Without it \\`ConfigService.get('YOUR_KEY')\\` returns \\`undefined\\` for every user-defined key. \\`@Value('YOUR_KEY')\\` *appears* to keep working but only via a raw \\`process.env\\` fallback (Zod coercion + schema defaults are silently skipped).\n\n## Learn More\n\n- [KickJS Documentation](https://forinda.github.io/kick-js/)\n- [API Reference](https://forinda.github.io/kick-js/api/)\n- [CLI Commands](https://forinda.github.io/kick-js/guide/cli-commands.html)\n- [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)\n`\n}\n\n/** Generate AGENTS.md with AI agent guide */\nexport function generateAgents(name: string, template: ProjectTemplate, pm: string): string {\n return `# AGENTS.md — AI Agent Guide for ${name}\n\nThis guide helps AI agents (Claude, Copilot, etc.) work effectively on this KickJS application.\n\n## Before You Start\n\n1. Read \\`CLAUDE.md\\` for project conventions and commands\n2. Run \\`${pm} install\\` to install dependencies\n3. Run \\`kick dev\\` to verify the app starts\n4. Read the [KickJS documentation](https://forinda.github.io/kick-js/) for framework details\n\n## Where to Find Things\n\n### Application Structure\n\n| What | Where |\n|------|-------|\n| Entry point | \\`src/index.ts\\` |\n| Module registry | \\`src/modules/index.ts\\` |\n| Feature modules | \\`src/modules/<module-name>/\\` |\n${template === 'graphql' ? '| GraphQL resolvers | `src/resolvers/` |\\n' : ''}| Env values | \\`.env\\` |\n| Env schema (Zod) | \\`src/config/index.ts\\` |\n| TypeScript config | \\`tsconfig.json\\` |\n| Vite config (HMR) | \\`vite.config.ts\\` |\n| Vitest config | \\`vitest.config.ts\\` |\n| Prettier config | \\`.prettierrc\\` |\n| CLI config | \\`kick.config.ts\\` |\n\n### Module Pattern (${template.toUpperCase()})\n\nEach module in \\`src/modules/<name>/\\` typically contains:\n\n${\n template === 'ddd'\n ? `\\`\\`\\`\n<name>/\n├── <name>.controller.ts # HTTP routes (@Controller)\n├── <name>.service.ts # Business logic (@Service)\n├── <name>.repository.ts # Data access (@Repository)\n├── <name>.dto.ts # Request/response schemas (Zod)\n├── <name>.entity.ts # Domain entity (optional)\n└── <name>.module.ts # Module definition (implements AppModule)\n\\`\\`\\`\n`\n : template === 'cqrs'\n ? `\\`\\`\\`\n<name>/\n├── commands/ # Write operations\n│ ├── create-<name>.command.ts\n│ └── create-<name>.handler.ts\n├── queries/ # Read operations\n│ ├── get-<name>.query.ts\n│ └── get-<name>.handler.ts\n├── events/ # Domain events\n│ └── <name>-created.event.ts\n├── <name>.controller.ts # HTTP routes\n├── <name>.repository.ts # Data access\n└── <name>.module.ts # Module definition (implements AppModule)\n\\`\\`\\`\n`\n : template === 'graphql'\n ? `\\`\\`\\`\nresolvers/\n├── <name>.resolver.ts # @Resolver, @Query, @Mutation\n├── <name>.types.ts # GraphQL type definitions\n└── <name>.service.ts # Business logic\n\\`\\`\\`\n`\n : template === 'rest'\n ? `\\`\\`\\`\n<name>/\n├── <name>.controller.ts # HTTP routes (@Controller)\n├── <name>.service.ts # Business logic (@Service)\n├── <name>.dto.ts # Request/response schemas (Zod)\n└── <name>.module.ts # Module definition (implements AppModule)\n\\`\\`\\`\n`\n : `\\`\\`\\`\nsrc/\n├── index.ts # Add routes here\n└── ... # Custom structure\n\\`\\`\\`\n`\n}\n\n## Checklist: Adding a Feature\n\n### New Module (Recommended)\n\nUse the CLI generator for consistency:\n\n\\`\\`\\`bash\nkick g module <name> # Generate full module\n# or\nkick g scaffold <name> <fields> # Generate CRUD from fields\n\\`\\`\\`\n\nThen:\n- [ ] Review generated files in \\`src/modules/<name>/\\`\n- [ ] Verify module is registered in \\`src/modules/index.ts\\`\n- [ ] Update DTOs in \\`<name>.dto.ts\\` if needed\n- [ ] Implement business logic in \\`<name>.service.ts\\`\n- [ ] Run \\`kick dev\\` to test with HMR\n- [ ] Write tests in \\`<name>.test.ts\\`\n\n### Manual Controller\n\nIf not using generators:\n\n- [ ] Create \\`src/modules/<name>/<name>.controller.ts\\`\n- [ ] Add \\`@Controller('/path')\\` decorator\n- [ ] Add route handlers with \\`@Get()\\`, \\`@Post()\\`, etc.\n- [ ] Create module file implementing \\`AppModule\\` with \\`routes()\\` returning \\`{ path, router: buildRoutes(Controller), controller }\\`\n- [ ] Register module in \\`src/modules/index.ts\\` (\\`AppModuleClass[]\\` array)\n- [ ] Test with \\`kick dev\\`\n\n### Manual Service\n\n- [ ] Create \\`src/modules/<name>/<name>.service.ts\\`\n- [ ] Add \\`@Service()\\` decorator\n- [ ] Inject dependencies with \\`@Autowired()\\`\n- [ ] Inject via \\`@Autowired()\\` where needed\n- [ ] Write unit tests\n\n### New Middleware\n\n- [ ] Create \\`src/middleware/<name>.middleware.ts\\`\n- [ ] Export middleware function (Express format)\n- [ ] Register in \\`src/index.ts\\` or attach to routes with \\`@Middleware()\\`\n- [ ] Test with sample requests\n\n### Adding a Package\n\nUse \\`kick add\\` to install KickJS packages with correct peer dependencies:\n\n- [ ] Run \\`kick add <package>\\` (e.g., \\`kick add auth\\`)\n- [ ] Follow package-specific setup in terminal output\n- [ ] Update \\`src/index.ts\\` to register adapter (if needed)\n- [ ] Configure environment variables in \\`.env\\`\n- [ ] Test integration with \\`kick dev\\`\n\n## Common Tasks\n\n### Generate CRUD Module\n\n\\`\\`\\`bash\nkick g scaffold user name:string email:string:optional age:number\n\\`\\`\\`\n\nAppend \\`:optional\\` for optional fields (shell-safe, no quoting needed).\nQuoted \\`?\\` syntax also works: \\`\"email:string?\"\\` or \\`\"email?:string\"\\`.\n\nThis creates a full CRUD module with:\n- Controller with GET, POST, PUT, DELETE routes\n- Service with business logic\n- Repository with data access\n- DTOs with Zod validation\n\n### Add Authentication\n\n\\`\\`\\`bash\nkick add auth\n\\`\\`\\`\n\nThen configure in \\`src/index.ts\\`:\n\n\\`\\`\\`ts\nimport { AuthAdapter, JwtStrategy } from '@forinda/kickjs-auth'\n\nbootstrap({\n modules,\n adapters: [\n new AuthAdapter({\n strategies: [new JwtStrategy({ secret: process.env.JWT_SECRET! })],\n }),\n ],\n})\n\\`\\`\\`\n\n### Add Database (Prisma)\n\n\\`\\`\\`bash\nkick add prisma\n${pm} install prisma @prisma/client\nnpx prisma init\n# Edit prisma/schema.prisma\nnpx prisma migrate dev --name init\nkick g module user --repo prisma\n\\`\\`\\`\n\n### Add WebSocket Support\n\n\\`\\`\\`bash\nkick add ws\n\\`\\`\\`\n\nThen add adapter in \\`src/index.ts\\`:\n\n\\`\\`\\`ts\nimport { WsAdapter } from '@forinda/kickjs-ws'\n\nbootstrap({\n modules,\n adapters: [new WsAdapter()],\n})\n\\`\\`\\`\n\nCreate WebSocket controller:\n\n\\`\\`\\`bash\nkick g controller chat --ws\n\\`\\`\\`\n\n## Testing Guidelines\n\nAll tests use Vitest:\n\n\\`\\`\\`ts\nimport { describe, it, expect, beforeEach } from 'vitest'\nimport { Container } from '@forinda/kickjs'\nimport { createTestApp } from '@forinda/kickjs-testing'\n\ndescribe('UserController', () => {\n beforeEach(() => {\n Container.reset() // Important: isolate DI state\n })\n\n it('should return users', async () => {\n const app = await createTestApp([UserModule])\n const res = await app.get('/users')\n \n expect(res.status).toBe(200)\n expect(res.body).toHaveProperty('users')\n })\n})\n\\`\\`\\`\n\nRun tests:\n- \\`${pm} run test\\` — run all tests once\n- \\`${pm} run test:watch\\` — watch mode\n- Individual file: \\`${pm} run test src/modules/user/user.test.ts\\`\n\n## Environment Variables\n\nSchema is declared in \\`src/config/index.ts\\` (extends the base\n\\`PORT\\`/\\`NODE_ENV\\`/\\`LOG_LEVEL\\` shape via \\`defineEnv\\`) and registered\nwith kickjs at module load. \\`src/index.ts\\` imports it via\n\\`import './config'\\` **before** \\`bootstrap()\\` so the cache is populated\nin time for DI. Add new keys to the schema, drop their values into\n\\`.env\\`, and they're typed everywhere.\n\nAccess patterns:\n\n1. **@Value() decorator** (recommended for known-at-construction keys):\n\\`\\`\\`ts\n@Value('DATABASE_URL')\nprivate dbUrl!: string\n\\`\\`\\`\n\n2. **ConfigService** (recommended for dynamic / method-scoped access):\n\\`\\`\\`ts\n@Autowired()\nprivate config!: ConfigService\n\nconst port = this.config.get('PORT') // typed: number\n\\`\\`\\`\n\n3. **Standalone utilities** (no DI — works in scripts, CLI, plain files):\n\\`\\`\\`ts\nimport { loadEnv, getEnv, reloadEnv, resetEnvCache } from '@forinda/kickjs/config'\n\nconst env = loadEnv(schema) // Parse + validate all vars\nconst port = getEnv('PORT') // Single value lookup\nreloadEnv() // Re-read .env from disk\nresetEnvCache() // Full reset (for tests)\n\\`\\`\\`\n\n4. **Direct \\`process.env\\`** — avoid in app code; bypasses Zod\n coercion and the typed \\`KickEnv\\` registry.\n\n> **Pitfall**: never delete \\`import './config'\\` from \\`src/index.ts\\`.\n> If the schema is not registered before DI runs, \\`config.get()\\`\n> returns \\`undefined\\` for user keys (the base shape only) and\n> \\`@Value()\\` only works because of its raw \\`process.env\\` fallback —\n> Zod coercion + schema defaults are silently skipped.\n\n## Standalone Utilities (No DI Required)\n\nThese work anywhere — scripts, plain files, outside \\`@Service\\`/\\`@Controller\\`:\n\n| Utility | Import | Example |\n|---------|--------|---------|\n| \\`Logger.for(name)\\` | \\`@forinda/kickjs\\` | \\`const log = Logger.for('MyScript')\\` |\n| \\`createLogger(name)\\` | \\`@forinda/kickjs\\` | \\`const log = createLogger('Worker')\\` |\n| \\`createToken<T>(name)\\` | \\`@forinda/kickjs\\` | \\`const TOKEN = createToken<string>('db.url')\\` |\n| \\`ref(value)\\` | \\`@forinda/kickjs\\` | \\`const count = ref(0)\\` |\n| \\`computed(fn)\\` | \\`@forinda/kickjs\\` | \\`const doubled = computed(() => count.value * 2)\\` |\n| \\`watch(source, cb)\\` | \\`@forinda/kickjs\\` | \\`watch(() => count.value, (v) => log(v))\\` |\n| \\`reactive(obj)\\` | \\`@forinda/kickjs\\` | \\`const state = reactive({ count: 0 })\\` |\n| \\`HttpException\\` | \\`@forinda/kickjs\\` | \\`throw new HttpException(404, 'Not found')\\` |\n| \\`HttpStatus\\` | \\`@forinda/kickjs\\` | \\`HttpStatus.NOT_FOUND // 404\\` |\n\n## Key Decorators\n\n### HTTP Routes\n| Decorator | Purpose |\n|-----------|---------|\n| \\`@Controller('/path')\\` | Define route prefix |\n| \\`@Get('/'), @Post('/')\\` | HTTP method handlers |\n| \\`@Middleware(fn)\\` | Attach middleware |\n| \\`@Public()\\` | Skip auth (requires auth adapter) |\n| \\`@Roles('admin')\\` | Role-based access |\n\n### Dependency Injection\n| Decorator | Purpose |\n|-----------|---------|\n| \\`AppModule\\` interface | Define feature module (implements \\`routes()\\`) |\n| \\`@Service()\\` | Register singleton service |\n| \\`@Repository()\\` | Register repository |\n| \\`@Autowired()\\` | Property injection |\n| \\`@Inject('token')\\` | Token-based injection |\n| \\`@Value('VAR')\\` | Inject env variable |\n\n${\n template === 'graphql'\n ? `### GraphQL\n| Decorator | Purpose |\n|-----------|---------|\n| \\`@Resolver()\\` | GraphQL resolver class |\n| \\`@Query()\\` | Query handler |\n| \\`@Mutation()\\` | Mutation handler |\n| \\`@Arg('name')\\` | Resolver argument |\n\n`\n : ''\n}${\n template === 'cqrs'\n ? `### Background Jobs\n| Decorator | Purpose |\n|-----------|---------|\n| \\`@Job('name')\\` | Queue job handler |\n| \\`@Process('queue')\\` | Queue processor |\n| \\`@Cron('0 * * * *')\\` | Cron schedule |\n| \\`@WsController()\\` | WebSocket controller |\n\n`\n : ''\n }## Common Pitfalls\n\n1. **Forgot to register module** — Add to \\`src/modules/index.ts\\` exports array\n2. **DI not working** — Ensure \\`reflect-metadata\\` is imported in \\`src/index.ts\\`\n3. **Tests failing randomly** — Missing \\`Container.reset()\\` in \\`beforeEach\\`\n4. **Routes not found** — Check controller path and module registration\n5. **HMR not working** — Verify \\`vite.config.ts\\` has \\`hmr: true\\`\n6. **Decorators not working** — Check \\`tsconfig.json\\` has \\`experimentalDecorators: true\\`\n7. **\\`config.get('YOUR_KEY')\\` returns \\`undefined\\`** — \\`src/index.ts\\` is missing \\`import './config'\\`. That side-effect import registers the env schema with kickjs (\\`loadEnv(envSchema)\\` runs at module load). Without it, \\`ConfigService\\` falls back to the base schema (\\`PORT\\`/\\`NODE_ENV\\`/\\`LOG_LEVEL\\` only) and every user-defined key reads as \\`undefined\\`. \\`@Value()\\` may *appear* to work because of a raw \\`process.env\\` fallback, but Zod coercion and schema defaults are silently skipped — investigate \\`src/index.ts\\` and \\`src/config/index.ts\\` first.\n\n## CLI Commands Reference\n\n| Command | Description |\n|---------|-------------|\n| \\`kick dev\\` | Dev server with HMR |\n| \\`kick dev:debug\\` | Dev server with debugger |\n| \\`kick build\\` | Production build |\n| \\`kick start\\` | Run production build |\n| \\`kick g module <names...>\\` | Generate one or more modules |\n| \\`kick g scaffold <name> <fields>\\` | Generate CRUD |\n| \\`kick g controller <name>\\` | Generate controller |\n| \\`kick g service <name>\\` | Generate service |\n| \\`kick g middleware <name>\\` | Generate middleware |\n| \\`kick add <package>\\` | Add KickJS package |\n| \\`kick add --list\\` | List available packages |\n| \\`kick rm module <names...>\\` | Remove one or more modules |\n\n> **Note:** When using \\`kick new\\` in scripts or CI, pass \\`-t\\` (or \\`--template\\`) and \\`-r\\` (or \\`--repo\\`) flags to bypass interactive prompts:\n> \\`\\`\\`bash\n> kick new my-api -t ddd -r prisma --pm ${pm} --no-git --no-install -f\n> \\`\\`\\`\n\n## Learn More\n\n- [KickJS Docs](https://forinda.github.io/kick-js/)\n- [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)\n- [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)\n- [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)\n- [Testing](https://forinda.github.io/kick-js/api/testing.html)\n`\n}\n","import { join, dirname } from 'node:path'\nimport { execSync } from 'node:child_process'\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { writeFileSafe } from '../utils/fs'\nimport {\n generatePackageJson,\n generateViteConfig,\n generateTsConfig,\n generatePrettierConfig,\n generateEditorConfig,\n generateGitIgnore,\n generateGitAttributes,\n generateEnv,\n generateEnvExample,\n generateVitestConfig,\n} from './templates/project-config'\nimport {\n generateEntryFile,\n generateEnvFile,\n generateModulesIndex,\n generateKickConfig,\n generateHelloService,\n generateHelloController,\n generateHelloModule,\n} from './templates/project-app'\nimport { generateReadme, generateClaude, generateAgents } from './templates/project-docs'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst cliPkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'))\nconst KICKJS_VERSION = `^${cliPkg.version}`\n\ntype ProjectTemplate = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\ninterface InitProjectOptions {\n name: string\n directory: string\n packageManager?: 'pnpm' | 'npm' | 'yarn'\n initGit?: boolean\n installDeps?: boolean\n template?: ProjectTemplate\n defaultRepo?: string\n packages?: string[]\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n const {\n name,\n directory,\n packageManager = 'pnpm',\n template = 'rest',\n defaultRepo = 'inmemory',\n packages = [],\n } = options\n const dir = directory\n\n const log = (msg: string) => console.log(` ${msg}`)\n\n console.log(`\\n Creating KickJS project: ${name}\\n`)\n\n // ── package.json — template-aware deps ────────────────────────────\n await writeFileSafe(\n join(dir, 'package.json'),\n generatePackageJson(name, template, KICKJS_VERSION, packages),\n )\n\n // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n await writeFileSafe(join(dir, 'vite.config.ts'), generateViteConfig())\n\n // ── tsconfig.json ───────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'tsconfig.json'), generateTsConfig())\n\n // ── .prettierrc ─────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.prettierrc'), generatePrettierConfig())\n\n // ── .editorconfig ─────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.editorconfig'), generateEditorConfig())\n\n // ── .gitignore ──────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.gitignore'), generateGitIgnore())\n\n // ── .gitattributes ────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.gitattributes'), generateGitAttributes())\n\n // ── .env ────────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, '.env'), generateEnv())\n\n await writeFileSafe(join(dir, '.env.example'), generateEnvExample())\n\n // ── src/config/index.ts — typed env schema (read by `kick typegen`) ─\n // Lives under `src/config/` so the framework's \"config\" concept has a\n // single, conventional home. Old projects with `src/env.ts` still\n // work — `detectEnvFile()` searches both locations.\n await writeFileSafe(join(dir, 'src/config/index.ts'), generateEnvFile())\n\n // ── src/index.ts — template-aware entry point ─────────────────────\n await writeFileSafe(\n join(dir, 'src/index.ts'),\n generateEntryFile(name, template, cliPkg.version, packages),\n )\n\n // ── src/modules/index.ts ────────────────────────────────────────────\n await writeFileSafe(join(dir, 'src/modules/index.ts'), generateModulesIndex())\n\n // ── src/modules/hello/ — sample module ─────────────────────────────\n await writeFileSafe(join(dir, 'src/modules/hello/hello.service.ts'), generateHelloService())\n await writeFileSafe(join(dir, 'src/modules/hello/hello.controller.ts'), generateHelloController())\n await writeFileSafe(join(dir, 'src/modules/hello/hello.module.ts'), generateHelloModule())\n\n // ── Template-specific files ─────────────────────────────────────────\n if (template === 'graphql') {\n await writeFileSafe(join(dir, 'src/resolvers/.gitkeep'), '')\n }\n\n // ── kick.config.ts — CLI configuration ─────────────────────────────\n await writeFileSafe(join(dir, 'kick.config.ts'), generateKickConfig(template, defaultRepo))\n\n // ── vitest.config.ts ────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'vitest.config.ts'), generateVitestConfig())\n\n // ── README.md ────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'README.md'), generateReadme(name, template, packageManager))\n\n // ── CLAUDE.md ────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'CLAUDE.md'), generateClaude(name, template, packageManager))\n\n // ── AGENTS.md ────────────────────────────────────────────────────────\n await writeFileSafe(join(dir, 'AGENTS.md'), generateAgents(name, template, packageManager))\n\n // ── Install Dependencies ────────────────────────────────────────────\n // Install BEFORE git init so the lockfile is included in the first commit.\n if (options.installDeps) {\n console.log(`\\n Installing dependencies with ${packageManager}...\\n`)\n try {\n execSync(`${packageManager} install`, { cwd: dir, stdio: 'inherit' })\n console.log('\\n Dependencies installed successfully!')\n } catch {\n console.log(`\\n Warning: ${packageManager} install failed. Run it manually.`)\n }\n }\n\n // ── Initial typegen ────────────────────────────────────────────────\n // Run typegen once so the freshly-scaffolded HelloController's\n // `Ctx<KickRoutes.HelloController['index']>` references resolve in\n // the user's editor immediately. Failures are non-fatal.\n try {\n const { runTypegen } = await import('../typegen')\n await runTypegen({ cwd: dir, allowDuplicates: true, silent: true })\n } catch {\n // First-run typegen errors are non-fatal — `kick dev` will retry.\n }\n\n // ── Git Init ─────────────────────────────────────────────────────────\n // Runs after install + typegen so lockfile and generated types are\n // included in the initial commit.\n if (options.initGit) {\n try {\n execSync('git init', { cwd: dir, stdio: 'pipe' })\n execSync('git branch -M main', { cwd: dir, stdio: 'pipe' })\n execSync('git add -A', { cwd: dir, stdio: 'pipe' })\n execSync('git commit -m \"chore: initial commit from kick new\"', {\n cwd: dir,\n stdio: 'pipe',\n })\n log('Git repository initialized')\n } catch {\n log('Warning: git init failed (git may not be installed)')\n }\n }\n\n console.log('\\n Project scaffolded successfully!')\n console.log()\n\n const needsCd = dir !== process.cwd()\n log('Next steps:')\n if (needsCd) log(` cd ${name}`)\n if (!options.installDeps) log(` ${packageManager} install`)\n\n const genHint: Record<string, string> = {\n rest: 'kick g module user',\n graphql: 'kick g resolver user',\n ddd: 'kick g module user --repo drizzle',\n cqrs: 'kick g module user --pattern cqrs',\n minimal: '# add your routes to src/index.ts',\n }\n log(` ${genHint[template] ?? genHint.rest}`)\n log(' kick dev')\n log('')\n log('Commands:')\n log(' kick dev Start dev server with Vite HMR')\n log(' kick build Production build via Vite')\n log(' kick start Run production build')\n log('')\n log('Generators:')\n log(' kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)')\n log(' kick g scaffold <n> <f..> CRUD module from field definitions')\n log(' kick g controller <name> Standalone controller')\n log(' kick g service <name> @Service() class')\n log(' kick g middleware <name> Express middleware')\n log(' kick g guard <name> Route guard (auth, roles, etc.)')\n log(' kick g adapter <name> AppAdapter with lifecycle hooks')\n log(' kick g dto <name> Zod DTO schema')\n if (template === 'graphql') log(' kick g resolver <name> GraphQL resolver')\n if (template === 'cqrs') log(' kick g job <name> Queue job processor')\n log(' kick g config Generate kick.config.ts')\n log('')\n log('Add packages:')\n log(' kick add <pkg> Install a KickJS package + peers')\n log(' kick add --list Show all available packages')\n log('')\n log('Available: auth, swagger, graphql, drizzle, prisma, ws,')\n log(' cron, queue, mailer, otel, multi-tenant, notifications, testing')\n log('')\n}\n","import { readFile, access } from 'node:fs/promises'\nimport { join } from 'node:path'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Project pattern — controls what generators produce and which deps are installed */\nexport type ProjectPattern = 'rest' | 'graphql' | 'ddd' | 'cqrs' | 'minimal'\n\n/** Built-in repository types with first-class code generation support */\nexport type BuiltinRepoType = 'drizzle' | 'inmemory' | 'prisma'\n\nexport const BUILTIN_REPO_TYPES: readonly string[] = ['drizzle', 'inmemory', 'prisma']\n\n/** Custom repository type — generates a stub with TODO markers */\nexport interface CustomRepoType {\n name: string\n}\n\n/** Repository type — built-in string or custom object */\nexport type RepoTypeConfig = BuiltinRepoType | CustomRepoType\n\n/**\n * Supported schema validators for `kick typegen` body/query/params\n * type extraction. Only `'zod'` ships built-in for now; other libraries\n * (Joi, Yup, JSON Schema) will be added later as the adapter system\n * grows. Set to `false` (or omit) to disable schema-driven body typing\n * entirely (the route entries will keep `body: unknown`).\n */\nexport type SchemaValidator = 'zod' | false\n\n/** Typegen settings — controls .kickjs/types/* generation */\nexport interface TypegenConfig {\n /**\n * Source directory to scan for controllers and decorators.\n * Defaults to `'src'`.\n */\n srcDir?: string\n /**\n * Output directory for generated `.d.ts` files.\n * Defaults to `'.kickjs/types'`.\n */\n outDir?: string\n /**\n * Schema validator used to derive `body` types from route metadata.\n *\n * - `'zod'` — emit `z.infer<typeof <importedSchema>>` for any schema\n * referenced as a named identifier in `@Get/@Post/...({ body, query, params })`.\n * - `false` — disable schema-driven body typing.\n *\n * Future: `'joi' | 'yup' | 'json-schema'` plus a `{ name; module }`\n * escape hatch for custom adapters.\n *\n * @default 'zod'\n */\n schemaValidator?: SchemaValidator\n /**\n * Path to the project's env schema file (relative to project root).\n * Must default-export a `defineEnv(...)` schema for typegen to emit\n * the typed `KickEnv` global registry.\n *\n * Set to `false` to disable env typing entirely.\n *\n * @default 'src/env.ts'\n */\n envFile?: string | false\n}\n\n/** Module generation settings — controls how `kick g module` produces code */\nexport interface ModuleConfig {\n /** Where modules live (default: 'src/modules') */\n dir?: string\n /**\n * Default repository implementation for generators.\n *\n * Built-in types (string): `'drizzle'`, `'inmemory'`, `'prisma'`\n * — generate fully working repository code.\n *\n * Custom types (object): `{ name: 'typeorm' }`\n * — generate a stub repository with TODO markers.\n *\n * @example\n * repo: 'prisma' // built-in\n * repo: { name: 'typeorm' } // custom\n */\n repo?: RepoTypeConfig\n /** Schema output directory (e.g. 'src/db/schema' for Drizzle, 'prisma/' for Prisma) */\n schemaDir?: string\n /**\n * Whether to pluralize module names in generated code.\n * When true (default), `kick g module user` creates `src/modules/users/`.\n * When false, it creates `src/modules/user/` and uses singular names throughout.\n */\n pluralize?: boolean\n /**\n * Import path for the Prisma generated client in `--repo prisma` templates.\n * Must resolve within `src/` for path alias compatibility.\n *\n * @default '@prisma/client' (Prisma 5/6)\n * @example\n * prismaClientPath: '@/generated/prisma/client' // Prisma 7+\n * prismaClientPath: './generated/prisma/client' // relative\n */\n prismaClientPath?: string\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /**\n * Project pattern — controls default generator behavior.\n * - 'rest' — Express + Swagger (default)\n * - 'graphql' — GraphQL + GraphiQL\n * - 'ddd' — Full DDD modules with use cases, entities, value objects\n * - 'cqrs' — CQRS with commands, queries, events, WebSocket + queue\n * - 'minimal' — Bare Express with no scaffolding\n */\n pattern?: ProjectPattern\n /**\n * Module generation settings — directory, repo type, pluralization, schema dir.\n *\n * @example\n * modules: {\n * dir: 'src/modules',\n * repo: 'prisma',\n * pluralize: false,\n * schemaDir: 'prisma/',\n * }\n */\n modules?: ModuleConfig\n\n // ── Backward-compatible top-level aliases (deprecated, use modules.* instead) ──\n /** @deprecated Use `modules.dir` instead */\n modulesDir?: string\n /** @deprecated Use `modules.repo` instead */\n defaultRepo?: RepoTypeConfig\n /** @deprecated Use `modules.schemaDir` instead */\n schemaDir?: string\n /** @deprecated Use `modules.pluralize` instead */\n pluralize?: boolean\n /**\n * Directories to copy to dist/ after build.\n * Useful for EJS templates, email templates, static assets, etc.\n *\n * @example\n * ```ts\n * copyDirs: [\n * 'src/views', // copies to dist/src/views\n * { src: 'src/views', dest: 'dist/views' }, // custom dest\n * 'src/emails',\n * ]\n * ```\n */\n copyDirs?: Array<string | { src: string; dest?: string }>\n /**\n * Typegen settings — controls `.kickjs/types/*` generation including\n * the schema validator used for body type extraction.\n *\n * @example\n * ```ts\n * typegen: {\n * schemaValidator: 'zod',\n * }\n * ```\n */\n typegen?: TypegenConfig\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\n/** Resolve module config with backward-compatible fallbacks from top-level fields */\nexport function resolveModuleConfig(config: KickConfig | null): ModuleConfig {\n if (!config) return {}\n const mc: ModuleConfig = {\n dir: config.modules?.dir ?? config.modulesDir,\n repo: config.modules?.repo ?? config.defaultRepo,\n schemaDir: config.modules?.schemaDir ?? config.schemaDir,\n pluralize: config.modules?.pluralize ?? config.pluralize,\n prismaClientPath: config.modules?.prismaClientPath,\n }\n\n // Warn if a string repo value isn't a known built-in\n if (mc.repo && typeof mc.repo === 'string' && !BUILTIN_REPO_TYPES.includes(mc.repo)) {\n console.warn(\n ` Warning: modules.repo '${mc.repo}' is not a built-in type (${BUILTIN_REPO_TYPES.join(', ')}).` +\n ` It will generate a stub repository. Use { name: '${mc.repo}' } to silence this warning.`,\n )\n }\n\n return mc\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n return mod.default ?? mod\n } catch (err) {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n"],"mappings":"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"}