@forinda/kickjs-cli 5.3.2 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/{builtins-CnQ6lxcV.mjs → builtins-DBzZkJey.mjs} +151 -90
  2. package/dist/builtins-DBzZkJey.mjs.map +1 -0
  3. package/dist/{builtins-BxGfcEP6.mjs → builtins-K-nRJcJG.mjs} +409 -214
  4. package/dist/cli.mjs +2 -2
  5. package/dist/config-CCNnXhar.mjs +11 -0
  6. package/dist/config-CQZ6Hppr.mjs +12 -0
  7. package/dist/config-CQZ6Hppr.mjs.map +1 -0
  8. package/dist/{generator-extension-BNgcYlom.mjs → generator-extension-Bn2aH7kY.mjs} +228 -94
  9. package/dist/generator-extension-Bn2aH7kY.mjs.map +1 -0
  10. package/dist/index.d.mts +45 -0
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +2 -2
  13. package/dist/{plugin-B56zClEX.mjs → plugin-D0C4ISZA.mjs} +2 -2
  14. package/dist/{plugin-Ccvf-gn6.mjs → plugin-DasN_2Zr.mjs} +3 -3
  15. package/dist/{plugin-Ccvf-gn6.mjs.map → plugin-DasN_2Zr.mjs.map} +1 -1
  16. package/dist/{rolldown-runtime-CP9PNXAB.mjs → rolldown-runtime-BTpMa50s.mjs} +1 -1
  17. package/dist/{run-plugins-sjeIm8hS.mjs → run-plugins-Dk7KBKON.mjs} +2 -2
  18. package/dist/{typegen-CYA1y8NJ.mjs → typegen-Bl9kUVNL.mjs} +4 -4
  19. package/dist/{typegen-CYA1y8NJ.mjs.map → typegen-Bl9kUVNL.mjs.map} +1 -1
  20. package/dist/{typegen-CFW1vIgv.mjs → typegen-DDQJNnUl.mjs} +3 -3
  21. package/dist/{types-2ICiQzlQ.mjs → types-kAfWJgh0.mjs} +2 -2
  22. package/dist/{types-2ICiQzlQ.mjs.map → types-kAfWJgh0.mjs.map} +1 -1
  23. package/package.json +2 -2
  24. package/dist/builtins-CnQ6lxcV.mjs.map +0 -1
  25. package/dist/config-B5g_GsV2.mjs +0 -12
  26. package/dist/config-B5g_GsV2.mjs.map +0 -1
  27. package/dist/config-DE9Vo6LN.mjs +0 -11
  28. package/dist/generator-extension-BNgcYlom.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v5.3.2
2
+ * @forinda/kickjs-cli v5.4.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{createRequire as e}from"node:module";import{dirname as t,extname as n,join as r,resolve as i}from"node:path";import{existsSync as a,readFileSync as o}from"node:fs";import{access as s,mkdir as c,readFile as l,writeFile as u}from"node:fs/promises";import*as d from"@clack/prompts";import f from"picocolors";import p from"pluralize";import{execSync as m}from"node:child_process";import{fileURLToPath as h,pathToFileURL as g}from"node:url";let _=!1;function v(e){_=e}const y=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function b(e,r){_||(await c(t(e),{recursive:!0}),await u(e,r,`utf-8`),y.has(n(e))&&await te(e,r).catch(()=>{}))}let x;async function ee(t){if(x!==void 0)return x;try{x=await import(e(r(t,`package.json`)).resolve(`oxfmt`))}catch{x=null}return x}async function te(e,t){let n=await ee(process.cwd());if(!n)return;let r=await ne(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await u(e,i.code,`utf-8`)}const S=new Map;async function ne(e){let n=t(e),i=n;if(S.has(i))return S.get(i);for(;;){let e=r(n,`.oxfmtrc.json`);if(a(e))try{let t=await l(e,`utf-8`),n=JSON.parse(t);return delete n.$schema,delete n.ignorePatterns,S.set(i,n),n}catch{return S.set(i,null),null}let o=t(n);if(o===n)return S.set(i,null),null;n=o}}async function C(e){try{return await s(e),!0}catch{return!1}}const re={GET:f.green,POST:f.cyan,PUT:f.yellow,PATCH:f.magenta,DELETE:f.red};function ie(e){return(re[e]??f.dim)(e.padEnd(7))}function ae(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return f.red(t);case`WARNING`:return f.yellow(t);case`INFO`:return f.blue(f.dim(t));default:return t}}f.green(`✓`),f.red(`✖`),f.yellow(`⚠`),f.blue(`ℹ`);function oe(e){d.intro(f.bgCyan(f.black(` ${e} `)))}function se(e){d.outro(e)}function w(e){d.isCancel(e)&&(d.cancel(`Operation cancelled.`),process.exit(0))}async function ce(e){let t=await d.text(e);return w(t),t}async function le(e){let t=await d.select(e);return w(t),t}async function ue(e){let t=await d.multiselect(e);return w(t),t}async function T(e){let t=await d.confirm(e);return w(t),t}function de(){return d.spinner()}const E=d.log;function D(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function O(e){let t=D(e);return t.charAt(0).toLowerCase()+t.slice(1)}function k(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function A(e){return p.plural(e)}function j(e){return p.plural(e)}const fe={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function M(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function pe(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function N(e){return fe[e]??M(e)}function P(e,t,n){let r={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},i={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`};return{repoClass:r[n]??`${M(n)}${e}Repository`,repoFile:i[n]??`${pe(n)}-${t}`}}function me(e){let{pascal:t,kebab:n,plural:r=``,repo:i}=e,{repoClass:a,repoFile:o}=P(t,n,i);return`/**
11
+ import{createRequire as e}from"node:module";import{dirname as t,extname as n,join as r,resolve as i}from"node:path";import{existsSync as a,readFileSync as o}from"node:fs";import{access as s,mkdir as c,readFile as l,writeFile as u}from"node:fs/promises";import*as d from"@clack/prompts";import f from"picocolors";import p from"pluralize";import{execSync as m}from"node:child_process";import{fileURLToPath as h,pathToFileURL as g}from"node:url";let _=!1;function v(e){_=e}const y=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function b(e,r){_||(await c(t(e),{recursive:!0}),await u(e,r,`utf-8`),y.has(n(e))&&await te(e,r).catch(()=>{}))}let x;async function ee(t){if(x!==void 0)return x;try{x=await import(e(r(t,`package.json`)).resolve(`oxfmt`))}catch{x=null}return x}async function te(e,t){let n=await ee(process.cwd());if(!n)return;let r=await ne(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await u(e,i.code,`utf-8`)}const S=new Map;async function ne(e){let n=t(e),i=n;if(S.has(i))return S.get(i);for(;;){let e=r(n,`.oxfmtrc.json`);if(a(e))try{let t=await l(e,`utf-8`),n=JSON.parse(t);return delete n.$schema,delete n.ignorePatterns,S.set(i,n),n}catch{return S.set(i,null),null}let o=t(n);if(o===n)return S.set(i,null),null;n=o}}async function C(e){try{return await s(e),!0}catch{return!1}}const re={GET:f.green,POST:f.cyan,PUT:f.yellow,PATCH:f.magenta,DELETE:f.red};function ie(e){return(re[e]??f.dim)(e.padEnd(7))}function ae(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return f.red(t);case`WARNING`:return f.yellow(t);case`INFO`:return f.blue(f.dim(t));default:return t}}f.green(`✓`),f.red(`✖`),f.yellow(`⚠`),f.blue(`ℹ`);function oe(e){d.intro(f.bgCyan(f.black(` ${e} `)))}function se(e){d.outro(e)}function w(e){d.isCancel(e)&&(d.cancel(`Operation cancelled.`),process.exit(0))}async function ce(e){let t=await d.text(e);return w(t),t}async function le(e){let t=await d.select(e);return w(t),t}async function ue(e){let t=await d.multiselect(e);return w(t),t}async function T(e){let t=await d.confirm(e);return w(t),t}function de(){return d.spinner()}const E=d.log;function D(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function O(e){let t=D(e);return t.charAt(0).toLowerCase()+t.slice(1)}function k(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function A(e){return p.plural(e)}function j(e){return p.plural(e)}const fe={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function M(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function pe(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function N(e){return fe[e]??M(e)}function P(e,t,n){let r={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},i={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`};return{repoClass:r[n]??`${M(n)}${e}Repository`,repoFile:i[n]??`${pe(n)}-${t}`}}function F(e){return e??`define`}function me(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=P(t,n,i),c=F(a),l=`/**
12
12
  * ${t} Module
13
13
  *
14
14
  * Self-contained feature module following Domain-Driven Design (DDD).
@@ -19,18 +19,34 @@ import{createRequire as e}from"node:module";import{dirname as t,extname as n,joi
19
19
  * application/ — Use cases (orchestration) and DTOs (validation)
20
20
  * domain/ — Entities, value objects, repository interfaces, domain services
21
21
  * infrastructure/ — Repository implementations (currently ${N(i)})
22
- */
23
- import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
24
- import { buildRoutes } from '@forinda/kickjs'
25
- import { ${t.toUpperCase()}_REPOSITORY } from './domain/repositories/${n}.repository'
26
- import { ${a} } from './infrastructure/repositories/${o}.repository'
22
+ */`,u=`import { ${t.toUpperCase()}_REPOSITORY } from './domain/repositories/${n}.repository'
23
+ import { ${o} } from './infrastructure/repositories/${s}.repository'
27
24
  import { ${t}Controller } from './presentation/${n}.controller'
28
25
 
29
26
  // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
30
27
  import.meta.glob(
31
28
  ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],
32
29
  { eager: true },
33
- )
30
+ )`,d=` /**
31
+ * Declare HTTP routes for this module.
32
+ *
33
+ * The path is prefixed with the global apiPrefix and version
34
+ * (e.g. /api/v1/${r}). The framework derives the Express
35
+ * Router from the controller via \`buildRoutes()\` and uses the
36
+ * same controller for OpenAPI spec generation via SwaggerAdapter.
37
+ *
38
+ * Return an **array** to mount multiple route sets under the
39
+ * same module (e.g. side-by-side v1 + v2 controllers). Each
40
+ * entry can override the API version with a \`version\` field —
41
+ * the mount path becomes \`/{apiPrefix}/v{version}{path}\`:
42
+ *
43
+ * return [
44
+ * { path: '/${r}', version: 1, controller: ${t}V1Controller },
45
+ * { path: '/${r}', version: 2, controller: ${t}V2Controller },
46
+ * ]
47
+ */`;return c===`class`?`${l}
48
+ import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
49
+ ${u}
34
50
 
35
51
  export class ${t}Module implements AppModule {
36
52
  /**
@@ -40,24 +56,46 @@ export class ${t}Module implements AppModule {
40
56
  */
41
57
  register(container: Container): void {
42
58
  container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
43
- container.resolve(${a}),
59
+ container.resolve(${o}),
44
60
  )
45
61
  }
46
62
 
47
- /**
48
- * Declare HTTP routes for this module.
49
- * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${r}).
50
- * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.
51
- */
63
+ ${d.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
52
64
  routes(): ModuleRoutes {
53
65
  return {
54
66
  path: '/${r}',
55
- router: buildRoutes(${t}Controller),
56
67
  controller: ${t}Controller,
57
68
  }
58
69
  }
59
70
  }
60
- `}function he(e){let{pascal:t,kebab:n,plural:r=``,repo:i}=e,{repoClass:a,repoFile:o}=P(t,n,i);return`/**
71
+ `:`${l}
72
+ import { defineModule } from '@forinda/kickjs'
73
+ ${u}
74
+
75
+ export const ${t}Module = defineModule({
76
+ name: '${t}Module',
77
+ build: () => ({
78
+ /**
79
+ * Register module dependencies in the DI container.
80
+ * Bind repository interface tokens to their implementations here.
81
+ * Currently wired to ${N(i)}. To swap implementations, change the factory target.
82
+ */
83
+ register(container) {
84
+ container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
85
+ container.resolve(${o}),
86
+ )
87
+ },
88
+
89
+ ${d}
90
+ routes() {
91
+ return {
92
+ path: '/${r}',
93
+ controller: ${t}Controller,
94
+ }
95
+ },
96
+ }),
97
+ })
98
+ `}function he(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=P(t,n,i),c=F(a),l=`/**
61
99
  * ${t} Module
62
100
  *
63
101
  * REST module with a flat folder structure.
@@ -67,46 +105,106 @@ export class ${t}Module implements AppModule {
67
105
  * ${n}.controller.ts — HTTP routes (CRUD)
68
106
  * ${n}.service.ts — Business logic
69
107
  * ${n}.repository.ts — Repository interface
70
- * ${o}.repository.ts — Repository implementation
108
+ * ${s}.repository.ts — Repository implementation
71
109
  * dtos/ — Request/response schemas
72
- */
73
- import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
74
- import { buildRoutes } from '@forinda/kickjs'
75
- import { ${t.toUpperCase()}_REPOSITORY } from './${n}.repository'
76
- import { ${a} } from './${o}.repository'
110
+ */`,u=`import { ${t.toUpperCase()}_REPOSITORY } from './${n}.repository'
111
+ import { ${o} } from './${s}.repository'
77
112
  import { ${t}Controller } from './${n}.controller'
