@forinda/kickjs-cli 5.3.2 → 5.4.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.
Files changed (28) hide show
  1. package/dist/{builtins-CnQ6lxcV.mjs → builtins-BCRm8cUp.mjs} +163 -100
  2. package/dist/builtins-BCRm8cUp.mjs.map +1 -0
  3. package/dist/{builtins-BxGfcEP6.mjs → builtins-BbJqgLmS.mjs} +432 -220
  4. package/dist/cli.mjs +2 -2
  5. package/dist/config-cyBKEKWL.mjs +12 -0
  6. package/dist/config-cyBKEKWL.mjs.map +1 -0
  7. package/dist/config-q_jBP6Ln.mjs +11 -0
  8. package/dist/{generator-extension-BNgcYlom.mjs → generator-extension-CsT2e6Fj.mjs} +274 -125
  9. package/dist/generator-extension-CsT2e6Fj.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-Ccvf-gn6.mjs → plugin-8R67gfJG.mjs} +3 -3
  14. package/dist/{plugin-Ccvf-gn6.mjs.map → plugin-8R67gfJG.mjs.map} +1 -1
  15. package/dist/{plugin-B56zClEX.mjs → plugin-D6nfJWY0.mjs} +2 -2
  16. package/dist/{rolldown-runtime-CP9PNXAB.mjs → rolldown-runtime-B9Lxtctb.mjs} +1 -1
  17. package/dist/{run-plugins-sjeIm8hS.mjs → run-plugins-CYRt77yP.mjs} +2 -2
  18. package/dist/{typegen-CFW1vIgv.mjs → typegen-CgWQM1FH.mjs} +3 -3
  19. package/dist/{typegen-CYA1y8NJ.mjs → typegen-SyGEEyKv.mjs} +4 -4
  20. package/dist/{typegen-CYA1y8NJ.mjs.map → typegen-SyGEEyKv.mjs.map} +1 -1
  21. package/dist/{types-2ICiQzlQ.mjs → types-dPuCyHXz.mjs} +2 -2
  22. package/dist/{types-2ICiQzlQ.mjs.map → types-dPuCyHXz.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.1
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{execFileSync as m,execSync as h}from"node:child_process";import{fileURLToPath as g,pathToFileURL as _}from"node:url";let v=!1;function y(e){v=e}const ee=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function b(e,r){v||(await c(t(e),{recursive:!0}),await u(e,r,`utf-8`),ee.has(n(e))&&await ne(e,r).catch(()=>{}))}let x;async function te(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 ne(e,t){let n=await te(process.cwd());if(!n)return;let r=await re(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 re(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 ie={GET:f.green,POST:f.cyan,PUT:f.yellow,PATCH:f.magenta,DELETE:f.red};function ae(e){return(ie[e]??f.dim)(e.padEnd(7))}function oe(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 se(e){d.intro(f.bgCyan(f.black(` ${e} `)))}function ce(e){d.outro(e)}function w(e){d.isCancel(e)&&(d.cancel(`Operation cancelled.`),process.exit(0))}async function le(e){let t=await d.text(e);return w(t),t}async function ue(e){let t=await d.select(e);return w(t),t}async function de(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 fe(){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)}function M(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const pe={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function me(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function he(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function N(e){return pe[e]??me(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]??`${me(n)}${e}Repository`,repoFile:i[n]??`${he(n)}-${t}`}}function F(e){return e??`define`}function ge(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. Return value shape:
32
+ *
33
+ * - \`path\` — URL prefix for this route set, mounted under
34
+ * \`/{apiPrefix}/v{version}{path}\`.
35
+ * - \`controller\` — Controller class. Used both for the route
36
+ * handler bindings and OpenAPI spec generation.
37
+ * - \`version\` — Optional. Overrides the app-wide API version
38
+ * for this route set only.
39
+ *
40
+ * Return an **array** to mount multiple route sets under the
41
+ * same module (e.g. side-by-side v1 + v2 controllers):
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 _e(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,47 +105,109 @@ 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. Return value shape:
117
+ *
118
+ * - \`path\` — URL prefix for this route set.
119
+ * - \`controller\` — Controller class (also drives OpenAPI).
120
+ * - \`version\` — Optional. Overrides the app-wide API version.
121
+ *
122
+ * Return an **array** to mount multiple route sets — admin
123
+ * surfaces, side-by-side v1 + v2 controllers, etc:
124
+ *
125
+ * return [
126
+ * { path: '/${r}', version: 1, controller: ${t}V1Controller },
127
+ * { path: '/${r}', version: 2, controller: ${t}V2Controller },
128
+ * ]
129
+ */`;return c===`class`?`${l}
130
+ import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
131
+ ${u}
81
132
 
82
133
  export class ${t}Module implements AppModule {
83
134
  register(container: Container): void {
84
135
  container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
85
- container.resolve(${a}),
136
+ container.resolve(${o}),
86
137
  )
87
138
  }
88
139
 
140
+ ${d.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
89
141
  routes(): ModuleRoutes {
90
142
  return {
91
143
  path: '/${r}',
92
- router: buildRoutes(${t}Controller),
93
144
  controller: ${t}Controller,
94
145
  }
95
146
  }
96
147
  }
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'
148
+ `:`${l}
149
+ import { defineModule } from '@forinda/kickjs'
150
+ ${u}
151
+
152
+ export const ${t}Module = defineModule({
153
+ name: '${t}Module',
154
+ build: () => ({
155
+ register(container) {
156
+ container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
157
+ container.resolve(${o}),
158
+ )
159
+ },
160
+
161
+ ${d}
162
+ routes() {
163
+ return {
164
+ path: '/${r}',
165
+ controller: ${t}Controller,
166
+ }
167
+ },
168
+ }),
169
+ })
170
+ `}function ve(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=F(i),o=` /**
171
+ * Declare HTTP routes. Return value shape:
172
+ *
173
+ * - \`path\` — URL prefix for this route set.
174
+ * - \`controller\` — Controller class (also drives OpenAPI).
175
+ * - \`version\` — Optional. Overrides the app-wide API version.
176
+ *
177
+ * Return an array to mount multiple route sets:
178
+ *
179
+ * return [
180
+ * { path: '/${r}', version: 1, controller: ${t}V1Controller },
181
+ * { path: '/${r}', version: 2, controller: ${t}V2Controller },
182
+ * ]
183
+ */`;return a===`class`?`import { type AppModule, type ModuleRoutes } from '@forinda/kickjs'
99
184
  import { ${t}Controller } from './${n}.controller'
100
185
 
101
186
  export class ${t}Module implements AppModule {
187
+ ${o.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
102
188
  routes(): ModuleRoutes {
103
189
  return {
104
190
  path: '/${r}',
105
- router: buildRoutes(${t}Controller),
106
191
  controller: ${t}Controller,
107
192
  }
108
193
  }
109
194
  }
110
- `}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'
195
+ `:`import { defineModule } from '@forinda/kickjs'
196
+ import { ${t}Controller } from './${n}.controller'
197
+
198
+ export const ${t}Module = defineModule({
199
+ name: '${t}Module',
200
+ build: () => ({
201
+ ${o}
202
+ routes() {
203
+ return {
204
+ path: '/${r}',
205
+ controller: ${t}Controller,
206
+ }
207
+ },
208
+ }),
209
+ })
210
+ `}function ye(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
211
  import { ApiTags } from '@forinda/kickjs-swagger'
112
212
  import { Create${t}UseCase } from '../application/use-cases/create-${n}.use-case'
113
213
  import { Get${t}UseCase } from '../application/use-cases/get-${n}.use-case'
@@ -170,7 +270,7 @@ export class ${t}Controller {
170
270
  ctx.noContent()
171
271
  }
172
272
  }
173
- `}function ve(e){let{pascal:t,kebab:n}=e,r=t.charAt(0).toLowerCase()+t.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
273
+ `}function be(e){let{pascal:t,kebab:n}=e,r=t.charAt(0).toLowerCase()+t.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
174
274
  import { ApiTags } from '@forinda/kickjs-swagger'
175
275
  import { ${t}Service } from './${n}.service'
176
276
  import { create${t}Schema } from './dtos/create-${n}.dto'
@@ -225,14 +325,14 @@ export class ${t}Controller {
225
325
  ctx.noContent()
226
326
  }
227
327
  }
228
- `}function ye(e){let{pascal:t}=e;return`import type { QueryParamsConfig } from '@forinda/kickjs'
328
+ `}function xe(e){let{pascal:t}=e;return`import type { QueryParamsConfig } from '@forinda/kickjs'
229
329
 
230
330
  export const ${t.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
231
331
  filterable: ['name'],
232
332
  sortable: ['name', 'createdAt'],
233
333
  searchable: ['name'],
234
334
  }
235
- `}function F(e){let{pascal:t}=e;return`import { z } from 'zod'
335
+ `}function I(e){let{pascal:t}=e;return`import { z } from 'zod'
236
336
 
237
337
  /**
238
338
  * Create ${t} DTO — Zod schema for validating POST request bodies.
@@ -248,20 +348,20 @@ export const create${t}Schema = z.object({
248
348
  })
249
349
 
250
350
  export type Create${t}DTO = z.infer<typeof create${t}Schema>
251
- `}function I(e){let{pascal:t}=e;return`import { z } from 'zod'
351
+ `}function L(e){let{pascal:t}=e;return`import { z } from 'zod'
252
352
 
253
353
  export const update${t}Schema = z.object({
254
354
  name: z.string().min(1).max(200).optional(),
255
355
  })
256
356
 
257
357
  export type Update${t}DTO = z.infer<typeof update${t}Schema>
258
- `}function L(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
358
+ `}function R(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
259
359
  id: string
260
360
  name: string
261
361
  createdAt: string
262
362
  updatedAt: string
263
363
  }
264
- `}function be(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`create-${n}.use-case.ts`,content:`/**
364
+ `}function Se(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`create-${n}.use-case.ts`,content:`/**
265
365
  * Create ${t} Use Case
266
366
  *
267
367
  * Application layer — orchestrates a single business operation.
@@ -339,7 +439,7 @@ export class Delete${t}UseCase {
339
439
  await this.repo.delete(id)
340
440
  }
341
441
  }
342
- `}]}function R(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
442
+ `}]}function z(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
343
443
  * ${t} Repository Interface
344
444
  *
345
445
  * Defines the contract for data access.
@@ -374,7 +474,7 @@ export interface I${t}Repository {
374
474
  * adopters must NOT use the reserved \`'kick/'\` namespace.
375
475
  */
376
476
  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`/**
477
+ `}function B(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
378
478
  * In-Memory ${t} Repository
379
479
  *
380
480
  * Implements the repository interface using a Map.
@@ -434,7 +534,7 @@ export class InMemory${t}Repository implements I${t}Repository {
434
534
  this.store.delete(id)
435
535
  }
436
536
  }
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`/**
537
+ `}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
538
  * ${o} ${t} Repository
439
539
  *
440
540
  * Stub implementation for a custom '${r}' repository.
@@ -503,7 +603,7 @@ export class ${o}${t}Repository implements I${t}Repository {
503
603
  this.store.delete(id)
504
604
  }
505
605
  }
506
- `}function xe(e){let{pascal:t,kebab:n}=e;return`/**
606
+ `}function Ce(e){let{pascal:t,kebab:n}=e;return`/**
507
607
  * ${t} Domain Service
508
608
  *
509
609
  * Domain layer — contains business rules that don't belong to a single entity.
@@ -526,7 +626,7 @@ export class ${t}DomainService {
526
626
  }
527
627
  }
528
628
  }
529
- `}function Se(e){let{pascal:t,kebab:n}=e;return`/**
629
+ `}function we(e){let{pascal:t,kebab:n}=e;return`/**
530
630
  * ${t} Entity
531
631
  *
532
632
  * Domain layer — the core business object.
@@ -595,7 +695,7 @@ export class ${t} {
595
695
  }
596
696
  }
597
697
  }
598
- `}function Ce(e){let{pascal:t}=e;return`/**
698
+ `}function Te(e){let{pascal:t}=e;return`/**
599
699
  * ${t} ID Value Object
600
700
  *
601
701
  * Domain layer — wraps a primitive ID with type safety and validation.
@@ -629,7 +729,7 @@ export class ${t}Id {
629
729
  return this.value === other.value
630
730
  }
631
731
  }
632
- `}function V(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
732
+ `}function H(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
633
733
  import { Container } from '@forinda/kickjs'
634
734
 
635
735
  describe('${t}Controller', () => {
@@ -681,7 +781,7 @@ describe('${t}Controller', () => {
681
781
  })
682
782
  })
683
783
  })
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'
784
+ `}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
785
  import { InMemory${t}Repository } from '${i}'
686
786
 
687
787
  describe('InMemory${t}Repository', () => {
@@ -743,7 +843,7 @@ describe('InMemory${t}Repository', () => {
743
843
  expect(found).toBeNull()
744
844
  })
745
845
  })
746
- `}function we(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
846
+ `}function Ee(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
747
847
  import type { ParsedQuery } from '@forinda/kickjs'
748
848
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from './${n}.repository'
749
849
  import type { ${t}ResponseDTO } from './dtos/${n}-response.dto'
@@ -780,14 +880,14 @@ export class ${t}Service {
780
880
  await this.repo.delete(id)
781
881
  }
782
882
  }
783
- `}function U(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
883
+ `}function W(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
784
884
 
785
885
  export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
786
886
  filterable: ['name'],
787
887
  sortable: ['name', 'createdAt'],
788
888
  searchable: ['name'],
789
889
  }
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`/**
890
+ `}function De(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
891
  * ${t} Module — CQRS Pattern
792
892
  *
793
893
  * Separates read (queries) and write (commands) operations.
@@ -799,11 +899,8 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
799
899
  * queries/ — Read operations (get, list)
800
900
  * events/ — Domain events + handlers (WS broadcast, queue dispatch)
801
901
  * 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'
902
+ */`,f=`import { ${t.toUpperCase()}_REPOSITORY } from './${n}.repository'
903
+ import { ${c} } from './${l}.repository'
807
904
  import { ${t}Controller } from './${n}.controller'
808
905
 
809
906
  // Eagerly load decorated classes
@@ -815,24 +912,61 @@ import.meta.glob(
815
912
  '!./**/*.test.ts',
816
913
  ],
817
914
  { eager: true },
818
- )
915
+ )`,p=` /**
916
+ * Declare HTTP routes for this CQRS module. Return value shape:
917
+ *
918
+ * - \`path\` — URL prefix for this route set.
919
+ * - \`controller\` — Controller class (also drives OpenAPI).
920
+ * - \`version\` — Optional. Overrides the app-wide API version.
921
+ *
922
+ * Return an array to mount multiple route sets:
923
+ *
924
+ * return [
925
+ * { path: '/${r}', version: 1, controller: ${t}V1Controller },
926
+ * { path: '/${r}', version: 2, controller: ${t}V2Controller },
927
+ * ]
928
+ */`;return u===`class`?`${d}
929
+ import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs'
930
+ ${f}
819
931
 
820
932
  export class ${t}Module implements AppModule {
821
933
  register(container: Container): void {
822
934
  container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
823
- container.resolve(${s}),
935
+ container.resolve(${c}),
824
936
  )
825
937
  }
826
938
 
939
+ ${p.replace(/^ {4}/gm,` `).replace(/^ {6}/gm,` `)}
827
940
  routes(): ModuleRoutes {
828
941
  return {
829
942
  path: '/${r}',
830
- router: buildRoutes(${t}Controller),
831
943
  controller: ${t}Controller,
832
944
  }
833
945
  }
834
946
  }
835
- `}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'
947
+ `:`${d}
948
+ import { defineModule } from '@forinda/kickjs'
949
+ ${f}
950
+
951
+ export const ${t}Module = defineModule({
952
+ name: '${t}Module',
953
+ build: () => ({
954
+ register(container) {
955
+ container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
956
+ container.resolve(${c}),
957
+ )
958
+ },
959
+
960
+ ${p}
961
+ routes() {
962
+ return {
963
+ path: '/${r}',
964
+ controller: ${t}Controller,
965
+ }
966
+ },
967
+ }),
968
+ })
969
+ `}function Oe(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
970
  import { ApiTags } from '@forinda/kickjs-swagger'
837
971
  import { Create${t}Command } from './commands/create-${n}.command'
838
972
  import { Update${t}Command } from './commands/update-${n}.command'
@@ -895,7 +1029,7 @@ export class ${t}Controller {
895
1029
  ctx.noContent()
896
1030
  }
897
1031
  }
898
- `}function De(e){let{pascal:t,kebab:n}=e;return[{file:`create-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
1032
+ `}function ke(e){let{pascal:t,kebab:n}=e;return[{file:`create-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
899
1033
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
900
1034
  import type { Create${t}DTO } from '../dtos/create-${n}.dto'
901
1035
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
@@ -949,7 +1083,7 @@ export class Delete${t}Command {
949
1083
  this.events.emit('${n}.deleted', { id })
950
1084
  }
951
1085
  }
952
- `}]}function Oe(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`get-${n}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
1086
+ `}]}function Ae(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`get-${n}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
953
1087
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
954
1088
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
955
1089
 
@@ -977,7 +1111,7 @@ export class List${i}Query {
977
1111
  return this.repo.findPaginated(parsed)
978
1112
  }
979
1113
  }
980
- `}]}function ke(e){let{pascal:t,kebab:n}=e;return[{file:`${n}.events.ts`,content:`import { Service } from '@forinda/kickjs'
1114
+ `}]}function je(e){let{pascal:t,kebab:n}=e;return[{file:`${n}.events.ts`,content:`import { Service } from '@forinda/kickjs'
981
1115
  import { EventEmitter } from 'node:events'
982
1116
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
983
1117
 
@@ -1063,7 +1197,7 @@ export class On${t}ChangeHandler {
1063
1197
  })
