@forinda/kickjs-cli 6.2.2 → 6.3.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.
- package/dist/{agent-docs-DLRxp4T-.mjs → agent-docs-DrGK8taL.mjs} +3 -3
- package/dist/{agent-docs-DLRxp4T-.mjs.map → agent-docs-DrGK8taL.mjs.map} +1 -1
- package/dist/{build-CDoZ8_rP.mjs → build-BP3bAsWN.mjs} +3 -3
- package/dist/{build-CDoZ8_rP.mjs.map → build-BP3bAsWN.mjs.map} +1 -1
- package/dist/{builtins-BVkOvAez.mjs → builtins-DBoirqjH.mjs} +2 -2
- package/dist/cli.mjs +144 -139
- package/dist/{config-DRa14hGi.mjs → config-BCGU5sEB.mjs} +3 -3
- package/dist/{config-DRa14hGi.mjs.map → config-BCGU5sEB.mjs.map} +1 -1
- package/dist/{doctor-Dn8TOdKx.mjs → doctor-CyW4lHWm.mjs} +13 -8
- package/dist/doctor-CyW4lHWm.mjs.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{plugin-Bl8ngv-D.mjs → plugin-D5VBchsh.mjs} +3 -3
- package/dist/{plugin-Bl8ngv-D.mjs.map → plugin-D5VBchsh.mjs.map} +1 -1
- package/dist/{project-docs-Dxq236Ke.mjs → project-docs-BC9IeqGg.mjs} +3 -3
- package/dist/{project-docs-Dxq236Ke.mjs.map → project-docs-BC9IeqGg.mjs.map} +1 -1
- package/dist/{project-root-BISuVB2p.mjs → project-root-By_tYe1R.mjs} +3 -3
- package/dist/{project-root-BISuVB2p.mjs.map → project-root-By_tYe1R.mjs.map} +1 -1
- package/dist/{rolldown-runtime-Cppk8mNq.mjs → rolldown-runtime-CxXPTOrW.mjs} +1 -1
- package/dist/{run-plugins-D5ltWD8e.mjs → run-plugins-DEn7gHVu.mjs} +5 -5
- package/dist/{run-plugins-D5ltWD8e.mjs.map → run-plugins-DEn7gHVu.mjs.map} +1 -1
- package/dist/typegen-C5ZXwZZv.mjs +114 -0
- package/dist/typegen-C5ZXwZZv.mjs.map +1 -0
- package/dist/{types-shx0Uu7e.mjs → types-5S0Va4VP.mjs} +1 -1
- package/package.json +4 -4
- package/dist/doctor-Dn8TOdKx.mjs.map +0 -1
- package/dist/typegen-DymwIHGr.mjs +0 -114
- package/dist/typegen-DymwIHGr.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v6.
|
|
2
|
+
* @forinda/kickjs-cli v6.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{createRequire as e}from"node:module";import{Command as t}from"commander";import{cpSync as n,existsSync as r,mkdirSync as i,readFileSync as a,readdirSync as o,rmSync as s,statSync as c,writeFileSync as l}from"node:fs";import u,{basename as d,dirname as f,extname as p,isAbsolute as m,join as h,parse as g,relative as _,resolve as v,sep as y}from"node:path";import{fileURLToPath as b,pathToFileURL as x}from"node:url";import{execFileSync as
|
|
12
|
-
`,`utf-8`)}catch{}}function
|
|
11
|
+
import{createRequire as e}from"node:module";import{Command as t}from"commander";import{cpSync as n,existsSync as r,mkdirSync as i,readFileSync as a,readdirSync as o,rmSync as s,statSync as c,writeFileSync as l}from"node:fs";import u,{basename as d,dirname as f,extname as p,isAbsolute as m,join as h,parse as g,relative as _,resolve as v,sep as y}from"node:path";import{fileURLToPath as b,pathToFileURL as x}from"node:url";import{execFileSync as S,execSync as C,fork as ee,spawn as te,spawnSync as ne}from"node:child_process";import{access as re,copyFile as ie,mkdir as w,readFile as T,readdir as ae,rm as oe,stat as se,unlink as ce,writeFile as E}from"node:fs/promises";import{KickPluginConflictError as le,defineCliPlugin as D}from"@forinda/kickjs-cli-kit";import*as O from"@clack/prompts";import k from"picocolors";import ue from"pluralize";import{parseSync as de}from"oxc-parser";import{glob as fe,globSync as pe}from"glob";import{groupAssetKeys as me}from"@forinda/kickjs";import{arch as he,platform as ge,release as _e}from"node:os";var ve=Object.defineProperty,A=(e,t)=>{let n={};for(var r in e)ve(n,r,{get:e[r],enumerable:!0});return t||ve(n,Symbol.toStringTag,{value:`Module`}),n};function ye(e,t,n){C(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function be(e,t,n){let r=ne(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}function xe(e,t){if(!t?.commands?.length)return;let n=new Set(e.commands.map(e=>e.name()));for(let r of t.commands){if(n.has(r.name)){console.warn(` Warning: custom command '${r.name}' skipped — conflicts with a built-in command`);continue}Se(e,r)}}function Se(e,t){let n=e.command(t.name).description(t.description);if(t.aliases)for(let e of t.aliases)n.alias(e);n.allowUnknownOption(!0),n.argument(`[args...]`,`Additional arguments passed to the command`),n.action(e=>{let n=e.join(` `),r=Array.isArray(t.steps)?t.steps:[t.steps];for(let e of r){let r=n?`${e} ${n}`:e;console.log(` $ ${r}`);try{ye(r)}catch{console.error(` Command failed: ${t.name}`),process.exitCode=1;return}}})}var Ce=A({BUILTIN_REPO_TYPES:()=>Te,DEPRECATED_REPO_TYPES:()=>Ee,PACKAGE_MANAGERS:()=>we,defineConfig:()=>Oe,loadKickConfig:()=>M,resolveModuleConfig:()=>j,resolveTokenScope:()=>ke,validateAssetMap:()=>Ne,warnIfDeprecatedRepo:()=>De,writeAssetConfigSnapshot:()=>Me});const we=[`pnpm`,`npm`,`yarn`,`bun`],Te=[`inmemory`],Ee=[`prisma`,`drizzle`];function De(e){return Ee.includes(e)?(console.warn(` Note: the '${e}' repository preset is deprecated. Generating a generic custom repository named '${e}' instead — wire it to your DB by hand. Pass any name via \`--repo <name>\` or \`modules.repo: { name: '<name>' }\`.`),!0):!1}function Oe(e){return e}function ke(e,t){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=Ae(e.tokenScope);if(t.length>0)return t}try{let e=h(t,`package.json`);if(r(e)){let t=JSON.parse(a(e,`utf-8`));if(typeof t.name==`string`&&t.name.length>0){let e=t.name.match(/^@([^/]+)\//),n=Ae(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function Ae(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function j(e){if(!e)return{};let t={dir:e.modules?.dir,repo:e.modules?.repo,schemaDir:e.modules?.schemaDir,pluralize:e.modules?.pluralize,prismaClientPath:e.modules?.prismaClientPath,style:e.modules?.style};return t.style!==void 0&&t.style!==`define`&&t.style!==`class`&&(console.warn(` Warning: modules.style '${t.style}' is not a valid value (expected 'define' or 'class'). Falling back to 'define'.`),t.style=`define`),t.repo&&typeof t.repo==`string`&&!Te.includes(t.repo)&&(De(t.repo)||console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${Te.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`)),t}const je=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function M(e){let{findProjectRoot:t}=await Promise.resolve().then(()=>tn),n=t(e);for(let e of je){let t=h(n,e);try{await re(t)}catch{continue}if(e.endsWith(`.json`)){let e=await T(t,`utf-8`);return JSON.parse(e)}if(e.endsWith(`.ts`)){let r;try{r=await import(`jiti`)}catch(t){let n=t instanceof Error?t.message:String(t);n.includes(`Cannot find package 'jiti'`)||n.includes(`ERR_MODULE_NOT_FOUND`)?console.warn(`Warning: Failed to load ${e} — 'jiti' is required for TypeScript configs. Run \`pnpm add -D jiti\` (or your package manager's equivalent), or rename the file to kick.config.js / kick.config.mjs / kick.config.json.`):console.warn(`Warning: Failed to initialize jiti for ${e}: ${n}`);continue}try{let e=await r.createJiti(n,{interopDefault:!0,fsCache:!1}).import(t,{default:!0}),i=Ne(e,n);for(let e of i)console.warn(` Warning: ${e}`);return Me(n,e),e}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`Warning: Failed to load ${e}: ${n}`);continue}}try{let{pathToFileURL:e}=await import(`node:url`),r=await import(e(t).href),i=r.default??r,a=Ne(i,n);for(let e of a)console.warn(` Warning: ${e}`);return Me(n,i),i}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`Warning: Failed to load ${e}: ${n}`);continue}}return null}function Me(e,t){if(!(!t?.assetMap||Object.keys(t.assetMap).length===0))try{let n=h(e,`.kickjs`);i(n,{recursive:!0});let r={version:1,assetMap:t.assetMap,...t.build?.outDir?{build:{outDir:t.build.outDir}}:{}};l(h(n,`kick.config.json`),JSON.stringify(r,null,2)+`
|
|
12
|
+
`,`utf-8`)}catch{}}function Ne(e,t){let n=[];if(!e?.assetMap)return n;let i=v(t);for(let[a,o]of Object.entries(e.assetMap)){if(!a||a.includes(`/`)){n.push(`assetMap key '${a}' is invalid — must be a non-empty string without '/'`);continue}if(typeof o?.src!=`string`||o.src.length===0){n.push(`assetMap.${a} is missing a non-empty 'src' field`);continue}r(v(t,o.src))||n.push(`assetMap.${a}.src ('${o.src}') does not exist — typegen + build will fail`),o.dest&&Pe(v(t,o.dest),i)&&n.push(`assetMap.${a}.dest ('${o.dest}') resolves outside the project root — refusing to copy`)}return n}function Pe(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function Fe(e,t=[]){let n=new Map;for(let t of e){let e=(n.get(t.name)??0)+1;if(n.set(t.name,e),e===2)throw new le(`plugin`,t.name,[t.name,t.name])}let r=new Map,i=[];for(let t of e)for(let e of t.commands??[]){let n=r.get(e.name);if(n)throw new le(`command`,e.name,[n,t.name]);r.set(e.name,t.name),i.push(e)}let a=new Set(t.map(e=>e.name)),o=[...i.filter(e=>!a.has(e.name)),...t],s=new Map,c=[];for(let t of e)for(let e of t.typegens??[]){let n=s.get(e.id);if(n)throw new le(`typegen`,e.id,[n,t.name]);s.set(e.id,t.name),c.push(e)}let l=new Map,u=[];for(let t of e)for(let e of t.generators??[]){let n=l.get(e.name);if(n)throw new le(`generator`,e.name,[n,t.name]);l.set(e.name,t.name),u.push({source:t.name,spec:e})}return{commands:o,typegens:c,generators:u,register:async(t,n)=>{let r;if(n)r={generators:u,...n};else{let{findProjectRoot:e}=await Promise.resolve().then(()=>tn),t=process.cwd();r={cwd:t,projectRoot:e(t),config:null,log:()=>{},generators:u}}for(let n of e)n.register&&await n.register(t,r)}}}var Ie=A({mergeCliPlugins:()=>Fe});let Le=!1;function N(e){Le=e}const Re=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function P(e,t){Le||(await w(f(e),{recursive:!0}),await E(e,t,`utf-8`),Re.has(p(e))&&await Ve(e,t).catch(()=>{}))}let ze;async function Be(t){if(ze!==void 0)return ze;try{ze=await import(e(h(t,`package.json`)).resolve(`oxfmt`))}catch{ze=null}return ze}async function Ve(e,t){let n=await Be(process.cwd());if(!n)return;let r=await Ue(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await E(e,i.code,`utf-8`)}const He=new Map;async function Ue(e){let t=f(e),n=t;if(He.has(n))return He.get(n);for(;;){let e=h(t,`.oxfmtrc.json`);if(r(e))try{let t=await T(e,`utf-8`),r=JSON.parse(t);return delete r.$schema,delete r.ignorePatterns,He.set(n,r),r}catch{return He.set(n,null),null}let i=f(t);if(i===t)return He.set(n,null),null;t=i}}async function We(e){try{return await re(e),!0}catch{return!1}}const Ge={swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`},Ke={zod:{name:`zod`,range:`^4.3.6`},valibot:{name:`valibot`,range:`^1.4.1`},yup:{name:`yup`,range:`^1.7.1`}};function qe(e,t){let n=e[t];if(!n)throw Error(`generatePackageJson: missing resolved version for ${t}. Add it to SIBLING_PACKAGES in generators/project.ts.`);return n}function Je(e,t,n,r=[],i=`zod`,a=`express`){let o=Ke[i],s={"@forinda/kickjs":qe(n,`@forinda/kickjs`),"@forinda/kickjs-schema":qe(n,`@forinda/kickjs-schema`),dotenv:`^17.3.1`,"reflect-metadata":`^0.2.2`,[o.name]:o.range};a===`express`?s.express=`^5.1.0`:a===`fastify`?(s.fastify=`^5.0.0`,s[`@fastify/middie`]=`^9.0.0`,s[`serve-static`]=`^2.2.0`):a===`h3`&&(s.h3=`^1.0.0`,s[`serve-static`]=`^2.2.0`);for(let e of r){let t=Ge[e];t&&!s[t]&&(s[t]=qe(n,t))}return JSON.stringify({name:e,version:`0.0.0`,type:`module`,scripts:{dev:`kick dev`,"dev:debug":`kick dev:debug`,build:`kick build`,start:`kick start`,test:`vitest run`,"test:watch":`vitest`,typecheck:`tsc --noEmit`,typegen:`kick typegen`,lint:`eslint src/`,format:`prettier --write src/`},dependencies:s,devDependencies:{"@forinda/kickjs-cli":qe(n,`@forinda/kickjs-cli`),"@forinda/kickjs-vite":qe(n,`@forinda/kickjs-vite`),"@swc/core":`^1.15.21`,...a===`express`?{"@types/express":`^5.0.6`}:{},"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^6.0.3`,prettier:`^3.8.1`}},null,2)}function Ye(){return`import { defineConfig } from 'vite'
|
|
13
13
|
import { resolve } from 'node:path'
|
|
14
14
|
import swc from 'unplugin-swc'
|
|
15
15
|
import { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'
|
|
@@ -39,7 +39,7 @@ export default defineConfig({
|
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
})
|
|
42
|
-
`}function
|
|
42
|
+
`}function Xe(){return JSON.stringify({compilerOptions:{target:`ES2022`,module:`ESNext`,moduleResolution:`bundler`,lib:[`ES2022`],types:[`node`,`vite/client`],strict:!0,esModuleInterop:!0,skipLibCheck:!0,sourceMap:!0,declaration:!0,experimentalDecorators:!0,emitDecoratorMetadata:!0,outDir:`dist`,paths:{"@/*":[`./src/*`]}},include:[`src`,`.kickjs/types/**/*.d.ts`,`.kickjs/types/**/*.ts`]},null,2)}function Ze(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function Qe(){return`# https://editorconfig.org
|
|
43
43
|
root = true
|
|
44
44
|
|
|
45
45
|
[*]
|
|
@@ -52,14 +52,14 @@ insert_final_newline = true
|
|
|
52
52
|
|
|
53
53
|
[*.md]
|
|
54
54
|
trim_trailing_whitespace = false
|
|
55
|
-
`}function
|
|
55
|
+
`}function $e(){return`node_modules/
|
|
56
56
|
dist/
|
|
57
57
|
.env
|
|
58
58
|
coverage/
|
|
59
59
|
.DS_Store
|
|
60
60
|
*.tsbuildinfo
|
|
61
61
|
.kickjs/
|
|
62
|
-
`}function
|
|
62
|
+
`}function et(){return`# Auto-detect text files and normalise line endings to LF
|
|
63
63
|
* text=auto eol=lf
|
|
64
64
|
|
|
65
65
|
# Explicitly mark generated / binary files
|
|
@@ -77,11 +77,11 @@ coverage/
|
|
|
77
77
|
pnpm-lock.yaml -diff linguist-generated
|
|
78
78
|
yarn.lock -diff linguist-generated
|
|
79
79
|
package-lock.json -diff linguist-generated
|
|
80
|
-
`}function
|
|
80
|
+
`}function tt(){return`PORT=3000
|
|
81
81
|
NODE_ENV=development
|
|
82
|
-
`}function
|
|
82
|
+
`}function nt(){return`PORT=3000
|
|
83
83
|
NODE_ENV=development
|
|
84
|
-
`}function
|
|
84
|
+
`}function rt(){return`import { defineConfig } from 'vitest/config'
|
|
85
85
|
import swc from 'unplugin-swc'
|
|
86
86
|
|
|
87
87
|
export default defineConfig({
|
|
@@ -92,7 +92,7 @@ export default defineConfig({
|
|
|
92
92
|
include: ['src/**/*.test.ts'],
|
|
93
93
|
},
|
|
94
94
|
})
|
|
95
|
-
`}const
|
|
95
|
+
`}const it={express:{from:`@forinda/kickjs`,name:`expressRuntime`},fastify:{from:`@forinda/kickjs/fastify`,name:`fastifyRuntime`},h3:{from:`@forinda/kickjs/h3`,name:`h3Runtime`}};function at(e,t,n,r=[],i=`express`){let a=it[i],o=i===`express`;switch(t){case`minimal`:{let t=[],i=[],s=o?`import { bootstrap, ${a.name} } from '@forinda/kickjs'`:`import { bootstrap } from '@forinda/kickjs'\nimport { ${a.name} } from '${a.from}'`;r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({ info: { title: '${e}', version: '${n}' } }),`)),r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`));let c=t.length?t.join(`
|
|
96
96
|
`)+`
|
|
97
97
|
`:``,l=i.length?`,\n adapters: [\n${i.join(`
|
|
98
98
|
`)}\n ]`:``;return`import 'reflect-metadata'
|
|
@@ -132,14 +132,14 @@ export const app = await bootstrap({
|
|
|
132
132
|
requestLogger(),${d}
|
|
133
133
|
],
|
|
134
134
|
})
|
|
135
|
-
`}}}function
|
|
135
|
+
`}}}function ot(){return`import { defineModules } from '@forinda/kickjs'
|
|
136
136
|
import { HelloModule } from './hello/hello.module'
|
|
137
137
|
|
|
138
138
|
// Remove HelloModule and run: kick g module <name>
|
|
139
139
|
// \`defineModules()\` returns a chainable list — \`kick g module\` appends
|
|
140
140
|
// \`.mount(NewModule())\` to the chain on every generation.
|
|
141
141
|
export const modules = defineModules().mount(HelloModule())
|
|
142
|
-
`}function
|
|
142
|
+
`}function st(e=`zod`){return e===`valibot`?`import { loadEnvFromSchema } from '@forinda/kickjs/config'
|
|
143
143
|
import { fromValibot } from '@forinda/kickjs-schema/valibot'
|
|
144
144
|
import * as v from 'valibot'
|
|
145
145
|
|
|
@@ -267,7 +267,7 @@ const envSchema = fromZod(
|
|
|
267
267
|
export const env = loadEnvFromSchema(envSchema)
|
|
268
268
|
|
|
269
269
|
export default envSchema
|
|
270
|
-
`}function
|
|
270
|
+
`}function ct(){return`import { Service } from '@forinda/kickjs'
|
|
271
271
|
|
|
272
272
|
@Service()
|
|
273
273
|
export class HelloService {
|
|
@@ -279,7 +279,7 @@ export class HelloService {
|
|
|
279
279
|
return { status: 'ok', uptime: process.uptime() }
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
|
-
`}function
|
|
282
|
+
`}function lt(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
|
|
283
283
|
import { HelloService } from './hello.service'
|
|
284
284
|
|
|
285
285
|
// \`Ctx<KickRoutes.HelloController['<method>']>\` is generated by
|
|
@@ -301,7 +301,7 @@ export class HelloController {
|
|
|
301
301
|
ctx.json(this.helloService.healthCheck())
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
|
-
`}function
|
|
304
|
+
`}function ut(){return`import { defineModule } from '@forinda/kickjs'
|
|
305
305
|
import { HelloController } from './hello.controller'
|
|
306
306
|
|
|
307
307
|
export const HelloModule = defineModule({
|
|
@@ -322,7 +322,7 @@ export const HelloModule = defineModule({
|
|
|
322
322
|
},
|
|
323
323
|
}),
|
|
324
324
|
})
|
|
325
|
-
`}function
|
|
325
|
+
`}function dt(e,t=`inmemory`,n=`pnpm`,r=`express`){return`import { defineConfig } from '@forinda/kickjs-cli'
|
|
326
326
|
|
|
327
327
|
export default defineConfig({
|
|
328
328
|
pattern: '${e}',
|
|
@@ -374,7 +374,7 @@ export default defineConfig({
|
|
|
374
374
|
},
|
|
375
375
|
],
|
|
376
376
|
})
|
|
377
|
-
`}function
|
|
377
|
+
`}function ft(e,t,n){let r={rest:`REST API`,ddd:`Domain-Driven Design`,cqrs:`CQRS + Event-Driven`,minimal:`Minimal`},i=[`@forinda/kickjs`,`@forinda/kickjs-vite`];return t!==`minimal`&&i.push(`@forinda/kickjs-swagger`,`@forinda/kickjs-devtools`),`# ${e}
|
|
378
378
|
|
|
379
379
|
A **${r[t]??`REST API`}** built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework for TypeScript that runs on Express, Fastify, or h3 (swap the engine in one line).
|
|
380
380
|
|
|
@@ -437,7 +437,7 @@ Copy \`.env.example\` to \`.env\` and configure:
|
|
|
437
437
|
|
|
438
438
|
- [KickJS Documentation](https://forinda.github.io/kick-js/)
|
|
439
439
|
- [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
|
|
440
|
-
`}function
|
|
440
|
+
`}function pt(e,t,n){return`# CLAUDE.md — ${e}
|
|
441
441
|
|
|
442
442
|
**Read \`./.agents/AGENTS.md\` first.** It is the canonical, multi-agent
|
|
443
443
|
reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
|
|
@@ -512,7 +512,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
|
|
|
512
512
|
- **Refresh these files**: \`kick g agents -f\` regenerates \`CLAUDE.md\` at the project root and \`.agents/AGENTS.md\` + \`.agents/GEMINI.md\` + \`.agents/COPILOT.md\` + every \`.agents/skills/<name>/SKILL.md\` from the latest CLI templates. Hand-edited content is overwritten — keep customisation in \`.agents/AGENTS.local.md\` or per-skill \`SKILL.local.md\` files alongside.
|
|
513
513
|
|
|
514
514
|
For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`.agents/AGENTS.md\`.
|
|
515
|
-
`}function
|
|
515
|
+
`}function mt(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
|
|
516
516
|
|
|
517
517
|
This guide is the **canonical, multi-agent reference** for this KickJS
|
|
518
518
|
application — Claude, Copilot, Codex, Gemini, etc. all read it first.
|
|
@@ -1027,7 +1027,7 @@ Full guide: <https://forinda.github.io/kick-js/guide/context-decorators>.
|
|
|
1027
1027
|
- [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
|
|
1028
1028
|
- [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
|
|
1029
1029
|
- [Testing](https://forinda.github.io/kick-js/api/testing.html)
|
|
1030
|
-
`}function
|
|
1030
|
+
`}function ht(e,t,n){let r=`<!-- Generated by \`kick g agents\` for ${e}. Edits are overwritten on the next refresh; keep customisation in a SKILL.local.md alongside. -->`;return[{slug:`add-module`,frontmatterName:`kickjs-add-module`,description:`Use when the user asks to add a new feature module (controller + service + repo + DTOs).`,body:`**Trigger phrases**: "add a users module", "scaffold tasks", "new feature for X".
|
|
1031
1031
|
|
|
1032
1032
|
**Steps**:
|
|
1033
1033
|
1. Run \`kick g module <name>\` (use plural form if the project pluralizes — check \`kick.config.ts\`).
|
|
@@ -1052,7 +1052,7 @@ export const TodosModule = defineModule({
|
|
|
1052
1052
|
})
|
|
1053
1053
|
\`\`\`
|
|
1054
1054
|
|
|
1055
|
-
The module file MUST include \`import.meta.glob([...], { eager: true })\` for every \`@Service\` / \`@Repository\` / \`@Component\` class — without it, decorators never fire and DI silently resolves to \`undefined
|
|
1055
|
+
The module file MUST include \`import.meta.glob([...], { eager: true })\` for every \`@Controller\` / \`@Service\` / \`@Repository\` / \`@Component\` class — without it, decorators never fire and DI silently resolves to \`undefined\` (or routes vanish). Use **recursive** patterns (\`./**/*.controller.ts\`) so the glob keeps working when you nest files into sub-folders (\`controllers/\`, \`presentation/\`, …). If you reorganise and a class stops loading, \`kick typegen\` flags it as orphaned and \`kick typegen --fix\` patches the glob for you.
|
|
1056
1056
|
|
|
1057
1057
|
**Multiple route sets / versioning** — \`routes()\` may return an array with per-entry \`version\` override:
|
|
1058
1058
|
|
|
@@ -1162,7 +1162,7 @@ description: ${e.description}
|
|
|
1162
1162
|
${r}
|
|
1163
1163
|
|
|
1164
1164
|
${e.body}
|
|
1165
|
-
`}))}function
|
|
1165
|
+
`}))}function gt(e,t,n){return`# GEMINI.md — ${e}
|
|
1166
1166
|
|
|
1167
1167
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
1168
1168
|
reference for this project — every convention, structure, decorator
|
|
@@ -1196,7 +1196,7 @@ without us copy-pasting.
|
|
|
1196
1196
|
\`kick g agents --only gemini -f\` regenerates this file from the
|
|
1197
1197
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
1198
1198
|
in \`.agents/GEMINI.local.md\`.
|
|
1199
|
-
`}function
|
|
1199
|
+
`}function _t(e,t,n){return`# COPILOT.md — ${e}
|
|
1200
1200
|
|
|
1201
1201
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
1202
1202
|
reference for this project — every convention, structure, decorator
|
|
@@ -1229,16 +1229,16 @@ Codex / Cursor / Gemini / Claude Code without copy-pasting.
|
|
|
1229
1229
|
\`kick g agents --only copilot -f\` regenerates this file from the
|
|
1230
1230
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
1231
1231
|
in \`.agents/COPILOT.local.md\`.
|
|
1232
|
-
`}const
|
|
1232
|
+
`}const vt={kickjs:{pkg:`@forinda/kickjs`,peers:[`express`],description:`Unified framework: DI, decorators, routing, middleware`,core:!0},vite:{pkg:`@forinda/kickjs-vite`,peers:[`vite`],description:`Vite plugin: dev server, HMR, module discovery`,dev:!0,core:!0},cli:{pkg:`@forinda/kickjs-cli`,peers:[],description:`CLI tool and code generators`,dev:!0,core:!0},zod:{pkg:`zod`,peers:[],description:`Zod schema validation (env, DTOs, OpenAPI) — wrap with fromZod()`},valibot:{pkg:`valibot`,peers:[],description:`Valibot schema validation — wrap with fromValibot()`},yup:{pkg:`yup`,peers:[],description:`Yup schema validation — wrap with fromYup()`},auth:{pkg:`@forinda/kickjs-auth`,peers:[`jsonwebtoken`],description:`JWT, API key, OAuth strategies, @Public, @Roles (+ optional argon2/bcryptjs)`,deprecated:`auth is moving to BYO — compose @LoadAuthUser/@RequireRole/@Public from defineContextDecorator (see the BYO Auth recipe in the docs)`},ai:{pkg:`@forinda/kickjs-ai`,peers:[`zod`],description:`AI toolkit — LLM providers, tool definitions from controllers`},swagger:{pkg:`@forinda/kickjs-swagger`,peers:[],description:`OpenAPI spec + Swagger UI + ReDoc`},db:{pkg:`@forinda/kickjs-db`,peers:[],description:`kick/db core — schema DSL, migrations, KickDbClient, customType`},pg:{pkg:`@forinda/kickjs-db`,peers:[`pg`],description:`kick/db + PostgreSQL driver (use @forinda/kickjs-db/pg)`},sqlite:{pkg:`@forinda/kickjs-db`,peers:[`better-sqlite3`],description:`kick/db + SQLite driver (use @forinda/kickjs-db/sqlite)`},mysql:{pkg:`@forinda/kickjs-db`,peers:[`mysql2`],description:`kick/db + MySQL driver (use @forinda/kickjs-db/mysql)`},drizzle:{pkg:`@forinda/kickjs-drizzle`,peers:[`drizzle-orm`],description:`Drizzle ORM adapter + query builder`,deprecated:"early-adoption adapter, no longer maintained — wire Drizzle directly (BYO), or use @forinda/kickjs-db, the built-in Kick ORM (`kick add db` / pg / sqlite / mysql)"},prisma:{pkg:`@forinda/kickjs-prisma`,peers:[`@prisma/client`],description:`Prisma adapter + query builder`,deprecated:"early-adoption adapter, no longer maintained — wire Prisma directly (BYO), or use @forinda/kickjs-db, the built-in Kick ORM (`kick add db` / pg / sqlite / mysql)"},ws:{pkg:`@forinda/kickjs-ws`,peers:[`ws`],description:`WebSocket with @WsController decorators`},devtools:{pkg:`@forinda/kickjs-devtools`,peers:[],description:`Development dashboard — routes, DI, metrics, health`,dev:!0},queue:{pkg:`@forinda/kickjs-queue`,peers:[],description:`Queue adapter (BullMQ/RabbitMQ/Kafka)`},"queue:bullmq":{pkg:`@forinda/kickjs-queue`,peers:[`bullmq`,`ioredis`],description:`Queue with BullMQ + Redis`},"queue:rabbitmq":{pkg:`@forinda/kickjs-queue`,peers:[`amqplib`],description:`Queue with RabbitMQ`},"queue:kafka":{pkg:`@forinda/kickjs-queue`,peers:[`kafkajs`],description:`Queue with Kafka`},"queue:redis-pubsub":{pkg:`@forinda/kickjs-queue`,peers:[`ioredis`],description:`Lightweight pub/sub via Redis (no persistence)`},mcp:{pkg:`@forinda/kickjs-mcp`,peers:[`@modelcontextprotocol/sdk`],description:`Model Context Protocol server — expose @Controller endpoints as AI tools`},testing:{pkg:`@forinda/kickjs-testing`,peers:[],description:`Test utilities and TestModule builder`,dev:!0}},yt=Object.entries(vt).filter(([e,t])=>!t.core&&!t.deprecated&&!e.includes(`:`)&&![`pg`,`sqlite`,`mysql`,`zod`,`valibot`,`yup`].includes(e)).map(([e])=>e).join(`, `),bt={express:{prod:`multer`,dev:`@types/multer`,note:`Express uploads use multer (memory/disk storage, ctx.file / ctx.files).`},fastify:{prod:`@fastify/multipart`,note:`Fastify uploads use @fastify/multipart (buffered into ctx.file / ctx.files).`},h3:{note:`h3 parses multipart natively (readMultipartFormData) — no driver to install.`}};async function xt(e=process.cwd()){let t=(await M(e))?.runtime;return t===`express`||t===`fastify`||t===`h3`?t:St(e)}function St(e=process.cwd()){let t=Ct(`package.json`,e);if(t)try{let e=JSON.parse(a(v(t,`package.json`),`utf-8`)),n={...e.dependencies,...e.devDependencies};if(`fastify`in n)return`fastify`;if(`h3`in n)return`h3`}catch{}return`express`}function Ct(e,t=process.cwd()){let n=t;for(;;){if(r(v(n,e)))return n;let t=f(n);if(t===n)return null;n=t}}function wt(){return Ct(`pnpm-lock.yaml`)?`pnpm`:Ct(`yarn.lock`)?`yarn`:Ct(`bun.lockb`)||Ct(`bun.lock`)?`bun`:Ct(`package-lock.json`)?`npm`:null}function Tt(){let e=process.cwd();for(;e;){let t=v(e,`package.json`);if(r(t))try{let e=JSON.parse(a(t,`utf-8`)).packageManager;if(typeof e==`string`){let t=e.split(`@`)[0];if(we.includes(t))return t}}catch{}let n=f(e);if(n===e)return null;e=n}return null}async function Et(e){if(e&&we.includes(e))return{pm:e,source:`flag`};let t=await M(process.cwd());if(t?.packageManager&&we.includes(t.packageManager))return{pm:t.packageManager,source:`config`};let n=Tt();if(n)return{pm:n,source:`package.json`};let r=wt();return r?{pm:r,source:`lockfile`}:{pm:`npm`,source:`default`}}async function Dt(e){let{pm:t}=await Et(e);return t}function Ot(e=!1){let t=Object.entries(vt),n=Math.max(...t.map(([e])=>e.length)),r=t.filter(([,e])=>e.core),i=t.filter(([,e])=>!e.core),a=([e,t])=>{let r=e.padEnd(n+2),i=t.peers.length?` (+ ${t.peers.join(`, `)})`:``,a=t.deprecated?` [DEPRECATED — ${t.deprecated}]`:``;return` ${r} ${t.description}${i}${a}`};console.log(`
|
|
1233
1233
|
Core packages (always installed by \`kick new\`):
|
|
1234
1234
|
`);for(let e of r)console.log(a(e));if(e){console.log(`
|
|
1235
1235
|
Optional packages (add as needed):
|
|
1236
1236
|
`);for(let e of i)console.log(a(e))}else console.log(`\n Plus ${i.length} optional packages (auth, swagger, db, queue, …).`),console.log(" Run `kick add --list --all` for the full catalog.");console.log(`
|
|
1237
|
-
Usage: kick add ai db swagger`),console.log(` kick add queue:bullmq`),console.log(` kick add upload # installs the multipart driver for your runtime`),console.log()}function
|
|
1238
|
-
`),a.length===0&&o.length===0))){if(a.length>0){let e=a,t=`${n} add ${e.join(` `)}`;console.log(`\n Installing ${e.length} dependency(ies):`);for(let t of e)console.log(` + ${t}`);console.log();try{
|
|
1239
|
-
`)}})}const
|
|
1240
|
-
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await Promise.resolve().then(()=>
|
|
1241
|
-
Project scaffolded successfully!`),console.log();let p=l!==process.cwd();u(`Next steps:`),p&&u(` cd ${t}`),e.installDeps||u(` ${r} install`);let m={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};u(` ${m[i]??m.rest}`),u(` kick dev`),u(``),u(`Commands:`),u(` kick dev Start dev server with Vite HMR`),u(` kick build Production build via Vite`),u(` kick start Run production build`),u(``),u(`Generators:`),u(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),u(` kick g scaffold <n> <f..> CRUD module from field definitions`),u(` kick g controller <name> Standalone controller`),u(` kick g service <name> @Service() class`),u(` kick g middleware <name> Express middleware`),u(` kick g guard <name> Route guard (auth, roles, etc.)`),u(` kick g adapter <name> AppAdapter with lifecycle hooks`),u(` kick g dto <name> Zod DTO schema`),u(` kick g config Generate kick.config.ts`),u(``),u(`Add packages:`),u(` kick add <pkg> Install a KickJS package + peers`),u(` kick add --list Show all available packages`),u(``),u(`Available: ${
|
|
1237
|
+
Usage: kick add ai db swagger`),console.log(` kick add queue:bullmq`),console.log(` kick add upload # installs the multipart driver for your runtime`),console.log()}function kt(e,t,n=`express`){let r=new Set,i=new Set,a=[],o=[],s=[];for(let c of e){if(c===`upload`){let e=bt[n];s.push(`upload (${n}): ${e.note}`),e.prod&&(t?i:r).add(e.prod),e.dev&&i.add(e.dev);continue}let e=vt[c];if(!e){a.push(c);continue}e.deprecated&&o.push(`'${c}' (${e.pkg}) is deprecated — ${e.deprecated}`);let l=t||e.dev?i:r;l.add(e.pkg);for(let t of e.peers)l.add(t)}return{prodDeps:[...r],devDeps:[...i],unknown:a,warnings:o,notices:s}}function At(e){e.command(`list`).alias(`ls`).description(`List KickJS packages (core only; pair with --all for the full catalog)`).option(`--all`,`Include the full optional catalog`).action(e=>{Ot(!!e.all)})}function jt(e){e.command(`add [packages...]`).description(`Add KickJS packages with their required dependencies`).option(`--pm <manager>`,`Package manager override`).option(`-D, --dev`,`Install as dev dependency`).option(`--list`,`List packages (core only by default; pair with --all)`).option(`--all`,`When listing, include the full optional catalog`).action(async(e,t)=>{if(t.list||e.length===0){Ot(!!t.all);return}let{pm:n,source:r}=await Et(t.pm);console.log(`\n Using ${n} (resolved from ${r})`);let i=await xt(process.cwd()),{prodDeps:a,devDeps:o,unknown:s,warnings:c,notices:l}=kt(e,!!t.dev,i);for(let e of c)console.warn(`\n WARNING: ${e}`);for(let e of l)console.log(`\n ${e}`);if(!(s.length>0&&(console.log(`\n Unknown packages: ${s.join(`, `)}`),console.log(` Run "kick add --list" to see available packages.
|
|
1238
|
+
`),a.length===0&&o.length===0))){if(a.length>0){let e=a,t=`${n} add ${e.join(` `)}`;console.log(`\n Installing ${e.length} dependency(ies):`);for(let t of e)console.log(` + ${t}`);console.log();try{C(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}if(o.length>0){let e=o,t=`${n} add -D ${e.join(` `)}`;console.log(`\n Installing ${e.length} dev dependency(ies):`);for(let t of e)console.log(` + ${t} (dev)`);console.log();try{C(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}console.log(` Done!
|
|
1239
|
+
`)}})}const Mt=f(b(import.meta.url)),Nt=JSON.parse(a(h(Mt,`..`,`package.json`),`utf-8`)),Pt=`^${Nt.version}`,Ft=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-schema`,`@forinda/kickjs-vite`,`@forinda/kickjs-swagger`,`@forinda/kickjs-ws`,`@forinda/kickjs-queue`,`@forinda/kickjs-devtools`,`@forinda/kickjs-testing`];async function It(){let e=await Promise.all(Ft.map(async e=>{try{let t=S(`npm`,[`view`,e,`version`],{encoding:`utf-8`,timeout:5e3,stdio:[`ignore`,`pipe`,`ignore`]}).toString().trim();if(t&&/^\d+\.\d+\.\d+/.test(t))return[e,`^${t}`]}catch{}return[e,Pt]}));return Object.fromEntries(e)}function Lt(e,t){try{let n=S(`npm`,[`view`,`${e}@${t}`,`version`],{encoding:`utf-8`,timeout:5e3,stdio:[`ignore`,`pipe`,`ignore`]}).toString().trim();return n&&/^\d+\.\d+\.\d+/.test(n)?n:null}catch{return null}}function Rt(e){return(e??``).replace(/^[\^~>=<\s]+/,``)}function zt(e,t){let n=e=>Rt(e).split(`-`)[0].split(`.`).map(e=>Number.parseInt(e,10)||0),[r=0,i=0,a=0]=n(e),[o=0,s=0,c=0]=n(t);return r===o?i===s?a>=c:i>s:r>o}function Bt(e,t,n){try{let r=S(`npm`,[`view`,`${e}@${t}`,`exports`,`--json`],{encoding:`utf-8`,timeout:5e3,stdio:[`ignore`,`pipe`,`ignore`]}).toString().trim();if(!r)return!1;let i=JSON.parse(r);return Object.prototype.hasOwnProperty.call(i,n)}catch{return!1}}async function Vt(e){let{name:t,directory:n,packageManager:r=`pnpm`,template:i=`rest`,defaultRepo:a=`inmemory`,packages:o=[],schemaLib:s=`zod`,runtime:c=`express`}=e,l=n,u=e=>console.log(` ${e}`);console.log(`\n Creating KickJS project: ${t}\n`),u(`Resolving package versions...`);let d=await It();if(c!==`express`)if(Bt(`@forinda/kickjs`,`latest`,`./${c}`))u(`Using @forinda/kickjs@latest (stable ships the ${c} runtime)`);else{let e=[`@forinda/kickjs`,`@forinda/kickjs-cli`,`@forinda/kickjs-vite`],t=[],n=!1;for(let r of e){let e=Lt(r,`alpha`);e&&zt(e,Rt(d[r]))&&(d[r]=`^${e}`,t.push(`${r}@^${e}`),r===`@forinda/kickjs`&&(n=!0))}u(n?`Using the alpha channel for the ${c} runtime: ${t.join(`, `)}`:`WARNING: could not resolve @forinda/kickjs@alpha — the ${c} runtime subpath may be missing. After install, run: ${r} add @forinda/kickjs@alpha`)}await P(h(l,`package.json`),Je(t,i,d,o,s,c)),await P(h(l,`vite.config.ts`),Ye()),await P(h(l,`tsconfig.json`),Xe()),await P(h(l,`.prettierrc`),Ze()),await P(h(l,`.editorconfig`),Qe()),await P(h(l,`.gitignore`),$e()),await P(h(l,`.gitattributes`),et()),await P(h(l,`.env`),tt()),await P(h(l,`.env.example`),nt()),await P(h(l,`src/config/index.ts`),st(s)),await P(h(l,`src/index.ts`),at(t,i,Nt.version,o,c)),await P(h(l,`src/modules/index.ts`),ot()),await P(h(l,`src/modules/hello/hello.service.ts`),ct()),await P(h(l,`src/modules/hello/hello.controller.ts`),lt()),await P(h(l,`src/modules/hello/hello.module.ts`),ut()),await P(h(l,`kick.config.ts`),dt(i,a,r,c)),await P(h(l,`vitest.config.ts`),rt()),await P(h(l,`README.md`),ft(t,i,r));let{generateAgentDocs:f}=await Promise.resolve().then(()=>ar);if(await f({outDir:l,name:t,pm:r,template:i,only:`all`,force:!0}),e.installDeps){console.log(`\n Installing dependencies with ${r}...\n`);try{C(`${r} install`,{cwd:l,stdio:`inherit`}),console.log(`
|
|
1240
|
+
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await Promise.resolve().then(()=>Aa);await e({cwd:l,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{C(`git init`,{cwd:l,stdio:`pipe`}),C(`git branch -M main`,{cwd:l,stdio:`pipe`}),C(`git add -A`,{cwd:l,stdio:`pipe`}),C(`git commit -m "chore: initial commit from kick new"`,{cwd:l,stdio:`pipe`}),u(`Git repository initialized`)}catch{u(`Warning: git init failed (git may not be installed)`)}console.log(`
|
|
1241
|
+
Project scaffolded successfully!`),console.log();let p=l!==process.cwd();u(`Next steps:`),p&&u(` cd ${t}`),e.installDeps||u(` ${r} install`);let m={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};u(` ${m[i]??m.rest}`),u(` kick dev`),u(``),u(`Commands:`),u(` kick dev Start dev server with Vite HMR`),u(` kick build Production build via Vite`),u(` kick start Run production build`),u(``),u(`Generators:`),u(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),u(` kick g scaffold <n> <f..> CRUD module from field definitions`),u(` kick g controller <name> Standalone controller`),u(` kick g service <name> @Service() class`),u(` kick g middleware <name> Express middleware`),u(` kick g guard <name> Route guard (auth, roles, etc.)`),u(` kick g adapter <name> AppAdapter with lifecycle hooks`),u(` kick g dto <name> Zod DTO schema`),u(` kick g config Generate kick.config.ts`),u(``),u(`Add packages:`),u(` kick add <pkg> Install a KickJS package + peers`),u(` kick add --list Show all available packages`),u(``),u(`Available: ${yt}`),u(``)}const Ht={GET:k.green,POST:k.cyan,PUT:k.yellow,PATCH:k.magenta,DELETE:k.red};function Ut(e){return(Ht[e]??k.dim)(e.padEnd(7))}function Wt(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return k.red(t);case`WARNING`:return k.yellow(t);case`INFO`:return k.blue(k.dim(t));default:return t}}k.green(`✓`),k.red(`✖`),k.yellow(`⚠`),k.blue(`ℹ`);function Gt(e){O.intro(k.bgCyan(k.black(` ${e} `)))}function F(e){O.outro(e)}function Kt(e){O.isCancel(e)&&(O.cancel(`Operation cancelled.`),process.exit(0))}async function qt(e){let t=await O.text(e);return Kt(t),t}async function Jt(e){let t=await O.select(e);return Kt(t),t}async function Yt(e){let t=await O.multiselect(e);return Kt(t),t}async function I(e){let t=await O.confirm(e);return Kt(t),t}function Xt(){return O.spinner()}const L=O.log,Zt=[{value:`swagger`,label:`Swagger`,hint:`OpenAPI docs`},{value:`ws`,label:`WebSocket`,hint:`rooms, heartbeat`},{value:`queue`,label:`Queue`,hint:`BullMQ/RabbitMQ/Kafka`},{value:`devtools`,label:`DevTools`,hint:`debug dashboard`}];function Qt(e){e.command(`new [name]`).alias(`init`).description(`Create a new KickJS project (use "." for current directory)`).option(`-d, --directory <dir>`,`Target directory (defaults to project name)`).option(`--pm <manager>`,`Package manager: pnpm | npm | yarn | bun`).option(`--git`,`Initialize git repository`).option(`--no-git`,`Skip git initialization`).option(`--install`,`Install dependencies after scaffolding`).option(`--no-install`,`Skip dependency installation`).option(`-f, --force`,`Remove existing files without prompting`).option(`-t, --template <type>`,`Project template: rest | minimal`).option(`--runtime <engine>`,`HTTP runtime: express | fastify | h3`).option(`-r, --repo <type>`,`Repository name (inmemory, or any DB name e.g. postgres)`).option(`-s, --schema <lib>`,`Schema library for env / DTOs: zod | valibot | yup (default: zod)`).option(`--packages <packages>`,`Comma-separated packages to include (e.g. auth,swagger,ws,queue)`).option(`-y, --yes`,`Pick safe defaults for every prompt (template=minimal, repo=inmemory, no extras, git+install on)`).option(`--non-interactive`,`alias for --yes`).action(async(e,t)=>{Gt(`KickJS — Create a new project`);let n=!!(t.yes||t.nonInteractive);e||=n?`my-api`:await qt({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let i;if(e===`.`?(i=v(`.`),e=d(i)):i=v(t.directory||e),r(i)){let r=o(i);if(r.length>0){if(t.force)L.warn(`Clearing existing files in ${i}`);else if(n){L.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),F(`Aborted.`);return}else{L.warn(`Directory "${e}" is not empty:`);let t=r.slice(0,5);for(let e of t)L.message(` - ${e}`);if(r.length>5&&L.message(` ... and ${r.length-5} more`),!await I({message:k.red(`Remove all existing files and proceed?`),initialValue:!1})){F(`Aborted.`);return}}for(let e of r)s(v(i,e),{recursive:!0,force:!0})}}let a=t.template;a||=n?`minimal`:await Jt({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`minimal`,label:`Minimal`,hint:`bare Express`}]});let c=t.runtime;c||=n?`express`:await Jt({message:`HTTP runtime`,options:[{value:`express`,label:`Express`,hint:`default, zero-config`},{value:`fastify`,label:`Fastify`,hint:`fastify + @fastify/middie`},{value:`h3`,label:`h3`,hint:`Nitro / Nuxt engine`}]});let l=t.pm;l||=n?await Dt(void 0):await Jt({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let u=t.repo;u||=n?`inmemory`:await qt({message:`Repository name`,placeholder:`inmemory (or a DB name, e.g. postgres)`,defaultValue:`inmemory`}),De(u);let f=t.schema;f||=n?`zod`:await Jt({message:`Schema library (env + DTO validation)`,options:[{value:`zod`,label:`Zod`,hint:`default — broad ecosystem`},{value:`valibot`,label:`Valibot`,hint:`smaller bundle`},{value:`yup`,label:`Yup`,hint:`classic API`}]}),[`zod`,`valibot`,`yup`].includes(f)||(L.warn(`Unknown --schema "${f}", falling back to zod.`),f=`zod`);let p;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();p=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else p=n?[]:await Yt({message:`Select packages to include`,options:[...Zt],required:!1});let m;m=t.git===void 0?n?!0:await I({message:`Initialize git repository?`,initialValue:!0}):t.git;let h;h=t.install===void 0?n?!0:await I({message:`Install dependencies?`,initialValue:!0}):t.install,await Vt({name:e,directory:i,packageManager:l,initGit:m,installDeps:h,template:a,defaultRepo:u,packages:p,schemaLib:f,runtime:c}),F(`Done! Next steps: ${k.cyan(`cd ${e} && ${l} dev`)}`)})}function R(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function z(e){let t=R(e);return t.charAt(0).toLowerCase()+t.slice(1)}function B(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function $t(e){return ue.plural(e)}function en(e){return ue.plural(e)}var tn=A({findProjectRoot:()=>rn});const nn=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];function rn(e=process.cwd()){let t=v(e),{root:n}=g(t),i=null,a=t;for(;;){for(let e of nn)if(r(v(a,e)))return a;if(i===null&&r(v(a,`package.json`))&&(i=a),a===n)break;let e=f(a);if(e===a)break;a=e}return i??t}function an(e){return B(e).replace(/-/g,`_`)}function on(e){let t=e.cwd??process.cwd(),n=e.projectRoot??rn(t),r=e.pluralize??!0,i=R(e.name),a=z(e.name),o=B(e.name),s=an(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=$t(o);c.pluralKebab=e,c.pluralPascal=R(e),c.pluralCamel=z(e)}return c}function sn(e,t){return v(e.cwd,t)}async function cn(e){return import(x(e).href)}const ln=new Map;async function un(e){let t=ln.get(e);if(t)return t;let n=dn(e);return ln.set(e,n),n}async function dn(t){let n=v(t,`package.json`);if(!r(n))return{generators:[],loaded:[],failed:[]};let i=fn(JSON.parse(await T(n,`utf-8`))),a=e(v(t,`package.json`)),o=[],s=[],c=[];for(let e of i){let t;try{t=a.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await T(t,`utf-8`))}catch(t){c.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let i=n.kickjs.generators,l=v(f(t),i);if(!r(l)){c.push({source:e,reason:`kickjs.generators points to missing file: ${i}`});continue}let u;try{u=await cn(l)}catch(t){c.push({source:e,reason:`failed to import manifest: ${t}`});continue}let d=u.default;if(!Array.isArray(d)){c.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of d){if(!pn(t)){c.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}o.push({source:e,spec:t})}s.push(e)}return{generators:o,loaded:s,failed:c}}function fn(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 pn(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function mn(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return _n(r.spec,r.source,e,n);let i=gn(await un(n),e.generatorName);return i?_n(i.spec,i.source,e,n):null}async function hn(e,t=[]){let n=await un(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 gn(e,t){return e.generators.find(e=>e.spec.name===t)}async function _n(e,t,n,r){let i=on({name:n.itemName,args:n.args,flags:n.flags,modulesDir:n.modulesDir,pluralize:n.pluralize,cwd:r,projectRoot:n.projectRoot}),a=await e.files(i),o=[];for(let e of a){let t=sn(i,e.path);await P(t,e.content),o.push(t)}return{files:o,source:t}}function V(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function vn(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function yn(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function bn(e,t,n){let r={inmemory:`InMemory${e}Repository`,drizzle:`Drizzle${e}Repository`,prisma:`Prisma${e}Repository`},i={inmemory:`in-memory-${t}`,drizzle:`drizzle-${t}`,prisma:`prisma-${t}`};return{repoClass:r[n]??`${vn(n)}${e}Repository`,repoFile:i[n]??`${yn(n)}-${t}`}}function xn(e){return e??`define`}function Sn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=bn(t,n,i),c=xn(a),l=`/**
|
|
1242
1242
|
* ${t} Module
|
|
1243
1243
|
*
|
|
1244
1244
|
* REST module with a flat folder structure.
|
|
@@ -1254,8 +1254,13 @@ in \`.agents/COPILOT.local.md\`.
|
|
|
1254
1254
|
import { ${o} } from './${s}.repository'
|
|
1255
1255
|
import { ${t}Controller } from './${n}.controller'
|
|
1256
1256
|
|
|
1257
|
-
// Eagerly load decorated classes so @Service()/@Repository() decorators
|
|
1258
|
-
|
|
1257
|
+
// Eagerly load decorated classes so @Controller()/@Service()/@Repository() decorators
|
|
1258
|
+
// register in the DI container. Recursive globs (./**/) so the module keeps working
|
|
1259
|
+
// however you nest files (e.g. moving controllers into a controllers/ sub-folder).
|
|
1260
|
+
import.meta.glob(
|
|
1261
|
+
['./**/*.controller.ts', './**/*.service.ts', './**/*.repository.ts', '!./**/*.test.ts'],
|
|
1262
|
+
{ eager: true },
|
|
1263
|
+
)`,d=` /**
|
|
1259
1264
|
* Declare HTTP routes for this module. Return value shape:
|
|
1260
1265
|
*
|
|
1261
1266
|
* - \`path\` — URL prefix for this route set.
|
|
@@ -1310,7 +1315,7 @@ ${d}
|
|
|
1310
1315
|
},
|
|
1311
1316
|
}),
|
|
1312
1317
|
})
|
|
1313
|
-
`}function
|
|
1318
|
+
`}function Cn(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=xn(i),o=` /**
|
|
1314
1319
|
* Declare HTTP routes. Return value shape:
|
|
1315
1320
|
*
|
|
1316
1321
|
* - \`path\` — URL prefix for this route set.
|
|
@@ -1350,7 +1355,7 @@ ${o}
|
|
|
1350
1355
|
},
|
|
1351
1356
|
}),
|
|
1352
1357
|
})
|
|
1353
|
-
`}function
|
|
1358
|
+
`}function wn(e){let{pascal:t,kebab:n}=e,r=t.charAt(0).toLowerCase()+t.slice(1);return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
|
|
1354
1359
|
import { ApiTags } from '@forinda/kickjs-swagger'
|
|
1355
1360
|
import { ${t}Service } from './${n}.service'
|
|
1356
1361
|
import { create${t}Schema } from './dtos/create-${n}.dto'
|
|
@@ -1405,7 +1410,7 @@ export class ${t}Controller {
|
|
|
1405
1410
|
ctx.noContent()
|
|
1406
1411
|
}
|
|
1407
1412
|
}
|
|
1408
|
-
`}function
|
|
1413
|
+
`}function Tn(e){let{pascal:t}=e;return`import { z } from 'zod'
|
|
1409
1414
|
|
|
1410
1415
|
/**
|
|
1411
1416
|
* Create ${t} DTO — Zod schema for validating POST request bodies.
|
|
@@ -1421,20 +1426,20 @@ export const create${t}Schema = z.object({
|
|
|
1421
1426
|
})
|
|
1422
1427
|
|
|
1423
1428
|
export type Create${t}DTO = z.infer<typeof create${t}Schema>
|
|
1424
|
-
`}function
|
|
1429
|
+
`}function En(e){let{pascal:t}=e;return`import { z } from 'zod'
|
|
1425
1430
|
|
|
1426
1431
|
export const update${t}Schema = z.object({
|
|
1427
1432
|
name: z.string().min(1).max(200).optional(),
|
|
1428
1433
|
})
|
|
1429
1434
|
|
|
1430
1435
|
export type Update${t}DTO = z.infer<typeof update${t}Schema>
|
|
1431
|
-
`}function
|
|
1436
|
+
`}function Dn(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
|
|
1432
1437
|
id: string
|
|
1433
1438
|
name: string
|
|
1434
1439
|
createdAt: string
|
|
1435
1440
|
updatedAt: string
|
|
1436
1441
|
}
|
|
1437
|
-
`}function
|
|
1442
|
+
`}function On(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
|
|
1438
1443
|
* ${t} Repository Interface
|
|
1439
1444
|
*
|
|
1440
1445
|
* Defines the contract for data access.
|
|
@@ -1469,7 +1474,7 @@ export interface I${t}Repository {
|
|
|
1469
1474
|
* adopters must NOT use the reserved \`'kick/'\` namespace.
|
|
1470
1475
|
*/
|
|
1471
1476
|
export const ${t.toUpperCase()}_REPOSITORY = createToken<I${t}Repository>('${i}/${t}/repository')
|
|
1472
|
-
`}function
|
|
1477
|
+
`}function kn(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
|
|
1473
1478
|
* In-Memory ${t} Repository
|
|
1474
1479
|
*
|
|
1475
1480
|
* Implements the repository interface using a Map.
|
|
@@ -1529,7 +1534,7 @@ export class InMemory${t}Repository implements I${t}Repository {
|
|
|
1529
1534
|
this.store.delete(id)
|
|
1530
1535
|
}
|
|
1531
1536
|
}
|
|
1532
|
-
`}function
|
|
1537
|
+
`}function An(e){let{pascal:t,kebab:n,repoType:r=``,repoPrefix:i=`../../domain/repositories`,dtoPrefix:a=`../../application/dtos`}=e,o=r.charAt(0).toUpperCase()+r.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
|
|
1533
1538
|
* ${o} ${t} Repository
|
|
1534
1539
|
*
|
|
1535
1540
|
* Stub implementation for a custom '${r}' repository.
|
|
@@ -1598,7 +1603,7 @@ export class ${o}${t}Repository implements I${t}Repository {
|
|
|
1598
1603
|
this.store.delete(id)
|
|
1599
1604
|
}
|
|
1600
1605
|
}
|
|
1601
|
-
`}function
|
|
1606
|
+
`}function jn(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
|
|
1602
1607
|
import { Container } from '@forinda/kickjs'
|
|
1603
1608
|
|
|
1604
1609
|
describe('${t}Controller', () => {
|
|
@@ -1650,7 +1655,7 @@ describe('${t}Controller', () => {
|
|
|
1650
1655
|
})
|
|
1651
1656
|
})
|
|
1652
1657
|
})
|
|
1653
|
-
`}function
|
|
1658
|
+
`}function Mn(e){let{pascal:t,kebab:n,plural:r=``,repoPrefix:i=`../infrastructure/repositories/in-memory-${n}.repository`}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
|
|
1654
1659
|
import { InMemory${t}Repository } from '${i}'
|
|
1655
1660
|
|
|
1656
1661
|
describe('InMemory${t}Repository', () => {
|
|
@@ -1712,7 +1717,7 @@ describe('InMemory${t}Repository', () => {
|
|
|
1712
1717
|
expect(found).toBeNull()
|
|
1713
1718
|
})
|
|
1714
1719
|
})
|
|
1715
|
-
`}function
|
|
1720
|
+
`}function Nn(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
|
|
1716
1721
|
import type { ParsedQuery } from '@forinda/kickjs'
|
|
1717
1722
|
import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from './${n}.repository'
|
|
1718
1723
|
import type { ${t}ResponseDTO } from './dtos/${n}-response.dto'
|
|
@@ -1749,14 +1754,14 @@ export class ${t}Service {
|
|
|
1749
1754
|
await this.repo.delete(id)
|
|
1750
1755
|
}
|
|
1751
1756
|
}
|
|
1752
|
-
`}function
|
|
1757
|
+
`}function Pn(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
|
|
1753
1758
|
|
|
1754
1759
|
export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
|
|
1755
1760
|
filterable: ['name'],
|
|
1756
1761
|
sortable: ['name', 'createdAt'],
|
|
1757
1762
|
searchable: ['name'],
|
|
1758
1763
|
}
|
|
1759
|
-
`}async function
|
|
1764
|
+
`}async function Fn(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,Cn({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
|
|
1760
1765
|
|
|
1761
1766
|
// \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
|
|
1762
1767
|
// \`kick typegen\` (auto-run on \`kick dev\`).
|
|
@@ -1768,7 +1773,7 @@ export class ${t}Controller {
|
|
|
1768
1773
|
ctx.json({ message: '${t} list' })
|
|
1769
1774
|
}
|
|
1770
1775
|
}
|
|
1771
|
-
`)}async function
|
|
1776
|
+
`)}async function In(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,tokenScope:s,style:c,write:l}=e;await l(`${n}.module.ts`,Sn({pascal:t,kebab:n,plural:r,repo:a,style:c})),await l(`${n}.constants.ts`,Pn({pascal:t,kebab:n})),await l(`${n}.controller.ts`,wn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await l(`${n}.service.ts`,Nn({pascal:t,kebab:n})),await l(`dtos/create-${n}.dto.ts`,Tn({pascal:t,kebab:n})),await l(`dtos/update-${n}.dto.ts`,En({pascal:t,kebab:n})),await l(`dtos/${n}-response.dto.ts`,Dn({pascal:t,kebab:n})),await l(`${n}.repository.ts`,On({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:s}));let u=a===`inmemory`,d=u?`in-memory-${n}`:`${B(a)}-${n}`,f=u?kn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}):An({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`});await l(`${d}.repository.ts`,f),o||(a!==`inmemory`&&await l(`in-memory-${n}.repository.ts`,kn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await l(`__tests__/${n}.controller.test.ts`,jn({pascal:t,kebab:n,plural:r})),await l(`__tests__/${n}.repository.test.ts`,Mn({pascal:t,kebab:n,plural:r,repoPrefix:`../in-memory-${n}.repository`})))}function Ln(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function Rn(e){let{name:t,modulesDir:n,noEntity:r,noTests:i,repo:a=`inmemory`,force:o,dryRun:s}=e,c=e.pluralize!==!1,l=e.pattern??`rest`;e.minimal&&(l=`minimal`);let u=B(t),d=R(t),f=c?$t(u):u,p=c?en(d):d,m=h(n,f),g=[],_=o??!1,v={kebab:u,pascal:d,plural:f,pluralPascal:p,moduleDir:m,repo:a,noEntity:r??!1,noTests:i??!1,prismaClientPath:e.prismaClientPath??`@prisma/client`,tokenScope:e.tokenScope??`app`,style:e.style??`define`,write:async(e,t)=>{let n=h(m,e);if(s){g.push(n);return}if(!_&&await We(n)&&!await I({message:`File exists: ${k.dim(e)}. Overwrite?`,initialValue:!1})){L.warn(`Skipped: ${e}`);return}await P(n,t),g.push(n)},files:g};switch(l){case`minimal`:await Fn(v);break;default:await In(v);break}return s||await zn(n,d,f,u,v.style),g}async function zn(e,t,n,r,i=`define`){let a=h(e,`index.ts`),o=await We(a),s=`./${n}/${r}.module`,c=i===`class`?`${t}Module`:`${t}Module()`;if(!o){await P(a,i===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
|
|
1772
1777
|
import { ${t}Module } from '${s}'
|
|
1773
1778
|
|
|
1774
1779
|
export const modules: AppModuleEntry[] = [${c}]
|
|
@@ -1776,11 +1781,11 @@ export const modules: AppModuleEntry[] = [${c}]
|
|
|
1776
1781
|
import { ${t}Module } from '${s}'
|
|
1777
1782
|
|
|
1778
1783
|
export const modules = defineModules().mount(${c})
|
|
1779
|
-
`);return}let l=await
|
|
1784
|
+
`);return}let l=await T(a,`utf-8`),u=`import { ${t}Module } from '${s}'`,d=V(s);if(!RegExp(`^import\\s*\\{[^}]*\\b${V(t)}Module\\b[^}]*\\}\\s*from\\s*['"]${d}['"]`,`m`).test(l)){let e=l.lastIndexOf(`import `);if(e!==-1){let t=l.indexOf(`
|
|
1780
1785
|
`,e);l=l.slice(0,t+1)+u+`
|
|
1781
1786
|
`+l.slice(t+1)}else l=u+`
|
|
1782
|
-
`+l}let f=
|
|
1783
|
-
`;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function
|
|
1787
|
+
`+l}let f=Vn(l);if(f){let e=l.slice(f.rhsStart,f.rhsEnd+1);RegExp(`\\b${V(t)}Module\\b`).test(e)||(l=Bn(l,c))}else l=Bn(l,c);await E(a,l,`utf-8`)}function Bn(e,t){let n=Vn(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 Vn(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=Wn(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=Hn(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function Hn(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=Gn(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=Gn(e,t);if(n===-1)break;i=n+1}return i}function Un(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
|
|
1788
|
+
`;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function Wn(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=Un(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 Gn(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=Un(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 Kn(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=h(n,`${r}.adapter.ts`);return await P(o,`import {
|
|
1784
1789
|
defineAdapter,
|
|
1785
1790
|
type AdapterContext,
|
|
1786
1791
|
type AdapterMiddleware,
|
|
@@ -1949,7 +1954,7 @@ export const ${i}Adapter = defineAdapter<${i}AdapterConfig>({
|
|
|
1949
1954
|
}
|
|
1950
1955
|
},
|
|
1951
1956
|
})
|
|
1952
|
-
`),a.push(o),a}async function
|
|
1957
|
+
`),a.push(o),a}async function qn(e){let{name:t,outDir:n}=e,r=B(t),i=R(t),a=[],o=h(n,`${r}.plugin.ts`);return await P(o,`import {
|
|
1953
1958
|
definePlugin,
|
|
1954
1959
|
type AppAdapter,
|
|
1955
1960
|
type AppModuleEntry,
|
|
@@ -2093,9 +2098,9 @@ export const ${i}Plugin = definePlugin<${i}PluginConfig>({
|
|
|
2093
2098
|
},
|
|
2094
2099
|
}),
|
|
2095
2100
|
})
|
|
2096
|
-
`),a.push(o),a}const
|
|
2101
|
+
`),a.push(o),a}const Jn={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,contributor:`contributors`};function Yn(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,shouldPluralize:o=!0}=e;if(n)return v(n);if(r){let e=Jn,n=B(r),a=o?$t(n):n,s=e[t]??``,c=h(i,a);return v(s?h(c,s):c)}return v(a)}async function Xn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=Yn({type:`middleware`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/middleware`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=z(t),c=[],l=h(a,`${o}.middleware.ts`);return await P(l,`import type { Request, Response, NextFunction } from 'express'
|
|
2097
2102
|
|
|
2098
|
-
export interface ${
|
|
2103
|
+
export interface ${R(t)}Options {
|
|
2099
2104
|
// Add configuration options here. The factory below closes over the
|
|
2100
2105
|
// resolved options object; pass them at the call site —
|
|
2101
2106
|
// \`${s}({ foo: 'bar' })\` — and the closure preserves them across
|
|
@@ -2103,7 +2108,7 @@ export interface ${I(t)}Options {
|
|
|
2103
2108
|
}
|
|
2104
2109
|
|
|
2105
2110
|
/**
|
|
2106
|
-
* ${
|
|
2111
|
+
* ${R(t)} middleware.
|
|
2107
2112
|
*
|
|
2108
2113
|
* Usage in bootstrap (fires on every request):
|
|
2109
2114
|
* middleware: [${s}()]
|
|
@@ -2135,7 +2140,7 @@ export interface ${I(t)}Options {
|
|
|
2135
2140
|
* Usage with @Middleware decorator:
|
|
2136
2141
|
* @Middleware(${s}())
|
|
2137
2142
|
*/
|
|
2138
|
-
export function ${s}(options: ${
|
|
2143
|
+
export function ${s}(options: ${R(t)}Options = {}) {
|
|
2139
2144
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
2140
2145
|
// Implement your middleware logic here. \`options\` is captured by
|
|
2141
2146
|
// closure — log or read it anywhere in this handler body.
|
|
@@ -2143,7 +2148,7 @@ export function ${s}(options: ${I(t)}Options = {}) {
|
|
|
2143
2148
|
next()
|
|
2144
2149
|
}
|
|
2145
2150
|
}
|
|
2146
|
-
`),c.push(l),c}async function
|
|
2151
|
+
`),c.push(l),c}async function Zn(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=Yn({type:`guard`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/guards`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=z(t),c=R(t),l=[],u=h(a,`${o}.guard.ts`);return await P(u,`import { Container, HttpException } from '@forinda/kickjs'
|
|
2147
2152
|
import type { RequestContext } from '@forinda/kickjs'
|
|
2148
2153
|
|
|
2149
2154
|
/**
|
|
@@ -2179,8 +2184,8 @@ export async function ${s}Guard(ctx: RequestContext, next: () => void): Promise<
|
|
|
2179
2184
|
ctx.res.status(401).json({ message: 'Invalid or expired token' })
|
|
2180
2185
|
}
|
|
2181
2186
|
}
|
|
2182
|
-
`),l.push(u),l}function
|
|
2183
|
-
`)}\n}\n`:``,m=l.length>0?`${d}.withParams<${s}Params>()({`:`${d}({`,g=l.map(e=>({name:e.name,def
|
|
2187
|
+
`),l.push(u),l}function Qn(e){return e?e.split(`,`).map(e=>e.trim()).filter(Boolean).map(e=>{let[t,n]=e.split(`:`).map(e=>e.trim());return{name:t,type:n||`string`}}).filter(e=>e.name.length>0):[]}function $n(e){switch(e){case`string`:return`''`;case`number`:return`0`;case`boolean`:return`false`;default:return null}}async function er(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=e.type??`http`,o=B(t),s=R(t),c=e.key??z(t),l=Array.isArray(e.params)?e.params:Qn(e.params),u=Yn({type:`contributor`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/contributors`,pattern:i,shouldPluralize:e.pluralize??!0}),d=a===`http`?`defineHttpContextDecorator`:`defineContextDecorator`,f=a===`http`?`RequestContext`:`ExecutionContext`,p=l.length>0?`\nexport type ${s}Params = {\n${l.map(e=>` ${e.name}: ${e.type}`).join(`
|
|
2188
|
+
`)}\n}\n`:``,m=l.length>0?`${d}.withParams<${s}Params>()({`:`${d}({`,g=l.map(e=>({name:e.name,def:$n(e.type)})).filter(e=>e.def!==null).map(e=>` ${e.name}: ${e.def},`),_=l.length>0?` paramDefaults: {\n${g.join(`
|
|
2184
2189
|
`)}\n },\n`:``,v=l.length>0?`(ctx, _deps, params)`:`(ctx)`,y=l.length>0?` // \`params\` is typed as ${s}Params (call-site overrides merged onto paramDefaults).`:` // \`ctx\` is a ${f} — read ctx.req / ctx.headers / ctx.params (http) or ctx.get (bare).`,b=`import { ${d} } from '@forinda/kickjs'
|
|
2185
2190
|
import type { ${f} } from '@forinda/kickjs'
|
|
2186
2191
|
|
|
@@ -2219,7 +2224,7 @@ ${y}
|
|
|
2219
2224
|
throw new Error("${s} contributor: resolve() not implemented")
|
|
2220
2225
|
},
|
|
2221
2226
|
})
|
|
2222
|
-
`,x=h(u,`${o}.contributor.ts`);return await
|
|
2227
|
+
`,x=h(u,`${o}.contributor.ts`);return await P(x,b),[x]}async function tr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=Yn({type:`service`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/services`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=[],l=h(a,`${o}.service.ts`);return await P(l,`import { Service } from '@forinda/kickjs'
|
|
2223
2228
|
|
|
2224
2229
|
@Service()
|
|
2225
2230
|
export class ${s}Service {
|
|
@@ -2228,7 +2233,7 @@ export class ${s}Service {
|
|
|
2228
2233
|
// @Inject(MY_REPO) private readonly repo: IMyRepository,
|
|
2229
2234
|
// ) {}
|
|
2230
2235
|
}
|
|
2231
|
-
`),c.push(l),c}async function
|
|
2236
|
+
`),c.push(l),c}async function nr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=Yn({type:`controller`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/controllers`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=[],l=h(a,`${o}.controller.ts`);return await P(l,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
|
|
2232
2237
|
|
|
2233
2238
|
// \`Ctx<KickRoutes.${s}Controller['<method>']>\` is generated by
|
|
2234
2239
|
// \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
|
|
@@ -2249,7 +2254,7 @@ export class ${s}Controller {
|
|
|
2249
2254
|
ctx.created({ message: '${s} created', data: ctx.body })
|
|
2250
2255
|
}
|
|
2251
2256
|
}
|
|
2252
|
-
`),c.push(l),c}async function
|
|
2257
|
+
`),c.push(l),c}async function rr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=Yn({type:`dto`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/dtos`,pattern:i,shouldPluralize:e.pluralize??!0}),o=B(t),s=R(t),c=z(t),l=[],u=h(a,`${o}.dto.ts`);return await P(u,`import { z } from 'zod'
|
|
2253
2258
|
|
|
2254
2259
|
export const ${c}Schema = z.object({
|
|
2255
2260
|
// Define your schema fields here
|
|
@@ -2257,8 +2262,8 @@ export const ${c}Schema = z.object({
|
|
|
2257
2262
|
})
|
|
2258
2263
|
|
|
2259
2264
|
export type ${s}DTO = z.infer<typeof ${c}Schema>
|
|
2260
|
-
`),l.push(u),l}async function
|
|
2261
|
-
Skipped — existing kick.config.ts preserved.`),[]):(await
|
|
2265
|
+
`),l.push(u),l}async function ir(e){let t=h(e.outDir,`kick.config.ts`),n=e.modulesDir??`src/modules`,i=e.defaultRepo??`inmemory`;return r(t)&&!e.force&&!await I({message:`kick.config.ts already exists. Overwrite?`,initialValue:!1})?(console.log(`
|
|
2266
|
+
Skipped — existing kick.config.ts preserved.`),[]):(await P(t,`import { defineConfig } from '@forinda/kickjs-cli'
|
|
2262
2267
|
|
|
2263
2268
|
export default defineConfig({
|
|
2264
2269
|
modules: {
|
|
@@ -2295,18 +2300,18 @@ export default defineConfig({
|
|
|
2295
2300
|
},
|
|
2296
2301
|
],
|
|
2297
2302
|
})
|
|
2298
|
-
`),[t])}var
|
|
2303
|
+
`),[t])}var ar=A({generateAgentDocs:()=>dr});const or=`.agents`,sr=new Set([`rest`,`minimal`]);function cr(e,t){if(t)return t;try{let t=JSON.parse(a(h(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function lr(e,t){if(t)return t;try{let t=JSON.parse(a(h(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function ur(e,t){if(t)return t;try{let t=(await M(e))?.pattern;if(t&&sr.has(t))return t}catch{}return`rest`}async function dr(e){let t=e.only??`all`,n=cr(e.outDir,e.name),i=lr(e.outDir,e.pm),a=await ur(e.outDir,e.template),o=t===`agents`||t===`both`||t===`all`,s=t===`claude`||t===`both`||t===`all`,c=t===`skills`||t===`all`,l=t===`gemini`||t===`all`,u=t===`copilot`||t===`all`,d=[];if(o&&d.push({file:h(e.outDir,or,`AGENTS.md`),render:()=>mt(n,a,i)}),s&&d.push({file:h(e.outDir,`CLAUDE.md`),render:()=>pt(n,a,i)}),c)for(let t of ht(n,a,i))d.push({file:h(e.outDir,or,`skills`,t.slug,`SKILL.md`),render:()=>t.content});l&&d.push({file:h(e.outDir,or,`GEMINI.md`),render:()=>gt(n,a,i)}),u&&d.push({file:h(e.outDir,or,`COPILOT.md`),render:()=>_t(n,a,i)});let f=[];for(let{file:t,render:n}of d){if(r(t)&&!e.force&&!await I({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await P(t,n()),f.push(t)}return f}function fr(e,t){if(e[t]!==`{`)return-1;let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`{`)n++;else if(t===`}`&&(n--,n===0))return r}return-1}function pr(e,t){let n=t.exec(e);if(!n)return null;let r=n.index+n[0].length-1,i=fr(e,r);return i===-1?null:e.slice(r+1,i)}function mr(e,t,n){let r=` `.repeat(n);return e.split(`
|
|
2299
2304
|
`).map(e=>{if(e.trim()===``)return e;let n=RegExp(`^ {0,${t}}`);return r+e.replace(n,``)}).join(`
|
|
2300
|
-
`)}function hr(e){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,t)=>{let n=t.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`Container`&&e!==`type Container`&&e!==`type AppModule`&&e!==`AppModule`&&e!==`type ModuleRoutes`&&e!==`ModuleRoutes`);return n.includes(`defineModule`)||n.push(`defineModule`),`import { ${n.join(`, `)} } from '@forinda/kickjs'`})}function gr(e,t){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,n)=>{let r=n.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`defineModule`);return t.container&&!r.includes(`Container`)&&r.push(`Container`),t.appModule&&!r.some(e=>e===`AppModule`||e===`type AppModule`)&&r.push(`type AppModule`),t.moduleRoutes&&!r.some(e=>e===`ModuleRoutes`||e===`type ModuleRoutes`)&&r.push(`type ModuleRoutes`),t.contributorRegistrations&&!r.some(e=>e===`ContributorRegistrations`||e===`type ContributorRegistrations`)&&r.push(`type ContributorRegistrations`),`import { ${r.join(`, `)} } from '@forinda/kickjs'`})}function _r(e){if(/\bdefineModule\s*\(/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+class\s+(\w+Module)\s+implements\s+AppModule\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no class form detected`};if(t.length>1)return{migrated:null,reason:`multiple module classes in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=
|
|
2305
|
+
`)}function hr(e){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,t)=>{let n=t.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`Container`&&e!==`type Container`&&e!==`type AppModule`&&e!==`AppModule`&&e!==`type ModuleRoutes`&&e!==`ModuleRoutes`);return n.includes(`defineModule`)||n.push(`defineModule`),`import { ${n.join(`, `)} } from '@forinda/kickjs'`})}function gr(e,t){return e.replaceAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*'@forinda\/kickjs'/g,(e,n)=>{let r=n.split(`,`).map(e=>e.trim()).filter(e=>e&&e!==`defineModule`);return t.container&&!r.includes(`Container`)&&r.push(`Container`),t.appModule&&!r.some(e=>e===`AppModule`||e===`type AppModule`)&&r.push(`type AppModule`),t.moduleRoutes&&!r.some(e=>e===`ModuleRoutes`||e===`type ModuleRoutes`)&&r.push(`type ModuleRoutes`),t.contributorRegistrations&&!r.some(e=>e===`ContributorRegistrations`||e===`type ContributorRegistrations`)&&r.push(`type ContributorRegistrations`),`import { ${r.join(`, `)} } from '@forinda/kickjs'`})}function _r(e){if(/\bdefineModule\s*\(/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+class\s+(\w+Module)\s+implements\s+AppModule\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no class form detected`};if(t.length>1)return{migrated:null,reason:`multiple module classes in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=fr(e,i);if(a===-1)return{migrated:null,reason:`unbalanced class braces`};let o=e.slice(i+1,a),s=e.slice(0,n.index),c=e.slice(a+1),l=pr(o,/register\s*\(([^)]*)\)\s*:\s*void\s*\{/),u=pr(o,/contributors\s*\(\s*\)\s*:\s*ContributorRegistrations\s*\{/),d=pr(o,/routes\s*\(\s*\)\s*:\s*[A-Za-z|[\]\s]+\{/);if(!d)return{migrated:null,reason:`routes() method missing or signature unrecognized`};let f=hr(s),p=``;return l&&(p+=` register(container) {${mr(l,4,6)} },\n\n`),u&&(p+=` contributors() {${mr(u,4,6)} },\n\n`),p+=` routes() {${mr(d,4,6)} },`,{migrated:`${f}${`export const ${r} = defineModule({
|
|
2301
2306
|
name: '${r}',
|
|
2302
2307
|
build: () => ({
|
|
2303
2308
|
${p}
|
|
2304
2309
|
}),
|
|
2305
|
-
})`}${c}`}}function vr(e){if(/export\s+class\s+\w+Module\s+implements\s+AppModule\s*\{/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+const\s+(\w+Module)\s*=\s*defineModule\s*\(\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no defineModule form detected`};if(t.length>1)return{migrated:null,reason:`multiple defineModule blocks in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=
|
|
2306
|
-
`||e[l]===`\r`);)l++;let u=e.slice(l),d=/build\s*:\s*\([^)]*\)\s*=>\s*\(\s*\{/g.exec(s);if(!d)return{migrated:null,reason:`build: () => ({...}) not found in defineModule`};let f=d.index+d[0].length-1,p=
|
|
2310
|
+
})`}${c}`}}function vr(e){if(/export\s+class\s+\w+Module\s+implements\s+AppModule\s*\{/.test(e))return{migrated:null,reason:`already in target form`};let t=[...e.matchAll(/export\s+const\s+(\w+Module)\s*=\s*defineModule\s*\(\s*\{/g)];if(t.length===0)return{migrated:null,reason:`no defineModule form detected`};if(t.length>1)return{migrated:null,reason:`multiple defineModule blocks in one file — migrate manually`};let n=t[0],r=n[1],i=n.index+n[0].length-1,a=fr(e,i);if(a===-1)return{migrated:null,reason:`unbalanced defineModule braces`};let o=e.indexOf(`)`,a);if(o===-1)return{migrated:null,reason:`unbalanced defineModule call parens`};let s=e.slice(i+1,a),c=e.slice(0,n.index),l=o+1;for(;l<e.length&&(e[l]===`
|
|
2311
|
+
`||e[l]===`\r`);)l++;let u=e.slice(l),d=/build\s*:\s*\([^)]*\)\s*=>\s*\(\s*\{/g.exec(s);if(!d)return{migrated:null,reason:`build: () => ({...}) not found in defineModule`};let f=d.index+d[0].length-1,p=fr(s,f);if(p===-1)return{migrated:null,reason:`unbalanced build() braces`};let m=s.slice(f+1,p),h=pr(m,/register\s*\(([^)]*)\)\s*\{/),g=pr(m,/contributors\s*\(\s*\)\s*\{/),_=pr(m,/routes\s*\(\s*\)\s*\{/);if(!_)return{migrated:null,reason:`routes() method missing inside build()`};let v=gr(c,{container:h!==null,appModule:!0,moduleRoutes:!0,contributorRegistrations:g!==null}),y=``;return h!==null&&(y+=` register(container: Container): void {${mr(h,6,4)} }\n\n`),g!==null&&(y+=` contributors(): ContributorRegistrations {${mr(g,6,4)} }\n\n`),y+=` routes(): ModuleRoutes {${mr(_,6,4)} }`,{migrated:`${v}${`export class ${r} implements AppModule {
|
|
2307
2312
|
${y}
|
|
2308
2313
|
}
|
|
2309
|
-
`}${u}`}}function yr(e,t){return t===`class`?vr(e):_r(e)}function br(e,t){let n=e,r=!1;if(t===`define`){/\bAppModuleClass\b/.test(n)&&(n=n.replaceAll(/\bAppModuleClass\b/g,`AppModuleEntry`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)(?![(.])/g,`$1()`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}else{/\bAppModuleEntry\b/.test(n)&&(n=n.replaceAll(/\bAppModuleEntry\b/g,`AppModuleClass`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)\s*\(\s*\)/g,`$1`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}return r?{migrated:n}:{migrated:null,reason:`no changes needed`}}async function xr(e){let t=[];return await n(v(e),0),t;async function n(e,r){let i;try{i=await
|
|
2314
|
+
`}${u}`}}function yr(e,t){return t===`class`?vr(e):_r(e)}function br(e,t){let n=e,r=!1;if(t===`define`){/\bAppModuleClass\b/.test(n)&&(n=n.replaceAll(/\bAppModuleClass\b/g,`AppModuleEntry`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)(?![(.])/g,`$1()`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}else{/\bAppModuleEntry\b/.test(n)&&(n=n.replaceAll(/\bAppModuleEntry\b/g,`AppModuleClass`),r=!0);let e=/(=\s*\[)([\s\S]*?)(])/,t=e.exec(n);if(t){let i=t[1],a=t[3],o=t[2],s=o.replaceAll(/(\b\w+Module)\s*\(\s*\)/g,`$1`);s!==o&&(n=n.replace(e,`${i}${s}${a}`),r=!0)}}return r?{migrated:n}:{migrated:null,reason:`no changes needed`}}async function xr(e){let t=[];return await n(v(e),0),t;async function n(e,r){let i;try{i=await ae(e)}catch{return}for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=h(e,a),o;try{o=await se(i)}catch{continue}o.isDirectory()?await n(i,r+1):(a.endsWith(`.module.ts`)||a===`index.ts`&&r===1)&&t.push(i)}}}async function Sr(e,t){let n=0;return await r(e,t),n;async function r(e,t){let i;try{i=await ae(e)}catch{return}await w(t,{recursive:!0});for(let a of i){if(a===`node_modules`||a===`dist`||a===`.kickjs`)continue;let i=h(e,a),o=h(t,a),s;try{s=await se(i)}catch{continue}s.isDirectory()?await r(i,o):(await ie(i,o),n++)}}}function Cr(e){return h(e,`.kickjs`,`codemod-backups`,`${new Date().toISOString().replaceAll(/[:.]/g,`-`)}-modules`)}async function wr(e,t){let{dryRun:n=!1,cwd:r=process.cwd(),target:i}=t,a=t.backup??!n,o=await xr(e),s=await T(h(e,`index.ts`),`utf-8`).then(()=>!0,()=>!1),c=null;a&&(o.length>0||s)&&(c=Cr(r),await Sr(e,c));let l=[];for(let e of o){let t=yr(await T(e,`utf-8`),i);if(t.migrated==null){l.push({path:e,status:`skipped`,reason:t.reason});continue}n||await E(e,t.migrated,`utf-8`),l.push({path:e,status:`migrated`})}let u=h(e,`index.ts`),d=null;try{d=await T(u,`utf-8`)}catch{return{target:i,files:l,indexStatus:`not-found`,indexPath:u,backupDir:c}}let f=br(d,i);return f.migrated==null?{target:i,files:l,indexStatus:`skipped`,indexPath:u,indexReason:f.reason,backupDir:c}:(n||await E(u,f.migrated,`utf-8`),{target:i,files:l,indexStatus:`migrated`,indexPath:u,backupDir:c})}async function Tr(e,t){let n=await xr(e),r=[],i=t===`define`?/export\s+class\s+\w+Module\s+implements\s+AppModule\s*\{/:/export\s+const\s+\w+Module\s*=\s*defineModule\s*\(/;for(let e of n){let t=await T(e,`utf-8`);i.test(t)&&r.push(e)}return r}async function Er(e){let{name:t,outDir:n}=e,r=R(t),i=B(t),a=z(t),o=e.queue??`${i}-queue`,s=[];return await(async(e,t)=>{let r=h(n,e);await P(r,t),s.push(r)})(`${i}.job.ts`,`import { Inject } from '@forinda/kickjs'
|
|
2310
2315
|
import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-queue'
|
|
2311
2316
|
|
|
2312
2317
|
/**
|
|
@@ -2339,7 +2344,7 @@ export class ${r}Job {
|
|
|
2339
2344
|
// Handle high-priority variant of this job
|
|
2340
2345
|
}
|
|
2341
2346
|
}
|
|
2342
|
-
`),s}const Dr={string:{ts:`string`,zod:`z.string()`},text:{ts:`string`,zod:`z.string()`},number:{ts:`number`,zod:`z.number()`},int:{ts:`number`,zod:`z.number().int()`},float:{ts:`number`,zod:`z.number()`},boolean:{ts:`boolean`,zod:`z.boolean()`},date:{ts:`string`,zod:`z.string().datetime()`},email:{ts:`string`,zod:`z.string().email()`},url:{ts:`string`,zod:`z.string().url()`},uuid:{ts:`string`,zod:`z.string().uuid()`},json:{ts:`any`,zod:`z.any()`}};function Or(e){return e.map(e=>{let t=e.indexOf(`:`);if(t===-1)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let n=e.slice(0,t),r=e.slice(t+1);if(!n||!r)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let i=!1;r.endsWith(`:optional`)&&(r=r.slice(0,-9),i=!0),n.endsWith(`?`)&&(n=n.slice(0,-1),i=!0),r.endsWith(`?`)&&(r=r.slice(0,-1),i=!0);let a=r;if(a.startsWith(`enum:`)){let e=a.slice(5).split(`,`);return{name:n,type:`enum`,tsType:e.map(e=>`'${e}'`).join(` | `),zodType:`z.enum([${e.map(e=>`'${e}'`).join(`, `)}])`,optional:i}}let o=Dr[a];if(!o){let e=[...Object.keys(Dr),`enum:a,b,c`].join(`, `);throw Error(`Unknown field type: "${a}". Valid types: ${e}`)}return{name:n,type:a,tsType:o.ts,zodType:o.zod,optional:i}})}async function kr(e){let{name:t,fields:n,modulesDir:r,repo:i=`inmemory`,tokenScope:a=`app`,style:o=`define`}=e,s=e.pluralize!==!1,c=
|
|
2347
|
+
`),s}const Dr={string:{ts:`string`,zod:`z.string()`},text:{ts:`string`,zod:`z.string()`},number:{ts:`number`,zod:`z.number()`},int:{ts:`number`,zod:`z.number().int()`},float:{ts:`number`,zod:`z.number()`},boolean:{ts:`boolean`,zod:`z.boolean()`},date:{ts:`string`,zod:`z.string().datetime()`},email:{ts:`string`,zod:`z.string().email()`},url:{ts:`string`,zod:`z.string().url()`},uuid:{ts:`string`,zod:`z.string().uuid()`},json:{ts:`any`,zod:`z.any()`}};function Or(e){return e.map(e=>{let t=e.indexOf(`:`);if(t===-1)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let n=e.slice(0,t),r=e.slice(t+1);if(!n||!r)throw Error(`Invalid field: "${e}". Use format: name:type (e.g. title:string)`);let i=!1;r.endsWith(`:optional`)&&(r=r.slice(0,-9),i=!0),n.endsWith(`?`)&&(n=n.slice(0,-1),i=!0),r.endsWith(`?`)&&(r=r.slice(0,-1),i=!0);let a=r;if(a.startsWith(`enum:`)){let e=a.slice(5).split(`,`);return{name:n,type:`enum`,tsType:e.map(e=>`'${e}'`).join(` | `),zodType:`z.enum([${e.map(e=>`'${e}'`).join(`, `)}])`,optional:i}}let o=Dr[a];if(!o){let e=[...Object.keys(Dr),`enum:a,b,c`].join(`, `);throw Error(`Unknown field type: "${a}". Valid types: ${e}`)}return{name:n,type:a,tsType:o.ts,zodType:o.zod,optional:i}})}async function kr(e){let{name:t,fields:n,modulesDir:r,repo:i=`inmemory`,tokenScope:a=`app`,style:o=`define`}=e,s=e.pluralize!==!1,c=B(t),l=R(t),u=s?$t(c):c,d=s?en(l):l,f=h(r,u),p=[],m=async(e,t)=>{let n=h(f,e);await P(n,t),p.push(n)};await m(`${c}.module.ts`,Sn({pascal:l,kebab:c,plural:u,repo:i,style:o})),await m(`${c}.constants.ts`,Pn({pascal:l,kebab:c})),await m(`${c}.controller.ts`,wn({pascal:l,kebab:c,plural:u,pluralPascal:d})),await m(`${c}.service.ts`,Nn({pascal:l,kebab:c})),await m(`dtos/create-${c}.dto.ts`,Ar(l,n)),await m(`dtos/update-${c}.dto.ts`,jr(l,n)),await m(`dtos/${c}-response.dto.ts`,Mr(l,n)),await m(`${c}.repository.ts`,On({pascal:l,kebab:c,dtoPrefix:`./dtos`,tokenScope:a}));let g=i===`inmemory`,_=g?`in-memory-${c}`:`${B(i)}-${c}`,v=g?kn({pascal:l,kebab:c,repoPrefix:`.`,dtoPrefix:`./dtos`}):An({pascal:l,kebab:c,repoType:i,repoPrefix:`.`,dtoPrefix:`./dtos`});return await m(`${_}.repository.ts`,v),await zn(r,l,u,c,o),p}function Ar(e,t){return`import { z } from 'zod'
|
|
2343
2348
|
|
|
2344
2349
|
export const create${e}Schema = z.object({
|
|
2345
2350
|
${t.map(e=>{let t=e.zodType;return` ${e.name}: ${t}${e.optional?`.optional()`:``},`}).join(`
|
|
@@ -2362,7 +2367,7 @@ ${t.map(e=>` ${e.name}${e.optional?`?`:``}: ${e.tsType}`).join(`
|
|
|
2362
2367
|
createdAt: string
|
|
2363
2368
|
updatedAt: string
|
|
2364
2369
|
}
|
|
2365
|
-
`}async function Nr(e){let{name:t,moduleName:n,modulesDir:r}=e,i=e.pluralize??!0,a=
|
|
2370
|
+
`}async function Nr(e){let{name:t,moduleName:n,modulesDir:r}=e,i=e.pluralize??!0,a=B(t),o=R(t),s=[],c;if(e.outDir)c=v(e.outDir);else if(n){let e=B(n),t=i?$t(e):e;c=v(h(r??`src/modules`,t,`__tests__`))}else c=v(`src/__tests__`);let l=h(c,`${a}.test.ts`);return await P(l,`import { describe, it, expect, beforeEach } from 'vitest'
|
|
2366
2371
|
import { Container } from '@forinda/kickjs'
|
|
2367
2372
|
|
|
2368
2373
|
describe('${o}', () => {
|
|
@@ -2385,9 +2390,9 @@ describe('${o}', () => {
|
|
|
2385
2390
|
expect(true).toBe(true)
|
|
2386
2391
|
})
|
|
2387
2392
|
})
|
|
2388
|
-
`),s.push(l),s}const Pr=[`classes`,`tokens`,`injects`,`pluginsAndAdapters`,`augmentations`,`contextKeys`,`routes`,`moduleMounts`,`globPatterns`];function Fr(e){if(!e||typeof e!=`object`)return!1;let t=e;return Pr.every(e=>Array.isArray(t[e]))}var Ir=class e{path;prev;next=new Map;nextSig=new Map;constructor(e,t){this.path=e,this.prev=t}static async load(t){let n=h(t,`scan.json`),r=new Map;try{let e=await C(n,`utf-8`),t=JSON.parse(e);if(t.version===2&&t.files)for(let[e,n]of Object.entries(t.files))n&&typeof n.sig==`string`&&Fr(n.extract)&&r.set(e,n)}catch{}return new e(n,r)}static async signature(e){try{let t=await le(e);return`${t.mtimeMs}:${t.size}`}catch{return null}}get(e,t){let n=this.prev.get(e);return n&&n.sig===t?n.extract:null}set(e,t,n){this.next.set(e,n),this.nextSig.set(e,t)}cachedFiles(){return[...this.prev.keys()]}peek(e){return this.prev.get(e)?.extract??null}carry(e){let t=this.prev.get(e);return t?(this.next.set(e,t.extract),this.nextSig.set(e,t.sig),!0):!1}async save(){let e={};for(let[t,n]of this.next){let r=this.nextSig.get(t);r&&(e[t]={sig:r,extract:n})}let t={version:2,files:e};try{await oe(f(this.path),{recursive:!0}),await w(this.path,JSON.stringify(t),`utf-8`)}catch{}}};let Lr=null;function Rr(){return Lr??=new Set(ei),Lr}const zr=new Set([`Get`,`Post`,`Put`,`Delete`,`Patch`]);function H(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}function U(e,t){if(Array.isArray(e)){for(let n of e)U(n,t);return}if(H(e)){t(e);for(let n of Object.keys(e)){if(n===`type`)continue;let r=e[n];typeof r==`object`&&r&&U(r,t)}}}function W(e){if(!H(e))return null;if(e.type===`Literal`&&typeof e.value==`string`)return e.value;if(e.type===`TemplateLiteral`){let t=e.quasis,n=e.expressions;if(t?.length===1&&(n?.length??0)===0){let e=t[0].value?.cooked;return typeof e==`string`?e:null}}return null}function G(e){return H(e)&&e.type===`Identifier`?e.name:null}function Br(e){return G(e.callee)}function K(e,t){if(!e||e.type!==`ObjectExpression`)return null;for(let n of e.properties??[]){if(n.type!==`Property`)continue;let e=n.key;if((G(e)??(e.type===`Literal`?String(e.value):W(e)))===t)return n.value}return null}function Vr(e){let t=e.arguments?.[0];return H(t)&&t.type===`ObjectExpression`?t:null}function Hr(e,t){let n=K(e,t);if(!H(n)||n.type!==`ArrayExpression`)return[];let r=[];for(let e of n.elements??[]){let t=W(e);t!==null&&r.push(t)}return r}function Ur(e,t){return _(t,e).split(y).join(`/`)}function Wr(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function Gr(e,t){for(let n of e.implements??[]){let e=n.expression??n;if(G(e)===t)return!0;if(e.type===`TSQualifiedName`||e.type===`MemberExpression`){let n=e.right??e.property;if(n&&G(n)===t)return!0}}return!1}function Kr(e){return e.decorators??[]}function qr(e){let t=e.expression;if(!H(t)||t.type!==`CallExpression`)return null;let n=Br(t);return n?{name:n,call:t}:null}function Jr(e){let t=new Map,n=new Set;for(let r of e.body??[]){if(r.type===`ImportDeclaration`){let e=W(r.source)??``;for(let n of r.specifiers??[]){let r=G(n.local);r&&t.set(r,{source:e})}continue}let e=r.type===`VariableDeclaration`?r:r.type===`ExportNamedDeclaration`&&H(r.declaration)?r.declaration:null;if(H(e)&&e.type===`VariableDeclaration`)for(let t of e.declarations??[]){let e=G(t.id);e&&n.add(e)}}return{imports:t,topLevelConsts:n}}function Yr(e,t){let n=t.imports.get(e);return n?{identifier:e,source:n.source}:t.topLevelConsts.has(e)?{identifier:e,source:``}:{identifier:e,source:null}}function Xr(e,t,n){let r=G(K(e,t));return r?Yr(r,n):null}function Zr(e,t){for(let n of e){let e=qr(n);if(!e||e.name!==`ApiQueryParams`)continue;let r=e.call.arguments?.[0],i=null;if(H(r)&&r.type===`ObjectExpression`)i=r;else{let e=G(r);if(e){let n=t.get(e);n&&n.type===`ObjectExpression`&&(i=n)}}return{filterable:Hr(i,`filterable`),sortable:Hr(i,`sortable`),searchable:Hr(i,`searchable`)}}return null}function Qr(e,t,n){let r;try{let n=pe(t,e);if(n.errors.length>0)return null;r=n.program}catch{return null}let i=Ur(t,n),a=Jr(r),o=[],s=[],c=[],l=[],u=[],d=[],f=[],p=[],m=[],h=new Set,g=new Set,_=new Set,v=new Map;for(let e of r.body??[]){let t=e.type===`VariableDeclaration`?e:e.type===`ExportNamedDeclaration`&&H(e.declaration)?e.declaration:null;if(H(t)&&t.type===`VariableDeclaration`)for(let e of t.declarations??[]){let t=G(e.id);t&&H(e.init)&&v.set(t,e.init)}}let y=[];for(let e of r.body??[])if(e.type===`ExportNamedDeclaration`&&H(e.declaration)){let t=e.declaration;t.type===`ClassDeclaration`&&y.push({cls:t,isDefault:!1})}else if(e.type===`ExportDefaultDeclaration`&&H(e.declaration)){let t=e.declaration;t.type===`ClassDeclaration`&&y.push({cls:t,isDefault:!0})}for(let{cls:e,isDefault:n}of y){let r=G(e.id);if(!r)continue;let a=null;for(let t of Kr(e)){let e=qr(t);if(e&&Rr().has(e.name)){a=e.name;break}}a?o.push({className:r,decorator:a,filePath:t,relativePath:i,isDefault:n}):Gr(e,`AppModule`)&&o.push({className:r,decorator:`Module`,filePath:t,relativePath:i,isDefault:n})}for(let e of r.body??[]){if(e.type!==`ExportNamedDeclaration`||!H(e.declaration))continue;let n=e.declaration;if(n.type===`VariableDeclaration`)for(let e of n.declarations??[]){let n=G(e.id),r=e.init;!n||!H(r)||r.type!==`CallExpression`||Br(r)===`defineModule`&&(o.some(e=>e.className===n)||o.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!1}))}}U(r,e=>{if(e.type===`VariableDeclarator`){let n=e.init;if(H(n)&&n.type===`CallExpression`&&Br(n)===`createToken`){let r=W(n.arguments?.[0]);r!==null&&(_.add(n),s.push({name:r,variable:G(e.id),filePath:t,relativePath:i}))}return}if(e.type!==`CallExpression`){if(e.type===`Decorator`){let n=qr(e);if(n?.name===`Inject`){let e=W(n.call.arguments?.[0]);e!==null&&c.push({name:e,filePath:t,relativePath:i})}}return}let n=e.callee,r=Br(e);if(r===`createToken`&&!_.has(e)){let n=W(e.arguments?.[0]);n!==null&&s.push({name:n,variable:null,filePath:t,relativePath:i});return}if(r===`defineAdapter`||r===`definePlugin`){let n=W(K(Vr(e),`name`));if(n!==null){let e=r===`definePlugin`?`plugin`:`adapter`,a=`${r}::${n}::${t}`;h.has(a)||(h.add(a),l.push({kind:e,name:n,filePath:t,relativePath:i}))}return}if(r===`defineAugmentation`){let n=e.arguments??[],r=W(n[0]);if(r!==null){let e=H(n[1])&&n[1].type===`ObjectExpression`?n[1]:null;u.push({name:r,description:W(K(e,`description`)),example:W(K(e,`example`)),filePath:t,relativePath:i})}return}if(r===`defineContextDecorator`||r===`defineHttpContextDecorator`){let n=W(K(Vr(e),`key`));n!==null&&!g.has(n)&&(g.add(n),d.push({key:n,filePath:t,relativePath:i}));return}if(H(n)&&n.type===`CallExpression`){let r=n.callee;if(H(r)&&r.type===`MemberExpression`&&G(r.property)===`withParams`){let n=G(r.object);if(n===`defineContextDecorator`||n===`defineHttpContextDecorator`){let n=W(K(Vr(e),`key`));n!==null&&!g.has(n)&&(g.add(n),d.push({key:n,filePath:t,relativePath:i}))}}return}if(H(n)&&n.type===`MemberExpression`&&G(n.property)===`glob`){let t=n.object;H(t)&&t.type===`MetaProperty`&&U(e.arguments,e=>{let t=W(e);t!==null&&m.push(t)})}});let b=[];U(r,e=>{if(e.type===`ClassDeclaration`||e.type===`ClassExpression`){let t=G(e.id);t&&b.push({cls:e,className:t})}});for(let{cls:e,className:n}of b){let r=o.find(e=>e.className===n),s=e.body?.body;if(Gr(e,`AppAdapter`))for(let e of s??[]){if(e.type!==`PropertyDefinition`||G(e.key)!==`name`)continue;let n=W(e.value);if(n===null)continue;let r=`class::${n}::${t}`;h.has(r)||(h.add(r),l.push({kind:`adapter`,name:n,filePath:t,relativePath:i}));break}for(let e of s??[]){if(e.type!==`MethodDefinition`)continue;let o=G(e.key);if(!o)continue;if(o===`routes`){$r(e.value,p);continue}if(!r)continue;let s=Kr(e),c=Zr(s,v);for(let e of s){let r=qr(e);if(!r||!zr.has(r.name))continue;let s=r.call.arguments??[],l=W(s[0]),u=l&&l.length>0?l:`/`,d=H(s[1])&&s[1].type===`ObjectExpression`?s[1]:null;f.push({controller:n,method:o,httpMethod:r.name.toUpperCase(),path:u,pathParams:Wr(u),queryFilterable:c?.filterable??null,querySortable:c?.sortable??null,querySearchable:c?.searchable??null,bodySchema:Xr(d,`body`,a),querySchema:Xr(d,`query`,a),paramsSchema:Xr(d,`params`,a),filePath:t,relativePath:i})}}}return U(r,e=>{if(e.type!==`Property`||G(e.key)!==`routes`)return;let t=e.value;H(t)&&(t.type===`FunctionExpression`||t.type===`ArrowFunctionExpression`)&&$r(t,p)}),{classes:o,tokens:s,injects:c,pluginsAndAdapters:l,augmentations:u,contextKeys:d,routes:f,moduleMounts:p,globPatterns:/\.module\.[mc]?[tj]sx?$/.test(t)?m:[]}}function $r(e,t){let n=[],r=[];U(e.body,e=>{if(e.type!==`Property`)return;let t=G(e.key);if(t===`path`){let t=W(e.value);t!==null&&n.push(t)}else if(t===`controller`){let t=G(e.value);t&&/^[A-Z]/.test(t)&&r.push(t)}});let i=Math.min(n.length,r.length);for(let e=0;e<i;e++)t.push({controller:r[e],mountPath:n[e]})}const ei=[`Service`,`Controller`,`Repository`,`Injectable`,`Component`,`Module`],ti=[`.ts`,`.tsx`,`.mts`,`.cts`],ni=[`node_modules`,`.kickjs`,`dist`,`build`,`.test.`,`.spec.`,`.d.ts`],ri=new RegExp(String.raw`@(${ei.join(`|`)})\s*\([^)]*\)`+String.raw`(?:\s*@[A-Z]\w*(?:\s*\([^)]*\))?)*`+String.raw`\s*export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`,`g`),ii=new RegExp(String.raw`export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppModule\b`,`g`),ai=/export\s+const\s+(\w+)\s*(?::\s*[^=]+)?=\s*defineModule\s*(?:<[^>]*>)?\s*\(/g,oi=/(?:export\s+)?const\s+(\w+)\s*(?::\s*[^=]+)?=\s*createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,si=/createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,ci=/@Inject\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,li=/\b(defineAdapter|definePlugin)\s*(?:<[^>]*>)?\s*\(/g,ui=/\b(?:defineContextDecorator|defineHttpContextDecorator)\s*(?:\.withParams\s*<(?:[^<>]|<[^<>]*>)*>\s*\(\s*\))?\s*(?:<(?:[^<>]|<[^<>]*>)*>)?\s*\(/g,di=new RegExp(String.raw`export\s+(?:default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppAdapter\b`,`g`),fi=/\bname\s*(?::\s*[^=]+)?=\s*['"`]([^'"`]+)['"`]/,pi=/\bdefineAugmentation\s*\(\s*['"`]([^'"`]+)['"`]\s*(,\s*\{)?/g,mi=new RegExp(String.raw`@(${[`Get`,`Post`,`Put`,`Delete`,`Patch`].join(`|`)})\s*\(`,`g`);function hi(e,t){let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`(`)n++;else if(t===`)`&&(n--,n===0))return r}return-1}function gi(e,t){let n=t;for(;n<e.length;){for(;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]!==`@`)break;let t=e.slice(n).match(/^@([A-Z]\w*)/);if(!t)break;for(n+=t[0].length;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]===`(`){let t=hi(e,n);if(t<0)return null;n=t+1}}for(;n<e.length&&/\s/.test(e[n]);)n++;for(let t of[`public`,`private`,`protected`])if(e.slice(n,n+t.length)===t&&/\s/.test(e.charAt(n+t.length))){for(n+=t.length;n<e.length&&/\s/.test(e[n]);)n++;break}if(e.slice(n,n+5)===`async`&&/\s/.test(e.charAt(n+5)))for(n+=5;n<e.length&&/\s/.test(e[n]);)n++;let r=e.slice(n).match(/^([a-zA-Z_]\w*)\s*\(/);return r?{methodName:r[1],endPos:n+r[0].length}:null}function _i(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function vi(e,t){let n=e.endsWith(`/`)?e.slice(0,-1):e;return!t||t===`/`?n||`/`:n+(t.startsWith(`/`)?t:`/`+t)||`/`}const yi=/\b(?:public\s+|private\s+|protected\s+)?routes\s*\([^)]*\)\s*(?::\s*[A-Za-z_][\w<>[\]\s,|]*\s*)?\{/g,bi=/\bpath\s*:\s*['"`]([^'"`]*)['"`]/g,xi=/\bcontroller\s*:\s*([A-Z]\w*)\b/g,Si=/\bimport\.meta\.glob\s*\(/g;function Ci(e){let t=[];for(Si.lastIndex=0;Si.exec(e)!==null;){let n=Si.lastIndex-1,r=hi(e,n);if(r<0)continue;let i=e.slice(n+1,r),a=/['"`]([^'"`]+)['"`]/g,o;for(;(o=a.exec(i))!==null;)t.push(o[1])}return t}function wi(e){let t=e.replace(/[.+^$()|[\]\\]/g,`\\$&`).replace(/\?/g,`.`).replace(/\*\*\//g,`___DOUBLESTAR_SLASH___`).replace(/\*\*/g,`___DOUBLESTAR___`).replace(/\*/g,`[^/]*`).replace(/___DOUBLESTAR_SLASH___/g,`(?:.+/)?`).replace(/___DOUBLESTAR___/g,`.*`);return RegExp(`^`+t+`$`)}function Ti(e,t){let n=e.startsWith(`./`)?e:`./`+e,r=!1;for(let e of t){let t=e.startsWith(`!`);wi(t?e.slice(1):e).test(n)&&(r=!t)}return r}function Ei(e){let t=[];yi.lastIndex=0;let n;for(;(n=yi.exec(e))!==null;){let r=e.indexOf(`{`,n.index+n[0].length-1);if(r<0)continue;let i=Ri(e,r);if(i<0)continue;let a=e.slice(r+1,i),o=[];bi.lastIndex=0;let s;for(;(s=bi.exec(a))!==null;)o.push(s[1]??``);let c=[];xi.lastIndex=0;let l;for(;(l=xi.exec(a))!==null;)c.push(l[1]);let u=Math.min(o.length,c.length);for(let e=0;e<u;e++)t.push({controller:c[e],mountPath:o[e]})}return t}function Di(e,t){let n=new RegExp(String.raw`\b${t}\s*:\s*([A-Za-z_$][\w$]*)`,`g`).exec(e);return n?n[1]:null}function Oi(e,t){let n=new RegExp(String.raw`import\s*(?:type\s+)?\{[^}]*\b${t}\b[^}]*\}\s*from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(n)return n[1];let r=new RegExp(String.raw`import\s+(?:type\s+)?${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(r)return r[1];let i=new RegExp(String.raw`import\s*\*\s*as\s+${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);return i?i[1]:new RegExp(String.raw`(?:^|\n)\s*(?:export\s+)?const\s+${t}\b`).test(e)?``:null}function ki(e,t){let n=/@ApiQueryParams\s*\(\s*([\s\S]*?)\s*\)\s*$/.exec(e);if(!n){let n=/@ApiQueryParams\s*\(([\s\S]*?)\)/.exec(e);return n?Ai(n[1].trim(),t):null}return Ai(n[1].trim(),t)}function Ai(e,t){if(e.startsWith(`{`))return Mi(e);let n=/^([A-Za-z_]\w*)/.exec(e);if(n){let e=n[1],r=new RegExp(String.raw`const\s+${e}\s*(?::\s*[^=]+)?=\s*(\{[\s\S]*?\n\})`,`m`).exec(t);if(r)return Mi(r[1])}return{filterable:[],sortable:[],searchable:[]}}function ji(e,t){let n=new RegExp(String.raw`${t}\s*:\s*\[([\s\S]*?)\]`).exec(e);return n?Array.from(n[1].matchAll(/['"`]([^'"`]+)['"`]/g)).map(e=>e[1]):[]}function Mi(e){return{filterable:ji(e,`filterable`),sortable:ji(e,`sortable`),searchable:ji(e,`searchable`)}}async function Ni(e,t){let n=t.extensions??ti,r=t.exclude??ni,i=[],a;try{a=await se(e,{withFileTypes:!0,encoding:`utf-8`})}catch{return i}for(let o of a){let a=h(e,o.name),s=_(t.cwd,a);r.some(e=>s.includes(e))||(o.isDirectory()?i.push(...await Ni(a,t)):o.isFile()&&n.some(e=>o.name.endsWith(e))&&i.push(a))}return i}function q(e,t){return _(t,e).split(y).join(`/`)}function Pi(e,t,n){let r=[],i=q(t,n);ri.lastIndex=0;let a;for(;(a=ri.exec(e))!==null;){let[,e,n,o]=a;r.push({className:o,decorator:e,filePath:t,relativePath:i,isDefault:!!n})}ii.lastIndex=0;let o;for(;(o=ii.exec(e))!==null;){let[,e,n]=o;r.some(e=>e.className===n&&e.filePath===t)||r.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!!e})}ai.lastIndex=0;let s;for(;(s=ai.exec(e))!==null;){let[,e]=s;r.some(n=>n.className===e&&n.filePath===t)||r.push({className:e,decorator:`Module`,filePath:t,relativePath:i,isDefault:!1})}return r}function Fi(e,t,n){let r=[],i=q(t,n),a=new Set;oi.lastIndex=0;let o;for(;(o=oi.exec(e))!==null;){let[e,n,s]=o;a.add(e),r.push({name:s,variable:n,filePath:t,relativePath:i})}for(si.lastIndex=0;(o=si.exec(e))!==null;)a.has(o[0])||r.push({name:o[1],variable:null,filePath:t,relativePath:i});return r}function Ii(e,t,n,r,i=new Map){let a=[];if(r.length===0)return a;let o=q(t,n),s=[];for(let t of r){let n=new RegExp(String.raw`class\s+${t.className}\b`).exec(e);n?.index!==void 0&&s.push({cls:t,start:n.index})}s.sort((e,t)=>e.start-t.start);for(let n=0;n<s.length;n++){let{cls:r,start:c}=s[n],l=n+1<s.length?s[n+1].start:e.length,u=e.slice(c,l);mi.lastIndex=0;let d;for(;(d=mi.exec(u))!==null;){let n=d[1],s=d.index,c=mi.lastIndex-1,l=hi(u,c);if(l<0)continue;let f=u.slice(c+1,l),p=f.match(/^\s*['"`]([^'"`]*)['"`]/),m=p&&p[1].length>0?p[1]:`/`,h=gi(u,l+1);if(!h)continue;let{methodName:g,endPos:_}=h;mi.lastIndex=_;let v=ki(u.slice(s,_),e),y=Di(f,`body`),b=Di(f,`query`),x=Di(f,`params`),ee=i.get(r.className)??``,S=ee?vi(ee,m):m;a.push({controller:r.className,method:g,httpMethod:n.toUpperCase(),path:m,pathParams:_i(S),queryFilterable:v?.filterable??null,querySortable:v?.sortable??null,querySearchable:v?.searchable??null,bodySchema:y?{identifier:y,source:Oi(e,y)}:null,querySchema:b?{identifier:b,source:Oi(e,b)}:null,paramsSchema:x?{identifier:x,source:Oi(e,x)}:null,filePath:t,relativePath:o})}}return a}function Li(e,t,n){let r=[],i=q(t,n);ci.lastIndex=0;let a;for(;(a=ci.exec(e))!==null;)r.push({name:a[1],filePath:t,relativePath:i});return r}function Ri(e,t){let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`{`)n++;else if(t===`}`&&(n--,n===0))return r}return-1}function zi(e,t,n){let r=[],i=q(t,n),a=new Set;li.lastIndex=0;let o;for(;(o=li.exec(e))!==null;){let n=o[1],s=li.lastIndex-1,c=hi(e,s);if(c<0)continue;let l=e.slice(s+1,c),u=/\bname\s*:\s*['"`]([^'"`]+)['"`]/.exec(l);if(!u)continue;let d=u[1],f=`${n}::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:n===`definePlugin`?`plugin`:`adapter`,name:d,filePath:t,relativePath:i}))}di.lastIndex=0;let s;for(;(s=di.exec(e))!==null;){let n=s.index,o=e.indexOf(`{`,n);if(o<0)continue;let c=Ri(e,o);if(c<0)continue;let l=e.slice(o+1,c),u=fi.exec(l);if(!u)continue;let d=u[1],f=`class::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:`adapter`,name:d,filePath:t,relativePath:i}))}return r}function Bi(e,t,n){let r=[],i=q(t,n),a=new Set;for(ui.lastIndex=0;ui.exec(e)!==null;){let n=ui.lastIndex-1,o=hi(e,n);if(o<0)continue;let s=e.slice(n+1,o),c=/\bkey\s*:\s*['"`]([^'"`]+)['"`]/.exec(s);if(!c)continue;let l=c[1];a.has(l)||(a.add(l),r.push({key:l,filePath:t,relativePath:i}))}return r}function Vi(e,t,n){let r=[],i=q(t,n);pi.lastIndex=0;let a;for(;(a=pi.exec(e))!==null;){let n=a[1],o=null,s=null;if(a[2]){let t=e.indexOf(`{`,a.index+a[0].length-1);if(t>=0){let n=Ri(e,t);if(n>=0){let r=e.slice(t+1,n);o=Hi(r,`description`),s=Hi(r,`example`)}}}r.push({name:n,description:o,example:s,filePath:t,relativePath:i})}return r}function Hi(e,t){let n=RegExp(`\\b${t}\\s*:\\s*(['"\`])`,`g`).exec(e);if(!n)return null;let r=n[1],i=n.index+n[0].length,a=i,o=null;for(;a<e.length;){let t=e[a];if(t===`\\`){a+=2;continue}if(t===r){o=e.slice(i,a);break}a++}return o===null?null:o.replace(/\\(.)/g,(e,t)=>t===`n`?`
|
|
2389
|
-
`:t===`t`?` `:t===`r`?`\r`:t)}const Ui=[`src/config/index.ts`,`src/config/env.ts`,`src/config.ts`,`src/env.ts`];async function Wi(e,t){let n=t===`src/env.ts`?Ui:[t];for(let t of n){let n=v(e,t),r;try{r=await
|
|
2390
|
-
`)}function
|
|
2393
|
+
`),s.push(l),s}const Pr=[`classes`,`tokens`,`injects`,`pluginsAndAdapters`,`augmentations`,`contextKeys`,`routes`,`moduleMounts`,`globPatterns`];function Fr(e){if(!e||typeof e!=`object`)return!1;let t=e;return Pr.every(e=>Array.isArray(t[e]))}var Ir=class e{path;prev;next=new Map;nextSig=new Map;constructor(e,t){this.path=e,this.prev=t}static async load(t){let n=h(t,`scan.json`),r=new Map;try{let e=await T(n,`utf-8`),t=JSON.parse(e);if(t.version===2&&t.files)for(let[e,n]of Object.entries(t.files))n&&typeof n.sig==`string`&&Fr(n.extract)&&r.set(e,n)}catch{}return new e(n,r)}static async signature(e){try{let t=await se(e);return`${t.mtimeMs}:${t.size}`}catch{return null}}get(e,t){let n=this.prev.get(e);return n&&n.sig===t?n.extract:null}set(e,t,n){this.next.set(e,n),this.nextSig.set(e,t)}cachedFiles(){return[...this.prev.keys()]}peek(e){return this.prev.get(e)?.extract??null}carry(e){let t=this.prev.get(e);return t?(this.next.set(e,t.extract),this.nextSig.set(e,t.sig),!0):!1}async save(){let e={};for(let[t,n]of this.next){let r=this.nextSig.get(t);r&&(e[t]={sig:r,extract:n})}let t={version:2,files:e};try{await w(f(this.path),{recursive:!0}),await E(this.path,JSON.stringify(t),`utf-8`)}catch{}}};let Lr=null;function Rr(){return Lr??=new Set(ei),Lr}const zr=new Set([`Get`,`Post`,`Put`,`Delete`,`Patch`]);function H(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}function U(e,t){if(Array.isArray(e)){for(let n of e)U(n,t);return}if(H(e)){t(e);for(let n of Object.keys(e)){if(n===`type`)continue;let r=e[n];typeof r==`object`&&r&&U(r,t)}}}function W(e){if(!H(e))return null;if(e.type===`Literal`&&typeof e.value==`string`)return e.value;if(e.type===`TemplateLiteral`){let t=e.quasis,n=e.expressions;if(t?.length===1&&(n?.length??0)===0){let e=t[0].value?.cooked;return typeof e==`string`?e:null}}return null}function G(e){return H(e)&&e.type===`Identifier`?e.name:null}function Br(e){return G(e.callee)}function K(e,t){if(!e||e.type!==`ObjectExpression`)return null;for(let n of e.properties??[]){if(n.type!==`Property`)continue;let e=n.key;if((G(e)??(e.type===`Literal`?String(e.value):W(e)))===t)return n.value}return null}function Vr(e){let t=e.arguments?.[0];return H(t)&&t.type===`ObjectExpression`?t:null}function Hr(e,t){let n=K(e,t);if(!H(n)||n.type!==`ArrayExpression`)return[];let r=[];for(let e of n.elements??[]){let t=W(e);t!==null&&r.push(t)}return r}function Ur(e,t){return _(t,e).split(y).join(`/`)}function Wr(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function Gr(e,t){for(let n of e.implements??[]){let e=n.expression??n;if(G(e)===t)return!0;if(e.type===`TSQualifiedName`||e.type===`MemberExpression`){let n=e.right??e.property;if(n&&G(n)===t)return!0}}return!1}function Kr(e){return e.decorators??[]}function qr(e){let t=e.expression;if(!H(t)||t.type!==`CallExpression`)return null;let n=Br(t);return n?{name:n,call:t}:null}function Jr(e){let t=new Map,n=new Set;for(let r of e.body??[]){if(r.type===`ImportDeclaration`){let e=W(r.source)??``;for(let n of r.specifiers??[]){let r=G(n.local);r&&t.set(r,{source:e})}continue}let e=r.type===`VariableDeclaration`?r:r.type===`ExportNamedDeclaration`&&H(r.declaration)?r.declaration:null;if(H(e)&&e.type===`VariableDeclaration`)for(let t of e.declarations??[]){let e=G(t.id);e&&n.add(e)}}return{imports:t,topLevelConsts:n}}function Yr(e,t){let n=t.imports.get(e);return n?{identifier:e,source:n.source}:t.topLevelConsts.has(e)?{identifier:e,source:``}:{identifier:e,source:null}}function Xr(e,t,n){let r=G(K(e,t));return r?Yr(r,n):null}function Zr(e,t){for(let n of e){let e=qr(n);if(!e||e.name!==`ApiQueryParams`)continue;let r=e.call.arguments?.[0],i=null;if(H(r)&&r.type===`ObjectExpression`)i=r;else{let e=G(r);if(e){let n=t.get(e);n&&n.type===`ObjectExpression`&&(i=n)}}return{filterable:Hr(i,`filterable`),sortable:Hr(i,`sortable`),searchable:Hr(i,`searchable`)}}return null}function Qr(e,t,n){let r;try{let n=de(t,e);if(n.errors.length>0)return null;r=n.program}catch{return null}let i=Ur(t,n),a=Jr(r),o=[],s=[],c=[],l=[],u=[],d=[],f=[],p=[],m=[],h=new Set,g=new Set,_=new Set,v=new Map;for(let e of r.body??[]){let t=e.type===`VariableDeclaration`?e:e.type===`ExportNamedDeclaration`&&H(e.declaration)?e.declaration:null;if(H(t)&&t.type===`VariableDeclaration`)for(let e of t.declarations??[]){let t=G(e.id);t&&H(e.init)&&v.set(t,e.init)}}let y=[];for(let e of r.body??[])if(e.type===`ExportNamedDeclaration`&&H(e.declaration)){let t=e.declaration;t.type===`ClassDeclaration`&&y.push({cls:t,isDefault:!1})}else if(e.type===`ExportDefaultDeclaration`&&H(e.declaration)){let t=e.declaration;t.type===`ClassDeclaration`&&y.push({cls:t,isDefault:!0})}for(let{cls:e,isDefault:n}of y){let r=G(e.id);if(!r)continue;let a=null;for(let t of Kr(e)){let e=qr(t);if(e&&Rr().has(e.name)){a=e.name;break}}a?o.push({className:r,decorator:a,filePath:t,relativePath:i,isDefault:n}):Gr(e,`AppModule`)&&o.push({className:r,decorator:`Module`,filePath:t,relativePath:i,isDefault:n})}for(let e of r.body??[]){if(e.type!==`ExportNamedDeclaration`||!H(e.declaration))continue;let n=e.declaration;if(n.type===`VariableDeclaration`)for(let e of n.declarations??[]){let n=G(e.id),r=e.init;!n||!H(r)||r.type!==`CallExpression`||Br(r)===`defineModule`&&(o.some(e=>e.className===n)||o.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!1}))}}U(r,e=>{if(e.type===`VariableDeclarator`){let n=e.init;if(H(n)&&n.type===`CallExpression`&&Br(n)===`createToken`){let r=W(n.arguments?.[0]);r!==null&&(_.add(n),s.push({name:r,variable:G(e.id),filePath:t,relativePath:i}))}return}if(e.type!==`CallExpression`){if(e.type===`Decorator`){let n=qr(e);if(n?.name===`Inject`){let e=W(n.call.arguments?.[0]);e!==null&&c.push({name:e,filePath:t,relativePath:i})}}return}let n=e.callee,r=Br(e);if(r===`createToken`&&!_.has(e)){let n=W(e.arguments?.[0]);n!==null&&s.push({name:n,variable:null,filePath:t,relativePath:i});return}if(r===`defineAdapter`||r===`definePlugin`){let n=W(K(Vr(e),`name`));if(n!==null){let e=r===`definePlugin`?`plugin`:`adapter`,a=`${r}::${n}::${t}`;h.has(a)||(h.add(a),l.push({kind:e,name:n,filePath:t,relativePath:i}))}return}if(r===`defineAugmentation`){let n=e.arguments??[],r=W(n[0]);if(r!==null){let e=H(n[1])&&n[1].type===`ObjectExpression`?n[1]:null;u.push({name:r,description:W(K(e,`description`)),example:W(K(e,`example`)),filePath:t,relativePath:i})}return}if(r===`defineContextDecorator`||r===`defineHttpContextDecorator`){let n=W(K(Vr(e),`key`));n!==null&&!g.has(n)&&(g.add(n),d.push({key:n,filePath:t,relativePath:i}));return}if(H(n)&&n.type===`CallExpression`){let r=n.callee;if(H(r)&&r.type===`MemberExpression`&&G(r.property)===`withParams`){let n=G(r.object);if(n===`defineContextDecorator`||n===`defineHttpContextDecorator`){let n=W(K(Vr(e),`key`));n!==null&&!g.has(n)&&(g.add(n),d.push({key:n,filePath:t,relativePath:i}))}}return}if(H(n)&&n.type===`MemberExpression`&&G(n.property)===`glob`){let t=n.object;H(t)&&t.type===`MetaProperty`&&U(e.arguments,e=>{let t=W(e);t!==null&&m.push(t)})}});let b=[];U(r,e=>{if(e.type===`ClassDeclaration`||e.type===`ClassExpression`){let t=G(e.id);t&&b.push({cls:e,className:t})}});for(let{cls:e,className:n}of b){let r=o.find(e=>e.className===n),s=e.body?.body;if(Gr(e,`AppAdapter`))for(let e of s??[]){if(e.type!==`PropertyDefinition`||G(e.key)!==`name`)continue;let n=W(e.value);if(n===null)continue;let r=`class::${n}::${t}`;h.has(r)||(h.add(r),l.push({kind:`adapter`,name:n,filePath:t,relativePath:i}));break}for(let e of s??[]){if(e.type!==`MethodDefinition`)continue;let o=G(e.key);if(!o)continue;if(o===`routes`){$r(e.value,p);continue}if(!r)continue;let s=Kr(e),c=Zr(s,v);for(let e of s){let r=qr(e);if(!r||!zr.has(r.name))continue;let s=r.call.arguments??[],l=W(s[0]),u=l&&l.length>0?l:`/`,d=H(s[1])&&s[1].type===`ObjectExpression`?s[1]:null;f.push({controller:n,method:o,httpMethod:r.name.toUpperCase(),path:u,pathParams:Wr(u),queryFilterable:c?.filterable??null,querySortable:c?.sortable??null,querySearchable:c?.searchable??null,bodySchema:Xr(d,`body`,a),querySchema:Xr(d,`query`,a),paramsSchema:Xr(d,`params`,a),filePath:t,relativePath:i})}}}return U(r,e=>{if(e.type!==`Property`||G(e.key)!==`routes`)return;let t=e.value;H(t)&&(t.type===`FunctionExpression`||t.type===`ArrowFunctionExpression`)&&$r(t,p)}),{classes:o,tokens:s,injects:c,pluginsAndAdapters:l,augmentations:u,contextKeys:d,routes:f,moduleMounts:p,globPatterns:/\.module\.[mc]?[tj]sx?$/.test(t)?m:[]}}function $r(e,t){let n=[],r=[];U(e.body,e=>{if(e.type!==`Property`)return;let t=G(e.key);if(t===`path`){let t=W(e.value);t!==null&&n.push(t)}else if(t===`controller`){let t=G(e.value);t&&/^[A-Z]/.test(t)&&r.push(t)}});let i=Math.min(n.length,r.length);for(let e=0;e<i;e++)t.push({controller:r[e],mountPath:n[e]})}const ei=[`Service`,`Controller`,`Repository`,`Injectable`,`Component`,`Module`],ti=[`.ts`,`.tsx`,`.mts`,`.cts`],ni=[`node_modules`,`.kickjs`,`dist`,`build`,`.test.`,`.spec.`,`.d.ts`],ri=new RegExp(String.raw`@(${ei.join(`|`)})\s*\([^)]*\)`+String.raw`(?:\s*@[A-Z]\w*(?:\s*\([^)]*\))?)*`+String.raw`\s*export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`,`g`),ii=new RegExp(String.raw`export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppModule\b`,`g`),ai=/export\s+const\s+(\w+)\s*(?::\s*[^=]+)?=\s*defineModule\s*(?:<[^>]*>)?\s*\(/g,oi=/(?:export\s+)?const\s+(\w+)\s*(?::\s*[^=]+)?=\s*createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,si=/createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,ci=/@Inject\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,li=/\b(defineAdapter|definePlugin)\s*(?:<[^>]*>)?\s*\(/g,ui=/\b(?:defineContextDecorator|defineHttpContextDecorator)\s*(?:\.withParams\s*<(?:[^<>]|<[^<>]*>)*>\s*\(\s*\))?\s*(?:<(?:[^<>]|<[^<>]*>)*>)?\s*\(/g,di=new RegExp(String.raw`export\s+(?:default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppAdapter\b`,`g`),fi=/\bname\s*(?::\s*[^=]+)?=\s*['"`]([^'"`]+)['"`]/,pi=/\bdefineAugmentation\s*\(\s*['"`]([^'"`]+)['"`]\s*(,\s*\{)?/g,mi=new RegExp(String.raw`@(${[`Get`,`Post`,`Put`,`Delete`,`Patch`].join(`|`)})\s*\(`,`g`);function hi(e,t){let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`(`)n++;else if(t===`)`&&(n--,n===0))return r}return-1}function gi(e,t){let n=t;for(;n<e.length;){for(;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]!==`@`)break;let t=e.slice(n).match(/^@([A-Z]\w*)/);if(!t)break;for(n+=t[0].length;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]===`(`){let t=hi(e,n);if(t<0)return null;n=t+1}}for(;n<e.length&&/\s/.test(e[n]);)n++;for(let t of[`public`,`private`,`protected`])if(e.slice(n,n+t.length)===t&&/\s/.test(e.charAt(n+t.length))){for(n+=t.length;n<e.length&&/\s/.test(e[n]);)n++;break}if(e.slice(n,n+5)===`async`&&/\s/.test(e.charAt(n+5)))for(n+=5;n<e.length&&/\s/.test(e[n]);)n++;let r=e.slice(n).match(/^([a-zA-Z_]\w*)\s*\(/);return r?{methodName:r[1],endPos:n+r[0].length}:null}function _i(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function vi(e,t){let n=e.endsWith(`/`)?e.slice(0,-1):e;return!t||t===`/`?n||`/`:n+(t.startsWith(`/`)?t:`/`+t)||`/`}const yi=/\b(?:public\s+|private\s+|protected\s+)?routes\s*\([^)]*\)\s*(?::\s*[A-Za-z_][\w<>[\]\s,|]*\s*)?\{/g,bi=/\bpath\s*:\s*['"`]([^'"`]*)['"`]/g,xi=/\bcontroller\s*:\s*([A-Z]\w*)\b/g,Si=/\bimport\.meta\.glob\s*\(/g;function Ci(e){let t=[];for(Si.lastIndex=0;Si.exec(e)!==null;){let n=Si.lastIndex-1,r=hi(e,n);if(r<0)continue;let i=e.slice(n+1,r),a=/['"`]([^'"`]+)['"`]/g,o;for(;(o=a.exec(i))!==null;)t.push(o[1])}return t}function wi(e){let t=e.replace(/[.+^$()|[\]\\]/g,`\\$&`).replace(/\?/g,`.`).replace(/\*\*\//g,`___DOUBLESTAR_SLASH___`).replace(/\*\*/g,`___DOUBLESTAR___`).replace(/\*/g,`[^/]*`).replace(/___DOUBLESTAR_SLASH___/g,`(?:.+/)?`).replace(/___DOUBLESTAR___/g,`.*`);return RegExp(`^`+t+`$`)}function Ti(e,t){let n=e.startsWith(`./`)?e:`./`+e,r=!1;for(let e of t){let t=e.startsWith(`!`);wi(t?e.slice(1):e).test(n)&&(r=!t)}return r}function Ei(e){let t=[];yi.lastIndex=0;let n;for(;(n=yi.exec(e))!==null;){let r=e.indexOf(`{`,n.index+n[0].length-1);if(r<0)continue;let i=Ri(e,r);if(i<0)continue;let a=e.slice(r+1,i),o=[];bi.lastIndex=0;let s;for(;(s=bi.exec(a))!==null;)o.push(s[1]??``);let c=[];xi.lastIndex=0;let l;for(;(l=xi.exec(a))!==null;)c.push(l[1]);let u=Math.min(o.length,c.length);for(let e=0;e<u;e++)t.push({controller:c[e],mountPath:o[e]})}return t}function Di(e,t){let n=new RegExp(String.raw`\b${t}\s*:\s*([A-Za-z_$][\w$]*)`,`g`).exec(e);return n?n[1]:null}function Oi(e,t){let n=new RegExp(String.raw`import\s*(?:type\s+)?\{[^}]*\b${t}\b[^}]*\}\s*from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(n)return n[1];let r=new RegExp(String.raw`import\s+(?:type\s+)?${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(r)return r[1];let i=new RegExp(String.raw`import\s*\*\s*as\s+${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);return i?i[1]:new RegExp(String.raw`(?:^|\n)\s*(?:export\s+)?const\s+${t}\b`).test(e)?``:null}function ki(e,t){let n=/@ApiQueryParams\s*\(\s*([\s\S]*?)\s*\)\s*$/.exec(e);if(!n){let n=/@ApiQueryParams\s*\(([\s\S]*?)\)/.exec(e);return n?Ai(n[1].trim(),t):null}return Ai(n[1].trim(),t)}function Ai(e,t){if(e.startsWith(`{`))return Mi(e);let n=/^([A-Za-z_]\w*)/.exec(e);if(n){let e=n[1],r=new RegExp(String.raw`const\s+${e}\s*(?::\s*[^=]+)?=\s*(\{[\s\S]*?\n\})`,`m`).exec(t);if(r)return Mi(r[1])}return{filterable:[],sortable:[],searchable:[]}}function ji(e,t){let n=new RegExp(String.raw`${t}\s*:\s*\[([\s\S]*?)\]`).exec(e);return n?Array.from(n[1].matchAll(/['"`]([^'"`]+)['"`]/g)).map(e=>e[1]):[]}function Mi(e){return{filterable:ji(e,`filterable`),sortable:ji(e,`sortable`),searchable:ji(e,`searchable`)}}async function Ni(e,t){let n=t.extensions??ti,r=t.exclude??ni,i=[],a;try{a=await ae(e,{withFileTypes:!0,encoding:`utf-8`})}catch{return i}for(let o of a){let a=h(e,o.name),s=_(t.cwd,a);r.some(e=>s.includes(e))||(o.isDirectory()?i.push(...await Ni(a,t)):o.isFile()&&n.some(e=>o.name.endsWith(e))&&i.push(a))}return i}function q(e,t){return _(t,e).split(y).join(`/`)}function Pi(e,t,n){let r=[],i=q(t,n);ri.lastIndex=0;let a;for(;(a=ri.exec(e))!==null;){let[,e,n,o]=a;r.push({className:o,decorator:e,filePath:t,relativePath:i,isDefault:!!n})}ii.lastIndex=0;let o;for(;(o=ii.exec(e))!==null;){let[,e,n]=o;r.some(e=>e.className===n&&e.filePath===t)||r.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!!e})}ai.lastIndex=0;let s;for(;(s=ai.exec(e))!==null;){let[,e]=s;r.some(n=>n.className===e&&n.filePath===t)||r.push({className:e,decorator:`Module`,filePath:t,relativePath:i,isDefault:!1})}return r}function Fi(e,t,n){let r=[],i=q(t,n),a=new Set;oi.lastIndex=0;let o;for(;(o=oi.exec(e))!==null;){let[e,n,s]=o;a.add(e),r.push({name:s,variable:n,filePath:t,relativePath:i})}for(si.lastIndex=0;(o=si.exec(e))!==null;)a.has(o[0])||r.push({name:o[1],variable:null,filePath:t,relativePath:i});return r}function Ii(e,t,n,r,i=new Map){let a=[];if(r.length===0)return a;let o=q(t,n),s=[];for(let t of r){let n=new RegExp(String.raw`class\s+${t.className}\b`).exec(e);n?.index!==void 0&&s.push({cls:t,start:n.index})}s.sort((e,t)=>e.start-t.start);for(let n=0;n<s.length;n++){let{cls:r,start:c}=s[n],l=n+1<s.length?s[n+1].start:e.length,u=e.slice(c,l);mi.lastIndex=0;let d;for(;(d=mi.exec(u))!==null;){let n=d[1],s=d.index,c=mi.lastIndex-1,l=hi(u,c);if(l<0)continue;let f=u.slice(c+1,l),p=f.match(/^\s*['"`]([^'"`]*)['"`]/),m=p&&p[1].length>0?p[1]:`/`,h=gi(u,l+1);if(!h)continue;let{methodName:g,endPos:_}=h;mi.lastIndex=_;let v=ki(u.slice(s,_),e),y=Di(f,`body`),b=Di(f,`query`),x=Di(f,`params`),S=i.get(r.className)??``,C=S?vi(S,m):m;a.push({controller:r.className,method:g,httpMethod:n.toUpperCase(),path:m,pathParams:_i(C),queryFilterable:v?.filterable??null,querySortable:v?.sortable??null,querySearchable:v?.searchable??null,bodySchema:y?{identifier:y,source:Oi(e,y)}:null,querySchema:b?{identifier:b,source:Oi(e,b)}:null,paramsSchema:x?{identifier:x,source:Oi(e,x)}:null,filePath:t,relativePath:o})}}return a}function Li(e,t,n){let r=[],i=q(t,n);ci.lastIndex=0;let a;for(;(a=ci.exec(e))!==null;)r.push({name:a[1],filePath:t,relativePath:i});return r}function Ri(e,t){let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`{`)n++;else if(t===`}`&&(n--,n===0))return r}return-1}function zi(e,t,n){let r=[],i=q(t,n),a=new Set;li.lastIndex=0;let o;for(;(o=li.exec(e))!==null;){let n=o[1],s=li.lastIndex-1,c=hi(e,s);if(c<0)continue;let l=e.slice(s+1,c),u=/\bname\s*:\s*['"`]([^'"`]+)['"`]/.exec(l);if(!u)continue;let d=u[1],f=`${n}::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:n===`definePlugin`?`plugin`:`adapter`,name:d,filePath:t,relativePath:i}))}di.lastIndex=0;let s;for(;(s=di.exec(e))!==null;){let n=s.index,o=e.indexOf(`{`,n);if(o<0)continue;let c=Ri(e,o);if(c<0)continue;let l=e.slice(o+1,c),u=fi.exec(l);if(!u)continue;let d=u[1],f=`class::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:`adapter`,name:d,filePath:t,relativePath:i}))}return r}function Bi(e,t,n){let r=[],i=q(t,n),a=new Set;for(ui.lastIndex=0;ui.exec(e)!==null;){let n=ui.lastIndex-1,o=hi(e,n);if(o<0)continue;let s=e.slice(n+1,o),c=/\bkey\s*:\s*['"`]([^'"`]+)['"`]/.exec(s);if(!c)continue;let l=c[1];a.has(l)||(a.add(l),r.push({key:l,filePath:t,relativePath:i}))}return r}function Vi(e,t,n){let r=[],i=q(t,n);pi.lastIndex=0;let a;for(;(a=pi.exec(e))!==null;){let n=a[1],o=null,s=null;if(a[2]){let t=e.indexOf(`{`,a.index+a[0].length-1);if(t>=0){let n=Ri(e,t);if(n>=0){let r=e.slice(t+1,n);o=Hi(r,`description`),s=Hi(r,`example`)}}}r.push({name:n,description:o,example:s,filePath:t,relativePath:i})}return r}function Hi(e,t){let n=RegExp(`\\b${t}\\s*:\\s*(['"\`])`,`g`).exec(e);if(!n)return null;let r=n[1],i=n.index+n[0].length,a=i,o=null;for(;a<e.length;){let t=e[a];if(t===`\\`){a+=2;continue}if(t===r){o=e.slice(i,a);break}a++}return o===null?null:o.replace(/\\(.)/g,(e,t)=>t===`n`?`
|
|
2394
|
+
`:t===`t`?` `:t===`r`?`\r`:t)}const Ui=[`src/config/index.ts`,`src/config/env.ts`,`src/config.ts`,`src/env.ts`];async function Wi(e,t){let n=t===`src/env.ts`?Ui:[t];for(let t of n){let n=v(e,t),r;try{r=await T(n,`utf-8`)}catch{continue}if(!(!/\bdefineEnv\s*\(/.test(r)&&!/\bfrom(Zod|Valibot|Yup)\s*\(/.test(r))&&/export\s+default\b/.test(r)&&!/export\s+default\s+loadEnvFromSchema\s*\(/.test(r))return{filePath:n,relativePath:q(n,e)}}return null}function Gi(e){let t=new Map;for(let n of e){let e=t.get(n.className)??[];e.push(n),t.set(n.className,e)}let n=[];for(let[e,r]of t)new Set(r.map(e=>e.filePath)).size>1&&n.push({className:e,classes:r});return n.sort((e,t)=>e.className.localeCompare(t.className)),n}function Ki(e,t,n){return Qr(e,t,n)||qi(e,t,n)}function qi(e,t,n){let r=Pi(e,t,n);return{classes:r,tokens:Fi(e,t,n),injects:Li(e,t,n),pluginsAndAdapters:zi(e,t,n),augmentations:Vi(e,t,n),contextKeys:Bi(e,t,n),routes:Ii(e,t,n,r,new Map),moduleMounts:Ei(e),globPatterns:/\.module\.[mc]?[tj]sx?$/.test(t)?Ci(e):[]}}async function Ji(e,t,n){let r=n?await Ir.signature(e):null;if(n&&r){let t=n.get(e,r);if(t)return n.set(e,r,t),t}let i;try{i=await T(e,`utf-8`)}catch{return null}let a=Ki(i,e,t);return n&&r&&n.set(e,r,a),a}async function Yi(e,t,n){let r=[],i=0,a=Array.from({length:Math.min(t,e.length)},async()=>{for(;;){let t=i++;if(t>=e.length)return;r[t]=await n(e[t],t)}});return await Promise.all(a),r}async function Xi(e){let t=(await Ni(v(e.root),e)).toSorted(),n=e.cacheDir?await Ir.load(e.cacheDir):null,r=$i(t,await Yi(t,16,t=>Ji(t,e.cwd,n))),i=await Wi(e.cwd,e.envFile??`src/env.ts`);return n&&await n.save(),{...r,env:i}}function Zi(e,t,n){let r=n.extensions??ti,i=n.exclude??ni;if(!e.startsWith(t+y)&&e!==t||!r.some(t=>e.endsWith(t)))return!1;let a=_(n.cwd,e);return!i.some(e=>a.includes(e))}async function Qi(e,t){if(!e.cacheDir)return Xi(e);let n=v(e.root),r=await Ir.load(e.cacheDir),i=r.cachedFiles();if(i.length===0)return Xi(e);let a=new Set(t.removed.map(t=>v(e.cwd,t))),o=t.changed.map(t=>v(e.cwd,t)).filter(t=>!a.has(t)&&Zi(t,n,e)),s=new Set(o),c=new Set(i);for(let e of s)c.add(e);for(let e of a)c.delete(e);let l=new Map;await Yi(o,16,async t=>{if(!c.has(t))return;let n=await Ir.signature(t),i;try{i=await T(t,`utf-8`)}catch{c.delete(t);return}let a=Ki(i,t,e.cwd);l.set(t,a),n&&r.set(t,n,a)});let u=[...c].toSorted(),d=$i(u,u.map(e=>l.get(e)||(r.carry(e),r.peek(e)))),f=await Wi(e.cwd,e.envFile??`src/env.ts`);return await r.save(),{...d,env:f}}function $i(e,t){let n=[],r=[],i=[],a=[],o=[],s=[],c=[],l=new Map;for(let e of t)if(e)for(let{controller:t,mountPath:n}of e.moduleMounts)l.has(t)||l.set(t,n);let u=new Map;for(let d=0;d<e.length;d++){let f=t[d];if(f){n.push(...f.classes),i.push(...f.tokens),a.push(...f.injects),o.push(...f.pluginsAndAdapters),s.push(...f.augmentations),c.push(...f.contextKeys),f.globPatterns.length>0&&u.set(e[d],f.globPatterns);for(let e of f.routes){let t=l.get(e.controller);if(t){let n=vi(t,e.path);r.push({...e,pathParams:_i(n)})}else r.push(e)}}}let d=[];for(let[e,t]of u){if(!/\.module\.[mc]?[tj]sx?$/.test(e)||t.length===0)continue;let r=e.replaceAll(y,`/`),i=r.slice(0,r.lastIndexOf(`/`));for(let a of n){if(a.decorator===`Module`)continue;let n=a.filePath.replaceAll(y,`/`);n.startsWith(i+`/`)&&n!==r&&(Ti(n.slice(i.length+1),t)||d.push({className:a.className,filePath:a.filePath,relativePath:a.relativePath,moduleFilePath:e,decorator:a.decorator}))}}n.sort((e,t)=>e.className===t.className?e.relativePath.localeCompare(t.relativePath):e.className.localeCompare(t.className)),i.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),a.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),r.sort((e,t)=>e.controller.localeCompare(t.controller)||e.method.localeCompare(t.method)),o.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),s.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),c.sort((e,t)=>e.key.localeCompare(t.key)||e.relativePath.localeCompare(t.relativePath));let f=Gi(n);return d.sort((e,t)=>e.relativePath.localeCompare(t.relativePath)||e.className.localeCompare(t.className)),{classes:n,routes:r,tokens:i,injects:a,collisions:f,pluginsAndAdapters:o,augmentations:s,contextKeys:c,orphanedClasses:d}}function ea(e){let t=e.lastIndexOf(`.`);return t<=0?{stem:e,ext:``}:{stem:e.slice(0,t),ext:e.slice(t+1)}}function ta(e){let t=e.replaceAll(`\\`,`/`),{stem:n,ext:r}=ea(t.slice(t.lastIndexOf(`/`)+1)),i=r||`ts`,a=n.lastIndexOf(`.`);return a>0?`./**/*.${n.slice(a+1)}.${i}`:`./**/*.${i}`}function na(e){let t=new Set;for(let n of e)t.add(ta(n.relativePath));return[...t].toSorted()}function ra(e,t){let n=0,r=null;for(let i=t;i<e.length;i++){let t=e[i];if(r){if(t===`\\`){i++;continue}t===r&&(r=null);continue}if(t===`'`||t===`"`||t==="`")r=t;else if(t===`(`)n++;else if(t===`)`&&(n--,n===0))return i}return-1}function ia(e,t,n,r){let i=null;for(let a=n;a<r;a++){let n=e[a];if(i){if(n===`\\`){a++;continue}n===i&&(i=null);continue}if(n===`'`||n===`"`||n==="`")i=n;else if(n===t)return a}return-1}function aa(e,t){let n=0,r=null;for(let i=t;i<e.length;i++){let t=e[i];if(r){if(t===`\\`){i++;continue}t===r&&(r=null);continue}if(t===`'`||t===`"`||t==="`")r=t;else if(t===`[`)n++;else if(t===`]`&&(n--,n===0))return i}return-1}function oa(e){let t=/\bimport\.meta\.glob\s*\(/g,n=[],r;for(;(r=t.exec(e))!==null;){let t=e.indexOf(`(`,r.index);if(t<0)continue;let i=ra(e,t);i<0||n.push({start:r.index,open:t,close:i})}return n}function sa(e,t){let n=oa(e);if(n.length===0)return null;let r=n.find(t=>/\beager\s*:\s*true\b/.test(e.slice(t.open,t.close+1)))??n[0],i=e.slice(r.start,r.close+1),a=new Set(Ci(i).map(e=>e.startsWith(`!`)?e.slice(1):e)),o=t.filter(e=>!a.has(e));if(o.length===0)return null;let s=o.map(e=>`'${e}'`).join(`, `),c=ia(e,`[`,r.open,r.close);if(c>=0){let t=aa(e,c);if(t<0||t>r.close)return null;let n=e.slice(0,t);return n+(/[[,]\s*$/.test(n)?``:`, `)+s+e.slice(t)}let l=/(['"`])((?:\\.|(?!\1).)*)\1/,u=e.slice(r.open+1,r.close),d=l.exec(u);if(!d)return null;let f=r.open+1+d.index,p=f+d[0].length;return e.slice(0,f)+`[${d[0]}, ${s}]`+e.slice(p)}const J="/* eslint-disable */\n// AUTO-GENERATED by `kick typegen`. DO NOT EDIT.\n// Re-run with `kick typegen` or rely on `kick dev` to refresh.\n",ca=new Set([`Service`,`Repository`,`Injectable`,`Component`]);var la=class extends Error{collisions;constructor(e){super(ua(e)),this.name=`TokenCollisionError`,this.collisions=e}};function ua(e){let t=[`kick typegen: token collision detected`];for(let n of e){t.push(``),t.push(` ${n.classes.length} classes named '${n.className}':`);for(let e of n.classes)t.push(` - ${e.relativePath}`)}return t.push(``),t.push(`Resolutions:`),t.push(` (a) Rename one of the classes`),t.push(` (b) Use createToken<T>('namespaced/Name') and import the token explicitly — see @forinda/kickjs`),t.push(` (c) Pass --allow-duplicates to namespace the registry keys automatically`),t.push(` (e.g. 'modules/users/UserService' instead of 'UserService')`),t.join(`
|
|
2395
|
+
`)}function da(e,t){let n=_(f(t),e).split(y).join(`/`);return n=n.replace(/\.(ts|tsx|mts|cts)$/i,``),n.startsWith(`.`)||(n=`./`+n),n}function fa(e){let t=e.relativePath.replace(/^src\//,``).replace(/\.(ts|tsx|mts|cts)$/i,``).split(`/`);t.pop();let n=t.join(`/`);return n?`${n}/${e.className}`:e.className}function pa(e,t,n){let r=new Set,i=[];for(let a of e){if(!ca.has(a.decorator))continue;let e=n.has(a.className)?fa(a):a.className;if(r.has(e))continue;r.add(e);let o=da(a.filePath,t),s=a.isDefault?`import('${o}').default`:`import('${o}').${a.className}`;i.push(` '${e}': ${s}`)}return`${J}
|
|
2391
2396
|
declare module '@forinda/kickjs' {
|
|
2392
2397
|
interface KickJsRegistry {
|
|
2393
2398
|
${i.length?i.join(`
|
|
@@ -2396,7 +2401,7 @@ ${i.length?i.join(`
|
|
|
2396
2401
|
}
|
|
2397
2402
|
|
|
2398
2403
|
export {}
|
|
2399
|
-
`}function
|
|
2404
|
+
`}function ma(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function ha(e){return`${J}
|
|
2400
2405
|
declare module '@forinda/kickjs' {
|
|
2401
2406
|
/**
|
|
2402
2407
|
* Key-only registry of every context key produced by a
|
|
@@ -2405,20 +2410,20 @@ declare module '@forinda/kickjs' {
|
|
|
2405
2410
|
* \`ContextMeta\`; this only records that the key exists.
|
|
2406
2411
|
*/
|
|
2407
2412
|
interface ContextKeys {
|
|
2408
|
-
${[...new Set(e.map(e=>e.key))].toSorted().map(e=>` ${
|
|
2413
|
+
${[...new Set(e.map(e=>e.key))].toSorted().map(e=>` ${ma(e)?e:JSON.stringify(e)}: true`).join(`
|
|
2409
2414
|
`)}
|
|
2410
2415
|
}
|
|
2411
2416
|
}
|
|
2412
2417
|
|
|
2413
2418
|
export {}
|
|
2414
|
-
`}function
|
|
2419
|
+
`}function ga(e,t,n){return t.length===0?`${J}
|
|
2415
2420
|
// ${n}
|
|
2416
2421
|
export type ${e} = never
|
|
2417
2422
|
`:`${J}
|
|
2418
2423
|
export type ${e} =
|
|
2419
2424
|
${[...new Set(t)].toSorted().map(e=>` | '${e}'`).join(`
|
|
2420
2425
|
`)}
|
|
2421
|
-
`}function
|
|
2426
|
+
`}function _a(e,t,n,r){return[...e.filter(e=>ca.has(e.decorator)).map(e=>r.has(e.className)?fa(e):e.className),...t.map(e=>e.name),...n.map(e=>e.name)]}function va(e){return e.filter(e=>e.decorator===`Module`).map(e=>e.className)}function ya(e){let t=new Map;for(let n of e)t.has(n.name)||t.set(n.name,n);return`${J}
|
|
2422
2427
|
declare module '@forinda/kickjs' {
|
|
2423
2428
|
/**
|
|
2424
2429
|
* Map of every plugin/adapter \`name\` discovered in the project. The
|
|
@@ -2433,7 +2438,7 @@ ${[...t.values()].toSorted((e,t)=>e.name.localeCompare(t.name)).map(e=>` '${e
|
|
|
2433
2438
|
}
|
|
2434
2439
|
|
|
2435
2440
|
export {}
|
|
2436
|
-
`}function
|
|
2441
|
+
`}function ba(e){if(e.length===0)return`${J}
|
|
2437
2442
|
// No augmentations discovered.
|
|
2438
2443
|
//
|
|
2439
2444
|
// Plugins advertise augmentable interfaces via:
|
|
@@ -2457,7 +2462,7 @@ export {}
|
|
|
2457
2462
|
${n.join(`
|
|
2458
2463
|
|
|
2459
2464
|
`)}
|
|
2460
|
-
`}const
|
|
2465
|
+
`}const xa=/^(kick\/)?([a-z][\w-]*\/[A-Z]\w*)(\/.+)?(:[a-z][\w-]+(:[a-z][\w-]+)*)?$/;function Sa(e){let t=[];for(let n of e){let e=n.name;e.startsWith(`kickjs.`)||xa.test(e)||t.push({token:e,variable:n.variable,filePath:n.relativePath,reason:"does not match `<scope>/<PascalKey>[/<suffix>][:<instance>]`",suggestion:Ca(e)})}return t}function Ca(e){if(/^[A-Z]\w*$/.test(e))return`'<scope>/${e}' (e.g. 'mycorp/${e}')`;if(e.includes(`.`))return`consider '<scope>/PascalKey' instead of dotted form`;let t=/^([a-z][\w-]*)\/([a-z]\w*)$/.exec(e);if(t){let[,e,n]=t;return`'${e}/${n.charAt(0).toUpperCase()}${n.slice(1)}'`}}function wa(e,t){if(!e)return{entries:[],count:0};let n=new Map;for(let[r,i]of Object.entries(e)){if(!i||typeof i.src!=`string`)continue;let e=v(t,i.src);if(!ka(e))continue;let a=pe(i.glob??`**/*`,{cwd:e,nodir:!0,dot:!1,posix:!0});a.sort();let{pairs:o}=me(r,a,{strategy:i.keys??`auto`});for(let{key:e}of o){let t=e.slice(r.length+1);n.set(e,{namespace:r,key:t})}}return{entries:[...n.values()],count:n.size}}function Ta(e){let t="/* eslint-disable */\n// AUTO-GENERATED by `kick typegen`. DO NOT EDIT.\n// Re-run with `kick typegen` or rely on `kick dev` to refresh.\n";if(e.entries.length===0)return`${t}
|
|
2461
2466
|
declare module '@forinda/kickjs' {
|
|
2462
2467
|
/**
|
|
2463
2468
|
* Map of every typed asset discovered in the project's assetMap.
|
|
@@ -2468,7 +2473,7 @@ declare module '@forinda/kickjs' {
|
|
|
2468
2473
|
}
|
|
2469
2474
|
|
|
2470
2475
|
export {}
|
|
2471
|
-
`;let n={};for(let t of e.entries){let e=`${t.namespace}/${t.key}`.split(`/`),r=n;for(let t=0;t<e.length-1;t++){let n=e[t],i=r[n];if(i===
|
|
2476
|
+
`;let n={};for(let t of e.entries){let e=`${t.namespace}/${t.key}`.split(`/`),r=n;for(let t=0;t<e.length-1;t++){let n=e[t],i=r[n];if(i===Ea){let e={};r[n]=e,r=e}else i||(r[n]={}),r=r[n]}let i=e[e.length-1];typeof r[i]!=`object`&&(r[i]=Ea)}return`${t}
|
|
2472
2477
|
declare module '@forinda/kickjs' {
|
|
2473
2478
|
/**
|
|
2474
2479
|
* Map of every typed asset discovered in the project's assetMap.
|
|
@@ -2477,63 +2482,63 @@ declare module '@forinda/kickjs' {
|
|
|
2477
2482
|
* prod → dist).
|
|
2478
2483
|
*/
|
|
2479
2484
|
interface KickAssets {
|
|
2480
|
-
${
|
|
2485
|
+
${Da(n,` `)}
|
|
2481
2486
|
}
|
|
2482
2487
|
}
|
|
2483
2488
|
|
|
2484
2489
|
export {}
|
|
2485
|
-
`}const
|
|
2486
|
-
`)}function
|
|
2490
|
+
`}const Ea=Symbol(`asset-leaf`);function Da(e,t){let n=Object.keys(e).toSorted(),r=[];for(let i of n){let n=e[i],a=Oa(i)?i:JSON.stringify(i);n===Ea?r.push(`${t}${a}: () => string`):(r.push(`${t}${a}: {`),r.push(Da(n,`${t} `)),r.push(`${t}}`))}return r.join(`
|
|
2491
|
+
`)}function Oa(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function ka(e){try{return c(e).isDirectory()}catch{return!1}}var Aa=A({runTypegen:()=>Ma,sweepStaleTypegen:()=>La,watchTypegen:()=>Ia,writeTypegenArtifacts:()=>Fa});function ja(e){let t=e.cwd??process.cwd();return{cwd:t,srcDir:v(t,e.srcDir??`src`),outDir:v(t,e.outDir??`.kickjs/types`),silent:e.silent??!1,allowDuplicates:e.allowDuplicates??!1,schemaValidator:e.schemaValidator??!1,envFile:e.envFile??`src/env.ts`}}async function Ma(e={}){let{cwd:t,srcDir:n,outDir:r,silent:i,allowDuplicates:a,envFile:o}=ja(e),s=Date.now(),c={root:n,cwd:t,cacheDir:e.noCache?void 0:v(t,`.kickjs`,`cache`),envFile:o===!1?void 0:o},l=e.changedFiles?await Qi(c,e.changedFiles):await Xi(c);if(l.collisions.length>0&&!a)throw new la(l.collisions);let u=wa(e.assetMap,t),d=[],f=[];if(e.runPlugins!==!1){try{let{runAllPluginTypegens:n}=await Promise.resolve().then(()=>Xa),{loadKickConfig:r}=await Promise.resolve().then(()=>Ce);d=await n({cwd:t,config:await r(t),silent:!0,changedFiles:e.changedFiles})}catch(e){if(!i){let t=e instanceof Error?e.message:String(e);console.warn(` kick typegen: plugin pipeline failed (${t}) — continuing`)}}f.push(...await Fa(r,d,i))}let p=Sa(l.tokens),m=Pa(l,u.count,f),h=Date.now()-s;if(!i){let e=r.replace(t+`/`,``),n=m.resolvedCollisions>0?`, ${m.resolvedCollisions} collisions namespaced`:``,i=m.envWritten?`, env typed`:``,a=m.pluginEntries>0?`, ${m.pluginEntries} plugins/adapters`:``,o=m.augmentationEntries>0?`, ${m.augmentationEntries} augmentations`:``,s=m.assetEntries>0?`, ${m.assetEntries} assets`:``;if(console.log(` kick typegen → ${m.serviceTokens} services, ${m.routeEntries} routes, ${m.moduleTokens} modules${a}${o}${s}${i}${n} → ${e} (${h}ms)`),p.length>0){console.warn(` kick typegen: ${p.length} token(s) don't match the §22.2 convention:`);for(let e of p){let t=e.variable?` [${e.variable}]`:``;console.warn(` '${e.token}' (${e.filePath})${t} — ${e.reason}`),e.suggestion&&console.warn(` → suggestion: ${e.suggestion}`)}}}return l.orphanedClasses.length>0&&await Na(l.orphanedClasses,{fix:e.fix??!1,silent:i}),{scan:l,result:m,tokenWarnings:p}}async function Na(e,{fix:t,silent:n}){let r=new Map;for(let t of e){let e=r.get(t.moduleFilePath)??[];e.push(t),r.set(t.moduleFilePath,e)}if(t){let e=0,t=[];for(let[i,a]of r){let r=na(a);try{let a=await T(i,`utf-8`),o=sa(a,r);o&&o!==a?(await E(i,o),e++,n||console.log(` kick typegen --fix: patched ${i}\n + ${r.join(`, `)}`)):t.push(i)}catch{t.push(i)}}if(!n&&(e>0&&console.log(` kick typegen --fix: updated ${e} module glob(s) — re-run typegen to pick up the now-loaded classes.`),t.length>0)){console.warn(` kick typegen --fix: could not auto-patch ${t.length} module(s) (no import.meta.glob() call found) — add the patterns by hand:`);for(let e of t){let t=r.get(e)??[];console.warn(` ${e}: ${na(t).join(`, `)}`)}}return}if(!n){console.warn(` kick typegen: ${e.length} decorated class(es) not matched by any module's import.meta.glob():`);for(let[e,t]of r){for(let e of t)console.warn(` @${e.decorator} ${e.className} (${e.relativePath})`);let n=na(t);console.warn(` → add to import.meta.glob([...]) in ${e}:`),console.warn(` ${n.map(e=>`'${e}'`).join(`, `)}`)}console.warn(" → or run `kick typegen --fix` to apply these automatically.")}}function Pa(e,t,n){let r=new Set(e.collisions.map(e=>e.className)),i=e.classes.filter(e=>ca.has(e.decorator)),a=_a(e.classes,e.tokens,e.injects,r);return{registryEntries:i.length,serviceTokens:new Set(a).size,moduleTokens:va(e.classes).length,routeEntries:e.routes.length,pluginEntries:new Set(e.pluginsAndAdapters.map(e=>e.name)).size,augmentationEntries:new Set(e.augmentations.map(e=>e.name)).size,assetEntries:t,envWritten:e.env!==null,written:n,resolvedCollisions:e.collisions.length}}async function Fa(e,t,n){await w(e,{recursive:!0}),await E(h(f(e),`.gitignore`),`# Auto-generated by kick typegen
|
|
2487
2492
|
*
|
|
2488
|
-
`,`utf-8`);let r=t.filter(e=>e.outFile).map(e=>e.outFile);return await
|
|
2493
|
+
`,`utf-8`);let r=t.filter(e=>e.outFile).map(e=>e.outFile);return await La(e,r,t,n),r}async function Ia(e={}){let t=ja(e),{srcDir:n,silent:r,cwd:i}=t,a={...t,allowDuplicates:!0,runPlugins:!1,noCache:e.noCache},o=process.env.KICKJS_WATCH_POLLING===`1`||process.env.KICKJS_WATCH_POLLING===`true`,[{runAllPluginTypegens:s},{loadKickConfig:c}]=await Promise.all([Promise.resolve().then(()=>Xa),Promise.resolve().then(()=>Ce)]),l=await c(i),u=async()=>{try{await Ma({...a})}catch(e){if(r)return;if(e instanceof la)console.error(`
|
|
2489
2494
|
`+e.message+`
|
|
2490
|
-
`);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}},d=async()=>{try{let e=await s({cwd:i,config:l,silent:!0});await
|
|
2491
|
-
(dry run — no files were written)`),console.log()}async function
|
|
2495
|
+
`);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}},d=async()=>{try{let e=await s({cwd:i,config:l,silent:!0});await Fa(t.outDir,e,!0)}catch{}};await u(),await d();let{watch:f}=await import(`node:fs`),p=null,m=e=>{e&&/\.(ts|tsx|mts|cts)$/.test(e)&&(e.includes(`.kickjs`)||e.endsWith(`.d.ts`)||(p&&clearTimeout(p),p=setTimeout(()=>{u().then(d)},100)))};if(o){r||console.log(` kick typegen: polling mode (KICKJS_WATCH_POLLING)`);let e=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(e)}let h;try{h=f(n,{recursive:!0},(e,t)=>{m(t)})}catch(e){r||console.warn(` kick typegen: watch mode unavailable (${e?.message??e}). Falling back to polling.`);let t=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(t)}return()=>{p&&clearTimeout(p),h.close()}}async function La(e,t,n,r){let i=new Set;for(let e of t)i.add(d(e));for(let e of n)e.outFile&&i.add(d(e.outFile));let a;try{a=await ae(e)}catch{return[]}let o=[];for(let t of a){if(!Ra.has(t)||i.has(t))continue;let n=v(e,t);try{if(!(await se(n)).isFile())continue;await ce(n),o.push(t)}catch{}}return o.length>0&&!r&&console.log(` kick typegen: swept ${o.length} stale file(s): ${o.join(`, `)}`),o}const Ra=new Set([`assets.d.ts`,`env.ts`,`routes.ts`,`registry.d.ts`,`services.d.ts`,`modules.d.ts`,`plugins.d.ts`,`augmentations.d.ts`,`index.d.ts`]),za=[`agents`,`claude`,`skills`,`gemini`,`copilot`,`both`,`all`];function Y(e){return e.parent?.opts()?.dryRun??!1}function X(e,t=!1){let n=process.cwd();console.log(`\n ${t?`Would generate`:`Generated`} ${e.length} file${e.length===1?``:`s`}:`);for(let t of e)console.log(` ${t.replace(n+`/`,``)}`);t&&console.log(`
|
|
2496
|
+
(dry run — no files were written)`),console.log()}async function Ba(e){if(!e)try{let e=await M(process.cwd());await Ma({cwd:process.cwd(),allowDuplicates:!0,silent:!0,schemaValidator:e?.typegen?.schemaValidator??`zod`,envFile:e?.typegen?.envFile,srcDir:e?.typegen?.srcDir,outDir:e?.typegen?.outDir})}catch{}}const Va=[{name:`module <name>`,description:`REST module (controller, service, DTOs, repo)`},{name:`scaffold <name> <fields...>`,description:`CRUD module from field definitions`},{name:`controller <name>`,description:`@Controller() class [-m module]`},{name:`service <name>`,description:`@Service() singleton [-m module]`},{name:`middleware <name>`,description:`Express middleware function [-m module]`},{name:`guard <name>`,description:`Route guard (auth, roles, etc.) [-m module]`},{name:`contributor <name>`,description:`Context contributor [--type http|bare] [--params a:string] [-m]`},{name:`dto <name>`,description:`Zod DTO schema [-m module]`},{name:`adapter <name>`,description:`AppAdapter with lifecycle hooks (app-level only)`},{name:`test <name>`,description:`Vitest test scaffold [-m module]`},{name:`job <name>`,description:`Queue @Job processor`},{name:`config`,description:`Generate kick.config.ts`},{name:`agents`,description:`Regenerate AGENTS.md + CLAUDE.md + kickjs-skills.md from upstream templates`}],Ha=new Set(Va.map(e=>e.name.split(` `)[0]));async function Ua(){console.log(`
|
|
2492
2497
|
Built-in generators:
|
|
2493
|
-
`);let e=Math.max(...
|
|
2498
|
+
`);let e=Math.max(...Va.map(e=>e.name.length));for(let t of Va)console.log(` kick g ${t.name.padEnd(e+2)} ${t.description}`);let t=await M(process.cwd()),n=Fe(t?.plugins??[],t?.commands??[]),r=await hn(process.cwd(),n.generators);if(r.generators.length>0){console.log(`
|
|
2494
2499
|
Plugin generators:
|
|
2495
2500
|
`);let e=Math.max(...r.generators.map(e=>`${e.spec.name} <name>`.length));for(let{source:t,spec:n}of r.generators){let r=`${n.name} <name>`;console.log(` kick g ${r.padEnd(e+2)} ${n.description} [${t}]`)}}if(r.failed.length>0){console.log(`
|
|
2496
2501
|
Failed to load:
|
|
2497
|
-
`);for(let{source:e,reason:t}of r.failed)console.log(` ${e} — ${t}`)}console.log()}async function
|
|
2498
|
-
Use -m to scope it to a module: kick g middleware auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);
|
|
2499
|
-
Use -m to scope it to a module: kick g guard admin -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);
|
|
2502
|
+
`);for(let{source:e,reason:t}of r.failed)console.log(` ${e} — ${t}`)}console.log()}async function Wa(e,t,n){let r=await M(process.cwd()),i=j(r),a=t.modulesDir??i.dir??`src/modules`,o=t.repo??Ln(i.repo);t.repo&&De(t.repo);let s=t.pattern??r?.pattern??`rest`,c=t.pluralize===!1?!1:i.pluralize??!0,l=ke(r,process.cwd()),u=i.style??`define`;if(!n&&u===`define`){let e=await Tr(v(a),`define`);if(e.length>0){console.error(`\n ${k.red(`Error:`)} ${e.length} module file(s) still use the legacy \`class … implements AppModule\` shape.\n ${k.dim(`Project setting:`)} modules.style: 'define' (default)\n\n ${k.bold(`Files needing migration:`)}`);for(let t of e.slice(0,5))console.error(` - ${t}`);e.length>5&&console.error(` … and ${e.length-5} more`),console.error(`\n ${k.bold(`Pick one:`)}\n 1. Migrate everything to defineModule:\n ${k.dim(`$`)} kick codemod modules --experimental --apply\n 2. Keep the class form — pin it in kick.config.ts:\n ${k.dim(`// kick.config.ts`)}\n ${k.dim(`export default defineConfig({ modules: { style: 'class' } })`)}\n`),process.exit(1)}}let d=[];for(let r of e){let e=await Rn({name:r,modulesDir:v(a),noEntity:t.entity===!1,noTests:t.tests===!1,repo:o,minimal:t.minimal,force:t.force,pattern:s,dryRun:n,pluralize:c,prismaClientPath:i.prismaClientPath,tokenScope:l,style:i.style});d.push(...e)}X(d,n),await Ba(n)}function Ga(e,t){let n=e.command(`generate [names...]`).alias(`g`).description("Generate code scaffolds — bare form `kick g <name>` is shorthand for `kick g module <name>`").option(`--list`,`List all available generators`).option(`--dry-run`,`Preview files that would be generated without writing them`).option(`--no-entity`,`Skip entity and value object generation (module shortcut)`).option(`--no-tests`,`Skip test file generation (module shortcut)`).option(`--repo <type>`,`Repository name: inmemory (default) or any DB name (e.g. postgres)`).option(`--pattern <pattern>`,`Override project pattern: rest | minimal`).option(`--minimal`,`Shorthand for --pattern minimal`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,r,i)=>{if(r.list){await Ua();return}if(!e||e.length===0){n.help();return}let a=Y(i);N(a);let[o,s,...c]=e;if(o){let e=await M(process.cwd()),n=Fe(e?.plugins??[],e?.commands??[]),i=await mn({generatorName:o,itemName:s??``,args:c,flags:r,cwd:process.cwd(),projectRoot:t?.projectRoot},n.generators);if(i){X(i.files,a);return}if(o!==`module`&&Ha.has(o)){console.error(`\n '${o}' is a generator, not a module name.`),console.error(` Did you mean: kick g ${o} ${s??`<name>`}`),console.error(` If that errors, your @forinda/kickjs-cli is older than the '${o}' generator — upgrade it.\n`),process.exitCode=1;return}}await Wa(e,r,a)});n.command(`module <names...>`).description(`Generate one or more modules (e.g. kick g module user task project)`).option(`--no-entity`,`Skip entity and value object generation`).option(`--no-tests`,`Skip test file generation`).option(`--repo <type>`,`Repository name: inmemory (default) or any DB name (e.g. postgres)`).option(`--pattern <pattern>`,`Override project pattern: rest | minimal`).option(`--minimal`,`Shorthand for --pattern minimal`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t,n)=>{let r=Y(n);N(r),await Wa(e,{...n.optsWithGlobals(),...t},r)}),n.command(`adapter <name>`).description(`Generate an AppAdapter with lifecycle hooks and middleware support`).option(`-o, --out <dir>`,`Output directory`,`src/adapters`).action(async(e,t,n)=>{let r=Y(n);N(r),X(await Kn({name:e,outDir:v(t.out)}),r)}),n.command(`plugin <name>`).description(`Generate a KickPlugin with DI, modules, adapters, middleware, and lifecycle hooks`).option(`-o, --out <dir>`,`Output directory`,`src/plugins`).action(async(e,t,n)=>{let r=Y(n);N(r),X(await qn({name:e,outDir:v(t.out)}),r)}),n.command(`middleware <name>`).description(`Generate an Express middleware function
|
|
2503
|
+
Use -m to scope it to a module: kick g middleware auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await Xn({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`guard <name>`).description(`Generate a route guard (auth, roles, etc.)
|
|
2504
|
+
Use -m to scope it to a module: kick g guard admin -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await Zn({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`contributor <name>`).description(`Generate a Context Contributor (typed alternative to @Middleware for ctx.set)
|
|
2500
2505
|
--type http (default, RequestContext) | bare (ExecutionContext)
|
|
2501
2506
|
--params "source:string,region:number" → emits the withParams<T>() form
|
|
2502
|
-
Use -m to scope it to a module: kick g contributor tenant -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).option(`-t, --type <type>`,`Contributor flavour: http | bare`,`http`).option(`-k, --key <key>`,`Context key it writes (defaults to camelCase of name)`).option(`--params <fields>`,`Per-call params, e.g. "source:string,region:number"`).action(async(e,t,n)=>{let r=Y(n);
|
|
2503
|
-
Use -m to scope it to a module: kick g service payment -m orders`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);
|
|
2504
|
-
Use -m to scope it to a module: kick g controller auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);
|
|
2505
|
-
Use -m to scope it to a module: kick g dto create-user -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);
|
|
2506
|
-
Use -m to scope it to a module: kick g test user-service -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module's __tests__/ folder`).action(async(e,t,n)=>{let r=Y(n);
|
|
2507
|
+
Use -m to scope it to a module: kick g contributor tenant -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).option(`-t, --type <type>`,`Contributor flavour: http | bare`,`http`).option(`-k, --key <key>`,`Context key it writes (defaults to camelCase of name)`).option(`--params <fields>`,`Per-call params, e.g. "source:string,region:number"`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=(t.type??`http`).toLowerCase();i!==`http`&&i!==`bare`&&(console.warn(` kick g contributor: unknown --type '${t.type}', using 'http'.`),i=`http`);let a=await M(process.cwd()),o=j(a),s=o.dir??`src/modules`;X(await er({name:e,type:i,key:t.key,params:t.params,outDir:t.out,moduleName:t.module,modulesDir:s,pattern:a?.pattern,pluralize:o.pluralize??!0}),r)}),n.command(`service <name>`).description(`Generate a @Service() class
|
|
2508
|
+
Use -m to scope it to a module: kick g service payment -m orders`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await tr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`controller <name>`).description(`Generate a @Controller() class with basic routes
|
|
2509
|
+
Use -m to scope it to a module: kick g controller auth -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await nr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r),await Ba(r)}),n.command(`dto <name>`).description(`Generate a Zod DTO schema
|
|
2510
|
+
Use -m to scope it to a module: kick g dto create-user -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module folder`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=await M(process.cwd()),a=j(i),o=a.dir??`src/modules`;X(await rr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`test <name>`).description(`Generate a Vitest test scaffold
|
|
2511
|
+
Use -m to scope it to a module: kick g test user-service -m users`).option(`-o, --out <dir>`,`Output directory (overrides --module)`).option(`-m, --module <module>`,`Place inside a module's __tests__/ folder`).action(async(e,t,n)=>{let r=Y(n);N(r);let i=j(await M(process.cwd())),a=i.dir??`src/modules`;X(await Nr({name:e,outDir:t.out,moduleName:t.module,modulesDir:a,pluralize:i.pluralize??!0}),r)}),n.command(`job <name>`).description(`Generate a @Job queue processor with @Process handlers`).option(`-o, --out <dir>`,`Output directory`,`src/jobs`).option(`-q, --queue <name>`,`Queue name (default: <name>-queue)`).action(async(e,t,n)=>{let r=Y(n);N(r),X(await Er({name:e,outDir:v(t.out),queue:t.queue}),r)}),n.command(`scaffold <name> [fields...]`).description(`Generate a full CRUD module from field definitions
|
|
2507
2512
|
Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
|
|
2508
2513
|
Types: string, text, number, int, float, boolean, date, email, url, uuid, json, enum:a,b,c
|
|
2509
2514
|
Optional: append :optional (shell-safe): description:text:optional
|
|
2510
|
-
or use ? with quoting: "description:text?" or "description?:text"`).option(`--no-entity`,`Skip entity and value object generation`).option(`--no-tests`,`Skip test file generation`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`--modules-dir <dir>`,`Modules directory`).action(async(e,t,n,r)=>{let i=Y(r);
|
|
2515
|
+
or use ? with quoting: "description:text?" or "description?:text"`).option(`--no-entity`,`Skip entity and value object generation`).option(`--no-tests`,`Skip test file generation`).option(`--no-pluralize`,`Use singular names (skip auto-pluralization)`).option(`--modules-dir <dir>`,`Modules directory`).action(async(e,t,n,r)=>{let i=Y(r);N(i),t.length===0&&(console.error(`
|
|
2511
2516
|
Error: At least one field is required.
|
|
2512
2517
|
Usage: kick g scaffold <name> <field:type> [field:type...]
|
|
2513
2518
|
Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
|
|
2514
2519
|
Optional: append :optional (shell-safe, no quoting needed)
|
|
2515
|
-
`),process.exit(1));let a=await
|
|
2516
|
-
`,d=``;if(r(a)&&(d=await
|
|
2517
|
-
`,`utf-8`),s(` ✓ wrote manifest → ${_(n,p)} (${Object.keys(d).length} entries)`),{manifestPath:p,entries:u,manifest:f}}async function
|
|
2520
|
+
`),process.exit(1));let a=await M(process.cwd()),o=j(a),s=n.modulesDir??o.dir??`src/modules`,c=Or(t),l=ke(a,process.cwd()),u=await kr({name:e,fields:c,modulesDir:v(s),noEntity:n.entity===!1,noTests:n.tests===!1,pluralize:n.pluralize===!1?!1:o.pluralize??!0,tokenScope:l,style:o.style});console.log(`\n Scaffolded ${e} with ${c.length} field(s):`);for(let e of c)console.log(` ${e.name}: ${e.type}${e.optional?` (optional)`:``}`);X(u,i),await Ba(i)}),n.command(`config`).description(`Generate a kick.config.ts at the project root`).option(`--modules-dir <dir>`,`Modules directory path`,`src/modules`).option(`--repo <type>`,`Repository name: inmemory (default) or any DB name`,`inmemory`).option(`-f, --force`,`Overwrite existing kick.config.ts without prompting`).action(async(e,t)=>{let n=Y(t);N(n),X(await ir({outDir:v(`.`),modulesDir:e.modulesDir,defaultRepo:e.repo,force:e.force}),n)}),n.command(`agents`).alias(`agent-docs`).alias(`ai-docs`).description(`Regenerate AGENTS.md + CLAUDE.md + kickjs-skills.md (sync after framework upgrades)`).option(`--only <which>`,`Limit scope: agents | claude | skills | both (agents+claude) | all (default: all)`,`all`).option(`--name <name>`,`Project name (defaults to package.json name)`).option(`--pm <pm>`,`Package manager (defaults to package.json packageManager)`).option(`--template <template>`,`Template: rest | minimal`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t)=>{let n=Y(t);N(n);let r=e.only??`all`;if(!za.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${za.join(` | `)}`),process.exitCode=1;return}X(await dr({outDir:v(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)});for(let e of t?.generators??[])Ka(n,e,t?.projectRoot)}function Ka(e,t,n){let{source:r,spec:i}=t,a=i.args?.[0],o=a?.name??`itemName`,s=a?.required?`<${o}>`:`[${o}]`,c=`${i.name} ${s} [extraArgs...]`,l=e.command(c).description(`${i.description} [${r}]`);for(let e of i.flags??[]){let t=e.takesValue?`--${e.name} <value>`:`--${e.name}`,n=e.alias?`-${e.alias}, ${t}`:t;l.option(n,e.description??``)}l.action(async(e,r,a,o)=>{let s=Y(o);N(s);let c=await mn({generatorName:i.name,itemName:e??``,args:r??[],flags:a,cwd:process.cwd(),projectRoot:n},[t]);c&&X(c.files,s)})}async function qa(e){let t=u.resolve(e.cwd,`.kickjs/types`);await w(t,{recursive:!0});let n=new Map,i=e.scan??Xi,a=u.resolve(e.cwd,`.kickjs`,`cache`),o=e.scan?void 0:e.changedFiles,s={cwd:e.cwd,config:e.config,async importTs(e){return await import(x(e).href)},async writeFile(t,n){let r=u.resolve(e.cwd,t);await w(u.dirname(r),{recursive:!0}),await E(r,n,`utf8`)},getScanResult:e=>{let t=Ja(e),r=n.get(t);if(!r){let s={cacheDir:a,...e};r=o?Qi(s,o):i(s),n.set(t,r)}return r},log:console},c=[];for(let n of e.plugins){let i=n.outExtension??`.d.ts`,a=u.join(t,`${n.id.replace(/\//g,`__`)}${i}`),o;try{o=await n.generate(s)}catch(e){let t=e instanceof Error?e.message:String(e);s.log.error(` ${n.id}: typegen failed (${t}) — keeping previous output`),c.push({id:n.id,status:`error`,outFile:a});continue}if(o===null){c.push({id:n.id,status:`skipped`});continue}let l=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: ${n.id} */\n\n`+o+`
|
|
2521
|
+
`,d=``;if(r(a)&&(d=await T(a,`utf8`)),d===l){c.push({id:n.id,status:`unchanged`,outFile:a});continue}if(e.check)throw Error(`kick typegen --check: drift detected for ${n.id} (${a})`);await E(a,l,`utf8`),c.push({id:n.id,status:`written`,outFile:a})}return c}function Ja(e){let t=(e.extensions??[]).slice().toSorted().join(`,`),n=(e.exclude??[]).slice().toSorted().join(`,`);return[`root=${e.root}`,`cwd=${e.cwd}`,`extensions=${t}`,`exclude=${n}`,`envFile=${e.envFile??``}`].join(`|`)}function Ya(e,t){let n=new Set(t),r=[],i=[],a=new Set;for(let t of e)n.has(t.id)?(i.push(t),a.add(t.id)):r.push(t);return{enabled:r,skipped:i,unknown:[...n].filter(e=>!a.has(e))}}var Xa=A({applyDisableFilter:()=>Ya,runAllPluginTypegens:()=>Qa});function Za(){let e=(process.env.LOG_LEVEL??process.env.KICKJS_LOG_LEVEL??``).toLowerCase();return e===`debug`||e===`trace`}async function Qa(e){let{enabled:t,skipped:n,unknown:r}=Ya(Fe([...Cc,...e.config?.plugins??[]],e.config?.commands??[]).typegens,e.config?.typegen?.disable??[]);if(!e.silent&&n.length>0)for(let e of n)console.log(` ${e.id}: disabled (typegen.disable)`);if(!e.silent&&r.length>0&&console.warn(` kick typegen: disable list references unknown id(s): ${r.map(e=>`'${e}'`).join(`, `)}. Run \`kick typegen --list\` to see registered ids.`),t.length===0)return[];try{let n=await qa({cwd:e.cwd,config:e.config??{},plugins:t,check:e.check,changedFiles:e.changedFiles});if(!e.silent&&Za())for(let e of n)console.log(` ${e.id}: ${e.status}`);return n}catch(t){if(!e.silent){let e=t instanceof Error?t.message:String(t);console.warn(` kick typegen plugins: skipped (${e})`)}return[]}}var $a=A({ASSET_MANIFEST_VERSION:()=>1,buildAssets:()=>eo});async function eo(e,t){let{cwd:n,silent:r=!1}=t,a=t.distDir??e?.build?.outDir??`dist`,o=e?.assetMap;if(!o||Object.keys(o).length===0)return null;let s=r?()=>{}:console.log,c=v(n,a);i(c,{recursive:!0});let u=[],d={};for(let[e,t]of Object.entries(o)){let r=await to(e,t,n,c);u.push(r.entrySummary),Object.assign(d,r.manifestSlice),s(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let f={version:1,entries:d},p=h(c,`.kickjs-assets.json`);return l(p,JSON.stringify(f,null,2)+`
|
|
2522
|
+
`,`utf-8`),s(` ✓ wrote manifest → ${_(n,p)} (${Object.keys(d).length} entries)`),{manifestPath:p,entries:u,manifest:f}}async function to(e,t,a,o){let s=v(a,t.src),c=t.dest?v(a,t.dest):h(o,e);if(io(c,a))return console.warn(` ⚠ assetMap.${e}.dest ('${t.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:t.src,dest:_(a,c),filesCopied:0},manifestSlice:{}};if(!r(s)||!ao(s))return{entrySummary:{namespace:e,src:t.src,dest:_(a,c),filesCopied:0},manifestSlice:{}};let l=await fe(t.glob??`**/*`,{cwd:s,nodir:!0,dot:!1,posix:!0});i(c,{recursive:!0});let u={},{pairs:d,collisionGroupsResolved:p}=me(e,[...l].toSorted(),{strategy:t.keys??`auto`}),m=0;for(let{rel:e,key:t}of d){let r=h(s,e),a=h(c,e);u[t]=ro(o,a),!no(r,a)&&(i(f(a),{recursive:!0}),n(r,a),m++)}return p>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${p} basename collision(s) by keeping extensions (set 'keys: "strip"' to opt back into legacy last-write-wins behaviour, or 'keys: "with-extension"' to keep all keys verbose).`),{entrySummary:{namespace:e,src:t.src,dest:_(a,c),filesCopied:m},manifestSlice:u}}function no(e,t){if(!r(t))return!1;try{let n=c(e),r=c(t);return r.size===n.size&&r.mtimeMs>=n.mtimeMs}catch{return!1}}function ro(e,t){return _(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function io(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function ao(e){try{return c(e).isDirectory()}catch{return!1}}function oo(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)}}}function so(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await Promise.resolve().then(()=>Aa)).runTypegen(e),runAllPluginTypegens:async e=>(await Promise.resolve().then(()=>Xa)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await Promise.resolve().then(()=>Aa)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await Promise.resolve().then(()=>$a)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=u.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=>u.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,d=e=>e.replaceAll(`\\`,`/`),f=c.map(d),p=e=>{let t=d(e);return f.some(e=>t===e||t.startsWith(`${e}/`))},m=oo(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}).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&&!d(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 co(e){let t=h(e,`node_modules`,`.bin`),n=process.platform===`win32`;for(let e of[`tsgo`,`tsc`]){let i=n?[`${e}.CMD`,`${e}.cmd`,`${e}.exe`]:[e];for(let a of i){let i=h(t,a);if(r(i))return{cmd:i,args:[`--noEmit`],shell:n,kind:e}}}return null}function lo(e){let t=e.spawnFn??te,n=null,r=0,i=!1;return{schedule(){if(i)return;let a=++r;n&&=(n.kill(),null);let o=Date.now(),s=t(e.bin.cmd,e.bin.args,{cwd:e.cwd,shell:e.bin.shell,stdio:[`ignore`,`pipe`,`pipe`]});n=s;let c=``;s.stdout?.on(`data`,e=>{c+=e.toString()}),s.stderr?.on(`data`,e=>{c+=e.toString()}),s.on(`error`,()=>{a===r&&(n=null)}),s.on(`close`,t=>{i||a!==r||(n=null,e.onResult({ok:t===0,output:c,durationMs:Date.now()-o,kind:e.bin.kind}))})},dispose(){i=!0,n&&=(n.kill(),null)}}}function uo(e,t=12){let n=e.trim().split(/\r?\n/);return n.length<=t?n.join(`
|
|
2518
2523
|
`):`${n.slice(0,t).join(`
|
|
2519
|
-
`)}\n… ${n.length-t} more line(s)`}function
|
|
2524
|
+
`)}\n… ${n.length-t} more line(s)`}function fo(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function po(e,t,n={}){t&&(process.env.PORT=t);let r=fo(n.polling),i=process.cwd(),a=await M(i),o=a?.typegen?.schemaValidator??`zod`,s=a?.typegen?.envFile;try{await Ma({cwd:i,allowDuplicates:!0,schemaValidator:o,envFile:s,srcDir:a?.typegen?.srcDir,outDir:a?.typegen?.outDir,assetMap:a?.assetMap,runPlugins:!1})}catch(e){console.warn(` kick typegen: skipped (${e?.message??e})`)}let c=v(i,a?.typegen?.outDir??`.kickjs/types`);try{await Fa(c,await Qa({cwd:i,config:a}),!1)}catch(e){console.warn(` kick typegen: plugin pass skipped (${e?.message??e})`)}let{createRequire:l}=await import(`node:module`),{createServer:u}=await import(x(l(v(`package.json`)).resolve(`vite`)).href);globalThis.__kickjs_typegen_owner=`kick-dev`;let d=await u({configFile:v(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...r?{watch:{usePolling:!0,interval:100}}:{}}}),f=n.typecheck??a?.dev?.typecheck??!1,p=null,m=!0;if(f){let e=co(i);e?p=lo({cwd:i,bin:e,onResult:e=>{d.hot.send({type:`custom`,event:`kickjs:typecheck`,data:{ok:e.ok,output:e.output,durationMs:e.durationMs}}),e.ok?m||(m=!0,console.log(` kick typecheck: clean again (${e.kind}, ${e.durationMs}ms)`)):(m=!1,console.warn(`\n kick typecheck (${e.kind}, ${e.durationMs}ms):`),console.warn(uo(e.output).replace(/^/gm,` `)))}}):console.warn(` kick dev: --typecheck requested but neither tsgo (@typescript/native-preview) nor typescript is installed in this project — skipping type checks.`)}let h=so({cwd:i,config:a,emitWarning:e=>{console.warn(e),d.hot.send({type:`custom`,event:`kickjs:typegen-error`,data:{message:e,timestamp:Date.now()}})},onPassComplete:()=>p?.schedule()});d.watcher.on(`add`,e=>h.handleWatchEvent(`add`,e)),d.watcher.on(`unlink`,e=>h.handleWatchEvent(`unlink`,e)),d.watcher.on(`change`,e=>h.handleWatchEvent(`change`,e)),d.watcher.on(`unlinkDir`,e=>h.handleWatchEvent(`unlinkDir`,e)),h.assetSrcRoots.length>0&&d.watcher.add([...h.assetSrcRoots]),await d.listen(),d.printUrls(),console.log(`
|
|
2520
2525
|
KickJS dev server running (Vite + @forinda/kickjs-vite)
|
|
2521
|
-
`),p?.schedule();let g=!1,_=async()=>{if(!g){g=!0,h.dispose(),p?.dispose();try{await globalThis.__kickjs_app_shutdown?.()}catch(e){console.error(` app shutdown hook failed: ${e?.message??e}`)}await d.close(),process.exit(0)}};process.on(`SIGINT`,_),process.on(`SIGTERM`,_),process.on(`SIGBREAK`,_)}function
|
|
2526
|
+
`),p?.schedule();let g=!1,_=async()=>{if(!g){g=!0,h.dispose(),p?.dispose();try{await globalThis.__kickjs_app_shutdown?.()}catch(e){console.error(` app shutdown hook failed: ${e?.message??e}`)}await d.close(),process.exit(0)}};process.on(`SIGINT`,_),process.on(`SIGTERM`,_),process.on(`SIGBREAK`,_)}function mo(e){e.command(`dev`).description(`Start development server with Vite HMR (zero-downtime reload)`).option(`-e, --entry <file>`,`Entry file`,`src/index.ts`).option(`-p, --port <port>`,`Port number`).option(`--polling`,`Force chokidar to poll for file changes (Docker / WSL / NFS / older kernels)`).option(`--typecheck`,`Run the project TypeScript checker (tsgo/tsc --noEmit) after each change and report diagnostics`).action(async e=>{try{await po(e.entry,e.port,{polling:e.polling,typecheck:e.typecheck})}catch(e){e.code===`ERR_MODULE_NOT_FOUND`&&e.message?.includes(`vite`)?console.error(`
|
|
2522
2527
|
Error: vite is not installed.
|
|
2523
2528
|
Run: pnpm add -D vite unplugin-swc
|
|
2524
2529
|
`):console.error(`
|
|
2525
2530
|
Dev server failed:`,e.message??e),process.exit(1)}}),e.command(`build`).description(`Build for production via Vite`).action(async()=>{console.log(`
|
|
2526
2531
|
Building for production...
|
|
2527
|
-
`);let{createRequire:e}=await import(`node:module`),{build:t}=await import(x(e(v(`package.json`)).resolve(`vite`)).href);await t({configFile:v(`vite.config.ts`)});let a=await
|
|
2532
|
+
`);let{createRequire:e}=await import(`node:module`),{build:t}=await import(x(e(v(`package.json`)).resolve(`vite`)).href);await t({configFile:v(`vite.config.ts`)});let a=await M(process.cwd()),o=a?.copyDirs??[];if(o.length>0){console.log(`
|
|
2528
2533
|
Copying directories to dist...`);for(let e of o){let t=typeof e==`string`?e:e.src,a=typeof e==`string`?h(`dist`,e):e.dest??h(`dist`,t),o=v(t),s=v(a);if(!r(o)){console.log(` ⚠ Skipped ${t} (not found)`);continue}i(s,{recursive:!0}),n(o,s,{recursive:!0}),console.log(` ✓ ${t} → ${a}`)}}if(a?.assetMap&&Object.keys(a.assetMap).length>0){console.log(`
|
|
2529
|
-
Building asset map...`);try{await
|
|
2534
|
+
Building asset map...`);try{await eo(a,{cwd:process.cwd()})}catch(e){console.error(` ✗ asset build failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}console.log(`
|
|
2530
2535
|
Build complete.
|
|
2531
|
-
`)}),e.command(`build:assets`).description(`Rebuild the .kickjs-assets.json manifest under the configured outDir (no JS rebuild)`).action(async()=>{let e=await
|
|
2532
|
-
Building asset map...`);try{await
|
|
2536
|
+
`)}),e.command(`build:assets`).description(`Rebuild the .kickjs-assets.json manifest under the configured outDir (no JS rebuild)`).action(async()=>{let e=await M(process.cwd());if(!e?.assetMap||Object.keys(e.assetMap).length===0){console.log(` No assetMap entries — nothing to build.`);return}console.log(`
|
|
2537
|
+
Building asset map...`);try{await eo(e,{cwd:process.cwd()}),console.log(`
|
|
2533
2538
|
Asset build complete.
|
|
2534
|
-
`)}catch(e){console.error(` ✗ ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}),e.command(`start`).description(`Start production server`).option(`-e, --entry <file>`,`Entry file`,`dist/index.js`).option(`-p, --port <port>`,`Port number`).action(e=>{let t={NODE_ENV:`production`};e.port&&(t.PORT=String(e.port)),
|
|
2535
|
-
Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function
|
|
2536
|
-
`))})}const{bold:Z,dim:Q,green:
|
|
2539
|
+
`)}catch(e){console.error(` ✗ ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}),e.command(`start`).description(`Start production server`).option(`-e, --entry <file>`,`Entry file`,`dist/index.js`).option(`-p, --port <port>`,`Port number`).action(e=>{let t={NODE_ENV:`production`};e.port&&(t.PORT=String(e.port)),be(e.entry,t)}),e.command(`dev:debug`).description(`Start dev server with Node.js inspector attached`).option(`-e, --entry <file>`,`Entry file`,`src/index.ts`).option(`-p, --port <port>`,`Port number`).option(`--inspect-port <port>`,`Inspector port`,`9229`).action(async e=>{let t=e.inspectPort??`9229`;process.env.NODE_OPTIONS=`--inspect=0.0.0.0:${t}`,console.log(` Debugger: ws://0.0.0.0:${t}`);try{await po(e.entry,e.port)}catch(e){console.error(`
|
|
2540
|
+
Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function ho(){try{let e=f(b(import.meta.url));return JSON.parse(a(h(e,`..`,`package.json`),`utf-8`)).version??`unknown`}catch{return`unknown`}}const go=new Set(Object.values(vt).filter(e=>e.deprecated).map(e=>e.pkg));function _o(e){let t=h(e,`package.json`);if(!r(t))return[];let n;try{n=JSON.parse(a(t,`utf-8`))}catch{return[]}let i={...n.dependencies,...n.devDependencies};return Object.keys(i).filter(e=>e===`@forinda/kickjs`||e.startsWith(`@forinda/kickjs-`)).toSorted().map(t=>{let n=null,o=h(e,`node_modules`,...t.split(`/`),`package.json`);if(r(o))try{n=JSON.parse(a(o,`utf-8`)).version??null}catch{}return{name:t,installed:n,declared:i[t]??null,deprecated:go.has(t)}})}function vo(e){let t=e;for(;;){if(r(h(t,`package.json`)))return t;let e=f(t);if(e===t)return null;t=e}}function yo(e){e.command(`info`).description(`Print system and framework info`).action(()=>{let e=[``,` KickJS CLI v${ho()}`,``,` System:`,` OS: ${ge()} ${_e()} (${he()})`,` Node: ${process.version}`],t=vo(process.cwd()),n=t?_o(t):[];if(!t)e.push(``,` Packages: (not inside a project — no package.json found)`);else if(n.length===0)e.push(``,` Packages: (no @forinda/kickjs* dependencies in ${t})`);else{e.push(``,` Packages:`);let t=Math.max(...n.map(e=>e.name.length));for(let r of n){let n=r.installed??`${r.declared??`?`} (declared — not installed)`,i=r.deprecated?" [DEPRECATED — see `kick add --list --all`]":``;e.push(` ${r.name.padEnd(t+2)} ${n}${i}`)}}e.push(``),console.log(e.join(`
|
|
2541
|
+
`))})}const{bold:Z,dim:Q,green:bo,red:xo,yellow:So,blue:Co}=k;function wo(e){let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),i=e%60,a=[];return t&&a.push(`${t}d`),n&&a.push(`${n}h`),r&&a.push(`${r}m`),a.push(`${i}s`),a.join(` `)}async function To(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function Eo(e,t){try{return await To(`${e}${t}`)}catch{return null}}async function Do(e){let[t,n,r,i,a]=await Promise.all([Eo(e,`/health`),Eo(e,`/metrics`),Eo(e,`/routes`),Eo(e,`/container`),Eo(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function Oo(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=Q(`─`.repeat(60));if(console.log(),console.log(Z(` KickJS Inspector`)+Q(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?bo(`● healthy`):xo(`● `+n.status);console.log(` ${Z(`Health:`)} ${e}`)}else console.log(` ${Z(`Health:`)} ${xo(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?xo:r.errorRate>0?So:bo;console.log(` ${Z(`Uptime:`)} ${wo(r.uptimeSeconds)}`),console.log(` ${Z(`Requests:`)} ${r.requests}`),console.log(` ${Z(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${Q(`(`)}${t(e+`%`)}${Q(`)`)}`)}if(a&&console.log(` ${Z(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${Z(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(Z(` Routes`)),console.log(s),console.log(` ${Q(`METHOD`)} ${Q(`PATH`.padEnd(36))} ${Q(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${Ut(e.method)} ${t} ${Co(e.controller)}.${Q(e.handler)}`)}}console.log(s),console.log()}function ko(e){e.command(`inspect [url]`).description(`Connect to a running KickJS app and display debug info`).option(`-p, --port <port>`,`Override port`).option(`-w, --watch`,`Poll every 5 seconds`).option(`-j, --json`,`Output raw JSON`).action(async(e,t)=>{let n=e??`http://localhost:3000`;if(t.port)try{let e=new URL(n);e.port=t.port,n=e.origin}catch{n=`http://localhost:${t.port}`}let r=`${n.replace(/\/$/,``)}/_debug`,i=async()=>{try{let e=await Do(r);t.json?console.log(JSON.stringify(e,null,2)):Oo(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(xo(` ✖ Could not connect to ${n}`)),console.error(Q(` ${e instanceof Error?e.message:String(e)}`))),t.watch||(process.exitCode=1)}};if(t.watch){let e=async()=>{process.stdout.write(`\x1B[2J\x1B[H`),await i()};await e(),setInterval(e,5e3)}else await i()})}function Ao(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function $(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const jo=[{match(e,t){let n=Ao(e,[`config`,`get`])&&$(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&$(e,[`undefined`,`is not defined`]);return!n&&!r?null:{confidence:n&&r?90:75,diagnosis:{id:`env-schema-not-registered`,title:`ConfigService.get() returns undefined for user-defined keys`,explanation:`Your src/index.ts is missing \`import "./config"\`. That side-effect import
|
|
2537
2542
|
registers the env schema with kickjs at module-load time. Without it,
|
|
2538
2543
|
ConfigService falls back to the base schema (PORT/NODE_ENV/LOG_LEVEL only)
|
|
2539
2544
|
and every user-defined key reads as undefined. @Value() may *appear* to
|
|
@@ -2555,7 +2560,7 @@ describe('UserController', () => {
|
|
|
2555
2560
|
beforeEach(() => Container.reset())
|
|
2556
2561
|
|
|
2557
2562
|
it('does the thing', async () => { /* ... */ })
|
|
2558
|
-
})`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||
|
|
2563
|
+
})`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||Ao(e,[`Module`,`is not a function`])||Ao(e,[`Module`,`no exported member`])?{confidence:80,diagnosis:{id:`module-decorator-not-found`,title:`KickJS does not have a @Module decorator (different pattern from NestJS)`,explanation:`NestJS uses @Module({ controllers, providers }). KickJS uses an interface
|
|
2559
2564
|
pattern instead: a class implements AppModule and exposes routes() that
|
|
2560
2565
|
returns the controller wiring. This was a deliberate choice — modules
|
|
2561
2566
|
become explicit values rather than metadata, which makes them easier to
|
|
@@ -2607,24 +2612,24 @@ drop the entry.`,fix:`Open src/modules/index.ts and verify the module is in the
|
|
|
2607
2612
|
import { UserModule } from './users/user.module'
|
|
2608
2613
|
import { TaskModule } from './tasks/task.module' // ← was this missing?
|
|
2609
2614
|
|
|
2610
|
-
export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function
|
|
2615
|
+
export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function Mo(e,t){let n=null;for(let r of jo){let i=null;try{i=r.match(e,t)}catch{continue}!i||i.confidence<40||(!n||i.confidence>n.confidence)&&(n=i)}return n}async function No(e){let t=e.provider??`openai`,n=process.env.OPENAI_API_KEY;if(t===`openai`&&!n)return{kind:`unavailable`,reason:`OPENAI_API_KEY environment variable is not set`,suggestion:`Set OPENAI_API_KEY in your shell, e.g.
|
|
2611
2616
|
export OPENAI_API_KEY="sk-..."
|
|
2612
2617
|
|
|
2613
2618
|
Then re-run \`kick explain --ai "<your error>"\`.`};let r;try{r=await import(`@forinda/kickjs-ai`)}catch{return{kind:`unavailable`,reason:`@forinda/kickjs-ai is not installed`,suggestion:`Install the AI package to enable the LLM fallback:
|
|
2614
2619
|
kick add ai
|
|
2615
2620
|
|
|
2616
2621
|
Or manually:
|
|
2617
|
-
pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=
|
|
2618
|
-
`)}function
|
|
2622
|
+
pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=Po(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=Fo((await a.chat({messages:[{role:`system`,content:o},{role:`user`,content:s}]})).content);return e?{kind:`ok`,diagnosis:e}:{kind:`error`,message:`The LLM responded but the payload was not valid JSON in the expected shape. Try again, or file an issue with the error text.`}}catch(e){return{kind:`error`,message:`LLM request failed: ${e instanceof Error?e.message:String(e)}`}}}function Po(e){return[`You are a diagnostic assistant for KickJS, a decorator-driven Node.js`,`framework built on Express 5 and TypeScript. KickJS projects use:`,` - @Controller, @Get, @Post, @Autowired, @Service, @Value decorators`,` - An AppModule interface with a routes() method (NOT a @Module decorator)`,` - Zod schemas as both runtime validators and OpenAPI sources`,` - Ctx<KickRoutes.ControllerName['method']> for typed request context`,` - src/config/index.ts with defineEnv/loadEnv for env schema`,' - A side-effect `import "./config"` in src/index.ts to register the schema',` - Container.reset() in beforeEach for DI test isolation`,``,`When the user gives you an error message or stack trace, produce a`,`structured diagnosis that helps them fix the bug. You MUST respond`,`with a single JSON object (no surrounding prose, no markdown fences)`,`matching this shape:`,``,`{`,` "id": "<kebab-case-identifier>",`,` "title": "<one-line problem summary>",`,` "explanation": "<multi-line explanation of what is wrong>",`,` "fix": "<multi-line instructions for fixing the problem>",`,` "codeBefore": "<optional: broken code snippet>",`,` "codeAfter": "<optional: corrected code snippet>",`,` "docs": "<optional: KickJS doc URL that discusses this topic>"`,`}`,``,`The KickJS docs live at https://forinda.github.io/kick-js/ — prefer`,`that domain for any doc links you suggest.`,e?`The project is located at ${e}.`:``].filter(e=>e.length>0).join(`
|
|
2623
|
+
`)}function Fo(e){let t=[e,Io(e),Lo(e)].filter(e=>e!==null);for(let e of t)try{let t=JSON.parse(e);if(Ro(t))return t}catch{continue}return null}function Io(e){let t=e.match(/```(?:json)?\s*\n([\s\S]*?)```/);return t?t[1]?.trim()??null:null}function Lo(e){let t=e.indexOf(`{`);if(t===-1)return null;let n=0,r=!1,i=!1;for(let a=t;a<e.length;a++){let o=e[a];if(i){i=!1;continue}if(o===`\\`&&r){i=!0;continue}if(o===`"`){r=!r;continue}if(!r&&(o===`{`&&n++,o===`}`&&(n--,n===0)))return e.slice(t,a+1)}return null}function Ro(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&typeof t.title==`string`&&typeof t.explanation==`string`&&typeof t.fix==`string`}function zo(e){e.command(`explain [message]`).description(`Explain a KickJS error and suggest a fix`).option(`-m, --message <text>`,`Error message to explain (alternative to positional arg)`).option(`--ai`,`Fall back to LLM if no known-issue matches (requires @forinda/kickjs-ai)`).option(`--model <name>`,`Model name for the --ai fallback`,`gpt-4o-mini`).option(`--json`,`Output the diagnosis as JSON for tooling integration`).action(async(e,t)=>{let n=await Ho(e,t.message);(!n||n.trim().length===0)&&(process.stderr.write(`Error: no input provided.
|
|
2619
2624
|
|
|
2620
2625
|
Pass a message as a positional arg, --message flag, or pipe via stdin:
|
|
2621
2626
|
kick explain "config.get returned undefined"
|
|
2622
2627
|
pnpm test 2>&1 | kick explain
|
|
2623
|
-
`),process.exit(1));let r=
|
|
2624
|
-
`);return}if(i){
|
|
2625
|
-
`),process.exit(2)),
|
|
2626
|
-
`),process.exit(a.kind===`ok`?0:2)),
|
|
2627
|
-
`)}function
|
|
2628
|
+
`),process.exit(1));let r=Wo(),i=Mo(n,r);if(t.json&&i){process.stdout.write(JSON.stringify({matched:!0,...i},null,2)+`
|
|
2629
|
+
`);return}if(i){Go(n,i.diagnosis,i.confidence);return}t.ai||(t.json&&(process.stdout.write(JSON.stringify({matched:!1},null,2)+`
|
|
2630
|
+
`),process.exit(2)),Ko(n,!1),process.exit(2));let a=await No({input:n,model:t.model,cwd:r.cwd});t.json&&(process.stdout.write(JSON.stringify(Bo(a),null,2)+`
|
|
2631
|
+
`),process.exit(a.kind===`ok`?0:2)),Vo(n,a),process.exit(a.kind===`ok`?0:2)})}function Bo(e){return e.kind===`ok`?{matched:!0,source:`ai`,diagnosis:e.diagnosis}:e.kind===`unavailable`?{matched:!1,aiUnavailable:!0,reason:e.reason}:{matched:!1,aiError:!0,error:e.message}}function Vo(e,t){if(t.kind===`ok`){Go(e,t.diagnosis,-1,!0);return}if(t.kind===`unavailable`){process.stdout.write(`\n Explaining: ${Jo(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback unavailable: ${t.reason}\n\n`),process.stdout.write(`${qo(t.suggestion,` `)}\n\n`);return}process.stdout.write(`\n Explaining: ${Jo(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback error: ${t.message}\n\n`)}async function Ho(e,t){return e&&e.trim().length>0?e:t&&t.trim().length>0?t:process.stdin.isTTY?``:Uo()}function Uo(){return new Promise((e,t)=>{let n=``;process.stdin.setEncoding(`utf8`),process.stdin.on(`data`,e=>{n+=e}),process.stdin.on(`end`,()=>e(n)),process.stdin.on(`error`,t)})}function Wo(){let e=process.cwd();return{cwd:e,hasFile:t=>r(v(e,t))}}function Go(e,t,n,r=!1){let i=Jo(e.trim(),200),a=r?`AI-generated — verify before applying`:Yo(n);process.stdout.write(`\n Explaining: ${i}\n`),process.stdout.write(`\n Match: ${t.id} (${a})\n`),process.stdout.write(` Title: ${t.title}\n`),process.stdout.write(`\n Diagnosis:\n${qo(t.explanation,` `)}\n`),process.stdout.write(`\n Fix:\n${qo(t.fix,` `)}\n`),t.codeBefore&&process.stdout.write(`\n Before:\n${qo(t.codeBefore,` `)}\n`),t.codeAfter&&process.stdout.write(`\n After:\n${qo(t.codeAfter,` `)}\n`),t.docs&&process.stdout.write(`\n Docs: ${t.docs}\n`),process.stdout.write(`
|
|
2632
|
+
`)}function Ko(e,t){let n=Jo(e.trim(),200);process.stdout.write(`\n Explaining: ${n}\n\n`),t?process.stdout.write(` No known-issue matched, and --ai fallback is not yet wired.
|
|
2628
2633
|
When @forinda/kickjs-ai ships its provider implementations,
|
|
2629
2634
|
this command will call the configured LLM with the error +
|
|
2630
2635
|
project context and return a structured fix.
|
|
@@ -2641,12 +2646,12 @@ Pass a message as a positional arg, --message flag, or pipe via stdin:
|
|
|
2641
2646
|
3. File an issue with the error text:
|
|
2642
2647
|
https://github.com/forinda/kick-js/issues/new
|
|
2643
2648
|
|
|
2644
|
-
`)}function
|
|
2649
|
+
`)}function qo(e,t){return e.split(`
|
|
2645
2650
|
`).map(e=>`${t}${e}`).join(`
|
|
2646
|
-
`)}function
|
|
2647
|
-
`,`utf8`),process.stdout.write(`\n ✓ Wrote MCP server entry "${i}" to ${o}\n\n To activate it:\n 1. Build your app: kick build\n 2. Restart your MCP client (Claude Code, Cursor, Zed)\n 3. The server should appear in the client's tool picker\n\n`)}function
|
|
2651
|
+
`)}function Jo(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function Yo(e){return e>=90?`high confidence`:e>=70?`good match`:e>=50?`medium confidence`:`low confidence — verify manually`}function Xo(e){let t=e.command(`mcp`).description(`Model Context Protocol commands (start | init)`);t.command(`start`,{isDefault:!0}).description(`Run the built application as an MCP server over stdio`).option(`-e, --entry <file>`,`Entry file`,`dist/index.js`).option(`--node-arg <arg...>`,`Extra arguments to pass to node`).action(Zo),t.command(`init`).description(`Generate .mcp.json for Claude Code / Cursor / Zed`).option(`-n, --name <name>`,`Server name (defaults to package.json name)`).option(`-o, --out <file>`,`Output file`,`.mcp.json`).option(`-f, --force`,`Overwrite an existing entry without prompting`).option(`--global`,`Write to ~/.mcp.json instead of the project root`).action(Qo)}function Zo(e){let t=v(e.entry);r(t)||(process.stderr.write(`Error: entry file not found: ${t}\n\nBuild the app first with \`kick build\`, or pass a custom entry:\n kick mcp -e dist/server.js\n`),process.exit(1));let n=[...e.nodeArg??[],t],i=te(process.execPath,n,{stdio:`inherit`,env:{...process.env,KICK_MCP_STDIO:`1`,NODE_ENV:process.env.NODE_ENV??`production`}});i.on(`error`,e=>{process.stderr.write(`Failed to start MCP server: ${e.message}\n`),process.exit(1)}),i.on(`exit`,(e,t)=>{if(t){process.kill(process.pid,t);return}process.exit(e??0)});let a=e=>{i.killed||i.kill(e)};process.on(`SIGINT`,()=>a(`SIGINT`)),process.on(`SIGTERM`,()=>a(`SIGTERM`))}function Qo(e){let t=process.cwd(),n=$o(t)??d(t),i=e.name??n,o=e.global?v(process.env.HOME??`.`,`.mcp.json`):v(t,e.out),s={command:`kick`,args:[`mcp`],cwd:t},c={mcpServers:{}};if(r(o))try{let e=a(o,`utf8`),t=JSON.parse(e);t&&typeof t==`object`&&t.mcpServers&&(c={mcpServers:{...t.mcpServers}})}catch(e){let t=e instanceof Error?e.message:String(e);process.stderr.write(`Error: existing ${o} is not valid JSON (${t}).\nFix the file or pass --force to overwrite the entry.\n`),process.exit(1)}c.mcpServers[i]&&!e.force&&(process.stderr.write(`Error: an entry for "${i}" already exists in ${o}.\nPass --force to overwrite it, or use --name to pick a different key.\n`),process.exit(1)),c.mcpServers[i]=s,l(o,JSON.stringify(c,null,2)+`
|
|
2652
|
+
`,`utf8`),process.stdout.write(`\n ✓ Wrote MCP server entry "${i}" to ${o}\n\n To activate it:\n 1. Build your app: kick build\n 2. Restart your MCP client (Claude Code, Cursor, Zed)\n 3. The server should appear in the client's tool picker\n\n`)}function $o(e){let t=v(e,`package.json`);if(!r(t))return null;try{let e=a(t,`utf8`),n=JSON.parse(e);return typeof n.name==`string`?n.name:null}catch{return null}}function es(e){e.command(`tinker`).description(`Interactive REPL with DI container and services loaded`).option(`-e, --entry <file>`,`Entry file to load`,`src/index.ts`).action(async e=>{let t=process.cwd(),n=v(t,e.entry);r(n)||(console.error(`\n Error: ${e.entry} not found.\n`),process.exit(1));let i=ns(t,`tsx`);i||(console.error(`
|
|
2648
2653
|
Error: tsx not found. Install it: pnpm add -D tsx
|
|
2649
|
-
`),process.exit(1));let a=
|
|
2654
|
+
`),process.exit(1));let a=ts(n,e.entry),o=h(t,`.kick-tinker.mjs`),{writeFileSync:s,unlinkSync:c}=await import(`node:fs`);s(o,a,`utf-8`);try{let e=ee(o,[],{cwd:t,execPath:i,stdio:`inherit`});await new Promise(t=>{e.on(`exit`,()=>t())})}finally{try{c(o)}catch{}}})}function ts(e,t){return`
|
|
2650
2655
|
import 'reflect-metadata'
|
|
2651
2656
|
|
|
2652
2657
|
// Prevent bootstrap() from starting the HTTP server
|
|
@@ -2700,39 +2705,39 @@ server.on('exit', () => {
|
|
|
2700
2705
|
console.log('\\n Goodbye!\\n')
|
|
2701
2706
|
process.exit(0)
|
|
2702
2707
|
})
|
|
2703
|
-
`}function
|
|
2708
|
+
`}function ns(e,t){let n=e;for(;;){let e=h(n,`node_modules`,`.bin`,t);if(r(e))return e;let i=v(n,`..`);if(i===n)break;n=i}return null}function rs(e,t){let n=RegExp(`^\\s*${V(t)}Module\\b`),r=!1,i=0,a=e;for(;;){let e=a.indexOf(`.mount(`,i);if(e===-1)break;let t=e+7,o=1,s=t;for(;s<a.length&&o>0;){let e=a.slice(s,s+2);if(e===`//`||e===`/*`){if(e===`//`)for(s+=2;s<a.length&&a[s]!==`
|
|
2704
2709
|
`;)s++;else{for(s+=2;s+1<a.length&&!(a[s]===`*`&&a[s+1]===`/`);)s++;s+=2}continue}let t=a[s]??``;if(t===`'`||t===`"`||t==="`"){let e=t;for(s++;s<a.length&&a[s]!==e;)a[s]===`\\`&&s++,s++}else if(t===`(`)o++;else if(t===`)`&&(o--,o===0))break;s++}if(o!==0)break;let c=a.slice(t,s);if(n.test(c)){let t=e;for(;t>0&&(a[t-1]===` `||a[t-1]===` `||a[t-1]===`
|
|
2705
|
-
`);)t--;a=a.slice(0,t)+a.slice(s+1),r=!0,i=t;continue}i=s+1}return{content:a,changed:r}}function
|
|
2710
|
+
`);)t--;a=a.slice(0,t)+a.slice(s+1),r=!0,i=t;continue}i=s+1}return{content:a,changed:r}}function is(e,t){let n=Vn(e);if(!n)return e;let r=n.rhsStart,i=n.rhsEnd+1,a=e.slice(r,i);return a=rs(a,t).content,a=a.replace(RegExp(`\\s*,?\\s*${V(t)}Module\\b(?:\\s*\\(\\s*\\))?\\s*,?`,`g`),e=>{let t=e.trimStart().startsWith(`,`),n=e.trimEnd().endsWith(`,`);return t&&n?`,`:``}),a=a.replace(/,(\s*])/,`$1`),e.slice(0,r)+a+e.slice(i)}async function as(e){let{name:t,modulesDir:n,force:r}=e,i=e.pluralize!==!1,a=B(t),o=R(t),s=i?$t(a):a,c=h(n,s);if(!await We(c)){console.log(`\n Module not found: ${c}\n`);return}if(!r&&!await I({message:k.red(`Delete module '${s}' at ${c}? This cannot be undone.`),initialValue:!1})){console.log(`
|
|
2706
2711
|
Cancelled.
|
|
2707
|
-
`);return}await
|
|
2712
|
+
`);return}await oe(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=h(n,`index.ts`);if(await We(l)){let e=await T(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${V(o)}Module\\s*\\}\\s*from\\s*['"][^'"]*${V(s)}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=is(e,o),e=e.replace(/\n{3,}/g,`
|
|
2708
2713
|
|
|
2709
|
-
`),e!==t&&(await
|
|
2714
|
+
`),e!==t&&(await E(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function os(e){e.command(`remove`).alias(`rm`).description(`Remove generated code`).command(`module <names...>`).description(`Remove one or more modules (e.g. kick rm module user task)`).option(`--modules-dir <dir>`,`Modules directory`).option(`--no-pluralize`,`Use singular module name`).option(`-f, --force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=j(await M(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await as({name:n,modulesDir:v(r),force:t.force,pluralize:i})})}function ss(e){if(e!==void 0){if(e===`false`||e===`off`||e===`none`)return!1;if(e===`zod`)return`zod`;if(e===`kickjs-schema`||e===`schema`)return`kickjs-schema`;console.warn(` kick typegen: unknown --schema-validator '${e}' (supported: 'zod', 'kickjs-schema', 'false'). Falling back to project config.`)}}function cs(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function ls(e){e.command(`typegen`).description(`Generate type-safe DI registry and module types into .kickjs/types/`).option(`-w, --watch`,`Watch source files and regenerate on change`).option(`-s, --src <dir>`,`Source directory to scan`,`src`).option(`-o, --out <dir>`,`Output directory`,`.kickjs/types`).option(`--silent`,`Suppress output`).option(`--allow-duplicates`,`Auto-namespace duplicate class names instead of failing (use with caution)`).option(`--schema-validator <name>`,`Schema validator for body/query/params typing (currently 'zod' or 'false')`).option(`--env-file <path>`,`Path to env schema file for KickEnv typing (default 'src/env.ts'; pass 'false' to disable)`).option(`--check`,`CI gate: fail on plugin-typegen drift instead of writing`).option(`--fix`,`Patch module import.meta.glob() calls to cover decorated classes that aren't loaded by any glob (orphans)`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").option(`--no-cache`,`Disable the persistent scan cache; re-read + re-extract every file from cold`).action(async e=>{let t=rn(process.cwd()),n=await M(t);if(e.list){let{mergeCliPlugins:e}=await Promise.resolve().then(()=>Ie),{builtinCliPlugins:t}=await Promise.resolve().then(()=>Sc),r=e([...t,...n?.plugins??[]],n?.commands??[]),i=new Set(n?.typegen?.disable??[]);if(r.typegens.length===0){console.log(` No typegen plugins registered.`);return}let a=Math.max(...r.typegens.map(e=>e.id.length));console.log(`
|
|
2710
2715
|
Registered typegen plugins:
|
|
2711
|
-
`);for(let e of r.typegens){let t=i.has(e.id)?` (disabled)`:``;console.log(` ${e.id.padEnd(a+2)}inputs: ${e.inputs.join(`, `)||`(none)`}${t}`)}console.log();return}let r=
|
|
2716
|
+
`);for(let e of r.typegens){let t=i.has(e.id)?` (disabled)`:``;console.log(` ${e.id.padEnd(a+2)}inputs: ${e.inputs.join(`, `)||`(none)`}${t}`)}console.log();return}let r=ss(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,i=cs(e.envFile)??n?.typegen?.envFile,a={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,fix:e.fix,allowDuplicates:e.allowDuplicates,noCache:e.cache===!1,schemaValidator:r,envFile:i,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await Ia(a);e.silent||console.log(` kick typegen: watching for changes (Ctrl-C to exit)`);let n=()=>{t(),process.exit(0)};process.on(`SIGINT`,n),process.on(`SIGTERM`,n),await new Promise(()=>{})}else{await Ma(a);let r=await Qa({cwd:t,config:n??null,silent:e.silent,check:e.check});e.check&&r.some(e=>e.status===`written`)&&process.exit(1),e.check||await Fa(v(t,e.out??n?.typegen?.outDir??`.kickjs/types`),r,e.silent??!1)}}catch(e){e instanceof la?console.error(`
|
|
2712
2717
|
`+e.message+`
|
|
2713
|
-
`):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function
|
|
2718
|
+
`):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function us(e){let t=[];if(!r(e))return t;let n=o(e,{withFileTypes:!0});for(let r of n){let n=h(e,r.name);if(r.isDirectory()){if([`node_modules`,`dist`,`.kickjs`,`.git`].includes(r.name))continue;t.push(...us(n))}else r.isFile()&&/\.tsx?$/.test(r.name)&&!r.name.endsWith(`.d.ts`)&&t.push(n)}return t}function ds(e){try{return a(e,`utf-8`)}catch{return``}}const fs=new Set([`secret`,`changeme`,`password`,`test`,`default`,``]);function ps(e,t){let n=ds(h(e,`.env`));if(n){let e=n.match(/^JWT_SECRET\s*=\s*['"]?([^'"\n]*)['"]?/m);if(e){let t=e[1].trim();if(fs.has(t.toLowerCase())||t.length<32)return{severity:`CRITICAL`,message:`JWT_SECRET appears to be a default value or too short (< 32 chars) — change it`}}}for(let e of t)for(let t of[/JWT_SECRET['"]?\s*[:=]\s*['"]?(secret|changeme|password|test|default)['"]?/i,/secret\s*[:=]\s*['"]?(secret|changeme|password|test|default)['"]?/i])if(t.test(e))return{severity:`CRITICAL`,message:`JWT_SECRET appears to be a default value in source code — use an environment variable`};return null}function ms(e){for(let t of e)if(/cors\s*\(/.test(t)&&/origin\s*:\s*['"]\*['"]/.test(t))return{severity:`CRITICAL`,message:`CORS origin is '*' — restrict to your domains`};return null}function hs(e){for(let t of e)if(/rateLimit/i.test(t)||/@RateLimit/i.test(t))return null;return{severity:`WARNING`,message:`No rate limiting detected — add rateLimit() middleware or @RateLimit decorator`}}function gs(){return process.env.NODE_ENV===`production`?null:{severity:`WARNING`,message:`NODE_ENV is '${process.env.NODE_ENV??`undefined`}', not 'production'`}}function _s(e){let t=!1,n=!1;for(let r of e)/tokenStore/i.test(r)&&(t=!0),/MemoryTokenStore/i.test(r)&&(n=!0);return n?{severity:`WARNING`,message:`MemoryTokenStore detected — use a persistent store (Redis, DB) for production deployments`}:t?null:{severity:`WARNING`,message:`No token revocation store detected — consider adding one for auth token management`}}function vs(e){for(let t of e)if(/helmet\s*\(/.test(t))return/security\s*\.\s*helmet\s*.*false/.test(t)?{severity:`WARNING`,message:`Helmet security headers are disabled — enable them for production`}:{severity:`INFO`,message:`Helmet security headers active`};return{severity:`WARNING`,message:`Helmet not detected — add helmet() middleware for security headers`}}function ys(e){for(let t of e)if(/AuthAdapter/i.test(t))return{severity:`INFO`,message:`AuthAdapter configured`};return{severity:`INFO`,message:`No AuthAdapter detected — add one if your app requires authentication`}}function bs(e){let t=us(h(e,`src`)).map(e=>ds(e)),n=[],r=ps(e,t);r&&n.push(r);let i=ms(t);i&&n.push(i);let a=hs(t);a&&n.push(a);let o=gs();o&&n.push(o);let s=_s(t);return s&&n.push(s),n.push(vs(t)),n.push(ys(t)),n}function xs(e){e.command(`check`).description(`Audit project for common issues`).option(`--deploy`,`Run production readiness checks`).action(e=>{if(!e.deploy){console.log(`
|
|
2714
2719
|
Usage: kick check --deploy
|
|
2715
2720
|
|
|
2716
2721
|
Available checks:
|
|
2717
2722
|
--deploy Audit for production readiness (security, config, best practices)
|
|
2718
|
-
`);return}let t=process.cwd();
|
|
2719
|
-
Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function
|
|
2723
|
+
`);return}let t=process.cwd();Gt(`KickJS Deploy Check`);let n=Xt();n.start(`Scanning project...`);let r=bs(t);n.stop(`Scan complete`);let i={CRITICAL:0,WARNING:1,INFO:2};r.sort((e,t)=>i[e.severity]-i[t.severity]);for(let e of r)L.message(`${Wt(e.severity)} ${e.message}`);let a=r.filter(e=>e.severity===`CRITICAL`).length,o=r.filter(e=>e.severity===`WARNING`).length,s=r.filter(e=>e.severity===`INFO`).length,c=o===1?`warning`:`warnings`,l=[a>0?k.red(`${a} critical`):`${a} critical`,o>0?k.yellow(`${o} ${c}`):`${o} ${c}`,`${s} info`].join(`, `);a>0?(F(k.red(`${l} — fix critical issues before deploying`)),process.exit(1)):F(k.green(`${l} — looking good!`))})}function Ss(e){try{return JSON.parse(a(e,`utf-8`))}catch{return null}}function Cs(e){try{return a(e,`utf-8`)}catch{return null}}function ws(e){let t=Cs(h(e,`tsconfig.json`));if(!t)return null;let n=t.replace(/\/\*[\s\S]*?\*\//g,``).replace(/\/\/.*$/gm,``),r;try{r=JSON.parse(n)}catch{return null}if(typeof r?.extends==`string`){let t=Ts(e,r.extends);if(t){let e=Ss(t)??{};r.compilerOptions={...e.compilerOptions,...r.compilerOptions}}}return r}function Ts(e,t){if(t.startsWith(`.`)){let n=v(e,t);return r(n)?n:null}let n=h(e,`node_modules`,t);return r(n)?n:null}function Es(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Ds(){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.
|
|
2724
|
+
Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function Os(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 ks(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 As={express:[],fastify:[`fastify`,`@fastify/middie`],h3:[`h3`]};function js(e){if(!e.pkg||e.runtime===`express`)return null;let t={...e.pkg.dependencies,...e.pkg.peerDependencies,...e.pkg.devDependencies},n=As[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 Ms(e){if(!e.pkg||!Ps(e.cwd))return null;let t=bt[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 Ns=2e3;function Ps(e){let t=h(e,`src`);if(!r(t))return!1;let n=/@FileUpload\b|\bupload\.(single|array|none)\s*\(/,i=[t],a=0;for(;i.length>0&&a<Ns;){let e=i.pop(),t;try{t=o(e,{withFileTypes:!0})}catch{continue}for(let r of t){if(a>=Ns)break;let t=h(e,r.name);if(r.isDirectory()){r.name!==`node_modules`&&i.push(t);continue}if(/\.(ts|tsx|mts|cts)$/.test(r.name)&&(a++,n.test(Cs(t)??``)))return!0}}return!1}function Fs(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.
|
|
2720
2725
|
Install it: pnpm add reflect-metadata
|
|
2721
2726
|
Then import it at the top of src/index.ts:
|
|
2722
2727
|
|
|
2723
2728
|
import 'reflect-metadata'
|
|
2724
|
-
// ... rest of bootstrap`}}function
|
|
2725
|
-
`).map(e=>` ${
|
|
2726
|
-
`)}function
|
|
2729
|
+
// ... rest of bootstrap`}}function Is(e){if(!e.tsconfig)return[{name:`tsconfig.json present`,status:`fail`,fix:"Create a tsconfig.json with `experimentalDecorators: true` and `emitDecoratorMetadata: true`. `kick new` scaffolds one automatically."}];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 Ls(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=>r(e)).filter(e=>/\bloadEnv\s*\(/.test(Cs(e)??``));if(t.length===0)return null;let n=[`src/index.ts`,`src/main.ts`].map(t=>h(e.cwd,t)).find(e=>r(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 i=Cs(n)??``,a=f(n),o=[];for(let e of t){let t=_(a,e).replace(/\\/g,`/`).replace(/\.ts$/,``),n=t.startsWith(`.`)?t:`./`+t,r=n.replace(/\/index$/,``);o.push(n,r);let i=e.replace(/\\/g,`/`).match(/\/src\/(.+?)(?:\.ts)?$/);if(i){let e=`@/`+i[1],t=e.replace(/\/index$/,``);o.push(e,t)}}let s=-1;for(let e of new Set(o)){let t=RegExp(`^import\\s+(?:.*?from\\s+)?['"]${Es(e)}['"]`,`m`),n=i.match(t);n&&n.index!==void 0&&(s===-1||n.index<s)&&(s=n.index)}let c=i.search(/\bbootstrap\s*\(/),l=t.map(t=>_(e.cwd,t).replace(/\\/g,`/`)).join(`, `);return s===-1?{name:`env wiring`,status:`fail`,message:l,fix:`An env-init file (${l}) calls \`loadEnv(...)\` but \`${_(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 ${_(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'`}:c!==-1&&s>c?{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 Rs(e,t=zs){let n=0,r=0,i=[e];for(;i.length>0&&r<t;){let e=i.pop(),a;try{a=o(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);continue}try{let e=c(a).mtimeMs;e>n&&(n=e)}catch{}}}return n}const zs=2e3;function Bs(e){let t=h(e.cwd,`.kickjs`,`types`);if(!r(t))return null;let n=Rs(t);if(n===0)return null;let i=Date.now()-n,a=Math.floor(i/6e4);return a>60?{name:`typegen freshness`,status:`warn`,message:`last updated ${a} 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:a===0?`just now`:`${a}m ago`}}const Vs=[()=>Ds(),Os,ks,js,Ms,Fs,Is,Ls,Bs];async function Hs(e,t={}){let n={cwd:e,pkg:Ss(h(e,`package.json`)),tsconfig:ws(e),runtime:t.runtime??`express`},r=[...Vs,...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 Us(e){switch(e){case`pass`:return k.green(`✔`);case`warn`:return k.yellow(`⚠`);case`fail`:return k.red(`✖`)}}function Ws(e){let t=Us(e.status),n=e.message?` ${k.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function Gs(e){return e.split(`
|
|
2730
|
+
`).map(e=>` ${k.dim(`→`)} ${e}`).join(`
|
|
2731
|
+
`)}function Ks(e){return e?.doctor?.checks??[]}function qs(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=Ks(await M(e)),n=await xt(e);Gt(`KickJS Doctor`);let r=await Hs(e,{extraChecks:t,runtime:n});for(let e of r)L.message(Ws(e)),e.fix&&e.status!==`pass`&&L.message(Gs(e.fix));let i=r.filter(e=>e.status===`pass`).length,a=r.filter(e=>e.status===`warn`).length,o=r.filter(e=>e.status===`fail`).length,s=[k.green(`${i} passed`),a>0?k.yellow(`${a} warning${a===1?``:`s`}`):`${a} warnings`,o>0?k.red(`${o} error${o===1?``:`s`}`):`${o} errors`].join(`, `);o>0?(F(`${s} — fix the errors above before running the app`),process.exit(1)):F(a>0?`${s} — review the warnings`:k.green(`${s} — your environment looks good`))})}function Js(e){return e.optsWithGlobals().dryRun??!1}function Ys(e){e.command(`codemod`).description(`Codebase migration commands (AST-style rewrites — distinct from db migrate)`).command(`modules`).description(`Rewrite module declarations between class form and the defineModule factory.
|
|
2727
2732
|
Direction defaults to \`modules.style\` from kick.config (or "define").
|
|
2728
2733
|
--target define|class Override the migration direction.
|
|
2729
2734
|
--apply Apply the changes (default: dry-run preview).
|
|
2730
|
-
--experimental Acknowledge that AST migration is experimental.`).option(`--modules-dir <dir>`,`Modules directory (default: src/modules from kick.config)`).option(`--apply`,`Apply the migration to disk (default: dry-run)`).option(`--experimental`,`Acknowledge that this command is experimental`).option(`--target <style>`,`Migration direction — 'define' or 'class'`).option(`--no-backup`,`Skip the .kickjs/codemod-backups/ snapshot (default: backup on)`).action(async(e,t)=>{let n=
|
|
2731
|
-
`+
|
|
2735
|
+
--experimental Acknowledge that AST migration is experimental.`).option(`--modules-dir <dir>`,`Modules directory (default: src/modules from kick.config)`).option(`--apply`,`Apply the migration to disk (default: dry-run)`).option(`--experimental`,`Acknowledge that this command is experimental`).option(`--target <style>`,`Migration direction — 'define' or 'class'`).option(`--no-backup`,`Skip the .kickjs/codemod-backups/ snapshot (default: backup on)`).action(async(e,t)=>{let n=Js(t)||!e.apply;N(n),e.experimental||(console.error(`
|
|
2736
|
+
`+k.red(`Error:`)+` kick codemod modules is experimental — pass --experimental to acknowledge.
|
|
2732
2737
|
The regex-based rewrite handles the shapes our templates produce.
|
|
2733
2738
|
Hand-rolled modules with non-standard structures may be skipped.
|
|
2734
2739
|
Always commit before running with --apply.
|
|
2735
|
-
`),process.exit(1));let r=
|
|
2740
|
+
`),process.exit(1));let r=j(await M(process.cwd())),i=v(e.modulesDir??r.dir??`src/modules`),a;e.target===`define`||e.target===`class`?a=e.target:e.target===void 0?a=r.style??`define`:(console.error(`\n ${k.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let o=k.dim(`→ ${a}`),s=n?k.dim(`(dry-run)`):k.bold(`(applying)`);console.log(`\n ${k.bold(`kick codemod modules`)} ${o} ${s}`),console.log(` modulesDir: ${k.dim(i)}\n`);let c=e.backup!==!1&&!n,l=await wr(i,{dryRun:n,target:a,backup:c});if(l.backupDir){let e=l.backupDir;console.log(` ${k.green(`✓`)} backup: ${k.dim(e)}\n ${k.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else !n&&e.backup===!1&&console.log(` ${k.dim(`(--no-backup — skipping snapshot)`)}\n`);let u=0,d=0;for(let e of l.files)if(e.status===`migrated`)u++,console.log(` ${k.green(`✓`)} ${e.path}`);else{d++;let t=k.dim(`(${e.reason??`skipped`})`);console.log(` ${k.dim(`-`)} ${e.path} ${t}`)}if(console.log(),l.indexStatus===`migrated`)console.log(` ${k.green(`✓`)} ${l.indexPath}`);else if(l.indexStatus===`skipped`){let e=k.dim(`(${l.indexReason??`skipped`})`);console.log(` ${k.dim(`-`)} ${l.indexPath} ${e}`)}else console.log(` ${k.dim(`-`)} ${l.indexPath} ${k.dim(`(not found)`)}`);let f=n?k.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${k.bold(String(u))} migrated, ${k.bold(String(d))} skipped${f}\n`)})}const Xs=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){if(!r(u.resolve(e.cwd,`kick.config.ts`)))return null;let t=await M(e.cwd);if(!t?.assetMap)return null;let n=wa(t.assetMap,e.cwd);return n.count===0?null:Ta(n)}}),Zs="/* eslint-disable */\n// AUTO-GENERATED by `kick typegen`. DO NOT EDIT.\n// Re-run with `kick typegen` or rely on `kick dev` to refresh.\n";function Qs(e,t,n,r={}){if(e.length===0)return`${Zs}
|
|
2736
2741
|
// (no routes discovered yet — annotate a controller method with
|
|
2737
2742
|
// @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
|
|
2738
2743
|
declare global {
|
|
@@ -2741,8 +2746,8 @@ declare global {
|
|
|
2741
2746
|
}
|
|
2742
2747
|
|
|
2743
2748
|
export {}
|
|
2744
|
-
`;let i=new Map;for(let t of e){let e=i.get(t.controller)??[];e.push(t),i.set(t.controller,e)}let a=new Map,o=(e,i,o)=>{let s=
|
|
2745
|
-
`))}return`${
|
|
2749
|
+
`;let i=new Map;for(let t of e){let e=i.get(t.controller)??[];e.push(t),i.set(t.controller,e)}let a=new Map,o=(e,i,o)=>{let s=tc(e,i.filePath,t,n,a);if(!s){if(e&&n!==!1){let t=o===`params`?`URL-pattern params`:o===`query`&&i.queryFilterable!==null?`the @ApiQueryParams-derived query shape`:`'unknown'`;r.onWarn?.(`route ${i.controller}.${i.method} (${i.httpMethod} ${i.path}): ${o} schema '${e.identifier}' could not be statically resolved — falling back to ${t}. Export the schema from the controller file or import it with a static specifier.`)}return null}return n===`kickjs-schema`?`import('@forinda/kickjs-schema').InferSchemaOutput<typeof ${s}>`:`import('zod').infer<typeof ${s}>`},s=[];for(let[e,t]of i){let n=[` interface ${e} {`];for(let e of t){let t=e.pathParams.length>0?`{ ${e.pathParams.map(e=>`${e}: string`).join(`; `)} }`:`{}`,r=o(e.bodySchema,e,`body`),i=o(e.querySchema,e,`query`),a=o(e.paramsSchema,e,`params`)??t,s=r??`unknown`,c=i??$s(e),l=ec(e);n.push(` /**`,` * ${e.httpMethod} ${e.path}`,...l.map(e=>` * ${e}`),` */`,` ${e.method}: {`,` params: ${a}`,` body: ${s}`,` query: ${c}`,` response: unknown`,` }`)}n.push(` }`),s.push(n.join(`
|
|
2750
|
+
`))}return`${Zs}${nc(a)}
|
|
2746
2751
|
declare global {
|
|
2747
2752
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
2748
2753
|
namespace KickRoutes {
|
|
@@ -2752,9 +2757,9 @@ ${s.join(`
|
|
|
2752
2757
|
}
|
|
2753
2758
|
|
|
2754
2759
|
export {}
|
|
2755
|
-
`}function
|
|
2760
|
+
`}function $s(e){if(e.queryFilterable===null)return`unknown`;let t=e.querySortable??[];return`{ filter?: string | string[]; sort?: ${t.length>0?t.flatMap(e=>[`'${e}'`,`'-${e}'`]).join(` | `):`string`}; q?: string; page?: string; limit?: string }`}function ec(e){let t=[];return e.queryFilterable&&e.queryFilterable.length>0&&t.push(`Filterable: ${e.queryFilterable.join(`, `)}`),e.querySortable&&e.querySortable.length>0&&t.push(`Sortable: ${e.querySortable.join(`, `)}`),e.querySearchable&&e.querySearchable.length>0&&t.push(`Searchable: ${e.querySearchable.join(`, `)}`),t}function tc(e,t,n,r,i){if(!e||r===!1||e.source===null)return null;let a=rc(e.source,t,n);if(a===`unknown`)return null;let o=`${a}::${e.identifier}`,s=i.get(o)?.specifier;return s?s=i.get(o).specifier:(s=`_S${i.size}`,i.set(o,{identifier:e.identifier,specifier:s})),s}function nc(e){if(e.size===0)return``;let t=[];for(let[n,r]of e){let[e]=n.split(`::`);t.push(`import type { ${r.identifier} as ${r.specifier} } from '${e}'`)}return t.join(`
|
|
2756
2761
|
`)+`
|
|
2757
|
-
`}function
|
|
2762
|
+
`}function rc(e,t,n){if(e===null)return`unknown`;let r=f(n);if(e===``){let e=_(r,t).split(y).join(`/`);return e=e.replace(/\.(ts|tsx|mts|cts)$/i,``),e.startsWith(`.`)||(e=`./`+e),e}if(!e.startsWith(`.`)&&!e.startsWith(`/`))return e;let i=_(r,v(f(t),e)).split(y).join(`/`);return i=i.replace(/\.(ts|tsx|mts|cts)$/i,``),i.startsWith(`.`)||(i=`./`+i),i}const ic=()=>({id:`kick/routes`,outExtension:`.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){let t=await e.getScanResult({root:ac(e),cwd:e.cwd,envFile:oc(e)}),n=e.config?.typegen?.schemaValidator??`zod`,r=u.resolve(e.cwd,`.kickjs/types/kick__routes.ts`);return Qs(t.routes,r,n,{onWarn:t=>e.log.warn(t)})}});function ac(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function oc(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function sc(e,t,n=`zod`){if(!e)return null;let r=_(f(t),e.filePath).split(y).join(`/`);return r=r.replace(/\.(ts|tsx|mts|cts)$/i,``),r.startsWith(`.`)||(r=`./`+r),`/* eslint-disable */
|
|
2758
2763
|
// AUTO-GENERATED by \`kick typegen\`. DO NOT EDIT.
|
|
2759
2764
|
// Re-run with \`kick typegen\` or rely on \`kick dev\` to refresh.
|
|
2760
2765
|
|
|
@@ -2792,5 +2797,5 @@ declare global {
|
|
|
2792
2797
|
}
|
|
2793
2798
|
|
|
2794
2799
|
export {}
|
|
2795
|
-
`}const
|
|
2796
|
-
`)}});var
|
|
2800
|
+
`}const cc=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=uc(e);if(t===!1)return null;let n=await e.getScanResult({root:lc(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=e.config?.typegen?.schemaValidator??`zod`,i=u.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return sc(n.env,i,r)}});function lc(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function uc(e){return e.config?.typegen?.envFile}function dc(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function fc(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function pc(e){return{root:dc(e),cwd:e.cwd,envFile:fc(e)}}const mc=()=>({id:`kick/registry`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(pc(e)),n=u.resolve(e.cwd,`.kickjs/types/kick__registry.d.ts`),r=new Set(t.collisions.map(e=>e.className));return pa(t.classes,n,r)}}),hc=()=>({id:`kick/services`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(pc(e)),n=new Set(t.collisions.map(e=>e.className));return ga(`ServiceToken`,_a(t.classes,t.tokens,t.injects,n),"(no tokens discovered — declare with createToken<T>() or `kick g service <name>`)")}}),gc=()=>({id:`kick/modules`,inputs:[`src/**/*.ts`],async generate(e){return ga(`ModuleToken`,va((await e.getScanResult(pc(e))).classes),"(no @Module classes discovered — `kick g module <name>` to add one)")}}),_c=()=>({id:`kick/plugins`,inputs:[`src/**/*.ts`],async generate(e){return ya((await e.getScanResult(pc(e))).pluginsAndAdapters)}}),vc=()=>({id:`kick/augmentations`,inputs:[`src/**/*.ts`],async generate(e){return ba((await e.getScanResult(pc(e))).augmentations)}}),yc=()=>({id:`kick/context`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult(pc(e));return t.contextKeys.length===0?null:ha(t.contextKeys)}}),bc={fastify:{subpath:`@forinda/kickjs/fastify`,typeName:`FastifyRuntimeTypes`},h3:{subpath:`@forinda/kickjs/h3`,typeName:`H3RuntimeTypes`}},xc=()=>({id:`kick/runtime`,outExtension:`.ts`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`],async generate(e){let t=e.config?.runtime;if(t!==`fastify`&&t!==`h3`)return null;let{subpath:n,typeName:r}=bc[t];return[`// Runtime escape-hatch types for the '${t}' engine (kick.config runtime).`,`declare module '@forinda/kickjs' {`,` interface KickRuntimeRegister {`,` runtime: import('${n}').${r}`,` }`,`}`,``,`export {}`,``].join(`
|
|
2801
|
+
`)}});var Sc=A({builtinCliPlugins:()=>Cc});const Cc=[D({name:`kick/init`,register:Qt}),D({name:`kick/generate`,register:Ga}),D({name:`kick/run`,register:mo}),D({name:`kick/info`,register:yo}),D({name:`kick/inspect`,register:ko}),D({name:`kick/add`,register:jt}),D({name:`kick/list`,register:At}),D({name:`kick/explain`,register:zo}),D({name:`kick/mcp`,register:Xo}),D({name:`kick/tinker`,register:es}),D({name:`kick/remove`,register:os}),D({name:`kick/typegen`,register:ls}),D({name:`kick/check`,register:xs}),D({name:`kick/doctor`,register:qs}),D({name:`kick/codemod`,register:Ys}),D({name:`kick/registry`,typegens:[mc()]}),D({name:`kick/services`,typegens:[hc()]}),D({name:`kick/modules`,typegens:[gc()]}),D({name:`kick/plugins`,typegens:[_c()]}),D({name:`kick/augmentations`,typegens:[vc()]}),D({name:`kick/context`,typegens:[yc()]}),D({name:`kick/assets`,typegens:[Xs()]}),D({name:`kick/routes`,typegens:[ic()]}),D({name:`kick/env`,typegens:[cc()]}),D({name:`kick/runtime`,typegens:[xc()]})],wc=f(b(import.meta.url)),Tc=JSON.parse(a(h(wc,`..`,`package.json`),`utf-8`));async function Ec(){let e=new t;e.name(`kick`).description(`KickJS — A production-grade, decorator-driven Node.js framework`).version(Tc.version);let n=rn(process.cwd()),r=n,i=await M(r)??{},a=Fe([...Cc,...i.plugins??[]],i.commands??[]);await a.register(e,{cwd:r,projectRoot:n,config:i,log:e=>console.log(e)}),xe(e,{...i,commands:a.commands}),e.showHelpAfterError();let o=process.argv.map(e=>e===`-v`?`--version`:e);await e.parseAsync(o)}Ec().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};
|