@forinda/kickjs-cli 8.1.4 → 8.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/{agent-docs-mWvpx5Qu.mjs → agent-docs-BK33p0Pw.mjs} +2 -2
  2. package/dist/{agent-docs-BKRxQ-Xq.mjs → agent-docs-DzaWoZc7.mjs} +3 -3
  3. package/dist/{agent-docs-BKRxQ-Xq.mjs.map → agent-docs-DzaWoZc7.mjs.map} +1 -1
  4. package/dist/{build-CXodASTD.mjs → build-DBT23vXN.mjs} +3 -3
  5. package/dist/{build-CXodASTD.mjs.map → build-DBT23vXN.mjs.map} +1 -1
  6. package/dist/{build-DYUzQOv-.mjs → build-clh7HpZV.mjs} +2 -2
  7. package/dist/{builtins-BK3dXr6F.mjs → builtins-B6Dc2coA.mjs} +136 -135
  8. package/dist/{builtins-CfAj3weS.mjs → builtins-HdwKAx0s.mjs} +2 -2
  9. package/dist/cli.mjs +2 -2
  10. package/dist/config-CzL24fBQ.mjs +12 -0
  11. package/dist/config-D06pHD-Y.mjs +13 -0
  12. package/dist/{config-CnsdWRi-.mjs.map → config-D06pHD-Y.mjs.map} +1 -1
  13. package/dist/{doctor-DhFt6Dql.mjs → doctor-Bi_jVzha.mjs} +53 -52
  14. package/dist/doctor-Bi_jVzha.mjs.map +1 -0
  15. package/dist/{fullstack-cs8K7UKU.mjs → fullstack-CdAbknb3.mjs} +4 -4
  16. package/dist/{fullstack-cs8K7UKU.mjs.map → fullstack-CdAbknb3.mjs.map} +1 -1
  17. package/dist/{fullstack-CfVMOuwT.mjs → fullstack-DAEEITND.mjs} +3 -3
  18. package/dist/index.d.mts +11 -0
  19. package/dist/index.d.mts.map +1 -1
  20. package/dist/index.mjs +2 -2
  21. package/dist/{plugin-Bx-oLIvD.mjs → plugin-BSNGbECd.mjs} +2 -2
  22. package/dist/{plugin-DBq3YOeu.mjs → plugin-CD9WjquV.mjs} +3 -3
  23. package/dist/{plugin-DBq3YOeu.mjs.map → plugin-CD9WjquV.mjs.map} +1 -1
  24. package/dist/{project-BrgyBfwX.mjs → project-DfBzpCeE.mjs} +5 -5
  25. package/dist/{project-docs-D3XB21OH.mjs → project-docs-BCwWphge.mjs} +3 -3
  26. package/dist/{project-docs-D3XB21OH.mjs.map → project-docs-BCwWphge.mjs.map} +1 -1
  27. package/dist/{project-docs-D1hQZj7V.mjs → project-docs-DRLN1EDX.mjs} +2 -2
  28. package/dist/{project-tpDcE3gD.mjs → project-indmSdfC.mjs} +6 -6
  29. package/dist/project-indmSdfC.mjs.map +1 -0
  30. package/dist/{project-root-8AbFL3Bz.mjs → project-root-BsyQhlS5.mjs} +2 -2
  31. package/dist/{project-root-BfJnDb6v.mjs → project-root-CQCNCAvv.mjs} +3 -3
  32. package/dist/{project-root-BfJnDb6v.mjs.map → project-root-CQCNCAvv.mjs.map} +1 -1
  33. package/dist/{prompts-BhN0QhO9.mjs → prompts-Ba0PO3Rn.mjs} +2 -2
  34. package/dist/{prompts-BhN0QhO9.mjs.map → prompts-Ba0PO3Rn.mjs.map} +1 -1
  35. package/dist/{rolldown-runtime-CiCyGOpK.mjs → rolldown-runtime-DmTqmRjS.mjs} +1 -1
  36. package/dist/{run-plugins-DMJnttf2.mjs → run-plugins-BKWupYoJ.mjs} +73 -73
  37. package/dist/run-plugins-BKWupYoJ.mjs.map +1 -0
  38. package/dist/{typegen-CvxsKt2a.mjs → typegen-B6vIx4Qd.mjs} +4 -4
  39. package/dist/{typegen-i3dMJl9r.mjs → typegen-CnsfSSpH.mjs} +5 -5
  40. package/dist/{typegen-i3dMJl9r.mjs.map → typegen-CnsfSSpH.mjs.map} +1 -1
  41. package/dist/{types-rB3GOMNT.mjs → types-B6yNws8R.mjs} +1 -1
  42. package/package.json +3 -3
  43. package/dist/config-CN5jLEsN.mjs +0 -12
  44. package/dist/config-CnsdWRi-.mjs +0 -13
  45. package/dist/doctor-DhFt6Dql.mjs.map +0 -1
  46. package/dist/project-tpDcE3gD.mjs.map +0 -1
  47. package/dist/run-plugins-DMJnttf2.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.1.4