78
113
 
79
114
  // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
80
- import.meta.glob(['./**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'], { eager: true })
115
+ import.meta.glob(['./**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'], { eager: true })`,d=` /**
116
+ * Declare HTTP routes for this module.
117
+ *
118
+ * Pass \`controller\` and the framework derives the Express
119
+ * Router via \`buildRoutes()\` and uses the same controller for
120
+ * OpenAPI spec generation through SwaggerAdapter.
121
+ *
122
+ * Return an **array** to mount multiple route sets under the
123
+ * same module (side-by-side v1 + v2 controllers, admin surfaces).
124
+ * Each entry can override the API version with a \`version\` field:
125
+ *
126
+ * return [
127
+ * { path: '/${r}', version: 1, controller: ${t}V1Controller },
128
+ * { path: '/${r}', version: 2, controller: ${t}V2Controller },
129
+ * ]
130
+ */`;return c===`class`?`${l}
131
+ import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
132
+ ${u}
81
133
 
82
134
  export class ${t}Module implements AppModule {
83
135
  register(container: Container): void {
84
136
  container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
85
- container.resolve(${a}),
137
+ container.resolve(${o}),
86
138
  )
87
139
  }
88
140
 
141
+ ${d.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
89
142
  routes(): ModuleRoutes {
90
143
  return {
91
144
  path: '/${r}',
92
- router: buildRoutes(${t}Controller),
93
145
  controller: ${t}Controller,
94
146
  }
95
147
  }
96
148
  }
97
- `}function ge(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { type AppModule, type ModuleRoutes } from '@forinda/kickjs'
98
- import { buildRoutes } from '@forinda/kickjs'
149
+ `:`${l}
150
+ import { defineModule } from '@forinda/kickjs'
151
+ ${u}
152
+
153
+ export const ${t}Module = defineModule({
154
+ name: '${t}Module',
155
+ build: () => ({
156
+ register(container) {
157
+ container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
158
+ container.resolve(${o}),
159
+ )
160
+ },
161
+
162
+ ${d}
163
+ routes() {
164
+ return {
165
+ path: '/${r}',
166
+ controller: ${t}Controller,
167
+ }
168
+ },
169
+ }),
170
+ })
171
+ `}function ge(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=F(i),o=` /**
172
+ * Pass \`controller\` and the framework derives the Express
173
+ * Router via \`buildRoutes()\`. Return an array to mount multiple
174
+ * route sets — each entry can override the API version with a
175
+ * \`version\` field:
176
+ *
177
+ * return [
178
+ * { path: '/${r}', version: 1, controller: ${t}V1Controller },
179
+ * { path: '/${r}', version: 2, controller: ${t}V2Controller },
180
+ * ]
181
+ */`;return a===`class`?`import { type AppModule, type ModuleRoutes } from '@forinda/kickjs'
99
182
  import { ${t}Controller } from './${n}.controller'
100
183
 
101
184
  export class ${t}Module implements AppModule {
185
+ ${o.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
102
186
  routes(): ModuleRoutes {
103
187
  return {
104
188
  path: '/${r}',
105
- router: buildRoutes(${t}Controller),
106
189
  controller: ${t}Controller,
107
190
  }
108
191
  }
109
192
  }
193
+ `:`import { defineModule } from '@forinda/kickjs'
194
+ import { ${t}Controller } from './${n}.controller'
195
+
196
+ export const ${t}Module = defineModule({
197
+ name: '${t}Module',
198
+ build: () => ({
199
+ ${o}
200
+ routes() {
201
+ return {
202
+ path: '/${r}',
203
+ controller: ${t}Controller,
204
+ }
205
+ },
206
+ }),
207
+ })
110
208
  `}function _e(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
111
209
  import { ApiTags } from '@forinda/kickjs-swagger'
112
210
  import { Create${t}UseCase } from '../application/use-cases/create-${n}.use-case'
@@ -232,7 +330,7 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
232
330
  sortable: ['name', 'createdAt'],
233
331
  searchable: ['name'],
234
332
  }
