@forinda/kickjs-cli 8.12.0 → 8.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/{agent-docs-CuD2-X3w.mjs → agent-docs-D0qgHBA8.mjs} +25 -21
  2. package/dist/{agent-docs-ykxoPqXX.mjs → agent-docs-DD0hT2pE.mjs} +18 -14
  3. package/dist/agent-docs-DD0hT2pE.mjs.map +1 -0
  4. package/dist/{build-C-AsmCh1.mjs → build-C1ZgYqj7.mjs} +2 -2
  5. package/dist/{build-DQnV0GCD.mjs → build-DEdLI54B.mjs} +3 -3
  6. package/dist/{build-DQnV0GCD.mjs.map → build-DEdLI54B.mjs.map} +1 -1
  7. package/dist/{builtins-BsYCQU80.mjs → builtins-BWtf5CEP.mjs} +2 -2
  8. package/dist/{builtins-Cjp9FT1m.mjs → builtins-DZ-kQSyt.mjs} +135 -124
  9. package/dist/cli.mjs +2 -2
  10. package/dist/{config-DbnBakh8.mjs → config-CHRM7WLZ.mjs} +3 -3
  11. package/dist/{config-DbnBakh8.mjs.map → config-CHRM7WLZ.mjs.map} +1 -1
  12. package/dist/{config-DMFwBdWg.mjs → config-CQGH0FTE.mjs} +2 -2
  13. package/dist/{doctor-rEbeoAoO.mjs → doctor-D0uazKD7.mjs} +34 -23
  14. package/dist/doctor-D0uazKD7.mjs.map +1 -0
  15. package/dist/fullstack-C8k03oM8.mjs +110 -0
  16. package/dist/fullstack-Cr5tath7.mjs +111 -0
  17. package/dist/fullstack-Cr5tath7.mjs.map +1 -0
  18. package/dist/index.d.mts +8 -2
  19. package/dist/index.d.mts.map +1 -1
  20. package/dist/index.mjs +2 -2
  21. package/dist/package-manager-B-BW1RBj.mjs +11 -0
  22. package/dist/package-manager-mqxVziQ9.mjs +12 -0
  23. package/dist/package-manager-mqxVziQ9.mjs.map +1 -0
  24. package/dist/{plugin--9hxxgsD.mjs → plugin-DSgKyJSD.mjs} +2 -2
  25. package/dist/{plugin-CvlUt9NG.mjs → plugin-MPu_4sWN.mjs} +2 -2
  26. package/dist/project--T8NPgfc.mjs +133 -0
  27. package/dist/{project-root-BXmtd-te.mjs → project-root-BsIxM6Gj.mjs} +2 -2
  28. package/dist/{project-root-FMt83NHV.mjs → project-root-C4lAZePJ.mjs} +3 -3
  29. package/dist/{project-root-FMt83NHV.mjs.map → project-root-C4lAZePJ.mjs.map} +1 -1
  30. package/dist/project-w-OcvS26.mjs +134 -0
  31. package/dist/project-w-OcvS26.mjs.map +1 -0
  32. package/dist/{rolldown-runtime-C4d34LEE.mjs → rolldown-runtime-BVrPnwAV.mjs} +1 -1
  33. package/dist/{run-plugins-9tjbMqS6.mjs → run-plugins-cqNounm7.mjs} +108 -108
  34. package/dist/run-plugins-cqNounm7.mjs.map +1 -0
  35. package/dist/{typegen-Lf0UPhdl.mjs → typegen-BfFiyGeh.mjs} +4 -4
  36. package/dist/{typegen-AGdhxyRc.mjs → typegen-Ctafx65M.mjs} +5 -5
  37. package/dist/{typegen-AGdhxyRc.mjs.map → typegen-Ctafx65M.mjs.map} +1 -1
  38. package/dist/{types-B5dY2mTz.mjs → types-CH5itn9u.mjs} +1 -1
  39. package/package.json +3 -3
  40. package/templates/base/files/README.md +11 -0
  41. package/templates/template-inertia/feature.json +1 -3
  42. package/templates/template-inertia/files/vite.client.config.ts +4 -1
  43. package/templates/web-kick/files/web/vite.config.ts +4 -1
  44. package/dist/agent-docs-ykxoPqXX.mjs.map +0 -1
  45. package/dist/doctor-rEbeoAoO.mjs.map +0 -1
  46. package/dist/fullstack-DdSScENL.mjs +0 -99
  47. package/dist/fullstack-XhuwRQEb.mjs +0 -100
  48. package/dist/fullstack-XhuwRQEb.mjs.map +0 -1
  49. package/dist/package-manager-C8ekNwsa.mjs +0 -11
  50. package/dist/package-manager-DvXi-NGm.mjs +0 -12
  51. package/dist/package-manager-DvXi-NGm.mjs.map +0 -1
  52. package/dist/project-BN1DnrN3.mjs +0 -134
  53. package/dist/project-BN1DnrN3.mjs.map +0 -1
  54. package/dist/project-DBmrFgdd.mjs +0 -133
  55. package/dist/prompts-DJBDNwHt.mjs +0 -12
  56. package/dist/prompts-DJBDNwHt.mjs.map +0 -1
  57. package/dist/run-plugins-9tjbMqS6.mjs.map +0 -1
  58. package/templates/host-config/files/vercel.json +0 -5
  59. /package/templates/{host-config → deploy-netlify}/files/netlify.toml +0 -0
  60. /package/templates/{fullstack-root → deploy-netlify-workspace}/files/netlify.toml +0 -0
  61. /package/templates/{base → deploy-serverless}/files/src/serverless.ts +0 -0
  62. /package/templates/{fullstack-root → deploy-vercel}/files/vercel.json +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.12.0