1064
1198
  }
1065
1199
  }
1066
- `}]}function W(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1200
+ `}]}function G(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
1067
1201
  * Drizzle ${t} Repository
1068
1202
  *
1069
1203
  * Implements the repository interface using Drizzle ORM.
@@ -1145,7 +1279,7 @@ export class Drizzle${t}Repository implements I${t}Repository {
1145
1279
  throw new Error('Drizzle ${t} repository not yet implemented')
1146
1280
  }
1147
1281
  }
1148
- `}function Ae(e){let{pascal:t,kebab:n}=e;return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
1282
+ `}function Me(e){let{pascal:t,kebab:n}=e;return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
1149
1283
  // TODO: Import your schema table and reference actual columns for type safety
1150
1284
  // import { ${n}s } from '@/db/schema'
1151
1285
 
@@ -1163,7 +1297,7 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {
1163
1297
  // ${n}s.name,
1164
1298
  ],
1165
1299
  }
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`/**
1300
+ `}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
1301
  * Prisma ${t} Repository
1168
1302
  *
1169
1303
  * Implements the repository interface using Prisma Client.
@@ -1221,7 +1355,7 @@ export class Prisma${t}Repository implements I${t}Repository {
1221
1355
  await this.prisma.${a}.deleteMany({ where: { id } })
1222
1356
  }