235
- `}function F(e){let{pascal:t}=e;return`import { z } from 'zod'
333
+ `}function I(e){let{pascal:t}=e;return`import { z } from 'zod'
236
334
 
237
335
  /**
238
336
  * Create ${t} DTO — Zod schema for validating POST request bodies.
@@ -248,14 +346,14 @@ export const create${t}Schema = z.object({
248
346
  })
249
347
 
250
348
  export type Create${t}DTO = z.infer<typeof create${t}Schema>
251
- `}function I(e){let{pascal:t}=e;return`import { z } from 'zod'
349
+ `}function L(e){let{pascal:t}=e;return`import { z } from 'zod'
252
350
 
253
351
  export const update${t}Schema = z.object({
254
352
  name: z.string().min(1).max(200).optional(),
255
353
  })
256
354
 
257
355
  export type Update${t}DTO = z.infer<typeof update${t}Schema>
258
- `}function L(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
356
+ `}function R(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
259
357
  id: string
260
358
  name: string
261
359
  createdAt: string
@@ -339,7 +437,7 @@ export class Delete${t}UseCase {
339
437
  await this.repo.delete(id)
340
438
  }
341
439
  }
342
- `}]}function R(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
440
+ `}]}function z(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
343
441
  * ${t} Repository Interface
344
442
  *
345
443
  * Defines the contract for data access.
@@ -374,7 +472,7 @@ export interface I${t}Repository {
374
472
  * adopters must NOT use the reserved \`'kick/'\` namespace.
375
473
  */
376
474
  export const ${t.toUpperCase()}_REPOSITORY = createToken<I${t}Repository>('${i}/${t}/repository')
377
- `}function z(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
475
+ `}function B(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
378
476
  * In-Memory ${t} Repository
379
477
  *
380
478
  * Implements the repository interface using a Map.
@@ -434,7 +532,7 @@ export class InMemory${t}Repository implements I${t}Repository {
434
532
  this.store.delete(id)
435
533
  }
436
534
  }
437
- `}function B(e){let{pascal:t,kebab:n,repoType:r=``,repoPrefix:i=`../../domain/repositories`,dtoPrefix:a=`../../application/dtos`}=e,o=r.charAt(0).toUpperCase()+r.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
535
+ `}function V(e){let{pascal:t,kebab:n,repoType:r=``,repoPrefix:i=`../../domain/repositories`,dtoPrefix:a=`../../application/dtos`}=e,o=r.charAt(0).toUpperCase()+r.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
438
536
  * ${o} ${t} Repository
439
537
  *
440
538
  * Stub implementation for a custom '${r}' repository.
@@ -629,7 +727,7 @@ export class ${t}Id {
629
727
  return this.value === other.value
630
728
  }
631
729
  }
632
- `}function V(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
730
+ `}function H(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
633
731
  import { Container } from '@forinda/kickjs'
634
732
 
635
733
  describe('${t}Controller', () => {
@@ -681,7 +779,7 @@ describe('${t}Controller', () => {
681
779
  })
682
780
  })
683
781
  })
684
- `}function H(e){let{pascal:t,kebab:n,plural:r=``,repoPrefix:i=`../infrastructure/repositories/in-memory-${n}.repository`}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
782
+ `}function U(e){let{pascal:t,kebab:n,plural:r=``,repoPrefix:i=`../infrastructure/repositories/in-memory-${n}.repository`}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
685
783
  import { InMemory${t}Repository } from '${i}'
686
784
 
687
785
  describe('InMemory${t}Repository', () => {
@@ -780,14 +878,14 @@ export class ${t}Service {
780
878
  await this.repo.delete(id)
781
879
  }
782
880
  }
783
- `}function U(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
881
+ `}function W(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
784
882
 
785
883
  export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
786
884
  filterable: ['name'],
787
885
  sortable: ['name', 'createdAt'],
788
886
  searchable: ['name'],
789
887
  }
790
- `}function Te(e){let{pascal:t,kebab:n,plural:r=``,repo:i}=e,a={inmemory:`InMemory${t}Repository`,drizzle:`Drizzle${t}Repository`,prisma:`Prisma${t}Repository`},o={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},s=a[i]??a.inmemory,c=o[i]??o.inmemory;return`/**
888
+ `}function Te(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o={inmemory:`InMemory${t}Repository`,drizzle:`Drizzle${t}Repository`,prisma:`Prisma${t}Repository`},s={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},c=o[i]??o.inmemory,l=s[i]??s.inmemory,u=a??`define`,d=`/**
791
889
  * ${t} Module — CQRS Pattern
792
890
  *
793
891
  * Separates read (queries) and write (commands) operations.
@@ -799,11 +897,8 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
799
897
  * queries/ — Read operations (get, list)
800
898
  * events/ — Domain events + handlers (WS broadcast, queue dispatch)
801
899
  * dtos/ — Request/response schemas
802
- */
803
- import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
804
- import { buildRoutes } from '@forinda/kickjs'
805
- import { ${t.toUpperCase()}_REPOSITORY } from './${n}.repository'
806
- import { ${s} } from './${c}.repository'
900
+ */`,f=`import { ${t.toUpperCase()}_REPOSITORY } from './${n}.repository'
901
+ import { ${c} } from './${l}.repository'
807
902
  import { ${t}Controller } from './${n}.controller'
808
903
 
809
904
  // Eagerly load decorated classes
@@ -815,23 +910,58 @@ import.meta.glob(
815
910
  '!./**/*.test.ts',
816
911
  ],
817
912
  { eager: true },
818
- )
913
+ )`,p=` /**
914
+ * Declare HTTP routes. Pass \`controller\` and the framework
915
+ * derives the Express Router via \`buildRoutes()\` and uses the
916
+ * same controller for OpenAPI spec generation. Return an array
917
+ * to mount multiple route sets — each entry can override the API
918
+ * version with a \`version\` field:
919
+ *
920
+ * return [
921
+ * { path: '/${r}', version: 1, controller: ${t}V1Controller },
922
+ * { path: '/${r}', version: 2, controller: ${t}V2Controller },
923
+ * ]
924
+ */`;return u===`class`?`${d}
925
+ import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
926
+ ${f}
819
927
 
820
928
  export class ${t}Module implements AppModule {
821
929
  register(container: Container): void {
822
930
  container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
823
- container.resolve(${s}),
931
+ container.resolve(${c}),
824
932
  )
825
933
  }
826
934
 
935
+ ${p.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
827
936
  routes(): ModuleRoutes {
828
937
  return {
829
938
  path: '/${r}',
830
- router: buildRoutes(${t}Controller),
831
939
  controller: ${t}Controller,
832
940
  }
833
941
  }
834
942
  }