2
+ * @forinda/kickjs-cli v8.13.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{i as e,o as t,t as n}from"./package-manager-DvXi-NGm.mjs";import{a as r,n as i,r as a,t as o,u as s}from"./prompts-DJBDNwHt.mjs";import{s as c}from"./config-DbnBakh8.mjs";import{c as l,i as u}from"./project-BN1DnrN3.mjs";import{t as d}from"./project-root-FMt83NHV.mjs";import{createRequire as f}from"node:module";import p,{dirname as m,join as h,relative as g,resolve as _}from"node:path";import{existsSync as v,readFileSync as y,readdirSync as b,statSync as x}from"node:fs";import{readFile as S}from"node:fs/promises";import C from"pluralize";import{pathToFileURL as w}from"node:url";import{defineGenerator as ee}from"@forinda/kickjs-cli-kit";C.addUncountableRule(`auth`);function T(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function E(e){let t=T(e);return t.charAt(0).toLowerCase()+t.slice(1)}function D(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function O(e){return C.plural(e)}function k(e){return C.plural(e)}function A(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const te={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function ne(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function re(e){return te[e]??ne(e)}function ie(e){return`create${e}Repository`}function j(e){return e??`define`}function M(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o=e.routePath??r,s=ie(t),c=j(a),l=`/**
11
+ import{_ as e,a as t,c as n,h as r,i,o as a,p as o,t as s}from"./package-manager-mqxVziQ9.mjs";import{s as c}from"./config-CHRM7WLZ.mjs";import{c as l,i as u}from"./project-w-OcvS26.mjs";import{t as d}from"./project-root-C4lAZePJ.mjs";import{createRequire as f}from"node:module";import p,{dirname as m,join as h,relative as g,resolve as _}from"node:path";import{existsSync as v,readFileSync as y,readdirSync as b,statSync as x}from"node:fs";import{readFile as S}from"node:fs/promises";import C from"pluralize";import{pathToFileURL as w}from"node:url";import{defineGenerator as ee}from"@forinda/kickjs-cli-kit";C.addUncountableRule(`auth`);function T(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function E(e){let t=T(e);return t.charAt(0).toLowerCase()+t.slice(1)}function D(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function O(e){return C.plural(e)}function k(e){return C.plural(e)}function A(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const te={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function ne(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function re(e){return te[e]??ne(e)}function ie(e){return`create${e}Repository`}function j(e){return e??`define`}function M(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o=e.routePath??r,s=ie(t),c=j(a),l=`/**
12
12
  * ${t} Module
13
13
  *
14
14
  * REST module with a flat folder structure.
@@ -250,7 +250,7 @@ export type Update${t}DTO = ${r.infer(i)}
250
250
  .filter(
251
251
  (row) =>
252
252
  parsed.filters.every((f) => matches(field(row, f.field), f)) &&
253
- (!q || SEARCHABLE.some((name) => String(field(row, name) ?? '').toLowerCase().includes(q))),
253
+ (!q || SEARCHABLE.some((name) => asText(field(row, name)).toLowerCase().includes(q))),
254
254
  )
255
255
  .sort((a, b) => order(a, b, parsed.sort, byId))
256
256
  }
@@ -336,13 +336,24 @@ function field(row: object, name: string): unknown {
336
336
  return (row as Record<string, unknown>)[name]
337
337
  }
338
338
 
339
+ /** A stored value as text — what search, filters and the text sort compare. */
340
+ function asText(value: unknown): string {
341
+ if (value === null || value === undefined) return ''
342
+ if (typeof value === 'string') return value
343
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
344
+ return String(value)
345
+ }
346
+ if (value instanceof Date) return value.toISOString()
347
+ return JSON.stringify(value)
348
+ }
349
+
339
350
  /**
340
351
  * A stored number compares by value (the query's value is text); everything
341
352
  * else, ISO dates included, as text — so a string field keeps '001' ≠ '1'.
342
353
  */
343
354
  function compare(stored: unknown, other: unknown): number {
344
355
  if (typeof stored === 'number') return stored - Number(other)
345
- return String(stored ?? '').localeCompare(String(other ?? ''))
356
+ return asText(stored).localeCompare(asText(other))
346
357
  }
347
358
 
348
359
  /**
@@ -361,7 +372,7 @@ function order(a: object, b: object, sort: readonly SortItem[], byId: boolean):
361
372
 
362
373
  /** One \`?filter=field:op:value\` — \`in\` and \`between\` take comma-separated values. */
363
374
  function matches(value: unknown, { operator, value: raw }: FilterItem): boolean {
364
- const text = String(value ?? '').toLowerCase()
375
+ const text = asText(value).toLowerCase()
365
376
  const list = raw.split(',')
366
377
  switch (operator) {
367
378
  case 'eq':
@@ -746,18 +757,18 @@ export class ${t}Controller {
746
757
  return reply.noContent()
747
758
  }
748
759
  }
749
- `)}async function me(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,routePath:a,repo:o,noTests:s,tokenScope:c,style:l,testHarness:u,testImport:d,write:f}=e,p=e.swagger??!1,m=e.schemaLib??`zod`;await f(`${n}.module.ts`,M({pascal:t,kebab:n,plural:r,routePath:a,repo:o,style:l})),await f(`${n}.constants.ts`,R({pascal:t,kebab:n})),await f(`${n}.controller.ts`,N({pascal:t,kebab:n,plural:r,pluralPascal:i,swagger:p})),await f(`${n}.service.ts`,L({pascal:t,kebab:n})),await f(`dtos/create-${n}.dto.ts`,oe({pascal:t,kebab:n,schemaLib:m})),await f(`dtos/update-${n}.dto.ts`,se({pascal:t,kebab:n,schemaLib:m})),await f(`dtos/${n}-response.dto.ts`,ce({pascal:t,kebab:n})),await f(`${n}.repository.ts`,I({pascal:t,kebab:n,repoType:o,dtoPrefix:`./dtos`,tokenScope:c})),s||(await f(`__tests__/${n}.controller.test.ts`,le({pascal:t,kebab:n,plural:r,routePath:a,style:l,testHarness:u,testImport:d})),await f(`__tests__/${n}.repository.test.ts`,ue({pascal:t,kebab:n,plural:r,repoPrefix:`../${n}.repository`,testImport:d})))}function he(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function ge(n){let{name:r,modulesDir:i,noEntity:c,noTests:l,repo:u=`inmemory`,force:d,dryRun:f}=n,p=n.pluralize===!0,m=n.pattern??`rest`;n.minimal&&(m=`minimal`);let g=D(r),_=T(r),v=p?O(g):g,y=p?k(_):_,b=n.pluralizeRoutes===!1?g:O(g),x=h(i,v),S=[],C=d??!1,w={kebab:g,pascal:_,plural:v,pluralPascal:y,routePath:b,moduleDir:x,repo:u,noEntity:c??!1,noTests:l??!1,tokenScope:n.tokenScope??`app`,swagger:n.swagger??!1,schemaLib:n.schemaLib??`zod`,testHarness:n.testHarness??!1,testImport:n.testImport,style:n.style??`define`,write:async(n,r)=>{let i=h(x,n);f?S.push(i):!C&&await e(i)&&!await o({message:`File exists: ${s.dim(n)}. Overwrite?`,initialValue:!1})?a.warn(`Skipped: ${n}`):(await t(i,r),S.push(i))},files:S};switch(m){case`minimal`:await pe(w);break;default:await me(w)}return f||await z(i,_,v,g,w.style),S}async function z(n,r,i,a,o=`define`){let s=h(n,`index.ts`),c=await e(s),l=`./${i}/${a}.module`,u=o===`class`?`${r}Module`:`${r}Module()`;if(!c){let e=o===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
750
- import { ${r}Module } from '${l}'
760
+ `)}async function me(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,routePath:a,repo:o,noTests:s,tokenScope:c,style:l,testHarness:u,testImport:d,write:f}=e,p=e.swagger??!1,m=e.schemaLib??`zod`;await f(`${n}.module.ts`,M({pascal:t,kebab:n,plural:r,routePath:a,repo:o,style:l})),await f(`${n}.constants.ts`,R({pascal:t,kebab:n})),await f(`${n}.controller.ts`,N({pascal:t,kebab:n,plural:r,pluralPascal:i,swagger:p})),await f(`${n}.service.ts`,L({pascal:t,kebab:n})),await f(`dtos/create-${n}.dto.ts`,oe({pascal:t,kebab:n,schemaLib:m})),await f(`dtos/update-${n}.dto.ts`,se({pascal:t,kebab:n,schemaLib:m})),await f(`dtos/${n}-response.dto.ts`,ce({pascal:t,kebab:n})),await f(`${n}.repository.ts`,I({pascal:t,kebab:n,repoType:o,dtoPrefix:`./dtos`,tokenScope:c})),s||(await f(`__tests__/${n}.controller.test.ts`,le({pascal:t,kebab:n,plural:r,routePath:a,style:l,testHarness:u,testImport:d})),await f(`__tests__/${n}.repository.test.ts`,ue({pascal:t,kebab:n,plural:r,repoPrefix:`../${n}.repository`,testImport:d})))}function he(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function ge(t){let{name:n,modulesDir:s,noEntity:c,noTests:l,repo:u=`inmemory`,force:d,dryRun:f}=t,p=t.pluralize===!0,m=t.pattern??`rest`;t.minimal&&(m=`minimal`);let g=D(n),_=T(n),v=p?O(g):g,y=p?k(_):_,b=t.pluralizeRoutes===!1?g:O(g),x=h(s,v),S=[],C=d??!1,w={kebab:g,pascal:_,plural:v,pluralPascal:y,routePath:b,moduleDir:x,repo:u,noEntity:c??!1,noTests:l??!1,tokenScope:t.tokenScope??`app`,swagger:t.swagger??!1,schemaLib:t.schemaLib??`zod`,testHarness:t.testHarness??!1,testImport:t.testImport,style:t.style??`define`,write:async(t,n)=>{let s=h(x,t);f?S.push(s):!C&&await r(s)&&!await i({message:`File exists: ${o.dim(t)}. Overwrite?`,initialValue:!1})?a.warn(`Skipped: ${t}`):(await e(s,n),S.push(s))},files:S};switch(m){case`minimal`:await pe(w);break;default:await me(w)}return f||await z(s,_,v,g,w.style),S}async function z(t,n,i,a,o=`define`){let s=h(t,`index.ts`),c=await r(s),l=`./${i}/${a}.module`,u=o===`class`?`${n}Module`:`${n}Module()`;if(!c){let t=o===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
761
+ import { ${n}Module } from '${l}'
751
762
 
752
763
  export const modules: AppModuleEntry[] = [${u}]
753
764
  `:`import { defineModules } from '@forinda/kickjs'
754
- import { ${r}Module } from '${l}'
765
+ import { ${n}Module } from '${l}'
755
766
 
756
767
  export const modules = defineModules().mount(${u})
757
- `;await t(s,e);return}let d=await S(s,`utf-8`),f=`import { ${r}Module } from '${l}'`,p=A(l);if(!RegExp(`^import\\s*\\{[^}]*\\b${A(r)}Module\\b[^}]*\\}\\s*from\\s*['"]${p}['"]`,`m`).test(d)){let e=d.lastIndexOf(`import `);if(e!==-1){let t=d.indexOf(`
768
+ `;await e(s,t);return}let d=await S(s,`utf-8`),f=`import { ${n}Module } from '${l}'`,p=A(l);if(!RegExp(`^import\\s*\\{[^}]*\\b${A(n)}Module\\b[^}]*\\}\\s*from\\s*['"]${p}['"]`,`m`).test(d)){let e=d.lastIndexOf(`import `);if(e!==-1){let t=d.indexOf(`
758
769
  `,e);d=d.slice(0,t+1)+f+`
759
770
  `+d.slice(t+1)}else d=f+`
760
- `+d}let m=V(d);if(m){let e=d.slice(m.rhsStart,m.rhsEnd+1);RegExp(`\\b${A(r)}Module\\b`).test(e)||(d=B(d,u))}else d=B(d,u);await t(s,d)}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=ve(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=_e(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function _e(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]!==`
771
+ `+d}let m=V(d);if(m){let e=d.slice(m.rhsStart,m.rhsEnd+1);RegExp(`\\b${A(n)}Module\\b`).test(e)||(d=B(d,u))}else d=B(d,u);await e(s,d)}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=ve(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=_e(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function _e(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]!==`
761
772
  `;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&(e[t]!==`*`||e[t+1]!==`/`);)t++;return t+2}return t}function ve(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++}else{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++}else{if(i===`(`)n++;else if(i===`)`&&(n--,n===0))return r;r++}}return-1}function W(e,t,n,r){return`/**
762
773
  * Snapshot for the DevTools topology view (\`/_debug\`).
763
774
  *
@@ -798,7 +809,7 @@ export const modules = defineModules().mount(${u})
798
809
  // ]
799
810
  // },`.split(`
800
811
  `).map(e=>r+e).join(`
801
- `)}async function ye(e){let{name:n,outDir:r}=e,i=D(n),a=T(n),o=[],s=h(r,`${i}.adapter.ts`);return await t(s,`import {
812
+ `)}async function ye(t){let{name:n,outDir:r}=t,i=D(n),a=T(n),o=[],s=h(r,`${i}.adapter.ts`);return await e(s,`import {
802
813
  defineAdapter,
803
814
  type AdapterContext,
804
815
  type AdapterMiddleware,
@@ -1007,8 +1018,8 @@ ${W(i,a,`adapter`,` `)}
1007
1018
  }
1008
1019
  },
1009
1020
  })
1010
- `),o.push(s),o}const be={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`};function G(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,shouldPluralize:o=!1}=e;if(n)return _(n);if(r){let e=be,n=D(r),a=o?O(n):n,s=e[t]??``,c=h(i,a);return _(s?h(c,s):c)}return _(a)}async function xe(e){let{name:n,moduleName:r,modulesDir:i,pattern:a}=e,o=e.runtime===`express`,s=e.runtime?`this project runs on ${e.runtime} and has no
1011
- // \`express\``:"this project declares no `runtime` in kick.config.ts, so it\n // may have no `express`",c=G({type:`middleware`,outDir:e.outDir,moduleName:r,modulesDir:i,defaultDir:`src/middleware`,pattern:a,shouldPluralize:e.pluralize??!1}),l=D(n),u=E(n),d=[],f=h(c,`${l}.middleware.ts`);return await t(f,`${o?`import type { Request, Response, NextFunction } from 'express'`:`import type { IncomingMessage, ServerResponse } from 'node:http'`}
1021
+ `),o.push(s),o}const be={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`};function G(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,shouldPluralize:o=!1}=e;if(n)return _(n);if(r){let e=be,n=D(r),a=o?O(n):n,s=e[t]??``,c=h(i,a);return _(s?h(c,s):c)}return _(a)}async function xe(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
1022
+ // \`express\``:"this project declares no `runtime` in kick.config.ts, so it\n // may have no `express`",c=G({type:`middleware`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/middleware`,pattern:a,shouldPluralize:t.pluralize??!1}),l=D(n),u=E(n),d=[],f=h(c,`${l}.middleware.ts`);return await e(f,`${o?`import type { Request, Response, NextFunction } from 'express'`:`import type { IncomingMessage, ServerResponse } from 'node:http'`}
1012
1023
 
1013
1024
  export interface ${T(n)}Options {
1014
1025
  // Add configuration options here. The factory below closes over the
@@ -1067,7 +1078,7 @@ ${o?" // Typed from `express` because that is this project's runtime\n // (`ru
1067
1078
  next()
1068
1079
  }
1069
1080
  }
1070
- `),d.push(f),d}async function Se(e){let{name:n,moduleName:r,modulesDir:i,pattern:a}=e,o=G({type:`guard`,outDir:e.outDir,moduleName:r,modulesDir:i,defaultDir:`src/guards`,pattern:a,shouldPluralize:e.pluralize??!1}),s=D(n),c=E(n),l=T(n),u=[],d=h(o,`${s}.guard.ts`);return await t(d,`import { Container, HttpException } from '@forinda/kickjs'
1081
+ `),d.push(f),d}async function Se(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=G({type:`guard`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/guards`,pattern:a,shouldPluralize:t.pluralize??!1}),s=D(n),c=E(n),l=T(n),u=[],d=h(o,`${s}.guard.ts`);return await e(d,`import { Container, HttpException } from '@forinda/kickjs'
1071
1082
  import type { RequestContext } from '@forinda/kickjs'
1072
1083
 
1073
1084
  /**
@@ -1107,7 +1118,7 @@ export async function ${c}Guard(ctx: RequestContext, next: () => void): Promise<
1107
1118
  ctx.problem.unauthorized({ detail: 'Invalid or expired token' })
1108
1119
  }
1109
1120
  }
1110
- `),u.push(d),u}async function Ce(e){let{name:n,moduleName:r,modulesDir:i,pattern:a}=e,o=G({type:`service`,outDir:e.outDir,moduleName:r,modulesDir:i,defaultDir:`src/services`,pattern:a,shouldPluralize:e.pluralize??!1}),s=D(n),c=T(n),l=[],u=h(o,`${s}.service.ts`);return await t(u,`import { Service } from '@forinda/kickjs'
1121
+ `),u.push(d),u}async function Ce(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=G({type:`service`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/services`,pattern:a,shouldPluralize:t.pluralize??!1}),s=D(n),c=T(n),l=[],u=h(o,`${s}.service.ts`);return await e(u,`import { Service } from '@forinda/kickjs'
1111
1122
 
1112
1123
  @Service()
1113
1124
  export class ${c}Service {
@@ -1116,7 +1127,7 @@ export class ${c}Service {
1116
1127
  // @Inject(MY_REPO) private readonly repo: IMyRepository,
1117
1128
  // ) {}
1118
1129
  }
1119
- `),l.push(u),l}async function we(e){let{name:n,moduleName:r,modulesDir:i,pattern:a}=e,o=G({type:`controller`,outDir:e.outDir,moduleName:r,modulesDir:i,defaultDir:`src/controllers`,pattern:a,shouldPluralize:e.pluralize??!1}),s=D(n),c=T(n),l=[],u=h(o,`${s}.controller.ts`);return await t(u,`import { Controller, Get, Post, Patch, Delete, reply, type Ctx } from '@forinda/kickjs'
1130
+ `),l.push(u),l}async function we(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=G({type:`controller`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/controllers`,pattern:a,shouldPluralize:t.pluralize??!1}),s=D(n),c=T(n),l=[],u=h(o,`${s}.controller.ts`);return await e(u,`import { Controller, Get, Post, Patch, Delete, reply, type Ctx } from '@forinda/kickjs'
1120
1131
 
1121
1132
  // \`Ctx<KickRoutes.${c}Controller['<method>']>\` is generated by
1122
1133
  // \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
@@ -1159,21 +1170,21 @@ export class ${c}Controller {
1159
1170
  return reply.noContent()
1160
1171
  }
1161
1172
  }
1162
- `),l.push(u),l}async function Te(e){let{name:n,moduleName:r,modulesDir:i,pattern:a}=e,o=G({type:`dto`,outDir:e.outDir,moduleName:r,modulesDir:i,defaultDir:`src/dtos`,pattern:a,shouldPluralize:e.pluralize??!1}),s=D(n),c=T(n),l=E(n),u=e.schemaLib??`zod`,d=P[u],f=[],p=h(o,`${s}.dto.ts`);return await t(p,`${d.import}
1173
+ `),l.push(u),l}async function Te(t){let{name:n,moduleName:r,modulesDir:i,pattern:a}=t,o=G({type:`dto`,outDir:t.outDir,moduleName:r,modulesDir:i,defaultDir:`src/dtos`,pattern:a,shouldPluralize:t.pluralize??!1}),s=D(n),c=T(n),l=E(n),u=t.schemaLib??`zod`,d=P[u],f=[],p=h(o,`${s}.dto.ts`);return await e(p,`${d.import}
1163
1174
 
1164
1175
  export const ${l}Schema = ${F(u,`// Define your schema fields here\n name: ${d.required}`)}
1165
1176
 
1166
1177
  export type ${c}DTO = ${d.infer(`${l}Schema`)}
1167
1178
  `),f.push(p),f}function Ee(){let e=(process.env.LOG_LEVEL??process.env.KICKJS_LOG_LEVEL??``).toLowerCase();return e===`debug`||e===`trace`}var De=class extends Error{drifted;constructor(e){let t=e.map(e=>` ${e.id} → ${e.outFile}`).join(`
1168
- `);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 Oe(e){return e}function ke(e){let t=/* @__PURE__ */ 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 Ae=`__kickjs_typegen_owner`;function je(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await import(`./typegen-AGdhxyRc.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await import(`./run-plugins-9tjbMqS6.mjs`).then(e=>e.n)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-AGdhxyRc.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-DQnV0GCD.mjs`).then(e=>e.n)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=p.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=>p.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,u=e=>e.replaceAll(`\\`,`/`),d=c.map(u),f=e=>{let t=u(e);return d.some(e=>t===e||t.startsWith(`${e}/`))},m=ke(e.emitWarning),h=null,g=!1,_=/* @__PURE__ */ new Set,v=/* @__PURE__ */ 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=f(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 Me(e){return D(e).replace(/-/g,`_`)}function K(e){let t=e.cwd??process.cwd(),n=e.projectRoot??d(t),r=e.pluralize??!1,i=T(e.name),a=E(e.name),o=D(e.name),s=Me(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=O(o);c.pluralKebab=e,c.pluralPascal=T(e),c.pluralCamel=E(e)}return c}function Ne(e,t){return _(e.cwd,t)}async function Pe(e){return import(w(e).href)}const q=/* @__PURE__ */ new Map;async function J(e){let t=q.get(e);if(t)return t;let n=Fe(e);return q.set(e,n),n}async function Fe(e){let t=_(e,`package.json`);if(!v(t))return{generators:[],loaded:[],failed:[]};let n=Ie(JSON.parse(await S(t,`utf-8`))),r=f(_(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 S(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=_(m(t),s);if(!v(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await Pe(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`});else{for(let t of u)Le(t)?i.push({source:e,spec:t}):o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});a.push(e)}}return{generators:i,loaded:a,failed:o}}function Ie(e){let t=/* @__PURE__ */ 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 Le(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Re(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Y(r.spec,r.source,e,n);let i=Be(await J(n),e.generatorName);return i?Y(i.spec,i.source,e,n):null}async function ze(e,t=[]){let n=await J(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 Be(e,t){return e.generators.find(e=>e.spec.name===t)}async function Y(e,n,r,i){let a=K({name:r.itemName,args:r.args,flags:r.flags,modulesDir:r.modulesDir,pluralize:r.pluralize,cwd:i,projectRoot:r.projectRoot}),o=await e.files(a),s=[];for(let e of o){let n=Ne(a,e.path);await t(n,e.content),s.push(n)}return{files:s,source:n}}function Ve(e){return e}function He(e){return e}function Ue(e){try{return JSON.parse(y(e,`utf-8`))}catch{return null}}function X(e){try{return y(e,`utf-8`)}catch{return null}}function We(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|[^:"'\\])\/\/.*$/gm,`$1`).replace(/,(\s*[}\]])/g,`$1`);try{return JSON.parse(t)}catch{return null}}function Ge(e){let t=h(e,`tsconfig.json`);if(v(t))return Z(t,/* @__PURE__ */ new Set)}function Z(e,t){if(t.has(e)||t.size>=16)return null;t.add(e);let n=X(e);if(n===null)return null;let r=We(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=Ke(m(e),n);if(!r)continue;let i=Z(r,t);i&&Object.assign(a,i.compilerOptions)}return r.compilerOptions={...a,...r.compilerOptions},r}function Ke(e,t){if(t.startsWith(`.`)||t.startsWith(`/`))return Q(_(e,t));let n=e;for(;;){let e=Q(h(n,`node_modules`,t));if(e)return e;let r=m(n);if(r===n)break;n=r}return null}function Q(e){if(v(e)){try{if(x(e).isDirectory()){let t=h(e,`tsconfig.json`);return v(t)?t:null}}catch{return null}return e}let t=`${e}.json`;return v(t)?t:null}function qe(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Je(){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.
1169
- Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function Ye(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 Xe(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: ${n(e.cwd)} add express`}:t.express?{name:`express installed`,status:`pass`,message:t.express}:null}const Ze={express:[],fastify:[`fastify`,`@fastify/middie`],h3:[`h3`]};function Qe(e){if(!e.pkg||e.runtime===`express`)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies},r=Ze[e.runtime].filter(e=>!t[e]),i=`runtime engine (${e.runtime})`;return r.length>0?{name:i,status:`fail`,fix:`Resolved runtime '${e.runtime}' is missing engine peer(s): ${r.join(`, `)}.\nInstall: ${n(e.cwd)} add ${r.join(` `)}`}:e.runtime===`h3`&&$e(e.cwd,t.h3)===1?{name:i,status:`fail`,message:`h3 v1`,fix:`This version of @forinda/kickjs runs on h3 v2 only. Upgrade: ${n(e.cwd)} add h3@^2 — no code change for apps that only use KickJS APIs.`}:{name:i,status:`pass`}}function $e(e,t){let n=t;for(let t=_(e);;t=m(t)){try{n=JSON.parse(y(h(t,`node_modules`,`h3`,`package.json`),`utf8`)).version;break}catch{}if(m(t)===t)break}let r=/(\d+)/.exec(n)?.[1];return r===void 0?void 0:Number(r)}function et(e){if(!e.pkg||!tt(e.cwd))return null;let t=u[e.runtime],r=`upload driver (${e.runtime})`;return t.prod?{...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies}[t.prod]?{name:r,status:`pass`,message:t.prod}:{name:r,status:`fail`,fix:`This project uses file uploads on the '${e.runtime}' runtime, which needs '${t.prod}'.\nInstall it: kick add upload (or ${n(e.cwd)} add ${t.prod})`}:{name:r,status:`pass`,message:`native multipart`}}const $=2e3;function tt(e){let t=h(e,`src`);if(!v(t))return!1;let n=/@FileUpload\b|\bupload\.(single|array|none)\s*\(/,r=[t],i=0;for(;r.length>0&&i<$;){let e=r.pop(),t;try{t=b(e,{withFileTypes:!0})}catch{continue}for(let a of t){if(i>=$)break;let t=h(e,a.name);if(a.isDirectory())a.name!==`node_modules`&&r.push(t);else if(/\.(ts|tsx|mts|cts)$/.test(a.name)&&(i++,n.test(X(t)??``)))return!0}}return!1}function nt(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.\nInstall it: ${n(e.cwd)} add reflect-metadata\nThen import it at the top of src/index.ts:\n\n import 'reflect-metadata'\n // ... rest of bootstrap`}}function rt(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 it(e){let t=[`src/env.ts`,`src/env/index.ts`,`src/config/env.ts`,`src/config/index.ts`].map(t=>h(e.cwd,t)).filter(e=>v(e)).filter(e=>/\bloadEnv\s*\(/.test(X(e)??``));if(t.length===0)return null;let n=[`src/index.ts`,`src/main.ts`].map(t=>h(e.cwd,t)).find(e=>v(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=X(n)??``,i=m(n),a=[];for(let e of t){let t=g(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+)?['"]${qe(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=>g(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 \`${g(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 ${g(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 at(e,t=ot){let n=0,r=0,i=[e];for(;i.length>0&&r<t;){let e=i.pop(),a;try{a=b(e,{withFileTypes:!0})}catch{continue}for(let o of a){if(r>=t)break;r++;let a=h(e,o.name);if(o.isDirectory())i.push(a);else try{let e=x(a).mtimeMs;e>n&&(n=e)}catch{}}}return n}const ot=2e3;function st(e){let t=h(e.cwd,`.kickjs`,`types`);if(!v(t))return null;let n=at(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 ct=[`vitest.config.ts`,`vitest.config.js`,`vitest.config.mts`,`vite.config.ts`,`jest.config.ts`,`jest.config.js`],lt=[`.env.test`,`.env.test.local`],ut=[`.env`,`.env.local`];function dt(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 ft(e){if(!ct.some(t=>v(h(e.cwd,t))))return null;let t=ut.filter(t=>v(h(e.cwd,t)));if(t.length===0)return null;let n=lt.filter(t=>v(h(e.cwd,t)));if(n.length>0){let t=dt(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
1179
+ `);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 Oe(e){return e}function ke(e){let t=/* @__PURE__ */ 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 Ae=`__kickjs_typegen_owner`;function je(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await import(`./typegen-Ctafx65M.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await import(`./run-plugins-cqNounm7.mjs`).then(e=>e.n)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-Ctafx65M.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-DEdLI54B.mjs`).then(e=>e.n)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=p.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=>p.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,u=e=>e.replaceAll(`\\`,`/`),d=c.map(u),f=e=>{let t=u(e);return d.some(e=>t===e||t.startsWith(`${e}/`))},m=ke(e.emitWarning),h=null,g=!1,_=/* @__PURE__ */ new Set,v=/* @__PURE__ */ 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=f(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 Me(e){return D(e).replace(/-/g,`_`)}function K(e){let t=e.cwd??process.cwd(),n=e.projectRoot??d(t),r=e.pluralize??!1,i=T(e.name),a=E(e.name),o=D(e.name),s=Me(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=O(o);c.pluralKebab=e,c.pluralPascal=T(e),c.pluralCamel=E(e)}return c}function Ne(e,t){return _(e.cwd,t)}async function Pe(e){return import(w(e).href)}const q=/* @__PURE__ */ new Map;async function J(e){let t=q.get(e);if(t)return t;let n=Fe(e);return q.set(e,n),n}async function Fe(e){let t=_(e,`package.json`);if(!v(t))return{generators:[],loaded:[],failed:[]};let n=Ie(JSON.parse(await S(t,`utf-8`))),r=f(_(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 S(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=_(m(t),s);if(!v(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await Pe(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`});else{for(let t of u)Le(t)?i.push({source:e,spec:t}):o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});a.push(e)}}return{generators:i,loaded:a,failed:o}}function Ie(e){let t=/* @__PURE__ */ 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 Le(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function Re(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return Y(r.spec,r.source,e,n);let i=Be(await J(n),e.generatorName);return i?Y(i.spec,i.source,e,n):null}async function ze(e,t=[]){let n=await J(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 Be(e,t){return e.generators.find(e=>e.spec.name===t)}async function Y(t,n,r,i){let a=K({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=Ne(a,t.path);await e(n,t.content),s.push(n)}return{files:s,source:n}}function Ve(e){return e}function He(e){return e}function Ue(e){try{return JSON.parse(y(e,`utf-8`))}catch{return null}}function X(e){try{return y(e,`utf-8`)}catch{return null}}function We(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|[^:"'\\])\/\/.*$/gm,`$1`).replace(/,(\s*[}\]])/g,`$1`);try{return JSON.parse(t)}catch{return null}}function Ge(e){let t=h(e,`tsconfig.json`);if(v(t))return Z(t,/* @__PURE__ */ new Set)}function Z(e,t){if(t.has(e)||t.size>=16)return null;t.add(e);let n=X(e);if(n===null)return null;let r=We(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=Ke(m(e),n);if(!r)continue;let i=Z(r,t);i&&Object.assign(a,i.compilerOptions)}return r.compilerOptions={...a,...r.compilerOptions},r}function Ke(e,t){if(t.startsWith(`.`)||t.startsWith(`/`))return Q(_(e,t));let n=e;for(;;){let e=Q(h(n,`node_modules`,t));if(e)return e;let r=m(n);if(r===n)break;n=r}return null}function Q(e){if(v(e)){try{if(x(e).isDirectory()){let t=h(e,`tsconfig.json`);return v(t)?t:null}}catch{return null}return e}let t=`${e}.json`;return v(t)?t:null}function qe(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Je(){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.
1180
+ Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function Ye(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 Xe(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: ${s(e.cwd)} add express`}:t.express?{name:`express installed`,status:`pass`,message:t.express}:null}const Ze={express:[],fastify:[`fastify`,`@fastify/middie`],h3:[`h3`]};function Qe(e){if(!e.pkg||e.runtime===`express`)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies},n=Ze[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: ${s(e.cwd)} add ${n.join(` `)}`}:e.runtime===`h3`&&$e(e.cwd,t.h3)===1?{name:r,status:`fail`,message:`h3 v1`,fix:`This version of @forinda/kickjs runs on h3 v2 only. Upgrade: ${s(e.cwd)} add h3@^2 — no code change for apps that only use KickJS APIs.`}:{name:r,status:`pass`}}function $e(e,t){let n=t;for(let t=_(e);;t=m(t)){try{n=JSON.parse(y(h(t,`node_modules`,`h3`,`package.json`),`utf8`)).version;break}catch{}if(m(t)===t)break}let r=/(\d+)/.exec(n)?.[1];return r===void 0?void 0:Number(r)}function et(e){if(!e.pkg||!tt(e.cwd))return null;let t=u[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 ${s(e.cwd)} add ${t.prod})`}:{name:n,status:`pass`,message:`native multipart`}}const $=2e3;function tt(e){let t=h(e,`src`);if(!v(t))return!1;let n=/@FileUpload\b|\bupload\.(single|array|none)\s*\(/,r=[t],i=0;for(;r.length>0&&i<$;){let e=r.pop(),t;try{t=b(e,{withFileTypes:!0})}catch{continue}for(let a of t){if(i>=$)break;let t=h(e,a.name);if(a.isDirectory())a.name!==`node_modules`&&r.push(t);else if(/\.(ts|tsx|mts|cts)$/.test(a.name)&&(i++,n.test(X(t)??``)))return!0}}return!1}function nt(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.\nInstall it: ${s(e.cwd)} add reflect-metadata\nThen import it at the top of src/index.ts:\n\n import 'reflect-metadata'\n // ... rest of bootstrap`}}function rt(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 it(e){let t=[`src/env.ts`,`src/env/index.ts`,`src/config/env.ts`,`src/config/index.ts`].map(t=>h(e.cwd,t)).filter(e=>v(e)).filter(e=>/\bloadEnv\s*\(/.test(X(e)??``));if(t.length===0)return null;let n=[`src/index.ts`,`src/main.ts`].map(t=>h(e.cwd,t)).find(e=>v(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=X(n)??``,i=m(n),a=[];for(let e of t){let t=g(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+)?['"]${qe(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=>g(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 \`${g(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 ${g(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 at(e,t=ot){let n=0,r=0,i=[e];for(;i.length>0&&r<t;){let e=i.pop(),a;try{a=b(e,{withFileTypes:!0})}catch{continue}for(let o of a){if(r>=t)break;r++;let a=h(e,o.name);if(o.isDirectory())i.push(a);else try{let e=x(a).mtimeMs;e>n&&(n=e)}catch{}}}return n}const ot=2e3;function st(e){let t=h(e.cwd,`.kickjs`,`types`);if(!v(t))return null;let n=at(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 ct=[`vitest.config.ts`,`vitest.config.js`,`vitest.config.mts`,`vite.config.ts`,`jest.config.ts`,`jest.config.js`],lt=[`.env.test`,`.env.test.local`],ut=[`.env`,`.env.local`];function dt(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 ft(e){if(!ct.some(t=>v(h(e.cwd,t))))return null;let t=ut.filter(t=>v(h(e.cwd,t)));if(t.length===0)return null;let n=lt.filter(t=>v(h(e.cwd,t)));if(n.length>0){let t=dt(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
1170
1181
  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
1171
1182
  development env — including DATABASE_URL and any third-party credentials.
1172
1183
 
1173
1184
  Create .env.test (cp .env.test.example .env.test, if the project has one)
1174
1185
  holding the whole environment the suite should run against
1175
1186
  (a var you leave out is then missing, not inherited), or set KICKJS_ENV_FILE=off
1176
- and supply env from the test runner.`}}const pt=[()=>Je(),Ye,Xe,Qe,et,nt,rt,it,ft,st];async function mt(e,t={}){let n={cwd:e,pkg:Ue(h(e,`package.json`)),tsconfig:Ge(e),runtime:t.runtime??`express`},r=[...pt,...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 ht(e){switch(e){case`pass`:return s.green(`✔`);case`warn`:return s.yellow(`⚠`);case`fail`:return s.red(`✖`)}}function gt(e){let t=ht(e.status),n=e.message?` ${s.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function _t(e){return e.split(`
1177
- `).map(e=>` ${s.dim(`→`)} ${e}`).join(`
1178
- `)}function vt(e){return e?.doctor?.checks??[]}function yt(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=vt(await c(e)),n=await l(e);i(`KickJS Doctor`);let o=await mt(e,{extraChecks:t,runtime:n});for(let e of o)a.message(gt(e)),e.fix&&e.status!==`pass`&&a.message(_t(e.fix));let u=o.filter(e=>e.status===`pass`).length,d=o.filter(e=>e.status===`warn`).length,f=o.filter(e=>e.status===`fail`).length,p=[s.green(`${u} passed`),d>0?s.yellow(`${d} warning${d===1?``:`s`}`):`${d} warnings`,f>0?s.red(`${f} error${f===1?``:`s`}`):`${f} errors`].join(`, `);f>0?(r(`${p} — fix the errors above before running the app`),process.exit(1)):r(d>0?`${p} — review the warnings`:s.green(`${p} — your environment looks good`))})}export{A,ge as C,I as D,L as E,T as F,k as M,E as N,N as O,D as P,V as S,R as T,xe as _,Re as a,W as b,Ae as c,Oe as d,Ee as f,Se as g,Ce as h,ze as i,O as j,M as k,je as l,we as m,Ve as n,K as o,Te as p,yt as r,ee as s,He as t,De as u,G as v,he as w,z as x,ye as y};
1179
- //# sourceMappingURL=doctor-rEbeoAoO.mjs.map
1187
+ and supply env from the test runner.`}}const pt=[()=>Je(),Ye,Xe,Qe,et,nt,rt,it,ft,st];async function mt(e,t={}){let n={cwd:e,pkg:Ue(h(e,`package.json`)),tsconfig:Ge(e),runtime:t.runtime??`express`},r=[...pt,...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 ht(e){switch(e){case`pass`:return o.green(`✔`);case`warn`:return o.yellow(`⚠`);case`fail`:return o.red(`✖`)}}function gt(e){let t=ht(e.status),n=e.message?` ${o.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function _t(e){return e.split(`
1188
+ `).map(e=>` ${o.dim(`→`)} ${e}`).join(`
1189
+ `)}function vt(e){return e?.doctor?.checks??[]}function yt(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),r=vt(await c(e)),i=await l(e);t(`KickJS Doctor`);let s=await mt(e,{extraChecks:r,runtime:i});for(let e of s)a.message(gt(e)),e.fix&&e.status!==`pass`&&a.message(_t(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{A,ge as C,I as D,L as E,T as F,k as M,E as N,N as O,D as P,V as S,R as T,xe as _,Re as a,W as b,Ae as c,Oe as d,Ee as f,Se as g,Ce as h,ze as i,O as j,M as k,je as l,we as m,Ve as n,K as o,Te as p,yt as r,ee as s,He as t,De as u,G as v,he as w,z as x,ye as y};
1190
+ //# sourceMappingURL=doctor-D0uazKD7.mjs.map