1223
1357
  }
1224
- `}function je(e,t,n,r=[]){switch(t){case`cqrs`:{let t=[],i=[];return r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`)),r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({\n info: { title: '${e}', version: '${n}' },\n }),`)),`import 'reflect-metadata'
1358
+ `}function Ne(e,t,n,r=[]){switch(t){case`cqrs`:{let t=[],i=[];return r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`)),r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({\n info: { title: '${e}', version: '${n}' },\n }),`)),`import 'reflect-metadata'
1225
1359
  // Side-effect import — registers the extended env schema with kickjs
1226
1360
  // **before** any controller / service / @Value gets resolved. Without
1227
1361
  // this line ConfigService.get('YOUR_KEY') returns undefined because the
@@ -1291,12 +1425,14 @@ export const app = await bootstrap({
1291
1425
  express.json(),
1292
1426
  ],
1293
1427
  })
1294
- `}}}function Me(){return`import type { AppModuleClass } from '@forinda/kickjs'
1428
+ `}}}function Pe(){return`import { defineModules } from '@forinda/kickjs'
1295
1429
  import { HelloModule } from './hello/hello.module'
1296
1430
 
1297
1431
  // Remove HelloModule and run: kick g module <name>
1298
- export const modules: AppModuleClass[] = [HelloModule]
1299
- `}function Ne(){return`import { defineEnv, loadEnv } from '@forinda/kickjs/config'
1432
+ // \`defineModules()\` returns a chainable list — \`kick g module\` appends
1433
+ // \`.mount(NewModule())\` to the chain on every generation.
1434
+ export const modules = defineModules().mount(HelloModule())
1435
+ `}function Fe(){return`import { defineEnv, loadEnv } from '@forinda/kickjs/config'
1300
1436
  import { z } from 'zod'
