@forinda/kickjs-cli 5.4.0 → 5.4.2

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 (27) hide show
  1. package/dist/{builtins-K-nRJcJG.mjs → builtins-CB0cpCRy.mjs} +207 -190
  2. package/dist/{builtins-DBzZkJey.mjs → builtins-DNnIUbGs.mjs} +101 -99
  3. package/dist/builtins-DNnIUbGs.mjs.map +1 -0
  4. package/dist/cli.mjs +2 -2
  5. package/dist/{config-CCNnXhar.mjs → config-CAjDTnMg.mjs} +2 -2
  6. package/dist/{config-CQZ6Hppr.mjs → config-f_GHcOYT.mjs} +3 -3
  7. package/dist/{config-CQZ6Hppr.mjs.map → config-f_GHcOYT.mjs.map} +1 -1
  8. package/dist/{generator-extension-Bn2aH7kY.mjs → generator-extension-Ds2fzYZS.mjs} +99 -84
  9. package/dist/generator-extension-Ds2fzYZS.mjs.map +1 -0
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +2 -2
  12. package/dist/{plugin-DasN_2Zr.mjs → plugin-CiWyeMpX.mjs} +3 -3
  13. package/dist/{plugin-DasN_2Zr.mjs.map → plugin-CiWyeMpX.mjs.map} +1 -1
  14. package/dist/{plugin-D0C4ISZA.mjs → plugin-Dz0Yu4Ow.mjs} +2 -2
  15. package/dist/{rolldown-runtime-BTpMa50s.mjs → rolldown-runtime-iJll81ez.mjs} +1 -1
  16. package/dist/{run-plugins-Dk7KBKON.mjs → run-plugins-DBOc1G96.mjs} +2 -2
  17. package/dist/typegen-COBqEd4w.mjs +116 -0
  18. package/dist/typegen-DzmDwZvN.mjs +117 -0
  19. package/dist/typegen-DzmDwZvN.mjs.map +1 -0
  20. package/dist/{types-kAfWJgh0.mjs → types-DucsCMzP.mjs} +2 -2
  21. package/dist/{types-kAfWJgh0.mjs.map → types-DucsCMzP.mjs.map} +1 -1
  22. package/package.json +1 -1
  23. package/dist/builtins-DBzZkJey.mjs.map +0 -1
  24. package/dist/generator-extension-Bn2aH7kY.mjs.map +0 -1
  25. package/dist/typegen-Bl9kUVNL.mjs +0 -115
  26. package/dist/typegen-Bl9kUVNL.mjs.map +0 -1
  27. package/dist/typegen-DDQJNnUl.mjs +0 -114
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v5.4.0
2
+ * @forinda/kickjs-cli v5.4.2
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 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=`/**
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).
@@ -28,17 +28,17 @@ import.meta.glob(
28
28
  ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],
29
29
  { eager: true },
30
30
  )`,d=` /**
31
- * Declare HTTP routes for this module.
31
+ * Declare HTTP routes for this module. Return value shape:
32
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.
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.
37
39
  *
38
40
  * 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}\`:
41
+ * same module (e.g. side-by-side v1 + v2 controllers):
42
42
  *
43
43
  * return [
44
44
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -95,7 +95,7 @@ ${d}
95
95
  },
96
96
  }),
97
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=`/**
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=`/**
99
99
  * ${t} Module
100
100
  *
101
101
  * REST module with a flat folder structure.
@@ -113,15 +113,14 @@ import { ${t}Controller } from './${n}.controller'
113
113
 
114
114
  // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
115
115
  import.meta.glob(['./**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'], { eager: true })`,d=` /**
116
- * Declare HTTP routes for this module.
116
+ * Declare HTTP routes for this module. Return value shape:
117
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.
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
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:
122
+ * Return an **array** to mount multiple route sets admin
123
+ * surfaces, side-by-side v1 + v2 controllers, etc:
125
124
  *
126
125
  * return [
127
126
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -168,11 +167,14 @@ ${d}
168
167
  },
169
168
  }),
170
169
  })
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:
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:
176
178
  *
177
179
  * return [
178
180
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -205,7 +207,7 @@ ${o}
205
207
  },
206
208
  }),
207
209
  })
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'
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'
209
211
  import { ApiTags } from '@forinda/kickjs-swagger'
210
212
  import { Create${t}UseCase } from '../application/use-cases/create-${n}.use-case'
211
213
  import { Get${t}UseCase } from '../application/use-cases/get-${n}.use-case'
@@ -268,7 +270,7 @@ export class ${t}Controller {
268
270
  ctx.noContent()
269
271
  }
270
272
  }
271
- `}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'
272
274
  import { ApiTags } from '@forinda/kickjs-swagger'
273
275
  import { ${t}Service } from './${n}.service'
274
276
  import { create${t}Schema } from './dtos/create-${n}.dto'
@@ -323,7 +325,7 @@ export class ${t}Controller {
323
325
  ctx.noContent()
324
326
  }
325
327
  }
326
- `}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'
327
329
 
328
330
  export const ${t.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
329
331
  filterable: ['name'],
@@ -359,7 +361,7 @@ export type Update${t}DTO = z.infer<typeof update${t}Schema>
359
361
  createdAt: string
360
362
  updatedAt: string
361
363
  }
362
- `}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:`/**
363
365
  * Create ${t} Use Case
364
366
  *
365
367
  * Application layer — orchestrates a single business operation.
@@ -601,7 +603,7 @@ export class ${o}${t}Repository implements I${t}Repository {
601
603
  this.store.delete(id)
602
604
  }
603
605
  }
604
- `}function xe(e){let{pascal:t,kebab:n}=e;return`/**
606
+ `}function Ce(e){let{pascal:t,kebab:n}=e;return`/**
605
607
  * ${t} Domain Service
606
608
  *
607
609
  * Domain layer — contains business rules that don't belong to a single entity.
@@ -624,7 +626,7 @@ export class ${t}DomainService {
624
626
  }
625
627
  }
626
628
  }
627
- `}function Se(e){let{pascal:t,kebab:n}=e;return`/**
629
+ `}function we(e){let{pascal:t,kebab:n}=e;return`/**
628
630
  * ${t} Entity
629
631
  *
630
632
  * Domain layer — the core business object.
@@ -693,7 +695,7 @@ export class ${t} {
693
695
  }
694
696
  }
695
697
  }
696
- `}function Ce(e){let{pascal:t}=e;return`/**
698
+ `}function Te(e){let{pascal:t}=e;return`/**
697
699
  * ${t} ID Value Object
698
700
  *
699
701
  * Domain layer — wraps a primitive ID with type safety and validation.
@@ -841,7 +843,7 @@ describe('InMemory${t}Repository', () => {
841
843
  expect(found).toBeNull()
842
844
  })
843
845
  })
844
- `}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'
845
847
  import type { ParsedQuery } from '@forinda/kickjs'
846
848
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from './${n}.repository'
847
849
  import type { ${t}ResponseDTO } from './dtos/${n}-response.dto'
@@ -885,7 +887,7 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
885
887
  sortable: ['name', 'createdAt'],
886
888
  searchable: ['name'],
887
889
  }
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=`/**
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=`/**
889
891
  * ${t} Module — CQRS Pattern
890
892
  *
891
893
  * Separates read (queries) and write (commands) operations.
@@ -911,11 +913,13 @@ import.meta.glob(
911
913
  ],
912
914
  { eager: true },
913
915
  )`,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:
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:
919
923
  *
920
924
  * return [
921
925
  * { path: '/${r}', version: 1, controller: ${t}V1Controller },
@@ -962,7 +966,7 @@ ${p}
962
966
  },
963
967
  }),
964
968
  })
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'
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'
966
970
  import { ApiTags } from '@forinda/kickjs-swagger'
967
971
  import { Create${t}Command } from './commands/create-${n}.command'
968
972
  import { Update${t}Command } from './commands/update-${n}.command'
@@ -1025,7 +1029,7 @@ export class ${t}Controller {
1025
1029
  ctx.noContent()
1026
1030
  }
1027
1031
  }
1028
- `}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'
1029
1033
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
1030
1034
  import type { Create${t}DTO } from '../dtos/create-${n}.dto'
1031
1035
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
@@ -1079,7 +1083,7 @@ export class Delete${t}Command {
1079
1083
  this.events.emit('${n}.deleted', { id })
1080
1084
  }
1081
1085
  }
1082
- `}]}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'
1083
1087
  import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
1084
1088
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
1085
1089
 
@@ -1107,7 +1111,7 @@ export class List${i}Query {
1107
1111
  return this.repo.findPaginated(parsed)
1108
1112
  }
1109
1113
  }
1110
- `}]}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'
1111
1115
  import { EventEmitter } from 'node:events'
1112
1116
  import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
1113
1117
 
@@ -1275,7 +1279,7 @@ export class Drizzle${t}Repository implements I${t}Repository {
1275
1279
  throw new Error('Drizzle ${t} repository not yet implemented')
1276
1280
  }
1277
1281
  }
1278
- `}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'
1279
1283
  // TODO: Import your schema table and reference actual columns for type safety
1280
1284
  // import { ${n}s } from '@/db/schema'
1281
1285
 
@@ -1351,7 +1355,7 @@ export class Prisma${t}Repository implements I${t}Repository {
1351
1355
  await this.prisma.${a}.deleteMany({ where: { id } })
1352
1356
  }
1353
1357
  }
1354
- `}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'
1355
1359
  // Side-effect import — registers the extended env schema with kickjs
1356
1360
  // **before** any controller / service / @Value gets resolved. Without
1357
1361
  // this line ConfigService.get('YOUR_KEY') returns undefined because the
@@ -1421,14 +1425,14 @@ export const app = await bootstrap({
1421
1425
  express.json(),
1422
1426
  ],
1423
1427
  })
1424
- `}}}function Me(){return`import type { AppModuleEntry } from '@forinda/kickjs'
1428
+ `}}}function Pe(){return`import { defineModules } from '@forinda/kickjs'
1425
1429
  import { HelloModule } from './hello/hello.module'
1426
1430
 
1427
1431
  // Remove HelloModule and run: kick g module <name>
1428
- // Modules built with \`defineModule\` are called as factoriesthe
1429
- // invocation produces the AppModule instance bootstrap registers.
1430
- export const modules: AppModuleEntry[] = [HelloModule()]
1431
- `}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'
1432
1436
  import { z } from 'zod'
1433
1437
 
1434
1438
  /**
@@ -1463,7 +1467,7 @@ const envSchema = defineEnv((base) =>
1463
1467
  export const env = loadEnv(envSchema)
1464
1468
 
1465
1469
  export default envSchema
1466
- `}function Pe(){return`import { Service } from '@forinda/kickjs'
1470
+ `}function Ie(){return`import { Service } from '@forinda/kickjs'
1467
1471
 
1468
1472
  @Service()
1469
1473
  export class HelloService {
@@ -1475,7 +1479,7 @@ export class HelloService {
1475
1479
  return { status: 'ok', uptime: process.uptime() }
1476
1480
  }
1477
1481
  }
1478
- `}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'
1479
1483
  import { HelloService } from './hello.service'
1480
1484
 
1481
1485
  // \`Ctx<KickRoutes.HelloController['<method>']>\` is generated by
@@ -1497,7 +1501,7 @@ export class HelloController {
1497
1501
  ctx.json(this.helloService.healthCheck())
1498
1502
  }
1499
1503
  }
1500
- `}function Ie(){return`import { defineModule } from '@forinda/kickjs'
1504
+ `}function Re(){return`import { defineModule } from '@forinda/kickjs'
1501
1505
  import { HelloController } from './hello.controller'
1502
1506
 
1503
1507
  export const HelloModule = defineModule({
@@ -1518,7 +1522,7 @@ export const HelloModule = defineModule({
1518
1522
  },
1519
1523
  }),
1520
1524
  })
1521
- `}function Le(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
1525
+ `}function ze(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
1522
1526
 
1523
1527
  export default defineConfig({
1524
1528
  pattern: '${e}',
@@ -1562,7 +1566,7 @@ export default defineConfig({
1562
1566
  },
1563
1567
  ],
1564
1568
  })
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'
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'
1566
1570
 
1567
1571
  // \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
1568
1572
  // \`kick typegen\` (auto-run on \`kick dev\`).
@@ -1574,14 +1578,19 @@ export class ${t}Controller {
1574
1578
  ctx.json({ message: '${t} list' })
1575
1579
  }
1576
1580
  }
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'
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'
1578
1582
  import { ${t}Module } from '${c}'
1579
1583
 
1580
1584
  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(`
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(`
1582
1590
  `,e);f=f.slice(0,t+1)+p+`
1583
1591
  `+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 {
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 {
1585
1594
  defineAdapter,
1586
1595
  type AdapterContext,
1587
1596
  type AdapterMiddleware,
@@ -1750,7 +1759,7 @@ export const ${a}Adapter = defineAdapter<${a}AdapterConfig>({
1750
1759
  }
1751
1760
  },
1752
1761
  })
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'
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'
1754
1763
 
1755
1764
  export interface ${D(t)}Options {
1756
1765
  // Add configuration options here
@@ -1774,7 +1783,7 @@ export function ${c}(options: ${D(t)}Options = {}) {
1774
1783
  next()
1775
1784
  }
1776
1785
  }
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'
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'
1778
1787
  import type { RequestContext } from '@forinda/kickjs'
1779
1788
 
1780
1789
  /**
@@ -1810,7 +1819,7 @@ export async function ${c}Guard(ctx: RequestContext, next: () => void): Promise<
1810
1819
  ctx.res.status(401).json({ message: 'Invalid or expired token' })
1811
1820
  }
1812
1821
  }
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'
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'
1814
1823
 
1815
1824
  @Service()
1816
1825
  export class ${c}Service {
@@ -1819,7 +1828,7 @@ export class ${c}Service {
1819
1828
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
1820
1829
  // ) {}
1821
1830
  }
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'
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'
1823
1832
 
1824
1833
  // \`Ctx<KickRoutes.${c}Controller['<method>']>\` is generated by
1825
1834
  // \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
@@ -1840,7 +1849,7 @@ export class ${c}Controller {
1840
1849
  ctx.created({ message: '${c} created', data: ctx.body })
1841
1850
  }
1842
1851
  }
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'
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'
1844
1853
 
1845
1854
  export const ${l}Schema = z.object({
1846
1855
  // Define your schema fields here
@@ -1848,7 +1857,7 @@ export const ${l}Schema = z.object({
1848
1857
  })
1849
1858
 
1850
1859
  export type ${c}DTO = z.infer<typeof ${l}Schema>
1851
- `),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'
1852
1861
  import { resolve } from 'node:path'
1853
1862
  import swc from 'unplugin-swc'
1854
1863
  import { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'
@@ -1883,7 +1892,7 @@ export default defineConfig({
1883
1892
  },
1884
1893
  },
1885
1894
  })
1886
- `}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
1887
1896
  root = true
1888
1897
 
1889
1898
  [*]
@@ -1896,14 +1905,14 @@ insert_final_newline = true
1896
1905
 
1897
1906
  [*.md]
1898
1907
  trim_trailing_whitespace = false
1899
- `}function ot(){return`node_modules/
1908
+ `}function lt(){return`node_modules/
1900
1909
  dist/
1901
1910
  .env
1902
1911
  coverage/
1903
1912
  .DS_Store
1904
1913
  *.tsbuildinfo
1905
1914
  .kickjs/
1906
- `}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
1907
1916
  * text=auto eol=lf
1908
1917
 
1909
1918
  # Explicitly mark generated / binary files
@@ -1921,11 +1930,11 @@ coverage/
1921
1930
  pnpm-lock.yaml -diff linguist-generated
1922
1931
  yarn.lock -diff linguist-generated
1923
1932
  package-lock.json -diff linguist-generated
1924
- `}function ct(){return`PORT=3000
1933
+ `}function dt(){return`PORT=3000
1925
1934
  NODE_ENV=development
1926
- `}function lt(){return`PORT=3000
1935
+ `}function ft(){return`PORT=3000
1927
1936
  NODE_ENV=development
1928
- `}function ut(){return`import { defineConfig } from 'vitest/config'
1937
+ `}function pt(){return`import { defineConfig } from 'vitest/config'
1929
1938
  import swc from 'unplugin-swc'
1930
1939
 
1931
1940
  export default defineConfig({
@@ -1936,7 +1945,7 @@ export default defineConfig({
1936
1945
  include: ['src/**/*.test.ts'],