943
+ `:`${d}
944
+ import { defineModule } from '@forinda/kickjs'
945
+ ${f}
946
+
947
+ export const ${t}Module = defineModule({
948
+ name: '${t}Module',
949
+ build: () => ({
950
+ register(container) {
951
+ container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
952
+ container.resolve(${c}),
953
+ )
954
+ },
955
+
956
+ ${p}
957
+ routes() {
958
+ return {
959
+ path: '/${r}',
960
+ controller: ${t}Controller,
961
+ }
962
+ },
963
+ }),
964
+ })
835
965
  `}function Ee(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
836
966
  import { ApiTags } from '@forinda/kickjs-swagger'
837
967
  import { Create${t}Command } from './commands/create-${n}.command'
@@ -1063,7 +1193,7 @@ export class On${t}ChangeHandler {
1063
1193
  })
1064
1194
  }
1065
1195
  }
1066
- `}]}function W(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1196
+ `}]}function G(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1067
1197
  * Drizzle ${t} Repository
1068
1198
  *
1069
1199
  * Implements the repository interface using Drizzle ORM.
@@ -1163,7 +1293,7 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {
1163
1293
  // ${n}s.name,
1164
1294
  ],
1165
1295
  }
1166
- `}function G(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e,a=n.replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
1296
+ `}function K(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e,a=n.replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
1167
1297
  * Prisma ${t} Repository
1168
1298
  *
1169
1299
  * Implements the repository interface using Prisma Client.
@@ -1291,11 +1421,13 @@ export const app = await bootstrap({
1291
1421
  express.json(),
1292
1422
  ],
1293
1423
  })
1294
- `}}}function Me(){return`import type { AppModuleClass } from '@forinda/kickjs'
1424
+ `}}}function Me(){return`import type { AppModuleEntry } from '@forinda/kickjs'
1295
1425
  import { HelloModule } from './hello/hello.module'
1296
1426
 
1297
1427
  // Remove HelloModule and run: kick g module <name>
1298
- export const modules: AppModuleClass[] = [HelloModule]
1428
+ // Modules built with \`defineModule\` are called as factories — the
1429
+ // invocation produces the AppModule instance bootstrap registers.
1430
+ export const modules: AppModuleEntry[] = [HelloModule()]
1299
1431
  `}function Ne(){return`import { defineEnv, loadEnv } from '@forinda/kickjs/config'
1300
1432
  import { z } from 'zod'
1301
1433
 
@@ -1365,25 +1497,27 @@ export class HelloController {
1365
1497
  ctx.json(this.helloService.healthCheck())
1366
1498
  }
1367
1499
  }
1368
- `}function Ie(){return`import { type AppModule, type ModuleRoutes, buildRoutes } from '@forinda/kickjs'
1500
+ `}function Ie(){return`import { defineModule } from '@forinda/kickjs'
1369
1501
  import { HelloController } from './hello.controller'
1370
1502
 
1371
- export class HelloModule implements AppModule {
1372
- // \`register(container)\` is optional — only implement it when you need
1373
- // to bind a token to a concrete implementation, e.g.
1374
- // register(container) {
1375
- // container.registerFactory(USER_REPOSITORY, () => container.resolve(InMemoryUserRepository))
1376
- // }
1377
- // The HelloService uses @Service() so the decorator handles registration.
1378
-
1379
- routes(): ModuleRoutes {
1380
- return {
1381
- path: '/hello',
1382
- router: buildRoutes(HelloController),
1383
- controller: HelloController,
1384
- }
1385
- }
1386
- }
1503
+ export const HelloModule = defineModule({
1504
+ name: 'HelloModule',
1505
+ build: () => ({
1506
+ // \`register(container)\` is optional — only implement it when you need
1507
+ // to bind a token to a concrete implementation, e.g.
1508
+ // register(container) {
1509
+ // container.registerFactory(USER_REPOSITORY, () => container.resolve(InMemoryUserRepository))
1510
+ // }
1511
+ // The HelloService uses @Service() so the decorator handles registration.
1512
+
1513
+ routes() {
1514
+ return {
1515
+ path: '/hello',
1516
+ controller: HelloController,
1517
+ }
1518
+ },
1519
+ }),
1520
+ })
1387
1521
  `}function Le(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
1388
1522
 
1389
1523
  export default defineConfig({
@@ -1428,7 +1562,7 @@ export default defineConfig({
1428
1562
  },
1429
1563
  ],
1430
1564
  })
1431
- `}async function Re(e){let{pascal:t,kebab:n,plural:r,write:i}=e;await i(`${n}.module.ts`,ge({pascal:t,kebab:n,plural:r})),await i(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
1565
+ `}async function Re(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,ge({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
1432
1566
 
1433
1567
  // \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
1434
1568
  // \`kick typegen\` (auto-run on \`kick dev\`).
@@ -1440,14 +1574,14 @@ export class ${t}Controller {
1440
1574
  ctx.json({ message: '${t} list' })
1441
1575
  }
1442
1576
  }
1443
- `)}async function ze(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,write:l}=e;await l(`${n}.module.ts`,he({pascal:t,kebab:n,plural:r,repo:a})),await l(`${n}.constants.ts`,U({pascal:t,kebab:n})),await l(`${n}.controller.ts`,ve({pascal:t,kebab:n,plural:r,pluralPascal:i})),await l(`${n}.service.ts`,we({pascal:t,kebab:n})),await l(`dtos/create-${n}.dto.ts`,F({pascal:t,kebab:n})),await l(`dtos/update-${n}.dto.ts`,I({pascal:t,kebab:n})),await l(`dtos/${n}-response.dto.ts`,L({pascal:t,kebab:n})),await l(`${n}.repository.ts`,R({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let u={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},d={inmemory:()=>z({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>W({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>G({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},f=u[a]??`${k(a)}-${n}`,p=d[a]??(()=>B({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await l(`${f}.repository.ts`,p()),o||(a!==`inmemory`&&await l(`in-memory-${n}.repository.ts`,z({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await l(`__tests__/${n}.controller.test.ts`,V({pascal:t,kebab:n,plural:r})),await l(`__tests__/${n}.repository.test.ts`,H({pascal:t,kebab:n,plural:r,repoPrefix:`../${u.inmemory??`in-memory-${n}`}.repository`})))}async function Be(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,write:l}=e;await l(`${n}.module.ts`,Te({pascal:t,kebab:n,plural:r,repo:a})),await l(`${n}.constants.ts`,U({pascal:t,kebab:n})),await l(`${n}.controller.ts`,Ee({pascal:t,kebab:n,plural:r,pluralPascal:i})),await l(`dtos/create-${n}.dto.ts`,F({pascal:t,kebab:n})),await l(`dtos/update-${n}.dto.ts`,I({pascal:t,kebab:n})),await l(`dtos/${n}-response.dto.ts`,L({pascal:t,kebab:n}));let u=De({pascal:t,kebab:n});for(let e of u)await l(`commands/${e.file}`,e.content);let d=Oe({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of d)await l(`queries/${e.file}`,e.content);let f=ke({pascal:t,kebab:n});for(let e of f)await l(`events/${e.file}`,e.content);await l(`${n}.repository.ts`,R({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let p={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},m={inmemory:()=>z({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>W({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>G({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},h=p[a]??`${k(a)}-${n}`,g=m[a]??(()=>B({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await l(`${h}.repository.ts`,g()),o||(a!==`inmemory`&&await l(`in-memory-${n}.repository.ts`,z({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await l(`__tests__/${n}.controller.test.ts`,V({pascal:t,kebab:n,plural:r})),await l(`__tests__/${n}.repository.test.ts`,H({pascal:t,kebab:n,plural:r,repoPrefix:`../${p.inmemory??`in-memory-${n}`}.repository`})))}async function Ve(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noEntity:o,noTests:s,prismaClientPath:c,tokenScope:l,write:u}=e;await u(`${n}.module.ts`,me({pascal:t,kebab:n,plural:r,repo:a})),await u(`constants.ts`,a===`drizzle`?Ae({pascal:t,kebab:n}):ye({pascal:t,kebab:n})),await u(`presentation/${n}.controller.ts`,_e({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`application/dtos/create-${n}.dto.ts`,F({pascal:t,kebab:n})),await u(`application/dtos/update-${n}.dto.ts`,I({pascal:t,kebab:n})),await u(`application/dtos/${n}-response.dto.ts`,L({pascal:t,kebab:n}));let d=be({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of d)await u(`application/use-cases/${e.file}`,e.content);await u(`domain/repositories/${n}.repository.ts`,R({pascal:t,kebab:n,tokenScope:l})),await u(`domain/services/${n}-domain.service.ts`,xe({pascal:t,kebab:n}));let f={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},p={inmemory:()=>z({pascal:t,kebab:n}),drizzle:()=>W({pascal:t,kebab:n}),prisma:()=>G({pascal:t,kebab:n,prismaClientPath:c})},m=f[a]??`${k(a)}-${n}`,h=p[a]??(()=>B({pascal:t,kebab:n,repoType:a}));await u(`infrastructure/repositories/${m}.repository.ts`,h()),o||(await u(`domain/entities/${n}.entity.ts`,Se({pascal:t,kebab:n})),await u(`domain/value-objects/${n}-id.vo.ts`,Ce({pascal:t,kebab:n}))),s||(a!==`inmemory`&&await u(`infrastructure/repositories/in-memory-${n}.repository.ts`,z({pascal:t,kebab:n})),await u(`__tests__/${n}.controller.test.ts`,V({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,H({pascal:t,kebab:n,plural:r})))}function He(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function Ue(e){let{name:t,modulesDir:n,noEntity:i,noTests:a,repo:o=`inmemory`,force:s,dryRun:c}=e,l=e.pluralize!==!1,u=e.pattern??`ddd`;e.minimal&&(u=`minimal`);let d=k(t),p=D(t),m=l?A(d):d,h=l?j(p):p,g=r(n,m),_=[],v=s??!1,y={kebab:d,pascal:p,plural:m,pluralPascal:h,moduleDir:g,repo:o,noEntity:i??!1,noTests:a??!1,prismaClientPath:e.prismaClientPath??`@prisma/client`,tokenScope:e.tokenScope??`app`,write:async(e,t)=>{let n=r(g,e);if(c){_.push(n);return}if(!v&&await C(n)&&!await T({message:`File exists: ${f.dim(e)}. Overwrite?`,initialValue:!1})){E.warn(`Skipped: ${e}`);return}await b(n,t),_.push(n)},files:_};switch(u){case`minimal`:await Re(y);break;case`rest`:await ze(y);break;case`cqrs`:await Be(y);break;default:await Ve(y);break}return c||await We(n,p,m,d),_}async function We(e,t,n,i){let a=r(e,`index.ts`),o=await C(a),s=`./${n}/${i}.module`;if(!o){await b(a,`import type { AppModuleClass } from '@forinda/kickjs'
1444
- import { ${t}Module } from '${s}'
1445
-
1446
- export const modules: AppModuleClass[] = [${t}Module]
1447
- `);return}let c=await l(a,`utf-8`),d=`import { ${t}Module } from '${s}'`;if(!c.includes(`${t}Module`)){let e=c.lastIndexOf(`import `);if(e!==-1){let t=c.indexOf(`
1448
- `,e);c=c.slice(0,t+1)+d+`
1449
- `+c.slice(t+1)}else c=d+`
1450
- `+c;c=c.replace(/(=\s*\[)([\s\S]*?)(])/,(e,n,r,i)=>{let a=r.trim();if(!a)return`${n}${t}Module${i}`;let o=a.endsWith(`,`)?``:`,`;return`${n}${r.trimEnd()}${o} ${t}Module${i}`})}await u(a,c,`utf-8`)}async function Ge(e){let{name:t,outDir:n}=e,i=k(t),a=D(t),o=[],s=r(n,`${i}.adapter.ts`);return await b(s,`import {
1577
+ `)}async function ze(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,he({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,W({pascal:t,kebab:n})),await u(`${n}.controller.ts`,ve({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`${n}.service.ts`,we({pascal:t,kebab:n})),await u(`dtos/create-${n}.dto.ts`,I({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,L({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,R({pascal:t,kebab:n})),await u(`${n}.repository.ts`,z({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let d={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},f={inmemory:()=>B({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>G({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>K({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},p=d[a]??`${k(a)}-${n}`,m=f[a]??(()=>V({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${p}.repository.ts`,m()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,B({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,H({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,U({pascal:t,kebab:n,plural:r,repoPrefix:`../${d.inmemory??`in-memory-${n}`}.repository`})))}async function Be(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,Te({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,W({pascal:t,kebab:n})),await u(`${n}.controller.ts`,Ee({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`dtos/create-${n}.dto.ts`,I({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,L({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,R({pascal:t,kebab:n}));let d=De({pascal:t,kebab:n});for(let e of d)await u(`commands/${e.file}`,e.content);let f=Oe({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await u(`queries/${e.file}`,e.content);let p=ke({pascal:t,kebab:n});for(let e of p)await u(`events/${e.file}`,e.content);await u(`${n}.repository.ts`,z({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let m={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},h={inmemory:()=>B({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>G({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>K({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},g=m[a]??`${k(a)}-${n}`,_=h[a]??(()=>V({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${g}.repository.ts`,_()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,B({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,H({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,U({pascal:t,kebab:n,plural:r,repoPrefix:`../${m.inmemory??`in-memory-${n}`}.repository`})))}async function Ve(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noEntity:o,noTests:s,prismaClientPath:c,tokenScope:l,style:u,write:d}=e;await d(`${n}.module.ts`,me({pascal:t,kebab:n,plural:r,repo:a,style:u})),await d(`constants.ts`,a===`drizzle`?Ae({pascal:t,kebab:n}):ye({pascal:t,kebab:n})),await d(`presentation/${n}.controller.ts`,_e({pascal:t,kebab:n,plural:r,pluralPascal:i})),await d(`application/dtos/create-${n}.dto.ts`,I({pascal:t,kebab:n})),await d(`application/dtos/update-${n}.dto.ts`,L({pascal:t,kebab:n})),await d(`application/dtos/${n}-response.dto.ts`,R({pascal:t,kebab:n}));let f=be({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await d(`application/use-cases/${e.file}`,e.content);await d(`domain/repositories/${n}.repository.ts`,z({pascal:t,kebab:n,tokenScope:l})),await d(`domain/services/${n}-domain.service.ts`,xe({pascal:t,kebab:n}));let p={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},m={inmemory:()=>B({pascal:t,kebab:n}),drizzle:()=>G({pascal:t,kebab:n}),prisma:()=>K({pascal:t,kebab:n,prismaClientPath:c})},h=p[a]??`${k(a)}-${n}`,g=m[a]??(()=>V({pascal:t,kebab:n,repoType:a}));await d(`infrastructure/repositories/${h}.repository.ts`,g()),o||(await d(`domain/entities/${n}.entity.ts`,Se({pascal:t,kebab:n})),await d(`domain/value-objects/${n}-id.vo.ts`,Ce({pascal:t,kebab:n}))),s||(a!==`inmemory`&&await d(`infrastructure/repositories/in-memory-${n}.repository.ts`,B({pascal:t,kebab:n})),await d(`__tests__/${n}.controller.test.ts`,H({pascal:t,kebab:n,plural:r})),await d(`__tests__/${n}.repository.test.ts`,U({pascal:t,kebab:n,plural:r})))}function He(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function Ue(e){let{name:t,modulesDir:n,noEntity:i,noTests:a,repo:o=`inmemory`,force:s,dryRun:c}=e,l=e.pluralize!==!1,u=e.pattern??`ddd`;e.minimal&&(u=`minimal`);let d=k(t),p=D(t),m=l?A(d):d,h=l?j(p):p,g=r(n,m),_=[],v=s??!1,y={kebab:d,pascal:p,plural:m,pluralPascal:h,moduleDir:g,repo:o,noEntity:i??!1,noTests:a??!1,prismaClientPath:e.prismaClientPath??`@prisma/client`,tokenScope:e.tokenScope??`app`,style:e.style??`define`,write:async(e,t)=>{let n=r(g,e);if(c){_.push(n);return}if(!v&&await C(n)&&!await T({message:`File exists: ${f.dim(e)}. Overwrite?`,initialValue:!1})){E.warn(`Skipped: ${e}`);return}await b(n,t),_.push(n)},files:_};switch(u){case`minimal`:await Re(y);break;case`rest`:await ze(y);break;case`cqrs`:await Be(y);break;default:await Ve(y);break}return c||await We(n,p,m,d,y.style),_}async function We(e,t,n,i,a=`define`){let o=r(e,`index.ts`),s=await C(o),c=`./${n}/${i}.module`,d=a===`class`?`${t}Module`:`${t}Module()`;if(!s){await b(o,`import type { AppModuleEntry } from '@forinda/kickjs'
1578
+ import { ${t}Module } from '${c}'
1579
+
1580
+ export const modules: AppModuleEntry[] = [${d}]
1581
+ `);return}let f=await l(o,`utf-8`),p=`import { ${t}Module } from '${c}'`;if(!f.includes(`${t}Module`)){let e=f.lastIndexOf(`import `);if(e!==-1){let t=f.indexOf(`
1582
+ `,e);f=f.slice(0,t+1)+p+`
1583
+ `+f.slice(t+1)}else f=p+`
1584
+ `+f;f=f.replace(/(=\s*\[)([\s\S]*?)(])/,(e,t,n,r)=>{let i=n.trim();if(!i)return`${t}${d}${r}`;let a=i.endsWith(`,`)?``:`,`;return`${t}${n.trimEnd()}${a} ${d}${r}`})}await u(o,f,`utf-8`)}async function Ge(e){let{name:t,outDir:n}=e,i=k(t),a=D(t),o=[],s=r(n,`${i}.adapter.ts`);return await b(s,`import {
1451
1585
  defineAdapter,
1452
1586
  type AdapterContext,
1453
1587
  type AdapterMiddleware,
@@ -1616,7 +1750,7 @@ export const ${a}Adapter = defineAdapter<${a}AdapterConfig>({
1616
1750
  }
1617
1751
  },
1618
1752
  })
1619
- `),o.push(s),o}const Ke={controller:`presentation`,service:`domain/services`,dto:`application/dtos`,guard:`presentation/guards`,middleware:`middleware`},qe={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`},Je={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,command:`commands`,query:`queries`,event:`events`};function K(e){let{type:t,outDir:n,moduleName:a,modulesDir:o=`src/modules`,defaultDir:s,pattern:c=`ddd`,shouldPluralize:l=!0}=e;if(n)return i(n);if(a){let e=c===`ddd`?Ke:c===`cqrs`?Je:qe,n=k(a),s=l?A(n):n,u=e[t]??``,d=r(o,s);return i(u?r(d,u):d)}return i(s)}async function Ye(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=K({type:`middleware`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/middleware`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=O(t),l=[],u=r(o,`${s}.middleware.ts`);return await b(u,`import type { Request, Response, NextFunction } from 'express'
1753
+ `),o.push(s),o}const Ke={controller:`presentation`,service:`domain/services`,dto:`application/dtos`,guard:`presentation/guards`,middleware:`middleware`},qe={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`},Je={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,command:`commands`,query:`queries`,event:`events`};function q(e){let{type:t,outDir:n,moduleName:a,modulesDir:o=`src/modules`,defaultDir:s,pattern:c=`ddd`,shouldPluralize:l=!0}=e;if(n)return i(n);if(a){let e=c===`ddd`?Ke:c===`cqrs`?Je:qe,n=k(a),s=l?A(n):n,u=e[t]??``,d=r(o,s);return i(u?r(d,u):d)}return i(s)}async function Ye(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=q({type:`middleware`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/middleware`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=O(t),l=[],u=r(o,`${s}.middleware.ts`);return await b(u,`import type { Request, Response, NextFunction } from 'express'
1620
1754
 
1621
1755
  export interface ${D(t)}Options {
1622
1756
  // Add configuration options here
@@ -1640,7 +1774,7 @@ export function ${c}(options: ${D(t)}Options = {}) {
1640
1774
  next()
1641
1775
  }
1642
1776
  }
1643
- `),l.push(u),l}async function Xe(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=K({type:`guard`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/guards`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=O(t),l=D(t),u=[],d=r(o,`${s}.guard.ts`);return await b(d,`import { Container, HttpException } from '@forinda/kickjs'
1777
+ `),l.push(u),l}async function Xe(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=q({type:`guard`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/guards`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=O(t),l=D(t),u=[],d=r(o,`${s}.guard.ts`);return await b(d,`import { Container, HttpException } from '@forinda/kickjs'
1644
1778
  import type { RequestContext } from '@forinda/kickjs'
1645
1779
 
1646
1780
  /**
@@ -1676,7 +1810,7 @@ export async function ${c}Guard(ctx: RequestContext, next: () => void): Promise<
1676
1810
  ctx.res.status(401).json({ message: 'Invalid or expired token' })
1677
1811
  }
1678
1812
  }
1679
- `),u.push(d),u}async function Ze(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=K({type:`service`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/services`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=D(t),l=[],u=r(o,`${s}.service.ts`);return await b(u,`import { Service } from '@forinda/kickjs'
1813
+ `),u.push(d),u}async function Ze(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=q({type:`service`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/services`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=D(t),l=[],u=r(o,`${s}.service.ts`);return await b(u,`import { Service } from '@forinda/kickjs'
1680
1814
 
1681
1815
  @Service()
1682
1816
  export class ${c}Service {
@@ -1685,7 +1819,7 @@ export class ${c}Service {
1685
1819
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
1686
1820
  // ) {}
1687
1821
  }
1688
- `),l.push(u),l}async function Qe(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=K({type:`controller`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/controllers`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=D(t),l=[],u=r(o,`${s}.controller.ts`);return await b(u,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
1822
+ `),l.push(u),l}async function Qe(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=q({type:`controller`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/controllers`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=D(t),l=[],u=r(o,`${s}.controller.ts`);return await b(u,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
1689
1823
 
1690
1824
  // \`Ctx<KickRoutes.${c}Controller['<method>']>\` is generated by
1691
1825
  // \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
@@ -1706,7 +1840,7 @@ export class ${c}Controller {
1706
1840
  ctx.created({ message: '${c} created', data: ctx.body })
1707
1841
  }
1708
1842
  }
1709
- `),l.push(u),l}async function $e(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=K({type:`dto`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/dtos`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=D(t),l=O(t),u=[],d=r(o,`${s}.dto.ts`);return await b(d,`import { z } from 'zod'
1843
+ `),l.push(u),l}async function $e(e){let{name:t,moduleName:n,modulesDir:i,pattern:a}=e,o=q({type:`dto`,outDir:e.outDir,moduleName:n,modulesDir:i,defaultDir:`src/dtos`,pattern:a,shouldPluralize:e.pluralize??!0}),s=k(t),c=D(t),l=O(t),u=[],d=r(o,`${s}.dto.ts`);return await b(d,`import { z } from 'zod'
1710
1844
 
1711
1845
  export const ${l}Schema = z.object({
1712
1846
  // Define your schema fields here
@@ -1865,7 +1999,7 @@ Copy \`.env.example\` to \`.env\` and configure:
1865
1999
 
1866
2000
  - [KickJS Documentation](https://forinda.github.io/kick-js/)
1867
2001
  - [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
1868
- `}function q(e,t,n){return`# CLAUDE.md — ${e}
2002
+ `}function J(e,t,n){return`# CLAUDE.md — ${e}
1869
2003
 
1870
2004
  **Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
1871
2005
  reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
@@ -1931,7 +2065,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
1931
2065
  - **Refresh these files**: \`kick g agents -f\` regenerates \`AGENTS.md\` + \`CLAUDE.md\` from the latest CLI templates. Hand-edited content is overwritten — keep customisation in \`AGENTS.local.md\`.
1932
2066
 
1933
2067
  For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`AGENTS.md\`.
1934
- `}function J(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
2068
+ `}function Y(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
1935
2069
 
1936
2070
  This guide is the **canonical, multi-agent reference** for this KickJS
1937
2071
  application — Claude, Copilot, Codex, Gemini, etc. all read it first.
@@ -2036,7 +2170,7 @@ mistakes:
2036
2170
 
2037
2171
  \`\`\`ts
2038
2172
  // src/modules/index.ts
2039
- export const modules: AppModuleClass[] = [HelloModule, UsersModule, ...]
2173
+ export const modules: AppModuleEntry[] = [HelloModule(), UsersModule(), ...]
2040
2174
 
2041
2175
  // src/middleware/index.ts
2042
2176
  export const middleware = [helmet(), cors(), requestId(), ...]
@@ -2100,7 +2234,7 @@ ${t===`ddd`?`\`\`\`
2100
2234
  ├── <name>.repository.ts # Data access (@Repository)
2101
2235
  ├── <name>.dto.ts # Request/response schemas (Zod)
2102
2236
  ├── <name>.entity.ts # Domain entity (optional)
2103
- └── <name>.module.ts # Module definition (implements AppModule)
2237
+ └── <name>.module.ts # Module definition (defineModule factory)
2104
2238
  \`\`\`
2105
2239
  `:t===`cqrs`?`\`\`\`
2106
2240
  <name>/
@@ -2114,14 +2248,14 @@ ${t===`ddd`?`\`\`\`
2114
2248
  │ └── <name>-created.event.ts
2115
2249
  ├── <name>.controller.ts # HTTP routes
2116
2250
  ├── <name>.repository.ts # Data access
2117
- └── <name>.module.ts # Module definition (implements AppModule)
2251
+ └── <name>.module.ts # Module definition (defineModule factory)
2118
2252
  \`\`\`
2119
2253
  `:t===`rest`?`\`\`\`
2120
2254
  <name>/
2121
2255
  ├── <name>.controller.ts # HTTP routes (@Controller)
2122
2256
  ├── <name>.service.ts # Business logic (@Service)
2123
2257
  ├── <name>.dto.ts # Request/response schemas (Zod)
2124
- └── <name>.module.ts # Module definition (implements AppModule)
2258
+ └── <name>.module.ts # Module definition (defineModule factory)
2125
2259
  \`\`\`
2126
2260
  `:"```\nsrc/\n├── index.ts # Add routes here\n└── ... # Custom structure\n```\n"}
2127
2261
 
@@ -2152,8 +2286,8 @@ If not using generators:
2152
2286
  - [ ] Create \`src/modules/<name>/<name>.controller.ts\`
2153
2287
  - [ ] Add \`@Controller()\` decorator
2154
2288
  - [ ] Add route handlers with \`@Get()\`, \`@Post()\`, etc.
2155
- - [ ] Create module file implementing \`AppModule\` with \`routes()\` returning \`{ path, router: buildRoutes(Controller), controller }\`
2156
- - [ ] Register module in \`src/modules/index.ts\` (\`AppModuleClass[]\` array)
2289
+ - [ ] Create module file with \`defineModule({ name, build: () => ({ routes() { return { path, controller } } }) })\` (the framework derives the Express router from the controller)
2290
+ - [ ] Register module in \`src/modules/index.ts\` (\`AppModuleEntry[]\` array — call the factory at the registration site: \`[MyModule()]\`)
2157
2291
  - [ ] Test with \`kick dev\`
2158
2292
 
2159
2293
  ### Manual Service
@@ -2434,7 +2568,7 @@ ${t===`cqrs`?`### Background Jobs
2434
2568
  - [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
2435
2569
  - [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
2436
2570
  - [Testing](https://forinda.github.io/kick-js/api/testing.html)
2437
- `}function Y(e,t,n){return`# kickjs-skills.md — Task Skills for AI Agents (${e})
2571
+ `}function X(e,t,n){return`# kickjs-skills.md — Task Skills for AI Agents (${e})
2438
2572
 
2439
2573
  This file is the agent-facing **skills index** for KickJS work in this
2440
2574
  repo. Each block below is a short, rigid workflow keyed to a specific
@@ -2681,7 +2815,7 @@ description: Patterns to refuse outright when the user asks for them — they br
2681
2815
  - [Decorators](https://forinda.github.io/kick-js/guide/decorators.html)
2682
2816
  - [Context Decorators](https://forinda.github.io/kick-js/guide/context-decorators.html)
2683
2817
  - [Testing](https://forinda.github.io/kick-js/api/testing.html)
2684
- `}const ft=t(h(import.meta.url)),X=JSON.parse(o(r(ft,`..`,`package.json`),`utf-8`)),pt=`^${X.version}`;async function mt(e){let{name:t,directory:n,packageManager:i=`pnpm`,template:a=`rest`,defaultRepo:o=`inmemory`,packages:s=[]}=e,c=n,l=e=>console.log(` ${e}`);if(console.log(`\n Creating KickJS project: ${t}\n`),await b(r(c,`package.json`),tt(t,a,pt,s)),await b(r(c,`vite.config.ts`),nt()),await b(r(c,`tsconfig.json`),rt()),await b(r(c,`.prettierrc`),it()),await b(r(c,`.editorconfig`),at()),await b(r(c,`.gitignore`),ot()),await b(r(c,`.gitattributes`),st()),await b(r(c,`.env`),ct()),await b(r(c,`.env.example`),lt()),await b(r(c,`src/config/index.ts`),Ne()),await b(r(c,`src/index.ts`),je(t,a,X.version,s)),await b(r(c,`src/modules/index.ts`),Me()),await b(r(c,`src/modules/hello/hello.service.ts`),Pe()),await b(r(c,`src/modules/hello/hello.controller.ts`),Fe()),await b(r(c,`src/modules/hello/hello.module.ts`),Ie()),await b(r(c,`kick.config.ts`),Le(a,o,i)),await b(r(c,`vitest.config.ts`),ut()),await b(r(c,`README.md`),dt(t,a,i)),await b(r(c,`CLAUDE.md`),q(t,a,i)),await b(r(c,`AGENTS.md`),J(t,a,i)),await b(r(c,`kickjs-skills.md`),Y(t,a,i)),e.installDeps){console.log(`\n Installing dependencies with ${i}...\n`);try{m(`${i} install`,{cwd:c,stdio:`inherit`}),console.log(`
2685
- Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${i} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-CYA1y8NJ.mjs`).then(e=>e.n);await e({cwd:c,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{m(`git init`,{cwd:c,stdio:`pipe`}),m(`git branch -M main`,{cwd:c,stdio:`pipe`}),m(`git add -A`,{cwd:c,stdio:`pipe`}),m(`git commit -m "chore: initial commit from kick new"`,{cwd:c,stdio:`pipe`}),l(`Git repository initialized`)}catch{l(`Warning: git init failed (git may not be installed)`)}console.log(`
2686
- Project scaffolded successfully!`),console.log();let u=c!==process.cwd();l(`Next steps:`),u&&l(` cd ${t}`),e.installDeps||l(` ${i} install`);let d={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};l(` ${d[a]??d.rest}`),l(` kick dev`),l(``),l(`Commands:`),l(` kick dev Start dev server with Vite HMR`),l(` kick build Production build via Vite`),l(` kick start Run production build`),l(``),l(`Generators:`),l(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),l(` kick g scaffold <n> <f..> CRUD module from field definitions`),l(` kick g controller <name> Standalone controller`),l(` kick g service <name> @Service() class`),l(` kick g middleware <name> Express middleware`),l(` kick g guard <name> Route guard (auth, roles, etc.)`),l(` kick g adapter <name> AppAdapter with lifecycle hooks`),l(` kick g dto <name> Zod DTO schema`),a===`cqrs`&&l(` kick g job <name> Queue job processor`),l(` kick g config Generate kick.config.ts`),l(``),l(`Add packages:`),l(` kick add <pkg> Install a KickJS package + peers`),l(` kick add --list Show all available packages`),l(``),l(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),l(``)}function ht(e){return e}function gt(e){return k(e).replace(/-/g,`_`)}function Z(e){let t=e.cwd??process.cwd(),n=e.pluralize??!0,r=D(e.name),i=O(e.name),a=k(e.name),o=gt(e.name),s={name:e.name,pascal:r,camel:i,kebab:a,snake:o,modulesDir:e.modulesDir??`src/modules`,cwd:t,args:e.args??[],flags:e.flags??{}};if(n){let e=A(a);s.pluralKebab=e,s.pluralPascal=D(e),s.pluralCamel=O(e)}return s}function _t(e,t){return i(e.cwd,t)}async function vt(e){return import(g(e).href)}const Q=new Map;async function $(e){let t=Q.get(e);if(t)return t;let n=yt(e);return Q.set(e,n),n}async function yt(n){let r=i(n,`package.json`);if(!a(r))return{generators:[],loaded:[],failed:[]};let o=bt(JSON.parse(await l(r,`utf-8`))),s=e(i(n,`package.json`)),c=[],u=[],d=[];for(let e of o){let n;try{n=s.resolve(`${e}/package.json`)}catch{continue}let r;try{r=JSON.parse(await l(n,`utf-8`))}catch(t){d.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!r.kickjs?.generators)continue;let o=r.kickjs.generators,f=i(t(n),o);if(!a(f)){d.push({source:e,reason:`kickjs.generators points to missing file: ${o}`});continue}let p;try{p=await vt(f)}catch(t){d.push({source:e,reason:`failed to import manifest: ${t}`});continue}let m=p.default;if(!Array.isArray(m)){d.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of m){if(!xt(t)){d.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}c.push({source:e,spec:t})}u.push(e)}return{generators:c,loaded:u,failed:d}}function bt(e){let t=new Set;for(let n of[e.dependencies,e.devDependencies,e.peerDependencies])if(n)for(let e of Object.keys(n))t.add(e);return Array.from(t)}function xt(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function St(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Tt(r.spec,r.source,e,n);let i=wt(await $(n),e.generatorName);return i?Tt(i.spec,i.source,e,n):null}async function Ct(e,t=[]){let n=await $(e),r=new Set(t.map(e=>e.spec.name)),i=n.generators.filter(e=>!r.has(e.spec.name));return{generators:[...t,...i],loaded:n.loaded,failed:n.failed}}function wt(e,t){return e.generators.find(e=>e.spec.name===t)}async function Tt(e,t,n,r){let i=Z({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r}),a=await e.files(i),o=[];for(let e of a){let t=_t(i,e.path);await b(t,e.content),o.push(t)}return{files:o,source:t}}export{ie as A,oe as C,le as D,se as E,b as F,ae as M,C as N,de as O,v as P,T as S,ue as T,A as _,mt as a,k as b,Y as c,Ze as d,Xe as f,He as g,Ue as h,ht as i,f as j,ce as k,$e as l,Ge as m,St as n,J as o,Ye as p,Z as r,q as s,Ct as t,Qe as u,j as v,E as w,D as x,O as y};
2687
- //# sourceMappingURL=generator-extension-BNgcYlom.mjs.map
2818
+ `}const ft=t(h(import.meta.url)),Z=JSON.parse(o(r(ft,`..`,`package.json`),`utf-8`)),pt=`^${Z.version}`;async function mt(e){let{name:t,directory:n,packageManager:i=`pnpm`,template:a=`rest`,defaultRepo:o=`inmemory`,packages:s=[]}=e,c=n,l=e=>console.log(` ${e}`);if(console.log(`\n Creating KickJS project: ${t}\n`),await b(r(c,`package.json`),tt(t,a,pt,s)),await b(r(c,`vite.config.ts`),nt()),await b(r(c,`tsconfig.json`),rt()),await b(r(c,`.prettierrc`),it()),await b(r(c,`.editorconfig`),at()),await b(r(c,`.gitignore`),ot()),await b(r(c,`.gitattributes`),st()),await b(r(c,`.env`),ct()),await b(r(c,`.env.example`),lt()),await b(r(c,`src/config/index.ts`),Ne()),await b(r(c,`src/index.ts`),je(t,a,Z.version,s)),await b(r(c,`src/modules/index.ts`),Me()),await b(r(c,`src/modules/hello/hello.service.ts`),Pe()),await b(r(c,`src/modules/hello/hello.controller.ts`),Fe()),await b(r(c,`src/modules/hello/hello.module.ts`),Ie()),await b(r(c,`kick.config.ts`),Le(a,o,i)),await b(r(c,`vitest.config.ts`),ut()),await b(r(c,`README.md`),dt(t,a,i)),await b(r(c,`CLAUDE.md`),J(t,a,i)),await b(r(c,`AGENTS.md`),Y(t,a,i)),await b(r(c,`kickjs-skills.md`),X(t,a,i)),e.installDeps){console.log(`\n Installing dependencies with ${i}...\n`);try{m(`${i} install`,{cwd:c,stdio:`inherit`}),console.log(`
2819
+ Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${i} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-Bl9kUVNL.mjs`).then(e=>e.n);await e({cwd:c,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{m(`git init`,{cwd:c,stdio:`pipe`}),m(`git branch -M main`,{cwd:c,stdio:`pipe`}),m(`git add -A`,{cwd:c,stdio:`pipe`}),m(`git commit -m "chore: initial commit from kick new"`,{cwd:c,stdio:`pipe`}),l(`Git repository initialized`)}catch{l(`Warning: git init failed (git may not be installed)`)}console.log(`
2820
+ Project scaffolded successfully!`),console.log();let u=c!==process.cwd();l(`Next steps:`),u&&l(` cd ${t}`),e.installDeps||l(` ${i} install`);let d={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};l(` ${d[a]??d.rest}`),l(` kick dev`),l(``),l(`Commands:`),l(` kick dev Start dev server with Vite HMR`),l(` kick build Production build via Vite`),l(` kick start Run production build`),l(``),l(`Generators:`),l(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),l(` kick g scaffold <n> <f..> CRUD module from field definitions`),l(` kick g controller <name> Standalone controller`),l(` kick g service <name> @Service() class`),l(` kick g middleware <name> Express middleware`),l(` kick g guard <name> Route guard (auth, roles, etc.)`),l(` kick g adapter <name> AppAdapter with lifecycle hooks`),l(` kick g dto <name> Zod DTO schema`),a===`cqrs`&&l(` kick g job <name> Queue job processor`),l(` kick g config Generate kick.config.ts`),l(``),l(`Add packages:`),l(` kick add <pkg> Install a KickJS package + peers`),l(` kick add --list Show all available packages`),l(``),l(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),l(``)}function ht(e){return e}function gt(e){return k(e).replace(/-/g,`_`)}function Q(e){let t=e.cwd??process.cwd(),n=e.pluralize??!0,r=D(e.name),i=O(e.name),a=k(e.name),o=gt(e.name),s={name:e.name,pascal:r,camel:i,kebab:a,snake:o,modulesDir:e.modulesDir??`src/modules`,cwd:t,args:e.args??[],flags:e.flags??{}};if(n){let e=A(a);s.pluralKebab=e,s.pluralPascal=D(e),s.pluralCamel=O(e)}return s}function _t(e,t){return i(e.cwd,t)}async function vt(e){return import(g(e).href)}const $=new Map;async function yt(e){let t=$.get(e);if(t)return t;let n=bt(e);return $.set(e,n),n}async function bt(n){let r=i(n,`package.json`);if(!a(r))return{generators:[],loaded:[],failed:[]};let o=xt(JSON.parse(await l(r,`utf-8`))),s=e(i(n,`package.json`)),c=[],u=[],d=[];for(let e of o){let n;try{n=s.resolve(`${e}/package.json`)}catch{continue}let r;try{r=JSON.parse(await l(n,`utf-8`))}catch(t){d.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!r.kickjs?.generators)continue;let o=r.kickjs.generators,f=i(t(n),o);if(!a(f)){d.push({source:e,reason:`kickjs.generators points to missing file: ${o}`});continue}let p;try{p=await vt(f)}catch(t){d.push({source:e,reason:`failed to import manifest: ${t}`});continue}let m=p.default;if(!Array.isArray(m)){d.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of m){if(!St(t)){d.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}c.push({source:e,spec:t})}u.push(e)}return{generators:c,loaded:u,failed:d}}function xt(e){let t=new Set;for(let n of[e.dependencies,e.devDependencies,e.peerDependencies])if(n)for(let e of Object.keys(n))t.add(e);return Array.from(t)}function St(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Ct(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Et(r.spec,r.source,e,n);let i=Tt(await yt(n),e.generatorName);return i?Et(i.spec,i.source,e,n):null}async function wt(e,t=[]){let n=await yt(e),r=new Set(t.map(e=>e.spec.name)),i=n.generators.filter(e=>!r.has(e.spec.name));return{generators:[...t,...i],loaded:n.loaded,failed:n.failed}}function Tt(e,t){return e.generators.find(e=>e.spec.name===t)}async function Et(e,t,n,r){let i=Q({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r}),a=await e.files(i),o=[];for(let e of a){let t=_t(i,e.path);await b(t,e.content),o.push(t)}return{files:o,source:t}}export{ie as A,oe as C,le as D,se as E,b as F,ae as M,C as N,de as O,v as P,T as S,ue as T,A as _,mt as a,k as b,X as c,Ze as d,Xe as f,He as g,Ue as h,ht as i,f as j,ce as k,$e as l,Ge as m,Ct as n,Y as o,Ye as p,Q as r,J as s,wt as t,Qe as u,j as v,E as w,D as x,O as y};
2821
+ //# sourceMappingURL=generator-extension-Bn2aH7kY.mjs.map