1301
1437
 
1302
1438
  /**
@@ -1331,7 +1467,7 @@ const envSchema = defineEnv((base) =>
1331
1467
  export const env = loadEnv(envSchema)
1332
1468
 
1333
1469
  export default envSchema
1334
- `}function Pe(){return`import { Service } from '@forinda/kickjs'
1470
+ `}function Ie(){return`import { Service } from '@forinda/kickjs'
1335
1471
 
1336
1472
  @Service()
1337
1473
  export class HelloService {
@@ -1343,7 +1479,7 @@ export class HelloService {
1343
1479
  return { status: 'ok', uptime: process.uptime() }
1344
1480
  }
1345
1481
  }
1346
- `}function Fe(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
1482
+ `}function Le(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
1347
1483
  import { HelloService } from './hello.service'
1348
1484
 
1349
1485
  // \`Ctx<KickRoutes.HelloController['<method>']>\` is generated by
@@ -1365,26 +1501,28 @@ export class HelloController {
1365
1501
  ctx.json(this.helloService.healthCheck())
1366
1502
  }
1367
1503
  }
1368
- `}function Ie(){return`import { type AppModule, type ModuleRoutes, buildRoutes } from '@forinda/kickjs'
1504
+ `}function Re(){return`import { defineModule } from '@forinda/kickjs'
1369
1505
  import { HelloController } from './hello.controller'
1370
1506
 
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
- }
1387
- `}function Le(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
1507
+ export const HelloModule = defineModule({
1508
+ name: 'HelloModule',
1509
+ build: () => ({
1510
+ // \`register(container)\` is optional — only implement it when you need
1511
+ // to bind a token to a concrete implementation, e.g.
1512
+ // register(container) {
1513
+ // container.registerFactory(USER_REPOSITORY, () => container.resolve(InMemoryUserRepository))
1514
+ // }
1515
+ // The HelloService uses @Service() so the decorator handles registration.
1516
+
1517
+ routes() {
1518
+ return {
1519
+ path: '/hello',
1520
+ controller: HelloController,
1521
+ }
1522
+ },
1523
+ }),
1524
+ })
1525
+ `}function ze(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
1388
1526
 
1389
1527
  export default defineConfig({
1390
1528
  pattern: '${e}',
@@ -1428,7 +1566,7 @@ export default defineConfig({
1428
1566
  },
1429
1567
  ],
1430
1568
  })
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'
1569
+ `}async function Be(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,ve({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
1432
1570
 
1433
1571
  // \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
1434
1572
  // \`kick typegen\` (auto-run on \`kick dev\`).
@@ -1440,14 +1578,19 @@ export class ${t}Controller {
1440
1578
  ctx.json({ message: '${t} list' })
1441
1579
  }
1442
1580
  }
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 {
1581
+ `)}async function Ve(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`,_e({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`,be({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`${n}.service.ts`,Ee({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 He(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`,De({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`,Oe({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=ke({pascal:t,kebab:n});for(let e of d)await u(`commands/${e.file}`,e.content);let f=Ae({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await u(`queries/${e.file}`,e.content);let p=je({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 Ue(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`,ge({pascal:t,kebab:n,plural:r,repo:a,style:u})),await d(`constants.ts`,a===`drizzle`?Me({pascal:t,kebab:n}):xe({pascal:t,kebab:n})),await d(`presentation/${n}.controller.ts`,ye({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=Se({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`,Ce({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`,we({pascal:t,kebab:n})),await d(`domain/value-objects/${n}-id.vo.ts`,Te({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 We(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function Ge(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 Be(y);break;case`rest`:await Ve(y);break;case`cqrs`:await He(y);break;default:await Ue(y);break}return c||await q(n,p,m,d,y.style),_}async function q(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,a===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
1582
+ import { ${t}Module } from '${c}'
1583
+
1584
+ export const modules: AppModuleEntry[] = [${d}]
1585
+ `:`import { defineModules } from '@forinda/kickjs'
1586
+ import { ${t}Module } from '${c}'
1587
+
1588
+ export const modules = defineModules().mount(${d})
1589
+ `);return}let f=await l(o,`utf-8`),p=`import { ${t}Module } from '${c}'`,m=M(c);if(!RegExp(`^import\\s*\\{[^}]*\\b${M(t)}Module\\b[^}]*\\}\\s*from\\s*['"]${m}['"]`,`m`).test(f)){let e=f.lastIndexOf(`import `);if(e!==-1){let t=f.indexOf(`
1590
+ `,e);f=f.slice(0,t+1)+p+`
1591
+ `+f.slice(t+1)}else f=p+`
1592
+ `+f}let h=Y(f);if(h){let e=f.slice(h.rhsStart,h.rhsEnd+1);RegExp(`\\b${M(t)}Module\\b`).test(e)||(f=J(f,d))}else f=J(f,d);await u(o,f,`utf-8`)}function J(e,t){let n=Y(e);if(!n)return e;if(n.shape===`array`){let r=e.slice(n.rhsStart+1,n.rhsEnd),i=r.trim(),a;if(!i)a=`[${t}]`;else{let e=i.endsWith(`,`)?``:`,`;a=`[${r.trimEnd()}${e} ${t}]`}return e.slice(0,n.rhsStart)+a+e.slice(n.rhsEnd+1)}return`${e.slice(0,n.chainEnd)}\n .mount(${t})${e.slice(n.chainEnd)}`}function Y(e){let t=/export\s+const\s+modules\b[^=]*=/.exec(e);if(!t)return null;let n=t.index+t[0].length;for(;n<e.length&&/\s/.test(e[n]??``);)n++;if(e[n]===`[`){let t=qe(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=Ke(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function Ke(e,t=0){let n=/defineModules\s*\(/g;n.lastIndex=t;let r=n.exec(e);if(!r)return-1;let i=r.index+r[0].length-1;if(e[i]!==`(`||(i=Z(e,i),i===-1))return-1;for(i++;;){let t=i;for(;t<e.length&&/\s/.test(e[t]??``);)t++;if(e[t]!==`.`||e.slice(t,t+6)!==`.mount`)break;for(t+=6;t<e.length&&/\s/.test(e[t]??``);)t++;if(e[t]!==`(`)break;let n=Z(e,t);if(n===-1)break;i=n+1}return i}function X(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
1593
+ `;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function qe(e,t){if(e[t]!==`[`)return-1;let n=1,r=t+1;for(;r<e.length;){let t=e.slice(r,r+2);if(t===`//`||t===`/*`){r=X(e,r);continue}let i=e[r]??``;if(i===`'`||i===`"`||i==="`"){let t=i;for(r++;r<e.length&&e[r]!==t;)e[r]===`\\`&&r++,r++;r<e.length&&r++;continue}if(i===`[`)n++;else if(i===`]`&&(n--,n===0))return r;r++}return-1}function Z(e,t){if(e[t]!==`(`)return-1;let n=1,r=t+1;for(;r<e.length;){let t=e.slice(r,r+2);if(t===`//`||t===`/*`){r=X(e,r);continue}let i=e[r]??``;if(i===`'`||i===`"`||i==="`"){let t=i;for(r++;r<e.length&&e[r]!==t;)e[r]===`\\`&&r++,r++;r<e.length&&r++;continue}if(i===`(`)n++;else if(i===`)`&&(n--,n===0))return r;r++}return-1}async function Je(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
1594
  defineAdapter,
1452
1595
  type AdapterContext,
1453
1596
  type AdapterMiddleware,
@@ -1616,7 +1759,7 @@ export const ${a}Adapter = defineAdapter<${a}AdapterConfig>({
1616
1759
  }
1617
1760
  },
1618
1761
  })
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'
1762
+ `),o.push(s),o}const Ye={controller:`presentation`,service:`domain/services`,dto:`application/dtos`,guard:`presentation/guards`,middleware:`middleware`},Xe={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`},Ze={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`?Ye:c===`cqrs`?Ze:Xe,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 Qe(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
1763
 
1621
1764
  export interface ${D(t)}Options {
1622
1765
  // Add configuration options here
@@ -1640,7 +1783,7 @@ export function ${c}(options: ${D(t)}Options = {}) {
1640
1783
  next()
1641
1784
  }
1642
1785
  }
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'
1786
+ `),l.push(u),l}async function $e(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
1787
  import type { RequestContext } from '@forinda/kickjs'
1645
1788
 
1646
1789
  /**
@@ -1676,7 +1819,7 @@ export async function ${c}Guard(ctx: RequestContext, next: () => void): Promise<
1676
1819
  ctx.res.status(401).json({ message: 'Invalid or expired token' })
1677
1820
  }
1678
1821
  }
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'
1822
+ `),u.push(d),u}async function et(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
1823
 
1681
1824
  @Service()
1682
1825
  export class ${c}Service {
@@ -1685,7 +1828,7 @@ export class ${c}Service {
1685
1828
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
1686
1829
  // ) {}
1687
1830
  }
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'
1831
+ `),l.push(u),l}async function tt(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
1832
 
1690
1833
  // \`Ctx<KickRoutes.${c}Controller['<method>']>\` is generated by
1691
1834
  // \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
@@ -1706,7 +1849,7 @@ export class ${c}Controller {
1706
1849
  ctx.created({ message: '${c} created', data: ctx.body })
1707
1850
  }
1708
1851
  }
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'
1852
+ `),l.push(u),l}async function nt(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
1853
 
1711
1854
  export const ${l}Schema = z.object({
1712
1855
  // Define your schema fields here
@@ -1714,7 +1857,7 @@ export const ${l}Schema = z.object({
1714
1857
  })
1715
1858
 
1716
1859
  export type ${c}DTO = z.infer<typeof ${l}Schema>
1717
- `),u.push(d),u}const et={auth:`@forinda/kickjs-auth`,swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`};function tt(e,t,n,r=[]){let i={"@forinda/kickjs":n,dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,zod:`^4.3.6`,pino:`^10.3.1`,"pino-pretty":`^13.1.3`};for(let e of r){let t=et[e];t&&!i[t]&&(i[t]=n)}return JSON.stringify({name:e,version:n.replace(`^`,``),type:`module`,scripts:{dev:`vite`,"dev:debug":`kick dev:debug`,build:`kick build`,start:`kick start`,test:`vitest run`,"test:watch":`vitest`,typecheck:`tsc --noEmit`,typegen:`kick typegen`,lint:`eslint src/`,format:`prettier --write src/`},dependencies:i,devDependencies:{"@forinda/kickjs-cli":n,"@forinda/kickjs-vite":n,"@swc/core":`^1.15.21`,"@types/express":`^5.0.6`,"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^6.0.3`,prettier:`^3.8.1`}},null,2)}function nt(){return`import { defineConfig } from 'vite'
1860
+ `),u.push(d),u}const rt={auth:`@forinda/kickjs-auth`,swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`};function $(e,t){let n=e[t];if(!n)throw Error(`generatePackageJson: missing resolved version for ${t}. Add it to SIBLING_PACKAGES in generators/project.ts.`);return n}function it(e,t,n,r=[]){let i={"@forinda/kickjs":$(n,`@forinda/kickjs`),dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,zod:`^4.3.6`,pino:`^10.3.1`,"pino-pretty":`^13.1.3`};for(let e of r){let t=rt[e];t&&!i[t]&&(i[t]=$(n,t))}return JSON.stringify({name:e,version:`0.0.0`,type:`module`,scripts:{dev:`vite`,"dev:debug":`kick dev:debug`,build:`kick build`,start:`kick start`,test:`vitest run`,"test:watch":`vitest`,typecheck:`tsc --noEmit`,typegen:`kick typegen`,lint:`eslint src/`,format:`prettier --write src/`},dependencies:i,devDependencies:{"@forinda/kickjs-cli":$(n,`@forinda/kickjs-cli`),"@forinda/kickjs-vite":$(n,`@forinda/kickjs-vite`),"@swc/core":`^1.15.21`,"@types/express":`^5.0.6`,"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^6.0.3`,prettier:`^3.8.1`}},null,2)}function at(){return`import { defineConfig } from 'vite'
1718
1861
  import { resolve } from 'node:path'
1719
1862
  import swc from 'unplugin-swc'
1720
1863
  import { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'
@@ -1749,7 +1892,7 @@ export default defineConfig({
1749
1892
  },
1750
1893
  },
1751
1894
  })
1752
- `}function rt(){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`,paths:{"@/*":[`./src/*`]}},include:[`src`,`.kickjs/types/**/*.d.ts`,`.kickjs/types/**/*.ts`]},null,2)}function it(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function at(){return`# https://editorconfig.org
1895
+ `}function ot(){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`,paths:{"@/*":[`./src/*`]}},include:[`src`,`.kickjs/types/**/*.d.ts`,`.kickjs/types/**/*.ts`]},null,2)}function st(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function ct(){return`# https://editorconfig.org
1753
1896
  root = true
1754
1897
 
1755
1898
  [*]
@@ -1762,14 +1905,14 @@ insert_final_newline = true
1762
1905
 
1763
1906
  [*.md]
1764
1907
  trim_trailing_whitespace = false
1765
- `}function ot(){return`node_modules/
1908
+ `}function lt(){return`node_modules/
1766
1909
  dist/
1767
1910
  .env
1768
1911
  coverage/
1769
1912
  .DS_Store
1770
1913
  *.tsbuildinfo
1771
1914
  .kickjs/
1772
- `}function st(){return`# Auto-detect text files and normalise line endings to LF
1915
+ `}function ut(){return`# Auto-detect text files and normalise line endings to LF
1773
1916
  * text=auto eol=lf
1774
1917
 
1775
1918
  # Explicitly mark generated / binary files
@@ -1787,11 +1930,11 @@ coverage/
1787
1930
  pnpm-lock.yaml -diff linguist-generated
1788
1931
  yarn.lock -diff linguist-generated
1789
1932
  package-lock.json -diff linguist-generated
1790
- `}function ct(){return`PORT=3000
1933
+ `}function dt(){return`PORT=3000
1791
1934
  NODE_ENV=development
1792
- `}function lt(){return`PORT=3000
1935
+ `}function ft(){return`PORT=3000
1793
1936
  NODE_ENV=development
1794
- `}function ut(){return`import { defineConfig } from 'vitest/config'
1937
+ `}function pt(){return`import { defineConfig } from 'vitest/config'
1795
1938
  import swc from 'unplugin-swc'
1796
1939
 
1797
1940
  export default defineConfig({
@@ -1802,7 +1945,7 @@ export default defineConfig({
1802
1945
  include: ['src/**/*.test.ts'],
1803
1946
  },
1804
1947
  })
1805
- `}function dt(e,t,n){let r={rest:`REST API`,ddd:`Domain-Driven Design`,cqrs:`CQRS + Event-Driven`,minimal:`Minimal`},i=[`@forinda/kickjs`,`@forinda/kickjs-vite`];return t!==`minimal`&&i.push(`@forinda/kickjs-swagger`,`@forinda/kickjs-devtools`),t===`cqrs`&&i.push(`@forinda/kickjs-queue`,`@forinda/kickjs-ws`),`# ${e}
1948
+ `}function mt(e,t,n){let r={rest:`REST API`,ddd:`Domain-Driven Design`,cqrs:`CQRS + Event-Driven`,minimal:`Minimal`},i=[`@forinda/kickjs`,`@forinda/kickjs-vite`];return t!==`minimal`&&i.push(`@forinda/kickjs-swagger`,`@forinda/kickjs-devtools`),t===`cqrs`&&i.push(`@forinda/kickjs-queue`,`@forinda/kickjs-ws`),`# ${e}
1806
1949
 
1807
1950
  A **${r[t]??`REST API`}** built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.
1808
1951
 
@@ -1865,7 +2008,7 @@ Copy \`.env.example\` to \`.env\` and configure:
1865
2008
 
1866
2009
  - [KickJS Documentation](https://forinda.github.io/kick-js/)
1867
2010
  - [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
1868
- `}function q(e,t,n){return`# CLAUDE.md — ${e}
2011
+ `}function ht(e,t,n){return`# CLAUDE.md — ${e}
1869
2012
 
1870
2013
  **Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
1871
2014
  reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
@@ -1931,7 +2074,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
1931
2074
  - **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
2075
 
1933
2076
  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}
2077
+ `}function gt(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
1935
2078
 
1936
2079
  This guide is the **canonical, multi-agent reference** for this KickJS
1937
2080
  application — Claude, Copilot, Codex, Gemini, etc. all read it first.
@@ -2035,8 +2178,10 @@ mistakes:
2035
2178
  inline registration in the entry file:
2036
2179
 
2037
2180
  \`\`\`ts
2038
- // src/modules/index.ts
2039
- export const modules: AppModuleClass[] = [HelloModule, UsersModule, ...]
2181
+ // src/modules/index.ts — fluent chain (default for \`modules.style: 'define'\`)
2182
+ export const modules = defineModules().mount(HelloModule()).mount(UsersModule())
2183
+ // OR with \`modules.style: 'class'\`:
2184
+ // export const modules: AppModuleEntry[] = [HelloModule, UsersModule]
2040
2185
 
2041
2186
  // src/middleware/index.ts
2042
2187
  export const middleware = [helmet(), cors(), requestId(), ...]
@@ -2100,7 +2245,7 @@ ${t===`ddd`?`\`\`\`
2100
2245
  ├── <name>.repository.ts # Data access (@Repository)
2101
2246
  ├── <name>.dto.ts # Request/response schemas (Zod)
2102
2247
  ├── <name>.entity.ts # Domain entity (optional)
2103
- └── <name>.module.ts # Module definition (implements AppModule)
2248
+ └── <name>.module.ts # Module definition (defineModule factory)
2104
2249
  \`\`\`
2105
2250
  `:t===`cqrs`?`\`\`\`
2106
2251
  <name>/
@@ -2114,14 +2259,14 @@ ${t===`ddd`?`\`\`\`
2114
2259
  │ └── <name>-created.event.ts
2115
2260
  ├── <name>.controller.ts # HTTP routes
2116
2261
  ├── <name>.repository.ts # Data access
2117
- └── <name>.module.ts # Module definition (implements AppModule)
2262
+ └── <name>.module.ts # Module definition (defineModule factory)
2118
2263
  \`\`\`
2119
2264
  `:t===`rest`?`\`\`\`
2120
2265
  <name>/
2121
2266
  ├── <name>.controller.ts # HTTP routes (@Controller)
2122
2267
  ├── <name>.service.ts # Business logic (@Service)
2123
2268
  ├── <name>.dto.ts # Request/response schemas (Zod)
2124
- └── <name>.module.ts # Module definition (implements AppModule)
2269
+ └── <name>.module.ts # Module definition (defineModule factory)
2125
2270
  \`\`\`
2126
2271
  `:"```\nsrc/\n├── index.ts # Add routes here\n└── ... # Custom structure\n```\n"}
2127
2272
 
@@ -2152,8 +2297,8 @@ If not using generators:
2152
2297
  - [ ] Create \`src/modules/<name>/<name>.controller.ts\`
2153
2298
  - [ ] Add \`@Controller()\` decorator
2154
2299
  - [ ] 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)
2300
+ - [ ] Create module file with \`defineModule({ name, build: () => ({ routes() { return { path, controller } } }) })\` — the framework derives the Express router from the controller. Class-form (\`class XModule implements AppModule\`) is the legacy alternative; toggle via \`kick.config.ts > modules.style\`.
2301
+ - [ ] Register module in \`src/modules/index.ts\`. Default form is the fluent chain: \`defineModules().mount(MyModule()).mount(...)\`. \`kick g module <name>\` appends \`.mount(NewModule())\` automatically.
2157
2302
  - [ ] Test with \`kick dev\`
2158
2303
 
2159
2304
  ### Manual Service
@@ -2355,7 +2500,9 @@ These work anywhere — scripts, plain files, outside \`@Service\`/\`@Controller
2355
2500
  ### Dependency Injection
2356
2501
  | Decorator | Purpose |
2357
2502
  |-----------|---------|
2358
- | \`AppModule\` interface | Define feature module (implements \`routes()\`) |
2503
+ | \`defineModule({...})\` | Define feature module (factory; preferred — paired with \`defineModules()\` registry) |
2504
+ | \`defineModules()\` | Build the modules registry as a chainable list (\`.mount(X())\`) |
2505
+ | \`AppModule\` interface | Legacy module shape — \`class X implements AppModule\` (toggle via \`modules.style: 'class'\`) |
2359
2506
  | \`@Service()\` | Register singleton service |
2360
2507
  | \`@Repository()\` | Register repository |
2361
2508
  | \`@Autowired()\` | Property injection |
@@ -2372,7 +2519,7 @@ is a value other code reads off \`ctx\`.
2372
2519
  |---------|----------------|
2373
2520
  | \`defineContextDecorator({ key, deps, dependsOn, optional, onError, resolve })\` | \`@forinda/kickjs\` |
2374
2521
  | Method/class decorator | \`@LoadX\` on a controller method/class |
2375
- | Module hook | \`AppModule.contributors?(): ContributorRegistration[]\` |
2522
+ | Module hook | \`build: () => ({ contributors() { return [...] } })\` (\`defineModule\`) — or \`AppModule.contributors?()\` for class form |
2376
2523
  | Adapter hook | \`AppAdapter.contributors?(): ContributorRegistration[]\` |
2377
2524
  | Global registration | \`bootstrap({ contributors: [LoadX.registration] })\` |
2378
2525
  | Type augmentation | \`declare module '@forinda/kickjs' { interface ContextMeta { ... } }\` |
@@ -2434,7 +2581,7 @@ ${t===`cqrs`?`### Background Jobs
2434
2581
  - [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
2435
2582
  - [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
2436
2583
  - [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})
2584
+ `}function _t(e,t,n){return`# kickjs-skills.md — Task Skills for AI Agents (${e})
2438
2585
 
2439
2586
  This file is the agent-facing **skills index** for KickJS work in this
2440
2587
  repo. Each block below is a short, rigid workflow keyed to a specific
@@ -2569,8 +2716,10 @@ description: Use when src/index.ts is accumulating module/middleware/plugin/adap
2569
2716
  **Refactor target**:
2570
2717
 
2571
2718
  \`\`\`ts
2572
- // src/modules/index.ts
2573
- export const modules: AppModuleClass[] = [HelloModule, UsersModule, ...]
2719
+ // src/modules/index.ts — fluent chain (default for \`modules.style: 'define'\`)
2720
+ export const modules = defineModules().mount(HelloModule()).mount(UsersModule())
2721
+ // OR for class-form projects (\`modules.style: 'class'\`):
2722
+ // export const modules: AppModuleEntry[] = [HelloModule, UsersModule]
2574
2723
 
2575
2724
  // src/middleware/index.ts
2576
2725
  export const middleware = [helmet(), cors(), requestId(), ...]
@@ -2681,7 +2830,7 @@ description: Patterns to refuse outright when the user asks for them — they br
2681
2830
  - [Decorators](https://forinda.github.io/kick-js/guide/decorators.html)
2682
2831
  - [Context Decorators](https://forinda.github.io/kick-js/guide/context-decorators.html)
2683
2832
  - [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
2833
+ `}const vt=t(g(import.meta.url)),yt=JSON.parse(o(r(vt,`..`,`package.json`),`utf-8`)),bt=`^${yt.version}`,xt=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-vite`,`@forinda/kickjs-auth`,`@forinda/kickjs-swagger`,`@forinda/kickjs-ws`,`@forinda/kickjs-queue`,`@forinda/kickjs-devtools`,`@forinda/kickjs-testing`];async function St(){let e=await Promise.all(xt.map(async e=>{try{let t=m(`npm`,[`view`,e,`version`],{encoding:`utf-8`,timeout:5e3,stdio:[`ignore`,`pipe`,`ignore`]}).toString().trim();if(t&&/^\d+\.\d+\.\d+/.test(t))return[e,`^${t}`]}catch{}return[e,bt]}));return Object.fromEntries(e)}async function Ct(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}`);console.log(`\n Creating KickJS project: ${t}\n`),l(`Resolving package versions...`);let u=await St();if(await b(r(c,`package.json`),it(t,a,u,s)),await b(r(c,`vite.config.ts`),at()),await b(r(c,`tsconfig.json`),ot()),await b(r(c,`.prettierrc`),st()),await b(r(c,`.editorconfig`),ct()),await b(r(c,`.gitignore`),lt()),await b(r(c,`.gitattributes`),ut()),await b(r(c,`.env`),dt()),await b(r(c,`.env.example`),ft()),await b(r(c,`src/config/index.ts`),Fe()),await b(r(c,`src/index.ts`),Ne(t,a,yt.version,s)),await b(r(c,`src/modules/index.ts`),Pe()),await b(r(c,`src/modules/hello/hello.service.ts`),Ie()),await b(r(c,`src/modules/hello/hello.controller.ts`),Le()),await b(r(c,`src/modules/hello/hello.module.ts`),Re()),await b(r(c,`kick.config.ts`),ze(a,o,i)),await b(r(c,`vitest.config.ts`),pt()),await b(r(c,`README.md`),mt(t,a,i)),await b(r(c,`CLAUDE.md`),ht(t,a,i)),await b(r(c,`AGENTS.md`),gt(t,a,i)),await b(r(c,`kickjs-skills.md`),_t(t,a,i)),e.installDeps){console.log(`\n Installing dependencies with ${i}...\n`);try{h(`${i} install`,{cwd:c,stdio:`inherit`}),console.log(`
2834
+ Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${i} install failed. Run it manually.`)}}try{let{runTypegen:e}=await import(`./typegen-SyGEEyKv.mjs`).then(e=>e.n);await e({cwd:c,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{h(`git init`,{cwd:c,stdio:`pipe`}),h(`git branch -M main`,{cwd:c,stdio:`pipe`}),h(`git add -A`,{cwd:c,stdio:`pipe`}),h(`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(`
2835
+ Project scaffolded successfully!`),console.log();let d=c!==process.cwd();l(`Next steps:`),d&&l(` cd ${t}`),e.installDeps||l(` ${i} install`);let f={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(` ${f[a]??f.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 wt(e){return e}function Tt(e){return k(e).replace(/-/g,`_`)}function Et(e){let t=e.cwd??process.cwd(),n=e.pluralize??!0,r=D(e.name),i=O(e.name),a=k(e.name),o=Tt(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 Dt(e,t){return i(e.cwd,t)}async function Ot(e){return import(_(e).href)}const kt=new Map;async function At(e){let t=kt.get(e);if(t)return t;let n=jt(e);return kt.set(e,n),n}async function jt(n){let r=i(n,`package.json`);if(!a(r))return{generators:[],loaded:[],failed:[]};let o=Mt(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 Ot(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(!Nt(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 Mt(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 Nt(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Pt(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Lt(r.spec,r.source,e,n);let i=It(await At(n),e.generatorName);return i?Lt(i.spec,i.source,e,n):null}async function Ft(e,t=[]){let n=await At(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 It(e,t){return e.generators.find(e=>e.spec.name===t)}async function Lt(e,t,n,r){let i=Et({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=Dt(i,e.path);await b(t,e.content),o.push(t)}return{files:o,source:t}}export{ue as A,k as C,E as D,se as E,oe as F,C as I,y as L,le as M,ae as N,de as O,f as P,b as R,O as S,T,Ge as _,Ct as a,A as b,_t as c,et as d,$e as f,Y as g,q as h,wt as i,fe as j,ce as k,nt as l,Je as m,Pt as n,gt as o,Qe as p,Et as r,ht as s,Ft as t,tt as u,We as v,D as w,j as x,M as y};
2836
+ //# sourceMappingURL=generator-extension-CsT2e6Fj.mjs.map