2
+ * @forinda/kickjs-cli v8.1.5
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{l as e,s as t}from"./project-docs-D3XB21OH.mjs";import{a as n,n as r,r as i,t as a,u as o}from"./prompts-BhN0QhO9.mjs";import{i as s,s as c}from"./project-tpDcE3gD.mjs";import{o as l}from"./config-CnsdWRi-.mjs";import{t as u}from"./project-root-BfJnDb6v.mjs";import{createRequire as d}from"node:module";import f,{dirname as p,join as m,relative as h,resolve as g}from"node:path";import{existsSync as _,readFileSync as v,readdirSync as y,statSync as b}from"node:fs";import{readFile as x,writeFile as S}from"node:fs/promises";import C from"pluralize";import{pathToFileURL as w}from"node:url";import{defineGenerator as T}from"@forinda/kickjs-cli-kit";function E(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function D(e){let t=E(e);return t.charAt(0).toLowerCase()+t.slice(1)}function O(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function k(e){return C.plural(e)}function A(e){return C.plural(e)}function j(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const ee={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function te(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function ne(e){return ee[e]??te(e)}function re(e){return`create${e}Repository`}function M(e){return e??`define`}function N(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o=re(t),s=M(a),c=`/**
11
+ import{l as e,s as t}from"./project-docs-BCwWphge.mjs";import{a as n,n as r,r as i,t as a,u as o}from"./prompts-Ba0PO3Rn.mjs";import{i as s,s as c}from"./project-indmSdfC.mjs";import{o as l}from"./config-D06pHD-Y.mjs";import{t as u}from"./project-root-CQCNCAvv.mjs";import{createRequire as d}from"node:module";import f,{dirname as p,join as m,relative as h,resolve as g}from"node:path";import{existsSync as _,readFileSync as v,readdirSync as y,statSync as b}from"node:fs";import{readFile as x,writeFile as S}from"node:fs/promises";import C from"pluralize";import{pathToFileURL as ee}from"node:url";import{defineGenerator as te}from"@forinda/kickjs-cli-kit";function w(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function T(e){let t=w(e);return t.charAt(0).toLowerCase()+t.slice(1)}function E(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function D(e){return C.plural(e)}function O(e){return C.plural(e)}function k(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const ne={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function re(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function ie(e){return ne[e]??re(e)}function ae(e){return`create${e}Repository`}function A(e){return e??`define`}function j(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o=ae(t),s=A(a),c=`/**
12
12
  * ${t} Module
13
13
  *
14
14
  * REST module with a flat folder structure.
@@ -21,7 +21,7 @@ import{l as e,s as t}from"./project-docs-D3XB21OH.mjs";import{a as n,n as r,r as
21
21
  * dtos/ — Request/response schemas
22
22
  *
23
23
  * The repository is backed by an in-memory Map so this module works as
24
- * generated. Swap in ${ne(i)} by replacing the factory body in
24
+ * generated. Swap in ${ie(i)} by replacing the factory body in
25
25
  * ${n}.repository.ts — the contract is whatever that factory returns, so
26
26
  * nothing else has to change.
27
27
  */`,l=`import { ${t.toUpperCase()}_REPOSITORY, ${o} } from './${n}.repository'
@@ -86,7 +86,7 @@ ${u}
86
86
  },
87
87
  }),
88
88
  })
89
- `}function P(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=M(i),o=` /**
89
+ `}function M(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=A(i),o=` /**
90
90
  * Declare HTTP routes. Return value shape:
91
91
  *
92
92
  * - \`path\` — URL prefix for this route set.
@@ -126,7 +126,7 @@ ${o}
126
126
  },
127
127
  }),
128
128
  })
129
- `}function F(e){let{pascal:t,kebab:n}=e,r=e.swagger?`import { ApiTags } from '@forinda/kickjs-swagger'
129
+ `}function N(e){let{pascal:t,kebab:n}=e,r=e.swagger?`import { ApiTags } from '@forinda/kickjs-swagger'
130
130
  `:``,i=e.swagger?` @ApiTags('${e.pascal}')\n`:``,a=t.charAt(0).toLowerCase()+t.slice(1);return`import {
131
131
  Controller,
132
132
  Get,
@@ -198,30 +198,28 @@ ${i} async remove(ctx: Ctx<KickRoutes.${t}Controller['remove']>) {
198
198
  return reply.noContent()
199
199
  }
200
200
  }
201
- `}function ie(e){let{pascal:t}=e;return`import { z } from 'zod'
201
+ `}const P={zod:{import:`import { z } from 'zod'`,required:`z.string().min(1, 'Name is required').max(200)`,optional:`z.string().min(1).max(200).optional()`,infer:e=>`z.infer<typeof ${e}>`,hint:[` * z.string(), z.number(), z.boolean(), z.enum([...]),`,` * z.array(), z.object(), .optional(), .default(), .transform()`].join(`
202
+ `)},valibot:{import:`import * as v from 'valibot'`,required:`v.pipe(v.string(), v.minLength(1, 'Name is required'), v.maxLength(200))`,optional:`v.optional(v.pipe(v.string(), v.minLength(1), v.maxLength(200)))`,infer:e=>`v.InferOutput<typeof ${e}>`,hint:[` * v.string(), v.number(), v.boolean(), v.picklist([...]),`,` * v.array(), v.object(), v.optional(), and v.pipe(...) to chain checks`].join(`
203
+ `)},yup:{import:`import * as yup from 'yup'`,required:`yup.string().required('Name is required').min(1).max(200)`,optional:`yup.string().min(1).max(200).optional()`,infer:e=>`yup.InferType<typeof ${e}>`,hint:[` * yup.string(), yup.number(), yup.boolean(), .oneOf([...]),`,` * yup.array(), yup.object(), .required(), .optional(), .default()`].join(`
204
+ `)}};function F(e,t){return`${e===`zod`?`z.object`:e===`valibot`?`v.object`:`yup.object`}({\n ${t},\n})`}function oe(e){let{pascal:t}=e,n=e.schemaLib??`zod`,r=P[n],i=`create${t}Schema`,a=n===`zod`?`Zod`:n===`valibot`?`Valibot`:`Yup`;return`${r.import}
202
205
 
203
206
  /**
204
- * Create ${t} DTO — Zod schema for validating POST request bodies.
205
- * This schema is passed to @Post('/', { body: create${t}Schema }) for automatic validation.
207
+ * Create ${t} DTO — ${a} schema for validating POST request bodies.
208
+ * This schema is passed to @Post('/', { body: ${i} }) for automatic validation.
206
209
  * It also generates OpenAPI request body docs when SwaggerAdapter is used.
207
210
  *
208
- * Add more fields as needed. Supported Zod types:
209
- * z.string(), z.number(), z.boolean(), z.enum([...]),
210
- * z.array(), z.object(), .optional(), .default(), .transform()
211
+ * Add more fields as needed. Supported ${a} types:
212
+ ${r.hint}
211
213
  */
212
- export const create${t}Schema = z.object({
213
- name: z.string().min(1, 'Name is required').max(200),
214
- })
214
+ export const ${i} = ${F(n,`name: ${r.required}`)}
215
215
 
216
- export type Create${t}DTO = z.infer<typeof create${t}Schema>
217
- `}function ae(e){let{pascal:t}=e;return`import { z } from 'zod'
216
+ export type Create${t}DTO = ${r.infer(i)}
217
+ `}function se(e){let{pascal:t}=e,n=e.schemaLib??`zod`,r=P[n],i=`update${t}Schema`;return`${r.import}
218
218
 
219
- export const update${t}Schema = z.object({
220
- name: z.string().min(1).max(200).optional(),
221
- })
219
+ export const ${i} = ${F(n,`name: ${r.optional}`)}
222
220
 
223
- export type Update${t}DTO = z.infer<typeof update${t}Schema>
224
- `}function oe(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
221
+ export type Update${t}DTO = ${r.infer(i)}
222
+ `}function ce(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
225
223
  id: string
226
224
  name: string
227
225
  createdAt: string
@@ -302,7 +300,7 @@ export type ${t}Repository = ReturnType<typeof ${s}>
302
300
  * adopters must NOT use the reserved \`'kick/'\` namespace.
303
301
  */
304
302
  export const ${t.toUpperCase()}_REPOSITORY = createToken<${t}Repository>('${a}/${t}/repository')
305
- `}function se(e){let{pascal:t,kebab:n,plural:r=``,style:i=`define`,testHarness:a=!1}=e,o=i===`define`?`${t}Module()`:`${t}Module`;return`${a?`import { describe, it, expect, beforeEach } from 'vitest'
303
+ `}function le(e){let{pascal:t,kebab:n,plural:r=``,style:i=`define`,testHarness:a=!1}=e,o=i===`define`?`${t}Module()`:`${t}Module`;return`${a?`import { describe, it, expect, beforeEach } from 'vitest'
306
304
  import request from 'supertest'
307
305
  import { Container } from '@forinda/kickjs'
308
306
  import { createTestApp } from '@forinda/kickjs-testing'
@@ -396,7 +394,7 @@ ${a?` /**
396
394
  it.todo('deletes a ${n}')
397
395
  })
398
396
  })
399
- `}function ce(e){let{pascal:t,kebab:n,plural:r=``,repoPrefix:i=`../${n}.repository`}=e,a=`create${t}Repository`;return`import { describe, it, expect, beforeEach } from 'vitest'
397
+ `}function ue(e){let{pascal:t,kebab:n,plural:r=``,repoPrefix:i=`../${n}.repository`}=e,a=`create${t}Repository`;return`import { describe, it, expect, beforeEach } from 'vitest'
400
398
  import { ${a}, type ${t}Repository } from '${i}'
401
399
 
402
400
  describe('${t} repository', () => {
@@ -502,7 +500,7 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
502
500
  sortable: ['name', 'createdAt'],
503
501
  searchable: ['name'],
504
502
  }
505
- `}async function le(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,P({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, Post, Put, Delete, reply, type Ctx } from '@forinda/kickjs'
503
+ `}async function de(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,M({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, Post, Put, Delete, reply, type Ctx } from '@forinda/kickjs'
506
504
 
507
505
  // \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
508
506
  // \`kick typegen\` (auto-run on \`kick dev\`).
@@ -542,7 +540,7 @@ export class ${t}Controller {
542
540
  return reply.noContent()
543
541
  }
544
542
  }
545
- `)}async function ue(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,tokenScope:s,style:c,testHarness:l,write:u}=e,d=e.swagger??!1;await u(`${n}.module.ts`,N({pascal:t,kebab:n,plural:r,repo:a,style:c})),await u(`${n}.constants.ts`,R({pascal:t,kebab:n})),await u(`${n}.controller.ts`,F({pascal:t,kebab:n,plural:r,pluralPascal:i,swagger:d})),await u(`${n}.service.ts`,L({pascal:t,kebab:n})),await u(`dtos/create-${n}.dto.ts`,ie({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,ae({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,oe({pascal:t,kebab:n})),await u(`${n}.repository.ts`,I({pascal:t,kebab:n,repoType:a,dtoPrefix:`./dtos`,tokenScope:s})),o||(await u(`__tests__/${n}.controller.test.ts`,se({pascal:t,kebab:n,plural:r,style:c,testHarness:l})),await u(`__tests__/${n}.repository.test.ts`,ce({pascal:t,kebab:n,plural:r,repoPrefix:`../${n}.repository`})))}function de(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function fe(n){let{name:r,modulesDir:s,noEntity:c,noTests:l,repo:u=`inmemory`,force:d,dryRun:f}=n,p=n.pluralize!==!1,h=n.pattern??`rest`;n.minimal&&(h=`minimal`);let g=O(r),_=E(r),v=p?k(g):g,y=p?A(_):_,b=m(s,v),x=[],S=d??!1,C={kebab:g,pascal:_,plural:v,pluralPascal:y,moduleDir:b,repo:u,noEntity:c??!1,noTests:l??!1,tokenScope:n.tokenScope??`app`,swagger:n.swagger??!1,testHarness:n.testHarness??!1,style:n.style??`define`,write:async(n,r)=>{let s=m(b,n);if(f){x.push(s);return}if(!S&&await t(s)&&!await a({message:`File exists: ${o.dim(n)}. Overwrite?`,initialValue:!1})){i.warn(`Skipped: ${n}`);return}await e(s,r),x.push(s)},files:x};switch(h){case`minimal`:await le(C);break;default:await ue(C);break}return f||await z(s,_,v,g,C.style),x}async function z(n,r,i,a,o=`define`){let s=m(n,`index.ts`),c=await t(s),l=`./${i}/${a}.module`,u=o===`class`?`${r}Module`:`${r}Module()`;if(!c){await e(s,o===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
543
+ `)}async function fe(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,tokenScope:s,style:c,testHarness:l,write:u}=e,d=e.swagger??!1,f=e.schemaLib??`zod`;await u(`${n}.module.ts`,j({pascal:t,kebab:n,plural:r,repo:a,style:c})),await u(`${n}.constants.ts`,R({pascal:t,kebab:n})),await u(`${n}.controller.ts`,N({pascal:t,kebab:n,plural:r,pluralPascal:i,swagger:d})),await u(`${n}.service.ts`,L({pascal:t,kebab:n})),await u(`dtos/create-${n}.dto.ts`,oe({pascal:t,kebab:n,schemaLib:f})),await u(`dtos/update-${n}.dto.ts`,se({pascal:t,kebab:n,schemaLib:f})),await u(`dtos/${n}-response.dto.ts`,ce({pascal:t,kebab:n})),await u(`${n}.repository.ts`,I({pascal:t,kebab:n,repoType:a,dtoPrefix:`./dtos`,tokenScope:s})),o||(await u(`__tests__/${n}.controller.test.ts`,le({pascal:t,kebab:n,plural:r,style:c,testHarness:l})),await u(`__tests__/${n}.repository.test.ts`,ue({pascal:t,kebab:n,plural:r,repoPrefix:`../${n}.repository`})))}function pe(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function me(n){let{name:r,modulesDir:s,noEntity:c,noTests:l,repo:u=`inmemory`,force:d,dryRun:f}=n,p=n.pluralize!==!1,h=n.pattern??`rest`;n.minimal&&(h=`minimal`);let g=E(r),_=w(r),v=p?D(g):g,y=p?O(_):_,b=m(s,v),x=[],S=d??!1,C={kebab:g,pascal:_,plural:v,pluralPascal:y,moduleDir:b,repo:u,noEntity:c??!1,noTests:l??!1,tokenScope:n.tokenScope??`app`,swagger:n.swagger??!1,schemaLib:n.schemaLib??`zod`,testHarness:n.testHarness??!1,style:n.style??`define`,write:async(n,r)=>{let s=m(b,n);if(f){x.push(s);return}if(!S&&await t(s)&&!await a({message:`File exists: ${o.dim(n)}. Overwrite?`,initialValue:!1})){i.warn(`Skipped: ${n}`);return}await e(s,r),x.push(s)},files:x};switch(h){case`minimal`:await de(C);break;default:await fe(C);break}return f||await z(s,_,v,g,C.style),x}async function z(n,r,i,a,o=`define`){let s=m(n,`index.ts`),c=await t(s),l=`./${i}/${a}.module`,u=o===`class`?`${r}Module`:`${r}Module()`;if(!c){await e(s,o===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
546
544
  import { ${r}Module } from '${l}'
547
545
 
548
546
  export const modules: AppModuleEntry[] = [${u}]
@@ -550,11 +548,11 @@ export const modules: AppModuleEntry[] = [${u}]
550
548
  import { ${r}Module } from '${l}'
551
549
 
552
550
  export const modules = defineModules().mount(${u})
553
- `);return}let d=await x(s,`utf-8`),f=`import { ${r}Module } from '${l}'`,p=j(l);if(!RegExp(`^import\\s*\\{[^}]*\\b${j(r)}Module\\b[^}]*\\}\\s*from\\s*['"]${p}['"]`,`m`).test(d)){let e=d.lastIndexOf(`import `);if(e!==-1){let t=d.indexOf(`
551
+ `);return}let d=await x(s,`utf-8`),f=`import { ${r}Module } from '${l}'`,p=k(l);if(!RegExp(`^import\\s*\\{[^}]*\\b${k(r)}Module\\b[^}]*\\}\\s*from\\s*['"]${p}['"]`,`m`).test(d)){let e=d.lastIndexOf(`import `);if(e!==-1){let t=d.indexOf(`
554
552
  `,e);d=d.slice(0,t+1)+f+`
555
553
  `+d.slice(t+1)}else d=f+`
556
- `+d}let h=V(d);if(h){let e=d.slice(h.rhsStart,h.rhsEnd+1);RegExp(`\\b${j(r)}Module\\b`).test(e)||(d=B(d,u))}else d=B(d,u);await S(s,d,`utf-8`)}function B(e,t){let n=V(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 V(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=me(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=pe(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function pe(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=U(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=U(e,t);if(n===-1)break;i=n+1}return i}function H(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
557
- `;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&(e[t]!==`*`||e[t+1]!==`/`);)t++;return t+2}return t}function me(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=H(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 U(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=H(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 he(t){let{name:n,outDir:r}=t,i=O(n),a=E(n),o=[],s=m(r,`${i}.adapter.ts`);return await e(s,`import {
554
+ `+d}let h=V(d);if(h){let e=d.slice(h.rhsStart,h.rhsEnd+1);RegExp(`\\b${k(r)}Module\\b`).test(e)||(d=B(d,u))}else d=B(d,u);await S(s,d,`utf-8`)}function B(e,t){let n=V(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 V(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=ge(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=he(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function he(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=U(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=U(e,t);if(n===-1)break;i=n+1}return i}function H(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
555
+ `;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&(e[t]!==`*`||e[t+1]!==`/`);)t++;return t+2}return t}function ge(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=H(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 U(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=H(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 _e(t){let{name:n,outDir:r}=t,i=E(n),a=w(n),o=[],s=m(r,`${i}.adapter.ts`);return await e(s,`import {
558
556
  defineAdapter,
559
557
  type AdapterContext,
560
558
  type AdapterMiddleware,
@@ -619,7 +617,8 @@ export const ${a}Adapter = defineAdapter<${a}AdapterConfig>({
619
617
  * \`phase\` controls where each handler sits in the pipeline:
620
618
  * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'.
621
619
  *
622
- * \`path\` (optional) scopes the entry to a path prefix.
620
+ * \`path\` (optional) scopes the entry — a string prefix, a RegExp,
621
+ * or an array mixing both. See \`MiddlewarePath\`.
623
622
  *
624
623
  * Delete this hook entirely if you don't add middleware.
625
624
  */
@@ -651,8 +650,13 @@ export const ${a}Adapter = defineAdapter<${a}AdapterConfig>({
651
650
  * Delete this hook if you have no early routes.
652
651
  */
653
652
  beforeMount(_ctx: AdapterContext): void {
654
- // Example:
655
- // _ctx.app.get('/${i}/status', (_req, res) => res.json({ status: 'ok' }))
653
+ // Example — \`ctx.http\` is the engine-neutral seam, so this route
654
+ // works under Express, Fastify and h3 alike:
655
+ // _ctx.http.route('GET', '/${i}/status', (ctx) => ctx.json({ status: 'ok' }))
656
+ //
657
+ // \`ctx.app\` is the engine-native instance (an Express app only under
658
+ // the default runtime). Reach for it when what you're wiring is
659
+ // genuinely engine-specific, and accept the lock-in.
656
660
  },
657
661
 
658
662
  /**
@@ -793,10 +797,10 @@ export const ${a}Adapter = defineAdapter<${a}AdapterConfig>({
793
797
  }
794
798
  },
795
799
  })
796
- `),o.push(s),o}const ge={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`};function W(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,shouldPluralize:o=!0}=e;if(n)return g(n);if(r){let e=ge,n=O(r),a=o?k(n):n,s=e[t]??``,c=m(i,a);return g(s?m(c,s):c)}return g(a)}async function _e(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=t.runtime===`express`,s=t.runtime?`this project runs on ${t.runtime} and has no
797
- // \`express\``:"this project declares no `runtime` in kick.config.ts, so it\n // may have no `express`",c=W({type:`middleware`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/middleware`,pattern:a,shouldPluralize:t.pluralize??!0}),l=O(n),u=D(n),d=[],f=m(c,`${l}.middleware.ts`);return await e(f,`${o?`import type { Request, Response, NextFunction } from 'express'`:`import type { IncomingMessage, ServerResponse } from 'node:http'`}
800
+ `),o.push(s),o}const ve={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`};function W(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,shouldPluralize:o=!0}=e;if(n)return g(n);if(r){let e=ve,n=E(r),a=o?D(n):n,s=e[t]??``,c=m(i,a);return g(s?m(c,s):c)}return g(a)}async function ye(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=t.runtime===`express`,s=t.runtime?`this project runs on ${t.runtime} and has no
801
+ // \`express\``:"this project declares no `runtime` in kick.config.ts, so it\n // may have no `express`",c=W({type:`middleware`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/middleware`,pattern:a,shouldPluralize:t.pluralize??!0}),l=E(n),u=T(n),d=[],f=m(c,`${l}.middleware.ts`);return await e(f,`${o?`import type { Request, Response, NextFunction } from 'express'`:`import type { IncomingMessage, ServerResponse } from 'node:http'`}
798
802
 
799
- export interface ${E(n)}Options {
803
+ export interface ${w(n)}Options {
800
804
  // Add configuration options here. The factory below closes over the
801
805
  // resolved options object; pass them at the call site —
802
806
  // \`${u}({ foo: 'bar' })\` — and the closure preserves them across
@@ -804,7 +808,7 @@ export interface ${E(n)}Options {
804
808
  }
805
809
 
806
810
  /**
807
- * ${E(n)} middleware.
811
+ * ${w(n)} middleware.
808
812
  *
809
813
  * Usage in bootstrap (fires on every request):
810
814
  * middlewares: [${u}()]
@@ -840,7 +844,7 @@ export interface ${E(n)}Options {
840
844
  * first \`next()\` throws \`TypeError: next is not a function\`. Generate a
841
845
  * guard instead (\`kick g guard\`) for the per-route, ctx-style shape.
842
846
  */
843
- export function ${u}(options: ${E(n)}Options = {}) {
847
+ export function ${u}(options: ${w(n)}Options = {}) {
844
848
  ${o?" // Typed from `express` because that is this project's runtime\n // (`runtime: 'express'` in kick.config.ts). Global middleware is\n // connect-style on every engine, but only Express hands the handler its own\n // request / response objects — so `req.originalUrl`, `req.query` and\n // `res.json()` are all available here. Switching `runtime` later means\n // re-typing this signature from `node:http`.\n return (req: Request, res: Response, next: NextFunction) => {":` // Typed from \`node:http\`, not \`express\`. Global middleware is connect-style
845
849
  // on every engine, but ${s} dependency to import types from. Under Fastify the handler
846
850
  // receives \`request.raw\` / a reply driver, and under h3 the node objects, so
@@ -853,7 +857,7 @@ ${o?" // Typed from `express` because that is this project's runtime\n // (`ru
853
857
  next()
854
858
  }
855
859
  }
856
- `),d.push(f),d}async function ve(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`guard`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/guards`,pattern:a,shouldPluralize:t.pluralize??!0}),s=O(n),c=D(n),l=E(n),u=[],d=m(o,`${s}.guard.ts`);return await e(d,`import { Container, HttpException } from '@forinda/kickjs'
860
+ `),d.push(f),d}async function be(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`guard`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/guards`,pattern:a,shouldPluralize:t.pluralize??!0}),s=E(n),c=T(n),l=w(n),u=[],d=m(o,`${s}.guard.ts`);return await e(d,`import { Container, HttpException } from '@forinda/kickjs'
857
861
  import type { RequestContext } from '@forinda/kickjs'
858
862
 
859
863
  /**
@@ -893,7 +897,7 @@ export async function ${c}Guard(ctx: RequestContext, next: () => void): Promise<
893
897
  ctx.problem.unauthorized({ detail: 'Invalid or expired token' })
894
898
  }
895
899
  }
896
- `),u.push(d),u}async function ye(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`service`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/services`,pattern:a,shouldPluralize:t.pluralize??!0}),s=O(n),c=E(n),l=[],u=m(o,`${s}.service.ts`);return await e(u,`import { Service } from '@forinda/kickjs'
900
+ `),u.push(d),u}async function xe(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`service`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/services`,pattern:a,shouldPluralize:t.pluralize??!0}),s=E(n),c=w(n),l=[],u=m(o,`${s}.service.ts`);return await e(u,`import { Service } from '@forinda/kickjs'
897
901
 
898
902
  @Service()
899
903
  export class ${c}Service {
@@ -902,7 +906,7 @@ export class ${c}Service {
902
906
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
903
907
  // ) {}
904
908
  }
905
- `),l.push(u),l}async function be(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`controller`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/controllers`,pattern:a,shouldPluralize:t.pluralize??!0}),s=O(n),c=E(n),l=[],u=m(o,`${s}.controller.ts`);return await e(u,`import { Controller, Get, Post, Put, Delete, reply, type Ctx } from '@forinda/kickjs'
909
+ `),l.push(u),l}async function Se(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`controller`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/controllers`,pattern:a,shouldPluralize:t.pluralize??!0}),s=E(n),c=w(n),l=[],u=m(o,`${s}.controller.ts`);return await e(u,`import { Controller, Get, Post, Put, Delete, reply, type Ctx } from '@forinda/kickjs'
906
910
 
907
911
  // \`Ctx<KickRoutes.${c}Controller['<method>']>\` is generated by
908
912
  // \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
@@ -944,28 +948,25 @@ export class ${c}Controller {
944
948
  return reply.noContent()
945
949
  }
946
950
  }
947
- `),l.push(u),l}async function xe(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`dto`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/dtos`,pattern:a,shouldPluralize:t.pluralize??!0}),s=O(n),c=E(n),l=D(n),u=[],d=m(o,`${s}.dto.ts`);return await e(d,`import { z } from 'zod'
951
+ `),l.push(u),l}async function Ce(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=W({type:`dto`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/dtos`,pattern:a,shouldPluralize:t.pluralize??!0}),s=E(n),c=w(n),l=T(n),u=t.schemaLib??`zod`,d=P[u],f=[],p=m(o,`${s}.dto.ts`);return await e(p,`${d.import}
948
952
 
949
- export const ${l}Schema = z.object({
950
- // Define your schema fields here
951
- name: z.string().min(1).max(200),
952
- })
953
+ export const ${l}Schema = ${F(u,`// Define your schema fields here\n name: ${d.required}`)}
953
954
 
954
- export type ${c}DTO = z.infer<typeof ${l}Schema>
955
- `),u.push(d),u}function Se(){let e=(process.env.LOG_LEVEL??process.env.KICKJS_LOG_LEVEL??``).toLowerCase();return e===`debug`||e===`trace`}var Ce=class extends Error{drifted;constructor(e){let t=e.map(e=>` ${e.id} → ${e.outFile}`).join(`
956
- `);super(`kick typegen --check: ${e.length} generated file(s) are out of date:\n${t}\n Run \`kick typegen\` and commit the result.`),this.name=`TypegenDriftError`,this.drifted=e}};function we(e){return e}function Te(e){let t=new Map;return{report(n,r){let i=r instanceof Error?r.message:String(r);t.get(n)!==i&&(t.set(n,i),e(` kick typegen: ${n} pass failed (${i}) — types in .kickjs/types may be stale`))},clear(e){t.delete(e)}}}const Ee=`__kickjs_typegen_owner`;function De(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await import(`./typegen-i3dMJl9r.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await import(`./run-plugins-DMJnttf2.mjs`)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-i3dMJl9r.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-CXodASTD.mjs`).then(e=>e.n)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=f.resolve(t,n?.typegen?.outDir??`.kickjs/types`),c=n?.assetMap?Object.values(n.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>f.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,u=e=>e.replaceAll(`\\`,`/`),d=c.map(u),p=e=>{let t=u(e);return d.some(e=>t===e||t.startsWith(`${e}/`))},m=Te(e.emitWarning),h=null,g=!1,_=new Set,v=new Set,y=!1,b=!1;function x(r,c){i.runTypegen({cwd:t,silent:!0,allowDuplicates:!0,schemaValidator:a,envFile:o,srcDir:n?.typegen?.srcDir,outDir:n?.typegen?.outDir,assetMap:n?.assetMap,changedFiles:r,runPlugins:!1}).then(()=>m.clear(`scan`)).catch(e=>m.report(`scan`,e)),i.runAllPluginTypegens({cwd:t,config:n,silent:!0,changedFiles:r,watch:!0}).then(e=>i.writeTypegenArtifacts(s,e,!0)).then(()=>m.clear(`plugins`)).catch(e=>m.report(`plugins`,e)).finally(()=>e.onPassComplete?.()),c&&n&&i.buildAssets(n,{cwd:t,silent:!0}).catch(()=>{})}function S(){let e=y?void 0:{changed:[..._],removed:[...v]},t=b;_.clear(),v.clear(),y=!1,b=!1,x(e,t)}return{assetSrcRoots:c,handleWatchEvent(e,t){if(!g&&!u(t).includes(`/.kickjs/`)){if(e===`unlinkDir`)y=!0,l&&(b=!0);else{if(t.endsWith(`.d.ts`))return;let n=/\.(ts|tsx|mts|cts)$/.test(t),r=p(t);if(!n&&!r)return;r&&l&&(b=!0),n&&(e===`unlink`?(v.add(t),_.delete(t)):(_.add(t),v.delete(t)))}h&&clearTimeout(h),h=setTimeout(S,r)}},runOnce(){g||x(void 0,l)},dispose(){g=!0,h&&clearTimeout(h),h=null}}}function Oe(e){return O(e).replace(/-/g,`_`)}function G(e){let t=e.cwd??process.cwd(),n=e.projectRoot??u(t),r=e.pluralize??!0,i=E(e.name),a=D(e.name),o=O(e.name),s=Oe(e.name),c={name:e.name,pascal:i,camel:a,kebab:o,snake:s,modulesDir:e.modulesDir??`src/modules`,cwd:t,projectRoot:n,args:e.args??[],flags:e.flags??{}};if(r){let e=k(o);c.pluralKebab=e,c.pluralPascal=E(e),c.pluralCamel=D(e)}return c}function ke(e,t){return g(e.cwd,t)}async function Ae(e){return import(w(e).href)}const K=new Map;async function q(e){let t=K.get(e);if(t)return t;let n=je(e);return K.set(e,n),n}async function je(e){let t=g(e,`package.json`);if(!_(t))return{generators:[],loaded:[],failed:[]};let n=Me(JSON.parse(await x(t,`utf-8`))),r=d(g(e,`package.json`)),i=[],a=[],o=[];for(let e of n){let t;try{t=r.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await x(t,`utf-8`))}catch(t){o.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let s=n.kickjs.generators,c=g(p(t),s);if(!_(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await Ae(c)}catch(t){o.push({source:e,reason:`failed to import manifest: ${t}`});continue}let u=l.default;if(!Array.isArray(u)){o.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of u){if(!Ne(t)){o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}i.push({source:e,spec:t})}a.push(e)}return{generators:i,loaded:a,failed:o}}function Me(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 Ne(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Pe(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return J(r.spec,r.source,e,n);let i=Ie(await q(n),e.generatorName);return i?J(i.spec,i.source,e,n):null}async function Fe(e,t=[]){let n=await q(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 Ie(e,t){return e.generators.find(e=>e.spec.name===t)}async function J(t,n,r,i){let a=G({name:r.itemName,args:r.args,flags:r.flags,modulesDir:r.modulesDir,pluralize:r.pluralize,cwd:i,projectRoot:r.projectRoot}),o=await t.files(a),s=[];for(let t of o){let n=ke(a,t.path);await e(n,t.content),s.push(n)}return{files:s,source:n}}function Le(e){return e}function Re(e){return e}function ze(e){try{return JSON.parse(v(e,`utf-8`))}catch{return null}}function Y(e){try{return v(e,`utf-8`)}catch{return null}}function Be(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|[^:"'\\])\/\/.*$/gm,`$1`).replace(/,(\s*[}\]])/g,`$1`);try{return JSON.parse(t)}catch{return null}}function Ve(e){let t=m(e,`tsconfig.json`);if(_(t))return X(t,new Set)}function X(e,t){if(t.has(e)||t.size>=16)return null;t.add(e);let n=Y(e);if(n===null)return null;let r=Be(n);if(typeof r!=`object`||!r)return null;let i=Array.isArray(r.extends)?r.extends:typeof r.extends==`string`?[r.extends]:[],a={};for(let n of i){if(typeof n!=`string`)continue;let r=He(p(e),n);if(!r)continue;let i=X(r,t);i&&Object.assign(a,i.compilerOptions)}return r.compilerOptions={...a,...r.compilerOptions},r}function He(e,t){if(t.startsWith(`.`)||t.startsWith(`/`))return Z(g(e,t));let n=e;for(;;){let e=Z(m(n,`node_modules`,t));if(e)return e;let r=p(n);if(r===n)break;n=r}return null}function Z(e){if(_(e)){try{if(b(e).isDirectory()){let t=m(e,`tsconfig.json`);return _(t)?t:null}}catch{return null}return e}let t=`${e}.json`;return _(t)?t:null}function Ue(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function We(){let e=process.version,t=Number.parseInt(e.replace(/^v/,``).split(`.`)[0],10);return Number.isNaN(t)||t<20?{name:`Node version`,status:`fail`,message:e,fix:`KickJS requires Node 20 or newer.
957
- Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function Ge(e){if(!e.pkg)return{name:`@forinda/kickjs installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]?{name:`@forinda/kickjs installed`,status:`pass`,message:t[`@forinda/kickjs`]}:{name:`@forinda/kickjs installed`,status:`fail`,fix:"This directory does not look like a KickJS project — `@forinda/kickjs` is not in your package.json. Run `kick doctor` from the project root, or scaffold a fresh project with `kick new <name>`."}}function Ke(e){if(!e.pkg)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]&&!t.express?{name:`express installed`,status:`fail`,fix:"`@forinda/kickjs` declares `express` as a required peer dependency, but your package.json does not include it. Install: pnpm add express"}:t.express?{name:`express installed`,status:`pass`,message:t.express}:null}const qe={express:[],fastify:[`fastify`,`@fastify/middie`],h3:[`h3`]};function Je(e){if(!e.pkg||e.runtime===`express`)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies},n=qe[e.runtime].filter(e=>!t[e]),r=`runtime engine (${e.runtime})`;return n.length>0?{name:r,status:`fail`,fix:`Resolved runtime '${e.runtime}' is missing engine peer(s): ${n.join(`, `)}.\nInstall: pnpm add ${n.join(` `)}`}:{name:r,status:`pass`}}function Ye(e){if(!e.pkg||!Xe(e.cwd))return null;let t=s[e.runtime],n=`upload driver (${e.runtime})`;return t.prod?{...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies}[t.prod]?{name:n,status:`pass`,message:t.prod}:{name:n,status:`fail`,fix:`This project uses file uploads on the '${e.runtime}' runtime, which needs '${t.prod}'.\nInstall it: kick add upload (or pnpm add ${t.prod})`}:{name:n,status:`pass`,message:`native multipart`}}const Q=2e3;function Xe(e){let t=m(e,`src`);if(!_(t))return!1;let n=/@FileUpload\b|\bupload\.(single|array|none)\s*\(/,r=[t],i=0;for(;r.length>0&&i<Q;){let e=r.pop(),t;try{t=y(e,{withFileTypes:!0})}catch{continue}for(let a of t){if(i>=Q)break;let t=m(e,a.name);if(a.isDirectory()){a.name!==`node_modules`&&r.push(t);continue}if(/\.(ts|tsx|mts|cts)$/.test(a.name)&&(i++,n.test(Y(t)??``)))return!0}}return!1}function Ze(e){if(!e.pkg)return{name:`reflect-metadata installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies};return t[`reflect-metadata`]?{name:`reflect-metadata installed`,status:`pass`,message:t[`reflect-metadata`]}:{name:`reflect-metadata installed`,status:`fail`,fix:`KickJS decorators require the reflect-metadata polyfill.
955
+ export type ${c}DTO = ${d.infer(`${l}Schema`)}
956
+ `),f.push(p),f}function we(){let e=(process.env.LOG_LEVEL??process.env.KICKJS_LOG_LEVEL??``).toLowerCase();return e===`debug`||e===`trace`}var Te=class extends Error{drifted;constructor(e){let t=e.map(e=>` ${e.id} → ${e.outFile}`).join(`
957
+ `);super(`kick typegen --check: ${e.length} generated file(s) are out of date:\n${t}\n Run \`kick typegen\` and commit the result.`),this.name=`TypegenDriftError`,this.drifted=e}};function Ee(e){return e}function De(e){let t=new Map;return{report(n,r){let i=r instanceof Error?r.message:String(r);t.get(n)!==i&&(t.set(n,i),e(` kick typegen: ${n} pass failed (${i}) — types in .kickjs/types may be stale`))},clear(e){t.delete(e)}}}const Oe=`__kickjs_typegen_owner`;function ke(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await import(`./typegen-CnsfSSpH.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await import(`./run-plugins-BKWupYoJ.mjs`)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-CnsfSSpH.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-DBT23vXN.mjs`).then(e=>e.n)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=f.resolve(t,n?.typegen?.outDir??`.kickjs/types`),c=n?.assetMap?Object.values(n.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>f.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,u=e=>e.replaceAll(`\\`,`/`),d=c.map(u),p=e=>{let t=u(e);return d.some(e=>t===e||t.startsWith(`${e}/`))},m=De(e.emitWarning),h=null,g=!1,_=new Set,v=new Set,y=!1,b=!1;function x(r,c){i.runTypegen({cwd:t,silent:!0,allowDuplicates:!0,schemaValidator:a,envFile:o,srcDir:n?.typegen?.srcDir,outDir:n?.typegen?.outDir,assetMap:n?.assetMap,changedFiles:r,runPlugins:!1}).then(()=>m.clear(`scan`)).catch(e=>m.report(`scan`,e)),i.runAllPluginTypegens({cwd:t,config:n,silent:!0,changedFiles:r,watch:!0}).then(e=>i.writeTypegenArtifacts(s,e,!0)).then(()=>m.clear(`plugins`)).catch(e=>m.report(`plugins`,e)).finally(()=>e.onPassComplete?.()),c&&n&&i.buildAssets(n,{cwd:t,silent:!0}).catch(()=>{})}function S(){let e=y?void 0:{changed:[..._],removed:[...v]},t=b;_.clear(),v.clear(),y=!1,b=!1,x(e,t)}return{assetSrcRoots:c,handleWatchEvent(e,t){if(!g&&!u(t).includes(`/.kickjs/`)){if(e===`unlinkDir`)y=!0,l&&(b=!0);else{if(t.endsWith(`.d.ts`))return;let n=/\.(ts|tsx|mts|cts)$/.test(t),r=p(t);if(!n&&!r)return;r&&l&&(b=!0),n&&(e===`unlink`?(v.add(t),_.delete(t)):(_.add(t),v.delete(t)))}h&&clearTimeout(h),h=setTimeout(S,r)}},runOnce(){g||x(void 0,l)},dispose(){g=!0,h&&clearTimeout(h),h=null}}}function Ae(e){return E(e).replace(/-/g,`_`)}function G(e){let t=e.cwd??process.cwd(),n=e.projectRoot??u(t),r=e.pluralize??!0,i=w(e.name),a=T(e.name),o=E(e.name),s=Ae(e.name),c={name:e.name,pascal:i,camel:a,kebab:o,snake:s,modulesDir:e.modulesDir??`src/modules`,cwd:t,projectRoot:n,args:e.args??[],flags:e.flags??{}};if(r){let e=D(o);c.pluralKebab=e,c.pluralPascal=w(e),c.pluralCamel=T(e)}return c}function je(e,t){return g(e.cwd,t)}async function Me(e){return import(ee(e).href)}const K=new Map;async function q(e){let t=K.get(e);if(t)return t;let n=Ne(e);return K.set(e,n),n}async function Ne(e){let t=g(e,`package.json`);if(!_(t))return{generators:[],loaded:[],failed:[]};let n=Pe(JSON.parse(await x(t,`utf-8`))),r=d(g(e,`package.json`)),i=[],a=[],o=[];for(let e of n){let t;try{t=r.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await x(t,`utf-8`))}catch(t){o.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let s=n.kickjs.generators,c=g(p(t),s);if(!_(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await Me(c)}catch(t){o.push({source:e,reason:`failed to import manifest: ${t}`});continue}let u=l.default;if(!Array.isArray(u)){o.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of u){if(!Fe(t)){o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}i.push({source:e,spec:t})}a.push(e)}return{generators:i,loaded:a,failed:o}}function Pe(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 Fe(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Ie(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return J(r.spec,r.source,e,n);let i=Re(await q(n),e.generatorName);return i?J(i.spec,i.source,e,n):null}async function Le(e,t=[]){let n=await q(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 Re(e,t){return e.generators.find(e=>e.spec.name===t)}async function J(t,n,r,i){let a=G({name:r.itemName,args:r.args,flags:r.flags,modulesDir:r.modulesDir,pluralize:r.pluralize,cwd:i,projectRoot:r.projectRoot}),o=await t.files(a),s=[];for(let t of o){let n=je(a,t.path);await e(n,t.content),s.push(n)}return{files:s,source:n}}function ze(e){return e}function Be(e){return e}function Ve(e){try{return JSON.parse(v(e,`utf-8`))}catch{return null}}function Y(e){try{return v(e,`utf-8`)}catch{return null}}function He(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|[^:"'\\])\/\/.*$/gm,`$1`).replace(/,(\s*[}\]])/g,`$1`);try{return JSON.parse(t)}catch{return null}}function Ue(e){let t=m(e,`tsconfig.json`);if(_(t))return X(t,new Set)}function X(e,t){if(t.has(e)||t.size>=16)return null;t.add(e);let n=Y(e);if(n===null)return null;let r=He(n);if(typeof r!=`object`||!r)return null;let i=Array.isArray(r.extends)?r.extends:typeof r.extends==`string`?[r.extends]:[],a={};for(let n of i){if(typeof n!=`string`)continue;let r=We(p(e),n);if(!r)continue;let i=X(r,t);i&&Object.assign(a,i.compilerOptions)}return r.compilerOptions={...a,...r.compilerOptions},r}function We(e,t){if(t.startsWith(`.`)||t.startsWith(`/`))return Z(g(e,t));let n=e;for(;;){let e=Z(m(n,`node_modules`,t));if(e)return e;let r=p(n);if(r===n)break;n=r}return null}function Z(e){if(_(e)){try{if(b(e).isDirectory()){let t=m(e,`tsconfig.json`);return _(t)?t:null}}catch{return null}return e}let t=`${e}.json`;return _(t)?t:null}function Ge(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Ke(){let e=process.version,t=Number.parseInt(e.replace(/^v/,``).split(`.`)[0],10);return Number.isNaN(t)||t<20?{name:`Node version`,status:`fail`,message:e,fix:`KickJS requires Node 20 or newer.
958
+ Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function qe(e){if(!e.pkg)return{name:`@forinda/kickjs installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]?{name:`@forinda/kickjs installed`,status:`pass`,message:t[`@forinda/kickjs`]}:{name:`@forinda/kickjs installed`,status:`fail`,fix:"This directory does not look like a KickJS project — `@forinda/kickjs` is not in your package.json. Run `kick doctor` from the project root, or scaffold a fresh project with `kick new <name>`."}}function Je(e){if(!e.pkg)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies};return t[`@forinda/kickjs`]&&!t.express?{name:`express installed`,status:`fail`,fix:"`@forinda/kickjs` declares `express` as a required peer dependency, but your package.json does not include it. Install: pnpm add express"}:t.express?{name:`express installed`,status:`pass`,message:t.express}:null}const Ye={express:[],fastify:[`fastify`,`@fastify/middie`],h3:[`h3`]};function Xe(e){if(!e.pkg||e.runtime===`express`)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies},n=Ye[e.runtime].filter(e=>!t[e]),r=`runtime engine (${e.runtime})`;return n.length>0?{name:r,status:`fail`,fix:`Resolved runtime '${e.runtime}' is missing engine peer(s): ${n.join(`, `)}.\nInstall: pnpm add ${n.join(` `)}`}:{name:r,status:`pass`}}function Ze(e){if(!e.pkg||!Qe(e.cwd))return null;let t=s[e.runtime],n=`upload driver (${e.runtime})`;return t.prod?{...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies}[t.prod]?{name:n,status:`pass`,message:t.prod}:{name:n,status:`fail`,fix:`This project uses file uploads on the '${e.runtime}' runtime, which needs '${t.prod}'.\nInstall it: kick add upload (or pnpm add ${t.prod})`}:{name:n,status:`pass`,message:`native multipart`}}const Q=2e3;function Qe(e){let t=m(e,`src`);if(!_(t))return!1;let n=/@FileUpload\b|\bupload\.(single|array|none)\s*\(/,r=[t],i=0;for(;r.length>0&&i<Q;){let e=r.pop(),t;try{t=y(e,{withFileTypes:!0})}catch{continue}for(let a of t){if(i>=Q)break;let t=m(e,a.name);if(a.isDirectory()){a.name!==`node_modules`&&r.push(t);continue}if(/\.(ts|tsx|mts|cts)$/.test(a.name)&&(i++,n.test(Y(t)??``)))return!0}}return!1}function $e(e){if(!e.pkg)return{name:`reflect-metadata installed`,status:`warn`,message:`no package.json`};let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies};return t[`reflect-metadata`]?{name:`reflect-metadata installed`,status:`pass`,message:t[`reflect-metadata`]}:{name:`reflect-metadata installed`,status:`fail`,fix:`KickJS decorators require the reflect-metadata polyfill.
958
959
  Install it: pnpm add reflect-metadata
959
960
  Then import it at the top of src/index.ts:
960
961
 
961
962
  import 'reflect-metadata'
962
- // ... rest of bootstrap`}}function Qe(e){if(e.tsconfig===void 0)return[{name:`tsconfig.json present`,status:`fail`,fix:"Create a tsconfig.json with `experimentalDecorators: true` and `emitDecoratorMetadata: true`. `kick new` scaffolds one automatically."}];if(e.tsconfig===null)return[{name:`tsconfig.json readable`,status:`warn`,message:`could not parse tsconfig.json (or a config it extends)`,fix:"Check tsconfig.json for a syntax error, and that every path in its `extends` chain resolves. Decorator options could not be verified."}];let t=e.tsconfig.compilerOptions??{},n=[];return n.push(t.experimentalDecorators===!0?{name:`tsconfig: experimentalDecorators`,status:`pass`}:{name:`tsconfig: experimentalDecorators`,status:`fail`,fix:'Add `"experimentalDecorators": true` to compilerOptions in tsconfig.json. Without it, @Service / @Controller / @Get etc. don\'t register any metadata at compile time.'}),n.push(t.emitDecoratorMetadata===!0?{name:`tsconfig: emitDecoratorMetadata`,status:`pass`}:{name:`tsconfig: emitDecoratorMetadata`,status:`fail`,fix:'Add `"emitDecoratorMetadata": true` to compilerOptions in tsconfig.json. The DI container uses this metadata for constructor-parameter injection.'}),n}function $e(e){let t=[`src/env.ts`,`src/env/index.ts`,`src/config/env.ts`,`src/config/index.ts`].map(t=>m(e.cwd,t)).filter(e=>_(e)).filter(e=>/\bloadEnv\s*\(/.test(Y(e)??``));if(t.length===0)return null;let n=[`src/index.ts`,`src/main.ts`].map(t=>m(e.cwd,t)).find(e=>_(e));if(!n)return{name:`env wiring`,status:`warn`,message:`env-init file exists but no src/index.ts or src/main.ts found`};let r=Y(n)??``,i=p(n),a=[];for(let e of t){let t=h(i,e).replace(/\\/g,`/`).replace(/\.ts$/,``),n=t.startsWith(`.`)?t:`./`+t,r=n.replace(/\/index$/,``);a.push(n,r);let o=e.replace(/\\/g,`/`).match(/\/src\/(.+?)(?:\.ts)?$/);if(o){let e=`@/`+o[1],t=e.replace(/\/index$/,``);a.push(e,t)}}let o=-1;for(let e of new Set(a)){let t=RegExp(`^import\\s+(?:.*?from\\s+)?['"]${Ue(e)}['"]`,`m`),n=r.match(t);n&&n.index!==void 0&&(o===-1||n.index<o)&&(o=n.index)}let s=r.search(/\bbootstrap\s*\(/),c=t.map(t=>h(e.cwd,t).replace(/\\/g,`/`)).join(`, `);return o===-1?{name:`env wiring`,status:`fail`,message:c,fix:`An env-init file (${c}) calls \`loadEnv(...)\` but \`${h(e.cwd,n).replace(/\\/g,`/`)}\` doesn't import it.\nWithout this, ConfigService.get('X') returns undefined while @Value('X') works via process.env fallback — a half-broken config you won't notice until something is missing.\n\nFix: add a side-effect import at the top of ${h(e.cwd,n).replace(/\\/g,`/`)} (above bootstrap()), pointing at one of the detected files. For example:\n\n import './env'\n // or\n import './config'\n // or, with the @/ alias:\n import '@/config/env'`}:s!==-1&&o>s?{name:`env wiring`,status:`warn`,message:`env-init imported AFTER bootstrap() — should be before`,fix:`Move the env import above the bootstrap() call so the schema runs before any service reads from ConfigService.`}:{name:`env wiring`,status:`pass`}}function et(e,t=tt){let n=0,r=0,i=[e];for(;i.length>0&&r<t;){let e=i.pop(),a;try{a=y(e,{withFileTypes:!0})}catch{continue}for(let o of a){if(r>=t)break;r++;let a=m(e,o.name);if(o.isDirectory()){i.push(a);continue}try{let e=b(a).mtimeMs;e>n&&(n=e)}catch{}}}return n}const tt=2e3;function $(e){let t=m(e.cwd,`.kickjs`,`types`);if(!_(t))return null;let n=et(t);if(n===0)return null;let r=Date.now()-n,i=Math.floor(r/6e4);return i>60?{name:`typegen freshness`,status:`warn`,message:`last updated ${i} minutes ago`,fix:"Re-run `kick typegen` (or `kick dev`, which runs it on every reload) so generated types match the current code."}:{name:`typegen freshness`,status:`pass`,message:i===0?`just now`:`${i}m ago`}}const nt=[`vitest.config.ts`,`vitest.config.js`,`vitest.config.mts`,`vite.config.ts`,`jest.config.ts`,`jest.config.js`],rt=[`.env.test`,`.env.test.local`],it=[`.env`,`.env.local`];function at(e){let t=e.pkg?.scripts;if(t&&typeof t==`object`)for(let[e,n]of Object.entries(t)){if(!e.startsWith(`test`)||typeof n!=`string`)continue;let t=/KICKJS_ENV_FILE=(\S+)/.exec(n);if(t?.[1])return t[1]}return process.env.KICKJS_ENV_FILE??null}function ot(e){if(!nt.some(t=>_(m(e.cwd,t))))return null;let t=it.filter(t=>_(m(e.cwd,t)));if(t.length===0)return null;let n=rt.filter(t=>_(m(e.cwd,t)));if(n.length>0){let t=at(e);return t&&t!==`off`&&t!==`none`?{name:`test env isolation`,status:`warn`,message:`${n.join(`, `)} present, but KICKJS_ENV_FILE=${t} overrides it`,fix:`KICKJS_ENV_FILE is checked before test-mode isolation, so ${n[0]} is\nignored and "${t}" is read instead. Drop the override to use the\ntest files, or set KICKJS_ENV_FILE=off if env comes from the runner.`}:{name:`test env isolation`,status:`pass`,message:`${n.join(`, `)} present`}}return{name:`test env isolation`,status:`warn`,message:`${t.join(`, `)} present, no .env.test`,fix:`Under NODE_ENV=test (or vitest's VITEST) KickJS reads .env.test / .env.test.local
963
+ // ... rest of bootstrap`}}function et(e){if(e.tsconfig===void 0)return[{name:`tsconfig.json present`,status:`fail`,fix:"Create a tsconfig.json with `experimentalDecorators: true` and `emitDecoratorMetadata: true`. `kick new` scaffolds one automatically."}];if(e.tsconfig===null)return[{name:`tsconfig.json readable`,status:`warn`,message:`could not parse tsconfig.json (or a config it extends)`,fix:"Check tsconfig.json for a syntax error, and that every path in its `extends` chain resolves. Decorator options could not be verified."}];let t=e.tsconfig.compilerOptions??{},n=[];return n.push(t.experimentalDecorators===!0?{name:`tsconfig: experimentalDecorators`,status:`pass`}:{name:`tsconfig: experimentalDecorators`,status:`fail`,fix:'Add `"experimentalDecorators": true` to compilerOptions in tsconfig.json. Without it, @Service / @Controller / @Get etc. don\'t register any metadata at compile time.'}),n.push(t.emitDecoratorMetadata===!0?{name:`tsconfig: emitDecoratorMetadata`,status:`pass`}:{name:`tsconfig: emitDecoratorMetadata`,status:`fail`,fix:'Add `"emitDecoratorMetadata": true` to compilerOptions in tsconfig.json. The DI container uses this metadata for constructor-parameter injection.'}),n}function tt(e){let t=[`src/env.ts`,`src/env/index.ts`,`src/config/env.ts`,`src/config/index.ts`].map(t=>m(e.cwd,t)).filter(e=>_(e)).filter(e=>/\bloadEnv\s*\(/.test(Y(e)??``));if(t.length===0)return null;let n=[`src/index.ts`,`src/main.ts`].map(t=>m(e.cwd,t)).find(e=>_(e));if(!n)return{name:`env wiring`,status:`warn`,message:`env-init file exists but no src/index.ts or src/main.ts found`};let r=Y(n)??``,i=p(n),a=[];for(let e of t){let t=h(i,e).replace(/\\/g,`/`).replace(/\.ts$/,``),n=t.startsWith(`.`)?t:`./`+t,r=n.replace(/\/index$/,``);a.push(n,r);let o=e.replace(/\\/g,`/`).match(/\/src\/(.+?)(?:\.ts)?$/);if(o){let e=`@/`+o[1],t=e.replace(/\/index$/,``);a.push(e,t)}}let o=-1;for(let e of new Set(a)){let t=RegExp(`^import\\s+(?:.*?from\\s+)?['"]${Ge(e)}['"]`,`m`),n=r.match(t);n&&n.index!==void 0&&(o===-1||n.index<o)&&(o=n.index)}let s=r.search(/\bbootstrap\s*\(/),c=t.map(t=>h(e.cwd,t).replace(/\\/g,`/`)).join(`, `);return o===-1?{name:`env wiring`,status:`fail`,message:c,fix:`An env-init file (${c}) calls \`loadEnv(...)\` but \`${h(e.cwd,n).replace(/\\/g,`/`)}\` doesn't import it.\nWithout this, ConfigService.get('X') returns undefined while @Value('X') works via process.env fallback — a half-broken config you won't notice until something is missing.\n\nFix: add a side-effect import at the top of ${h(e.cwd,n).replace(/\\/g,`/`)} (above bootstrap()), pointing at one of the detected files. For example:\n\n import './env'\n // or\n import './config'\n // or, with the @/ alias:\n import '@/config/env'`}:s!==-1&&o>s?{name:`env wiring`,status:`warn`,message:`env-init imported AFTER bootstrap() — should be before`,fix:`Move the env import above the bootstrap() call so the schema runs before any service reads from ConfigService.`}:{name:`env wiring`,status:`pass`}}function $(e,t=nt){let n=0,r=0,i=[e];for(;i.length>0&&r<t;){let e=i.pop(),a;try{a=y(e,{withFileTypes:!0})}catch{continue}for(let o of a){if(r>=t)break;r++;let a=m(e,o.name);if(o.isDirectory()){i.push(a);continue}try{let e=b(a).mtimeMs;e>n&&(n=e)}catch{}}}return n}const nt=2e3;function rt(e){let t=m(e.cwd,`.kickjs`,`types`);if(!_(t))return null;let n=$(t);if(n===0)return null;let r=Date.now()-n,i=Math.floor(r/6e4);return i>60?{name:`typegen freshness`,status:`warn`,message:`last updated ${i} minutes ago`,fix:"Re-run `kick typegen` (or `kick dev`, which runs it on every reload) so generated types match the current code."}:{name:`typegen freshness`,status:`pass`,message:i===0?`just now`:`${i}m ago`}}const it=[`vitest.config.ts`,`vitest.config.js`,`vitest.config.mts`,`vite.config.ts`,`jest.config.ts`,`jest.config.js`],at=[`.env.test`,`.env.test.local`],ot=[`.env`,`.env.local`];function st(e){let t=e.pkg?.scripts;if(t&&typeof t==`object`)for(let[e,n]of Object.entries(t)){if(!e.startsWith(`test`)||typeof n!=`string`)continue;let t=/KICKJS_ENV_FILE=(\S+)/.exec(n);if(t?.[1])return t[1]}return process.env.KICKJS_ENV_FILE??null}function ct(e){if(!it.some(t=>_(m(e.cwd,t))))return null;let t=ot.filter(t=>_(m(e.cwd,t)));if(t.length===0)return null;let n=at.filter(t=>_(m(e.cwd,t)));if(n.length>0){let t=st(e);return t&&t!==`off`&&t!==`none`?{name:`test env isolation`,status:`warn`,message:`${n.join(`, `)} present, but KICKJS_ENV_FILE=${t} overrides it`,fix:`KICKJS_ENV_FILE is checked before test-mode isolation, so ${n[0]} is\nignored and "${t}" is read instead. Drop the override to use the\ntest files, or set KICKJS_ENV_FILE=off if env comes from the runner.`}:{name:`test env isolation`,status:`pass`,message:`${n.join(`, `)} present`}}return{name:`test env isolation`,status:`warn`,message:`${t.join(`, `)} present, no .env.test`,fix:`Under NODE_ENV=test (or vitest's VITEST) KickJS reads .env.test / .env.test.local
963
964
  INSTEAD of ${t.join(` and `)} — no layering, no fallback. Without one of\nthose files, every var your test config does not pin resolves from your
964
965
  development env — including DATABASE_URL and any third-party credentials.
965
966
 
966
967
  Create .env.test holding the whole environment the suite should run against
967
968
  (a var you leave out is then missing, not inherited), or set KICKJS_ENV_FILE=off
968
- and supply env from the test runner.`}}const st=[()=>We(),Ge,Ke,Je,Ye,Ze,Qe,$e,ot,$];async function ct(e,t={}){let n={cwd:e,pkg:ze(m(e,`package.json`)),tsconfig:Ve(e),runtime:t.runtime??`express`},r=[...st,...t.extraChecks??[]],i=[];for(let e of r){let t;try{t=await e(n)}catch(t){i.push({name:e.name||`doctor check`,status:`fail`,message:t instanceof Error?t.message:String(t)});continue}t!=null&&(Array.isArray(t)?i.push(...t):i.push(t))}return i}function lt(e){switch(e){case`pass`:return o.green(`✔`);case`warn`:return o.yellow(`⚠`);case`fail`:return o.red(`✖`)}}function ut(e){let t=lt(e.status),n=e.message?` ${o.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function dt(e){return e.split(`
969
+ and supply env from the test runner.`}}const lt=[()=>Ke(),qe,Je,Xe,Ze,$e,et,tt,ct,rt];async function ut(e,t={}){let n={cwd:e,pkg:Ve(m(e,`package.json`)),tsconfig:Ue(e),runtime:t.runtime??`express`},r=[...lt,...t.extraChecks??[]],i=[];for(let e of r){let t;try{t=await e(n)}catch(t){i.push({name:e.name||`doctor check`,status:`fail`,message:t instanceof Error?t.message:String(t)});continue}t!=null&&(Array.isArray(t)?i.push(...t):i.push(t))}return i}function dt(e){switch(e){case`pass`:return o.green(`✔`);case`warn`:return o.yellow(`⚠`);case`fail`:return o.red(`✖`)}}function ft(e){let t=dt(e.status),n=e.message?` ${o.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function pt(e){return e.split(`
969
970
  `).map(e=>` ${o.dim(`→`)} ${e}`).join(`
970
- `)}function ft(e){return e?.doctor?.checks??[]}function pt(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=ft(await l(e)),a=await c(e);r(`KickJS Doctor`);let s=await ct(e,{extraChecks:t,runtime:a});for(let e of s)i.message(ut(e)),e.fix&&e.status!==`pass`&&i.message(dt(e.fix));let u=s.filter(e=>e.status===`pass`).length,d=s.filter(e=>e.status===`warn`).length,f=s.filter(e=>e.status===`fail`).length,p=[o.green(`${u} passed`),d>0?o.yellow(`${d} warning${d===1?``:`s`}`):`${d} warnings`,f>0?o.red(`${f} error${f===1?``:`s`}`):`${f} errors`].join(`, `);f>0?(n(`${p} — fix the errors above before running the app`),process.exit(1)):n(d>0?`${p} — review the warnings`:o.green(`${p} — your environment looks good`))})}export{k as A,de as C,F as D,I as E,D as M,O as N,N as O,E as P,fe as S,L as T,_e as _,Pe as a,z as b,Ee as c,we as d,Se as f,ve as g,ye as h,Fe as i,A as j,j as k,De as l,be as m,Le as n,G as o,xe as p,pt as r,T as s,Re as t,Ce as u,W as v,R as w,V as x,he as y};
971
- //# sourceMappingURL=doctor-DhFt6Dql.mjs.map
971
+ `)}function mt(e){return e?.doctor?.checks??[]}function ht(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=mt(await l(e)),a=await c(e);r(`KickJS Doctor`);let s=await ut(e,{extraChecks:t,runtime:a});for(let e of s)i.message(ft(e)),e.fix&&e.status!==`pass`&&i.message(pt(e.fix));let u=s.filter(e=>e.status===`pass`).length,d=s.filter(e=>e.status===`warn`).length,f=s.filter(e=>e.status===`fail`).length,p=[o.green(`${u} passed`),d>0?o.yellow(`${d} warning${d===1?``:`s`}`):`${d} warnings`,f>0?o.red(`${f} error${f===1?``:`s`}`):`${f} errors`].join(`, `);f>0?(n(`${p} — fix the errors above before running the app`),process.exit(1)):n(d>0?`${p} — review the warnings`:o.green(`${p} — your environment looks good`))})}export{D as A,pe as C,N as D,I as E,T as M,E as N,j as O,w as P,me as S,L as T,ye as _,Ie as a,z as b,Oe as c,Ee as d,we as f,be as g,xe as h,Le as i,O as j,k,ke as l,Se as m,ze as n,G as o,Ce as p,ht as r,te as s,Be as t,Te as u,W as v,R as w,V as x,_e as y};
972
+ //# sourceMappingURL=doctor-Bi_jVzha.mjs.map