@forinda/kickjs-cli 8.1.4 → 8.1.6
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.
- package/dist/{agent-docs-mWvpx5Qu.mjs → agent-docs-BBlVl1tY.mjs} +2 -2
- package/dist/{agent-docs-BKRxQ-Xq.mjs → agent-docs-CW5TQHti.mjs} +3 -3
- package/dist/{agent-docs-BKRxQ-Xq.mjs.map → agent-docs-CW5TQHti.mjs.map} +1 -1
- package/dist/{build-CXodASTD.mjs → build-DOI_zYDS.mjs} +3 -3
- package/dist/{build-CXodASTD.mjs.map → build-DOI_zYDS.mjs.map} +1 -1
- package/dist/{build-DYUzQOv-.mjs → build-htBdOg51.mjs} +2 -2
- package/dist/{builtins-CfAj3weS.mjs → builtins-Cj4BWpIe.mjs} +2 -2
- package/dist/{builtins-BK3dXr6F.mjs → builtins-SMK1mtlk.mjs} +232 -135
- package/dist/cli.mjs +2 -2
- package/dist/config-BYSNxf_t.mjs +12 -0
- package/dist/config-DST3ilXt.mjs +13 -0
- package/dist/{config-CnsdWRi-.mjs.map → config-DST3ilXt.mjs.map} +1 -1
- package/dist/{doctor-DhFt6Dql.mjs → doctor-CJYTXARe.mjs} +53 -52
- package/dist/doctor-CJYTXARe.mjs.map +1 -0
- package/dist/{fullstack-CfVMOuwT.mjs → fullstack-19gafr4U.mjs} +3 -3
- package/dist/{fullstack-cs8K7UKU.mjs → fullstack-Mkw3lkF1.mjs} +4 -4
- package/dist/{fullstack-cs8K7UKU.mjs.map → fullstack-Mkw3lkF1.mjs.map} +1 -1
- package/dist/index.d.mts +11 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{plugin-DBq3YOeu.mjs → plugin-Cfiz2G3K.mjs} +3 -3
- package/dist/{plugin-DBq3YOeu.mjs.map → plugin-Cfiz2G3K.mjs.map} +1 -1
- package/dist/{plugin-Bx-oLIvD.mjs → plugin-IEDGa0ny.mjs} +2 -2
- package/dist/{project-BrgyBfwX.mjs → project-5ljMCm0U.mjs} +5 -5
- package/dist/{project-tpDcE3gD.mjs → project-CAamSqrL.mjs} +6 -6
- package/dist/project-CAamSqrL.mjs.map +1 -0
- package/dist/{project-docs-D1hQZj7V.mjs → project-docs-CYCi7cHt.mjs} +2 -2
- package/dist/{project-docs-D3XB21OH.mjs → project-docs-at2gZlUE.mjs} +3 -3
- package/dist/{project-docs-D3XB21OH.mjs.map → project-docs-at2gZlUE.mjs.map} +1 -1
- package/dist/{project-root-8AbFL3Bz.mjs → project-root-BhBKSGeK.mjs} +2 -2
- package/dist/{project-root-BfJnDb6v.mjs → project-root-PMRCA_2T.mjs} +3 -3
- package/dist/{project-root-BfJnDb6v.mjs.map → project-root-PMRCA_2T.mjs.map} +1 -1
- package/dist/{prompts-BhN0QhO9.mjs → prompts-BxPTyuY3.mjs} +2 -2
- package/dist/{prompts-BhN0QhO9.mjs.map → prompts-BxPTyuY3.mjs.map} +1 -1
- package/dist/{rolldown-runtime-CiCyGOpK.mjs → rolldown-runtime-D-i_dFAb.mjs} +1 -1
- package/dist/{run-plugins-DMJnttf2.mjs → run-plugins-GxEtP9WR.mjs} +176 -80
- package/dist/run-plugins-GxEtP9WR.mjs.map +1 -0
- package/dist/{typegen-i3dMJl9r.mjs → typegen-CJvd5MEz.mjs} +5 -5
- package/dist/{typegen-i3dMJl9r.mjs.map → typegen-CJvd5MEz.mjs.map} +1 -1
- package/dist/{typegen-CvxsKt2a.mjs → typegen-D7aeVM0D.mjs} +4 -4
- package/dist/{types-rB3GOMNT.mjs → types-PxKCj-JF.mjs} +1 -1
- package/package.json +3 -3
- package/dist/config-CN5jLEsN.mjs +0 -12
- package/dist/config-CnsdWRi-.mjs +0 -13
- package/dist/doctor-DhFt6Dql.mjs.map +0 -1
- package/dist/project-tpDcE3gD.mjs.map +0 -1
- package/dist/run-plugins-DMJnttf2.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.1.
|
|
2
|
+
* @forinda/kickjs-cli v8.1.6
|
|
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-
|
|
11
|
+
import{l as e,s as t}from"./project-docs-at2gZlUE.mjs";import{a as n,n as r,r as i,t as a,u as o}from"./prompts-BxPTyuY3.mjs";import{i as s,s as c}from"./project-CAamSqrL.mjs";import{o as l}from"./config-DST3ilXt.mjs";import{t as u}from"./project-root-PMRCA_2T.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 ${
|
|
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
|
|
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
|
|
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
|
-
`}
|
|
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 —
|
|
205
|
-
* This schema is passed to @Post('/', { body:
|
|
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
|
|
209
|
-
|
|
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
|
|
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 =
|
|
217
|
-
`}function
|
|
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
|
|
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 =
|
|
224
|
-
`}function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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=
|
|
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${
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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=
|
|
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 ${
|
|
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
|
-
* ${
|
|
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: ${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
955
|
-
`),
|
|
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
|
|
957
|
-
Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function
|
|
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-CJvd5MEz.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await import(`./run-plugins-GxEtP9WR.mjs`)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-CJvd5MEz.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-DOI_zYDS.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
|
|
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
|
|
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
|
|
971
|
-
//# sourceMappingURL=doctor-
|
|
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-CJYTXARe.mjs.map
|