1937
1946
  },
1938
1947
  })
1939
- `}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}
1940
1949
 
1941
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.
1942
1951
 
@@ -1999,7 +2008,7 @@ Copy \`.env.example\` to \`.env\` and configure:
1999
2008
 
2000
2009
  - [KickJS Documentation](https://forinda.github.io/kick-js/)
2001
2010
  - [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
2002
- `}function J(e,t,n){return`# CLAUDE.md — ${e}
2011
+ `}function ht(e,t,n){return`# CLAUDE.md — ${e}
2003
2012
 
2004
2013
  **Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
2005
2014
  reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
@@ -2065,7 +2074,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
2065
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\`.
2066
2075
 
2067
2076
  For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`AGENTS.md\`.
2068
- `}function Y(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}
2069
2078
 
2070
2079
  This guide is the **canonical, multi-agent reference** for this KickJS
2071
2080
  application — Claude, Copilot, Codex, Gemini, etc. all read it first.
@@ -2169,8 +2178,10 @@ mistakes:
2169
2178
  inline registration in the entry file:
2170
2179
 
2171
2180
  \`\`\`ts
2172
- // src/modules/index.ts
2173
- export const modules: AppModuleEntry[] = [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]
2174
2185
 
2175
2186
  // src/middleware/index.ts
2176
2187
  export const middleware = [helmet(), cors(), requestId(), ...]
@@ -2286,8 +2297,8 @@ If not using generators:
2286
2297
  - [ ] Create \`src/modules/<name>/<name>.controller.ts\`
2287
2298
  - [ ] Add \`@Controller()\` decorator
2288
2299
  - [ ] Add route handlers with \`@Get()\`, \`@Post()\`, etc.
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()]\`)
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.
2291
2302
  - [ ] Test with \`kick dev\`
2292
2303
 
2293
2304
  ### Manual Service
@@ -2489,7 +2500,9 @@ These work anywhere — scripts, plain files, outside \`@Service\`/\`@Controller
2489
2500
  ### Dependency Injection
2490
2501
  | Decorator | Purpose |
2491
2502
  |-----------|---------|
2492
- | \`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'\`) |
2493
2506
  | \`@Service()\` | Register singleton service |
2494
2507
  | \`@Repository()\` | Register repository |
2495
2508
  | \`@Autowired()\` | Property injection |
@@ -2506,7 +2519,7 @@ is a value other code reads off \`ctx\`.
2506
2519
  |---------|----------------|
2507
2520
  | \`defineContextDecorator({ key, deps, dependsOn, optional, onError, resolve })\` | \`@forinda/kickjs\` |
2508
2521
  | Method/class decorator | \`@LoadX\` on a controller method/class |
2509
- | Module hook | \`AppModule.contributors?(): ContributorRegistration[]\` |
2522
+ | Module hook | \`build: () => ({ contributors() { return [...] } })\` (\`defineModule\`) — or \`AppModule.contributors?()\` for class form |
2510
2523
  | Adapter hook | \`AppAdapter.contributors?(): ContributorRegistration[]\` |
2511
2524
  | Global registration | \`bootstrap({ contributors: [LoadX.registration] })\` |
2512
2525
  | Type augmentation | \`declare module '@forinda/kickjs' { interface ContextMeta { ... } }\` |
@@ -2568,7 +2581,7 @@ ${t===`cqrs`?`### Background Jobs
2568
2581
  - [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
2569
2582
  - [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
2570
2583
  - [Testing](https://forinda.github.io/kick-js/api/testing.html)
2571
- `}function X(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})
2572
2585
 
2573
2586
  This file is the agent-facing **skills index** for KickJS work in this
2574
2587
  repo. Each block below is a short, rigid workflow keyed to a specific
@@ -2703,8 +2716,10 @@ description: Use when src/index.ts is accumulating module/middleware/plugin/adap
2703
2716
  **Refactor target**:
2704
2717
 
2705
2718
  \`\`\`ts
2706
- // src/modules/index.ts
2707
- 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]
2708
2723
 
2709
2724
  // src/middleware/index.ts
2710
2725
  export const middleware = [helmet(), cors(), requestId(), ...]
@@ -2815,7 +2830,7 @@ description: Patterns to refuse outright when the user asks for them — they br
2815
2830
  - [Decorators](https://forinda.github.io/kick-js/guide/decorators.html)
2816
2831
  - [Context Decorators](https://forinda.github.io/kick-js/guide/context-decorators.html)
2817
2832
  - [Testing](https://forinda.github.io/kick-js/api/testing.html)
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
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-DzmDwZvN.mjs`).then(e=>e.r);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-Ds2fzYZS.mjs.map