@forinda/kickjs-cli 1.2.13 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,5 @@
1
1
  #!/usr/bin/env node
2
- var $t=Object.defineProperty;var s=(e,t)=>$t(e,"name",{value:t,configurable:!0});import{Command as No}from"commander";import{readFileSync as Yo}from"fs";import{dirname as Bo,join as Ho}from"path";import{fileURLToPath as Ko}from"url";import{resolve as te,basename as Ot}from"path";import{createInterface as It}from"readline";import{existsSync as St,readdirSync as Tt,rmSync as jt}from"fs";import{join as h,dirname as vt}from"path";import{execSync as V}from"child_process";import{readFileSync as Ct}from"fs";import{fileURLToPath as xt}from"url";import{writeFile as gt,mkdir as yt,access as ht,readFile as er}from"fs/promises";import{dirname as wt}from"path";var Se=!1;function v(e){Se=e}s(v,"setDryRun");async function l(e,t){Se||(await yt(wt(e),{recursive:!0}),await gt(e,t,"utf-8"))}s(l,"writeFileSafe");async function _(e){try{return await ht(e),!0}catch{return!1}}s(_,"fileExists");var kt=vt(xt(import.meta.url)),Z=JSON.parse(Ct(h(kt,"..","package.json"),"utf-8")),D=`^${Z.version}`;async function Te(e){let{name:t,directory:o,packageManager:r="pnpm",template:n="rest"}=e,i=o;console.log(`
3
- Creating KickJS project: ${t}
4
- `);let d={"@forinda/kickjs-core":D,"@forinda/kickjs-http":D,"@forinda/kickjs-config":D,express:"^5.1.0","reflect-metadata":"^0.2.2",zod:"^4.3.6",pino:"^10.3.1","pino-pretty":"^13.1.3"};if(n!=="minimal"&&(d["@forinda/kickjs-swagger"]=D,d["@forinda/kickjs-devtools"]=D),n==="graphql"&&(d["@forinda/kickjs-graphql"]=D,d.graphql="^16.11.0"),n==="cqrs"&&(d["@forinda/kickjs-queue"]=D,d["@forinda/kickjs-ws"]=D,d["@forinda/kickjs-otel"]=D),n==="ddd"&&(d["@forinda/kickjs-swagger"]=D),await l(h(i,"package.json"),JSON.stringify({name:t,version:Z.version,type:"module",scripts:{dev:"kick dev","dev:debug":"kick dev:debug",build:"kick build",start:"kick start",test:"vitest run","test:watch":"vitest",typecheck:"tsc --noEmit",lint:"eslint src/",format:"prettier --write src/"},dependencies:d,devDependencies:{"@forinda/kickjs-cli":D,"@swc/core":"^1.7.28","@types/express":"^5.0.6","@types/node":"^24.5.2","unplugin-swc":"^1.5.9",vite:"^7.3.1","vite-node":"^5.3.0",vitest:"^3.2.4",typescript:"^5.9.2",prettier:"^3.8.1"}},null,2)),await l(h(i,"vite.config.ts"),`import { defineConfig } from 'vite'
2
+ var Nt=Object.defineProperty;var s=(r,e)=>Nt(r,"name",{value:e,configurable:!0});import{Command as Co}from"commander";import{readFileSync as xo}from"fs";import{dirname as Ro,join as Do}from"path";import{fileURLToPath as bo}from"url";import{resolve as oe,basename as er}from"path";import{createInterface as tr}from"readline";import{existsSync as rr,readdirSync as or,rmSync as ir}from"fs";import{join as h,dirname as Yt}from"path";import{execSync as J}from"child_process";import{readFileSync as Jt}from"fs";import{fileURLToPath as Vt}from"url";import{writeFile as Wt,mkdir as Bt,access as Kt,readFile as jo}from"fs/promises";import{dirname as Ht}from"path";var Ee=!1;function x(r){Ee=r}s(x,"setDryRun");async function m(r,e){Ee||(await Bt(Ht(r),{recursive:!0}),await Wt(r,e,"utf-8"))}s(m,"writeFileSafe");async function A(r){try{return await Kt(r),!0}catch{return!1}}s(A,"fileExists");function Ue(r,e,t){let o={"@forinda/kickjs-core":t,"@forinda/kickjs-http":t,"@forinda/kickjs-config":t,express:"^5.1.0","reflect-metadata":"^0.2.2",zod:"^4.3.6",pino:"^10.3.1","pino-pretty":"^13.1.3"};return e!=="minimal"&&(o["@forinda/kickjs-swagger"]=t,o["@forinda/kickjs-devtools"]=t),e==="graphql"&&(o["@forinda/kickjs-graphql"]=t,o.graphql="^16.11.0"),e==="cqrs"&&(o["@forinda/kickjs-queue"]=t,o["@forinda/kickjs-ws"]=t,o["@forinda/kickjs-otel"]=t),e==="ddd"&&(o["@forinda/kickjs-swagger"]=t),JSON.stringify({name:r,version:t.replace("^",""),type:"module",scripts:{dev:"kick dev","dev:debug":"kick dev:debug",build:"kick build",start:"kick start",test:"vitest run","test:watch":"vitest",typecheck:"tsc --noEmit",lint:"eslint src/",format:"prettier --write src/"},dependencies:o,devDependencies:{"@forinda/kickjs-cli":t,"@swc/core":"^1.7.28","@types/express":"^5.0.6","@types/node":"^24.5.2","unplugin-swc":"^1.5.9",vite:"^7.3.1","vite-node":"^5.3.0",vitest:"^3.2.4",typescript:"^5.9.2",prettier:"^3.8.1"}},null,2)}s(Ue,"generatePackageJson");function ze(){return`import { defineConfig } from 'vite'
5
3
  import { resolve } from 'path'
6
4
  import swc from 'unplugin-swc'
7
5
 
@@ -27,7 +25,7 @@ export default defineConfig({
27
25
  },
28
26
  },
29
27
  })
30
- `),await l(h(i,"tsconfig.json"),JSON.stringify({compilerOptions:{target:"ES2022",module:"ESNext",moduleResolution:"bundler",lib:["ES2022"],types:["node","vite/client"],strict:!0,esModuleInterop:!0,skipLibCheck:!0,sourceMap:!0,declaration:!0,experimentalDecorators:!0,emitDecoratorMetadata:!0,outDir:"dist",rootDir:"src",paths:{"@/*":["./src/*"]}},include:["src"]},null,2)),await l(h(i,".prettierrc"),JSON.stringify({semi:!1,singleQuote:!0,trailingComma:"all",printWidth:100,tabWidth:2},null,2)),await l(h(i,".editorconfig"),`# https://editorconfig.org
28
+ `}s(ze,"generateViteConfig");function Me(){return JSON.stringify({compilerOptions:{target:"ES2022",module:"ESNext",moduleResolution:"bundler",lib:["ES2022"],types:["node","vite/client"],strict:!0,esModuleInterop:!0,skipLibCheck:!0,sourceMap:!0,declaration:!0,experimentalDecorators:!0,emitDecoratorMetadata:!0,outDir:"dist",rootDir:"src",paths:{"@/*":["./src/*"]}},include:["src"]},null,2)}s(Me,"generateTsConfig");function qe(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:"all",printWidth:100,tabWidth:2},null,2)}s(qe,"generatePrettierConfig");function _e(){return`# https://editorconfig.org
31
29
  root = true
32
30
 
33
31
  [*]
@@ -40,13 +38,13 @@ insert_final_newline = true
40
38
 
41
39
  [*.md]
42
40
  trim_trailing_whitespace = false
43
- `),await l(h(i,".gitignore"),`node_modules/
41
+ `}s(_e,"generateEditorConfig");function Ge(){return`node_modules/
44
42
  dist/
45
43
  .env
46
44
  coverage/
47
45
  .DS_Store
48
46
  *.tsbuildinfo
49
- `),await l(h(i,".gitattributes"),`# Auto-detect text files and normalise line endings to LF
47
+ `}s(Ge,"generateGitIgnore");function Qe(){return`# Auto-detect text files and normalise line endings to LF
50
48
  * text=auto eol=lf
51
49
 
52
50
  # Explicitly mark generated / binary files
@@ -64,45 +62,11 @@ coverage/
64
62
  pnpm-lock.yaml -diff linguist-generated
65
63
  yarn.lock -diff linguist-generated
66
64
  package-lock.json -diff linguist-generated
67
- `),await l(h(i,".env"),`PORT=3000
65
+ `}s(Qe,"generateGitAttributes");function Fe(){return`PORT=3000
68
66
  NODE_ENV=development
69
- `),await l(h(i,".env.example"),`PORT=3000
67
+ `}s(Fe,"generateEnv");function Le(){return`PORT=3000
70
68
  NODE_ENV=development
71
- `),await l(h(i,"src/index.ts"),Rt(t,n)),await l(h(i,"src/modules/index.ts"),`import type { AppModuleClass } from '@forinda/kickjs-core'
72
-
73
- export const modules: AppModuleClass[] = []
74
- `),n==="graphql"&&await l(h(i,"src/resolvers/.gitkeep"),""),await l(h(i,"kick.config.ts"),`import { defineConfig } from '@forinda/kickjs-cli'
75
-
76
- export default defineConfig({
77
- pattern: '${n}',
78
- modulesDir: 'src/modules',
79
- defaultRepo: 'inmemory',
80
-
81
- commands: [
82
- {
83
- name: 'test',
84
- description: 'Run tests with Vitest',
85
- steps: 'npx vitest run',
86
- },
87
- {
88
- name: 'format',
89
- description: 'Format code with Prettier',
90
- steps: 'npx prettier --write src/',
91
- },
92
- {
93
- name: 'format:check',
94
- description: 'Check formatting without writing',
95
- steps: 'npx prettier --check src/',
96
- },
97
- {
98
- name: 'check',
99
- description: 'Run typecheck + format check',
100
- steps: ['npx tsc --noEmit', 'npx prettier --check src/'],
101
- aliases: ['verify', 'ci'],
102
- },
103
- ],
104
- })
105
- `),await l(h(i,"vitest.config.ts"),`import { defineConfig } from 'vitest/config'
69
+ `}s(Le,"generateEnvExample");function Ne(){return`import { defineConfig } from 'vitest/config'
106
70
  import swc from 'unplugin-swc'
107
71
 
108
72
  export default defineConfig({
@@ -113,12 +77,7 @@ export default defineConfig({
113
77
  include: ['src/**/*.test.ts'],
114
78
  },
115
79
  })
116
- `),await l(h(i,"README.md"),Dt(t,n,r)),e.initGit)try{V("git init",{cwd:i,stdio:"pipe"}),V("git add -A",{cwd:i,stdio:"pipe"}),V('git commit -m "chore: initial commit from kick new"',{cwd:i,stdio:"pipe"}),console.log(" Git repository initialized")}catch{console.log(" Warning: git init failed (git may not be installed)")}if(e.installDeps){console.log(`
117
- Installing dependencies with ${r}...
118
- `);try{V(`${r} install`,{cwd:i,stdio:"inherit"}),console.log(`
119
- Dependencies installed successfully!`)}catch{console.log(`
120
- Warning: ${r} install failed. Run it manually.`)}}console.log(`
121
- Project scaffolded successfully!`),console.log();let c=i!==process.cwd();console.log(" Next steps:"),c&&console.log(` cd ${t}`),e.installDeps||console.log(` ${r} install`);let a={rest:"kick g module user",graphql:"kick g resolver user",ddd:"kick g module user --repo drizzle",cqrs:"kick g module user --pattern cqrs",minimal:"# add your routes to src/index.ts"};console.log(` ${a[n]??a.rest}`),console.log(" kick dev"),console.log(),console.log(" Commands:"),console.log(" kick dev Start dev server with Vite HMR"),console.log(" kick build Production build via Vite"),console.log(" kick start Run production build"),console.log(),console.log(" Generators:"),console.log(" kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)"),console.log(" kick g scaffold <n> <f..> CRUD module from field definitions"),console.log(" kick g controller <name> Standalone controller"),console.log(" kick g service <name> @Service() class"),console.log(" kick g middleware <name> Express middleware"),console.log(" kick g guard <name> Route guard (auth, roles, etc.)"),console.log(" kick g adapter <name> AppAdapter with lifecycle hooks"),console.log(" kick g dto <name> Zod DTO schema"),n==="graphql"&&console.log(" kick g resolver <name> GraphQL resolver"),n==="cqrs"&&console.log(" kick g job <name> Queue job processor"),console.log(" kick g config Generate kick.config.ts"),console.log(),console.log(" Add packages:"),console.log(" kick add <pkg> Install a KickJS package + peers"),console.log(" kick add --list Show all available packages"),console.log(),console.log(" Available: auth, swagger, graphql, drizzle, prisma, ws,"),console.log(" cron, queue, mailer, otel, multi-tenant, notifications, testing"),console.log()}s(Te,"initProject");function Rt(e,t){switch(t){case"graphql":return`import 'reflect-metadata'
80
+ `}s(Ne,"generateVitestConfig");function We(r,e,t){switch(e){case"graphql":return`import 'reflect-metadata'
122
81
  import { bootstrap } from '@forinda/kickjs-http'
123
82
  import { DevToolsAdapter } from '@forinda/kickjs-devtools'
124
83
  import { GraphQLAdapter } from '@forinda/kickjs-graphql'
@@ -150,10 +109,10 @@ import { modules } from './modules'
150
109
  bootstrap({
151
110
  modules,
152
111
  adapters: [
153
- new OtelAdapter({ serviceName: '${e}' }),
112
+ new OtelAdapter({ serviceName: '${r}' }),
154
113
  new DevToolsAdapter(),
155
114
  new SwaggerAdapter({
156
- info: { title: '${e}', version: '${Z.version}' },
115
+ info: { title: '${r}', version: '${t}' },
157
116
  }),
158
117
  // Uncomment for WebSocket support:
159
118
  // new WsAdapter(),
@@ -179,18 +138,55 @@ bootstrap({
179
138
  adapters: [
180
139
  new DevToolsAdapter(),
181
140
  new SwaggerAdapter({
182
- info: { title: '${e}', version: '${Z.version}' },
141
+ info: { title: '${r}', version: '${t}' },
183
142
  }),
184
143
  ],
185
144
  })
186
- `}}s(Rt,"getEntryFile");function Dt(e,t,o){let r={rest:"REST API",graphql:"GraphQL API",ddd:"Domain-Driven Design",cqrs:"CQRS + Event-Driven",minimal:"Minimal"},n=["@forinda/kickjs-core","@forinda/kickjs-http","@forinda/kickjs-config"];return t!=="minimal"&&n.push("@forinda/kickjs-swagger","@forinda/kickjs-devtools"),t==="graphql"&&n.push("@forinda/kickjs-graphql"),t==="cqrs"&&n.push("@forinda/kickjs-queue","@forinda/kickjs-ws","@forinda/kickjs-otel"),`# ${e}
145
+ `}}s(We,"generateEntryFile");function Be(){return`import type { AppModuleClass } from '@forinda/kickjs-core'
146
+
147
+ export const modules: AppModuleClass[] = []
148
+ `}s(Be,"generateModulesIndex");function Ke(r,e="inmemory"){return`import { defineConfig } from '@forinda/kickjs-cli'
149
+
150
+ export default defineConfig({
151
+ pattern: '${r}',
152
+ modules: {
153
+ dir: 'src/modules',
154
+ repo: '${e}',
155
+ pluralize: true,
156
+ },
157
+
158
+ commands: [
159
+ {
160
+ name: 'test',
161
+ description: 'Run tests with Vitest',
162
+ steps: 'npx vitest run',
163
+ },
164
+ {
165
+ name: 'format',
166
+ description: 'Format code with Prettier',
167
+ steps: 'npx prettier --write src/',
168
+ },
169
+ {
170
+ name: 'format:check',
171
+ description: 'Check formatting without writing',
172
+ steps: 'npx prettier --check src/',
173
+ },
174
+ {
175
+ name: 'check',
176
+ description: 'Run typecheck + format check',
177
+ steps: ['npx tsc --noEmit', 'npx prettier --check src/'],
178
+ aliases: ['verify', 'ci'],
179
+ },
180
+ ],
181
+ })
182
+ `}s(Ke,"generateKickConfig");function He(r,e,t){let o={rest:"REST API",graphql:"GraphQL API",ddd:"Domain-Driven Design",cqrs:"CQRS + Event-Driven",minimal:"Minimal"},n=["@forinda/kickjs-core","@forinda/kickjs-http","@forinda/kickjs-config"];return e!=="minimal"&&n.push("@forinda/kickjs-swagger","@forinda/kickjs-devtools"),e==="graphql"&&n.push("@forinda/kickjs-graphql"),e==="cqrs"&&n.push("@forinda/kickjs-queue","@forinda/kickjs-ws","@forinda/kickjs-otel"),`# ${r}
187
183
 
188
- A **${r[t]??"REST API"}** built with [KickJS](https://forinda.github.io/kick-js/) \u2014 a decorator-driven Node.js framework on Express 5 and TypeScript.
184
+ A **${o[e]??"REST API"}** built with [KickJS](https://forinda.github.io/kick-js/) \u2014 a decorator-driven Node.js framework on Express 5 and TypeScript.
189
185
 
190
186
  ## Getting Started
191
187
 
192
188
  \`\`\`bash
193
- ${o} install
189
+ ${t} install
194
190
  kick dev
195
191
  \`\`\`
196
192
 
@@ -201,7 +197,7 @@ kick dev
201
197
  | \`kick dev\` | Start dev server with Vite HMR |
202
198
  | \`kick build\` | Production build |
203
199
  | \`kick start\` | Run production build |
204
- | \`${o} run test\` | Run tests with Vitest |
200
+ | \`${t} run test\` | Run tests with Vitest |
205
201
  | \`kick g module <name>\` | Generate a DDD module |
206
202
  | \`kick g scaffold <name> <fields...>\` | Generate CRUD from field definitions |
207
203
  | \`kick add <package>\` | Add a KickJS package |
@@ -246,9 +242,561 @@ Copy \`.env.example\` to \`.env\` and configure:
246
242
 
247
243
  - [KickJS Documentation](https://forinda.github.io/kick-js/)
248
244
  - [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
249
- `}s(Dt,"generateReadme");function re(e,t){let o=It({input:process.stdin,output:process.stdout}),r=t?` (${t})`:"";return new Promise(n=>{o.question(` ${e}${r}: `,i=>{o.close(),n(i.trim()||t||"")})})}s(re,"ask");async function je(e,t,o=0){console.log(` ${e}`);for(let i=0;i<t.length;i++)console.log(` ${i===o?">":" "} ${i+1}. ${t[i]}`);let r=await re("Choose",String(o+1)),n=parseInt(r,10)-1;return t[n]??t[o]}s(je,"choose");async function oe(e,t=!0){let r=await re(`${e} (${t?"Y/n":"y/N"})`);return r?r.toLowerCase().startsWith("y"):t}s(oe,"confirm");function Pe(e){e.command("new [name]").alias("init").description('Create a new KickJS project (use "." for current directory)').option("-d, --directory <dir>","Target directory (defaults to project name)").option("--pm <manager>","Package manager: pnpm | npm | yarn").option("--git","Initialize git repository").option("--no-git","Skip git initialization").option("--install","Install dependencies after scaffolding").option("--no-install","Skip dependency installation").option("-f, --force","Remove existing files without prompting").option("-t, --template <type>","Project template: rest | graphql | ddd | cqrs | minimal").action(async(t,o)=>{console.log(),t||(t=await re("Project name","my-api"));let r;if(t==="."?(r=te("."),t=Ot(r)):r=te(o.directory||t),St(r)){let a=Tt(r);if(a.length>0){if(o.force)console.log(` Clearing existing files in ${r}...
250
- `);else{console.log(` Directory "${t}" is not empty:`);let p=a.slice(0,5);for(let u of p)console.log(` - ${u}`);if(a.length>5&&console.log(` ... and ${a.length-5} more`),console.log(),!await oe("Remove all existing files and proceed?",!1)){console.log(` Aborted.
251
- `);return}}for(let p of a)jt(te(r,p),{recursive:!0,force:!0})}}let n=o.template;n||(n=await je("Project template:",["REST API (Express + Swagger)","GraphQL API (GraphQL + GraphiQL)","DDD (Domain-Driven Design modules)","CQRS (Commands, Queries, Events + WS/Queue)","Minimal (bare Express)"],0),n={"REST API (Express + Swagger)":"rest","GraphQL API (GraphQL + GraphiQL)":"graphql","DDD (Domain-Driven Design modules)":"ddd","CQRS (Commands, Queries, Events + WS/Queue)":"cqrs","Minimal (bare Express)":"minimal"}[n]??"rest");let i=o.pm;i||(i=await je("Package manager:",["pnpm","npm","yarn"],0));let d;o.git===void 0?d=await oe("Initialize git repository?",!0):d=o.git;let c;o.install===void 0?c=await oe("Install dependencies?",!0):c=o.install,await Te({name:t,directory:r,packageManager:i,initGit:d,installDeps:c,template:n})})}s(Pe,"registerInitCommand");import{resolve as z}from"path";import{join as Ce}from"path";import{createInterface as Pt}from"readline";function f(e){return e.replace(/[-_\s]+(.)?/g,(t,o)=>o?o.toUpperCase():"").replace(/^(.)/,t=>t.toUpperCase())}s(f,"toPascalCase");function x(e){let t=f(e);return t.charAt(0).toLowerCase()+t.slice(1)}s(x,"toCamelCase");function $(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}s($,"toKebabCase");function j(e){return e.endsWith("s")?e:e.endsWith("x")||e.endsWith("z")||e.endsWith("sh")||e.endsWith("ch")?e+"es":e.endsWith("y")&&!/[aeiou]y$/.test(e)?e.slice(0,-1)+"ies":e+"s"}s(j,"pluralize");function X(e){return e.endsWith("s")?e:e.endsWith("x")||e.endsWith("z")||e.endsWith("sh")||e.endsWith("ch")?e+"es":e.endsWith("y")&&!/[aeiou]y$/i.test(e)?e.slice(0,-1)+"ies":e+"s"}s(X,"pluralizePascal");import{readFile as Et,writeFile as At}from"fs/promises";function Ee(e,t,o){let r={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},n={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`};return{repoClass:r[o]??r.inmemory,repoFile:n[o]??n.inmemory}}s(Ee,"repoMaps");function ie(e,t,o,r){let{repoClass:n,repoFile:i}=Ee(e,t,r);return`/**
245
+ `}s(He,"generateReadme");function Ye(r,e,t){return`# CLAUDE.md \u2014 ${r} Development Guide
246
+
247
+ ## Project Overview
248
+
249
+ This is a **${{rest:"REST API",graphql:"GraphQL API",ddd:"Domain-Driven Design",cqrs:"CQRS + Event-Driven",minimal:"Minimal Express"}[e]??"REST API"}** application built with [KickJS](https://forinda.github.io/kick-js/) \u2014 a decorator-driven Node.js framework on Express 5 and TypeScript.
250
+
251
+ ## Quick Commands
252
+
253
+ \`\`\`bash
254
+ ${t} install # Install dependencies
255
+ kick dev # Start dev server with HMR
256
+ kick build # Production build via Vite
257
+ kick start # Run production build
258
+ ${t} run test # Run tests with Vitest
259
+ ${t} run typecheck # TypeScript type checking
260
+ ${t} run format # Format code with Prettier
261
+ \`\`\`
262
+
263
+ ## Project Structure
264
+
265
+ \`\`\`
266
+ src/
267
+ \u251C\u2500\u2500 index.ts # Application bootstrap
268
+ \u251C\u2500\u2500 modules/ # Feature modules (DDD/CQRS pattern)
269
+ \u2502 \u2514\u2500\u2500 index.ts # Module registry
270
+ ${e==="graphql"?`\u251C\u2500\u2500 resolvers/ # GraphQL resolvers
271
+ `:""}\u2514\u2500\u2500 ...
272
+ \`\`\`
273
+
274
+ ## Package Manager
275
+
276
+ - Always use **${t}** for this project
277
+ - Run \`${t} install\` to sync dependencies
278
+ - Never mix package managers (npm/yarn/pnpm)
279
+
280
+ ## Code Style
281
+
282
+ - **Prettier** \u2014 no semicolons, single quotes, trailing commas, 100 char width
283
+ - **TypeScript strict mode** \u2014 all types required
284
+ - Format before committing: \`${t} run format\`
285
+ - Type check with: \`${t} run typecheck\`
286
+
287
+ ## Key Patterns
288
+
289
+ ### Controllers
290
+
291
+ Use decorators to define routes:
292
+
293
+ \`\`\`ts
294
+ import { Controller, Get, Post, RequestContext } from '@forinda/kickjs-http'
295
+
296
+ @Controller('/users')
297
+ export class UserController {
298
+ @Get('/')
299
+ async findAll(ctx: RequestContext) {
300
+ return ctx.json({ users: [] })
301
+ }
302
+
303
+ @Post('/')
304
+ async create(ctx: RequestContext) {
305
+ const data = ctx.body
306
+ return ctx.created({ user: data })
307
+ }
308
+ }
309
+ \`\`\`
310
+
311
+ ### Services
312
+
313
+ Inject dependencies with \`@Service()\` and \`@Autowired()\`:
314
+
315
+ \`\`\`ts
316
+ import { Service, Autowired } from '@forinda/kickjs-core'
317
+
318
+ @Service()
319
+ export class UserService {
320
+ @Autowired()
321
+ private userRepository!: UserRepository
322
+
323
+ async findAll() {
324
+ return this.userRepository.findAll()
325
+ }
326
+ }
327
+ \`\`\`
328
+
329
+ ### Modules
330
+
331
+ Register controllers and providers in modules:
332
+
333
+ \`\`\`ts
334
+ import { Module } from '@forinda/kickjs-core'
335
+ import { UserController } from './user.controller'
336
+ import { UserService } from './user.service'
337
+
338
+ @Module({
339
+ controllers: [UserController],
340
+ providers: [UserService],
341
+ })
342
+ export class UserModule {}
343
+ \`\`\`
344
+
345
+ ### RequestContext
346
+
347
+ Every controller method receives \`ctx: RequestContext\`:
348
+
349
+ \`\`\`ts
350
+ ctx.body // Request body (parsed JSON)
351
+ ctx.params // Route params
352
+ ctx.query // Query string
353
+ ctx.headers // Request headers
354
+ ctx.requestId // Auto-generated request ID
355
+ ctx.session // Session data (if session middleware enabled)
356
+ ctx.file // Uploaded file (single)
357
+ ctx.files // Uploaded files (multiple)
358
+
359
+ // Pagination helpers
360
+ ctx.qs(config) // Parse query with filters/sort/pagination
361
+ ctx.paginate(handler) // Auto-paginated response
362
+
363
+ // Response helpers
364
+ ctx.json(data) // 200 OK with JSON
365
+ ctx.created(data) // 201 Created
366
+ ctx.noContent() // 204 No Content
367
+ ctx.notFound() // 404 Not Found
368
+ ctx.badRequest(msg) // 400 Bad Request
369
+ \`\`\`
370
+
371
+ ## CLI Generators
372
+
373
+ Generate code with the \`kick\` CLI:
374
+
375
+ \`\`\`bash
376
+ kick g module <name> # Full module (controller, service, DTOs, repo)
377
+ kick g scaffold <name> <fields> # CRUD module from field definitions
378
+ kick g controller <name> # Standalone controller
379
+ kick g service <name> # Service class
380
+ kick g middleware <name> # Express middleware
381
+ kick g guard <name> # Route guard (auth, roles)
382
+ kick g adapter <name> # AppAdapter with lifecycle hooks
383
+ kick g dto <name> # Zod DTO schema
384
+ ${e==="graphql"?`kick g resolver <name> # GraphQL resolver
385
+ `:""}${e==="cqrs"?`kick g job <name> # Queue job processor
386
+ `:""}\`\`\`
387
+
388
+ ## Adding Packages
389
+
390
+ \`\`\`bash
391
+ kick add auth # JWT, API key, OAuth strategies
392
+ kick add swagger # OpenAPI docs from decorators
393
+ kick add ws # WebSocket support
394
+ kick add queue # Background jobs (BullMQ/RabbitMQ/Kafka)
395
+ kick add mailer # Email (SMTP, Resend, SES)
396
+ kick add cron # Scheduled tasks
397
+ kick add prisma # Prisma ORM adapter
398
+ kick add drizzle # Drizzle ORM adapter
399
+ kick add otel # OpenTelemetry tracing
400
+ kick add --list # Show all available packages
401
+ \`\`\`
402
+
403
+ ## Environment Configuration
404
+
405
+ Edit \`.env\` for environment variables. Access them with \`@Value()\` decorator:
406
+
407
+ \`\`\`ts
408
+ import { Value } from '@forinda/kickjs-config'
409
+
410
+ @Service()
411
+ export class ApiService {
412
+ @Value('API_KEY')
413
+ private apiKey!: string
414
+
415
+ @Value('PORT', 3000) // With default
416
+ private port!: number
417
+ }
418
+ \`\`\`
419
+
420
+ Or use \`ConfigService\`:
421
+
422
+ \`\`\`ts
423
+ import { ConfigService } from '@forinda/kickjs-config'
424
+
425
+ @Service()
426
+ export class AppService {
427
+ @Autowired()
428
+ private config!: ConfigService
429
+
430
+ getPort() {
431
+ return this.config.get('PORT', 3000)
432
+ }
433
+ }
434
+ \`\`\`
435
+
436
+ ## Testing
437
+
438
+ Tests live in \`src/**/*.test.ts\`:
439
+
440
+ \`\`\`ts
441
+ import { describe, it, expect, beforeEach } from 'vitest'
442
+ import { Container } from '@forinda/kickjs-core'
443
+ import { createTestApp } from '@forinda/kickjs-testing'
444
+
445
+ describe('UserController', () => {
446
+ beforeEach(() => Container.reset())
447
+
448
+ it('should return users', async () => {
449
+ const app = await createTestApp([UserModule])
450
+ const res = await app.get('/users')
451
+ expect(res.status).toBe(200)
452
+ })
453
+ })
454
+ \`\`\`
455
+
456
+ Run tests:
457
+ - \`${t} run test\` \u2014 run all tests
458
+ - \`${t} run test:watch\` \u2014 watch mode
459
+
460
+ ## Decorators Reference
461
+
462
+ ### Route Decorators
463
+ - \`@Controller('/path')\` \u2014 define controller prefix
464
+ - \`@Get('/'), @Post('/'), @Put('/'), @Delete('/'), @Patch('/')\` \u2014 HTTP methods
465
+ - \`@Middleware(fn)\` \u2014 attach middleware
466
+ - \`@Public()\` \u2014 skip authentication (requires @forinda/kickjs-auth)
467
+ - \`@Roles('admin', 'user')\` \u2014 role-based access control
468
+
469
+ ### DI Decorators
470
+ - \`@Module({ controllers, providers, imports })\` \u2014 define module
471
+ - \`@Service()\` \u2014 singleton service (DI-registered)
472
+ - \`@Repository()\` \u2014 repository (semantic alias for @Service)
473
+ - \`@Autowired()\` \u2014 property injection
474
+ - \`@Inject('token')\` \u2014 token-based injection
475
+ - \`@Value('ENV_VAR')\` \u2014 inject config value
476
+
477
+ ${e==="cqrs"?"### CQRS/Event Decorators\n- `@Job('job-name')` \u2014 queue job handler\n- `@Process('queue-name')` \u2014 queue processor\n- `@Cron('0 * * * *')` \u2014 cron schedule\n- `@WsController('/path')` \u2014 WebSocket controller\n- `@Subscribe('event')` \u2014 WebSocket event handler\n\n":""}${e==="graphql"?"### GraphQL Decorators\n- `@Resolver()` \u2014 GraphQL resolver\n- `@Query()` \u2014 GraphQL query\n- `@Mutation()` \u2014 GraphQL mutation\n- `@Arg('name')` \u2014 resolver argument\n\n":""}## Common Pitfalls
478
+
479
+ 1. **Decorators fire at import time** \u2014 make sure to import module classes in \`src/modules/index.ts\`
480
+ 2. **Tests need \`Container.reset()\`** \u2014 call in \`beforeEach\` to isolate DI state
481
+ 3. **Always use \`ctx.body\`** \u2014 never \`req.body\` directly
482
+ 4. **DI requires \`reflect-metadata\`** \u2014 already imported in \`src/index.ts\`
483
+ 5. **Vite HMR requires proper cleanup** \u2014 adapters should implement \`shutdown()\`
484
+
485
+ ## Learn More
486
+
487
+ - [KickJS Documentation](https://forinda.github.io/kick-js/)
488
+ - [API Reference](https://forinda.github.io/kick-js/api/)
489
+ - [CLI Commands](https://forinda.github.io/kick-js/guide/cli-commands.html)
490
+ - [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
491
+ `}s(Ye,"generateClaude");function Je(r,e,t){return`# AGENTS.md \u2014 AI Agent Guide for ${r}
492
+
493
+ This guide helps AI agents (Claude, Copilot, etc.) work effectively on this KickJS application.
494
+
495
+ ## Before You Start
496
+
497
+ 1. Read \`CLAUDE.md\` for project conventions and commands
498
+ 2. Run \`${t} install\` to install dependencies
499
+ 3. Run \`kick dev\` to verify the app starts
500
+ 4. Read the [KickJS documentation](https://forinda.github.io/kick-js/) for framework details
501
+
502
+ ## Where to Find Things
503
+
504
+ ### Application Structure
505
+
506
+ | What | Where |
507
+ |------|-------|
508
+ | Entry point | \`src/index.ts\` |
509
+ | Module registry | \`src/modules/index.ts\` |
510
+ | Feature modules | \`src/modules/<module-name>/\` |
511
+ ${e==="graphql"?"| GraphQL resolvers | `src/resolvers/` |\n":""}| Environment config | \`.env\` |
512
+ | TypeScript config | \`tsconfig.json\` |
513
+ | Vite config (HMR) | \`vite.config.ts\` |
514
+ | Vitest config | \`vitest.config.ts\` |
515
+ | Prettier config | \`.prettierrc\` |
516
+ | CLI config | \`kick.config.ts\` |
517
+
518
+ ### Module Pattern (${e.toUpperCase()})
519
+
520
+ Each module in \`src/modules/<name>/\` typically contains:
521
+
522
+ ${e==="ddd"?`\`\`\`
523
+ <name>/
524
+ \u251C\u2500\u2500 <name>.controller.ts # HTTP routes (@Controller)
525
+ \u251C\u2500\u2500 <name>.service.ts # Business logic (@Service)
526
+ \u251C\u2500\u2500 <name>.repository.ts # Data access (@Repository)
527
+ \u251C\u2500\u2500 <name>.dto.ts # Request/response schemas (Zod)
528
+ \u251C\u2500\u2500 <name>.entity.ts # Domain entity (optional)
529
+ \u2514\u2500\u2500 <name>.module.ts # Module definition (@Module)
530
+ \`\`\`
531
+ `:e==="cqrs"?`\`\`\`
532
+ <name>/
533
+ \u251C\u2500\u2500 commands/ # Write operations
534
+ \u2502 \u251C\u2500\u2500 create-<name>.command.ts
535
+ \u2502 \u2514\u2500\u2500 create-<name>.handler.ts
536
+ \u251C\u2500\u2500 queries/ # Read operations
537
+ \u2502 \u251C\u2500\u2500 get-<name>.query.ts
538
+ \u2502 \u2514\u2500\u2500 get-<name>.handler.ts
539
+ \u251C\u2500\u2500 events/ # Domain events
540
+ \u2502 \u2514\u2500\u2500 <name>-created.event.ts
541
+ \u251C\u2500\u2500 <name>.controller.ts # HTTP routes
542
+ \u251C\u2500\u2500 <name>.repository.ts # Data access
543
+ \u2514\u2500\u2500 <name>.module.ts # Module definition
544
+ \`\`\`
545
+ `:e==="graphql"?"```\nresolvers/\n\u251C\u2500\u2500 <name>.resolver.ts # @Resolver, @Query, @Mutation\n\u251C\u2500\u2500 <name>.types.ts # GraphQL type definitions\n\u2514\u2500\u2500 <name>.service.ts # Business logic\n```\n":e==="rest"?`\`\`\`
546
+ <name>/
547
+ \u251C\u2500\u2500 <name>.controller.ts # HTTP routes (@Controller)
548
+ \u251C\u2500\u2500 <name>.service.ts # Business logic (@Service)
549
+ \u251C\u2500\u2500 <name>.dto.ts # Request/response schemas (Zod)
550
+ \u2514\u2500\u2500 <name>.module.ts # Module definition (@Module)
551
+ \`\`\`
552
+ `:"```\nsrc/\n\u251C\u2500\u2500 index.ts # Add routes here\n\u2514\u2500\u2500 ... # Custom structure\n```\n"}
553
+
554
+ ## Checklist: Adding a Feature
555
+
556
+ ### New Module (Recommended)
557
+
558
+ Use the CLI generator for consistency:
559
+
560
+ \`\`\`bash
561
+ kick g module <name> # Generate full module
562
+ # or
563
+ kick g scaffold <name> <fields> # Generate CRUD from fields
564
+ \`\`\`
565
+
566
+ Then:
567
+ - [ ] Review generated files in \`src/modules/<name>/\`
568
+ - [ ] Verify module is registered in \`src/modules/index.ts\`
569
+ - [ ] Update DTOs in \`<name>.dto.ts\` if needed
570
+ - [ ] Implement business logic in \`<name>.service.ts\`
571
+ - [ ] Run \`kick dev\` to test with HMR
572
+ - [ ] Write tests in \`<name>.test.ts\`
573
+
574
+ ### Manual Controller
575
+
576
+ If not using generators:
577
+
578
+ - [ ] Create \`src/modules/<name>/<name>.controller.ts\`
579
+ - [ ] Add \`@Controller('/path')\` decorator
580
+ - [ ] Add route handlers with \`@Get()\`, \`@Post()\`, etc.
581
+ - [ ] Create module file with \`@Module({ controllers: [NameController] })\`
582
+ - [ ] Register module in \`src/modules/index.ts\`
583
+ - [ ] Test with \`kick dev\`
584
+
585
+ ### Manual Service
586
+
587
+ - [ ] Create \`src/modules/<name>/<name>.service.ts\`
588
+ - [ ] Add \`@Service()\` decorator
589
+ - [ ] Inject dependencies with \`@Autowired()\`
590
+ - [ ] Register in module \`providers\` array
591
+ - [ ] Write unit tests
592
+
593
+ ### New Middleware
594
+
595
+ - [ ] Create \`src/middleware/<name>.middleware.ts\`
596
+ - [ ] Export middleware function (Express format)
597
+ - [ ] Register in \`src/index.ts\` or attach to routes with \`@Middleware()\`
598
+ - [ ] Test with sample requests
599
+
600
+ ### Adding a Package
601
+
602
+ Use \`kick add\` to install KickJS packages with correct peer dependencies:
603
+
604
+ - [ ] Run \`kick add <package>\` (e.g., \`kick add auth\`)
605
+ - [ ] Follow package-specific setup in terminal output
606
+ - [ ] Update \`src/index.ts\` to register adapter (if needed)
607
+ - [ ] Configure environment variables in \`.env\`
608
+ - [ ] Test integration with \`kick dev\`
609
+
610
+ ## Common Tasks
611
+
612
+ ### Generate CRUD Module
613
+
614
+ \`\`\`bash
615
+ kick g scaffold user name:string email:string age:number
616
+ \`\`\`
617
+
618
+ This creates a full CRUD module with:
619
+ - Controller with GET, POST, PUT, DELETE routes
620
+ - Service with business logic
621
+ - Repository with data access
622
+ - DTOs with Zod validation
623
+
624
+ ### Add Authentication
625
+
626
+ \`\`\`bash
627
+ kick add auth
628
+ \`\`\`
629
+
630
+ Then configure in \`src/index.ts\`:
631
+
632
+ \`\`\`ts
633
+ import { AuthAdapter, JwtStrategy } from '@forinda/kickjs-auth'
634
+
635
+ bootstrap({
636
+ modules,
637
+ adapters: [
638
+ new AuthAdapter({
639
+ strategies: [new JwtStrategy({ secret: process.env.JWT_SECRET! })],
640
+ }),
641
+ ],
642
+ })
643
+ \`\`\`
644
+
645
+ ### Add Database (Prisma)
646
+
647
+ \`\`\`bash
648
+ kick add prisma
649
+ ${t} install prisma @prisma/client
650
+ npx prisma init
651
+ # Edit prisma/schema.prisma
652
+ npx prisma migrate dev --name init
653
+ kick g module user --repo prisma
654
+ \`\`\`
655
+
656
+ ### Add WebSocket Support
657
+
658
+ \`\`\`bash
659
+ kick add ws
660
+ \`\`\`
661
+
662
+ Then add adapter in \`src/index.ts\`:
663
+
664
+ \`\`\`ts
665
+ import { WsAdapter } from '@forinda/kickjs-ws'
666
+
667
+ bootstrap({
668
+ modules,
669
+ adapters: [new WsAdapter()],
670
+ })
671
+ \`\`\`
672
+
673
+ Create WebSocket controller:
674
+
675
+ \`\`\`bash
676
+ kick g controller chat --ws
677
+ \`\`\`
678
+
679
+ ## Testing Guidelines
680
+
681
+ All tests use Vitest:
682
+
683
+ \`\`\`ts
684
+ import { describe, it, expect, beforeEach } from 'vitest'
685
+ import { Container } from '@forinda/kickjs-core'
686
+ import { createTestApp } from '@forinda/kickjs-testing'
687
+
688
+ describe('UserController', () => {
689
+ beforeEach(() => {
690
+ Container.reset() // Important: isolate DI state
691
+ })
692
+
693
+ it('should return users', async () => {
694
+ const app = await createTestApp([UserModule])
695
+ const res = await app.get('/users')
696
+
697
+ expect(res.status).toBe(200)
698
+ expect(res.body).toHaveProperty('users')
699
+ })
700
+ })
701
+ \`\`\`
702
+
703
+ Run tests:
704
+ - \`${t} run test\` \u2014 run all tests once
705
+ - \`${t} run test:watch\` \u2014 watch mode
706
+ - Individual file: \`${t} run test src/modules/user/user.test.ts\`
707
+
708
+ ## Environment Variables
709
+
710
+ Managed via \`.env\` file. Access with:
711
+
712
+ 1. **@Value() decorator** (recommended):
713
+ \`\`\`ts
714
+ @Value('DATABASE_URL')
715
+ private dbUrl!: string
716
+ \`\`\`
717
+
718
+ 2. **ConfigService** (for dynamic access):
719
+ \`\`\`ts
720
+ @Autowired()
721
+ private config!: ConfigService
722
+
723
+ const port = this.config.get('PORT', 3000)
724
+ \`\`\`
725
+
726
+ 3. **Direct access** (avoid in app code):
727
+ \`\`\`ts
728
+ process.env.PORT
729
+ \`\`\`
730
+
731
+ ## Key Decorators
732
+
733
+ ### HTTP Routes
734
+ | Decorator | Purpose |
735
+ |-----------|---------|
736
+ | \`@Controller('/path')\` | Define route prefix |
737
+ | \`@Get('/'), @Post('/')\` | HTTP method handlers |
738
+ | \`@Middleware(fn)\` | Attach middleware |
739
+ | \`@Public()\` | Skip auth (requires auth adapter) |
740
+ | \`@Roles('admin')\` | Role-based access |
741
+
742
+ ### Dependency Injection
743
+ | Decorator | Purpose |
744
+ |-----------|---------|
745
+ | \`@Module({})\` | Define feature module |
746
+ | \`@Service()\` | Register singleton service |
747
+ | \`@Repository()\` | Register repository |
748
+ | \`@Autowired()\` | Property injection |
749
+ | \`@Inject('token')\` | Token-based injection |
750
+ | \`@Value('VAR')\` | Inject env variable |
751
+
752
+ ${e==="graphql"?"### 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":""}${e==="cqrs"?"### 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":""}## Common Pitfalls
753
+
754
+ 1. **Forgot to register module** \u2014 Add to \`src/modules/index.ts\` exports array
755
+ 2. **DI not working** \u2014 Ensure \`reflect-metadata\` is imported in \`src/index.ts\`
756
+ 3. **Tests failing randomly** \u2014 Missing \`Container.reset()\` in \`beforeEach\`
757
+ 4. **Routes not found** \u2014 Check controller path and module registration
758
+ 5. **HMR not working** \u2014 Verify \`vite.config.ts\` has \`hmr: true\`
759
+ 6. **Decorators not working** \u2014 Check \`tsconfig.json\` has \`experimentalDecorators: true\`
760
+
761
+ ## CLI Commands Reference
762
+
763
+ | Command | Description |
764
+ |---------|-------------|
765
+ | \`kick dev\` | Dev server with HMR |
766
+ | \`kick dev:debug\` | Dev server with debugger |
767
+ | \`kick build\` | Production build |
768
+ | \`kick start\` | Run production build |
769
+ | \`kick g module <names...>\` | Generate one or more modules |
770
+ | \`kick g scaffold <name> <fields>\` | Generate CRUD |
771
+ | \`kick g controller <name>\` | Generate controller |
772
+ | \`kick g service <name>\` | Generate service |
773
+ | \`kick g middleware <name>\` | Generate middleware |
774
+ | \`kick add <package>\` | Add KickJS package |
775
+ | \`kick add --list\` | List available packages |
776
+ | \`kick rm module <names...>\` | Remove one or more modules |
777
+
778
+ > **Note:** When using \`kick new\` in scripts or CI, pass \`-t\` (or \`--template\`) and \`-r\` (or \`--repo\`) flags to bypass interactive prompts:
779
+ > \`\`\`bash
780
+ > kick new my-api -t ddd -r prisma --pm ${t} --no-git --no-install -f
781
+ > \`\`\`
782
+
783
+ ## Learn More
784
+
785
+ - [KickJS Docs](https://forinda.github.io/kick-js/)
786
+ - [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
787
+ - [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
788
+ - [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
789
+ - [Testing](https://forinda.github.io/kick-js/api/testing.html)
790
+ `}s(Je,"generateAgents");var Zt=Yt(Vt(import.meta.url)),Ve=JSON.parse(Jt(h(Zt,"..","package.json"),"utf-8")),Xt=`^${Ve.version}`;async function Ze(r){let{name:e,directory:t,packageManager:o="pnpm",template:n="rest",defaultRepo:i="inmemory"}=r,c=t,d=s(l=>console.log(` ${l}`),"log");if(console.log(`
791
+ Creating KickJS project: ${e}
792
+ `),await m(h(c,"package.json"),Ue(e,n,Xt)),await m(h(c,"vite.config.ts"),ze()),await m(h(c,"tsconfig.json"),Me()),await m(h(c,".prettierrc"),qe()),await m(h(c,".editorconfig"),_e()),await m(h(c,".gitignore"),Ge()),await m(h(c,".gitattributes"),Qe()),await m(h(c,".env"),Fe()),await m(h(c,".env.example"),Le()),await m(h(c,"src/index.ts"),We(e,n,Ve.version)),await m(h(c,"src/modules/index.ts"),Be()),n==="graphql"&&await m(h(c,"src/resolvers/.gitkeep"),""),await m(h(c,"kick.config.ts"),Ke(n,i)),await m(h(c,"vitest.config.ts"),Ne()),await m(h(c,"README.md"),He(e,n,o)),await m(h(c,"CLAUDE.md"),Ye(e,n,o)),await m(h(c,"AGENTS.md"),Je(e,n,o)),r.initGit)try{J("git init",{cwd:c,stdio:"pipe"}),J("git branch -M main",{cwd:c,stdio:"pipe"}),J("git add -A",{cwd:c,stdio:"pipe"}),J('git commit -m "chore: initial commit from kick new"',{cwd:c,stdio:"pipe"}),d("Git repository initialized")}catch{d("Warning: git init failed (git may not be installed)")}if(r.installDeps){console.log(`
793
+ Installing dependencies with ${o}...
794
+ `);try{J(`${o} install`,{cwd:c,stdio:"inherit"}),console.log(`
795
+ Dependencies installed successfully!`)}catch{console.log(`
796
+ Warning: ${o} install failed. Run it manually.`)}}console.log(`
797
+ Project scaffolded successfully!`),console.log();let a=c!==process.cwd();d("Next steps:"),a&&d(` cd ${e}`),r.installDeps||d(` ${o} install`);let p={rest:"kick g module user",graphql:"kick g resolver user",ddd:"kick g module user --repo drizzle",cqrs:"kick g module user --pattern cqrs",minimal:"# add your routes to src/index.ts"};d(` ${p[n]??p.rest}`),d(" kick dev"),d(""),d("Commands:"),d(" kick dev Start dev server with Vite HMR"),d(" kick build Production build via Vite"),d(" kick start Run production build"),d(""),d("Generators:"),d(" kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)"),d(" kick g scaffold <n> <f..> CRUD module from field definitions"),d(" kick g controller <name> Standalone controller"),d(" kick g service <name> @Service() class"),d(" kick g middleware <name> Express middleware"),d(" kick g guard <name> Route guard (auth, roles, etc.)"),d(" kick g adapter <name> AppAdapter with lifecycle hooks"),d(" kick g dto <name> Zod DTO schema"),n==="graphql"&&d(" kick g resolver <name> GraphQL resolver"),n==="cqrs"&&d(" kick g job <name> Queue job processor"),d(" kick g config Generate kick.config.ts"),d(""),d("Add packages:"),d(" kick add <pkg> Install a KickJS package + peers"),d(" kick add --list Show all available packages"),d(""),d("Available: auth, swagger, graphql, drizzle, prisma, ws,"),d(" cron, queue, mailer, otel, multi-tenant, notifications, testing"),d("")}s(Ze,"initProject");function te(r,e){let t=tr({input:process.stdin,output:process.stdout}),o=e?` (${e})`:"";return new Promise(n=>{t.question(` ${r}${o}: `,i=>{t.close(),n(i.trim()||e||"")})})}s(te,"ask");async function ie(r,e,t=0){console.log(` ${r}`);for(let i=0;i<e.length;i++)console.log(` ${i===t?">":" "} ${i+1}. ${e[i]}`);let o=await te("Choose",String(t+1)),n=parseInt(o,10)-1;return e[n]??e[t]}s(ie,"choose");async function se(r,e=!0){let o=await te(`${r} (${e?"Y/n":"y/N"})`);return o?o.toLowerCase().startsWith("y"):e}s(se,"confirm");function Xe(r){r.command("new [name]").alias("init").description('Create a new KickJS project (use "." for current directory)').option("-d, --directory <dir>","Target directory (defaults to project name)").option("--pm <manager>","Package manager: pnpm | npm | yarn").option("--git","Initialize git repository").option("--no-git","Skip git initialization").option("--install","Install dependencies after scaffolding").option("--no-install","Skip dependency installation").option("-f, --force","Remove existing files without prompting").option("-t, --template <type>","Project template: rest | graphql | ddd | cqrs | minimal").option("-r, --repo <type>","Default repository: prisma | drizzle | inmemory | custom").action(async(e,t)=>{console.log(),e||(e=await te("Project name","my-api"));let o;if(e==="."?(o=oe("."),e=er(o)):o=oe(t.directory||e),rr(o)){let p=or(o);if(p.length>0){if(t.force)console.log(` Clearing existing files in ${o}...
798
+ `);else{console.log(` Directory "${e}" is not empty:`);let l=p.slice(0,5);for(let g of l)console.log(` - ${g}`);if(p.length>5&&console.log(` ... and ${p.length-5} more`),console.log(),!await se("Remove all existing files and proceed?",!1)){console.log(` Aborted.
799
+ `);return}}for(let l of p)ir(oe(o,l),{recursive:!0,force:!0})}}let n=t.template;n||(n=await ie("Project template:",["REST API (Express + Swagger)","GraphQL API (GraphQL + GraphiQL)","DDD (Domain-Driven Design modules)","CQRS (Commands, Queries, Events + WS/Queue)","Minimal (bare Express)"],0),n={"REST API (Express + Swagger)":"rest","GraphQL API (GraphQL + GraphiQL)":"graphql","DDD (Domain-Driven Design modules)":"ddd","CQRS (Commands, Queries, Events + WS/Queue)":"cqrs","Minimal (bare Express)":"minimal"}[n]??"rest");let i=t.pm;i||(i=await ie("Package manager:",["pnpm","npm","yarn"],0));let c=t.repo;if(!c){let p=await ie("Default repository/ORM:",["Prisma","Drizzle","In-Memory","Custom (specify later)"],0);c={Prisma:"prisma",Drizzle:"drizzle","In-Memory":"inmemory","Custom (specify later)":"custom"}[p]??"inmemory",c==="custom"&&(c=await te("Custom repository name","custom"))}let d;t.git===void 0?d=await se("Initialize git repository?",!0):d=t.git;let a;t.install===void 0?a=await se("Install dependencies?",!0):a=t.install,await Ze({name:e,directory:o,packageManager:i,initGit:d,installDeps:a,template:n,defaultRepo:c})})}s(Xe,"registerInitCommand");import{resolve as Y}from"path";import{join as Pe}from"path";import{createInterface as ar}from"readline";function $(r){return r.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():"").replace(/^(.)/,e=>e.toUpperCase())}s($,"toPascalCase");function R(r){let e=$(r);return e.charAt(0).toLowerCase()+e.slice(1)}s(R,"toCamelCase");function f(r){return r.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}s(f,"toKebabCase");function T(r){return r.endsWith("s")?r:r.endsWith("x")||r.endsWith("z")||r.endsWith("sh")||r.endsWith("ch")?r+"es":r.endsWith("y")&&!/[aeiou]y$/.test(r)?r.slice(0,-1)+"ies":r+"s"}s(T,"pluralize");function re(r){return r.endsWith("s")?r:r.endsWith("x")||r.endsWith("z")||r.endsWith("sh")||r.endsWith("ch")?r+"es":r.endsWith("y")&&!/[aeiou]y$/i.test(r)?r.slice(0,-1)+"ies":r+"s"}s(re,"pluralizePascal");import{readFile as cr,writeFile as dr}from"fs/promises";var sr={inmemory:"in-memory",drizzle:"Drizzle",prisma:"Prisma"};function tt(r){return r.charAt(0).toUpperCase()+r.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}s(tt,"toPascalRepoType");function nr(r){return r.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}s(nr,"toKebabRepoType");function et(r){return sr[r]??tt(r)}s(et,"repoLabel");function rt(r,e,t){let o={inmemory:`InMemory${r}Repository`,drizzle:`Drizzle${r}Repository`,prisma:`Prisma${r}Repository`},n={inmemory:`in-memory-${e}`,drizzle:`drizzle-${e}`,prisma:`prisma-${e}`};return{repoClass:o[t]??`${tt(t)}${r}Repository`,repoFile:n[t]??`${nr(t)}-${e}`}}s(rt,"repoMaps");function ne(r){let{pascal:e,kebab:t,plural:o="",repo:n}=r,{repoClass:i,repoFile:c}=rt(e,t,n);return`/**
252
800
  * ${e} Module
253
801
  *
254
802
  * Self-contained feature module following Domain-Driven Design (DDD).
@@ -258,12 +806,12 @@ Copy \`.env.example\` to \`.env\` and configure:
258
806
  * presentation/ \u2014 HTTP controllers (entry points)
259
807
  * application/ \u2014 Use cases (orchestration) and DTOs (validation)
260
808
  * domain/ \u2014 Entities, value objects, repository interfaces, domain services
261
- * infrastructure/ \u2014 Repository implementations (in-memory, Drizzle, Prisma, etc.)
809
+ * infrastructure/ \u2014 Repository implementations (currently ${et(n)})
262
810
  */
263
811
  import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'
264
812
  import { buildRoutes } from '@forinda/kickjs-http'
265
813
  import { ${e.toUpperCase()}_REPOSITORY } from './domain/repositories/${t}.repository'
266
- import { ${n} } from './infrastructure/repositories/${i}.repository'
814
+ import { ${i} } from './infrastructure/repositories/${c}.repository'
267
815
  import { ${e}Controller } from './presentation/${t}.controller'
268
816
 
269
817
  // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
@@ -276,11 +824,11 @@ export class ${e}Module implements AppModule {
276
824
  /**
277
825
  * Register module dependencies in the DI container.
278
826
  * Bind repository interface tokens to their implementations here.
279
- * To swap implementations (e.g. in-memory -> Drizzle), change the factory target.
827
+ * Currently wired to ${et(n)}. To swap implementations, change the factory target.
280
828
  */
281
829
  register(container: Container): void {
282
830
  container.registerFactory(${e.toUpperCase()}_REPOSITORY, () =>
283
- container.resolve(${n}),
831
+ container.resolve(${i}),
284
832
  )
285
833
  }
286
834
 
@@ -297,7 +845,7 @@ export class ${e}Module implements AppModule {
297
845
  }
298
846
  }
299
847
  }
300
- `}s(ie,"generateModuleIndex");function ne(e,t,o,r){let{repoClass:n,repoFile:i}=Ee(e,t,r);return`/**
848
+ `}s(ne,"generateModuleIndex");function ae(r){let{pascal:e,kebab:t,plural:o="",repo:n}=r,{repoClass:i,repoFile:c}=rt(e,t,n);return`/**
301
849
  * ${e} Module
302
850
  *
303
851
  * REST module with a flat folder structure.
@@ -307,13 +855,13 @@ export class ${e}Module implements AppModule {
307
855
  * ${t}.controller.ts \u2014 HTTP routes (CRUD)
308
856
  * ${t}.service.ts \u2014 Business logic
309
857
  * ${t}.repository.ts \u2014 Repository interface
310
- * ${i}.repository.ts \u2014 Repository implementation
858
+ * ${c}.repository.ts \u2014 Repository implementation
311
859
  * dtos/ \u2014 Request/response schemas
312
860
  */
313
861
  import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'
314
862
  import { buildRoutes } from '@forinda/kickjs-http'
315
863
  import { ${e.toUpperCase()}_REPOSITORY } from './${t}.repository'
316
- import { ${n} } from './${i}.repository'
864
+ import { ${i} } from './${c}.repository'
317
865
  import { ${e}Controller } from './${t}.controller'
318
866
 
319
867
  // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
@@ -322,7 +870,7 @@ import.meta.glob(['./**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'
322
870
  export class ${e}Module implements AppModule {
323
871
  register(container: Container): void {
324
872
  container.registerFactory(${e.toUpperCase()}_REPOSITORY, () =>
325
- container.resolve(${n}),
873
+ container.resolve(${i}),
326
874
  )
327
875
  }
328
876
 
@@ -334,7 +882,7 @@ export class ${e}Module implements AppModule {
334
882
  }
335
883
  }
336
884
  }
337
- `}s(ne,"generateRestModuleIndex");function se(e,t,o){return`import { type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'
885
+ `}s(ae,"generateRestModuleIndex");function ce(r){let{pascal:e,kebab:t,plural:o=""}=r;return`import { type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'
338
886
  import { buildRoutes } from '@forinda/kickjs-http'
339
887
  import { ${e}Controller } from './${t}.controller'
340
888
 
@@ -347,12 +895,12 @@ export class ${e}Module implements AppModule {
347
895
  }
348
896
  }
349
897
  }
350
- `}s(se,"generateMinimalModuleIndex");function ae(e,t,o,r){return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
898
+ `}s(ce,"generateMinimalModuleIndex");function de(r){let{pascal:e,kebab:t,plural:o="",pluralPascal:n=""}=r;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
351
899
  import type { RequestContext } from '@forinda/kickjs-http'
352
900
  import { ApiTags } from '@forinda/kickjs-swagger'
353
901
  import { Create${e}UseCase } from '../application/use-cases/create-${t}.use-case'
354
902
  import { Get${e}UseCase } from '../application/use-cases/get-${t}.use-case'
355
- import { List${r}UseCase } from '../application/use-cases/list-${o}.use-case'
903
+ import { List${n}UseCase } from '../application/use-cases/list-${o}.use-case'
356
904
  import { Update${e}UseCase } from '../application/use-cases/update-${t}.use-case'
357
905
  import { Delete${e}UseCase } from '../application/use-cases/delete-${t}.use-case'
358
906
  import { create${e}Schema } from '../application/dtos/create-${t}.dto'
@@ -363,7 +911,7 @@ import { ${e.toUpperCase()}_QUERY_CONFIG } from '../constants'
363
911
  export class ${e}Controller {
364
912
  @Autowired() private create${e}UseCase!: Create${e}UseCase
365
913
  @Autowired() private get${e}UseCase!: Get${e}UseCase
366
- @Autowired() private list${r}UseCase!: List${r}UseCase
914
+ @Autowired() private list${n}UseCase!: List${n}UseCase
367
915
  @Autowired() private update${e}UseCase!: Update${e}UseCase
368
916
  @Autowired() private delete${e}UseCase!: Delete${e}UseCase
369
917
 
@@ -372,7 +920,7 @@ export class ${e}Controller {
372
920
  @ApiQueryParams(${e.toUpperCase()}_QUERY_CONFIG)
373
921
  async list(ctx: RequestContext) {
374
922
  return ctx.paginate(
375
- (parsed) => this.list${r}UseCase.execute(parsed),
923
+ (parsed) => this.list${n}UseCase.execute(parsed),
376
924
  ${e.toUpperCase()}_QUERY_CONFIG,
377
925
  )
378
926
  }
@@ -406,7 +954,7 @@ export class ${e}Controller {
406
954
  ctx.noContent()
407
955
  }
408
956
  }
409
- `}s(ae,"generateController");function de(e,t,o,r){let n=e.charAt(0).toLowerCase()+e.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
957
+ `}s(de,"generateController");function pe(r){let{pascal:e,kebab:t,plural:o="",pluralPascal:n=""}=r,i=e.charAt(0).toLowerCase()+e.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
410
958
  import type { RequestContext } from '@forinda/kickjs-http'
411
959
  import { ApiTags } from '@forinda/kickjs-swagger'
412
960
  import { ${e}Service } from './${t}.service'
@@ -416,14 +964,14 @@ import { ${e.toUpperCase()}_QUERY_CONFIG } from './${t}.constants'
416
964
 
417
965
  @Controller()
418
966
  export class ${e}Controller {
419
- @Autowired() private ${n}Service!: ${e}Service
967
+ @Autowired() private ${i}Service!: ${e}Service
420
968
 
421
969
  @Get('/')
422
970
  @ApiTags('${e}')
423
971
  @ApiQueryParams(${e.toUpperCase()}_QUERY_CONFIG)
424
972
  async list(ctx: RequestContext) {
425
973
  return ctx.paginate(
426
- (parsed) => this.${n}Service.findPaginated(parsed),
974
+ (parsed) => this.${i}Service.findPaginated(parsed),
427
975
  ${e.toUpperCase()}_QUERY_CONFIG,
428
976
  )
429
977
  }
@@ -431,7 +979,7 @@ export class ${e}Controller {
431
979
  @Get('/:id')
432
980
  @ApiTags('${e}')
433
981
  async getById(ctx: RequestContext) {
434
- const result = await this.${n}Service.findById(ctx.params.id)
982
+ const result = await this.${i}Service.findById(ctx.params.id)
435
983
  if (!result) return ctx.notFound('${e} not found')
436
984
  ctx.json(result)
437
985
  }
@@ -439,50 +987,32 @@ export class ${e}Controller {
439
987
  @Post('/', { body: create${e}Schema, name: 'Create${e}' })
440
988
  @ApiTags('${e}')
441
989
  async create(ctx: RequestContext) {
442
- const result = await this.${n}Service.create(ctx.body)
990
+ const result = await this.${i}Service.create(ctx.body)
443
991
  ctx.created(result)
444
992
  }
445
993
 
446
994
  @Put('/:id', { body: update${e}Schema, name: 'Update${e}' })
447
995
  @ApiTags('${e}')
448
996
  async update(ctx: RequestContext) {
449
- const result = await this.${n}Service.update(ctx.params.id, ctx.body)
997
+ const result = await this.${i}Service.update(ctx.params.id, ctx.body)
450
998
  ctx.json(result)
451
999
  }
452
1000
 
453
1001
  @Delete('/:id')
454
1002
  @ApiTags('${e}')
455
1003
  async remove(ctx: RequestContext) {
456
- await this.${n}Service.delete(ctx.params.id)
1004
+ await this.${i}Service.delete(ctx.params.id)
457
1005
  ctx.noContent()
458
1006
  }
459
1007
  }
460
- `}s(de,"generateRestController");function ce(e){return`import type { QueryParamsConfig } from '@forinda/kickjs-core'
1008
+ `}s(pe,"generateRestController");function le(r){let{pascal:e}=r;return`import type { QueryParamsConfig } from '@forinda/kickjs-core'
461
1009
 
462
1010
  export const ${e.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
463
1011
  filterable: ['name'],
464
1012
  sortable: ['name', 'createdAt'],
465
1013
  searchable: ['name'],
466
1014
  }
467
- `}s(ce,"generateConstants");function pe(e,t){return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
468
- // TODO: Import your schema table and reference actual columns for type safety
469
- // import { ${t}s } from '@/db/schema'
470
-
471
- export const ${e.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {
472
- columns: {
473
- // Replace with actual Drizzle Column references for type-safe filtering:
474
- // name: ${t}s.name,
475
- // status: ${t}s.status,
476
- },
477
- sortable: {
478
- // name: ${t}s.name,
479
- // createdAt: ${t}s.createdAt,
480
- },
481
- searchColumns: [
482
- // ${t}s.name,
483
- ],
484
- }
485
- `}s(pe,"generateDrizzleConstants");function M(e,t){return`import { z } from 'zod'
1015
+ `}s(le,"generateConstants");function U(r){let{pascal:e,kebab:t}=r;return`import { z } from 'zod'
486
1016
 
487
1017
  /**
488
1018
  * Create ${e} DTO \u2014 Zod schema for validating POST request bodies.
@@ -498,20 +1028,20 @@ export const create${e}Schema = z.object({
498
1028
  })
499
1029
 
500
1030
  export type Create${e}DTO = z.infer<typeof create${e}Schema>
501
- `}s(M,"generateCreateDTO");function b(e,t){return`import { z } from 'zod'
1031
+ `}s(U,"generateCreateDTO");function z(r){let{pascal:e,kebab:t}=r;return`import { z } from 'zod'
502
1032
 
503
1033
  export const update${e}Schema = z.object({
504
1034
  name: z.string().min(1).max(200).optional(),
505
1035
  })
506
1036
 
507
1037
  export type Update${e}DTO = z.infer<typeof update${e}Schema>
508
- `}s(b,"generateUpdateDTO");function Q(e,t){return`export interface ${e}ResponseDTO {
1038
+ `}s(z,"generateUpdateDTO");function M(r){let{pascal:e,kebab:t}=r;return`export interface ${e}ResponseDTO {
509
1039
  id: string
510
1040
  name: string
511
1041
  createdAt: string
512
1042
  updatedAt: string
513
1043
  }
514
- `}s(Q,"generateResponseDTO");function me(e,t,o,r){return[{file:`create-${t}.use-case.ts`,content:`/**
1044
+ `}s(M,"generateResponseDTO");function me(r){let{pascal:e,kebab:t,plural:o="",pluralPascal:n=""}=r;return[{file:`create-${t}.use-case.ts`,content:`/**
515
1045
  * Create ${e} Use Case
516
1046
  *
517
1047
  * Application layer \u2014 orchestrates a single business operation.
@@ -552,7 +1082,7 @@ import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domai
552
1082
  import type { ParsedQuery } from '@forinda/kickjs-http'
553
1083
 
554
1084
  @Service()
555
- export class List${r}UseCase {
1085
+ export class List${n}UseCase {
556
1086
  constructor(
557
1087
  @Inject(${e.toUpperCase()}_REPOSITORY) private readonly repo: I${e}Repository,
558
1088
  ) {}
@@ -589,7 +1119,7 @@ export class Delete${e}UseCase {
589
1119
  await this.repo.delete(id)
590
1120
  }
591
1121
  }
592
- `}]}s(me,"generateUseCases");function G(e,t,o="../../application/dtos"){return`/**
1122
+ `}]}s(me,"generateUseCases");function q(r){let{pascal:e,kebab:t,dtoPrefix:o="../../application/dtos"}=r;return`/**
593
1123
  * ${e} Repository Interface
594
1124
  *
595
1125
  * Defines the contract for data access.
@@ -613,7 +1143,7 @@ export interface I${e}Repository {
613
1143
  }
614
1144
 
615
1145
  export const ${e.toUpperCase()}_REPOSITORY = Symbol('I${e}Repository')
616
- `}s(G,"generateRepositoryInterface");function F(e,t,o="../../domain/repositories",r="../../application/dtos"){return`/**
1146
+ `}s(q,"generateRepositoryInterface");function _(r){let{pascal:e,kebab:t,repoPrefix:o="../../domain/repositories",dtoPrefix:n="../../application/dtos"}=r;return`/**
617
1147
  * In-Memory ${e} Repository
618
1148
  *
619
1149
  * Implements the repository interface using a Map.
@@ -626,9 +1156,9 @@ import { randomUUID } from 'node:crypto'
626
1156
  import { Repository, HttpException } from '@forinda/kickjs-core'
627
1157
  import type { ParsedQuery } from '@forinda/kickjs-http'
628
1158
  import type { I${e}Repository } from '${o}/${t}.repository'
629
- import type { ${e}ResponseDTO } from '${r}/${t}-response.dto'
630
- import type { Create${e}DTO } from '${r}/create-${t}.dto'
631
- import type { Update${e}DTO } from '${r}/update-${t}.dto'
1159
+ import type { ${e}ResponseDTO } from '${n}/${t}-response.dto'
1160
+ import type { Create${e}DTO } from '${n}/create-${t}.dto'
1161
+ import type { Update${e}DTO } from '${n}/update-${t}.dto'
632
1162
 
633
1163
  @Repository()
634
1164
  export class InMemory${e}Repository implements I${e}Repository {
@@ -668,166 +1198,81 @@ export class InMemory${e}Repository implements I${e}Repository {
668
1198
  return updated
669
1199
  }
670
1200
 
671
- async delete(id: string): Promise<void> {
672
- if (!this.store.has(id)) throw HttpException.notFound('${e} not found')
673
- this.store.delete(id)
674
- }
675
- }
676
- `}s(F,"generateInMemoryRepository");function L(e,t,o="../../domain/repositories",r="../../application/dtos"){return`/**
677
- * Drizzle ${e} Repository
678
- *
679
- * Implements the repository interface using Drizzle ORM.
680
- * Uses buildFromColumns() with Column objects for type-safe query building.
681
- *
682
- * TODO: Update the schema import to match your Drizzle schema file.
683
- * TODO: Replace DRIZZLE_DB injection token with your actual database token.
684
- *
685
- * @Repository() registers this class in the DI container as a singleton.
686
- */
687
- import { eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc, count, sql } from 'drizzle-orm'
688
- import { Repository, HttpException, Inject } from '@forinda/kickjs-core'
689
- import { DRIZZLE_DB, DrizzleQueryAdapter } from '@forinda/kickjs-drizzle'
690
- import type { ParsedQuery } from '@forinda/kickjs-http'
691
- import type { I${e}Repository } from '${o}/${t}.repository'
692
- import type { ${e}ResponseDTO } from '${r}/${t}-response.dto'
693
- import type { Create${e}DTO } from '${r}/create-${t}.dto'
694
- import type { Update${e}DTO } from '${r}/update-${t}.dto'
695
- import { ${e.toUpperCase()}_QUERY_CONFIG } from '../../constants'
696
-
697
- // TODO: Import your Drizzle schema table \u2014 e.g.:
698
- // import { ${t}s } from '@/db/schema'
699
-
700
- const queryAdapter = new DrizzleQueryAdapter({
701
- eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc,
702
- })
703
-
704
- @Repository()
705
- export class Drizzle${e}Repository implements I${e}Repository {
706
- constructor(@Inject(DRIZZLE_DB) private db: any) {}
707
-
708
- async findById(id: string): Promise<${e}ResponseDTO | null> {
709
- // TODO: Implement with Drizzle
710
- // const row = this.db.select().from(${t}s).where(eq(${t}s.id, id)).get()
711
- // return row ?? null
712
- throw new Error('Drizzle ${e} repository not yet implemented \u2014 update schema imports and queries')
713
- }
714
-
715
- async findAll(): Promise<${e}ResponseDTO[]> {
716
- // TODO: Implement with Drizzle
717
- // return this.db.select().from(${t}s).all()
718
- throw new Error('Drizzle ${e} repository not yet implemented')
719
- }
720
-
721
- async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
722
- // TODO: Use buildFromColumns() with your query config for type-safe filtering
723
- // const query = queryAdapter.buildFromColumns(parsed, ${e.toUpperCase()}_QUERY_CONFIG)
724
- //
725
- // const data = this.db
726
- // .select().from(${t}s).$dynamic()
727
- // .where(query.where).orderBy(...query.orderBy)
728
- // .limit(query.limit).offset(query.offset).all()
729
- //
730
- // const totalResult = this.db
731
- // .select({ count: count() }).from(${t}s)
732
- // .$dynamic().where(query.where).get()
733
- //
734
- // return { data, total: totalResult?.count ?? 0 }
735
- throw new Error('Drizzle ${e} repository not yet implemented')
736
- }
737
-
738
- async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
739
- // TODO: Implement with Drizzle
740
- // return this.db.insert(${t}s).values(dto).returning().get()
741
- throw new Error('Drizzle ${e} repository not yet implemented')
742
- }
743
-
744
- async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
745
- // TODO: Implement with Drizzle
746
- // const row = this.db.update(${t}s).set(dto).where(eq(${t}s.id, id)).returning().get()
747
- // if (!row) throw HttpException.notFound('${e} not found')
748
- // return row
749
- throw new Error('Drizzle ${e} repository not yet implemented')
750
- }
751
-
752
- async delete(id: string): Promise<void> {
753
- // TODO: Implement with Drizzle
754
- // this.db.delete(${t}s).where(eq(${t}s.id, id)).run()
755
- throw new Error('Drizzle ${e} repository not yet implemented')
1201
+ async delete(id: string): Promise<void> {
1202
+ if (!this.store.has(id)) throw HttpException.notFound('${e} not found')
1203
+ this.store.delete(id)
756
1204
  }
757
1205
  }
758
- `}s(L,"generateDrizzleRepository");function N(e,t,o="../../domain/repositories",r="../../application/dtos"){let n=t.replace(/-([a-z])/g,(i,d)=>d.toUpperCase());return`/**
759
- * Prisma ${e} Repository
1206
+ `}s(_,"generateInMemoryRepository");function G(r){let{pascal:e,kebab:t,repoType:o="",repoPrefix:n="../../domain/repositories",dtoPrefix:i="../../application/dtos"}=r,c=o.charAt(0).toUpperCase()+o.slice(1).replace(/-([a-z])/g,(d,a)=>a.toUpperCase());return`/**
1207
+ * ${c} ${e} Repository
760
1208
  *
761
- * Implements the repository interface using Prisma Client.
762
- * Requires a PrismaClient instance injected via the DI container.
1209
+ * Stub implementation for a custom '${o}' repository.
1210
+ * Implements the repository interface using an in-memory Map as a placeholder.
763
1211
  *
764
- * TODO: Ensure your Prisma schema has a '${e}' model defined.
765
- * TODO: Replace 'PRISMA_CLIENT' with your actual Prisma injection token.
1212
+ * TODO: Replace the in-memory Map with your ${o} data-access logic.
1213
+ * See I${e}Repository for the interface contract.
766
1214
  *
767
1215
  * @Repository() registers this class in the DI container as a singleton.
768
1216
  */
769
- import { Repository, HttpException, Autowired } from '@forinda/kickjs-core'
1217
+ import { randomUUID } from 'node:crypto'
1218
+ import { Repository, HttpException } from '@forinda/kickjs-core'
770
1219
  import type { ParsedQuery } from '@forinda/kickjs-http'
771
- import type { I${e}Repository } from '${o}/${t}.repository'
772
- import type { ${e}ResponseDTO } from '${r}/${t}-response.dto'
773
- import type { Create${e}DTO } from '${r}/create-${t}.dto'
774
- import type { Update${e}DTO } from '${r}/update-${t}.dto'
775
-
776
- // TODO: Import your Prisma injection token \u2014 e.g.:
777
- // import { PRISMA_CLIENT } from '@/db/prisma.provider'
778
- // import type { PrismaClient } from '@prisma/client'
1220
+ import type { I${e}Repository } from '${n}/${t}.repository'
1221
+ import type { ${e}ResponseDTO } from '${i}/${t}-response.dto'
1222
+ import type { Create${e}DTO } from '${i}/create-${t}.dto'
1223
+ import type { Update${e}DTO } from '${i}/update-${t}.dto'
779
1224
 
780
1225
  @Repository()
781
- export class Prisma${e}Repository implements I${e}Repository {
782
- // TODO: Uncomment and configure your Prisma injection:
783
- // @Autowired(PRISMA_CLIENT) private prisma!: PrismaClient
1226
+ export class ${c}${e}Repository implements I${e}Repository {
1227
+ // TODO: Replace with your ${o} client/connection
1228
+ private store = new Map<string, ${e}ResponseDTO>()
784
1229
 
785
1230
  async findById(id: string): Promise<${e}ResponseDTO | null> {
786
- // TODO: Implement with Prisma
787
- // return this.prisma.${n}.findUnique({ where: { id } })
788
- throw new Error('Prisma ${e} repository not yet implemented \u2014 update Prisma imports and queries')
1231
+ // TODO: Implement with ${o}
1232
+ return this.store.get(id) ?? null
789
1233
  }
790
1234
 
791
1235
  async findAll(): Promise<${e}ResponseDTO[]> {
792
- // TODO: Implement with Prisma
793
- // return this.prisma.${n}.findMany()
794
- throw new Error('Prisma ${e} repository not yet implemented')
1236
+ // TODO: Implement with ${o}
1237
+ return Array.from(this.store.values())
795
1238
  }
796
1239
 
797
1240
  async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
798
- // TODO: Implement with Prisma
799
- // const [data, total] = await Promise.all([
800
- // this.prisma.${n}.findMany({
801
- // skip: parsed.pagination.offset,
802
- // take: parsed.pagination.limit,
803
- // }),
804
- // this.prisma.${n}.count(),
805
- // ])
806
- // return { data, total }
807
- throw new Error('Prisma ${e} repository not yet implemented')
1241
+ // TODO: Implement with ${o}
1242
+ const all = Array.from(this.store.values())
1243
+ const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)
1244
+ return { data, total: all.length }
808
1245
  }
809
1246
 
810
1247
  async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
811
- // TODO: Implement with Prisma
812
- // return this.prisma.${n}.create({ data: dto })
813
- throw new Error('Prisma ${e} repository not yet implemented')
1248
+ // TODO: Implement with ${o}
1249
+ const now = new Date().toISOString()
1250
+ const entity: ${e}ResponseDTO = {
1251
+ id: randomUUID(),
1252
+ name: dto.name,
1253
+ createdAt: now,
1254
+ updatedAt: now,
1255
+ }
1256
+ this.store.set(entity.id, entity)
1257
+ return entity
814
1258
  }
815
1259
 
816
1260
  async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
817
- // TODO: Implement with Prisma
818
- // const row = await this.prisma.${n}.update({ where: { id }, data: dto })
819
- // if (!row) throw HttpException.notFound('${e} not found')
820
- // return row
821
- throw new Error('Prisma ${e} repository not yet implemented')
1261
+ // TODO: Implement with ${o}
1262
+ const existing = this.store.get(id)
1263
+ if (!existing) throw HttpException.notFound('${e} not found')
1264
+ const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }
1265
+ this.store.set(id, updated)
1266
+ return updated
822
1267
  }
823
1268
 
824
1269
  async delete(id: string): Promise<void> {
825
- // TODO: Implement with Prisma
826
- // await this.prisma.${n}.delete({ where: { id } })
827
- throw new Error('Prisma ${e} repository not yet implemented')
1270
+ // TODO: Implement with ${o}
1271
+ if (!this.store.has(id)) throw HttpException.notFound('${e} not found')
1272
+ this.store.delete(id)
828
1273
  }
829
1274
  }
830
- `}s(N,"generatePrismaRepository");function le(e,t){return`/**
1275
+ `}s(G,"generateCustomRepository");function ue(r){let{pascal:e,kebab:t}=r;return`/**
831
1276
  * ${e} Domain Service
832
1277
  *
833
1278
  * Domain layer \u2014 contains business rules that don't belong to a single entity.
@@ -850,7 +1295,7 @@ export class ${e}DomainService {
850
1295
  }
851
1296
  }
852
1297
  }
853
- `}s(le,"generateDomainService");function ue(e,t){return`/**
1298
+ `}s(ue,"generateDomainService");function fe(r){let{pascal:e,kebab:t}=r;return`/**
854
1299
  * ${e} Entity
855
1300
  *
856
1301
  * Domain layer \u2014 the core business object.
@@ -919,7 +1364,7 @@ export class ${e} {
919
1364
  }
920
1365
  }
921
1366
  }
922
- `}s(ue,"generateEntity");function fe(e,t){return`/**
1367
+ `}s(fe,"generateEntity");function ge(r){let{pascal:e,kebab:t}=r;return`/**
923
1368
  * ${e} ID Value Object
924
1369
  *
925
1370
  * Domain layer \u2014 wraps a primitive ID with type safety and validation.
@@ -953,7 +1398,7 @@ export class ${e}Id {
953
1398
  return this.value === other.value
954
1399
  }
955
1400
  }
956
- `}s(fe,"generateValueObject");function Y(e,t,o){return`import { describe, it, expect, beforeEach } from 'vitest'
1401
+ `}s(ge,"generateValueObject");function Q(r){let{pascal:e,kebab:t,plural:o=""}=r;return`import { describe, it, expect, beforeEach } from 'vitest'
957
1402
  import { Container } from '@forinda/kickjs-core'
958
1403
 
959
1404
  describe('${e}Controller', () => {
@@ -1005,8 +1450,8 @@ describe('${e}Controller', () => {
1005
1450
  })
1006
1451
  })
1007
1452
  })
1008
- `}s(Y,"generateControllerTest");function B(e,t,o,r=`../infrastructure/repositories/in-memory-${t}.repository`){return`import { describe, it, expect, beforeEach } from 'vitest'
1009
- import { InMemory${e}Repository } from '${r}'
1453
+ `}s(Q,"generateControllerTest");function F(r){let{pascal:e,kebab:t,plural:o="",repoPrefix:n=`../infrastructure/repositories/in-memory-${t}.repository`}=r;return`import { describe, it, expect, beforeEach } from 'vitest'
1454
+ import { InMemory${e}Repository } from '${n}'
1010
1455
 
1011
1456
  describe('InMemory${e}Repository', () => {
1012
1457
  let repo: InMemory${e}Repository
@@ -1067,7 +1512,7 @@ describe('InMemory${e}Repository', () => {
1067
1512
  expect(found).toBeNull()
1068
1513
  })
1069
1514
  })
1070
- `}s(B,"generateRepositoryTest");function $e(e,t){return`import { Service, Inject, HttpException } from '@forinda/kickjs-core'
1515
+ `}s(F,"generateRepositoryTest");function $e(r){let{pascal:e,kebab:t}=r;return`import { Service, Inject, HttpException } from '@forinda/kickjs-core'
1071
1516
  import type { ParsedQuery } from '@forinda/kickjs-http'
1072
1517
  import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from './${t}.repository'
1073
1518
  import type { ${e}ResponseDTO } from './dtos/${t}-response.dto'
@@ -1104,14 +1549,14 @@ export class ${e}Service {
1104
1549
  await this.repo.delete(id)
1105
1550
  }
1106
1551
  }
1107
- `}s($e,"generateRestService");function ee(e){return`import type { QueryFieldConfig } from '@forinda/kickjs-http'
1552
+ `}s($e,"generateRestService");function V(r){let{pascal:e}=r;return`import type { QueryFieldConfig } from '@forinda/kickjs-http'
1108
1553
 
1109
1554
  export const ${e.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
1110
1555
  filterable: ['name'],
1111
1556
  sortable: ['name', 'createdAt'],
1112
1557
  searchable: ['name'],
1113
1558
  }
1114
- `}s(ee,"generateRestConstants");function ge(e,t,o,r){let n={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},i={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`},d=n[r]??n.inmemory,c=i[r]??i.inmemory;return`/**
1559
+ `}s(V,"generateRestConstants");function ye(r){let{pascal:e,kebab:t,plural:o="",repo:n}=r,i={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},c={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`},d=i[n]??i.inmemory,a=c[n]??c.inmemory;return`/**
1115
1560
  * ${e} Module \u2014 CQRS Pattern
1116
1561
  *
1117
1562
  * Separates read (queries) and write (commands) operations.
@@ -1127,7 +1572,7 @@ export const ${e.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
1127
1572
  import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'
1128
1573
  import { buildRoutes } from '@forinda/kickjs-http'
1129
1574
  import { ${e.toUpperCase()}_REPOSITORY } from './${t}.repository'
1130
- import { ${d} } from './${c}.repository'
1575
+ import { ${d} } from './${a}.repository'
1131
1576
  import { ${e}Controller } from './${t}.controller'
1132
1577
 
1133
1578
  // Eagerly load decorated classes
@@ -1156,14 +1601,14 @@ export class ${e}Module implements AppModule {
1156
1601
  }
1157
1602
  }
1158
1603
  }
1159
- `}s(ge,"generateCqrsModuleIndex");function ye(e,t,o,r){let n=e.charAt(0).toLowerCase()+e.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
1604
+ `}s(ye,"generateCqrsModuleIndex");function he(r){let{pascal:e,kebab:t,plural:o="",pluralPascal:n=""}=r;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
1160
1605
  import type { RequestContext } from '@forinda/kickjs-http'
1161
1606
  import { ApiTags } from '@forinda/kickjs-swagger'
1162
1607
  import { Create${e}Command } from './commands/create-${t}.command'
1163
1608
  import { Update${e}Command } from './commands/update-${t}.command'
1164
1609
  import { Delete${e}Command } from './commands/delete-${t}.command'
1165
1610
  import { Get${e}Query } from './queries/get-${t}.query'
1166
- import { List${r}Query } from './queries/list-${o}.query'
1611
+ import { List${n}Query } from './queries/list-${o}.query'
1167
1612
  import { create${e}Schema } from './dtos/create-${t}.dto'
1168
1613
  import { update${e}Schema } from './dtos/update-${t}.dto'
1169
1614
  import { ${e.toUpperCase()}_QUERY_CONFIG } from './${t}.constants'
@@ -1174,14 +1619,14 @@ export class ${e}Controller {
1174
1619
  @Autowired() private update${e}Command!: Update${e}Command
1175
1620
  @Autowired() private delete${e}Command!: Delete${e}Command
1176
1621
  @Autowired() private get${e}Query!: Get${e}Query
1177
- @Autowired() private list${r}Query!: List${r}Query
1622
+ @Autowired() private list${n}Query!: List${n}Query
1178
1623
 
1179
1624
  @Get('/')
1180
1625
  @ApiTags('${e}')
1181
1626
  @ApiQueryParams(${e.toUpperCase()}_QUERY_CONFIG)
1182
1627
  async list(ctx: RequestContext) {
1183
1628
  return ctx.paginate(
1184
- (parsed) => this.list${r}Query.execute(parsed),
1629
+ (parsed) => this.list${n}Query.execute(parsed),
1185
1630
  ${e.toUpperCase()}_QUERY_CONFIG,
1186
1631
  )
1187
1632
  }
@@ -1215,7 +1660,7 @@ export class ${e}Controller {
1215
1660
  ctx.noContent()
1216
1661
  }
1217
1662
  }
1218
- `}s(ye,"generateCqrsController");function he(e,t){return[{file:`create-${t}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1663
+ `}s(he,"generateCqrsController");function ke(r){let{pascal:e,kebab:t}=r;return[{file:`create-${t}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1219
1664
  import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../${t}.repository'
1220
1665
  import type { Create${e}DTO } from '../dtos/create-${t}.dto'
1221
1666
  import type { ${e}ResponseDTO } from '../dtos/${t}-response.dto'
@@ -1269,7 +1714,7 @@ export class Delete${e}Command {
1269
1714
  this.events.emit('${t}.deleted', { id })
1270
1715
  }
1271
1716
  }
1272
- `}]}s(he,"generateCqrsCommands");function we(e,t,o,r){return[{file:`get-${t}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1717
+ `}]}s(ke,"generateCqrsCommands");function we(r){let{pascal:e,kebab:t,plural:o="",pluralPascal:n=""}=r;return[{file:`get-${t}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1273
1718
  import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../${t}.repository'
1274
1719
  import type { ${e}ResponseDTO } from '../dtos/${t}-response.dto'
1275
1720
 
@@ -1288,7 +1733,7 @@ import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../${t}.rep
1288
1733
  import type { ParsedQuery } from '@forinda/kickjs-http'
1289
1734
 
1290
1735
  @Service()
1291
- export class List${r}Query {
1736
+ export class List${n}Query {
1292
1737
  constructor(
1293
1738
  @Inject(${e.toUpperCase()}_REPOSITORY) private readonly repo: I${e}Repository,
1294
1739
  ) {}
@@ -1297,7 +1742,7 @@ export class List${r}Query {
1297
1742
  return this.repo.findPaginated(parsed)
1298
1743
  }
1299
1744
  }
1300
- `}]}s(we,"generateCqrsQueries");function ve(e,t){return[{file:`${t}.events.ts`,content:`import { Service } from '@forinda/kickjs-core'
1745
+ `}]}s(we,"generateCqrsQueries");function ve(r){let{pascal:e,kebab:t}=r;return[{file:`${t}.events.ts`,content:`import { Service } from '@forinda/kickjs-core'
1301
1746
  import { EventEmitter } from 'node:events'
1302
1747
  import type { ${e}ResponseDTO } from '../dtos/${t}-response.dto'
1303
1748
 
@@ -1383,25 +1828,183 @@ export class On${e}ChangeHandler {
1383
1828
  })
1384
1829
  }
1385
1830
  }
1386
- `}]}s(ve,"generateCqrsEvents");function Ut(e){let t=Pt({input:process.stdin,output:process.stdout});return new Promise(o=>{t.question(e,r=>{t.close(),o(r.trim().toLowerCase())})})}s(Ut,"promptUser");async function Ae(e){let{name:t,modulesDir:o,noEntity:r,noTests:n,repo:i="inmemory",force:d,dryRun:c}=e,a=e.pattern??"ddd";e.minimal&&(a="minimal");let p=$(t),m=f(t),u=j(p),w=X(m),g=Ce(o,u),y=[],W=d??!1,A={kebab:p,pascal:m,plural:u,pluralPascal:w,moduleDir:g,repo:i,noEntity:r??!1,noTests:n??!1,write:s(async(U,ft)=>{let J=Ce(g,U);if(c){y.push(J);return}if(!W&&await _(J)){let Ie=await Ut(` File already exists: ${U}
1387
- Overwrite? (y/n/a = yes/no/all) `);if(Ie==="a")W=!0;else if(Ie!=="y"){console.log(` Skipped: ${U}`);return}}await l(J,ft),y.push(J)},"write"),files:y};switch(a){case"minimal":await zt(A);break;case"rest":await qt(A);break;case"cqrs":await _t(A);break;default:await Mt(A);break}return c||await bt(o,m,u),y}s(Ae,"generateModule");async function zt(e){let{pascal:t,kebab:o,plural:r,write:n}=e;await n("index.ts",se(t,o,r)),await n(`${o}.controller.ts`,`import { Controller, Get } from '@forinda/kickjs-core'
1831
+ `}]}s(ve,"generateCqrsEvents");function L(r){let{pascal:e,kebab:t,repoPrefix:o="../../domain/repositories",dtoPrefix:n="../../application/dtos"}=r;return`/**
1832
+ * Drizzle ${e} Repository
1833
+ *
1834
+ * Implements the repository interface using Drizzle ORM.
1835
+ * Uses buildFromColumns() with Column objects for type-safe query building.
1836
+ *
1837
+ * TODO: Update the schema import to match your Drizzle schema file.
1838
+ * TODO: Replace DRIZZLE_DB injection token with your actual database token.
1839
+ *
1840
+ * @Repository() registers this class in the DI container as a singleton.
1841
+ */
1842
+ import { eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc, count, sql } from 'drizzle-orm'
1843
+ import { Repository, HttpException, Inject } from '@forinda/kickjs-core'
1844
+ import { DRIZZLE_DB, DrizzleQueryAdapter } from '@forinda/kickjs-drizzle'
1845
+ import type { ParsedQuery } from '@forinda/kickjs-http'
1846
+ import type { I${e}Repository } from '${o}/${t}.repository'
1847
+ import type { ${e}ResponseDTO } from '${n}/${t}-response.dto'
1848
+ import type { Create${e}DTO } from '${n}/create-${t}.dto'
1849
+ import type { Update${e}DTO } from '${n}/update-${t}.dto'
1850
+ import { ${e.toUpperCase()}_QUERY_CONFIG } from '../../constants'
1851
+
1852
+ // TODO: Import your Drizzle schema table \u2014 e.g.:
1853
+ // import { ${t}s } from '@/db/schema'
1854
+
1855
+ const queryAdapter = new DrizzleQueryAdapter({
1856
+ eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc,
1857
+ })
1858
+
1859
+ @Repository()
1860
+ export class Drizzle${e}Repository implements I${e}Repository {
1861
+ constructor(@Inject(DRIZZLE_DB) private db: any) {}
1862
+
1863
+ async findById(id: string): Promise<${e}ResponseDTO | null> {
1864
+ // TODO: Implement with Drizzle
1865
+ // const row = this.db.select().from(${t}s).where(eq(${t}s.id, id)).get()
1866
+ // return row ?? null
1867
+ throw new Error('Drizzle ${e} repository not yet implemented \u2014 update schema imports and queries')
1868
+ }
1869
+
1870
+ async findAll(): Promise<${e}ResponseDTO[]> {
1871
+ // TODO: Implement with Drizzle
1872
+ // return this.db.select().from(${t}s).all()
1873
+ throw new Error('Drizzle ${e} repository not yet implemented')
1874
+ }
1875
+
1876
+ async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
1877
+ // TODO: Use buildFromColumns() with your query config for type-safe filtering
1878
+ // const query = queryAdapter.buildFromColumns(parsed, ${e.toUpperCase()}_QUERY_CONFIG)
1879
+ //
1880
+ // const data = this.db
1881
+ // .select().from(${t}s).$dynamic()
1882
+ // .where(query.where).orderBy(...query.orderBy)
1883
+ // .limit(query.limit).offset(query.offset).all()
1884
+ //
1885
+ // const totalResult = this.db
1886
+ // .select({ count: count() }).from(${t}s)
1887
+ // .$dynamic().where(query.where).get()
1888
+ //
1889
+ // return { data, total: totalResult?.count ?? 0 }
1890
+ throw new Error('Drizzle ${e} repository not yet implemented')
1891
+ }
1892
+
1893
+ async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
1894
+ // TODO: Implement with Drizzle
1895
+ // return this.db.insert(${t}s).values(dto).returning().get()
1896
+ throw new Error('Drizzle ${e} repository not yet implemented')
1897
+ }
1898
+
1899
+ async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
1900
+ // TODO: Implement with Drizzle
1901
+ // const row = this.db.update(${t}s).set(dto).where(eq(${t}s.id, id)).returning().get()
1902
+ // if (!row) throw HttpException.notFound('${e} not found')
1903
+ // return row
1904
+ throw new Error('Drizzle ${e} repository not yet implemented')
1905
+ }
1906
+
1907
+ async delete(id: string): Promise<void> {
1908
+ // TODO: Implement with Drizzle
1909
+ // this.db.delete(${t}s).where(eq(${t}s.id, id)).run()
1910
+ throw new Error('Drizzle ${e} repository not yet implemented')
1911
+ }
1912
+ }
1913
+ `}s(L,"generateDrizzleRepository");function Ce(r){let{pascal:e,kebab:t}=r;return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
1914
+ // TODO: Import your schema table and reference actual columns for type safety
1915
+ // import { ${t}s } from '@/db/schema'
1916
+
1917
+ export const ${e.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {
1918
+ columns: {
1919
+ // Replace with actual Drizzle Column references for type-safe filtering:
1920
+ // name: ${t}s.name,
1921
+ // status: ${t}s.status,
1922
+ },
1923
+ sortable: {
1924
+ // name: ${t}s.name,
1925
+ // createdAt: ${t}s.createdAt,
1926
+ },
1927
+ searchColumns: [
1928
+ // ${t}s.name,
1929
+ ],
1930
+ }
1931
+ `}s(Ce,"generateDrizzleConstants");function N(r){let{pascal:e,kebab:t,repoPrefix:o="../../domain/repositories",dtoPrefix:n="../../application/dtos"}=r,i=t.replace(/-([a-z])/g,(c,d)=>d.toUpperCase());return`/**
1932
+ * Prisma ${e} Repository
1933
+ *
1934
+ * Implements the repository interface using Prisma Client.
1935
+ * Requires a PrismaClient instance injected via the DI container.
1936
+ *
1937
+ * Ensure your Prisma schema has a '${e}' model defined.
1938
+ *
1939
+ * For full Prisma field-level type safety, replace PrismaModelDelegate with your PrismaClient:
1940
+ * @Inject(PRISMA_CLIENT) private prisma!: PrismaClient
1941
+ *
1942
+ * @Repository() registers this class in the DI container as a singleton.
1943
+ */
1944
+ import { Repository, HttpException, Inject } from '@forinda/kickjs-core'
1945
+ import { PRISMA_CLIENT, type PrismaModelDelegate } from '@forinda/kickjs-prisma'
1946
+ import type { ParsedQuery } from '@forinda/kickjs-http'
1947
+ import type { I${e}Repository } from '${o}/${t}.repository'
1948
+ import type { ${e}ResponseDTO } from '${n}/${t}-response.dto'
1949
+ import type { Create${e}DTO } from '${n}/create-${t}.dto'
1950
+ import type { Update${e}DTO } from '${n}/update-${t}.dto'
1951
+
1952
+ @Repository()
1953
+ export class Prisma${e}Repository implements I${e}Repository {
1954
+ @Inject(PRISMA_CLIENT) private prisma!: { ${i}: PrismaModelDelegate }
1955
+
1956
+ async findById(id: string): Promise<${e}ResponseDTO | null> {
1957
+ return this.prisma.${i}.findUnique({ where: { id } }) as Promise<${e}ResponseDTO | null>
1958
+ }
1959
+
1960
+ async findAll(): Promise<${e}ResponseDTO[]> {
1961
+ return this.prisma.${i}.findMany() as Promise<${e}ResponseDTO[]>
1962
+ }
1963
+
1964
+ async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
1965
+ const [data, total] = await Promise.all([
1966
+ this.prisma.${i}.findMany({
1967
+ skip: parsed.pagination.offset,
1968
+ take: parsed.pagination.limit,
1969
+ }) as Promise<${e}ResponseDTO[]>,
1970
+ this.prisma.${i}.count(),
1971
+ ])
1972
+ return { data, total }
1973
+ }
1974
+
1975
+ async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
1976
+ return this.prisma.${i}.create({ data: dto as Record<string, unknown> }) as Promise<${e}ResponseDTO>
1977
+ }
1978
+
1979
+ async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
1980
+ const existing = await this.prisma.${i}.findUnique({ where: { id } })
1981
+ if (!existing) throw HttpException.notFound('${e} not found')
1982
+ return this.prisma.${i}.update({ where: { id }, data: dto as Record<string, unknown> }) as Promise<${e}ResponseDTO>
1983
+ }
1984
+
1985
+ async delete(id: string): Promise<void> {
1986
+ await this.prisma.${i}.deleteMany({ where: { id } })
1987
+ }
1988
+ }
1989
+ `}s(N,"generatePrismaRepository");async function xe(r){let{pascal:e,kebab:t,plural:o,write:n}=r;await n("index.ts",ce({pascal:e,kebab:t,plural:o})),await n(`${t}.controller.ts`,`import { Controller, Get } from '@forinda/kickjs-core'
1388
1990
  import type { RequestContext } from '@forinda/kickjs-http'
1389
1991
 
1390
1992
  @Controller()
1391
- export class ${t}Controller {
1993
+ export class ${e}Controller {
1392
1994
  @Get('/')
1393
1995
  async list(ctx: RequestContext) {
1394
- ctx.json({ message: '${t} list' })
1996
+ ctx.json({ message: '${e} list' })
1395
1997
  }
1396
1998
  }
1397
- `)}s(zt,"generateMinimalFiles");async function qt(e){let{pascal:t,kebab:o,plural:r,pluralPascal:n,repo:i,noTests:d,write:c}=e;await c("index.ts",ne(t,o,r,i)),await c(`${o}.constants.ts`,ee(t)),await c(`${o}.controller.ts`,de(t,o,r,n)),await c(`${o}.service.ts`,$e(t,o)),await c(`dtos/create-${o}.dto.ts`,M(t,o)),await c(`dtos/update-${o}.dto.ts`,b(t,o)),await c(`dtos/${o}-response.dto.ts`,Q(t,o)),await c(`${o}.repository.ts`,G(t,o,"./dtos"));let a={inmemory:`in-memory-${o}`,drizzle:`drizzle-${o}`,prisma:`prisma-${o}`},p={inmemory:s(()=>F(t,o,".","./dtos"),"inmemory"),drizzle:s(()=>L(t,o,".","./dtos"),"drizzle"),prisma:s(()=>N(t,o,".","./dtos"),"prisma")};await c(`${a[i]}.repository.ts`,p[i]()),d||(await c(`__tests__/${o}.controller.test.ts`,Y(t,o,r)),await c(`__tests__/${o}.repository.test.ts`,B(t,o,r,`../${a.inmemory}.repository`)))}s(qt,"generateRestFiles");async function _t(e){let{pascal:t,kebab:o,plural:r,pluralPascal:n,repo:i,noTests:d,write:c}=e;await c("index.ts",ge(t,o,r,i)),await c(`${o}.constants.ts`,ee(t)),await c(`${o}.controller.ts`,ye(t,o,r,n)),await c(`dtos/create-${o}.dto.ts`,M(t,o)),await c(`dtos/update-${o}.dto.ts`,b(t,o)),await c(`dtos/${o}-response.dto.ts`,Q(t,o));let a=he(t,o);for(let g of a)await c(`commands/${g.file}`,g.content);let p=we(t,o,r,n);for(let g of p)await c(`queries/${g.file}`,g.content);let m=ve(t,o);for(let g of m)await c(`events/${g.file}`,g.content);await c(`${o}.repository.ts`,G(t,o,"./dtos"));let u={inmemory:`in-memory-${o}`,drizzle:`drizzle-${o}`,prisma:`prisma-${o}`},w={inmemory:s(()=>F(t,o,".","./dtos"),"inmemory"),drizzle:s(()=>L(t,o,".","./dtos"),"drizzle"),prisma:s(()=>N(t,o,".","./dtos"),"prisma")};await c(`${u[i]}.repository.ts`,w[i]()),d||(await c(`__tests__/${o}.controller.test.ts`,Y(t,o,r)),await c(`__tests__/${o}.repository.test.ts`,B(t,o,r,`../${u.inmemory}.repository`)))}s(_t,"generateCqrsFiles");async function Mt(e){let{pascal:t,kebab:o,plural:r,pluralPascal:n,repo:i,noEntity:d,noTests:c,write:a}=e;await a("index.ts",ie(t,o,r,i)),await a("constants.ts",i==="drizzle"?pe(t,o):ce(t)),await a(`presentation/${o}.controller.ts`,ae(t,o,r,n)),await a(`application/dtos/create-${o}.dto.ts`,M(t,o)),await a(`application/dtos/update-${o}.dto.ts`,b(t,o)),await a(`application/dtos/${o}-response.dto.ts`,Q(t,o));let p=me(t,o,r,n);for(let w of p)await a(`application/use-cases/${w.file}`,w.content);await a(`domain/repositories/${o}.repository.ts`,G(t,o)),await a(`domain/services/${o}-domain.service.ts`,le(t,o));let m={inmemory:`in-memory-${o}`,drizzle:`drizzle-${o}`,prisma:`prisma-${o}`},u={inmemory:s(()=>F(t,o),"inmemory"),drizzle:s(()=>L(t,o),"drizzle"),prisma:s(()=>N(t,o),"prisma")};await a(`infrastructure/repositories/${m[i]}.repository.ts`,u[i]()),d||(await a(`domain/entities/${o}.entity.ts`,ue(t,o)),await a(`domain/value-objects/${o}-id.vo.ts`,fe(t,o))),c||(await a(`__tests__/${o}.controller.test.ts`,Y(t,o,r)),await a(`__tests__/${o}.repository.test.ts`,B(t,o,r)))}s(Mt,"generateDddFiles");async function bt(e,t,o){let r=Ce(e,"index.ts");if(!await _(r)){await l(r,`import type { AppModuleClass } from '@forinda/kickjs-core'
1398
- import { ${t}Module } from './${o}'
1399
-
1400
- export const modules: AppModuleClass[] = [${t}Module]
1401
- `);return}let i=await Et(r,"utf-8"),d=`import { ${t}Module } from './${o}'`;if(!i.includes(`${t}Module`)){let c=i.lastIndexOf("import ");if(c!==-1){let a=i.indexOf(`
1402
- `,c);i=i.slice(0,a+1)+d+`
1403
- `+i.slice(a+1)}else i=d+`
1404
- `+i;i=i.replace(/(=\s*\[)([\s\S]*?)(])/,(a,p,m,u)=>{let w=m.trim();if(!w)return`${p}${t}Module${u}`;let g=w.endsWith(",")?"":",";return`${p}${m.trimEnd()}${g} ${t}Module${u}`})}await At(r,i,"utf-8")}s(bt,"autoRegisterModule");import{join as Qt}from"path";async function Ue(e){let{name:t,outDir:o}=e,r=$(t),n=f(t),i=[],d=Qt(o,`${r}.adapter.ts`);return await l(d,`import type { Express } from 'express'
1999
+ `)}s(xe,"generateMinimalFiles");async function Re(r){let{pascal:e,kebab:t,plural:o,pluralPascal:n,repo:i,noTests:c,prismaClientPath:d,write:a}=r;await a("index.ts",ae({pascal:e,kebab:t,plural:o,repo:i})),await a(`${t}.constants.ts`,V({pascal:e,kebab:t})),await a(`${t}.controller.ts`,pe({pascal:e,kebab:t,plural:o,pluralPascal:n})),await a(`${t}.service.ts`,$e({pascal:e,kebab:t})),await a(`dtos/create-${t}.dto.ts`,U({pascal:e,kebab:t})),await a(`dtos/update-${t}.dto.ts`,z({pascal:e,kebab:t})),await a(`dtos/${t}-response.dto.ts`,M({pascal:e,kebab:t})),await a(`${t}.repository.ts`,q({pascal:e,kebab:t,dtoPrefix:"./dtos"}));let p={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`},l={inmemory:s(()=>_({pascal:e,kebab:t,repoPrefix:".",dtoPrefix:"./dtos"}),"inmemory"),drizzle:s(()=>L({pascal:e,kebab:t,repoPrefix:".",dtoPrefix:"./dtos"}),"drizzle"),prisma:s(()=>N({pascal:e,kebab:t,repoPrefix:".",dtoPrefix:"./dtos",prismaClientPath:d}),"prisma")},u=p[i]??`${f(i)}-${t}`,g=l[i]??(()=>G({pascal:e,kebab:t,repoType:i,repoPrefix:".",dtoPrefix:"./dtos"}));await a(`${u}.repository.ts`,g()),c||(await a(`__tests__/${t}.controller.test.ts`,Q({pascal:e,kebab:t,plural:o})),await a(`__tests__/${t}.repository.test.ts`,F({pascal:e,kebab:t,plural:o,repoPrefix:`../${p.inmemory??`in-memory-${t}`}.repository`})))}s(Re,"generateRestFiles");async function De(r){let{pascal:e,kebab:t,plural:o,pluralPascal:n,repo:i,noTests:c,prismaClientPath:d,write:a}=r;await a("index.ts",ye({pascal:e,kebab:t,plural:o,repo:i})),await a(`${t}.constants.ts`,V({pascal:e,kebab:t})),await a(`${t}.controller.ts`,he({pascal:e,kebab:t,plural:o,pluralPascal:n})),await a(`dtos/create-${t}.dto.ts`,U({pascal:e,kebab:t})),await a(`dtos/update-${t}.dto.ts`,z({pascal:e,kebab:t})),await a(`dtos/${t}-response.dto.ts`,M({pascal:e,kebab:t}));let p=ke({pascal:e,kebab:t});for(let C of p)await a(`commands/${C.file}`,C.content);let l=we({pascal:e,kebab:t,plural:o,pluralPascal:n});for(let C of l)await a(`queries/${C.file}`,C.content);let u=ve({pascal:e,kebab:t});for(let C of u)await a(`events/${C.file}`,C.content);await a(`${t}.repository.ts`,q({pascal:e,kebab:t,dtoPrefix:"./dtos"}));let g={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`},k={inmemory:s(()=>_({pascal:e,kebab:t,repoPrefix:".",dtoPrefix:"./dtos"}),"inmemory"),drizzle:s(()=>L({pascal:e,kebab:t,repoPrefix:".",dtoPrefix:"./dtos"}),"drizzle"),prisma:s(()=>N({pascal:e,kebab:t,repoPrefix:".",dtoPrefix:"./dtos",prismaClientPath:d}),"prisma")},v=g[i]??`${f(i)}-${t}`,y=k[i]??(()=>G({pascal:e,kebab:t,repoType:i,repoPrefix:".",dtoPrefix:"./dtos"}));await a(`${v}.repository.ts`,y()),c||(await a(`__tests__/${t}.controller.test.ts`,Q({pascal:e,kebab:t,plural:o})),await a(`__tests__/${t}.repository.test.ts`,F({pascal:e,kebab:t,plural:o,repoPrefix:`../${g.inmemory??`in-memory-${t}`}.repository`})))}s(De,"generateCqrsFiles");async function be(r){let{pascal:e,kebab:t,plural:o,pluralPascal:n,repo:i,noEntity:c,noTests:d,prismaClientPath:a,write:p}=r;await p("index.ts",ne({pascal:e,kebab:t,plural:o,repo:i})),await p("constants.ts",i==="drizzle"?Ce({pascal:e,kebab:t}):le({pascal:e,kebab:t})),await p(`presentation/${t}.controller.ts`,de({pascal:e,kebab:t,plural:o,pluralPascal:n})),await p(`application/dtos/create-${t}.dto.ts`,U({pascal:e,kebab:t})),await p(`application/dtos/update-${t}.dto.ts`,z({pascal:e,kebab:t})),await p(`application/dtos/${t}-response.dto.ts`,M({pascal:e,kebab:t}));let l=me({pascal:e,kebab:t,plural:o,pluralPascal:n});for(let y of l)await p(`application/use-cases/${y.file}`,y.content);await p(`domain/repositories/${t}.repository.ts`,q({pascal:e,kebab:t})),await p(`domain/services/${t}-domain.service.ts`,ue({pascal:e,kebab:t}));let u={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`},g={inmemory:s(()=>_({pascal:e,kebab:t}),"inmemory"),drizzle:s(()=>L({pascal:e,kebab:t}),"drizzle"),prisma:s(()=>N({pascal:e,kebab:t,prismaClientPath:a}),"prisma")},k=u[i]??`${f(i)}-${t}`,v=g[i]??(()=>G({pascal:e,kebab:t,repoType:i}));await p(`infrastructure/repositories/${k}.repository.ts`,v()),c||(await p(`domain/entities/${t}.entity.ts`,fe({pascal:e,kebab:t})),await p(`domain/value-objects/${t}-id.vo.ts`,ge({pascal:e,kebab:t}))),d||(await p(`__tests__/${t}.controller.test.ts`,Q({pascal:e,kebab:t,plural:o})),await p(`__tests__/${t}.repository.test.ts`,F({pascal:e,kebab:t,plural:o})))}s(be,"generateDddFiles");function ot(r){return r?typeof r=="string"?r:r.name:"inmemory"}s(ot,"resolveRepoType");function pr(r){let e=ar({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(r,o=>{e.close(),t(o.trim().toLowerCase())})})}s(pr,"promptUser");async function it(r){let{name:e,modulesDir:t,noEntity:o,noTests:n,repo:i="inmemory",force:c,dryRun:d}=r,a=r.pluralize!==!1,p=r.pattern??"ddd";r.minimal&&(p="minimal");let l=f(e),u=$(e),g=a?T(l):l,k=a?re(u):u,v=Pe(t,g),y=[],C=c??!1,B=s(async(H,Lt)=>{let ee=Pe(v,H);if(d){y.push(ee);return}if(!C&&await A(ee)){let Ae=await pr(` File already exists: ${H}
2000
+ Overwrite? (y/n/a = yes/no/all) `);if(Ae==="a")C=!0;else if(Ae!=="y"){console.log(` Skipped: ${H}`);return}}await m(ee,Lt),y.push(ee)},"write"),K={kebab:l,pascal:u,plural:g,pluralPascal:k,moduleDir:v,repo:i,noEntity:o??!1,noTests:n??!1,prismaClientPath:r.prismaClientPath??"@prisma/client",write:B,files:y};switch(p){case"minimal":await xe(K);break;case"rest":await Re(K);break;case"cqrs":await De(K);break;default:await be(K);break}return d||await lr(t,u,g),y}s(it,"generateModule");async function lr(r,e,t){let o=Pe(r,"index.ts");if(!await A(o)){await m(o,`import type { AppModuleClass } from '@forinda/kickjs-core'
2001
+ import { ${e}Module } from './${t}'
2002
+
2003
+ export const modules: AppModuleClass[] = [${e}Module]
2004
+ `);return}let i=await cr(o,"utf-8"),c=`import { ${e}Module } from './${t}'`;if(!i.includes(`${e}Module`)){let d=i.lastIndexOf("import ");if(d!==-1){let a=i.indexOf(`
2005
+ `,d);i=i.slice(0,a+1)+c+`
2006
+ `+i.slice(a+1)}else i=c+`
2007
+ `+i;i=i.replace(/(=\s*\[)([\s\S]*?)(])/,(a,p,l,u)=>{let g=l.trim();if(!g)return`${p}${e}Module${u}`;let k=g.endsWith(",")?"":",";return`${p}${l.trimEnd()}${k} ${e}Module${u}`})}await dr(o,i,"utf-8")}s(lr,"autoRegisterModule");import{join as mr}from"path";async function st(r){let{name:e,outDir:t}=r,o=f(e),n=$(e),i=[],c=mr(t,`${o}.adapter.ts`);return await m(c,`import type { Express } from 'express'
1405
2008
  import type { AppAdapter, AdapterMiddleware, Container } from '@forinda/kickjs-core'
1406
2009
 
1407
2010
  export interface ${n}AdapterOptions {
@@ -1455,7 +2058,7 @@ export class ${n}Adapter implements AppAdapter {
1455
2058
  */
1456
2059
  beforeMount(app: Express, container: Container): void {
1457
2060
  // Example: mount a status route
1458
- // app.get('/${r}/status', (_req, res) => {
2061
+ // app.get('/${o}/status', (_req, res) => {
1459
2062
  // res.json({ status: 'ok' })
1460
2063
  // })
1461
2064
  }
@@ -1487,31 +2090,31 @@ export class ${n}Adapter implements AppAdapter {
1487
2090
  // await this.pool.end()
1488
2091
  }
1489
2092
  }
1490
- `),i.push(d),i}s(Ue,"generateAdapter");import{join as Nt}from"path";import{resolve as xe,join as ze}from"path";var Gt={controller:"presentation",service:"domain/services",dto:"application/dtos",guard:"presentation/guards",middleware:"middleware"},Ft={controller:"",service:"",dto:"dtos",guard:"guards",middleware:"middleware"},Lt={controller:"",service:"",dto:"dtos",guard:"guards",middleware:"middleware",command:"commands",query:"queries",event:"events"};function O(e){let{type:t,outDir:o,moduleName:r,modulesDir:n="src/modules",defaultDir:i,pattern:d="ddd"}=e;if(o)return xe(o);if(r){let c=d==="ddd"?Gt:d==="cqrs"?Lt:Ft,a=$(r),p=j(a),m=c[t]??"",u=ze(n,p);return xe(m?ze(u,m):u)}return xe(i)}s(O,"resolveOutDir");async function qe(e){let{name:t,moduleName:o,modulesDir:r,pattern:n}=e,i=O({type:"middleware",outDir:e.outDir,moduleName:o,modulesDir:r,defaultDir:"src/middleware",pattern:n}),d=$(t),c=x(t),a=[],p=Nt(i,`${d}.middleware.ts`);return await l(p,`import type { Request, Response, NextFunction } from 'express'
2093
+ `),i.push(c),i}s(st,"generateAdapter");import{join as $r}from"path";import{resolve as Te,join as nt}from"path";var ur={controller:"presentation",service:"domain/services",dto:"application/dtos",guard:"presentation/guards",middleware:"middleware"},fr={controller:"",service:"",dto:"dtos",guard:"guards",middleware:"middleware"},gr={controller:"",service:"",dto:"dtos",guard:"guards",middleware:"middleware",command:"commands",query:"queries",event:"events"};function O(r){let{type:e,outDir:t,moduleName:o,modulesDir:n="src/modules",defaultDir:i,pattern:c="ddd"}=r;if(t)return Te(t);if(o){let d=c==="ddd"?ur:c==="cqrs"?gr:fr,a=f(o),p=T(a),l=d[e]??"",u=nt(n,p);return Te(l?nt(u,l):u)}return Te(i)}s(O,"resolveOutDir");async function at(r){let{name:e,moduleName:t,modulesDir:o,pattern:n}=r,i=O({type:"middleware",outDir:r.outDir,moduleName:t,modulesDir:o,defaultDir:"src/middleware",pattern:n}),c=f(e),d=R(e),a=[],p=$r(i,`${c}.middleware.ts`);return await m(p,`import type { Request, Response, NextFunction } from 'express'
1491
2094
 
1492
- export interface ${f(t)}Options {
2095
+ export interface ${$(e)}Options {
1493
2096
  // Add configuration options here
1494
2097
  }
1495
2098
 
1496
2099
  /**
1497
- * ${f(t)} middleware.
2100
+ * ${$(e)} middleware.
1498
2101
  *
1499
2102
  * Usage in bootstrap:
1500
- * middleware: [${c}()]
2103
+ * middleware: [${d}()]
1501
2104
  *
1502
2105
  * Usage with adapter:
1503
- * middleware() { return [{ handler: ${c}(), phase: 'afterGlobal' }] }
2106
+ * middleware() { return [{ handler: ${d}(), phase: 'afterGlobal' }] }
1504
2107
  *
1505
2108
  * Usage with @Middleware decorator:
1506
- * @Middleware(${c}())
2109
+ * @Middleware(${d}())
1507
2110
  */
1508
- export function ${c}(options: ${f(t)}Options = {}) {
2111
+ export function ${d}(options: ${$(e)}Options = {}) {
1509
2112
  return (req: Request, res: Response, next: NextFunction) => {
1510
2113
  // Implement your middleware logic here
1511
2114
  next()
1512
2115
  }
1513
2116
  }
1514
- `),a.push(p),a}s(qe,"generateMiddleware");import{join as Yt}from"path";async function _e(e){let{name:t,moduleName:o,modulesDir:r,pattern:n}=e,i=O({type:"guard",outDir:e.outDir,moduleName:o,modulesDir:r,defaultDir:"src/guards",pattern:n}),d=$(t),c=x(t),a=f(t),p=[],m=Yt(i,`${d}.guard.ts`);return await l(m,`import { Container, HttpException } from '@forinda/kickjs-core'
2117
+ `),a.push(p),a}s(at,"generateMiddleware");import{join as yr}from"path";async function ct(r){let{name:e,moduleName:t,modulesDir:o,pattern:n}=r,i=O({type:"guard",outDir:r.outDir,moduleName:t,modulesDir:o,defaultDir:"src/guards",pattern:n}),c=f(e),d=R(e),a=$(e),p=[],l=yr(i,`${c}.guard.ts`);return await m(l,`import { Container, HttpException } from '@forinda/kickjs-core'
1515
2118
  import type { RequestContext } from '@forinda/kickjs-http'
1516
2119
 
1517
2120
  /**
@@ -1521,11 +2124,11 @@ import type { RequestContext } from '@forinda/kickjs-http'
1521
2124
  * Return early with an error response to block access.
1522
2125
  *
1523
2126
  * Usage:
1524
- * @Middleware(${c}Guard)
2127
+ * @Middleware(${d}Guard)
1525
2128
  * @Get('/protected')
1526
2129
  * async handler(ctx: RequestContext) { ... }
1527
2130
  */
1528
- export async function ${c}Guard(ctx: RequestContext, next: () => void): Promise<void> {
2131
+ export async function ${d}Guard(ctx: RequestContext, next: () => void): Promise<void> {
1529
2132
  // Example: check for an authorization header
1530
2133
  const header = ctx.headers.authorization
1531
2134
  if (!header?.startsWith('Bearer ')) {
@@ -1547,46 +2150,46 @@ export async function ${c}Guard(ctx: RequestContext, next: () => void): Promise<
1547
2150
  ctx.res.status(401).json({ message: 'Invalid or expired token' })
1548
2151
  }
1549
2152
  }
1550
- `),p.push(m),p}s(_e,"generateGuard");import{join as Bt}from"path";async function Me(e){let{name:t,moduleName:o,modulesDir:r,pattern:n}=e,i=O({type:"service",outDir:e.outDir,moduleName:o,modulesDir:r,defaultDir:"src/services",pattern:n}),d=$(t),c=f(t),a=[],p=Bt(i,`${d}.service.ts`);return await l(p,`import { Service } from '@forinda/kickjs-core'
2153
+ `),p.push(l),p}s(ct,"generateGuard");import{join as hr}from"path";async function dt(r){let{name:e,moduleName:t,modulesDir:o,pattern:n}=r,i=O({type:"service",outDir:r.outDir,moduleName:t,modulesDir:o,defaultDir:"src/services",pattern:n}),c=f(e),d=$(e),a=[],p=hr(i,`${c}.service.ts`);return await m(p,`import { Service } from '@forinda/kickjs-core'
1551
2154
 
1552
2155
  @Service()
1553
- export class ${c}Service {
2156
+ export class ${d}Service {
1554
2157
  // Inject dependencies via constructor
1555
2158
  // constructor(
1556
2159
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
1557
2160
  // ) {}
1558
2161
  }
1559
- `),a.push(p),a}s(Me,"generateService");import{join as Ht}from"path";async function be(e){let{name:t,moduleName:o,modulesDir:r,pattern:n}=e,i=O({type:"controller",outDir:e.outDir,moduleName:o,modulesDir:r,defaultDir:"src/controllers",pattern:n}),d=$(t),c=f(t),a=[],p=Ht(i,`${d}.controller.ts`);return await l(p,`import { Controller, Get, Post, Autowired } from '@forinda/kickjs-core'
2162
+ `),a.push(p),a}s(dt,"generateService");import{join as kr}from"path";async function pt(r){let{name:e,moduleName:t,modulesDir:o,pattern:n}=r,i=O({type:"controller",outDir:r.outDir,moduleName:t,modulesDir:o,defaultDir:"src/controllers",pattern:n}),c=f(e),d=$(e),a=[],p=kr(i,`${c}.controller.ts`);return await m(p,`import { Controller, Get, Post, Autowired } from '@forinda/kickjs-core'
1560
2163
  import type { RequestContext } from '@forinda/kickjs-http'
1561
2164
 
1562
2165
  @Controller()
1563
- export class ${c}Controller {
2166
+ export class ${d}Controller {
1564
2167
  // @Autowired() private myService!: MyService
1565
2168
 
1566
2169
  @Get('/')
1567
2170
  async list(ctx: RequestContext) {
1568
- ctx.json({ message: '${c} list' })
2171
+ ctx.json({ message: '${d} list' })
1569
2172
  }
1570
2173
 
1571
2174
  @Post('/')
1572
2175
  async create(ctx: RequestContext) {
1573
- ctx.created({ message: '${c} created', data: ctx.body })
2176
+ ctx.created({ message: '${d} created', data: ctx.body })
1574
2177
  }
1575
2178
  }
1576
- `),a.push(p),a}s(be,"generateController");import{join as Kt}from"path";async function Qe(e){let{name:t,moduleName:o,modulesDir:r,pattern:n}=e,i=O({type:"dto",outDir:e.outDir,moduleName:o,modulesDir:r,defaultDir:"src/dtos",pattern:n}),d=$(t),c=f(t),a=x(t),p=[],m=Kt(i,`${d}.dto.ts`);return await l(m,`import { z } from 'zod'
2179
+ `),a.push(p),a}s(pt,"generateController");import{join as wr}from"path";async function lt(r){let{name:e,moduleName:t,modulesDir:o,pattern:n}=r,i=O({type:"dto",outDir:r.outDir,moduleName:t,modulesDir:o,defaultDir:"src/dtos",pattern:n}),c=f(e),d=$(e),a=R(e),p=[],l=wr(i,`${c}.dto.ts`);return await m(l,`import { z } from 'zod'
1577
2180
 
1578
2181
  export const ${a}Schema = z.object({
1579
2182
  // Define your schema fields here
1580
2183
  name: z.string().min(1).max(200),
1581
2184
  })
1582
2185
 
1583
- export type ${c}DTO = z.infer<typeof ${a}Schema>
1584
- `),p.push(m),p}s(Qe,"generateDto");import{join as Wt}from"path";import{existsSync as Jt}from"fs";import{createInterface as Vt}from"readline";async function Zt(e){let t=Vt({input:process.stdin,output:process.stdout});return new Promise(o=>{t.question(` ${e} (y/N) `,r=>{t.close(),o(r.trim().toLowerCase()==="y")})})}s(Zt,"confirm");async function Ge(e){let t=Wt(e.outDir,"kick.config.ts"),o=e.modulesDir??"src/modules",r=e.defaultRepo??"inmemory";return Jt(t)&&!e.force&&!await Zt("kick.config.ts already exists. Overwrite?")?(console.log(`
1585
- Skipped \u2014 existing kick.config.ts preserved.`),[]):(await l(t,`import { defineConfig } from '@forinda/kickjs-cli'
2186
+ export type ${d}DTO = z.infer<typeof ${a}Schema>
2187
+ `),p.push(l),p}s(lt,"generateDto");import{join as vr}from"path";import{existsSync as Cr}from"fs";import{createInterface as xr}from"readline";async function Rr(r){let e=xr({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(` ${r} (y/N) `,o=>{e.close(),t(o.trim().toLowerCase()==="y")})})}s(Rr,"confirm");async function mt(r){let e=vr(r.outDir,"kick.config.ts"),t=r.modulesDir??"src/modules",o=r.defaultRepo??"inmemory";return Cr(e)&&!r.force&&!await Rr("kick.config.ts already exists. Overwrite?")?(console.log(`
2188
+ Skipped \u2014 existing kick.config.ts preserved.`),[]):(await m(e,`import { defineConfig } from '@forinda/kickjs-cli'
1586
2189
 
1587
2190
  export default defineConfig({
1588
- modulesDir: '${o}',
1589
- defaultRepo: '${r}',
2191
+ modulesDir: '${t}',
2192
+ defaultRepo: '${o}',
1590
2193
 
1591
2194
  commands: [
1592
2195
  {
@@ -1612,11 +2215,11 @@ export default defineConfig({
1612
2215
  },
1613
2216
  ],
1614
2217
  })
1615
- `),[t])}s(Ge,"generateConfig");import{join as Xt}from"path";async function Fe(e){let{name:t,outDir:o}=e,r=f(t),n=$(t),i=x(t),d=[],c=s(async(a,p)=>{let m=Xt(o,a);await l(m,p),d.push(m)},"write");return await c(`${n}.resolver.ts`,`import { Service } from '@forinda/kickjs-core'
2218
+ `),[e])}s(mt,"generateConfig");import{join as Dr}from"path";async function ut(r){let{name:e,outDir:t}=r,o=$(e),n=f(e),i=R(e),c=[],d=s(async(a,p)=>{let l=Dr(t,a);await m(l,p),c.push(l)},"write");return await d(`${n}.resolver.ts`,`import { Service } from '@forinda/kickjs-core'
1616
2219
  import { Resolver, Query, Mutation, Arg } from '@forinda/kickjs-graphql'
1617
2220
 
1618
2221
  /**
1619
- * ${r} GraphQL Resolver
2222
+ * ${o} GraphQL Resolver
1620
2223
  *
1621
2224
  * Decorators:
1622
2225
  * @Resolver(typeName?) \u2014 marks this class as a GraphQL resolver
@@ -1625,35 +2228,35 @@ import { Resolver, Query, Mutation, Arg } from '@forinda/kickjs-graphql'
1625
2228
  * @Arg(name, type?) \u2014 marks a method parameter as a GraphQL argument
1626
2229
  */
1627
2230
  @Service()
1628
- @Resolver('${r}')
1629
- export class ${r}Resolver {
2231
+ @Resolver('${o}')
2232
+ export class ${o}Resolver {
1630
2233
  private items: Array<{ id: string; name: string }> = []
1631
2234
 
1632
- @Query('${i}s', { returnType: '[${r}]', description: 'List all ${i}s' })
2235
+ @Query('${i}s', { returnType: '[${o}]', description: 'List all ${i}s' })
1633
2236
  findAll() {
1634
2237
  return this.items
1635
2238
  }
1636
2239
 
1637
- @Query('${i}', { returnType: '${r}', description: 'Get a ${i} by ID' })
2240
+ @Query('${i}', { returnType: '${o}', description: 'Get a ${i} by ID' })
1638
2241
  findById(@Arg('id', 'ID!') id: string) {
1639
2242
  return this.items.find((item) => item.id === id) ?? null
1640
2243
  }
1641
2244
 
1642
- @Mutation('create${r}', { returnType: '${r}', description: 'Create a new ${i}' })
2245
+ @Mutation('create${o}', { returnType: '${o}', description: 'Create a new ${i}' })
1643
2246
  create(@Arg('name', 'String!') name: string) {
1644
2247
  const item = { id: String(this.items.length + 1), name }
1645
2248
  this.items.push(item)
1646
2249
  return item
1647
2250
  }
1648
2251
 
1649
- @Mutation('update${r}', { returnType: '${r}', description: 'Update a ${i}' })
2252
+ @Mutation('update${o}', { returnType: '${o}', description: 'Update a ${i}' })
1650
2253
  update(@Arg('id', 'ID!') id: string, @Arg('name', 'String!') name: string) {
1651
2254
  const item = this.items.find((i) => i.id === id)
1652
2255
  if (item) item.name = name
1653
2256
  return item
1654
2257
  }
1655
2258
 
1656
- @Mutation('delete${r}', { returnType: 'Boolean', description: 'Delete a ${i}' })
2259
+ @Mutation('delete${o}', { returnType: 'Boolean', description: 'Delete a ${i}' })
1657
2260
  remove(@Arg('id', 'ID!') id: string) {
1658
2261
  const idx = this.items.findIndex((i) => i.id === id)
1659
2262
  if (idx === -1) return false
@@ -1661,21 +2264,21 @@ export class ${r}Resolver {
1661
2264
  return true
1662
2265
  }
1663
2266
  }
1664
- `),await c(`${n}.typedefs.ts`,`/**
1665
- * ${r} GraphQL type definitions.
2267
+ `),await d(`${n}.typedefs.ts`,`/**
2268
+ * ${o} GraphQL type definitions.
1666
2269
  * Pass to GraphQLAdapter's typeDefs option to register custom types.
1667
2270
  */
1668
2271
  export const ${i}TypeDefs = \`
1669
- type ${r} {
2272
+ type ${o} {
1670
2273
  id: ID!
1671
2274
  name: String!
1672
2275
  }
1673
2276
  \`
1674
- `),d}s(Fe,"generateResolver");import{join as eo}from"path";async function Le(e){let{name:t,outDir:o}=e,r=f(t),n=$(t),i=x(t),d=e.queue??`${n}-queue`,c=[];return await s(async(p,m)=>{let u=eo(o,p);await l(u,m),c.push(u)},"write")(`${n}.job.ts`,`import { Inject } from '@forinda/kickjs-core'
2277
+ `),c}s(ut,"generateResolver");import{join as br}from"path";async function ft(r){let{name:e,outDir:t}=r,o=$(e),n=f(e),i=R(e),c=r.queue??`${n}-queue`,d=[];return await s(async(p,l)=>{let u=br(t,p);await m(u,l),d.push(u)},"write")(`${n}.job.ts`,`import { Inject } from '@forinda/kickjs-core'
1675
2278
  import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-queue'
1676
2279
 
1677
2280
  /**
1678
- * ${r} Job Processor
2281
+ * ${o} Job Processor
1679
2282
  *
1680
2283
  * Decorators:
1681
2284
  * @Job(queueName) \u2014 marks this class as a job processor for a queue
@@ -1685,10 +2288,10 @@ import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-
1685
2288
  *
1686
2289
  * To add jobs to this queue from a service or controller:
1687
2290
  * @Inject(QUEUE_MANAGER) private queue: QueueService
1688
- * await this.queue.add('${d}', '${i}', { ... })
2291
+ * await this.queue.add('${c}', '${i}', { ... })
1689
2292
  */
1690
- @Job('${d}')
1691
- export class ${r}Job {
2293
+ @Job('${c}')
2294
+ export class ${o}Job {
1692
2295
  @Process()
1693
2296
  async handle(job: { name: string; data: any; id?: string }) {
1694
2297
  console.log(\`Processing \${job.name} (id: \${job.id})\`, job.data)
@@ -1704,68 +2307,68 @@ export class ${r}Job {
1704
2307
  // Handle high-priority variant of this job
1705
2308
  }
1706
2309
  }
1707
- `),c}s(Le,"generateJob");import{join as ke}from"path";import{readFile as to,writeFile as oo}from"fs/promises";var Ne={string:{ts:"string",zod:"z.string()"},text:{ts:"string",zod:"z.string()"},number:{ts:"number",zod:"z.number()"},int:{ts:"number",zod:"z.number().int()"},float:{ts:"number",zod:"z.number()"},boolean:{ts:"boolean",zod:"z.boolean()"},date:{ts:"string",zod:"z.string().datetime()"},email:{ts:"string",zod:"z.string().email()"},url:{ts:"string",zod:"z.string().url()"},uuid:{ts:"string",zod:"z.string().uuid()"},json:{ts:"any",zod:"z.any()"}};function Ye(e){return e.map(t=>{let o=t.indexOf(":");if(o===-1)throw new Error(`Invalid field: "${t}". Use format: name:type (e.g. title:string)`);let r=t.slice(0,o),n=t.slice(o+1);if(!r||!n)throw new Error(`Invalid field: "${t}". Use format: name:type (e.g. title:string)`);let i=n.endsWith("?"),d=i?n.slice(0,-1):n;if(d.startsWith("enum:")){let a=d.slice(5).split(",");return{name:r,type:"enum",tsType:a.map(p=>`'${p}'`).join(" | "),zodType:`z.enum([${a.map(p=>`'${p}'`).join(", ")}])`,optional:i}}let c=Ne[d];if(!c){let a=[...Object.keys(Ne),"enum:a,b,c"].join(", ");throw new Error(`Unknown field type: "${d}". Valid types: ${a}`)}return{name:r,type:d,tsType:c.ts,zodType:c.zod,optional:i}})}s(Ye,"parseFields");async function Be(e){let{name:t,fields:o,modulesDir:r,noEntity:n,noTests:i,repo:d="inmemory"}=e,c=$(t),a=f(t),p=x(t),m=j(c),u=X(a),w=ke(r,m),g=[],y=s(async(q,A)=>{let U=ke(w,q);await l(U,A),g.push(U)},"write");await y("index.ts",mo(a,c,m,d)),await y("constants.ts",so(a,o)),await y(`presentation/${c}.controller.ts`,lo(a,c,m,u)),await y(`application/dtos/create-${c}.dto.ts`,ro(a,o)),await y(`application/dtos/update-${c}.dto.ts`,io(a,o)),await y(`application/dtos/${c}-response.dto.ts`,no(a,o));let W=$o(a,c,m,u);for(let q of W)await y(`application/use-cases/${q.file}`,q.content);return await y(`domain/repositories/${c}.repository.ts`,uo(a,c)),await y(`domain/services/${c}-domain.service.ts`,fo(a,c)),d==="inmemory"&&await y(`infrastructure/repositories/in-memory-${c}.repository.ts`,ao(a,c,o)),n||(await y(`domain/entities/${c}.entity.ts`,co(a,c,o)),await y(`domain/value-objects/${c}-id.vo.ts`,po(a))),await go(r,a,m),g}s(Be,"generateScaffold");function ro(e,t){let o=t.map(r=>{let n=r.zodType;return` ${r.name}: ${n}${r.optional?".optional()":""},`}).join(`
2310
+ `),d}s(ft,"generateJob");import{join as Oe}from"path";import{readFile as Pr,writeFile as Tr}from"fs/promises";var gt={string:{ts:"string",zod:"z.string()"},text:{ts:"string",zod:"z.string()"},number:{ts:"number",zod:"z.number()"},int:{ts:"number",zod:"z.number().int()"},float:{ts:"number",zod:"z.number()"},boolean:{ts:"boolean",zod:"z.boolean()"},date:{ts:"string",zod:"z.string().datetime()"},email:{ts:"string",zod:"z.string().email()"},url:{ts:"string",zod:"z.string().url()"},uuid:{ts:"string",zod:"z.string().uuid()"},json:{ts:"any",zod:"z.any()"}};function $t(r){return r.map(e=>{let t=e.indexOf(":");if(t===-1)throw new Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let o=e.slice(0,t),n=e.slice(t+1);if(!o||!n)throw new Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let i=n.endsWith("?"),c=i?n.slice(0,-1):n;if(c.startsWith("enum:")){let a=c.slice(5).split(",");return{name:o,type:"enum",tsType:a.map(p=>`'${p}'`).join(" | "),zodType:`z.enum([${a.map(p=>`'${p}'`).join(", ")}])`,optional:i}}let d=gt[c];if(!d){let a=[...Object.keys(gt),"enum:a,b,c"].join(", ");throw new Error(`Unknown field type: "${c}". Valid types: ${a}`)}return{name:o,type:c,tsType:d.ts,zodType:d.zod,optional:i}})}s($t,"parseFields");async function yt(r){let{name:e,fields:t,modulesDir:o,noEntity:n,noTests:i,repo:c="inmemory"}=r,d=r.pluralize!==!1,a=f(e),p=$(e),l=R(e),u=d?T(a):a,g=d?re(p):p,k=Oe(o,u),v=[],y=s(async(B,K)=>{let H=Oe(k,B);await m(H,K),v.push(H)},"write");await y("index.ts",zr(p,a,u,c)),await y("constants.ts",jr(p,t)),await y(`presentation/${a}.controller.ts`,Mr(p,a,u,g)),await y(`application/dtos/create-${a}.dto.ts`,Or(p,t)),await y(`application/dtos/update-${a}.dto.ts`,Sr(p,t)),await y(`application/dtos/${a}-response.dto.ts`,Ir(p,t));let C=Gr(p,a,u,g);for(let B of C)await y(`application/use-cases/${B.file}`,B.content);return await y(`domain/repositories/${a}.repository.ts`,qr(p,a)),await y(`domain/services/${a}-domain.service.ts`,_r(p,a)),c==="inmemory"&&await y(`infrastructure/repositories/in-memory-${a}.repository.ts`,Ar(p,a,t)),n||(await y(`domain/entities/${a}.entity.ts`,Er(p,a,t)),await y(`domain/value-objects/${a}-id.vo.ts`,Ur(p))),await Qr(o,p,u),v}s(yt,"generateScaffold");function Or(r,e){let t=e.map(o=>{let n=o.zodType;return` ${o.name}: ${n}${o.optional?".optional()":""},`}).join(`
1708
2311
  `);return`import { z } from 'zod'
1709
2312
 
1710
- export const create${e}Schema = z.object({
1711
- ${o}
2313
+ export const create${r}Schema = z.object({
2314
+ ${t}
1712
2315
  })
1713
2316
 
1714
- export type Create${e}DTO = z.infer<typeof create${e}Schema>
1715
- `}s(ro,"genCreateDTO");function io(e,t){let o=t.map(r=>` ${r.name}: ${r.zodType}.optional(),`).join(`
2317
+ export type Create${r}DTO = z.infer<typeof create${r}Schema>
2318
+ `}s(Or,"genCreateDTO");function Sr(r,e){let t=e.map(o=>` ${o.name}: ${o.zodType}.optional(),`).join(`
1716
2319
  `);return`import { z } from 'zod'
1717
2320
 
1718
- export const update${e}Schema = z.object({
1719
- ${o}
2321
+ export const update${r}Schema = z.object({
2322
+ ${t}
1720
2323
  })
1721
2324
 
1722
- export type Update${e}DTO = z.infer<typeof update${e}Schema>
1723
- `}s(io,"genUpdateDTO");function no(e,t){let o=t.map(r=>` ${r.name}${r.optional?"?":""}: ${r.tsType}`).join(`
1724
- `);return`export interface ${e}ResponseDTO {
2325
+ export type Update${r}DTO = z.infer<typeof update${r}Schema>
2326
+ `}s(Sr,"genUpdateDTO");function Ir(r,e){let t=e.map(o=>` ${o.name}${o.optional?"?":""}: ${o.tsType}`).join(`
2327
+ `);return`export interface ${r}ResponseDTO {
1725
2328
  id: string
1726
- ${o}
2329
+ ${t}
1727
2330
  createdAt: string
1728
2331
  updatedAt: string
1729
2332
  }
1730
- `}s(no,"genResponseDTO");function so(e,t){let o=t.filter(a=>a.tsType==="string").map(a=>`'${a.name}'`),r=t.filter(a=>a.tsType==="number").map(a=>`'${a.name}'`),n=t.map(a=>`'${a.name}'`),i=[...n].join(", "),d=[...n,"'createdAt'","'updatedAt'"].join(", "),c=o.length>0?o.join(", "):"'name'";return`import type { ApiQueryParamsConfig } from '@forinda/kickjs-core'
2333
+ `}s(Ir,"genResponseDTO");function jr(r,e){let t=e.filter(a=>a.tsType==="string").map(a=>`'${a.name}'`),o=e.filter(a=>a.tsType==="number").map(a=>`'${a.name}'`),n=e.map(a=>`'${a.name}'`),i=[...n].join(", "),c=[...n,"'createdAt'","'updatedAt'"].join(", "),d=t.length>0?t.join(", "):"'name'";return`import type { ApiQueryParamsConfig } from '@forinda/kickjs-core'
1731
2334
 
1732
- export const ${e.toUpperCase()}_QUERY_CONFIG: ApiQueryParamsConfig = {
2335
+ export const ${r.toUpperCase()}_QUERY_CONFIG: ApiQueryParamsConfig = {
1733
2336
  filterable: [${i}],
1734
- sortable: [${d}],
1735
- searchable: [${c}],
2337
+ sortable: [${c}],
2338
+ searchable: [${d}],
1736
2339
  }
1737
- `}s(so,"genConstants");function ao(e,t,o){let r=o.map(i=>` ${i.name}: dto.${i.name},`).join(`
2340
+ `}s(jr,"genConstants");function Ar(r,e,t){let o=t.map(i=>` ${i.name}: dto.${i.name},`).join(`
1738
2341
  `);return`import { randomUUID } from 'node:crypto'
1739
2342
  import { Repository, HttpException } from '@forinda/kickjs-core'
1740
2343
  import type { ParsedQuery } from '@forinda/kickjs-http'
1741
- import type { I${e}Repository } from '../../domain/repositories/${t}.repository'
1742
- import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
1743
- import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
1744
- import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
2344
+ import type { I${r}Repository } from '../../domain/repositories/${e}.repository'
2345
+ import type { ${r}ResponseDTO } from '../../application/dtos/${e}-response.dto'
2346
+ import type { Create${r}DTO } from '../../application/dtos/create-${e}.dto'
2347
+ import type { Update${r}DTO } from '../../application/dtos/update-${e}.dto'
1745
2348
 
1746
2349
  @Repository()
1747
- export class InMemory${e}Repository implements I${e}Repository {
1748
- private store = new Map<string, ${e}ResponseDTO>()
2350
+ export class InMemory${r}Repository implements I${r}Repository {
2351
+ private store = new Map<string, ${r}ResponseDTO>()
1749
2352
 
1750
- async findById(id: string): Promise<${e}ResponseDTO | null> {
2353
+ async findById(id: string): Promise<${r}ResponseDTO | null> {
1751
2354
  return this.store.get(id) ?? null
1752
2355
  }
1753
2356
 
1754
- async findAll(): Promise<${e}ResponseDTO[]> {
2357
+ async findAll(): Promise<${r}ResponseDTO[]> {
1755
2358
  return Array.from(this.store.values())
1756
2359
  }
1757
2360
 
1758
- async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
2361
+ async findPaginated(parsed: ParsedQuery): Promise<{ data: ${r}ResponseDTO[]; total: number }> {
1759
2362
  const all = Array.from(this.store.values())
1760
2363
  const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)
1761
2364
  return { data, total: all.length }
1762
2365
  }
1763
2366
 
1764
- async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
2367
+ async create(dto: Create${r}DTO): Promise<${r}ResponseDTO> {
1765
2368
  const now = new Date().toISOString()
1766
- const entity: ${e}ResponseDTO = {
2369
+ const entity: ${r}ResponseDTO = {
1767
2370
  id: randomUUID(),
1768
- ${r}
2371
+ ${o}
1769
2372
  createdAt: now,
1770
2373
  updatedAt: now,
1771
2374
  }
@@ -1773,237 +2376,237 @@ ${r}
1773
2376
  return entity
1774
2377
  }
1775
2378
 
1776
- async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
2379
+ async update(id: string, dto: Update${r}DTO): Promise<${r}ResponseDTO> {
1777
2380
  const existing = this.store.get(id)
1778
- if (!existing) throw HttpException.notFound('${e} not found')
2381
+ if (!existing) throw HttpException.notFound('${r} not found')
1779
2382
  const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }
1780
2383
  this.store.set(id, updated)
1781
2384
  return updated
1782
2385
  }
1783
2386
 
1784
2387
  async delete(id: string): Promise<void> {
1785
- if (!this.store.has(id)) throw HttpException.notFound('${e} not found')
2388
+ if (!this.store.has(id)) throw HttpException.notFound('${r} not found')
1786
2389
  this.store.delete(id)
1787
2390
  }
1788
2391
  }
1789
- `}s(ao,"genInMemoryRepository");function co(e,t,o){let r=o.map(a=>` ${a.name}${a.optional?"?":""}: ${a.tsType}`).join(`
1790
- `),n=o.filter(a=>!a.optional).map(a=>`${a.name}: ${a.tsType}`).join("; "),i=o.filter(a=>!a.optional).map(a=>` ${a.name}: params.${a.name},`).join(`
1791
- `),d=o.map(a=>` get ${a.name}(): ${a.tsType}${a.optional?" | undefined":""} {
2392
+ `}s(Ar,"genInMemoryRepository");function Er(r,e,t){let o=t.map(a=>` ${a.name}${a.optional?"?":""}: ${a.tsType}`).join(`
2393
+ `),n=t.filter(a=>!a.optional).map(a=>`${a.name}: ${a.tsType}`).join("; "),i=t.filter(a=>!a.optional).map(a=>` ${a.name}: params.${a.name},`).join(`
2394
+ `),c=t.map(a=>` get ${a.name}(): ${a.tsType}${a.optional?" | undefined":""} {
1792
2395
  return this.props.${a.name}
1793
2396
  }`).join(`
1794
- `),c=o.map(a=>` ${a.name}: this.props.${a.name},`).join(`
1795
- `);return`import { ${e}Id } from '../value-objects/${t}-id.vo'
2397
+ `),d=t.map(a=>` ${a.name}: this.props.${a.name},`).join(`
2398
+ `);return`import { ${r}Id } from '../value-objects/${e}-id.vo'
1796
2399
 
1797
- interface ${e}Props {
1798
- id: ${e}Id
1799
- ${r}
2400
+ interface ${r}Props {
2401
+ id: ${r}Id
2402
+ ${o}
1800
2403
  createdAt: Date
1801
2404
  updatedAt: Date
1802
2405
  }
1803
2406
 
1804
- export class ${e} {
1805
- private constructor(private props: ${e}Props) {}
2407
+ export class ${r} {
2408
+ private constructor(private props: ${r}Props) {}
1806
2409
 
1807
- static create(params: { ${n} }): ${e} {
2410
+ static create(params: { ${n} }): ${r} {
1808
2411
  const now = new Date()
1809
- return new ${e}({
1810
- id: ${e}Id.create(),
2412
+ return new ${r}({
2413
+ id: ${r}Id.create(),
1811
2414
  ${i}
1812
2415
  createdAt: now,
1813
2416
  updatedAt: now,
1814
2417
  })
1815
2418
  }
1816
2419
 
1817
- static reconstitute(props: ${e}Props): ${e} {
1818
- return new ${e}(props)
2420
+ static reconstitute(props: ${r}Props): ${r} {
2421
+ return new ${r}(props)
1819
2422
  }
1820
2423
 
1821
- get id(): ${e}Id { return this.props.id }
1822
- ${d}
2424
+ get id(): ${r}Id { return this.props.id }
2425
+ ${c}
1823
2426
  get createdAt(): Date { return this.props.createdAt }
1824
2427
  get updatedAt(): Date { return this.props.updatedAt }
1825
2428
 
1826
2429
  toJSON() {
1827
2430
  return {
1828
2431
  id: this.props.id.toString(),
1829
- ${c}
2432
+ ${d}
1830
2433
  createdAt: this.props.createdAt.toISOString(),
1831
2434
  updatedAt: this.props.updatedAt.toISOString(),
1832
2435
  }
1833
2436
  }
1834
2437
  }
1835
- `}s(co,"genEntity");function po(e){return`import { randomUUID } from 'node:crypto'
2438
+ `}s(Er,"genEntity");function Ur(r){return`import { randomUUID } from 'node:crypto'
1836
2439
 
1837
- export class ${e}Id {
2440
+ export class ${r}Id {
1838
2441
  private constructor(private readonly value: string) {}
1839
2442
 
1840
- static create(): ${e}Id { return new ${e}Id(randomUUID()) }
2443
+ static create(): ${r}Id { return new ${r}Id(randomUUID()) }
1841
2444
 
1842
- static from(id: string): ${e}Id {
1843
- if (!id || id.trim().length === 0) throw new Error('${e}Id cannot be empty')
1844
- return new ${e}Id(id)
2445
+ static from(id: string): ${r}Id {
2446
+ if (!id || id.trim().length === 0) throw new Error('${r}Id cannot be empty')
2447
+ return new ${r}Id(id)
1845
2448
  }
1846
2449
 
1847
2450
  toString(): string { return this.value }
1848
- equals(other: ${e}Id): boolean { return this.value === other.value }
2451
+ equals(other: ${r}Id): boolean { return this.value === other.value }
1849
2452
  }
1850
- `}s(po,"genValueObject");function mo(e,t,o,r){return`import type { AppModule, AppModuleClass } from '@forinda/kickjs-core'
1851
- import { ${e}Controller } from './presentation/${t}.controller'
1852
- import { ${e}DomainService } from './domain/services/${t}-domain.service'
1853
- import { ${e.toUpperCase()}_REPOSITORY } from './domain/repositories/${t}.repository'
1854
- import { InMemory${e}Repository } from './infrastructure/repositories/in-memory-${t}.repository'
2453
+ `}s(Ur,"genValueObject");function zr(r,e,t,o){return`import type { AppModule, AppModuleClass } from '@forinda/kickjs-core'
2454
+ import { ${r}Controller } from './presentation/${e}.controller'
2455
+ import { ${r}DomainService } from './domain/services/${e}-domain.service'
2456
+ import { ${r.toUpperCase()}_REPOSITORY } from './domain/repositories/${e}.repository'
2457
+ import { InMemory${r}Repository } from './infrastructure/repositories/in-memory-${e}.repository'
1855
2458
 
1856
- export class ${e}Module implements AppModule {
2459
+ export class ${r}Module implements AppModule {
1857
2460
  register(container: any): void {
1858
2461
  container.registerFactory(
1859
- ${e.toUpperCase()}_REPOSITORY,
1860
- () => container.resolve(InMemory${e}Repository),
2462
+ ${r.toUpperCase()}_REPOSITORY,
2463
+ () => container.resolve(InMemory${r}Repository),
1861
2464
  )
1862
2465
  }
1863
2466
 
1864
2467
  routes() {
1865
- return { prefix: '/${o}', controllers: [${e}Controller] }
2468
+ return { prefix: '/${t}', controllers: [${r}Controller] }
1866
2469
  }
1867
2470
  }
1868
- `}s(mo,"genModuleIndex");function lo(e,t,o,r){return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
2471
+ `}s(zr,"genModuleIndex");function Mr(r,e,t,o){return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
1869
2472
  import type { RequestContext } from '@forinda/kickjs-http'
1870
2473
  import { ApiTags } from '@forinda/kickjs-swagger'
1871
- import { Create${e}UseCase } from '../application/use-cases/create-${t}.use-case'
1872
- import { Get${e}UseCase } from '../application/use-cases/get-${t}.use-case'
1873
- import { List${r}UseCase } from '../application/use-cases/list-${o}.use-case'
1874
- import { Update${e}UseCase } from '../application/use-cases/update-${t}.use-case'
1875
- import { Delete${e}UseCase } from '../application/use-cases/delete-${t}.use-case'
1876
- import { create${e}Schema } from '../application/dtos/create-${t}.dto'
1877
- import { update${e}Schema } from '../application/dtos/update-${t}.dto'
1878
- import { ${e.toUpperCase()}_QUERY_CONFIG } from '../constants'
2474
+ import { Create${r}UseCase } from '../application/use-cases/create-${e}.use-case'
2475
+ import { Get${r}UseCase } from '../application/use-cases/get-${e}.use-case'
2476
+ import { List${o}UseCase } from '../application/use-cases/list-${t}.use-case'
2477
+ import { Update${r}UseCase } from '../application/use-cases/update-${e}.use-case'
2478
+ import { Delete${r}UseCase } from '../application/use-cases/delete-${e}.use-case'
2479
+ import { create${r}Schema } from '../application/dtos/create-${e}.dto'
2480
+ import { update${r}Schema } from '../application/dtos/update-${e}.dto'
2481
+ import { ${r.toUpperCase()}_QUERY_CONFIG } from '../constants'
1879
2482
 
1880
2483
  @Controller()
1881
- export class ${e}Controller {
1882
- @Autowired() private create${e}UseCase!: Create${e}UseCase
1883
- @Autowired() private get${e}UseCase!: Get${e}UseCase
1884
- @Autowired() private list${r}UseCase!: List${r}UseCase
1885
- @Autowired() private update${e}UseCase!: Update${e}UseCase
1886
- @Autowired() private delete${e}UseCase!: Delete${e}UseCase
2484
+ export class ${r}Controller {
2485
+ @Autowired() private create${r}UseCase!: Create${r}UseCase
2486
+ @Autowired() private get${r}UseCase!: Get${r}UseCase
2487
+ @Autowired() private list${o}UseCase!: List${o}UseCase
2488
+ @Autowired() private update${r}UseCase!: Update${r}UseCase
2489
+ @Autowired() private delete${r}UseCase!: Delete${r}UseCase
1887
2490
 
1888
2491
  @Get('/')
1889
- @ApiTags('${e}')
1890
- @ApiQueryParams(${e.toUpperCase()}_QUERY_CONFIG)
2492
+ @ApiTags('${r}')
2493
+ @ApiQueryParams(${r.toUpperCase()}_QUERY_CONFIG)
1891
2494
  async list(ctx: RequestContext) {
1892
2495
  return ctx.paginate(
1893
- (parsed) => this.list${r}UseCase.execute(parsed),
1894
- ${e.toUpperCase()}_QUERY_CONFIG,
2496
+ (parsed) => this.list${o}UseCase.execute(parsed),
2497
+ ${r.toUpperCase()}_QUERY_CONFIG,
1895
2498
  )
1896
2499
  }
1897
2500
 
1898
2501
  @Get('/:id')
1899
- @ApiTags('${e}')
2502
+ @ApiTags('${r}')
1900
2503
  async getById(ctx: RequestContext) {
1901
- const result = await this.get${e}UseCase.execute(ctx.params.id)
1902
- if (!result) return ctx.notFound('${e} not found')
2504
+ const result = await this.get${r}UseCase.execute(ctx.params.id)
2505
+ if (!result) return ctx.notFound('${r} not found')
1903
2506
  ctx.json(result)
1904
2507
  }
1905
2508
 
1906
- @Post('/', { body: create${e}Schema, name: 'Create${e}' })
1907
- @ApiTags('${e}')
2509
+ @Post('/', { body: create${r}Schema, name: 'Create${r}' })
2510
+ @ApiTags('${r}')
1908
2511
  async create(ctx: RequestContext) {
1909
- const result = await this.create${e}UseCase.execute(ctx.body)
2512
+ const result = await this.create${r}UseCase.execute(ctx.body)
1910
2513
  ctx.created(result)
1911
2514
  }
1912
2515
 
1913
- @Put('/:id', { body: update${e}Schema, name: 'Update${e}' })
1914
- @ApiTags('${e}')
2516
+ @Put('/:id', { body: update${r}Schema, name: 'Update${r}' })
2517
+ @ApiTags('${r}')
1915
2518
  async update(ctx: RequestContext) {
1916
- const result = await this.update${e}UseCase.execute(ctx.params.id, ctx.body)
2519
+ const result = await this.update${r}UseCase.execute(ctx.params.id, ctx.body)
1917
2520
  ctx.json(result)
1918
2521
  }
1919
2522
 
1920
2523
  @Delete('/:id')
1921
- @ApiTags('${e}')
2524
+ @ApiTags('${r}')
1922
2525
  async remove(ctx: RequestContext) {
1923
- await this.delete${e}UseCase.execute(ctx.params.id)
2526
+ await this.delete${r}UseCase.execute(ctx.params.id)
1924
2527
  ctx.noContent()
1925
2528
  }
1926
2529
  }
1927
- `}s(lo,"genController");function uo(e,t){return`import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
1928
- import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
1929
- import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
2530
+ `}s(Mr,"genController");function qr(r,e){return`import type { ${r}ResponseDTO } from '../../application/dtos/${e}-response.dto'
2531
+ import type { Create${r}DTO } from '../../application/dtos/create-${e}.dto'
2532
+ import type { Update${r}DTO } from '../../application/dtos/update-${e}.dto'
1930
2533
  import type { ParsedQuery } from '@forinda/kickjs-http'
1931
2534
 
1932
- export interface I${e}Repository {
1933
- findById(id: string): Promise<${e}ResponseDTO | null>
1934
- findAll(): Promise<${e}ResponseDTO[]>
1935
- findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }>
1936
- create(dto: Create${e}DTO): Promise<${e}ResponseDTO>
1937
- update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO>
2535
+ export interface I${r}Repository {
2536
+ findById(id: string): Promise<${r}ResponseDTO | null>
2537
+ findAll(): Promise<${r}ResponseDTO[]>
2538
+ findPaginated(parsed: ParsedQuery): Promise<{ data: ${r}ResponseDTO[]; total: number }>
2539
+ create(dto: Create${r}DTO): Promise<${r}ResponseDTO>
2540
+ update(id: string, dto: Update${r}DTO): Promise<${r}ResponseDTO>
1938
2541
  delete(id: string): Promise<void>
1939
2542
  }
1940
2543
 
1941
- export const ${e.toUpperCase()}_REPOSITORY = Symbol('I${e}Repository')
1942
- `}s(uo,"genRepositoryInterface");function fo(e,t){return`import { Service, Inject, HttpException } from '@forinda/kickjs-core'
1943
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../repositories/${t}.repository'
2544
+ export const ${r.toUpperCase()}_REPOSITORY = Symbol('I${r}Repository')
2545
+ `}s(qr,"genRepositoryInterface");function _r(r,e){return`import { Service, Inject, HttpException } from '@forinda/kickjs-core'
2546
+ import { ${r.toUpperCase()}_REPOSITORY, type I${r}Repository } from '../repositories/${e}.repository'
1944
2547
 
1945
2548
  @Service()
1946
- export class ${e}DomainService {
2549
+ export class ${r}DomainService {
1947
2550
  constructor(
1948
- @Inject(${e.toUpperCase()}_REPOSITORY) private readonly repo: I${e}Repository,
2551
+ @Inject(${r.toUpperCase()}_REPOSITORY) private readonly repo: I${r}Repository,
1949
2552
  ) {}
1950
2553
 
1951
2554
  async ensureExists(id: string): Promise<void> {
1952
2555
  const entity = await this.repo.findById(id)
1953
- if (!entity) throw HttpException.notFound('${e} not found')
2556
+ if (!entity) throw HttpException.notFound('${r} not found')
1954
2557
  }
1955
2558
  }
1956
- `}s(fo,"genDomainService");function $o(e,t,o,r){return[{file:`create-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1957
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
1958
- import type { Create${e}DTO } from '../dtos/create-${t}.dto'
2559
+ `}s(_r,"genDomainService");function Gr(r,e,t,o){return[{file:`create-${e}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
2560
+ import { ${r.toUpperCase()}_REPOSITORY, type I${r}Repository } from '../../domain/repositories/${e}.repository'
2561
+ import type { Create${r}DTO } from '../dtos/create-${e}.dto'
1959
2562
 
1960
2563
  @Service()
1961
- export class Create${e}UseCase {
1962
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
1963
- async execute(dto: Create${e}DTO) { return this.repo.create(dto) }
2564
+ export class Create${r}UseCase {
2565
+ constructor(@Inject(${r.toUpperCase()}_REPOSITORY) private repo: I${r}Repository) {}
2566
+ async execute(dto: Create${r}DTO) { return this.repo.create(dto) }
1964
2567
  }
1965
- `},{file:`get-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1966
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
2568
+ `},{file:`get-${e}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
2569
+ import { ${r.toUpperCase()}_REPOSITORY, type I${r}Repository } from '../../domain/repositories/${e}.repository'
1967
2570
 
1968
2571
  @Service()
1969
- export class Get${e}UseCase {
1970
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
2572
+ export class Get${r}UseCase {
2573
+ constructor(@Inject(${r.toUpperCase()}_REPOSITORY) private repo: I${r}Repository) {}
1971
2574
  async execute(id: string) { return this.repo.findById(id) }
1972
2575
  }
1973
- `},{file:`list-${o}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
2576
+ `},{file:`list-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1974
2577
  import type { ParsedQuery } from '@forinda/kickjs-http'
1975
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
2578
+ import { ${r.toUpperCase()}_REPOSITORY, type I${r}Repository } from '../../domain/repositories/${e}.repository'
1976
2579
 
1977
2580
  @Service()
1978
- export class List${r}UseCase {
1979
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
2581
+ export class List${o}UseCase {
2582
+ constructor(@Inject(${r.toUpperCase()}_REPOSITORY) private repo: I${r}Repository) {}
1980
2583
  async execute(parsed: ParsedQuery) { return this.repo.findPaginated(parsed) }
1981
2584
  }
1982
- `},{file:`update-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1983
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
1984
- import type { Update${e}DTO } from '../dtos/update-${t}.dto'
2585
+ `},{file:`update-${e}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
2586
+ import { ${r.toUpperCase()}_REPOSITORY, type I${r}Repository } from '../../domain/repositories/${e}.repository'
2587
+ import type { Update${r}DTO } from '../dtos/update-${e}.dto'
1985
2588
 
1986
2589
  @Service()
1987
- export class Update${e}UseCase {
1988
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
1989
- async execute(id: string, dto: Update${e}DTO) { return this.repo.update(id, dto) }
2590
+ export class Update${r}UseCase {
2591
+ constructor(@Inject(${r.toUpperCase()}_REPOSITORY) private repo: I${r}Repository) {}
2592
+ async execute(id: string, dto: Update${r}DTO) { return this.repo.update(id, dto) }
1990
2593
  }
1991
- `},{file:`delete-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
1992
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
2594
+ `},{file:`delete-${e}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs-core'
2595
+ import { ${r.toUpperCase()}_REPOSITORY, type I${r}Repository } from '../../domain/repositories/${e}.repository'
1993
2596
 
1994
2597
  @Service()
1995
- export class Delete${e}UseCase {
1996
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
2598
+ export class Delete${r}UseCase {
2599
+ constructor(@Inject(${r.toUpperCase()}_REPOSITORY) private repo: I${r}Repository) {}
1997
2600
  async execute(id: string) { return this.repo.delete(id) }
1998
2601
  }
1999
- `}]}s($o,"genUseCases");async function go(e,t,o){let r=ke(e,"index.ts");if(!await _(r)){await l(r,`import type { AppModuleClass } from '@forinda/kickjs-core'
2000
- import { ${t}Module } from './${o}'
2001
-
2002
- export const modules: AppModuleClass[] = [${t}Module]
2003
- `);return}let i=await to(r,"utf-8"),d=`import { ${t}Module } from './${o}'`;if(!i.includes(`${t}Module`)){let c=i.lastIndexOf("import ");if(c!==-1){let a=i.indexOf(`
2004
- `,c);i=i.slice(0,a+1)+d+`
2005
- `+i.slice(a+1)}else i=d+`
2006
- `+i;i=i.replace(/(=\s*\[)([\s\S]*?)(])/,(a,p,m,u)=>{let w=m.trim();if(!w)return`${p}${t}Module${u}`;let g=w.endsWith(",")?"":",";return`${p}${m.trimEnd()}${g} ${t}Module${u}`})}await oo(r,i,"utf-8")}s(go,"autoRegisterModule");import{join as He,resolve as Re}from"path";async function Ke(e){let{name:t,moduleName:o,modulesDir:r}=e,n=$(t),i=f(t),d=[],c;if(e.outDir)c=Re(e.outDir);else if(o){let p=$(o),m=j(p);c=Re(He(r??"src/modules",m,"__tests__"))}else c=Re("src/__tests__");let a=He(c,`${n}.test.ts`);return await l(a,`import { describe, it, expect, beforeEach } from 'vitest'
2602
+ `}]}s(Gr,"genUseCases");async function Qr(r,e,t){let o=Oe(r,"index.ts");if(!await A(o)){await m(o,`import type { AppModuleClass } from '@forinda/kickjs-core'
2603
+ import { ${e}Module } from './${t}'
2604
+
2605
+ export const modules: AppModuleClass[] = [${e}Module]
2606
+ `);return}let i=await Pr(o,"utf-8"),c=`import { ${e}Module } from './${t}'`;if(!i.includes(`${e}Module`)){let d=i.lastIndexOf("import ");if(d!==-1){let a=i.indexOf(`
2607
+ `,d);i=i.slice(0,a+1)+c+`
2608
+ `+i.slice(a+1)}else i=c+`
2609
+ `+i;i=i.replace(/(=\s*\[)([\s\S]*?)(])/,(a,p,l,u)=>{let g=l.trim();if(!g)return`${p}${e}Module${u}`;let k=g.endsWith(",")?"":",";return`${p}${l.trimEnd()}${k} ${e}Module${u}`})}await Tr(o,i,"utf-8")}s(Qr,"autoRegisterModule");import{join as ht,resolve as Se}from"path";async function kt(r){let{name:e,moduleName:t,modulesDir:o}=r,n=f(e),i=$(e),c=[],d;if(r.outDir)d=Se(r.outDir);else if(t){let p=f(t),l=T(p);d=Se(ht(o??"src/modules",l,"__tests__"))}else d=Se("src/__tests__");let a=ht(d,`${n}.test.ts`);return await m(a,`import { describe, it, expect, beforeEach } from 'vitest'
2007
2610
  import { Container } from '@forinda/kickjs-core'
2008
2611
 
2009
2612
  describe('${i}', () => {
@@ -2026,36 +2629,36 @@ describe('${i}', () => {
2026
2629
  expect(true).toBe(true)
2027
2630
  })
2028
2631
  })
2029
- `),d.push(a),d}s(Ke,"generateTest");import{readFile as yo,access as ho}from"fs/promises";import{join as wo}from"path";var vo=["kick.config.ts","kick.config.js","kick.config.mjs","kick.config.json"];async function C(e){for(let t of vo){let o=wo(e,t);try{await ho(o)}catch{continue}if(t.endsWith(".json")){let r=await yo(o,"utf-8");return JSON.parse(r)}try{let{pathToFileURL:r}=await import("url"),n=await import(r(o).href);return n.default??n}catch{t.endsWith(".ts")&&console.warn(`Warning: Failed to load ${t}. TypeScript config files require a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.`);continue}}return null}s(C,"loadKickConfig");function k(e){return e.parent?.opts()?.dryRun??!1}s(k,"isDryRun");function R(e,t=!1){let o=process.cwd();console.log(`
2030
- ${t?"Would generate":"Generated"} ${e.length} file${e.length===1?"":"s"}:`);for(let n of e)console.log(` ${n.replace(o+"/","")}`);t&&console.log(`
2031
- (dry run \u2014 no files were written)`),console.log()}s(R,"printGenerated");var We=[{name:"module <name>",description:"Full DDD module (controller, DTOs, use-cases, repo)"},{name:"scaffold <name> <fields...>",description:"CRUD module from field definitions"},{name:"controller <name>",description:"@Controller() class [-m module]"},{name:"service <name>",description:"@Service() singleton [-m module]"},{name:"middleware <name>",description:"Express middleware function [-m module]"},{name:"guard <name>",description:"Route guard (auth, roles, etc.) [-m module]"},{name:"dto <name>",description:"Zod DTO schema [-m module]"},{name:"adapter <name>",description:"AppAdapter with lifecycle hooks (app-level only)"},{name:"test <name>",description:"Vitest test scaffold [-m module]"},{name:"resolver <name>",description:"GraphQL @Resolver class"},{name:"job <name>",description:"Queue @Job processor"},{name:"config",description:"Generate kick.config.ts"}];function Co(){console.log(`
2632
+ `),c.push(a),c}s(kt,"generateTest");import{readFile as Fr,access as Lr}from"fs/promises";import{join as Nr}from"path";var wt=["drizzle","inmemory","prisma"];function P(r){if(!r)return{};let e={dir:r.modules?.dir??r.modulesDir,repo:r.modules?.repo??r.defaultRepo,schemaDir:r.modules?.schemaDir??r.schemaDir,pluralize:r.modules?.pluralize??r.pluralize,prismaClientPath:r.modules?.prismaClientPath};return e.repo&&typeof e.repo=="string"&&!wt.includes(e.repo)&&console.warn(` Warning: modules.repo '${e.repo}' is not a built-in type (${wt.join(", ")}). It will generate a stub repository. Use { name: '${e.repo}' } to silence this warning.`),e}s(P,"resolveModuleConfig");var Wr=["kick.config.ts","kick.config.js","kick.config.mjs","kick.config.json"];async function w(r){for(let e of Wr){let t=Nr(r,e);try{await Lr(t)}catch{continue}if(e.endsWith(".json")){let o=await Fr(t,"utf-8");return JSON.parse(o)}try{let{pathToFileURL:o}=await import("url"),n=await import(o(t).href);return n.default??n}catch{e.endsWith(".ts")&&console.warn(`Warning: Failed to load ${e}. TypeScript config files require a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.`);continue}}return null}s(w,"loadKickConfig");function D(r){return r.parent?.opts()?.dryRun??!1}s(D,"isDryRun");function b(r,e=!1){let t=process.cwd();console.log(`
2633
+ ${e?"Would generate":"Generated"} ${r.length} file${r.length===1?"":"s"}:`);for(let n of r)console.log(` ${n.replace(t+"/","")}`);e&&console.log(`
2634
+ (dry run \u2014 no files were written)`),console.log()}s(b,"printGenerated");var vt=[{name:"module <name>",description:"Full DDD module (controller, DTOs, use-cases, repo)"},{name:"scaffold <name> <fields...>",description:"CRUD module from field definitions"},{name:"controller <name>",description:"@Controller() class [-m module]"},{name:"service <name>",description:"@Service() singleton [-m module]"},{name:"middleware <name>",description:"Express middleware function [-m module]"},{name:"guard <name>",description:"Route guard (auth, roles, etc.) [-m module]"},{name:"dto <name>",description:"Zod DTO schema [-m module]"},{name:"adapter <name>",description:"AppAdapter with lifecycle hooks (app-level only)"},{name:"test <name>",description:"Vitest test scaffold [-m module]"},{name:"resolver <name>",description:"GraphQL @Resolver class"},{name:"job <name>",description:"Queue @Job processor"},{name:"config",description:"Generate kick.config.ts"}];function Br(){console.log(`
2032
2635
  Available generators:
2033
- `);let e=Math.max(...We.map(t=>t.name.length));for(let t of We)console.log(` kick g ${t.name.padEnd(e+2)} ${t.description}`);console.log()}s(Co,"printGeneratorList");function Je(e){let t=e.command("generate").alias("g").description("Generate code scaffolds").option("--list","List all available generators").option("--dry-run","Preview files that would be generated without writing them").action(o=>{o.list?Co():t.help()});t.command("module <name>").description("Generate a module (structure depends on project pattern)").option("--no-entity","Skip entity and value object generation").option("--no-tests","Skip test file generation").option("--repo <type>","Repository implementation: inmemory | drizzle | prisma").option("--pattern <pattern>","Override project pattern: rest | ddd | cqrs | minimal").option("--minimal","Shorthand for --pattern minimal").option("--modules-dir <dir>","Modules directory").option("-f, --force","Overwrite existing files without prompting").action(async(o,r,n)=>{let i=k(n);v(i);let d=await C(process.cwd()),c=r.modulesDir??d?.modulesDir??"src/modules",a=r.repo??d?.defaultRepo??"inmemory",p=r.pattern??d?.pattern??"ddd",m=await Ae({name:o,modulesDir:z(c),noEntity:r.entity===!1,noTests:r.tests===!1,repo:a,minimal:r.minimal,force:r.force,pattern:p,dryRun:i});R(m,i)}),t.command("adapter <name>").description("Generate an AppAdapter with lifecycle hooks and middleware support").option("-o, --out <dir>","Output directory","src/adapters").action(async(o,r,n)=>{let i=k(n);v(i);let d=await Ue({name:o,outDir:z(r.out)});R(d,i)}),t.command("middleware <name>").description(`Generate an Express middleware function
2034
- Use -m to scope it to a module: kick g middleware auth -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(o,r,n)=>{let i=k(n);v(i);let d=await C(process.cwd()),c=d?.modulesDir??"src/modules",a=await qe({name:o,outDir:r.out,moduleName:r.module,modulesDir:c,pattern:d?.pattern});R(a,i)}),t.command("guard <name>").description(`Generate a route guard (auth, roles, etc.)
2035
- Use -m to scope it to a module: kick g guard admin -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(o,r,n)=>{let i=k(n);v(i);let d=await C(process.cwd()),c=d?.modulesDir??"src/modules",a=await _e({name:o,outDir:r.out,moduleName:r.module,modulesDir:c,pattern:d?.pattern});R(a,i)}),t.command("service <name>").description(`Generate a @Service() class
2036
- Use -m to scope it to a module: kick g service payment -m orders`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(o,r,n)=>{let i=k(n);v(i);let d=await C(process.cwd()),c=d?.modulesDir??"src/modules",a=await Me({name:o,outDir:r.out,moduleName:r.module,modulesDir:c,pattern:d?.pattern});R(a,i)}),t.command("controller <name>").description(`Generate a @Controller() class with basic routes
2037
- Use -m to scope it to a module: kick g controller auth -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(o,r,n)=>{let i=k(n);v(i);let d=await C(process.cwd()),c=d?.modulesDir??"src/modules",a=await be({name:o,outDir:r.out,moduleName:r.module,modulesDir:c,pattern:d?.pattern});R(a,i)}),t.command("dto <name>").description(`Generate a Zod DTO schema
2038
- Use -m to scope it to a module: kick g dto create-user -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(o,r,n)=>{let i=k(n);v(i);let d=await C(process.cwd()),c=d?.modulesDir??"src/modules",a=await Qe({name:o,outDir:r.out,moduleName:r.module,modulesDir:c,pattern:d?.pattern});R(a,i)}),t.command("test <name>").description(`Generate a Vitest test scaffold
2039
- Use -m to scope it to a module: kick g test user-service -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module's __tests__/ folder").action(async(o,r,n)=>{let i=k(n);v(i);let c=(await C(process.cwd()))?.modulesDir??"src/modules",a=await Ke({name:o,outDir:r.out,moduleName:r.module,modulesDir:c});R(a,i)}),t.command("resolver <name>").description("Generate a GraphQL @Resolver class with @Query and @Mutation methods").option("-o, --out <dir>","Output directory","src/resolvers").action(async(o,r,n)=>{let i=k(n);v(i);let d=await Fe({name:o,outDir:z(r.out)});R(d,i)}),t.command("job <name>").description("Generate a @Job queue processor with @Process handlers").option("-o, --out <dir>","Output directory","src/jobs").option("-q, --queue <name>","Queue name (default: <name>-queue)").action(async(o,r,n)=>{let i=k(n);v(i);let d=await Le({name:o,outDir:z(r.out),queue:r.queue});R(d,i)}),t.command("scaffold <name> [fields...]").description(`Generate a full CRUD module from field definitions
2636
+ `);let r=Math.max(...vt.map(e=>e.name.length));for(let e of vt)console.log(` kick g ${e.name.padEnd(r+2)} ${e.description}`);console.log()}s(Br,"printGeneratorList");function Ct(r){let e=r.command("generate").alias("g").description("Generate code scaffolds").option("--list","List all available generators").option("--dry-run","Preview files that would be generated without writing them").action(t=>{t.list?Br():e.help()});e.command("module <names...>").description("Generate one or more modules (e.g. kick g module user task project)").option("--no-entity","Skip entity and value object generation").option("--no-tests","Skip test file generation").option("--repo <type>","Repository implementation: inmemory | drizzle | prisma").option("--pattern <pattern>","Override project pattern: rest | ddd | cqrs | minimal").option("--minimal","Shorthand for --pattern minimal").option("--modules-dir <dir>","Modules directory").option("--no-pluralize","Use singular names (skip auto-pluralization)").option("-f, --force","Overwrite existing files without prompting").action(async(t,o,n)=>{let i=D(n);x(i);let c=await w(process.cwd()),d=P(c),a=o.modulesDir??d.dir??"src/modules",p=o.repo??ot(d.repo),l=o.pattern??c?.pattern??"ddd",u=o.pluralize===!1?!1:d.pluralize??!0,g=[];for(let k of t){let v=await it({name:k,modulesDir:Y(a),noEntity:o.entity===!1,noTests:o.tests===!1,repo:p,minimal:o.minimal,force:o.force,pattern:l,dryRun:i,pluralize:u,prismaClientPath:d.prismaClientPath});g.push(...v)}b(g,i)}),e.command("adapter <name>").description("Generate an AppAdapter with lifecycle hooks and middleware support").option("-o, --out <dir>","Output directory","src/adapters").action(async(t,o,n)=>{let i=D(n);x(i);let c=await st({name:t,outDir:Y(o.out)});b(c,i)}),e.command("middleware <name>").description(`Generate an Express middleware function
2637
+ Use -m to scope it to a module: kick g middleware auth -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(t,o,n)=>{let i=D(n);x(i);let c=await w(process.cwd()),d=P(c).dir??"src/modules",a=await at({name:t,outDir:o.out,moduleName:o.module,modulesDir:d,pattern:c?.pattern});b(a,i)}),e.command("guard <name>").description(`Generate a route guard (auth, roles, etc.)
2638
+ Use -m to scope it to a module: kick g guard admin -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(t,o,n)=>{let i=D(n);x(i);let c=await w(process.cwd()),d=P(c).dir??"src/modules",a=await ct({name:t,outDir:o.out,moduleName:o.module,modulesDir:d,pattern:c?.pattern});b(a,i)}),e.command("service <name>").description(`Generate a @Service() class
2639
+ Use -m to scope it to a module: kick g service payment -m orders`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(t,o,n)=>{let i=D(n);x(i);let c=await w(process.cwd()),d=P(c).dir??"src/modules",a=await dt({name:t,outDir:o.out,moduleName:o.module,modulesDir:d,pattern:c?.pattern});b(a,i)}),e.command("controller <name>").description(`Generate a @Controller() class with basic routes
2640
+ Use -m to scope it to a module: kick g controller auth -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(t,o,n)=>{let i=D(n);x(i);let c=await w(process.cwd()),d=P(c).dir??"src/modules",a=await pt({name:t,outDir:o.out,moduleName:o.module,modulesDir:d,pattern:c?.pattern});b(a,i)}),e.command("dto <name>").description(`Generate a Zod DTO schema
2641
+ Use -m to scope it to a module: kick g dto create-user -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module folder").action(async(t,o,n)=>{let i=D(n);x(i);let c=await w(process.cwd()),d=P(c).dir??"src/modules",a=await lt({name:t,outDir:o.out,moduleName:o.module,modulesDir:d,pattern:c?.pattern});b(a,i)}),e.command("test <name>").description(`Generate a Vitest test scaffold
2642
+ Use -m to scope it to a module: kick g test user-service -m users`).option("-o, --out <dir>","Output directory (overrides --module)").option("-m, --module <module>","Place inside a module's __tests__/ folder").action(async(t,o,n)=>{let i=D(n);x(i);let c=await w(process.cwd()),d=P(c).dir??"src/modules",a=await kt({name:t,outDir:o.out,moduleName:o.module,modulesDir:d});b(a,i)}),e.command("resolver <name>").description("Generate a GraphQL @Resolver class with @Query and @Mutation methods").option("-o, --out <dir>","Output directory","src/resolvers").action(async(t,o,n)=>{let i=D(n);x(i);let c=await ut({name:t,outDir:Y(o.out)});b(c,i)}),e.command("job <name>").description("Generate a @Job queue processor with @Process handlers").option("-o, --out <dir>","Output directory","src/jobs").option("-q, --queue <name>","Queue name (default: <name>-queue)").action(async(t,o,n)=>{let i=D(n);x(i);let c=await ft({name:t,outDir:Y(o.out),queue:o.queue});b(c,i)}),e.command("scaffold <name> [fields...]").description(`Generate a full CRUD module from field definitions
2040
2643
  Example: kick g scaffold Post title:string body:text published:boolean?
2041
2644
  Types: string, text, number, int, float, boolean, date, email, url, uuid, json, enum:a,b,c
2042
- Append ? for optional fields: description:text?`).option("--no-entity","Skip entity and value object generation").option("--no-tests","Skip test file generation").option("--modules-dir <dir>","Modules directory").action(async(o,r,n,i)=>{let d=k(i);v(d),r.length===0&&(console.error(`
2645
+ Append ? for optional fields: description:text?`).option("--no-entity","Skip entity and value object generation").option("--no-tests","Skip test file generation").option("--no-pluralize","Use singular names (skip auto-pluralization)").option("--modules-dir <dir>","Modules directory").action(async(t,o,n,i)=>{let c=D(i);x(c),o.length===0&&(console.error(`
2043
2646
  Error: At least one field is required.
2044
2647
  Usage: kick g scaffold <name> <field:type> [field:type...]
2045
2648
  Example: kick g scaffold Post title:string body:text published:boolean
2046
- `),process.exit(1));let c=await C(process.cwd()),a=n.modulesDir??c?.modulesDir??"src/modules",p=Ye(r),m=await Be({name:o,fields:p,modulesDir:z(a),noEntity:n.entity===!1,noTests:n.tests===!1});console.log(`
2047
- Scaffolded ${o} with ${p.length} field(s):`);for(let u of p)console.log(` ${u.name}: ${u.type}${u.optional?" (optional)":""}`);R(m,d)}),t.command("config").description("Generate a kick.config.ts at the project root").option("--modules-dir <dir>","Modules directory path","src/modules").option("--repo <type>","Default repository type: inmemory | drizzle | prisma","inmemory").option("-f, --force","Overwrite existing kick.config.ts without prompting").action(async(o,r)=>{let n=k(r);v(n);let i=await Ge({outDir:z("."),modulesDir:o.modulesDir,defaultRepo:o.repo,force:o.force});R(i,n)})}s(Je,"registerGenerateCommand");import{cpSync as ko,existsSync as Ro,mkdirSync as Do}from"fs";import{resolve as Ve,join as Ze}from"path";import{execSync as xo}from"child_process";function E(e,t){xo(e,{cwd:t,stdio:"inherit"})}s(E,"runShellCommand");function Xe(e){e.command("dev").description("Start development server with Vite HMR (zero-downtime reload)").option("-e, --entry <file>","Entry file","src/index.ts").option("-p, --port <port>","Port number").action(t=>{let o=[];t.port&&o.push(`PORT=${t.port}`);let r=`npx vite-node --watch ${t.entry}`,n=o.length?`${o.join(" ")} ${r}`:r;console.log(`
2048
- KickJS dev server starting...`),console.log(` Entry: ${t.entry}`),console.log(` HMR: enabled (vite-node)
2049
- `);try{E(n)}catch{}}),e.command("build").description("Build for production via Vite").action(async()=>{console.log(`
2649
+ `),process.exit(1));let d=await w(process.cwd()),a=P(d),p=n.modulesDir??a.dir??"src/modules",l=$t(o),u=await yt({name:t,fields:l,modulesDir:Y(p),noEntity:n.entity===!1,noTests:n.tests===!1,pluralize:n.pluralize===!1?!1:a.pluralize??!0});console.log(`
2650
+ Scaffolded ${t} with ${l.length} field(s):`);for(let g of l)console.log(` ${g.name}: ${g.type}${g.optional?" (optional)":""}`);b(u,c)}),e.command("config").description("Generate a kick.config.ts at the project root").option("--modules-dir <dir>","Modules directory path","src/modules").option("--repo <type>","Default repository type: inmemory | drizzle | prisma","inmemory").option("-f, --force","Overwrite existing kick.config.ts without prompting").action(async(t,o)=>{let n=D(o);x(n);let i=await mt({outDir:Y("."),modulesDir:t.modulesDir,defaultRepo:t.repo,force:t.force});b(i,n)})}s(Ct,"registerGenerateCommand");import{cpSync as Hr,existsSync as Yr,mkdirSync as Jr}from"fs";import{resolve as xt,join as Rt}from"path";import{execSync as Kr}from"child_process";function W(r,e){Kr(r,{cwd:e,stdio:"inherit"})}s(W,"runShellCommand");function Dt(r){r.command("dev").description("Start development server with Vite HMR (zero-downtime reload)").option("-e, --entry <file>","Entry file","src/index.ts").option("-p, --port <port>","Port number").action(e=>{let t=[];e.port&&t.push(`PORT=${e.port}`);let o=`npx vite-node --watch ${e.entry}`,n=t.length?`${t.join(" ")} ${o}`:o;console.log(`
2651
+ KickJS dev server starting...`),console.log(` Entry: ${e.entry}`),console.log(` HMR: enabled (vite-node)
2652
+ `);try{W(n)}catch{}}),r.command("build").description("Build for production via Vite").action(async()=>{console.log(`
2050
2653
  Building for production...
2051
- `),E("npx vite build");let o=(await C(process.cwd()))?.copyDirs??[];if(o.length>0){console.log(`
2052
- Copying directories to dist...`);for(let r of o){let n=typeof r=="string"?r:r.src,i=typeof r=="string"?Ze("dist",r):r.dest??Ze("dist",n),d=Ve(n),c=Ve(i);if(!Ro(d)){console.log(` \u26A0 Skipped ${n} (not found)`);continue}Do(c,{recursive:!0}),ko(d,c,{recursive:!0}),console.log(` \u2713 ${n} \u2192 ${i}`)}}console.log(`
2654
+ `),W("npx vite build");let t=(await w(process.cwd()))?.copyDirs??[];if(t.length>0){console.log(`
2655
+ Copying directories to dist...`);for(let o of t){let n=typeof o=="string"?o:o.src,i=typeof o=="string"?Rt("dist",o):o.dest??Rt("dist",n),c=xt(n),d=xt(i);if(!Yr(c)){console.log(` \u26A0 Skipped ${n} (not found)`);continue}Jr(d,{recursive:!0}),Hr(c,d,{recursive:!0}),console.log(` \u2713 ${n} \u2192 ${i}`)}}console.log(`
2053
2656
  Build complete.
2054
- `)}),e.command("start").description("Start production server").option("-e, --entry <file>","Entry file","dist/index.js").option("-p, --port <port>","Port number").action(t=>{let o=["NODE_ENV=production"];t.port&&o.push(`PORT=${t.port}`),E(`${o.join(" ")} node ${t.entry}`)}),e.command("dev:debug").description("Start dev server with Node.js inspector").option("-e, --entry <file>","Entry file","src/index.ts").option("-p, --port <port>","Port number").action(t=>{let o=t.port?`PORT=${t.port} `:"";try{E(`${o}npx vite-node --inspect --watch ${t.entry}`)}catch{}})}s(Xe,"registerRunCommands");import{platform as Oo,release as Io,arch as So}from"os";function et(e){e.command("info").description("Print system and framework info").action(()=>{console.log(`
2657
+ `)}),r.command("start").description("Start production server").option("-e, --entry <file>","Entry file","dist/index.js").option("-p, --port <port>","Port number").action(e=>{let t=["NODE_ENV=production"];e.port&&t.push(`PORT=${e.port}`),W(`${t.join(" ")} node ${e.entry}`)}),r.command("dev:debug").description("Start dev server with Node.js inspector").option("-e, --entry <file>","Entry file","src/index.ts").option("-p, --port <port>","Port number").action(e=>{let t=e.port?`PORT=${e.port} `:"";try{W(`${t}npx vite-node --inspect --watch ${e.entry}`)}catch{}})}s(Dt,"registerRunCommands");import{platform as Vr,release as Zr,arch as Xr}from"os";function bt(r){r.command("info").description("Print system and framework info").action(()=>{console.log(`
2055
2658
  KickJS CLI
2056
2659
 
2057
2660
  System:
2058
- OS: ${Oo()} ${Io()} (${So()})
2661
+ OS: ${Vr()} ${Zr()} (${Xr()})
2059
2662
  Node: ${process.version}
2060
2663
 
2061
2664
  Packages:
@@ -2063,32 +2666,32 @@ describe('${i}', () => {
2063
2666
  @forinda/kickjs-http workspace
2064
2667
  @forinda/kickjs-config workspace
2065
2668
  @forinda/kickjs-cli workspace
2066
- `)})}s(et,"registerInfoCommand");function tt(e,t){if(t?.commands?.length)for(let o of t.commands)To(e,o)}s(tt,"registerCustomCommands");function To(e,t){let o=e.command(t.name).description(t.description);if(t.aliases)for(let r of t.aliases)o.alias(r);o.allowUnknownOption(!0),o.argument("[args...]","Additional arguments passed to the command"),o.action(r=>{let n=r.join(" "),i=Array.isArray(t.steps)?t.steps:[t.steps];for(let d of i){let c=n?`${d} ${n}`:d;console.log(` $ ${c}`);try{E(c)}catch{console.error(` Command failed: ${t.name}`),process.exitCode=1;return}}})}s(To,"registerSingleCommand");var T=s(e=>`\x1B[${e}m`,"esc"),P=T("0"),S=s(e=>`${T("1")}${e}${P}`,"bold"),I=s(e=>`${T("2")}${e}${P}`,"dim"),De=s(e=>`${T("32")}${e}${P}`,"green"),K=s(e=>`${T("31")}${e}${P}`,"red"),ot=s(e=>`${T("33")}${e}${P}`,"yellow"),jo=s(e=>`${T("36")}${e}${P}`,"cyan"),Po=s(e=>`${T("35")}${e}${P}`,"magenta"),Eo=s(e=>`${T("34")}${e}${P}`,"blue"),Ao={GET:De,POST:jo,PUT:ot,PATCH:Po,DELETE:K};function Uo(e){return(Ao[e]??I)(e.padEnd(7))}s(Uo,"colorMethod");function zo(e){let t=Math.floor(e/86400),o=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),n=e%60,i=[];return t&&i.push(`${t}d`),o&&i.push(`${o}h`),r&&i.push(`${r}m`),i.push(`${n}s`),i.join(" ")}s(zo,"formatUptime");async function qo(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw new Error(`${t.status} ${t.statusText}`);return t.json()}s(qo,"fetchJson");async function H(e,t){try{return await qo(`${e}${t}`)}catch{return null}}s(H,"fetchEndpoint");async function _o(e){let[t,o,r,n,i]=await Promise.all([H(e,"/health"),H(e,"/metrics"),H(e,"/routes"),H(e,"/container"),H(e,"/ws")]);return{health:t,metrics:o,routes:r,container:n,ws:i}}s(_o,"fetchAll");function Mo(e,t){let{health:o,metrics:r,routes:n,container:i,ws:d}=t,c=I("\u2500".repeat(60));if(console.log(),console.log(S(" KickJS Inspector")+I(` \u2192 ${e}`)),console.log(c),o){let a=o.status==="healthy"?De("\u25CF healthy"):K("\u25CF "+o.status);console.log(` ${S("Health:")} ${a}`)}else console.log(` ${S("Health:")} ${K("\u25CF unreachable")}`);if(r){let a=((r.errorRate??0)*100).toFixed(1),p=r.errorRate>.1?K:r.errorRate>0?ot:De;console.log(` ${S("Uptime:")} ${zo(r.uptimeSeconds)}`),console.log(` ${S("Requests:")} ${r.requests}`),console.log(` ${S("Errors:")} ${r.serverErrors} server, ${r.clientErrors??0} client ${I("(")}${p(a+"%")}${I(")")}`)}if(i&&console.log(` ${S("DI:")} ${i.count} bindings`),d&&d.enabled&&console.log(` ${S("WS:")} ${d.connections??0} connections, ${d.namespaces??0} namespaces`),n?.routes?.length){console.log(),console.log(S(" Routes")),console.log(c),console.log(` ${I("METHOD")} ${I("PATH".padEnd(36))} ${I("CONTROLLER")}`);for(let a of n.routes){let p=a.path.length>36?a.path.slice(0,33)+"...":a.path.padEnd(36);console.log(` ${Uo(a.method)} ${p} ${Eo(a.controller)}.${I(a.handler)}`)}}console.log(c),console.log()}s(Mo,"printSummary");function rt(e){e.command("inspect [url]").description("Connect to a running KickJS app and display debug info").option("-p, --port <port>","Override port").option("-w, --watch","Poll every 5 seconds").option("-j, --json","Output raw JSON").action(async(t,o)=>{let r=t??"http://localhost:3000";if(o.port)try{let d=new URL(r);d.port=o.port,r=d.origin}catch{r=`http://localhost:${o.port}`}let n=`${r.replace(/\/$/,"")}/_debug`,i=s(async()=>{try{let d=await _o(n);o.json?console.log(JSON.stringify(d,null,2)):Mo(r,d)}catch(d){o.json?console.log(JSON.stringify({error:String(d)})):(console.error(K(` \u2716 Could not connect to ${r}`)),console.error(I(` ${d instanceof Error?d.message:String(d)}`))),o.watch||(process.exitCode=1)}},"run");if(o.watch){let d=s(async()=>{process.stdout.write("\x1B[2J\x1B[H"),await i()},"poll");await d(),setInterval(d,5e3)}else await i()})}s(rt,"registerInspectCommand");import{execSync as it}from"child_process";import{existsSync as nt}from"fs";import{resolve as st}from"path";var Oe={core:{pkg:"@forinda/kickjs-core",peers:[],description:"DI container, decorators, reactivity"},http:{pkg:"@forinda/kickjs-http",peers:["express"],description:"Express 5, routing, middleware"},config:{pkg:"@forinda/kickjs-config",peers:[],description:"Zod-based env validation"},cli:{pkg:"@forinda/kickjs-cli",peers:[],description:"CLI tool and code generators",dev:!0},swagger:{pkg:"@forinda/kickjs-swagger",peers:[],description:"OpenAPI spec + Swagger UI + ReDoc"},graphql:{pkg:"@forinda/kickjs-graphql",peers:["graphql"],description:"GraphQL resolvers + GraphiQL"},drizzle:{pkg:"@forinda/kickjs-drizzle",peers:["drizzle-orm"],description:"Drizzle ORM adapter + query builder"},prisma:{pkg:"@forinda/kickjs-prisma",peers:["@prisma/client"],description:"Prisma adapter + query builder"},ws:{pkg:"@forinda/kickjs-ws",peers:["socket.io"],description:"WebSocket with @WsController decorators"},otel:{pkg:"@forinda/kickjs-otel",peers:["@opentelemetry/api"],description:"OpenTelemetry tracing + metrics"},devtools:{pkg:"@forinda/kickjs-devtools",peers:[],description:"Development dashboard \u2014 routes, DI, metrics, health",dev:!0},auth:{pkg:"@forinda/kickjs-auth",peers:["jsonwebtoken"],description:"Authentication \u2014 JWT, API key, and custom strategies"},mailer:{pkg:"@forinda/kickjs-mailer",peers:["nodemailer"],description:"Email sending \u2014 SMTP, Resend, SES, or custom provider"},cron:{pkg:"@forinda/kickjs-cron",peers:["croner"],description:"Cron job scheduling (production-grade with croner)"},queue:{pkg:"@forinda/kickjs-queue",peers:[],description:"Queue adapter (BullMQ/RabbitMQ/Kafka)"},"queue:bullmq":{pkg:"@forinda/kickjs-queue",peers:["bullmq","ioredis"],description:"Queue with BullMQ + Redis"},"queue:rabbitmq":{pkg:"@forinda/kickjs-queue",peers:["amqplib"],description:"Queue with RabbitMQ"},"queue:kafka":{pkg:"@forinda/kickjs-queue",peers:["kafkajs"],description:"Queue with Kafka"},"multi-tenant":{pkg:"@forinda/kickjs-multi-tenant",peers:[],description:"Tenant resolution middleware"},notifications:{pkg:"@forinda/kickjs-notifications",peers:[],description:"Multi-channel notifications \u2014 email, Slack, Discord, webhook"},testing:{pkg:"@forinda/kickjs-testing",peers:[],description:"Test utilities and TestModule builder",dev:!0}};function bo(){return nt(st("pnpm-lock.yaml"))?"pnpm":nt(st("yarn.lock"))?"yarn":"npm"}s(bo,"detectPackageManager");function at(){console.log(`
2669
+ `)})}s(bt,"registerInfoCommand");function Pt(r,e){if(e?.commands?.length)for(let t of e.commands)eo(r,t)}s(Pt,"registerCustomCommands");function eo(r,e){let t=r.command(e.name).description(e.description);if(e.aliases)for(let o of e.aliases)t.alias(o);t.allowUnknownOption(!0),t.argument("[args...]","Additional arguments passed to the command"),t.action(o=>{let n=o.join(" "),i=Array.isArray(e.steps)?e.steps:[e.steps];for(let c of i){let d=n?`${c} ${n}`:c;console.log(` $ ${d}`);try{W(d)}catch{console.error(` Command failed: ${e.name}`),process.exitCode=1;return}}})}s(eo,"registerSingleCommand");var j=s(r=>`\x1B[${r}m`,"esc"),E=j("0"),I=s(r=>`${j("1")}${r}${E}`,"bold"),S=s(r=>`${j("2")}${r}${E}`,"dim"),Ie=s(r=>`${j("32")}${r}${E}`,"green"),X=s(r=>`${j("31")}${r}${E}`,"red"),Tt=s(r=>`${j("33")}${r}${E}`,"yellow"),to=s(r=>`${j("36")}${r}${E}`,"cyan"),ro=s(r=>`${j("35")}${r}${E}`,"magenta"),oo=s(r=>`${j("34")}${r}${E}`,"blue"),io={GET:Ie,POST:to,PUT:Tt,PATCH:ro,DELETE:X};function so(r){return(io[r]??S)(r.padEnd(7))}s(so,"colorMethod");function no(r){let e=Math.floor(r/86400),t=Math.floor(r%86400/3600),o=Math.floor(r%3600/60),n=r%60,i=[];return e&&i.push(`${e}d`),t&&i.push(`${t}h`),o&&i.push(`${o}m`),i.push(`${n}s`),i.join(" ")}s(no,"formatUptime");async function ao(r){let e=await fetch(r,{signal:AbortSignal.timeout(5e3)});if(!e.ok)throw new Error(`${e.status} ${e.statusText}`);return e.json()}s(ao,"fetchJson");async function Z(r,e){try{return await ao(`${r}${e}`)}catch{return null}}s(Z,"fetchEndpoint");async function co(r){let[e,t,o,n,i]=await Promise.all([Z(r,"/health"),Z(r,"/metrics"),Z(r,"/routes"),Z(r,"/container"),Z(r,"/ws")]);return{health:e,metrics:t,routes:o,container:n,ws:i}}s(co,"fetchAll");function po(r,e){let{health:t,metrics:o,routes:n,container:i,ws:c}=e,d=S("\u2500".repeat(60));if(console.log(),console.log(I(" KickJS Inspector")+S(` \u2192 ${r}`)),console.log(d),t){let a=t.status==="healthy"?Ie("\u25CF healthy"):X("\u25CF "+t.status);console.log(` ${I("Health:")} ${a}`)}else console.log(` ${I("Health:")} ${X("\u25CF unreachable")}`);if(o){let a=((o.errorRate??0)*100).toFixed(1),p=o.errorRate>.1?X:o.errorRate>0?Tt:Ie;console.log(` ${I("Uptime:")} ${no(o.uptimeSeconds)}`),console.log(` ${I("Requests:")} ${o.requests}`),console.log(` ${I("Errors:")} ${o.serverErrors} server, ${o.clientErrors??0} client ${S("(")}${p(a+"%")}${S(")")}`)}if(i&&console.log(` ${I("DI:")} ${i.count} bindings`),c&&c.enabled&&console.log(` ${I("WS:")} ${c.connections??0} connections, ${c.namespaces??0} namespaces`),n?.routes?.length){console.log(),console.log(I(" Routes")),console.log(d),console.log(` ${S("METHOD")} ${S("PATH".padEnd(36))} ${S("CONTROLLER")}`);for(let a of n.routes){let p=a.path.length>36?a.path.slice(0,33)+"...":a.path.padEnd(36);console.log(` ${so(a.method)} ${p} ${oo(a.controller)}.${S(a.handler)}`)}}console.log(d),console.log()}s(po,"printSummary");function Ot(r){r.command("inspect [url]").description("Connect to a running KickJS app and display debug info").option("-p, --port <port>","Override port").option("-w, --watch","Poll every 5 seconds").option("-j, --json","Output raw JSON").action(async(e,t)=>{let o=e??"http://localhost:3000";if(t.port)try{let c=new URL(o);c.port=t.port,o=c.origin}catch{o=`http://localhost:${t.port}`}let n=`${o.replace(/\/$/,"")}/_debug`,i=s(async()=>{try{let c=await co(n);t.json?console.log(JSON.stringify(c,null,2)):po(o,c)}catch(c){t.json?console.log(JSON.stringify({error:String(c)})):(console.error(X(` \u2716 Could not connect to ${o}`)),console.error(S(` ${c instanceof Error?c.message:String(c)}`))),t.watch||(process.exitCode=1)}},"run");if(t.watch){let c=s(async()=>{process.stdout.write("\x1B[2J\x1B[H"),await i()},"poll");await c(),setInterval(c,5e3)}else await i()})}s(Ot,"registerInspectCommand");import{execSync as St}from"child_process";import{existsSync as It}from"fs";import{resolve as jt}from"path";var je={core:{pkg:"@forinda/kickjs-core",peers:[],description:"DI container, decorators, reactivity"},http:{pkg:"@forinda/kickjs-http",peers:["express"],description:"Express 5, routing, middleware"},config:{pkg:"@forinda/kickjs-config",peers:[],description:"Zod-based env validation"},cli:{pkg:"@forinda/kickjs-cli",peers:[],description:"CLI tool and code generators",dev:!0},swagger:{pkg:"@forinda/kickjs-swagger",peers:[],description:"OpenAPI spec + Swagger UI + ReDoc"},graphql:{pkg:"@forinda/kickjs-graphql",peers:["graphql"],description:"GraphQL resolvers + GraphiQL"},drizzle:{pkg:"@forinda/kickjs-drizzle",peers:["drizzle-orm"],description:"Drizzle ORM adapter + query builder"},prisma:{pkg:"@forinda/kickjs-prisma",peers:["@prisma/client"],description:"Prisma adapter + query builder"},ws:{pkg:"@forinda/kickjs-ws",peers:["socket.io"],description:"WebSocket with @WsController decorators"},otel:{pkg:"@forinda/kickjs-otel",peers:["@opentelemetry/api"],description:"OpenTelemetry tracing + metrics"},devtools:{pkg:"@forinda/kickjs-devtools",peers:[],description:"Development dashboard \u2014 routes, DI, metrics, health",dev:!0},auth:{pkg:"@forinda/kickjs-auth",peers:["jsonwebtoken"],description:"Authentication \u2014 JWT, API key, and custom strategies"},mailer:{pkg:"@forinda/kickjs-mailer",peers:["nodemailer"],description:"Email sending \u2014 SMTP, Resend, SES, or custom provider"},cron:{pkg:"@forinda/kickjs-cron",peers:["croner"],description:"Cron job scheduling (production-grade with croner)"},queue:{pkg:"@forinda/kickjs-queue",peers:[],description:"Queue adapter (BullMQ/RabbitMQ/Kafka)"},"queue:bullmq":{pkg:"@forinda/kickjs-queue",peers:["bullmq","ioredis"],description:"Queue with BullMQ + Redis"},"queue:rabbitmq":{pkg:"@forinda/kickjs-queue",peers:["amqplib"],description:"Queue with RabbitMQ"},"queue:kafka":{pkg:"@forinda/kickjs-queue",peers:["kafkajs"],description:"Queue with Kafka"},"multi-tenant":{pkg:"@forinda/kickjs-multi-tenant",peers:[],description:"Tenant resolution middleware"},notifications:{pkg:"@forinda/kickjs-notifications",peers:[],description:"Multi-channel notifications \u2014 email, Slack, Discord, webhook"},testing:{pkg:"@forinda/kickjs-testing",peers:[],description:"Test utilities and TestModule builder",dev:!0}};function lo(){return It(jt("pnpm-lock.yaml"))?"pnpm":It(jt("yarn.lock"))?"yarn":"npm"}s(lo,"detectPackageManager");function At(){console.log(`
2067
2670
  Available KickJS packages:
2068
- `);let e=Math.max(...Object.keys(Oe).map(t=>t.length));for(let[t,o]of Object.entries(Oe)){let r=t.padEnd(e+2),n=o.peers.length?` (+ ${o.peers.join(", ")})`:"";console.log(` ${r} ${o.description}${n}`)}console.log(`
2069
- Usage: kick add graphql drizzle otel`),console.log(" kick add queue:bullmq"),console.log()}s(at,"printPackageList");function dt(e){e.command("list").alias("ls").description("List all available KickJS packages").action(()=>{at()})}s(dt,"registerListCommand");function ct(e){e.command("add [packages...]").description("Add KickJS packages with their required dependencies").option("--pm <manager>","Package manager override").option("-D, --dev","Install as dev dependency").option("--list","List all available packages").action(async(t,o)=>{if(o.list||t.length===0){at();return}let r=o.pm??bo(),n=o.dev,i=new Set,d=new Set,c=[];for(let a of t){let p=Oe[a];if(!p){c.push(a);continue}let m=n||p.dev?d:i;m.add(p.pkg);for(let u of p.peers)m.add(u)}if(!(c.length>0&&(console.log(`
2070
- Unknown packages: ${c.join(", ")}`),console.log(` Run "kick add --list" to see available packages.
2071
- `),i.size===0&&d.size===0))){if(i.size>0){let a=Array.from(i),p=`${r} add ${a.join(" ")}`;console.log(`
2072
- Installing ${a.length} dependency(ies):`);for(let m of a)console.log(` + ${m}`);console.log();try{it(p,{stdio:"inherit"})}catch{console.log(`
2671
+ `);let r=Math.max(...Object.keys(je).map(e=>e.length));for(let[e,t]of Object.entries(je)){let o=e.padEnd(r+2),n=t.peers.length?` (+ ${t.peers.join(", ")})`:"";console.log(` ${o} ${t.description}${n}`)}console.log(`
2672
+ Usage: kick add graphql drizzle otel`),console.log(" kick add queue:bullmq"),console.log()}s(At,"printPackageList");function Et(r){r.command("list").alias("ls").description("List all available KickJS packages").action(()=>{At()})}s(Et,"registerListCommand");function Ut(r){r.command("add [packages...]").description("Add KickJS packages with their required dependencies").option("--pm <manager>","Package manager override").option("-D, --dev","Install as dev dependency").option("--list","List all available packages").action(async(e,t)=>{if(t.list||e.length===0){At();return}let o=t.pm??lo(),n=t.dev,i=new Set,c=new Set,d=[];for(let a of e){let p=je[a];if(!p){d.push(a);continue}let l=n||p.dev?c:i;l.add(p.pkg);for(let u of p.peers)l.add(u)}if(!(d.length>0&&(console.log(`
2673
+ Unknown packages: ${d.join(", ")}`),console.log(` Run "kick add --list" to see available packages.
2674
+ `),i.size===0&&c.size===0))){if(i.size>0){let a=Array.from(i),p=`${o} add ${a.join(" ")}`;console.log(`
2675
+ Installing ${a.length} dependency(ies):`);for(let l of a)console.log(` + ${l}`);console.log();try{St(p,{stdio:"inherit"})}catch{console.log(`
2073
2676
  Installation failed. Run manually:
2074
2677
  ${p}
2075
- `)}}if(d.size>0){let a=Array.from(d),p=`${r} add -D ${a.join(" ")}`;console.log(`
2076
- Installing ${a.length} dev dependency(ies):`);for(let m of a)console.log(` + ${m} (dev)`);console.log();try{it(p,{stdio:"inherit"})}catch{console.log(`
2678
+ `)}}if(c.size>0){let a=Array.from(c),p=`${o} add -D ${a.join(" ")}`;console.log(`
2679
+ Installing ${a.length} dev dependency(ies):`);for(let l of a)console.log(` + ${l} (dev)`);console.log();try{St(p,{stdio:"inherit"})}catch{console.log(`
2077
2680
  Installation failed. Run manually:
2078
2681
  ${p}
2079
2682
  `)}}console.log(` Done!
2080
- `)}})}s(ct,"registerAddCommand");import{resolve as pt,join as mt}from"path";import{existsSync as lt}from"fs";import{pathToFileURL as Qo}from"url";import{fork as Go}from"child_process";function ut(e){e.command("tinker").description("Interactive REPL with DI container and services loaded").option("-e, --entry <file>","Entry file to load","src/index.ts").action(async t=>{let o=process.cwd(),r=pt(o,t.entry);lt(r)||(console.error(`
2081
- Error: ${t.entry} not found.
2082
- `),process.exit(1));let n=Lo(o,"tsx");n||(console.error(`
2683
+ `)}})}s(Ut,"registerAddCommand");import{resolve as zt,join as Mt}from"path";import{existsSync as qt}from"fs";import{pathToFileURL as mo}from"url";import{fork as uo}from"child_process";function _t(r){r.command("tinker").description("Interactive REPL with DI container and services loaded").option("-e, --entry <file>","Entry file to load","src/index.ts").action(async e=>{let t=process.cwd(),o=zt(t,e.entry);qt(o)||(console.error(`
2684
+ Error: ${e.entry} not found.
2685
+ `),process.exit(1));let n=go(t,"tsx");n||(console.error(`
2083
2686
  Error: tsx not found. Install it: pnpm add -D tsx
2084
- `),process.exit(1));let i=Fo(r,t.entry),d=mt(o,".kick-tinker.mjs"),{writeFileSync:c,unlinkSync:a}=await import("fs");c(d,i,"utf-8");try{let p=Go(d,[],{cwd:o,execPath:n,stdio:"inherit"});await new Promise(m=>{p.on("exit",()=>m())})}finally{try{a(d)}catch{}}})}s(ut,"registerTinkerCommand");function Fo(e,t){let o=Qo(e).href;return`
2687
+ `),process.exit(1));let i=fo(o,e.entry),c=Mt(t,".kick-tinker.mjs"),{writeFileSync:d,unlinkSync:a}=await import("fs");d(c,i,"utf-8");try{let p=uo(c,[],{cwd:t,execPath:n,stdio:"inherit"});await new Promise(l=>{p.on("exit",()=>l())})}finally{try{a(c)}catch{}}})}s(_t,"registerTinkerCommand");function fo(r,e){let t=mo(r).href;return`
2085
2688
  import 'reflect-metadata'
2086
2689
 
2087
2690
  // Prevent bootstrap() from starting the HTTP server
2088
2691
  process.env.KICK_TINKER = '1'
2089
2692
 
2090
2693
  console.log('\\n \u{1F527} KickJS Tinker')
2091
- console.log(' Loading: ${t}\\n')
2694
+ console.log(' Loading: ${e}\\n')
2092
2695
 
2093
2696
  // Load core
2094
2697
  let Container, Logger, HttpException, HttpStatus
@@ -2106,7 +2709,7 @@ try {
2106
2709
 
2107
2710
  // Load entry to trigger decorator registration
2108
2711
  try {
2109
- await import('${o}')
2712
+ await import('${t}')
2110
2713
  } catch (err) {
2111
2714
  console.warn(' Warning: ' + err.message)
2112
2715
  console.warn(' Container may be partially initialized.\\n')
@@ -2135,4 +2738,12 @@ server.on('exit', () => {
2135
2738
  console.log('\\n Goodbye!\\n')
2136
2739
  process.exit(0)
2137
2740
  })
2138
- `}s(Fo,"generateTinkerScript");function Lo(e,t){let o=e;for(;;){let r=mt(o,"node_modules",".bin",t);if(lt(r))return r;let n=pt(o,"..");if(n===o)break;o=n}return null}s(Lo,"findBin");var Wo=Bo(Ko(import.meta.url)),Jo=JSON.parse(Yo(Ho(Wo,"..","package.json"),"utf-8"));async function Vo(){let e=new No;e.name("kick").description("KickJS \u2014 A production-grade, decorator-driven Node.js framework").version(Jo.version);let t=await C(process.cwd());Pe(e),Je(e),Xe(e),et(e),rt(e),ct(e),dt(e),ut(e),tt(e,t),e.showHelpAfterError(),await e.parseAsync(process.argv)}s(Vo,"main");Vo().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});
2741
+ `}s(fo,"generateTinkerScript");function go(r,e){let t=r;for(;;){let o=Mt(t,"node_modules",".bin",e);if(qt(o))return o;let n=zt(t,"..");if(n===t)break;t=n}return null}s(go,"findBin");import{resolve as vo}from"path";import{join as Gt}from"path";import{readFile as $o,writeFile as yo,rm as ho}from"fs/promises";import{createInterface as ko}from"readline";function wo(r){let e=ko({input:process.stdin,output:process.stdout});return new Promise(t=>{e.question(` ${r} (y/N) `,o=>{e.close(),t(o.trim().toLowerCase()==="y")})})}s(wo,"promptConfirm");async function Qt(r){let{name:e,modulesDir:t,force:o}=r,n=r.pluralize!==!1,i=f(e),c=$(e),d=n?T(i):i,a=Gt(t,d);if(!await A(a)){console.log(`
2742
+ Module not found: ${a}
2743
+ `);return}if(!o&&!await wo(`Delete module '${d}' at ${a}? This cannot be undone.`)){console.log(`
2744
+ Cancelled.
2745
+ `);return}await ho(a,{recursive:!0,force:!0}),console.log(` Deleted: ${a}`);let p=Gt(t,"index.ts");if(await A(p)){let l=await $o(p,"utf-8"),u=l,g=new RegExp(`^import\\s*\\{\\s*${c}Module\\s*\\}\\s*from\\s*['\\./${d}']+.*\\n?`,"gm");l=l.replace(g,""),l=l.replace(new RegExp(`\\s*,?\\s*${c}Module\\s*,?`,"g"),k=>{let v=k.trimStart().startsWith(","),y=k.trimEnd().endsWith(",");return v&&y?",":""}),l=l.replace(/,(\s*])/,"$1"),l=l.replace(/\n{3,}/g,`
2746
+
2747
+ `),l!==u&&(await yo(p,l,"utf-8"),console.log(` Unregistered: ${c}Module from ${p}`))}console.log(`
2748
+ Module '${d}' removed.
2749
+ `)}s(Qt,"removeModule");function Ft(r){r.command("remove").alias("rm").description("Remove generated code").command("module <names...>").description("Remove one or more modules (e.g. kick rm module user task)").option("--modules-dir <dir>","Modules directory").option("--no-pluralize","Use singular module name").option("-f, --force","Skip confirmation prompt").action(async(t,o)=>{let n=await w(process.cwd()),i=P(n),c=o.modulesDir??i.dir??"src/modules",d=o.pluralize===!1?!1:i.pluralize??!0;for(let a of t)await Qt({name:a,modulesDir:vo(c),force:o.force,pluralize:d})})}s(Ft,"registerRemoveCommand");var Po=Ro(bo(import.meta.url)),To=JSON.parse(xo(Do(Po,"..","package.json"),"utf-8"));async function Oo(){let r=new Co;r.name("kick").description("KickJS \u2014 A production-grade, decorator-driven Node.js framework").version(To.version);let e=await w(process.cwd());Xe(r),Ct(r),Dt(r),bt(r),Ot(r),Ut(r),Et(r),_t(r),Ft(r),Pt(r,e),r.showHelpAfterError(),await r.parseAsync(process.argv)}s(Oo,"main");Oo().catch(r=>{console.error(r instanceof Error?r.message:r),process.exitCode=1});